Commit Graph
3693 Commits
Author SHA1 Message Date
Claude f91608244a merge: upstream sync 10 into the data audit branch
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y

# Conflicts:
#	docs/BUG_HISTORY.md
2026-11-04 12:41:54 +08:00
ClaudeandClaude Opus 5.5 80c3763fc4 chore(backtest): CONSULT_BACKTEST_GOLDEN swaps in a regenerated engine capture
Lets a before/after engine comparison run side by side without overwriting the
tracked fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:33:32 +08:00
ClaudeandClaude Opus 5.5 1c69c1b7e2 fix(chart): chart-page Shadbala takes the precise path readings use (BUG-1548)
The chart API called calc_shadbala without a context and so used the
simplified fallback, and it rewrote `degree` as the in-sign degree, which the
precise Dig bala reads as a longitude. Readings and reports took the precise
path, so the same chart showed different strengths and a different strongest
planet (Jobs: Moon 10.61 vs 6.61 Rupa). The endpoint now builds the same
context as cmd_shadbala and passes absolute longitudes; a test locks the two
equal per planet. Also records the astrologer's ruling on waning-Moon Paksha.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:33:23 +08:00
ClaudeandClaude Opus 5.5 7dcf8112ad fix(saham): natal Vivaha Saham uses the shared day/night rule (BUG-1547, upstream 26d5a52d)
The natal marriage point was hard-coded to Venus - Saturn + Asc with no
zodiacal-order exception, while the annual Tajika point already followed
references/saham_rules.json (PVR Table 74: night reverses the operands, plus
the +30 exception). The same night-born person had two marriage points; 6 of
the 9 public charts move. The full reading, the vivah-saham command and the
consult card now share tajika._formula_saham_trace, with day/night from the
card's own day_night evidence. 0 deg Aries is no longer "missing".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:23:21 +08:00
ClaudeandClaude Opus 5.5 9cd1e35f94 fix(shadbala): fold the Sun-Moon elongation before Paksha bala (BUG-1546)
abs(Sun - Moon) / 3 was never folded to 0-180 degrees, so on charts whose
raw difference passes 180 benefics got more than 60, malefics went negative
and the doubled Moon passed 120 (Monroe's Moon -45.76; 5 of 19 benchmark
charts). PyJHora has the same line, which is why the comparison agreed.

Same audit, no code change: the +/-60 Kala gap is PyJHora's hora formula;
PyJHora is the outlier on Mars/Jupiter/Venus Chesta; Sun/Moon Chesta is a
school difference. Shadbala totals stay off the card until those settle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:14:20 +08:00
ClaudeandClaude Opus 5.5 a6f5ffbb4f docs(sync10): record sync 10 in the ledger, changelog and progress note
Ledger entry for upstream 5fb8379c with target 9d69cd56 and rollback list.
The progress note has the inventory, what was not ported and why, test
results, and the status of the two 2026-10-03 upstream issues. Both are
fixed upstream: KARAKA_8 now follows BPHS order, and Narayana profiles now
reach calc_narayana_mahadasha.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:08:51 +08:00
ClaudeandClaude Opus 5.5 71510682dc fix(narayana): run the second cycle instead of replaying the first (BUG-1545)
The legacy current-period lookup took the age modulo the first-cycle total,
so anyone older than their first cycle (61-96 years on the nine public
charts) got a first-cycle period: an 80-year-old was placed in 2-12. The
second cycle runs the same signs for 12 minus their first-cycle years; the
lookup now places the age on both cycles and subdivides with the second
cycle's years. The rectification cache only covers the first cycle and falls
back to the live lookup past it, so first-cycle scoring is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:05:22 +08:00
ClaudeandClaude Opus 5.5 9d69cd5625 fix(kp): feed sub-lord analysis unrounded cusps, degrees and time (BUG-1543, upstream 26d5a52d)
cmd_kp handed calc_kp_analysis the cusps from calculate_bhava_boundaries
(rounded to 4 decimals), degree_in_sign (4 decimals) and the chart's
display julian_day (6 decimals). KP star, sub and sub-sub boundaries are
cut on raw longitude, so a body or cusp sitting on a boundary could land
one cell off. The fix recomputes the JD from the civil instant with the
compute_chart_data formula, uses calculate_cusps directly, and uses
degree_raw % 30.

Only the KP part of 26d5a52d is ported. Its Vivaha Saham day/night change
and Yoga status pass-through are left for a separate decision. Test ported
from upstream tests/test_kp_unrounded_inputs.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:01:47 +08:00
ClaudeandClaude Opus 5.5 8137c692b1 fix(full-reading): one observation date for Narayana, nakshatra and annual age (BUG-1542, upstream 933f254e)
today_str and transit_reference_date already followed transit_date, then
today, then now. Narayana's current period read only args.today, and the
nakshatra-dasha age and the annual fallback age used datetime.now(). A
dated report therefore mixed two dates. The annual fallback age also used
days // 365, which moves to the next year of age early.

All three now take the same observation date. The fallback age counts
calendar birthdays. Tests are ported from upstream
test_full_reading_observation_date.py and test_tajika_report_age.py and
adapted to cmd_full_reading. Same-day web consultations are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 12:00:44 +08:00
ClaudeandClaude Opus 5.5 4b6aa08726 fix(varga): count D12 linkage houses from the D12 ascendant (BUG-1541, upstream cf6c316d)
The full reading's inter-chart linkage appended D12 with a hard-coded None
ascendant, so every D12 row had house None even though d12_asc_idx was
already computed a few lines above. An unknown sign name also fell back to
Aries. Port upstream cf6c316d and f60568a0: pass d12_asc_idx through, and
raise on an unknown sign or a non 0-11 ascendant index. The full reading
records the error and the consult native layer marks it blocked.

Test ported from upstream tests/test_inter_chart_d12_house.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:59:33 +08:00
ClaudeandClaude Opus 5.5 74169e1bfc fix(benchmark): pass the ayanamsa to both engines and refuse a mismatched baseline
The local baseline still claimed "lahiri_assumed_by_skill" after the engine
default moved to Raman, so the PyJHora comparison reported 59% instead of
~95% (every longitude 1.446 deg off). The baseline now passes --ayanamsa and
--node-mode to the engine and records what the engine reports; the compare
takes --ayanamsa and stops when the baseline was built differently. The nine
public Rodden AA backtest figures join the fixed samples.

Raman run (19 samples): ascendant, planets, nakshatras, D2/D4/D9/D10 and
Ashtakavarga all 100%; Shadbala and three old-chart dashas differ (separate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:55:22 +08:00
ClaudeandClaude Opus 5.5 2539d57fee docs(skill): take upstream's source corrections to five reference guides
Upstream corrected guides whose calculations we already ported. Our guides
still described the old rules:

- argala: secondary Argala is house 5, blocked by house 9 (PVR Integrated
  Approach 10.5-10.7). The 8th-house and planet-gender rules are dropped.
  scripts/argala.py already does this (BUG-1386).
- sahams: the calculator carries all 36 PVR Table 74 formulas with day and
  night exceptions (BUG-1474). references/saham_rules.json is byte-equal to
  upstream.
- shodasavarga: Shodasa-varga weights are D27 0.5 and D30 1. The old 1 and
  1.5 summed to 21. They now match vimsopaka_calculator.py.
- yogi-avayogi: the mixed historical notes are marked as not a formula. The
  live profile is Sun + Moon + 93 deg 20 min in
  scripts/annual_native/yogi_sphuta.py; the upstream path is adapted.
- ai-reading workflow: adds the 2026-10-02 full-text evidence boundary
  (conditional openings, untested is not "absent", no celebrity fill-in).

event_judgment_wealth and SKILL.md now name finance-timing-strict with
wealth-timing-strict as the legacy alias, as the router already does. Chat
binds only the 商业运行时路由 section of SKILL.md and router sections, so
no chat prompt text changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:55:13 +08:00
ClaudeandClaude Opus 5.5 297e27e0bd docs(privacy): swap the leftover private sample for upstream's public example
Upstream replaced the redacted-year sample (April 17, 14:45, about 36.5N
114.2E) with a public birth (1935-06-21 11:00, Cajarc, France) in the
reading workflow and in the narayana-dasha / solar-return usage text. Our
copies still carried the private date, time and place. The PDF guide's
example coordinates now name the San Francisco values it already labels.

Doc and docstring text only; no calculation changes. The same sample is
still a quality-gate fixture in scripts/run_quality_gate.py and appears in
older docs/research notes; neither is changed here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:54:12 +08:00
ClaudeandClaude Opus 5.5 3bae79fbca docs(upstream): mirror upstream SKILL.md at main 5fb8379c (sync 10)
Run scripts/import_yinduzhanxing.py --apply from a clean clone of upstream
main 5fb8379c, the upstream HEAD on 2026-11-04. Only the root SKILL.md
moves into references/upstream/yinduzhanxing; the six semantic-merge paths
stay review_required and untouched. The new mirror drops the private
"yn-1993" sample wording the b9a0ef8f mirror still carried.

source-manifest.json and import-plan.json now pin 5fb8379c. The b9a0ef8f
import record stays as history and its test now checks only the record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:51:04 +08:00
ClaudeandClaude Opus 5.5 db2fc3fcfe fix(consult): cut what the agent reads from 24.5k to 18.4k characters (BUG-1540, step 2)
Independent Staging Quality Gate / validate-python (push) Successful in 6m14s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m14s
Independent Staging Quality Gate / publish (push) Successful in 2m56s
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
2026-11-04 11:00:54 +08:00
ClaudeandClaude Opus 5.5 788de754f9 fix(consult): list every ground with its meaning; say the presence range once per answer (BUG-1540)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m19s
Independent Staging Quality Gate / validate-python (push) Successful in 6m21s
Independent Staging Quality Gate / publish (push) Successful in 3m4s
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
2026-11-04 10:38:27 +08:00
ClaudeandClaude Opus 5.5 7fe337d420 fix(consult): keep a one-sentence range for heavily afflicted parents; plain words over jargon (BUG-1540)
Independent Staging Quality Gate / validate-python (push) Successful in 6m14s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m20s
Independent Staging Quality Gate / publish (push) Successful in 3m4s
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
2026-11-04 10:26:16 +08:00
ClaudeandClaude Opus 5.5 feb16ed358 fix(consult): one short VISIBLE VOICE instead of 17k characters of stacked answer rules (BUG-1540)
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
2026-11-04 09:53:27 +08:00
ClaudeandClaude Opus 5.5 9a6244bcc0 feat(consult): follow-up questions written from this question and answer, saved with it (BUG-1539)
Independent Staging Quality Gate / validate-python (push) Successful in 6m18s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m21s
Independent Staging Quality Gate / publish (push) Successful in 2m49s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 09:41:32 +08:00
ClaudeandClaude Opus 5.5 f577dcd279 fix(chat): readable 常用问题 hover, aligned answer actions, no 本轮技法 list, no keyword follow-ups (BUG-1539)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m11s
Independent Staging Quality Gate / validate-python (push) Successful in 6m14s
Independent Staging Quality Gate / publish (push) Successful in 2m30s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 09:23:13 +08:00
ClaudeandClaude Opus 5.5 5c9a51c4dd fix(sidebar): one hover colour per row, lighter than the current row; no credits under the name (BUG-1538)
Independent Staging Quality Gate / validate-python (push) Successful in 6m18s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m17s
Independent Staging Quality Gate / publish (push) Successful in 2m22s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-04 09:06:54 +08:00
ClaudeandClaude Opus 5.5 f0f570e17b feat(sidebar): option B — solid sidebar, outlined 新建对话, 3×2 tool grid, neutral selection (BUG-1537)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m19s
Independent Staging Quality Gate / validate-python (push) Successful in 6m29s
Independent Staging Quality Gate / publish (push) Successful in 2m59s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 23:47:05 +08:00
ClaudeandClaude Opus 5.5 3ec682763d test: header title assertions follow the shortened rectification title (BUG-1536)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m23s
Independent Staging Quality Gate / validate-python (push) Successful in 6m44s
Independent Staging Quality Gate / publish (push) Successful in 3m20s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 23:26:30 +08:00
ClaudeandClaude Opus 5.5 c1b828fce2 fix(rectification): header drops the window the range bar already shows (BUG-1536)
Independent Staging Quality Gate / validate-frontend (push) Failing after 5m41s
Independent Staging Quality Gate / validate-python (push) Successful in 6m21s
Independent Staging Quality Gate / publish (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 23:16:49 +08:00
ClaudeandClaude Opus 5.5 349704b7f3 fix(rectification): one 760px reading column for text, range bar and composer; sidebar clips (BUG-1536)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 23:14:24 +08:00
ClaudeandClaude Opus 5.5 837155f5ba fix: redirect signed-out / on the server; login tabs and code boxes; rectification starts at once (BUG-1535)
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m17s
Independent Staging Quality Gate / validate-python (push) Successful in 6m33s
Independent Staging Quality Gate / publish (push) Successful in 3m12s
- 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
2026-11-03 22:58:42 +08:00
ClaudeandClaude Opus 5.5 7cfde2085a feat(composer): option 2 单行起步 — one pill row that grows into the two-layer card
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m12s
Independent Staging Quality Gate / validate-python (push) Successful in 6m28s
Independent Staging Quality Gate / publish (push) Successful in 3m2s
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
2026-11-03 22:38:23 +08:00
Claude 7d7bba38dd Merge remote-tracking branch 'origin/staging' into codex/reports-page-1103
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m2s
Independent Staging Quality Gate / validate-python (push) Successful in 6m21s
Independent Staging Quality Gate / publish (push) Successful in 2m49s
# Conflicts:
#	CHANGELOG.md
#	docs/research/pre_work_error_ledger.md
2026-11-03 21:28:53 +08:00
ClaudeandClaude Opus 5.5 724b57e5d5 feat(reports): 我的报告 option A — two entry bars, compact row list
- 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
2026-11-03 21:28:02 +08:00
ClaudeandClaude Opus 5.5 6b66aceade feat(rectification): fill the 还没校正过 card with what the person said
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m20s
Independent Staging Quality Gate / validate-python (push) Successful in 6m23s
Independent Staging Quality Gate / publish (push) Successful in 3m26s
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
2026-11-03 21:06:13 +08:00
ClaudeandClaude Opus 5.5 1c9163e0bd feat(rectification): entry page time ruler (option A) with separated buttons
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
2026-11-03 20:02:20 +08:00
ClaudeandClaude Opus 5.5 212666cdd5 Merge remote-tracking branch 'origin/staging' into codex/preset-menu-1103
Independent Staging Quality Gate / validate-python (push) Successful in 6m22s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m24s
Independent Staging Quality Gate / publish (push) Successful in 3m9s
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
2026-11-03 18:44:18 +08:00
ClaudeandClaude Opus 5.5 8273a1e2be fix(chat): keep the 常用问题 panel above the trigger; #151 checklist for A + 1
- 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
2026-11-03 18:43:50 +08:00
ClaudeandClaude Opus 5.5 0acf1b3708 docs(ops): staging CI speed-up before/after
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 18:31:43 +08:00
ClaudeandClaude Opus 5.5 a2064b8d48 Merge remote-tracking branch 'origin/staging' into codex/preset-menu-1103
Conflicts in CHANGELOG.md, docs/BUG_HISTORY.md and the pre-work ledger were
both sides appending at the same place; both kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-03 18:22:28 +08:00
Claude 62a9feb0d2 Merge remote-tracking branch 'origin/staging' into codex/shell-fixes-1103
Independent Staging Quality Gate / validate-python (push) Successful in 6m48s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m52s
Independent Staging Quality Gate / publish (push) Successful in 2m40s
# Conflicts:
#	CHANGELOG.md
#	docs/BUG_HISTORY.md
#	docs/research/pre_work_error_ledger.md
2026-11-03 18:22:24 +08:00
ClaudeandClaude Opus 5.5 80cdfd2184 fix(chat): keep the 常用问题 panel above or below the trigger
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
2026-11-03 18:22:07 +08:00
ClaudeandClaude Opus 5.5 0013a48d7e fix(shell): chip person picker on every secondary page; one background after 新建对话 (BUG-1532, BUG-1533)
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
2026-11-03 18:21:28 +08:00
ClaudeandClaude Opus 5.5 a14040c0d7 ci: balance the two validate jobs by moving the CLI smoke tests
Independent Staging Quality Gate / validate-python (push) Successful in 6m41s
Independent Staging Quality Gate / validate-frontend (push) Successful in 6m44s
Independent Staging Quality Gate / publish (push) Successful in 2m37s
After the fixture change validate-frontend finished ~3 min before
validate-python (307 s vs 491 s in run 6487). tests/test_cli_smoke.py
(~110 s) now runs in validate-frontend after the frontend suite, with the
same PYTHONPATH/PYTHON the gate sets. run_quality_gate.py gains
--exclude-pytest-target, which refuses anything not in the selected
targets; a test checks every exclusion is run by the other job.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 18:19:06 +08:00
Claude 094e0f796d Merge remote-tracking branch 'origin/staging' into codex/chart-rate-1103
Independent Staging Quality Gate / publish (push) Canceled after 0s
Independent Staging Quality Gate / validate-frontend (push) Canceled after 21s
Independent Staging Quality Gate / validate-python (push) Canceled after 27s
2026-11-03 18:18:38 +08:00
ClaudeandClaude Opus 5.5 b8000ca0f3 feat(chat): 常用问题 as a text pill and a two-column panel (#151, A + 1)
- 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
2026-11-03 18:11:33 +08:00
ClaudeandClaude Opus 5.5 884a17997c ci: run the fragment audit once per quality gate
Independent Staging Quality Gate / validate-frontend (push) Successful in 5m7s
Independent Staging Quality Gate / validate-python (push) Successful in 8m11s
Independent Staging Quality Gate / publish (push) Successful in 2m31s
The gate ran scripts/audit_fragments.py --strict (~52 s on xiaoxin) and then
pytest ran the same audit() again in tests/test_api_server_security.py
(test_fragment_audit_blocks_registry_surface_drift asserts valid and more).
The separate step is gone; tests/test_quality_gate_fragment_audit_once.py,
now in the core targets, keeps the pytest copy and its target listing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 18:05:32 +08:00
Claude 0fef90320d Merge remote-tracking branch 'origin/staging' into codex/chart-rate-1103 2026-11-03 18:05:27 +08:00
ClaudeandClaude Opus 5.5 b6a6833ace fix(chart): stop /chart locking out with 「刚才打开得太勤」 after normal navigation (BUG-1530, BUG-1531)
- 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
2026-11-03 18:04:41 +08:00
ClaudeandClaude Opus 5.5 5ff6c2506a ci: let the gate run 6 PostgreSQL fixtures at once
Independent Staging Quality Gate / validate-frontend (push) Successful in 4m47s
Independent Staging Quality Gate / validate-python (push) Successful in 8m37s
Independent Staging Quality Gate / publish (push) Successful in 2m34s
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
2026-11-03 17:52:01 +08:00
ClaudeandClaude Opus 5.5 0afb151322 docs(bugs): restore 40 fix-version lines overwritten by the BUG-1516 record
c165669e meant to set only BUG-1516's 修复版本, but the substitution matched
every '修复版本:待提交' line. Those 40 entries go back to 待提交.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 17:51:26 +08:00
ClaudeandClaude Opus 5.5 df04c7108d ci: reuse one SSH connection per staging migrate/deploy step
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
2026-11-03 17:51:10 +08:00
Claude ed07e5300a Merge remote-tracking branch 'origin/staging' into codex/loading-1103
Independent Staging Quality Gate / validate-python (push) Successful in 9m8s
Independent Staging Quality Gate / validate-frontend (push) Successful in 9m8s
Independent Staging Quality Gate / publish (push) Successful in 3m18s
2026-11-03 17:35:07 +08:00
ClaudeandClaude Opus 5.5 cb035bd546 ci: report runner resources and the slowest frontend tests
Independent Staging Quality Gate / publish (push) Canceled after 0s
Independent Staging Quality Gate / validate-frontend (push) Canceled after 3m2s
Independent Staging Quality Gate / validate-python (push) Canceled after 3m11s
Timing evidence for the next tuning round: CPU/RAM in the toolchain step and
the 25 slowest top-level frontend tests from the TAP log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 17:32:17 +08:00
Claude 9779e195a4 Merge branch 'codex/chart-pending-1103' into codex/loading-1103
# Conflicts:
#	CHANGELOG.md
#	docs/BUG_HISTORY.md
#	docs/research/pre_work_error_ledger.md
2026-11-03 17:20:09 +08:00