The G2 precheck and the G5 noise floor had only a results file; the script
that produces them is now in scripts/research/d60_two_way_g2_g5.py, with
a test that reproduces the committed JSON byte for byte.
G5 is now reported per switch, with the ayanamsa offset in arcminutes.
Against the Raman baseline all three alternatives flip 77/77. Between the
alternatives themselves the number follows the offset: Lahiri to KP 21/77
(27.3%, 5.81'), KP to True Chitra 19/77 (24.7%, 5.02'), Lahiri to True
Chitra 2/77 (2.6%, 0.83'). The report says so and no longer claims that
any frame change flips every chart; the registered gate is baseline
relative and still triggers.
The report also states that G2's "not evaluable" comes from the registered
same-day answer policy, not from a measurement that D60 does not help.
Co-Authored-By: Grok (agent loop)
The G2-G5 results came without the script that produced them, so G5's
77/77 ayanamsa flip cannot be replayed. Commit the script, report G5 per
alternative ayanamsa, and say that G2's zero questions came from the
same-day scoring rule the planner chose.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
The registered same-day answer policy needs an event dated on the birth day;
the v5 holdout has none in any of the 77 cases, so group B adds no question
and is identical to group A. G2 is therefore not evaluable by construction,
not a measured zero, and no placebo test has a lift to check.
G5 is measurable and decisive: switching the ayanamsa from Raman to Lahiri,
KP or True Chitra changes the ascendant D60 sign in 77 of 77 cases (100%,
threshold 20%). Under the registered stop rule any minute-level wording is
forbidden.
Recommendation: do not adopt. D60 stays reference-only and the external copy
does not claim seconds. BUG-1497 is closed_by_design; the mapping fix itself
is BUG-1500 and already merged.
Co-Authored-By: Grok (agent loop)
The production D60 branch added one sign to 1-based even signs, with no
source, while the repository's own guide and the vedastro mapping count
from the sign itself. PyJHora agrees with the latter: 33/77 recorded times
before, 77/77 after.
- scripts/varga.py: D60 is (si+pi)%12 for odd and even signs; other
mappings and the vedastro mode are untouched.
- tests/test_d60_varga_mapping.py: 12 signs x 60 parts against
PyJHora, plus the even-sign first part.
- scripts/research/d60_two_way_run.py: the G1 reconciliation that found
this, now in the repository with a test; G1 passes 77/77.
- scripts/varga.py is part of the extended frozen identity, so the sealed
holdout and the reported-offset sweep were re-frozen per ERR-110. All
20 and 900 trials match the upstream_sync9b records on every field and
the metrics and summary are unchanged.
Co-Authored-By: Grok (agent loop)
Product chose 1: fix production D60 (count from the sign itself for odd
and even signs) before continuing the two-way study. Renumber the
branch's D60 bug BUG-1498 -> BUG-1500 to clear the staging collision,
and settle the D60 boundary scoring rule as same-day events only.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
Classification only needs the question, history, name and session model,
so it now starts in beforeReserve once moderation passes and is awaited
after the question is written. Billing is unchanged: smalltalk is still
reserved and refunded by complete_consultation_free, and an unused early
call (reserve refused) is capped at the classifier's 3 s fail-open.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Product chose A after the A/B: low cut answer-step reasoning tokens ~45%
and answer time 34s -> 22s with no quality loss. Unset now means "low";
CONSULT_ANSWER_REASONING_EFFORT=off restores the pre-change request body,
and the old "unset keeps the body" guarantee moves to "off".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The D60 ascendant of the production classical_local mapping agrees with
PyJHora on 33 of 77 recorded times (42.9%). All 44 mismatches are 1-based
even signs and differ by exactly one sign; the repository's own vedastro
mode agrees with PyJHora on 77 of 77.
So G1 fails the 95% gate, but the cause is the production mapping rule in
scripts/varga.py, not a missing D60 signal. BUG-1498 records the
inconsistency as investigating. G2-G5 did not run and no scoring rule was
registered.
jyotishganit is not installed here and VedAstro was not called, so the
reconciliation is single-engine and says so.
A task left running wrote its outcome into the next test's cache directory,
so the next test saw a remembered failure and never called the gateway.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Staging showed 「记下了:2016-09 2016 年 9 月上大学。」. evidenceRecapLine only
recognised an unspaced 「2016年」 as the phrase's own date, so a spaced year or
an ISO / slash date got the label in front again. It now recognises
`\d{4}\s*年` and `\d{4}[-/.]\d{1,2}`; phrases without a date still get the
label. Regression test fails before the fix and passes after.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Environment checks are done: swisseph 2.10.03, PyJHora importable with a
shashtyamsa chart, the v5 holdout present, and the four baseline test
files green (98 passed). jyotishganit is not installed, so G1 ends up with
PyJHora as the only external engine.
The B-group scoring rule cannot be implemented as written: the six-question
replay answers date-level boundary questions, while a D60 change happens
every couple of minutes inside one day. Two workable options are recorded
in PROGRESS and posted to the issue; nothing is scored before the rule is
preregistered.
Nadi/D150 seconds were falsified in BUG-1240; this brief only tests D60 as a
discriminator: production V9 vs V9 + D60 segment boundaries on the 77-case v5
holdout, both directions (help and harm), preregistered gates G1-G5, plus a
20-case model-in-the-loop conversation comparison. Offline, no production or
frozen-file changes. Reserves BUG-1497.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 7f7321b77725c8798292f184fc038fcfaf8c11ff)
The sync9b edit replaced the two sync8 entries in
IDENTITY_FORBIDDEN_PREFIXES instead of appending after them, so the guard
covered two records instead of four while still passing. Restore the
sync8 pair under its own comment and keep the sync9b pair after it.
The freshness test passes again (9) and the frontend confirmation-gate
test for the moved sealed report passes (8).
Co-Authored-By: Grok (agent loop)
- Sidebar 「生时校正」 under 星盘, behind a new account `rectification` flag.
- /rectification page: status card from entry-summary (not started / in
progress with window and confirmed event count / adopted time), a short
data check, then the home rectification surface (?rectify=1, or
?rectify=new to start over; ?c=<id> to continue or view). No price on
the page.
- entry-summary gains session id, candidate range, confirmed evidence count
and adopted times (add-only migration 20261028170000).
- The offer card under a consultation answer becomes one line and a link
to /rectification; an explicit request in chat also goes there. No case
is opened from a conversation any more.
- Starter home shows a rectification prompt for self charts with an
estimated time; onboarding checklist gains 做一次生时校正 for them.
- Chart-page link points to /rectification. Shell registers its router so
home hooks can navigate client-side without useRouter in Home().
- Docs: VOICE, DESIGN, CHANGELOG, device checklist.
Self profile only; other people are issue #160.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The freshness test's IDENTITY_FORBIDDEN_PREFIXES list is append-only;
the branch replaced the two sync8 entries instead of adding the sync9b
ones after them, which weakens the identity guard. Restore them.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
Upstream 50847e57, ported semantically:
- Sarpa Drekkana now accepts the five classical ranges (Cancer 2/3,
Scorpio 1/2, Pisces 3) and partitions on the raw longitude instead of
the rounded display degrees.
- The 22nd Drekkana is the eighth house of D3 (+7), not +21 zodiacal
ten-degree divisions.
scripts/varga.py is part of the extended frozen identity, so the sealed
holdout and the reported-offset sweep were re-frozen under ERR-110:
20/20 sealed trials and 900/900 sweep trials match the sync8 records on
every compared field, and the metrics, summary and widening geometry are
unchanged.
Tests: the upstream varga/ sarpa files are added under
tests/test_upstream_sync9b_*.py; the stale +21 assertion and the sarpa
definition string are updated with the original/new/reason columns in
PROGRESS.
Co-Authored-By: Grok (agent loop)
Product chose A on #159: change the frozen varga.py for the five Sarpa
drekkanas and the 22nd drekkana, and refreeze only on identical 20/900
rectification scores. Narayana AD strength (B2) is deferred: our code
has no strength-profile family for it to propagate.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
The single ThreadingHTTPServer ran pure-Python v5 score / block_scan / report
reference under one GIL, so the gate's two slots shared a core. start_server
now starts a spawn pool (workers = heavy concurrency, PYTHONHASHSEED=0, engine
pre-imported); those three routes call the same compute method in a worker.
Over HTTP: score alone 4.74 s, two at once 5.01 / 4.58 s (1.06x; in-process
1.56x). Results equal except per-process fingerprints; report markdown equal.
~165 MB extra. A crashed pool answers inline and restarts; off with
JYOTISH_HEAVY_COMPUTE_PROCESSES=0; tests calling compute methods unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/api/chart, /api/dasha and the analysis layer, daily guidance and the KP
monthly packet used compute_vimshottari_timeline, which hands
build_dasha_timeline only the birth date, so periods started at midnight;
cmd_dasha (reports) starts from the birth clock and lays antardashas from the
full parent with float days. scripts/chart_dasha/birth_moment.py reproduces
cmd_dasha; 60 standard charts: MD and AD 60/60 equal (old chart path 9/60),
51 charts move by at most one day. Frozen scoring files are untouched, so
rectification probes keep the day start (left for a product decision).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Step 0 of every turn could only call rectification-read-case with the
default projection, a result the server can compute. The runner now runs the
agent's own read-case tool after the Skill is bound (same tool, receipts and
projection), passes the call and result to the model as the turn's opening,
and gives step 0 the full tool set. Synthetic chunks go through the same loop
(case.loaded, activity and Skill receipt once each) but not into step timings.
The synthetic call carries a short reasoning line: thinking-mode DeepSeek
rejects a prior tool call without reasoning_content (checked live). read-case
stays callable for resume / full_diagnostics. Agents without listTools keep
the step-0 read. The Skill package has no "read first" text; prompts updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gate run 5888 failed: the synastry full dossier computes two full readings
on a thread pool, and the second thread got jyotish_engine from sys.modules
while the first was still executing it (no cmd_full_reading yet). Reuse now
goes through importlib.import_module, which waits on the module lock.
Four threads loading one module in a fresh interpreter: before
[False, True, True, True], after all True three times. Dossier scenario
before 4/4 AttributeError, after 6/6 ok; synastry-full-report.test.ts 17/17.
Ledger ERR-117: local npm baseline hid it (system python3 lacks swisseph).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Staging took BUG-1472..1482 while this branch was in review, so the
branch's eight entries move to BUG-1483..1490. Docs and one test
comment only; the branch's commit messages keep the old numbers.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
_load_local_module always re-executed the file as _jyotish_local_<name>, so
engine, dasha, varga and others ran as extra copies with their own caches.
It now reuses scripts.<name> / <name> when that file is already imported,
else imports it under its plain name so later imports share it; the private
copy remains only as a fallback. Call sites unchanged. Probe after one
consultation and one chart: loader-made copies 19 -> 0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Batch 1 of the scripts/ root cleanup: the closure scripts no runtime entry,
other script, workflow, deploy file, ops doc or quality gate reaches, with
their 11 test files (30 cases). Their references/ outputs stay. Scripts still
imported elsewhere, named by the gate, or listed in archived reference indexes
are kept. Root budget 452 -> 441.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unreachable from every app entry and frontend/scripts (dynamic imports
counted): chart-basics-tab, error-toast, seven unused shadcn ui files
(skeleton among them), three birth-time helpers only tests used, the motion
provider shell (it imported motion/react statically), and the two empty
people/account stores. Tests that only exercised them are removed or trimmed,
each with old/new/reason notes. Unreachable files 18 -> 3 (all kept on
purpose); npm test names drop exactly the 4 removed and 1 renamed test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The D9 smoke case expected Sun, which is what the old reader produced when
it took the 7th highest degree in the 8-karaka variant. The canonical table
and the fixed reader both give Moon for this chart (Moon 3.09 degrees).
Expect Moon and the D9 fields that follow it, and assert the reader agrees
with chara_karaka_8.karaka_table_8.Darakaraka.planet so the test locks
reader/main-table identity instead of one planet name.
Co-Authored-By: Grok (agent loop)
- Foreground gateway: a run that ended without official data is written to
the existing same-day negative snapshot store; later turns that day answer
from it without starting the gateway (second call <= 0.15 s, same fields).
Success still goes to the positive cache first; a consult-gate deferral and
a join timeout are not failures.
- /v5/vedastro-validate: a result blocked by VedAstro itself is kept in memory
for a day per (evidence fingerprint, candidate pair); evidence-decided
results are not. The whole check has 11 s (frontend waits 12 s); calls with
time to spare keep the adapter timeout, so normal output is unchanged.
- conftest also isolates the negative store and clears the check memory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The HTML early-read script also runs on /chart, /people and /synastry:
account, people list and the current person's sessions, plus on /chart the
remembered person's chart-view (bound to that person, page deadline kept).
The model list stays home-only.
- Account and people-list early reads hand one clone to the shell and one to
the page, once each, in either order; later reloads go to the network.
- Synastry sends product-access, account, people and history together; access
is still decided before anything about people paints.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The early-read script now also sends /api/sessions/<id> when ?c= carries a
valid session id (same rule as parseSessionUrlQuery), next to the account.
Only the home bootstrap takes it, bound to that id and once: the lookup for a
conversation off the first page, or the landing fetchSessionDetail. 401/404/
error handling and notices are unchanged; a failed early read refetches.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- consult_packet_view keeps the last 3 parsed packets with their shared domain
base (~30 MB each). A hit reads no file and copies nothing: attach for one
domain 0.106 s -> 0.002 s. Memory holds the file's JSON round trip, i.e.
exactly what a hit returned before; consult_card_facts sha256 equal old/new.
- Cache files are created 0600, same bytes as before.
- The consult route fires a warm for the turn's chart before reserving credit,
so the day's first question does not build the packet on the answer path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- parseBirthDate/formatBirthDate: hand-written yyyy-MM-dd with the same strict
round-trip check; equal to the date-fns version on 97,507 inputs.
- Sign-out imports the better-auth client on click.
- The share report export downloads at idle after first paint; once loaded,
share writes the clipboard inside the click exactly as before.
- page.tsx: drop the unused consultationReportMarkdown import.
gzip-9 of every referenced JS/CSS: / -29,240 B (still Static); /chart, /people,
/reports about -29 KB; /ephemeris -23.6 KB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
page.tsx imported the whole rectification surface statically; its verification
report also imported chat-markdown-view statically, which pulled react-markdown
into / even though chat-message-content already loaded it lazily.
- Home renders a same-named lazy wrapper; openRectificationCase starts the
download with the open request and awaits it before setting the ids that
mount the surface, so it still reveals once, drawn.
- The markdown loader moves to lib/chat-markdown-loader; the home bootstrap
awaits it before revealing a conversation with messages (no plain-text flash
on ?c=). The blank home does not wait.
/ first load, gzip-9 of every referenced JS/CSS: 704,165 -> 609,606 B (-13.4%),
still Static.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
executeWindowConsultation awaited /api/declared_window_chart before sending
/api/rectification/v5/range_reading, which does not depend on it. Both now go
out at once; a failed range reading still only drops the minute-sensitive
themes. Two 150 ms stubs: ~150 ms total instead of ~300 ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Home subscribed to the whole streamingReply object, so each animation frame of
an answer re-ran the page (header, picker, composer, overlays) and the desktop
natal panel under it. ChatStreamingTranscript now subscribes for its session
and feeds ChatTranscript; Home reads one derived boolean for the stop label.
ChatChartSplit is memoized. 100 frames: Home <=2 commits (was >=100), panel 0.
Two source-contract tests now pin the new component instead of the old names.
The onboarding typewriter still ticks at Home level (out of this ticket).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The quick gate fails one smoke test: the Darakaraka reader now agrees
with our own 7/8-karaka tables (Moon), but the old test pinned the
buggy reader's Sun. Fix the expectation and lock reader == table.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
BUG-1472 through BUG-1479. Rectification 20-case and 900-window metrics match the sync8 reports. Batch B is not done.
Co-Authored-By: Grok (agent loop)
Fifteen calculation fixes landed on upstream main on 10-16 that sync 8
never saw, because sync 8 took the upstream-notice branch instead.
Batch A (nine items outside the rectification freeze) goes to Grok now;
Varga and Narayana touch frozen files and wait for #137.
Co-Authored-By: Claude (agent loop) <noreply@anthropic.com>
read_full_data_domain deep-copied the shared worksheets on every call; a long
report reads five domains twice, so ten copies for read-only use. The shared
part is now copied once (full_data_domain_base) and reused for every domain's
facts and their leaf check; each domain's facts are still copied out so domains
share no objects. Long reports byte-identical on four fictional charts; with
#121, -24–29% end to end.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoz1Qk3y9buDv1mkmTu
Byte-identical to the legacy path on four fictional charts (PyJHora masked),
-19–26% end to end (median 23%). Short of the 25% written on the ticket; the
product owner chose to turn it on anyway. JYOTISH_REPORT_RENDER_FAST=0 restores
the old path.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoz1Qk3y9buDv1mkmTu
- Composer cancels InputGroup's dark-mode fills too (BUG-1466 covered light only).
- Chart head controls share one 32px height, tags 28px, per the signed prototype;
the birth line moves under the name so the phone top bar is one line.
- Inspector card has one fixed height and scrolls inside.
- Chart-type sheet header is a row (SheetHeader ships flex-col).
- Restore shadcn's base border-color rule: bare kit borders were drawn in
currentColor, a white line in dark mode; the phone chart sheet pads once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoz1Qk3y9buDv1mkmTu
The birth editor on /chart now loads when the pen row is clicked (warmed on
hover/focus), the people page's add/edit form is fetched after mount, and
the people city column reads the on-demand table. /chart first load
-116 KB gzip, /people -111 KB; home +0.19%, still static. A static import
graph test keeps the table out of both pages.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoz1Qk3y9buDv1mkmTu
The 300 ms budget failed twice on the gate runner while the test takes about
74 ms locally. What it proves is that the line shows before the server
answers, so assert that the controllable stream has not answered yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Ad9rqAB8pXXvyzh7f4X8v