Board: 59 rectification-related rows re-checked against origin/staging
ancestry, Gitea deploy-staging runs (current 8a409434, run 2930) and
acceptance records; unaccepted merges marked 已合入, real-device debt kept.
BUG_HISTORY: 085/086 closed_obsolete (V5 retired in f3946eaa); 981/984
fix-version lines record deployed commits/runs, status stays investigating;
1038-1047 fix-version lines corrected; 743 left as is (style probes still
score via tie_break path). BLOCKED: undeployed notes struck with evidence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
- D2: each intent-classifier attempt is capped at 10 s (same session model,
thinking untouched); a hang takes the existing retry -> classifier_unavailable
path. Success is timed too (RectificationClassifierDiagnostic).
- D3: a typed message builds the NDJSON stream first; the first line is
turn.progress "received", then the classifier and deterministic replies run
inside the stream. Preflight rejections become turn.rejected (old status,
code, message) and the client handles them like the old HTTP rejection.
Stage lines 收到,正在对照你的档案… / 正在记下这件事… / 正在重新对照盘面… /
正在准备下一个问题… are driven by existing tool events and engine calls, are
transient (live row only) and never persisted. VOICE / DESIGN updated.
- D4: RectificationRunDiagnostic records per-step start/end, provider token
usage incl. reasoning tokens, classifier timing and per-engine-call
durations (AsyncLocalStorage scope per turn); RectificationTurnDiagnostic
for deterministic turns. No user text, birth data or model text.
- D5: /v5/versions memo (30 s, complete identities only, per transport); the
exit gate skips its second persistNextInterviewIfIdle when the run's own
call found the next focus already active (provably identical).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
BUG-1045 (recurrence of BUG-585 via BUG-969): the snapshot merge now drops
the attached stem from the streamed "ack + stem" text with the same
stripQuestionSentences the GET route uses; server text unchanged.
BUG-1046: a failed choice submit (409 / network) or typed send withdraws
the local answered mark, remounts the card, re-reads the Case and shows
"这次没提交上,请再点一次。"; the persisted question hangs on the latest
settled assistant message with other copies of the same focus removed
(standalone block only when nothing can carry it); willContinue and the
send() settle merge unseen assistant turns (same gap as BUG-685).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
- The anchor listener and follow observer now attach whenever the scroller
element itself appears (checked after every commit, no-op unless element,
active or resetKey changed). The home page mounts `.conversation` after its
loading screen with unchanged active/resetKey, so a directly opened session
never got a listener, never landed on its newest content, showed the jump
chip under short replies and did not follow after pressing it.
- After a pin, geometry no longer releases the hold: only a wheel, touch drag,
scroll key or scrollbar press followed by a scroll within 1s does. The
rectification pin rests 94px from the bottom, inside the 96px threshold,
which dragged long replies to their last line.
- Real React lifecycle tests (loading screen -> reveal, 94px rest), DESIGN,
BUG history, PROGRESS, CHANGELOG, device checklist and CDP screenshots.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
The BUG-930 pin spacer sat on the last assistant row, pushing its sibling
.message-actions (and follow-ups / delivery card) below half a screen of
empty space. Move the same min-height onto the last turn's entry
(`:last-child:has(.message-assistant)`) with align-content: start so the
rectification grid wrap does not stretch its rows. Hook logic unchanged.
Records BUG-1043 / BUG-1044 (pre-existing, investigating) found during
browser verification.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
- D2 resumable hint becomes「上次那次校正还没完成,可以在历史对话里接着做。」
so it does not imply the homepage pill resumes (it always creates).
- The click-time non-self error in useRectificationSurface is the same
user-visible sentence as the homepage hint; add the full stop.
- Source, test, VOICE, DESIGN, CHANGELOG, BUG-1041, testing list and
PROGRESS (amendment by Claude) updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
TASK-starter-home-polish-20260926:
- D1 today's trend moves to a sub-line under the greeting
(.starter-greeting-sub), read from the same dailyStarlanguage state the
warm snapshot seeds; static sentence until ready, hidden without a minute.
- D2 the line under the pills appears only for a resumable case or a
non-self subject; the first-run and redo sentences are removed.
- BUG-1041 entrySummaryFromResponse read snake_case keys while the
entry-summary route returns camelCase, so every account parsed as a
first run; the parser now reads the route's shape (snake_case still ok).
- D3 daily entry icon MoonStar, credits icon Coins; D4 boundary line kept.
- Records: CHANGELOG, DESIGN, VOICE, BUG_HISTORY, PROGRESS, testing list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
Coming back to / from /chart, /ephemeris, /reports or /people by client
navigation remounted Home from hydrated=false and replayed the whole
bootstrap: model catalog, consult status, entry summary and daily card,
3-5 round trips plus up to 4 s of reveal budget, every time.
The reveal now counts per document load, not per mount:
- lib/home-warm-snapshot.ts: memory-only, per-account snapshot of the
model catalog, rectification entry summary, session cursor and today's
card (keyed by person + birth fingerprint + day). Account, profile and
the session list already survive in SessionListProvider. Cleared on
account change, sign-out, provider 401 and redirectToLogin.
- lib/home-warm-start.ts: Home's useState initializers take one warm
decision per mount. Complete snapshot + settled list + complete profile
+ a landing computable in memory -> start ready, landing resolved with
the cold-path functions (?new=1, ?c=, login-return stash and its person
scope from BUG-1038). Anything missing or needing a lookup -> the
unchanged cold path (no half-reveal, BUG-1021).
- runHomeWarmRefresh commits the landing, then refreshes catalog, account
and background-consultation recovery in the background (recovery shares
resolveReservedConsultation with the cold path). Summary and daily card
refresh through their existing effects.
- Next renders the new page before it writes the address bar, so AppLink /
navigateAppPath note the target href (lib/client-navigation-target.ts);
unknown target -> cold path.
Home() useState 33 / useRef 37 unchanged; page.tsx 1329 -> 1373 lines.
Tests: home-warm-return-lifecycle (13, real Home + sidebar + provider,
navigating in Next's render-then-write-URL order; 11 fail with warm start
disabled) and home-warm-snapshot (12). Full suite 3953 / 61 failing,
failure names identical to the 3928 / 61 baseline. Build: / stays Static,
rootMainFiles gzip 130933 B unchanged. Local Chrome with every /api/*
held 1.5 s: /chart -> 新建对话 interactive in 18-23 ms with no loading
ring (baseline 5530 ms with ring).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
Coming back to / from /people could show the previous rectification session
as a locked page: its title in the header, the composer stuck on
"正在打开生时校正…", and the new-chat greeting in the middle.
The state that survived between pages is the sessionStorage login-return
stash that secondary-page sidebar links write from the current ?c=:
- /people「和 TA 对话」used a second intent (?newChat=1) parsed by a
component mounted inside Home after bootstrap, so the bootstrap new-chat
branch never ran and the stash won.
- A stash id not in the current person's loaded list was looked up and
landed with urlAction "keep", which assumes ?c= is already in the address
bar. It was not, so the rectification auto-open never fired. The stash
also ignored which person was current.
- An in-page new chat left the stash in place.
Fix: delete NewChatDeepLink / ?newChat and route「和 TA 对话」through
newChatHref(); a looked-up stash writes ?c= back (replace-selected) and is
dropped when it belongs to another person; startNewChat and
openChatBoundToProfile clear the stash. ?c= deep links, BUG-989 and BUG-705
are unchanged.
Tests: new real-lifecycle suite mounting the real Home, sidebar and people
page (10 cases: four secondary pages + mobile drawer, 和 TA 对话 for self and
another person, out-of-scope stash, same-person stash beyond the first page,
in-page new chat), plus two contract/unit tests. Six fail on origin/staging,
all pass here. Full suite 3928 / 61 failing, failure names identical to the
0ab061b9 baseline (3916 / 61).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
- /people had zero CSS rules for its people-archive classes. Add the
approved layout: list -> detail below 1024px (data-view, ?person= history
entry so Back returns to the list), two columns at 1024px and above;
avatar rows with the current person highlighted, time cards with a
rectified state, readable ayanamsa name, three quick actions; delete moves
to the bottom of the edit view with unchanged confirm/count logic.
- Ephemeris: Chinese-first panchanga names from the brief's table only
(panchanga-names-zh.ts, three listed aliases, unknown names stay
Sanskrit), coloured 吉/中/凶 tags, N吉/M凶 counts and a fixed-rule day
summary (pure function, no model call); the header ask button becomes a
bottom hint card; transit rows show glyph, 「行星 在 星座」, house line and
degree; the Lahiri note names the subject's own ayanamsa.
- API, engine and database unchanged; /people and /ephemeris stay Static.
- DESIGN, VOICE, BUG_HISTORY, CHANGELOG, BLOCKED, PROGRESS and a manual
checklist updated. Two existing assertions changed, with 原值/新值/原因.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
Validate on Linux Node 22 and PostgreSQL 17: 3894 frontend tests and 64 database tests pass, with no removed test names or new failures. Preserve static Home, bounded gzip, assertion-change records and manual acceptance gaps.
Co-Authored-By: Claude Code <noreply@anthropic.com>
A 401 for the current person was stored, then hidden because the subject stamp only happened on success. Session, report, and birth contracts now follow the subject query and the shared birth lookup. Admin reset fixtures can no longer insert a retired self mirror.
The capability scan now lists the archive page. Chart profile writes no longer pretend to store a self mirror, and deletion stays an owned other-row transaction.
Chart, ephemeris, reports, daily language, consult, and synastry read birth data only through resolveSubjectBirth. The current person is a request parameter outside Home(). /people replaces the settings chart pane, and deleting someone removes that person's chats and reports.