Hide engine branding, gate supported divisional columns, align house cells, and add accessible symbol help. Reduce desktop chart width and stabilize the waiting slot.
Validated with 78 browser checks and 87 focused frontend tests. Full suite retains 29 identical baseline loader failures; no new failures.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Once the discriminator training gate is open, only choice cards are asked
and the range card goes out when they are exhausted; targeted lines, their
re-ask and guided windows no longer hold the card or invite more events.
Delivery body says how many choice questions were used instead of the event
fit percent; narration names an excluded cluster instead of "range
unchanged"; a delivered turn no longer carries a collect question.
Offline replay (v4, 3 radii x 2 directions): truth in range 20/20 in every
cell; guided-window injections give the same width in truth and opposite
directions, so red line 1 was revised by product to truth-in-range only.
Skill 10.0.31 -> 10.0.32 (10.0.31 kept as deprecated for pinned cases).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
「我的报告」 starts at 报告记录: the supporting paragraph and the overview
line are gone. CHANGELOG, DESIGN, the real-device checklist and PROGRESS
for TASK-self-edit-avatar-menu-20260928.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
Off / the footer was a plain link home. It is now the same Menu.Root
everywhere; off / its dialog entries link to /?account=<dialog>, which
Home opens once its account is ready and drops from the URL.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
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
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
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
Product decision A (TASK-birth-sky-followup-20260928):
- every generation path writes subject.birthFingerprint (stored-row
fingerprint, same function as the chart page's profileFingerprint);
never into the evidence bundle the model reads
- GET /api/reports/:id compares on the server and returns only
report.coverSubject (subject id or null); legacy reports never get one
- report page shows the night cover above the body, paper cover alone on
the first printed A4 page; silent on any failure, no waiting state
- TS / JSON schema / Python contract accept the optional field
- BLOCKED T5 struck through; DESIGN §17, CHANGELOG, checklist, PROGRESS
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
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
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
- --font-display leads with "Jyotisha Serif SC", then exactly the body
sans stack; no system 宋体 or generic serif (BUG-737 guards kept).
- serif-sc.css imported from site-styles.ts beside globals.css (root
layout also serves admin); swap, no preload.
- Long-form report title (.personal-report-md-article h1) takes the
heading face; deliberate sans headings pinned by a new contract test.
- font-stack-loadable-contract: loadable now includes self-hosted
@font-face with existing files; "no CJK serif" replaced by
"leads with Jyotisha Serif SC, never a system 宋体" (brief T3).
- DESIGN §3, BUG-737 note, CHANGELOG, device checklist, PROGRESS.
TASK-serif-headings-20260928 T2-T5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
Renamed, sliced subset of Noto Serif SC SemiBold (OFL 1.1, noto-cjk
Serif2.003) covering the 6500 level-1 + level-2 characters of the
通用规范汉字表 plus Latin, punctuation and common symbols.
- scripts/fonts/build_serif_slices.py: fontTools subsetting into 30 woff2
slices + serif-sc.css (@font-face, weight 500 700, font-display swap);
byte-identical output for the same input.
- Frequency order (char_order.txt): repo corpus top 300, then Google
Fonts SC frequency bands (nam-files, Apache-2.0), then corpus count;
unranked characters sliced by contiguous code point.
- tests/test_serif_font_slices.py: coverage, no overlap, files exist,
120 KB cap; added to the quick quality gate.
TASK-serif-headings-20260928 T1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
Drop the unlayered button { color: inherit } that beat every layered Tailwind
text utility; scope the raw-button disabled fade away from <Button>. Add the
--color-action-fill token pair (light #fbfaf7 on #a9583e 4.85:1, dark #f2f0ea
on #8f4a33 5.77:1) for <Button> default, .button-primary, composer send/stop
and the calendar's selected day. Remove the BUG-1078 report-only override.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
The generate button renders in SecondaryPageShell's actions slot, outside the
report roots, so while submitting it still got the global 45% fade. A
report-owned `report-center-generate` class brings it into the disabled rule;
SecondaryPageShell and button.tsx unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
T6: offer True Citra and Fagan-Bradley beside Raman/Lahiri/KP/True Pushya,
engine-supported values only; widen profiles_ayanamsa_check by an additive
migration; ephemeris note names; path tests so no new value falls back to
Raman.
T7: the unlayered `button { color: inherit; }` beats Tailwind's
text-primary-foreground, so solid report buttons showed page ink (light
(light 4.85:1, dark 5.77:1), grey disabled without fade, neutral selected
preset. button.tsx and theme tokens unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
- Voice: contrast limited to chart structures; drop 「这句我按『……』理解了」; forbid motive/need sentences; yes/no answered first (BUG-1070)
- Follow-up turn (session already holds an answer): ≤200-char direct answer, no skeleton; decided from stored history, no intent regex; tool still runs each turn (BUG-1071)
- Thinking bar first section 「先回答你问的这件事」 (BUG-1072)
- First turn: opener without actions, body headings 盘里支持 / 时间怎么看 / 这周可以做的一件事 only, actions once, ≤900 chars (BUG-1073, D8)
- Checklist is a list to check, not paragraphs to write (T3)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0199rbQDTsUbCVw84wc8BTFe
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
The marriage evidence card's gender field is the bound subject's own value
(女 / 男, 性别未知 when not filled). The condensed checklist keeps the
gender-unknown rule only when unset; otherwise it names the spouse
significator per strict-workflow-router.md §4 and the repo's gender
interpretation contract (supplement only, core stack gender-neutral). The
methodology cache is keyed by gender so one person's line never serves
another. Tests drive the real getJyotishAgent with a prompt-recording model.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
Additive migration: nullable profiles.gender / chart_profiles.gender with a
female/male CHECK, owner-only via existing table RLS, column grants mirroring
the neighbouring birth columns (service_role for the account PATCH, no
admin_runtime). Account PATCH/GET, people POST/PUT/GET, subject resolution
and the consult route carry each person's own value; a people write only
touches gender when the key is sent. DB test runs in the gate's DB job.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
TASK-consult-evidence-card-v2-20260927 T4 (方案 B). Career, marriage and
wealth hand the answer model a 5-7 line condensed checklist
(frontend/src/lib/consultation-condensed-checklist.ts) in place of the full
strict route plus event-judgment file: must-see items (all on the card),
the three layers (接触 / 结构性机会 / 公开落地; 心动接触 / 关系成对 /
社会法律落地; 挣钱机会 / 真实增长 / 到账变现), the forbidden statements
(5L 大运 ≠ 法律婚, 金星过本命月 ≠ 心动月, Punarphoo 不得写成结婚,
土星回到本命月是观察项), the gender-unknown rule, and the lookups (KP
blocked). The shared baseline still travels; timing / health keep their
full router sections; the router, the event-judgment files, the bound
system method and the skill are unchanged (no skill version change).
Only the consultation tool builds the methodology, so reports and other
surfaces are unaffected (source test).
Single-domain model-visible size, 3 public AA charts x (10 questions +
annual + timing): career 9.8K, marriage 10.5K, wealth 9.9K, annual 11.5K,
timing 11.3K; all <= 12,000.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
TASK-consult-evidence-card-v2-20260927 T3. Card version evidence-card-v2.
- Base section (every card): the engine's D9 summary (D9 lagna, each
planet's D9 sign and dignity, Vargottama, D1/D9 reversals); D9 houses and
aspects stay out.
- Career: + AL (engine pada A1), 10H SAV, SAV of the Jupiter / Saturn
transit signs.
- Marriage: + 5H / 5L, day / night, Punarphoo (observation_only), Double
Transit on 7H / 7L (house-7 run) and DK / UL, Vivah Saham, gender unknown.
- Wealth: 8H / 12H named.
- Annual: the annual Tajika chart verbatim (parameter_sensitive), or
年盘未接入 when the pack is blocked / not attached (never natal data);
houses 1 + running / next AD lords' houses + the year's Jupiter / Saturn
transit houses, with their basis; ingress / station dates only.
- Timing: Rahu / Ketu with ingress dates, Jupiter / Saturn SAV and BAV,
Double Transit conclusions (no degrees); vargas follow the turn's other
domain, D9 when alone.
- Chara Dasha leaves every card; KP is never on a card. The lookup enum adds
karakamsha, dispositor_chains, inter_chart_linkage, argala, moon_transit;
a KP lookup travels with its blocked note.
- System prompt and tool descriptions name the D9 summary, the
parameter_sensitive / observation_only tags, 年盘未接入 and the lookups.
- Telemetry card version / agentVersion bumped to v2 (three-column notes in
the touched tests).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
TASK-consult-evidence-card-v2-20260927 T2. toAgentConsultationContext carries
chart.consultation_native_layers as local_layers.native_layers; toModelOutput
projects d9_summary / punarphoo / vivah_saham / day_night into the natal card
and slow_transits / double_transit / annual_tajika into the timing card, each
through its own nested-key allowlist (as BUG-1054 did for Narayana), so the
existing natal and timing key sets are not widened and the depth / list caps
are unchanged. Pada A1 (the engine's Arudha Lagna) is allowlisted for the
career card's AL.
Golden test: every projected layer equals the engine layer value for value on
3 public AA charts (family, timing and annual routes); the Double Transit
per-house summary line is the only field left out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
T6 of TASK-rectification-grounding-20260927.
- skill-slice.ts: per-action slice rule as a code constant, keyed on heading
titles (evidence: 「ConversationFocus 与意图承接」「批量证据与日期真实性」, i.e.
§5/§7 of the 10.0.x layout); other actions and any bound Skill without those
headings (9.0.0) get the whole body, so historical Cases still run with their
exact bound Skill (BUG-621).
- The rectification Agent declares providesSkillDiscovery "on-demand"
(rectificationSkillBoundProcessor): no <available_skills> block with a temp
path and no "call the skill tool" system message; getSkill still loads the
bound package.
- Measured on a real Agent + recording model (public AA case, estimate = CJK
chars + other chars / 4): fixed overhead per call 12,002 → 6,471 tokens
(step 0: 8,440 → 2,909). Skill text unchanged; no version bump.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
T5 of TASK-rectification-grounding-20260927.
- rectification-offer-candidates returned the full projection (~100 KB on the
public AA case: *_pre_inference, 31 KB contrast packet, probe lists). It now
returns the compare stripping (offerModelProjection); 100,012 → 28,799 bytes.
- agentVisibleLatestProjection also drops engine_indistinguishable_width_minutes
(audit-only since BUG-593), keeps the verification Markdown once
(skill_verification_report; range_delivery.verification_markdown was a
byte-identical copy) and shows the slim candidate list.
- Receipt fingerprints stay over the full payloads; the case API projection
(latestResultToolProjection) is unchanged.
Contract tests on a real local engine response (public AA chart).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
T3 of TASK-rectification-grounding-20260927 (red line 3).
The turn-decision read-case is the model's only conversation memory; with
about 7+ candidates (9 in the public AA case) it exceeded 6 KB and cleared
recent_turns and relevant_evidence_summary first. Candidates in the
model-visible inference now carry time / score / status / cluster_range only
(the last round names candidates by time), candidate_summary.candidates (a
duplicate) is gone, and over budget the order is: drop cluster ranges → keep
the best six candidates → shorten turns/evidence → clear them. Stored
inference and receipts are untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
T2 of TASK-rectification-grounding-20260927 (product decision P1).
The rectification 「重试(重新生成)」 was a blind agent.generate rewrite that
persisted unchecked text (invented range / fit rate reproduced). Removed:
the regenerate route, regenerate-turn.ts, the regeneration agent and its
read-only tool set, the client regenerate action/state and the
regenerating/canRegenerate props. ChatMessageActions renders the regenerate
button only when onRegenerate is passed; ordinary consultation is unchanged.
The DB function regenerate_agentic_rectification_turn is kept (AGENTS §7.6,
retire in a later round). DESIGN.md / VOICE.md updated; source-contract
tests follow with 原值/新值/原因 notes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8