78f98eba changes the same-input rectification scores: Shadbala Sthana and Drik
feed the Shadbala auxiliary (BPHS Saptavargaja values, Moolatrikona 3 / 15 deg,
whole-sign Kendradi, BPHS 26 special aspects, Mercury with any malefic) and
jaimini.calc_arudha_padas feeds the event engine and feature facts. Per
BUG-1181 the algorithm identity moves rectification-v5-matrix-scoring-13 ->
-14. Policy v4, input contract v5 and the dated window contract (generation
>= 9) are unchanged; the SQL guard accepts scoring-(9|[1-9][0-9]+), so no
migration.
- Memoization golden v7 written by write_golden (source_commit 78f98eba); v6
stays byte-identical and is pinned by sha256. For this public request the
candidate scores are unchanged (12:00 8.5336, 12:01 8.5242, 12:02 8.088);
the Shadbala fingerprints, feature hash and candidate UUID moved.
- New scoring-14 cross-midnight golden from midnight_date_anchor_regression.py
--golden (baseline = this tree; independent-process A/B 3 x 7 fields equal);
scoring-13 golden kept as history and opens read-only with recompare.
- Dated-transitions scan unchanged (test passes without regeneration).
- v9EngineVersion() default and the identity tests follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
Astrologer ruling 2026-11-04 on #166; product decision the same day (Moon
option C, rulings implemented as given). The default is a named BPHS version;
the pre-#166 precise Sthana / Drik is kept byte-for-byte as variant
"raman_gbb" (Raman, Graha and Bhava Balas Ex. 13 / 55 still pass on it).
- Q3 (BUG-1581): the Moon's own Paksha is P on both sides (Sanskrit 27.11 lists
indu), Chesta = Paksha, total 2P. Drik still classifies a waning Moon as a
malefic (Q26), classify_drik_planets unchanged for the Moon.
- Q2 (BUG-1582): the Sun's Ayana is not doubled; Chesta = base Ayana; A + A.
On the VP Jain fixture Kala + Chesta = 46.73 + 35.07 = published 81.80 + 0.
- Q18 (BUG-1583, BUG-1575): Moolatrikona Moon Taurus from 3 deg, Mercury Virgo
from 15 deg, in shadbala.py and jyotish_engine.MOOLATRIKONA.
- Q16 / Q20 (BUG-1584): Saptavargaja 45/30/20/15/10/4/2, compound relation from D1.
- Q25 (BUG-1585): Mercury is a natural malefic with any natural malefic in its
sign (nodes not counted, recorded as an implementation choice).
- Q24 (BUG-1586): BPHS 26.9-12 piecewise special aspects replace the general
segment for Saturn, Mars and Jupiter; a single aspect stays within 0-60.
- Q21 (BUG-1587): Kendradi Bala by whole sign from the Lagna sign.
- Q27 (BUG-1588): jaimini.calc_arudha_pada_for_house takes the 10th from the
first-count pada (pada in the 7th -> 4th from the house), as special_lagnas did.
- Q30 (BUG-1589): D30 degree inside the sign is proportional within the
unequal span in varga.py; divisional_charts_extended uses exact 30/7.
- method_variants names every convention. Q22 edges and the Q24 60 cap are
locked in tests/test_astrologer_rulings_166.py (42 tests).
Raman / PyJHora comparison tests now run on "raman_gbb"; the VP Jain report
labels the new convention rows; chart-insight-golden.json's planets-only
Shadbala section regenerated from /api/shadbala. Rectification identity,
golden and re-freeze follow in separate commits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
FREEZE / REPORT constants first, --freeze, then replay: d30_venus_2026_11_04.
Contract rotated with previous = audit_wave2_2026_11_04 (kept byte-for-byte);
freshness test and frontend confirmation-gate test updated.
Versus audit_wave2_2026_11_04 (product accepted these costs 2026-11-04, no
tuning):
- sealed 20: 17 identical / 3 changed (case 5 rank 1 -> 3, case 18 12 -> 10,
case 14 reasons only); top_1 0.50 -> 0.45, MAE 6.65 -> 7.05; top_3 0.50 and
coverage 0 unchanged. All from the D30 table.
- reported offset 900: 650 identical / 250 changed; top-1 hits at
+-15/30/60 14/17/15 -> 4/3/0 of 300 (all from Venus roles); top-3 and
delivery coverage unchanged at every radius; mean minute error
19.79 -> 19.51 (from D30).
Attribution from single-fix replays on git-archive copies: D30 alone 3 sealed
/ 166 offset trials, Venus alone 0 / 108; they overlap only in case 20.
BUG-1560 and BUG-1570 resolved; ledger and CHANGELOG lines added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
18c685c4 changes the same-input rectification scores (varga.py even-sign D30
feeds health_pressure and feature facts v4; functional roles feed the
*_functional_*_auxiliary rules), so per BUG-1181 the algorithm identity moves
rectification-v5-matrix-scoring-12 -> -13. Policy v4, input contract v5 and
the dated window contract (generation >= 9) are unchanged; the SQL guard
already accepts scoring-13, so no migration.
- Memoization golden v6 written by write_golden (source_commit 18c685c4);
v5 stays byte-identical and is pinned by sha256. For this public request
the candidate scores are unchanged; the D30 feature (Capricorn -> Pisces),
its transition row and the feature hashes moved.
- frontend/tests/fixtures/rectification-dated-transitions.native.json: scan
regenerated from the real engine (D30 segment start Capricorn -> Pisces),
CRLF kept.
- New scoring-13 cross-midnight golden from midnight_date_anchor_regression.py
--golden (independent-process A/B 3 x 7 fields equal); scoring-12 golden kept
as history and opens read-only with recompare under scoring-13.
- v9EngineVersion() default and the identity tests follow.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
G (BUG-1560/1561: varga.py, divisional_charts_extended.py), H (BUG-1566/1567:
jaimini.py) and J (BUG-1270/1576: shadbala.py) each changed frozen identity
files and each froze its own audit_g / audit_h / audit_j record, which only
matches that branch's tree. Per ERR-110 the merged tree is frozen once as
audit_wave2_2026_11_04 (FREEZE/REPORT constants first, --freeze, then replay).
The contract now points at audit_wave2 with moon_paksha_2026_11_04 as the
previous record; the per-branch records are kept byte-for-byte and named as
intermediate in the superseded_reason notes. Freshness test and frontend gate
test updated.
Compared field by field with moon_paksha_2026_11_04: sealed holdout 20/20
trials identical, metrics unchanged; reported offset 900/900 identical,
summary unchanged; changed_trial_count vs 2026-09-20 stays 8 / 581.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Freeze contract, FREEZE/REPORT constants and gate tests keep the G state
here; the merged tree is re-frozen once as audit_wave2_2026_11_04 at the end.
H's audit_h records are kept byte-for-byte as history.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
BUG-1560 / BUG-1561 changed scripts/varga.py and
scripts/divisional_charts_extended.py, both in the frozen scoring identity.
Per ERR-110 new records were created with each script's --freeze and
replayed as audit_g_2026_11_04; scripts, contract, freshness test and the
frontend gate test point at them. Prior records are kept byte-for-byte.
Compared field by field with moon_paksha_2026_11_04: sealed holdout 20/20
trials identical, metrics unchanged; reported offset 900/900 identical,
summary unchanged; changed_trial_count vs 2026-09-20 stays 8 / 581.
(The D16/D20/D27/D45 and extended-module charts are not read by scoring.)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Data audit wave 2 (H) against PyJHora 4.8.6 and Swiss Ephemeris, 19 charts,
Raman and Lahiri passed explicitly to both sides.
- BUG-1566 (jaimini.py): the K.N. Rao Chara Scorpio / Aquarius lord read both
co-lords' dignity in the dasha sign itself, so Scorpio was always Ketu and
Aquarius always Saturn. Now one lord in the sign gives way to the other
(K.N. Rao; Rath p.43 (c); PyJHora); otherwise compared where each stands
(companions, Jupiter / Mercury / dispositor, dignity, modality, degrees).
MD years vs PyJHora 212/228 -> 225/228 (Raman), 226/228 (Lahiri).
- BUG-1567 (jaimini.py): K.N. Rao antardashas now run each MD's own
direction with the MD sign last (pp.35-36); book order 19/228 -> 228/228.
- BUG-1565 (gulika.py): Wednesday-Saturday night share table started one lord
early; Maandi and the four other time-segment points 79/114 -> 114/114
against an independent Swiss computation. Gulika unchanged (19/19).
- BUG-1568 (jyotish_engine.py): natal Panchanga vara / hora used the civil
date; a birth before sunrise belongs to the previous weekday (15/19 -> 19/19
vs PyJHora drik.vaara).
Narayana (legacy and Rath), transits, sunrise and day/night: no defect; the
second-cycle rule matches PyJHora's. Variants are listed in BUG_HISTORY.
jaimini.py is in the frozen identity: per ERR-110, new records frozen and
replayed as audit_h_2026_11_04; contract, freshness test and frontend gate
test rotated. Versus moon_paksha_2026_11_04: sealed 20/20 and reported offset
900/900 identical, metrics and summary unchanged. Chara sections of two
frontend fixtures and the rashi-dasha PyJHora fixture's native rows updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
The precise path doubled the Moon's Paksha in Kala (Raman, Graha and Bhava
Balas §55(c)) and then took that doubled value again as her Chesta (BPHS
27.18), so her Paksha entered the total four times; Chesta could reach 120,
clamping Kashta to 0 and pushing Ishta past 60. Every surveyed source
counts 2P.
Product decision 2026-11-04: BPHS (Santhanam) 27.10-11 + 27.18, as in
saravali.github.io, Maitreya8 (default) and jyotishyamitra. The Moon's
Paksha is the folded base, not doubled; waxing Moon benefic, waning Moon
malefic (BPHS 3.11, already what classify_drik_planets does, unchanged);
Chesta = Paksha. method_variants.moon_paksha names the convention. Other
planets, Drik and the legacy calc_kala_bala path are unchanged.
shadbala.py is in the rectification frozen identity, so per ERR-110 new
records were frozen and replayed as moon_paksha_2026_11_04. Compared field
by field with data_audit_2026_11_04: sealed holdout 20/20 and reported
offset 900/900 identical, metrics and summary unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Each domain house row on the consultation evidence card now carries
sav_strength: the raw SAV of the house's sign as 强 / 中 / 弱, never the
bindus. The band is the chart page's savBand (>= 28 强, 25-27 中, <= 24 弱),
sourced from references/ashtakavarga-complete-system.md §三 and the same
cut-offs as scripts/ashtakavarga.py sav_assessment (SAV_BAND_SOURCE).
A missing or mismatched engine row leaves the label off and lists a gap.
The system prompt's card description names the field in one clause.
Shadbala stays off the card (engines disagree).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
BUG-1545 (scripts/narayana_dasha.py, scripts/active_rectification_event_engine.py)
and BUG-1546 (scripts/shadbala.py) changed files in the frozen scoring
identity, so the integrity gate went red. Per ERR-110, new records were
created with each script's --freeze and replayed under the label
data_audit_2026_11_04; the scripts, contract, freshness test and frontend
gate test now point at them, following 129313e1. Prior records are kept
byte-for-byte.
Compared field by field with the d60_mapping_2026_10_29 records:
- sealed holdout: 20/20 trials identical; metrics unchanged.
- reported offset: 898/900 identical; 2 trials changed true_rank only
(one case, radius 60, offsets -30/-20: 76->67, 80->77). Top-1,
minute error, delivery coverage and summary are unchanged. Reverting
only the BUG-1545 files restores the old ranks; reverting shadbala.py
does not; a different PYTHONHASHSEED gives the same result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
The writing rules were only a slice of the agent's input; the rest pulled
answers toward a report. Product approved six cuts (2026-11-04):
1. Chat tool results no longer carry the router's English "Shared
mandatory baseline" (degrees, nakshatra, MEVG, case calibration, A/B/C
labels for every reading).
2. Checklist wording the model read aloud: house-counting is for judging
only; "双体星座" becomes the four sign names.
3. The bound skill excerpt keeps only the truth-boundary paragraph (KP /
Muhurta table, Ashtottari, P0/P1 list and three-layer method dropped;
marker kept).
4. The reference_transparency block goes: the card never carries it.
5. English rules that restated VISIBLE VOICE go; "keep conclusions
conditional" becomes "never call it verified, but say plainly what the
chart shows".
6. The rectification offer rule is the offer tool's description instead of
riding in every user turn.
Parents backtest: unglossed terms 16 -> 11 (std) and 25 -> 11 (verbatim
question); no absent parent written as present or involved.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Product 2026-11-04: grounds may be listed in full as long as each one says
what it means; the "can't tell distance from friction" range is said once
per answer (merged when both parents are heavy). Backtest: answers repeating
the range 11/18 -> 6/18 (std) and 6/9 -> 1/9 (verbatim question); unglossed
terms 33 -> 16; still no absent parent written as present or warm.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Backtest (parents, 9 Rodden AA figures, blind-scored) showed the slim voice
wrote absent parents as present and warm (severe 0 -> 8, then 1 -> 5) once
the presence range was gone. Product chose the hybrid: when a person's line
carries heavy pressure, give the range once in the model's own words and
write no portrait of that person's conduct or warmth on that side.
Hybrid round: severe 3 -> 0 (std), 2 -> 0 (correction), 4 -> 2 (verbatim
question); closing asks 26/26 -> 3/27; control false positives unchanged.
Also: correction turns say which line was off and never blame the user;
jargon and varga codes are said in plain words; house-counting is a named
ban; no mind-reading when the user asks for objectivity.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
The parents answer read as house-by-house fact chains with a gloss on every
house, opened with "both lines show pressure" instead of the pattern asked
for, and copied the example's 「实际是哪一种,告诉我一句」. The model was
satisfying ~13.9k characters of writing rules stated three times (voice,
English contract, user turn) plus copyable Good/Bad examples.
- VISIBLE VOICE is now the single statement: follow the user's own
structure, open with the overall picture, explain why each placement
means what it means, gloss terms briefly; then the red lines only.
- Contract and first/follow-up user turns point at it instead of
restating it; all example answers removed.
- AFFLICTION_RANGE_RULE keeps the red line (no biographical verdicts, no
reverse reassurance) but drops the forced range and closing ask; the
question's own premise counts.
- Contract tests cap the voice at 2600 characters and lock every red line
the old tests guarded; backtest script gains --question.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
- proxy.ts: no session cookie on `/` → 307 /login before any page code, so the
shell and 正在载入账户 no longer flash first
- login: segmented tabs fill the width and fit their track; six code boxes
span the form like the email field
- /rectification: drop the 先核对一下资料 step; every button sits in one row
at the card's foot instead of one inside and one below
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
Empty or short input is one pill row (64px desktop / 56px phone, radius
999): 常用问题 | field | 40px send (44px target). Once the text wraps in
the single row or contains a newline the form gets .is-expanded: the
leading slot on top, the field at full width, send bottom right, radius 24
(22 on a phone). The field grows to 6 x 26px = 156px, then scrolls inside
(.is-capped, overflow-y auto) with a currentColor mask fade at the top
when scrolled (.is-scrolled). Focus tints the border and adds a 3px
action-soft ring. Send is canvas-muted / ink-tertiary while there is
nothing to send, action-fill once there is; stop is unchanged.
The switch is decided from the real textarea (composer-layout.ts):
expand as soon as the single-row content exceeds one line; collapse only
when the text has no newline and fits the single-row width with 16px to
spare (hysteresis). No change during an IME composition; it settles on
compositionend. Only classes on the <form> change and the DOM order
(leading slot, field, send) is fixed, so focus, caret and the preset
fill's (…) selection survive. Same component on the starter, in a
conversation and on the rectification surface.
Tests: new chat-composer-single-row-20261103.test.tsx (11); three existing
assertions updated with 原值/新值/原因. DESIGN.md composer section,
CHANGELOG and the pre-work ledger updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
- Two half-width entry bars (76px, 72px stacked on phones): icon square,
title, one ellipsized line, right-side button. 生成报告 is the pale
accent (action-soft fill, action text, 600), 40px visual / 44px hit;
打开年运 is a bordered link. Phones show 生成 / 打开.
- 过往的报告: 共 N 份 only when every page is loaded; 刷新 removed, the
failed-read alert keeps 重试.
- 64px rows with hairlines; the whole row links to the report (generating
opens its progress); type icon (FileText / Sun / Heart), title, meta
(date · depth · themes, annual date only, failed rows show the failure
summary), plain status text by colour. ⋯ delete menu is a sibling of the
link. Phones drop the icon and the year.
- Signed-out / empty / failed states follow the same language; no large icon.
- Entry CSS moved from annual-report.css (off-allowlist 720px cut) to the
global 767 cut. Depth labels: DB only allows the four labelled values;
the raw "full" came from the screenshot mock, not a product bug.
- Tests: new reports-page-option-a-20261103; updated assertions carry
原值/新值/原因. DESIGN.md and CHANGELOG updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
The not-started card no longer leaves its button row empty. That reserved
44px row now reads 「来源 <source>」 with the intake's short source names
(issue #144, birthTimeSourceOptions labels), and, when an earliest / latest
range was given, 「你给的范围 HH:MM–HH:MM」 beside it (wrapping to a second
20px line on a narrow phone, still inside 44px).
- rectificationDeclaredFacts: clock sources use the declared earliest /
latest, or the pre-#144 minutes either side of the stated time; period and
shichen use their clock range; 不清楚误差 gives the source only; unknown,
legacy_import and family_exact say nothing (the row stays empty).
- The range given is drawn as the band on the ruler (same pale-accent
style) with the reported tick on it, and the ruler's range rule treats it
as the window; the legend adds a band swatch with 你给的范围.
- Card heights are unchanged (244px / 234px measured, pending equal).
Tests: none state with a range, with 不清楚误差, and with no usable source
(unknown, legacy import); the lib cases for all six sources, the minutes
fallback across midnight, and the ruler including a 23:00–03:59 range.
The earlier none-state test assertion is rewritten with 原值/新值/原因.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
The /rectification status card follows the product owner's approved option A
(时间尺), with the requested change that the two buttons are separate:
- The card no longer repeats the person and 本人; the header chip shows them.
- Status row (还没校正过 / 上次没做完 / 已采用) with 已收 N 件大事 or the
done note on the right; one big tabular time; a ruler with the current
window as a pale-accent band, the reported time as an ink tick and the
adopted time as an accent dot; a legend line.
- The ruler range comes from the data (rectificationRuler): the window, else
the adopted or reported time, about half an hour each side, at least two
hours, snapped to half hours (whole hours past four hours); a window whose
end is before its start crosses midnight. Missing data hides the ruler,
band or tick; never NaN.
- In the card only the action on this record (继续上次 / 查看结果), bordered.
Below the card, on its own, one pale-accent button for a new case
(开始 / 新建一次 / 再校正一次). Full width on phones. No solid clay button
left on the page; the check step's 开始校正 uses the accent too and the
close-failed note sits beside it. The 新建一次 flow is unchanged (BUG-1516).
- Summary and pending cards share one measured height (244px desktop, 234px
phone) and the outer button row is reserved, so nothing moves when the
summary lands (BUG-1528). Message states use the same card and pattern.
- Tokens and color-mix only; 44px targets.
Tests: new rectification-entry-ruler-20261103 (ranges incl. 23:40-00:20 and
missing data, band/tick/dot positions, in-card vs outer buttons, no person in
the card, token and 44px rules); loading-shell card-size assertion rewritten
with 原值/新值/原因. DESIGN.md, CHANGELOG and the pre-work ledger updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Brings in the shell fixes (BUG-1532, BUG-1533). CHANGELOG, BUG_HISTORY and the
pre-work ledger conflicted only where both sides appended; both kept.
globals.css merged cleanly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
- Popover collision: side "shift", align "shift", fallbackAxisSide "none",
padding 4 top / 8 elsewhere. Short of room (a window ~800px tall) the
panel shifts down inside the viewport and ends at the trigger instead of
falling back beside it. Measured in Chrome at 1280x800, 1280x860, 1440x900
and inside a conversation.
- Tests: the note only in its own domain, no hint line under titles, and the
caller's hide conditions (synastry, rectification, incomplete profile) and
first-blank selection unchanged.
- docs/testing/consult-preset-menu-20261102.md rewritten for the pill, the
two-column panel (hover, keys), the phone chips and pick-fills-not-sends.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
The 432px panel fitted neither above nor below the composer in a blank new
chat at 1280x860, so Base UI fell back to the trigger's right and covered
the input. The panel is now 404px (nav gap 0), and the Popover only flips
between top and bottom (fallbackAxisSide "none", collisionPadding 8). The kit
PopoverContent passes collisionAvoidance / collisionPadding to the positioner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
BUG-1532: SecondaryPageShell's default person entry was the one-line
inline switcher; only /chart passed variant="chip". The shell now
defaults to the chip, so /rectification, /ephemeris, /reports, /people
and /annual show the approved two-line chip (avatar initial, name, 本人,
date time · place, chevron; popover on desktop, drawer at <=640px,
「选择星盘」/「共 N 人」). The rectification page's own logic is unchanged.
BUG-1533: until Home registered (it waits for the account) the layout
fell back to "chat-panel secondary-panel" on "/" too. That painted the
pane --color-canvas-soft under the transparent starter composer while
.conversation stayed --color-canvas (the seam), and made Home's chart
frame, which holds the header, an overflow-y:auto box. The fallback is
now path-based (shellInsetClassName): Home gets chat-panel, other routes
chat-panel secondary-panel. Sidebar hover and the waiting 新建对话 row
use a half wash so only the current row carries the full one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
- Trigger: a 32px bordered pill with a Sparkle and 「常用问题」 replaces the
36px action-soft disc; 44px hit area via ::before; same on phone.
- Desktop: fixed 600x432 Popover, a 168px nav of all 12 domains (kit vertical
Tabs; hover 80ms or arrow keys select) beside the current domain's five
questions. No chevrons, no serif title, no inner scroll.
- Phone: fixed-height Drawer with a 15px/600 title, a sideways row of 36px
domain chips and five 52px rows with hairlines.
- BUG-1534: the domain list scrolled inside the popup, and two rows were
tinted at once (hover tint plus a background fade). One .is-active row now,
no fade.
- Prompt data and wording unchanged. Tests, DESIGN.md, CHANGELOG, ledger.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
- Reuse the loaded chart view and its layers from the module cache for
5 minutes (same as the server engine cache): returning to /chart, the
chat natal panel and the sidebar hover read make no request. Dropped on
fingerprint change, invalidate, person/account switch and sign-out.
- Birth-sky data is remembered the same way (account + person + fingerprint).
- Layer reads get their own limiter bucket (chartViewLayer 60/min); base view
stays 20/min, birth-sky 20/min. Throttled replies carry retryAfterSeconds
and Retry-After.
- Throttled base view keeps the workspace skeleton, shows the line once with
重试, and retries after the window; throttled layers retry after the window;
throttled birth-sky keeps the entry pending and retries.
- Layer reads no longer run the heavy ascendant precheck; a late D1 refresh
keeps ashtakavarga and points (BUG-1531).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Run 6477 showed the frontend step was a queue: ~46 fixture files shared 2
slots, so DB tests spent 100-330 s each waiting. The runner has 20 CPUs and
61 GiB; BUG-281 measured ~22 usable Docker networks, so 6 per gate keeps two
concurrent gates under the pool. Local runs keep the default of 2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
Each step opened about six SSH/SCP connections to the staging host before
the real work (~60 s before docker login). A ControlMaster connection in a
short private /tmp directory now carries them and is closed in cleanup.
Host-key pinning and batch mode are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
Review of the redesign screenshots: with one seed the face is the same light
tone in all eight palettes, so 32px avatar previews read as eight identical
faces. Each swatch now draws its five colours. The menu highlights its first
item on open, which on the identity row looked like the removed grey card;
hover and keyboard focus still show.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Settings modal:
- 72px header with the one title 「设置」 and a transparent 44px close;
184px nav + 1fr, 24px gap, no divider; current pane in the pale accent.
- Sections 32px apart with one hairline, 16px/600 body-face headings.
- 账户头像: 64px avatar beside 换一个形象; eight swatches in one row, each a
44px target with a 40px ring previewing this avatar in that palette.
- 账户信息: two 52px rows, 96px labels, no 名称同步 caption.
- 外观主题: one 420px segmented track (theme-preference-segment); the
ayanamsa options get their original theme-preference-option look back
(the previous commit had restyled that shared class).
- 注销账号: one 44px row with a borderless danger-text 「注销…」.
- Phone: full screen, 56px header, 3-segment label-only nav, 16px inset,
4x2 swatches; no inner scroll at 390x844.
Avatar menu: 264 wide; the identity row opens 个人资料; balance on
账户与点数; no chevrons; 外观 as three icon radio segments named by
aria-label; 退出登录 not red; 44px legal links.
DESIGN.md, CHANGELOG and contract tests updated (原值/新值/原因).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
Staging loading report, 2026-11-03.
- Sidebar (BUG-1526): 生时校正 / 婚恋合盘 rows follow the product registry
default until the account has been read; only an account that says off
hides them, so rows are no longer inserted mid-list. The shell commits the
account as soon as it is read (loadSessionList onAccount), ahead of the
people list and the sessions. 「最近」 reserves an empty fixed-height block
while the sessions are read instead of a line of copy (no skeleton).
- /api/account GET: avatar columns ride on the first profile select; profile,
membership, admin check and both product flags run in one Promise.all.
- loadRuntimeFeatureFlags caches per key, joins in-flight keys and batches
same-tick single-key calls into one query (parallel calls no longer evict
each other).
- GET /api/sessions (BUG-1527): page and pinned queries run in parallel. The
messages <> '[]' filter was measured on a local PG16 with synthetic data
(EXPLAIN ANALYZE: ~0.7 ms -> ~0.1 ms warm, ~2-3 ms -> ~0.2 ms cold buffers
per query); not worth a production schema change, so no migration.
- /rectification (BUG-1528): gated only on the account (plus the people list
for someone else); the intro, person line and a fixed-height status card
slot paint at once and only the card fills when the summary lands. The
first summary read joins Home's in-flight read or the HTML early read
(/rectification added to BOOT_READ_PAGES); Home's warm-snapshot summary
seeds the card and is revalidated. shell-motion NAV gains /rectification.
- /synastry (BUG-1529): open/closed comes from the shell account
(registry default until known); people and balance come from the shell; the
price and the history are read at mount without the setTimeout tick and
fill in on arrival; 开始合盘 stays disabled until the price is known.
/api/product-access runs its flags, catalog and prices in parallel.
Tests: new loading-shell-20261103 and loading-routes-20261103; every changed
assertion (six files) carries 原值/新值/原因 comments. BUG_HISTORY, CHANGELOG, DESIGN.md
and the pre-work ledger updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
- Split `validate` into `validate-python` and `validate-frontend`; publish
needs both. Runner capacity is >= 2 (publish and migrate already overlap).
- deploy/ci-python-venv.sh: venv kept under /root/.cache keyed by Python
version, ISO week, pins and requirements; persistent pip cache. A fresh
venv per run spent ~3 min re-downloading the same wheels.
- npm ci gets a persistent download cache and --prefer-offline (every one
of 1,010 packages was a cache miss).
- publish builds and pushes the API and web images concurrently; the web
Dockerfile mounts BuildKit caches for npm and .next/cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8