Commit Graph

870 Commits

Author SHA1 Message Date
Jesse_Chen 027e4b0827 fix(frontend): remove undefined ayanamsa class
Independent Staging Quality Gate / validate (push) Successful in 16m5s
Independent Staging Quality Gate / publish (push) Successful in 2m7s
2026-09-03 22:34:51 +08:00
Jesse_Chen 734d20590c feat(upstream): wire merged engine fields into chat and reports
Independent Staging Quality Gate / validate (push) Failing after 31m48s
Independent Staging Quality Gate / publish (push) Has been skipped
Consultation and personal reports otherwise ignore the merged friendship table, timing seed, module audit, and Pratyantar windows.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 20:58:47 +08:00
Jesse_Chen 2415e751fe chore(repo): make the release gate reproducible and clean product URLs
PyJHora absence is now partial, tests write research manifests to tmp, the registry allows experimental_variant, and product links point at the Gitea repo. Early logs move to docs/history.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 16:55:26 +08:00
Jesse_Chen b6a70aa7df fix(ayanamsa): pin Lahiri on reference sets and add a user setting
Product default stays Raman. Public-case revalidation and fixture dashas now pass --ayanamsa lahiri; profiles store the four selectable values.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 16:33:46 +08:00
Jesse_Chen 591ffd21a1 fix(rectification): keep an open out-of-sample A–D card tappable
Independent Staging Quality Gate / validate (push) Successful in 11m52s
Independent Staging Quality Gate / publish (push) Successful in 1m46s
GET was dropping choice_card when the recast had no choice_frame, so the
embedded options rendered disabled. Replay the persisted reverse-verify /
out-of-sample schema instead of silencing the live question.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 15:30:49 +08:00
Jesse_Chen 99a91a97f4 docs(rectification): record the surface redo — BUG-505..509, DESIGN.md rectification surface, walkthrough section 8
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-03 07:07:45 +00:00
Jesse_Chen 3c33e59814 feat(rectification): confirm the tap on the choice card and show the declared minute on the empty board
The choice card now marks the tapped option with a check and 已选择 and,
while the tap is being recorded, carries the same live row shape as a
timeline step instead of only a wait cursor. Before any candidate exists
the board's clock shows the declared birth minute, its body says what
fills it later, and the column narrows to minmax(16rem, 18rem); the
compact peek reads "填报 HH:MM". No house table is invented for the
declared time — the Case API does not provide one.

BUG-508, BUG-509

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-03 07:07:31 +00:00
Jesse_Chen 1e50007c50 fix(rectification): keep one live row from a tapped choice or an adopted candidate through the follow-up turn
After a choice was recorded the chat removed its "正在记录本次选择…" row,
dropped `busy`, and let an effect start the follow-up turn a frame later —
one blank frame, and the next card could flash before the turn hid it.
Adopting a candidate showed nothing but a greyed button. `send` now takes a
continuation that reuses an existing live row, the choice and adoption
flows await it in the same async chain, `busy` is held throughout, and
adoption puts "正在采用 HH:MM…" at the end of the transcript before the
round trip.

BUG-506

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-03 07:07:31 +00:00
Jesse_Chen 360989ca2c fix(rectification): make every gap a live row with retries, give an empty Case a start, and say why a run stopped
The chat used to show "当前没有可回答的问题,正在等待服务端更新" / "当前问题暂时无法显示"
/ "题目加载失败,请刷新" as bare copy above the composer. The gap between a
settled turn and its next question is now a state: `preparing` renders the
same timeline live row the reply uses ("正在准备下一个问题…") and refetches the
Case on a 2s timer up to two retries; `unavailable` renders one line and a
44px reload button. A snapshot that never arrived at hydration is the same
gap. A resumed Case with no turns and no server-started opening shows
"这段校正还没有开始。" with one 开始提问 action. Stopping a run keeps what
streamed and says so instead of "暂时不可用"; the opening turn's live row
names what is happening; a 402 explains itself for 600ms before leaving.

BUG-505, BUG-507

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-03 07:07:31 +00:00
Jesse_Chen 53017d4153 fix(rectification): reveal the surface once — hydrate the Case before the switch, never remount, static entry feedback
Opening a rectification Case used to switch sessions first and read the
turns afterwards, so the reader saw a plain transcript, then an empty
panel, then a remount when the turns arrived (and again after the first
turn settled, because the panel key carried a ready/loading suffix).
The surface hook now reads turns and snapshot in one Case request under
the home reveal budget and only then makes the session active; the
sidebar defers the switch the same way; a session selected at bootstrap
(deep link, refresh) is hydrated during the prepare phase so the reveal
shows the surface itself; the panel key is the session/Case binding only,
later turns fill an empty transcript as a prop update, and unmounting
aborts any stream or snapshot read. The homepage card and the sidebar row
say 正在打开 statically while the Case opens — no spinner after the reveal.

BUG-505

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-03 07:07:31 +00:00
Jesse_Chen 8e214e290a fix(rectification): give the opening collect question concrete examples
Independent Staging Quality Gate / validate (push) Successful in 10m12s
Independent Staging Quality Gate / publish (push) Successful in 1m50s
The other-domain fallback copy was being used as the first question.
Opening now uses GENERIC_COLLECT_QUESTION; after-evidence other copy stays.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 14:31:23 +08:00
Jesse_Chen 0c0df42679 fix(rectification): require three answers before uncertainty stop
Independent Staging Quality Gate / validate (push) Successful in 9m19s
Independent Staging Quality Gate / publish (push) Successful in 1m52s
One "一时说不好" no longer ends the interview. Plateau streaks use the
same sample floor. Delivery copy states why the range stopped.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 12:08:37 +08:00
Jesse_Chen e8c98c37cf fix(rectification): restore collect-phase exit and drop the consult handoff
Independent Staging Quality Gate / validate (push) Successful in 8m29s
Independent Staging Quality Gate / publish (push) Successful in 1m45s
Public can_adopt no longer starves the collect fallback, 改选 scrolls to
the offer, opening collect uses other, and probe_year stays on the
schema. The status bar no longer starts an empty consultation chat.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 10:41:36 +08:00
Jesse_Chen 13bde020fb fix(staging): let migrate accept docs-only-ahead like deploy
Independent Staging Quality Gate / validate (push) Successful in 8m57s
Independent Staging Quality Gate / publish (push) Successful in 1m49s
Docs-only staging HEAD blocked Migrate Staging Database even when an ancestor already had a successful exact-SHA gate, so pending SQL could not be applied.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 10:29:19 +08:00
Jesse_Chen cf6405ed88 fix(report): say chapters wrote when assembly never finished
Independent Staging Quality Gate / validate (push) Successful in 8m9s
Independent Staging Quality Gate / publish (push) Successful in 1m48s
The 09:31 staging card had four ready sections but showed only structural
validation failure. Derive the list copy from section status so a written
pipeline stop is not described as an empty schema miss.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 09:58:06 +08:00
Jesse_Chen fbd6e48036 fix(report): do not fail a written report when progress projection throws
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled
Staging wrote four ready chapters then marked the job schema-invalid 34ms
later with no summary telemetry. Keep chapter persistence and assemble
going if onProgress or a non-lease heartbeat error fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 09:54:32 +08:00
Jesse_Chen 35e5781e66 fix(rectification): gate collect-phase adopt cards and keep post-adopt verify answerable
Independent Staging Quality Gate / validate (push) Successful in 9m50s
Independent Staging Quality Gate / publish (push) Successful in 1m53s
Public can_adopt follows session_outcome; reverse_verify reuses the persisted question id; offer cards settle on the owning message with a status-bar handoff.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 09:29:34 +08:00
Jesse_Chen 5c0bec0c94 fix(report): keep personal-report heartbeats ref'd during chapter writes
Independent Staging Quality Gate / validate (push) Successful in 7m56s
Independent Staging Quality Gate / publish (push) Successful in 1m49s
Staging lost the job lease mid-chapter because the unref'd interval never
fired outside an HTTP request. Refresh the lease on section progress and
leave the heartbeat timer ref'd so a long model await cannot starve it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 02:13:13 +08:00
Jesse_Chen 4329426530 fix(report): keep personal-report leases alive through serial chapter writes
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled
Staging verification wrote four ready sections then lost the 120s job lease
mid-chapter. Lengthen the worker lease and cap summary tokens with the same
3072 ceiling the section budget already uses.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 02:07:18 +08:00
Jesse_Chen eda37c1523 fix(report): classify writer failures and size CJK section budgets
Independent Staging Quality Gate / validate (push) Successful in 9m41s
Independent Staging Quality Gate / publish (push) Successful in 1m49s
Staging personal_full died as report_schema_invalid after the first
chapter blocked. Keep assertWriterOutput, stop treating refs mismatch as
missing evidence, and surface section error codes on the report APIs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 01:17:46 +08:00
Jesse_Chen 3568801509 fix(rectification): keep the choice selected state inside the button
Independent Staging Quality Gate / validate (push) Successful in 10m25s
Independent Staging Quality Gate / publish (push) Successful in 1m57s
The outer focus ring overflowed the message bubble and stacked on the existing selected border. Draw keyboard focus inset and skip auto-focusing the first option.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 21:44:55 +08:00
Jesse_Chen 8dfe457f21 fix(rectification): keep choice options and scoring on the server
Independent Staging Quality Gate / validate (push) Successful in 9m30s
Independent Staging Quality Gate / publish (push) Successful in 1m50s
Agent set-focus was writing or dropping choice schema, so probes never scored. Force server-owned options, fail closed when focus list RPC errors, and require the probe year in spokenPrompt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 20:47:16 +08:00
Jesse_Chen d94049769e fix(rectification): put each question inside the assistant message
Independent Staging Quality Gate / validate (push) Successful in 25m7s
Independent Staging Quality Gate / publish (push) Successful in 2m8s
Focuses now carry asked_turn_id so GET rebuilds stem and options on the
same turn. Agent writes spokenPrompt; the live question slot is gone.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 19:55:20 +08:00
Jesse_Chen 7faf8555a5 fix(report): unblock personal-full themes with real varga, transit, and karaka evidence
Independent Staging Quality Gate / validate (push) Successful in 9m15s
Independent Staging Quality Gate / publish (push) Successful in 1m50s
The extractor only read an obsolete varga object shape, never issued Transit receipts, and the consultation response omitted Chara Karakas, so career/marriage/timing/wealth all blocked. Supply the live engine shape, fail-closed receipts, and jaimini.chara_karakas without relaxing the evidence plan.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 18:03:23 +08:00
Jesse_Chen 33d55b3a54 fix(rectification): satisfy React compiler lint for collect stem attach
Independent Staging Quality Gate / validate (push) Successful in 9m21s
Independent Staging Quality Gate / publish (push) Successful in 1m49s
Move the current-question ref off render and persist the collect stem from snapshot/send callbacks so ESLint no longer fails the staging gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 17:05:29 +08:00
Jesse_Chen b1d4796d30 fix(rectification): restore showActivity source lock for the staging gate
Independent Staging Quality Gate / validate (push) Failing after 8m5s
Independent Staging Quality Gate / publish (push) Has been skipped
Keep collect text on bubbleMessage but pass displayedMessage.state so the entry contract matches again.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 16:49:31 +08:00
Jesse_Chen 42c6de142b fix(rectification): put the collect stem in the assistant bubble
Independent Staging Quality Gate / validate (push) Failing after 8m27s
Independent Staging Quality Gate / publish (push) Has been skipped
The live question slot still rendered the collect prompt below the action icons when the streamed body was only a greeting. Join the GET prompt into that bubble and stop drawing a sibling collect slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 16:30:26 +08:00
Jesse_Chen 39c30b5597 fix(rectification): persist the collect stem on the same assistant turn
Independent Staging Quality Gate / validate (push) Successful in 7m55s
Independent Staging Quality Gate / publish (push) Successful in 1m47s
The live question slot disappeared on refresh because it was never written to assistant_message. Attach the current collect_spoken prompt to that turn before finalize so chat history keeps it.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 16:06:50 +08:00
Jesse_Chen 643f6f7a15 fix(report): give the interpretive fixture structured D2/D11/D24
Independent Staging Quality Gate / validate (push) Successful in 8m22s
Independent Staging Quality Gate / publish (push) Successful in 1m47s
BUG-486 demotion dropped wealth and education cards when the snapshot only had machine receipts, which failed Gitea validate. Keep write-theme cards only when varga_full is present.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 15:27:59 +08:00
Jesse_Chen 45f190a1d0 fix(report): extract D2/D11 varga aliases so wealth chapters pass final parse
Independent Staging Quality Gate / validate (push) Failing after 7m34s
Independent Staging Quality Gate / publish (push) Has been cancelled
Engine keys like D2_Hora never became structured charts, so wealth write
themes failed the document contract. Canonicalize document vargas, demote
missing charts to blocked, and classify the parse failure.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 14:55:06 +08:00
Jesse_Chen 661a0dab14 fix(rectification): stop the opening body from repeating the collect prompt
Independent Staging Quality Gate / validate (push) Has been cancelled
Independent Staging Quality Gate / publish (push) Has been cancelled
Persist the interview slot before the opening turn, keep the stem in the question slot, and hide that slot while a run is busy so the same ask does not appear twice.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 14:53:10 +08:00
Jesse_Chen aab3ad4b84 fix(rectification): keep choice stems visible and align overlay adopt with the engine
Independent Staging Quality Gate / validate (push) Successful in 7m44s
Independent Staging Quality Gate / publish (push) Successful in 1m48s
Walkthrough polish: fail-closed empty D9 prompts, stop asserting the next question is on screen, vary same-domain collect copy, switch to reverse-verify after adopt, and let coverage route interview without blocking can_adopt.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 13:11:22 +08:00
Jesse_Chen bd79689f66 docs(design): restore paragraph break in the waiting section
Independent Staging Quality Gate / validate (push) Successful in 7m37s
Independent Staging Quality Gate / publish (push) Successful in 1m46s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-02 04:45:47 +00:00
Jesse_Chen f42a886f87 Merge remote-tracking branch 'origin/staging' into codex/unified-loading-20260902
Independent Staging Quality Gate / publish (push) Has been cancelled
Independent Staging Quality Gate / validate (push) Successful in 8m17s
# Conflicts:
#	docs/BUG_HISTORY.md
#	frontend/DESIGN.md
#	frontend/src/app/page.tsx
2026-09-02 04:44:40 +00:00
Jesse_Chen 482796fc52 fix(chat): reveal the home page once after a two-phase bootstrap
The loading screen now owns every wait: starter questions, today's
starlanguage and the rectification entry summary are fetched in a prepare
phase before reveal (4s budget, static fallbacks), the rectification chunk is
warmed, recent sessions are prefetched, and no component spinner remains
after the page appears. BUG-479.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-02 04:39:04 +00:00
Jesse_Chen 4dc0c8c7b3 Merge codex/streaming-ux-20260901: frame-coalesced streaming, stable settlement, one activity UI and one composer across both chat surfaces
Independent Staging Quality Gate / validate (push) Successful in 8m32s
Independent Staging Quality Gate / publish (push) Successful in 3m11s
BUG-473..478. Verified: tsc 0, focused suites 188/188, full suite 2484/2450 with the 24 known no-Docker failures, next build 0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:32:57 +00:00
Jesse_Chen 2733c50295 docs(chat): note the second rebase and renumbering; re-lock the question-stem describedby on the shared composer
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen 152acbef8d docs(chat): record task 3 in progress and re-lock the starter-home scroll guard on the hook
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen f542c02490 refactor(chat): share composer, scroll follow and jump control across both chat surfaces
The rectification session rendered its own textarea (no length ceiling,
no count), its own rAF scroll follow with a sticky-scroll helper, and its
own jump chip styled differently from the main chat's inline Tailwind
button, while the main chat re-ran scrollTo on every streamed token and
added a smooth scroll on settle. ChatComposer now accepts a controlled
value so the rectification surface reuses it without touching the main
draft store; useConversationScrollAnchor owns the follow through a
ResizeObserver, one frame per content change, for both surfaces; a
single JumpToLatestButton replaces both chips; the 720px transcript
override is gone. DESIGN.md records the shared composer, the jump
control, the reading width and the two shadow tokens.

BUG-477 BUG-478

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen eeb82dfdc4 docs(chat): record streaming-ux progress, block task 3 on batch three, align DESIGN.md
DESIGN.md gains the streaming-states table, the thinking-collapse and
label-swap motion rows, the 17px body correction and the single live
marker rule; task 3 is registered in BLOCKED.md until the home split
batch three lands; PROGRESS lists every touched assertion with its
former value.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen 6356d7b549 refactor(chat): render rectification activity through the shared step timeline
The rectification surface had its own activity pipeline: a trace panel
with a 20px canvas orb clipped inside a 14px marker, a list that never
collapsed, a second receipt disclosure under every reply, an inline
failure banner and a staged label while regenerating. Its trace and
receipt are now projected onto ConsultationTimelineRow so both surfaces
render one ConsultationRunTimeline with one live marker and one settled
summary; receipt methods become source chips on the last completed row.
The unreachable sections-report/step-tree path, the trace panel, the
receipt component and the thinking-orbs dependency are removed. The
server-side drop of rectification thinking deltas is untouched.

BUG-476

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen aff9d19343 fix(chat): keep the latest reply mounted through settlement and animate the timeline collapse
The streaming and settled versions of the trailing assistant reply were
two components, so settling unmounted one and mounted the other and the
entrance tween replayed over text the reader was already on. One
LatestAssistantEntry now owns that row under a single key, and the
history list excludes it. The CSS entrance keyframe that doubled the
GSAP tween is gone and the tween matches the documented 160ms. The step
timeline no longer remounts on settle: it is a button-controlled
disclosure with a 180ms grid-rows transition, the reader's own toggle
wins over the live default, and an in-flight request with no events yet
shows a queued row instead of an empty shell.

BUG-474 BUG-475

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen ad9dba5c79 perf(chat): coalesce stream events per frame and pace text release
Every NDJSON event used to commit its own React update and re-parse the
whole partial answer through react-markdown, so long replies grew
quadratically slower. Stream events now land in a frame buffer that
flushes at most once per animation frame, releases answer and thinking
text at a steady pace with a twelve-frame catch-up, and settles
synchronously on completion, failure and abort. Streaming markdown is
split at the last completed block so only the tail is re-parsed each
frame. Applied to both the consultation hook and the rectification chat.

BUG-473

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:29:01 +00:00
Jesse_Chen e3df3d17e7 docs(chat): note the second rebase and renumbering; re-lock the question-stem describedby on the shared composer
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:04:09 +00:00
Jesse_Chen 6ac55aebbb docs(chat): record task 3 in progress and re-lock the starter-home scroll guard on the hook
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:02:50 +00:00
Jesse_Chen 6187d7fdb8 refactor(chat): share composer, scroll follow and jump control across both chat surfaces
The rectification session rendered its own textarea (no length ceiling,
no count), its own rAF scroll follow with a sticky-scroll helper, and its
own jump chip styled differently from the main chat's inline Tailwind
button, while the main chat re-ran scrollTo on every streamed token and
added a smooth scroll on settle. ChatComposer now accepts a controlled
value so the rectification surface reuses it without touching the main
draft store; useConversationScrollAnchor owns the follow through a
ResizeObserver, one frame per content change, for both surfaces; a
single JumpToLatestButton replaces both chips; the 720px transcript
override is gone. DESIGN.md records the shared composer, the jump
control, the reading width and the two shadow tokens.

BUG-477 BUG-478

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:02:50 +00:00
Jesse_Chen 12d8c8afbb docs(chat): record streaming-ux progress, block task 3 on batch three, align DESIGN.md
DESIGN.md gains the streaming-states table, the thinking-collapse and
label-swap motion rows, the 17px body correction and the single live
marker rule; task 3 is registered in BLOCKED.md until the home split
batch three lands; PROGRESS lists every touched assertion with its
former value.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:02:15 +00:00
Jesse_Chen ccdae76dd3 refactor(chat): render rectification activity through the shared step timeline
The rectification surface had its own activity pipeline: a trace panel
with a 20px canvas orb clipped inside a 14px marker, a list that never
collapsed, a second receipt disclosure under every reply, an inline
failure banner and a staged label while regenerating. Its trace and
receipt are now projected onto ConsultationTimelineRow so both surfaces
render one ConsultationRunTimeline with one live marker and one settled
summary; receipt methods become source chips on the last completed row.
The unreachable sections-report/step-tree path, the trace panel, the
receipt component and the thinking-orbs dependency are removed. The
server-side drop of rectification thinking deltas is untouched.

BUG-476

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:02:15 +00:00
Jesse_Chen be5e810ac9 fix(chat): keep the latest reply mounted through settlement and animate the timeline collapse
The streaming and settled versions of the trailing assistant reply were
two components, so settling unmounted one and mounted the other and the
entrance tween replayed over text the reader was already on. One
LatestAssistantEntry now owns that row under a single key, and the
history list excludes it. The CSS entrance keyframe that doubled the
GSAP tween is gone and the tween matches the documented 160ms. The step
timeline no longer remounts on settle: it is a button-controlled
disclosure with a 180ms grid-rows transition, the reader's own toggle
wins over the live default, and an in-flight request with no events yet
shows a queued row instead of an empty shell.

BUG-474 BUG-475

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:02:15 +00:00
Jesse_Chen 6eadb62eb7 perf(chat): coalesce stream events per frame and pace text release
Every NDJSON event used to commit its own React update and re-parse the
whole partial answer through react-markdown, so long replies grew
quadratically slower. Stream events now land in a frame buffer that
flushes at most once per animation frame, releases answer and thinking
text at a steady pace with a twelve-frame catch-up, and settles
synchronously on completion, failure and abort. Streaming markdown is
split at the last completed block so only the tail is re-parsed each
frame. Applied to both the consultation hook and the rectification chat.

BUG-473

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
2026-09-02 04:02:15 +00:00