Commit Graph
108 Commits
Author SHA1 Message Date
Jesse_ChenandClaude Opus 5.5 4f3d8d7c62 feat(compliance): content moderation on model input and output — local lexicon, Aliyun adapter, free completion, admin log
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-30 09:42:11 +08:00
Jesse_ChenandClaude Opus 5.5 3c8123d912 feat(support): in-app feedback & complaints with admin handling; persist reply ratings
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-30 09:42:11 +08:00
Jesse_ChenandClaude Opus 5.5 c59e362521 fix(chart,reports): chart card hugs the drawing, symbol help as a bubble, sky button shows at once, report card spacing and copy (BUG-1100..1103)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-29 20:19:32 +08:00
Jesse_ChenandClaude Opus 5.5 9686dfb945 feat(onboarding): no hint toast after the first-chart star convergence
Independent Staging Quality Gate / validate (push) Failing after 10m40s
Independent Staging Quality Gate / publish (push) Skipped
Product 2026-09-29: drop 「这片天空在星盘页可以保存。」. The chart page entry is now replay + share.
Verified: tsc 0, lint 0 errors, npm test 4335/4280/24 (same 24 Docker/DB/deploy names),
quick gate (gate params) passed, / Static, first-screen JS gzip 651,512 -> 651,143.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-29 09:24:00 +08:00
Jesse_ChenandClaude Opus 5.5 8415fdca72 fix(people): 本人 can edit their own birth data in 星盘档案 (S1, BUG-1081)
The owner had no edit entry anywhere once /people replaced the settings
chart pane. 本人 now gets 编辑 with the same form; the save goes through
PATCH /api/account via a shared lib/self-profile-save.ts that the home
onboarding also uses. The dead saveProfile is removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-29 00:43:43 +08:00
Jesse_ChenandClaude Opus 5.5 dec36bce01 feat(birth-sky): poster-only dialog, date/time/city caption, slower reveal, paywall on first refused send (P1–P5, BUG-1080)
TASK-birth-sky-polish-20260928.
- P1: chart page dialog shows only the picture on a dimmed stage, 「保存图片」 below, icon × in the corner.
- P2: BFF returns one server-built `caption` (「1994年5月18日 07:40 · 杭州」); printed under the fact line in all three places; adopted time adds 「 · 校正后」.
- P3: convergence 3 s + words 2.5 s + fade 1 s; settled frame still equals the exported cover.
- P4: redeem paywall no longer opens when the starter home appears; first send refused for credits opens it, later ones open billing; convergence dialog portalled to <body>. BUG-1080 investigating (Chrome repro rules out the overlay covering the convergence).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-29 00:03:46 +08:00
Jesse_ChenandClaude Opus 5.5 731c3b364b feat(onboarding): first-chart reveal becomes a star convergence, no buttons (F4)
TASK-birth-sky-followup-20260928 F4:
- pure timeline / seeded scatter / interpolation in lib/birth-sky/converge.ts;
  drawBirthSky takes an optional frame (positions interpolated, alphas
  multiplied) so the settled frame is the exported cover call for call
- lazy full-screen <dialog> overlay driven by requestAnimationFrame at
  viewport x DPR; tap / click / Esc end it; reduced motion only fades
- data, serif and overlay chunk must all arrive inside the 3 s budget,
  otherwise skipped silently; page.tsx wiring unchanged
- one sonner hint after it ends; dialog reveal variant (继续, is-reveal) removed
- DESIGN §17, VOICE, CHANGELOG, checklist, PROGRESS with verification

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
2026-09-28 22:07:01 +08:00
Jesse_ChenandClaude Opus 5.5 14ef18ac24 feat(onboarding): one-time 「那一刻的天空」 reveal after the first own chart (T6)
After saveOnboardingPlace succeeds (and the next step is already set), the
new useBirthSkyReveal hook fetches /api/birth-sky?subject=self and paints
the cover; if that finishes within 3 s the chart page's dialog fades in
(600 ms, none under reduced motion) with 「继续」. Timeout or failure is
silent, no retry; closing touches only the reveal's own state. Home() gains
no useState/useRef; page.tsx only wires. Family profiles and profile edits
never trigger it.

Also caps the dialog image by viewport height (the percentage max-height did
not resolve inside the flex/grid cell), and completes PROGRESS, DESIGN §17,
CHANGELOG and the real-device checklist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
2026-09-28 20:47:35 +08:00
Jesse_ChenandClaude Opus 5.5 d277cbd8ad feat(chart): 「那一刻的天空」封面 — engine, BFF, canvas painter, chart header entry
T1 scripts/birth_sky.py: real alt/az of the seven visible grahas (swe.calc_ut +
swe.azalt, geometric altitude, azimuth converted from swe's south origin to
north-east) and Yale BSC5 stars V<=4.0 (IAU 1976 precession); phase
day / twilight_morning / twilight_evening / night. Thin POST /api/birth_sky
registration in do_POST (no new handler method, no __new__).

T2 GET /api/birth-sky?subject=: birth truth read server side through
loadSubjectBirth + prepareChartViewProfile; zod contract; no billing, no
writes, no birth data in the response.

T3/T4 lib/birth-sky: sentence table, pure Canvas 2D drawBirthSky (night /
paper palettes from DESIGN tokens, east on the left, serif headline with
1.5 s font wait), PNG export via navigator.share or Blob + a.download.
Chart page prefetches and paints the cover once the chart is ok; the header
button appears only when the PNG is ready. Dialog is a lazy chunk.

T7 DESIGN §17, VOICE, CONTEXT glossary, CHANGELOG, real-device checklist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
2026-09-28 20:27:40 +08:00
Jesse_ChenandClaude Opus 5.5 c35e0195e1 fix(chart): Sripati Bhava from the real sidereal MC; Bhava chart and tables (T5, BUG-1077)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-28 15:38:24 +08:00
Jesse_ChenandClaude Opus 5.5 3f6bcb081a feat(chart): Moon chart from D1 and transit chart for today in the natal houses (T4)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-28 15:33:30 +08:00
Jesse_ChenandClaude Opus 5.5 af27709de4 feat(chart): hide qizheng from the chart page; backend endpoint kept (T1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-28 15:17:34 +08:00
Jesse_ChenandClaude Fable 5.1 891e9c62da fix(consult): paced settle is opt-in for the consultation reply; one rejection path for HTTP bodies and stream events (T2/T3 follow-up)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
2026-09-28 09:28:37 +08:00
Jesse_ChenandClaude Fable 5.1 0bc6659052 feat(consult): open the response stream before preparation, reservation and classification; rejections ride the stream (T2, BUG-1074)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
2026-09-28 09:20:23 +08:00
Jesse_ChenandClaude Fable 5.1 3f8b817261 feat(consult): type out streamed text at a capped pace and write the tail out on settle instead of one frame (T3, BUG-1075)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
2026-09-28 09:14:46 +08:00
Jesse_ChenandClaude Opus 5.5 d79dada970 feat(ui): optional gender radio in the people form and 个人资料 (T2)
One ProfileGenderField (女 / 男 / 不填, 44px, one hint line) in the
people-archive edit form (saved with the form, 不填 → null) and in
设置 → 个人资料 for the owner (saves on its own PATCH; birth-data saves never
send gender). The detail card shows 性别 (未填 when empty). Not asked in
onboarding. DESIGN/VOICE updated; 390/1280 screenshots with fictional data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-27 18:30:58 +08:00
Jesse_ChenandClaude Opus 5.5 d2551437c4 fix(home): land on the blank starter home after login and on bare / (BUG-1052)
Product decision 2026-09-27 (D1-D4), overriding the BUG-1038 login-return
stash and the "latest session" default landing:

- A full load of / without ?c= (login, typed address, bookmark, refresh of
  bare /) lands on the current person's blank starter home; an existing
  empty draft of that person is reused, otherwise one is created locally.
- ?c= and ?new=1 are unchanged; a refresh inside a conversation keeps its ?c=.
- The login-return stash is removed: redirectToLogin and sidebar links no
  longer write it, bootstrap no longer reads it and clears a leftover value
  once. replace-selected, the lookup origin/other-subject branch and the warm
  resumeRectification dependency go with it.
- A background answer being recovered no longer takes over the blank home
  (same rule BUG-1015 set for ?new=1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-27 00:51:51 +08:00
Jesse_ChenandClaude Opus 5.5 3a66c39f48 refactor(rectification): split the chat component into hooks, parameter functions and blocks
Move-only (TASK-rectification-code-split-20260926 T1/T4). No behavior, API,
copy, DB, Skill or scoring change.

- rectification-agentic-chat.tsx: 2043 -> 737 lines; component body
  1625 -> 630; useState 35 -> 12, useRef 16 -> 9, effects 9 -> 5,
  useCallback 12 -> 6.
- Snapshot sync -> hooks/use-rectification-case-snapshot.ts; board layout
  and live label clock -> two small hooks.
- send / submitStructuredChoice / acceptCandidate bodies ->
  lib/rectification-chat-{turn,choice,accept}-run.ts parameter functions
  (bodies verbatim, deps destructured to the same names); copy/regenerate,
  question repair, pure transcript and snapshot helpers and the per-render
  view derivation -> lib/rectification-chat-*.ts (no React hooks).
- Question-gap blocks and the read-only range line ->
  components/rectification-question-gap-notices.tsx.
- Dependency arrays kept exactly as before (lint warnings +3, listed in
  PROGRESS); no dep added to appease the linter.
- Tests: whole-source contracts read tests/rectification-chat-surface.ts
  (container + split files, like home-surface.ts); slices of moved code now
  call the extracted functions or render the extracted block, each with a
  原值/新值/原因 comment. New tests/rectification-growth-contract.test.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-26 19:23:52 +08:00
Jesse_ChenandClaude Opus 5.5 da2613ffd9 fix(chat): attach scroll anchor when the scroller appears; only reader scroll releases a pin (BUG-1043, BUG-1044)
- 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
2026-09-26 10:42:12 +08:00
Jesse_ChenandClaude Opus 5.5 83cce7ad6a fix(chat): keep latest-turn actions under the reply (BUG-1042)
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
2026-09-26 10:19:00 +08:00
Jesse_ChenandClaude Opus 5.5 f04da1038b docs+fix(home): amend resumable hint to point at history (brief amendment)
- 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
2026-09-26 08:50:18 +08:00
Jesse_ChenandClaude Opus 5.5 638b6a60c0 fix(home): warm return to / without replaying the loading ring (BUG-1040)
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
2026-09-26 08:21:35 +08:00
Jesse_ChenandClaude Opus 5.5 0a8350cc01 fix(home): one new-chat intent and a scoped login-return stash (BUG-1038)
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
2026-09-26 07:23:50 +08:00
jesse-ux d08ffdc0a6 fix: keep western labels near their planets and chats on the current person
Independent Staging Quality Gate / validate (push) Failing after 6m46s
Independent Staging Quality Gate / publish (push) Skipped
Cap planet captions at 30 degrees with a third ring, fall back only within the current person's sessions, and load self when the people catalog fails.
2026-09-25 23:02:17 +08:00
jesse-uxandClaude Code 4d801e53c3 fix: integrate people archive, report reader and western chart corrections
Independent Staging Quality Gate / validate (push) Successful in 16m28s
Independent Staging Quality Gate / publish (push) Successful in 3m33s
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>
2026-09-25 20:41:16 +08:00
jesse-ux ab6c55f822 feat: keep up to five chart subjects on typed columns
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.
2026-09-25 04:19:05 +08:00
jesse-ux a94a1d6748 fix(sessions): keep rectification result titles when a new chat opens
The case insert trigger writes the result time, then the existing open persist sends the minted title back. A before-update guard keeps that result unless the user chose a non-automatic name, and a new session reads the stored title into the sidebar.
2026-09-25 02:04:56 +08:00
jesse-uxandClaude Code 651c75e7ad fix(staging): repair gate contracts and balance broadcast
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 22:02:26 +08:00
jesse-uxandClaude Code 1d1983b484 docs(home): record slow-network acceptance
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 18:22:44 +08:00
jesse-uxandClaude Code 25e32fe6fd fix(billing): remove redundant account bootstrap request
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 18:22:44 +08:00
jesse-uxandClaude Code 2f53fa0171 perf: streamline billing panel bootstrap
Remove the redundant billing account read, cache packages for one minute, prefetch the billing chunk, and parallelize independent package reads.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 18:22:44 +08:00
jesse-uxandClaude Code 1420471ab1 feat: add chart waiting states and report block exports
Independent Staging Quality Gate / validate (push) Successful in 10m34s
Independent Staging Quality Gate / publish (push) Successful in 3m36s
Add bounded chart loading, per-layer retry states, and shared SVG skeletons. Add report block downloads with SVG, localized metadata, and inline deletion.

Record verification and retain CRLF export, full-build, and controlled-device acceptance blockers. User authorized staging delivery with these gaps documented.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-24 12:33:09 +08:00
jesse-ux f77a1b5a33 fix(web): ignore a missing documentElement when marking the home screen revealed
Independent Staging Quality Gate / validate (push) Failing after 10m8s
Independent Staging Quality Gate / publish (push) Skipped
2026-09-22 13:42:36 +08:00
jesse-ux 2a3013f224 fix(chat): choose the chart person before the first message 2026-09-22 12:57:04 +08:00
jesse-ux cc7ef8a339 fix(chart): keep account and chart-view birth truth consistent 2026-09-22 12:14:50 +08:00
jesse-ux 337d820076 fix(web): recover the home screen when the bundle never runs 2026-09-22 12:13:17 +08:00
jesse-ux 5a4b87383f fix(web): retire session archive UI and API, restore archived rows
Independent Staging Quality Gate / validate (push) Failing after 6m35s
Independent Staging Quality Gate / publish (push) Skipped
Remove archive/restore from the session menu and drop archived=1 listing. PATCH still accepts archived_at from old bundles then ignores it. A forward migration clears archived_at without bumping updated_at. Delete stays unchanged.
2026-09-21 18:49:40 +08:00
jesse-ux e71e4f9200 fix(web): keep rectification sessions listed and persist chats on first send
Independent Staging Quality Gate / validate (push) Failing after 16m52s
Independent Staging Quality Gate / publish (push) Skipped
Empty-consultation filtering is now session_type scoped so birth-time rows stay in the sidebar. Subtitles use updatedAt with sort/group/cursor. New chats stay local until the first send.
2026-09-21 16:39:32 +08:00
jesse-uxandClaude Code 539d4daee4 feat(consult): add free model-classified smalltalk fast path
Independent Staging Quality Gate / validate (push) Successful in 9m35s
Independent Staging Quality Gate / publish (push) Successful in 3m52s
Keep full consultation tool contracts unchanged. Persist short replies and refund the original reservation atomically while recording actual model usage. Verify Linux frontend 3566/3566, database 40/40, Static home and gzip +0.0493%.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-20 12:58:34 +08:00
jesse-uxandClaude Code 2c92f6100e fix(frontend): isolate sidebar registration to unblock navigation
Separate shell subscriptions from Home session data and cover effect convergence, transition cleanup, current callbacks and signed-out fallback with real React lifecycle tests. Record baseline-equivalent local failures and outstanding browser/build verification.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-19 14:32:42 +08:00
jesse-ux 824ecff026 fix(web): 账户弹窗移出 inert;校正快照失败不再静默(BUG-968/969)
账户弹窗与入门付费墙 portal 到 document.body,SidebarInset 的 inert 不再罩住弹窗。
GET 校正快照每个非 200 打 JSON warn;客户端失败显示「这一问还没读到」和重新读取。
下一题是可渲染选择题时,确定性回复正文带题干,挂卡后去重。
2026-09-18 19:16:00 +08:00
jesse-ux 9ccb65b71f fix(web): 次级页稳定外壳与缓存预取,跨部署导航自愈(BUG-966/967) 2026-09-18 18:45:48 +08:00
jesse-ux 94c1e81fa9 feat(consult): 进度、思考、正文三通道在生成时分开(BUG-942/943/944) 2026-09-18 12:16:20 +08:00
jesse-ux db5b0a214b fix(web): 会话列表合同跟着外壳搬家,无活跃会话不再静默吞发送
Independent Staging Quality Gate / validate (push) Failing after 6m30s
Independent Staging Quality Gate / publish (push) Skipped
四条源码合同改到 (app)/layout 与注册载荷两端对断。列表只剩校正会话时普通输入框锁定,发送会打开校正或给出提示。
2026-09-17 23:06:01 +08:00
jesse-ux cc1a89802e fix(web): 无用户行钉顶、闲置不上留白,并修会话列表 tsc 两错
Independent Staging Quality Gate / validate (push) Failing after 6m27s
Independent Staging Quality Gate / publish (push) Skipped
2026-09-17 22:25:53 +08:00
jesse-ux 11c0028d59 fix(web): 回答从开头开始读,两个会话面同一套钉顶跟随
Independent Staging Quality Gate / validate (push) Failing after 6m26s
Independent Staging Quality Gate / publish (push) Skipped
2026-09-17 21:47:54 +08:00
jesse-ux e4e73f56c0 fix(web): 四个页面共用一份会话列表,空会话不入列
Independent Staging Quality Gate / publish (push) Canceled after 0s
Independent Staging Quality Gate / validate (push) Canceled after 9m33s
对话、星盘、星历、报告进同一 (app) 外壳,列表只拉一次。服务端不再列出空咨询;新建复用已有空会话。新标题改成「生时校正 · M月D日」,侧栏副标题用创建时间。
2026-09-17 21:27:40 +08:00
jesse-ux 6d81062be9 fix(web): 校正会话上不再出现可用的普通输入框
Independent Staging Quality Gate / validate (push) Canceled after 5m37s
Independent Staging Quality Gate / publish (push) Canceled after 0s
send() 对校正会话不发 /api/consult,草稿保留并打开校正面。
普通输入框只有禁用态。咨询接口把类型不对改成 409 session_not_consultation。
删除和回退不再直接切到校正会话。
2026-09-17 20:06:25 +08:00
Jesse_ChenandClaude Fable 5.1 d9d347236f refactor(ui): 侧栏统一成一个组件,次级页共享外壳,跳转不再整页刷新
BUG-744 / BUG-745 / BUG-746,任务书 TASK-sidebar-unify-20260916。

T1 侧栏只剩一个组件。`AppSidebar` 收编次级页那份另写的侧栏:会话操作与
账户菜单收进可选的 `controls`,不传就渲染只读模式。只读行仍是同一个
`SidebarSessionRow`、同一套 `.session-row > .session-main` 标记,只是
`.session-main` 是 `<Link>`、不渲染菜单按钮,并用 `data-readonly="true"`
去掉那一列从不使用的 44px 空位;页脚是同一个 56px `.profile-trigger`,
渲染成去 `/` 的链接。只读模式只少菜单按钮、chevron、账户菜单三样。
`app-nav-rail.tsx`、`use-nav-rail.ts` 与 `.nav-rail-*` 两段 CSS 删除。

T2 四个次级路由移进 `app/(secondary)/` 路由组,`layout.tsx` 承载
`SidebarProvider + AppSidebar(只读) + SidebarInset`。`SecondaryShell` 拆剩
46px 顶栏并改名 `SecondaryHeader`,14 处调用同步。路由组不进 URL,四个
地址与四个渲染标记均未变。

T3 `sidebar-data-cache.ts`:模块级、按账户 id 键、60 秒的内存缓存,同步读
再后台刷新,不落 localStorage。`use-session-management.ts` 的新建 / 重命名 /
删除 / 归档 / 收藏成功后失效,401 清空。

T4 三个页面项改 `<SidebarMenuLink href=…>` 客户端跳转,`persistLoginSessionReturn()`
保留在 `onClick` 里,`/login` 仍是硬跳转。顺带删掉从未被调用的死 prop
`onOpenReports`;它删掉后 `page.tsx` 的 `router` 再无消费者,`useConsultationRun`
里同样解构成 `_router` 的死参数一并删。

T5 折叠状态存 localStorage 的 `sidebar_state`(不用 cookie:`/`、`/chart`、
`/ephemeris` 都是 Static,服务端读 cookie 会让三条路由掉出静态渲染)。移动端
抽屉不记。整页加载首帧仍可能闪一下,属让步顺序第 1 条,写在 BUG-746 与真机清单。

`Home()` 的 useState 36 / useRef 37 均未增长,`page.tsx` 净删 1 行。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 11:23:11 +00:00
Jesse_ChenandClaude Opus 5 317e9f1886 fix(rectification): 顶栏被 focus 滚出视野——面板改 clip,面板内 focus 一律 preventScroll
Independent Staging Quality Gate / validate (push) Successful in 10m24s
Independent Staging Quality Gate / publish (push) Successful in 19m9s
产品实测:生时校正答了三题后 46px 顶栏消失。devtools 取证——栅格是对的
(rows "46px 1297px"、panel y=0),但 header 自己的 rect 在 **y=-88**:
面板被程序化滚动了 88px。

根因:`overflow: hidden` 仍然是滚动容器,它只是去掉了滚动条。
BirthTimeChoiceQuestion 在每答完一题后 focus 新题的第一个选项,浏览器
为把它带进视野会滚动所有可滚动祖先,`.chat-panel` 就是其中之一——
而用户没有滚动条可以滚回来,顶栏于是永久消失。

两处都修:
- 病因:面板内 7 处程序化 focus 一律加 { preventScroll: true }。
  消息区有自己的 useConversationScrollAnchor,本来就不需要浏览器代劳。
  账户弹窗的 closeButton / returnTarget 不在此列——那是对话框焦点管理。
  同一教训 use-billing-panel.ts 已经吃过一次(那里早写了 preventScroll)。
- 结构:.chat-panel 与 .chat-app 从 overflow:hidden 改成 overflow:clip。
  clip 根本不创建滚动容器,此后任何 focus / scrollIntoView 都无法位移它。

新增 tests/chat-panel-scroll-guard.test.ts:锁住两个容器必须是 clip、
面板内不得有裸 focus(),并遍历 rectification/birth-time/chat- 全部组件,
新组件再写裸 focus 会直接打红。

测试 3372(+3),fail 仍 31 且与基线逐条一致;四个路由标记不变。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
2026-09-16 08:56:07 +00:00