Skip to content

perf: Phase 3 — prompt caching, reduced-motion canvas, stub audit - #5

Merged
Steel-tech merged 5 commits into
mainfrom
feat/phase-3
Jun 18, 2026
Merged

perf: Phase 3 — prompt caching, reduced-motion canvas, stub audit#5
Steel-tech merged 5 commits into
mainfrom
feat/phase-3

Conversation

@Steel-tech

@Steel-tech Steel-tech commented Jun 18, 2026

Copy link
Copy Markdown
Owner

Phase 3 (Depth & Polish) of the IronForge maximization roadmap (docs/plans/2026-06-17-001). Orchestrated as three parallel agents on disjoint file sets, reviewed, then integrated.

Units

  • U12 — AI prompt caching. buildSystemPrompt (chat route) now returns Anthropic.TextBlockParam[] with cache_control: ephemeral on the stable prefix (persona + step knowledge base + rules), and the volatile per-user profile moved to a trailing uncached block so the cached prefix is byte-identical across a user's turns on a step. onboarding and bid-review intentionally skipped — their prompts (~680 and ~1300 tokens) fall below the Sonnet (2048) and Opus (4096) cacheable minimums, so a breakpoint there would be a no-op. The chat route is both the qualifying prompt and the highest-frequency path (multiple turns per step).
  • U13 (partial) — reduced-motion + canvas throttling. New useReducedMotion hook (via useSyncExternalStore). Matrix rain now caps at ~30fps (time-accumulator in the rAF loop), pauses on tab-hidden (visibilitychange), and renders a single static frame under prefers-reduced-motion; tron-grid drops its perspective-depth layer under reduced motion. Cuts background-canvas CPU/GPU on mid-tier mobile.
  • U11 (partial) — stub/dead-code audit. Swept all ~19 routes + feature components: clean bill — no dead handlers, no-op buttons, or "coming soon" UI. Verified the heavy features actually function (estimator, capability statement, calendar .ics export, vault, bid-review SSE). One redundant render-gate simplified in starter-kit.

Verification

  • 71 tests green · tsc --noEmit clean · lint 0 errors (22 pre-existing warnings) · production build succeeds.
  • Three-agent review (correctness / testing / simplicity) on the diff before integration. The one substantive finding (an SSE buffering bug) was in the prior PR feat: Polish — ship progress export (U11) #3 and already fixed there.
  • Caching minimums confirmed against the claude-api reference (Opus 4.8 = 4096, Sonnet 4.6 = 2048).

Deferred (not in this PR)

  • Post-deploy check: confirm usage.cache_read_input_tokens > 0 on a 2nd WA chat turn (requires a live API call).
  • U12 large-file splits (onboarding-chat 611L, wizard page 591L, etc.) — conflict-prone, next push.
  • U13 service-worker audit, bundle/Lighthouse budget in CI, registry code-splitting.
  • A useReducedMotion unit test (matchMedia mock) — low value vs the build/type coverage; flagged.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Accessibility

    • Added support for reduced-motion preferences—animations now respect OS and browser settings for users who prefer less motion.
  • Performance

    • Implemented frame-rate limiting for smoother, optimized animation rendering.
  • Bug Fixes

    • Fixed starter kit preview display logic to render correctly when preview mode is enabled.

Steel-tech and others added 5 commits June 18, 2026 00:41
Restructure the wizard chat system prompt into cache-controlled content
blocks so repeat turns on the same step read the large stable prefix from
cache instead of reprocessing it (~0.1x input cost on hits).

- buildSystemPrompt now returns Anthropic.TextBlockParam[]: a stable block
  (persona + per-step knowledge base + rules + security) carrying
  cache_control: ephemeral, followed by a volatile block (per-user profile
  context) after the breakpoint.
- The volatile profile data previously sat in the MIDDLE of the prompt
  ("Current Context"), which would have invalidated everything after it on
  every request; it's now moved to a trailing uncached block so the cached
  prefix is byte-identical across a user's turns on a step.
- No model IDs, max_tokens, streaming, or data-tag handling changed; the
  system field already accepts a block array, so the chat route call site is
  unchanged beyond a clarifying comment.

Onboarding and bid-review routes are intentionally left uncached: their
static system prompts (~680 and ~1300 tokens) fall below the per-model
minimum cacheable prefix (2048 tokens on Sonnet 4.6, 4096 on Opus 4.8), so a
cache_control marker there would be a silent no-op.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a shared useReducedMotion hook (SSR-safe, subscribes to changes) and
wire it into the two backdrop effects:

- MatrixRain: skip the rAF loop entirely under prefers-reduced-motion
  (paint one static frame instead); when motion is allowed, cap the loop
  to ~30fps via a time accumulator in rAF and pause/resume on tab
  visibility changes. Tag the canvas with .matrix-rain-container so the
  existing reduced-motion/print CSS selectors actually match it.
- TronGrid: drop the perspective floor layer under reduced motion so the
  backdrop stays flat and calm.

Halves the per-frame work on low-power devices and stops animating
unfocused tabs, with no visual change when motion is allowed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The render guard `(previewMode || !hydrated) && hydrated` was provably
equivalent to `previewMode && hydrated` (previewMode is never true before
hydration), so collapse it to the simpler, clearer form. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the useEffect+useState matchMedia subscription with React's
external-store primitive — SSR-safe and free of the setState-in-effect
cascade warning. Behavior unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR introduces a useReducedMotion hook that reads the prefers-reduced-motion media query and wires it into MatrixRain (adding frame-rate capping, a static-frame path, and visibility-based pause/resume) and TronGrid (conditionally omitting the perspective floor). Separately, buildSystemPrompt is refactored to return Anthropic.TextBlockParam[] with cached-stable and volatile prompt blocks. Minor fixes include a starter-kit render condition simplification and a .gitignore addition.

Changes

Reduced-motion accessibility for UI animations

Layer / File(s) Summary
useReducedMotion hook
lib/hooks/use-reduced-motion.ts
New hook using useSyncExternalStore subscribes to prefers-reduced-motion: reduce changes on the client; returns false as the SSR server snapshot to prevent hydration mismatch.
MatrixRain reduced-motion and FPS throttling
components/ui/matrix-rain.tsx
Imports useReducedMotion; defines TARGET_FPS/FRAME_INTERVAL; extracts a renderFrame helper; replaces the animation loop with a frame-rate-capped loop(now); adds a single-frame static path for reduced motion; adds a visibilitychange handler to pause and resume the loop.
TronGrid conditional floor rendering
components/ui/tron-grid.tsx
Imports useReducedMotion and gates the .tron-floor div on !reducedMotion.

AI prompt caching refactor and minor fixes

Layer / File(s) Summary
buildSystemPrompt two-block cache structure
lib/ai/system-prompts.ts
Return type changes from string to Anthropic.TextBlockParam[]; builds a stablePrompt block with cache_control: ephemeral (persona + current step) and a volatilePrompt block (per-user profile lines) without cache control.
Chat route comment, page.tsx condition fix, and .gitignore update
app/api/chat/route.ts, app/starter-kit/page.tsx, .gitignore
Adds a comment in the POST handler describing the stable/volatile caching split; simplifies the starter-kit preview condition to previewMode && hydrated; adds .a5c/ to .gitignore.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 A rabbit hops through frames, slowing down with care,
When motion should be still, no spinning through the air.
The prompt splits in two — one cached, one fresh each call,
And .tron-floor rests quietly when reduced flags fall.
Less flicker, smarter cache, a cleaner render day —
This bunny approves of keeping jank at bay! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main improvements: prompt caching optimization (Phase 3 of roadmap), reduced-motion support with canvas throttling, and code audit. It directly maps to the core changes across the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/phase-3

Comment @coderabbitai help to get the list of available commands and usage tips.

@Steel-tech
Steel-tech merged commit fa8fe64 into main Jun 18, 2026
1 of 2 checks passed
@Steel-tech
Steel-tech deleted the feat/phase-3 branch June 18, 2026 06:47

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 144191612f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}

function getSnapshot(): boolean {
return window.matchMedia(QUERY).matches;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fall back when matchMedia is unavailable

In environments where window.matchMedia is absent (jsdom by default, and some embedded or legacy browsers), any component using this hook will throw during render because useSyncExternalStore calls getSnapshot even though subscribe handles the same case with a no-op. Rendering MatrixRain or TronGrid should fall back to false instead of crashing when matchMedia is unavailable.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant