main
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9dda9df132 |
Read History: the graph becomes something a person can read
The ancestry contract existed and nothing rendered it. This turns it into a product surface, and stops there. WHERE IT GOES. `LedgerCard` is the terminal surface — there is no Ledger detail view — so the history expands in place inside the card, matching the board's existing "ALL N READS" affordance rather than adding a page, a modal or a navigation category. It loads on first open, not on render. WHAT IT IS CALLED. "Read History". Lineage stays engineering vocabulary; a test asserts no rendered string contains lineage, natural key, ordinal, digest, graph, origin or recapture. ORIGIN reads "First published", REVISION reads "Updated", and the persisted `change_type` supplies "The price moved" / "The read changed" / "The read and the price changed". `change_type` is stored and trustworthy, so naming it is reporting; no field-level diff is persisted, so none is invented. THE SEPARATION, WHICH IS THE LOAD-BEARING PART. The grade strike means the LETTER changed. A history entry means the published CLAIM changed — often the price, sometimes the read, frequently with no letter change at all. The history uses no strike-through, shares no styling, and a tooth fails if it ever does. The ledger card's own strike is untouched. RECAPTURES ARE SUMMARISED, NEVER DESTROYED. A republishing board can produce hundreds of "unchanged" entries that bury the two that matter, so the UI collapses them to a count. The API still returns every one. WHAT EACH ENTRY SHOWS came from the acceptance run: without the published grade the history can say a Read changed but never what it changed to, which answers none of the questions someone opens a history to ask. `published_grade` / `published_p_win` / `published_line` are read off the SAME retained row the lineage action sits on — the authoritative record of the published claim, with lineage only the pointer to it. A tooth fails if they are ever synthesised from lineage metadata. TWO DEFECTS THE PRODUCTION ACCEPTANCE FOUND, NEITHER OF WHICH A TEST HAD. `ledger_entries.id` is a UUID and the route parsed it with Number.parseInt, so every real row would have 400'd. The unauthenticated probe that "proved the route was live" returns 401 from requireAuth before the handler runs, so it could never have seen this. And `chase burns / hits_allowed / under / 4.5` has SIX published captures and four lineage actions — two were published while the writer was off. The response said `chronology_complete: true` while showing four of six. Completeness now counts published-but-never-recorded states as well as attempted-and-failed ones, kept as separate numbers because the causes differ and the copy says which. Suite 399/5,544/0 · tsc 0 · web build 0 · teeth 15/15. Lint is not runnable in this repository (`next lint` removed in Next 16, no eslint.config.*) — pre-existing, untouched here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8 |
||
|
|
e5b20b0509 |
Software watches coverage now, and ancestry becomes a product contract
Three closeout items, traced before building.
THE OBSERVER WAS DIAGNOSTICS, NOT MONITORING. Traced from the deployed tree:
exactly two callsites, both manual internal routes, and nothing in the scheduler
or ops path consumed it. A persistent lineage failure could have sat unnoticed
until a human asked.
The monitor now runs on the scheduler's per-minute tick, throttled to 30
minutes. It is placed there rather than after a snapshot on purpose: an
in-snapshot audit structurally cannot report that no snapshot ran, which is the
failure mode that matters most, and it would run under peak write contention
where the audit already demonstrably times out. It reads only the durable
observer and never `attachLineage`'s counters, and every failure path is
swallowed — a monitor that can take down the pipeline it watches is worse than
no monitor.
HEALTHY IS SILENCE; EVERYTHING ELSE SPEAKS. `coverageAlarm` is pure, so the
policy is testable and cannot drift into the scheduler. AUDIT_UNAVAILABLE says
"could not be measured — the audit did not run", deliberately worded so it can
never be read as "coverage is zero": those are different claims and collapsing
them is how a monitor starts lying in the reassuring direction. Alerts dedupe on
(health, cohort) so a standing fault states itself once and a NEW cohort with
the same fault speaks again.
ANCESTRY BECOMES A PRODUCT CONTRACT. It was internal-only. `GET
/api/ancestry/ledger/:id` (requireAuth, rate-limited) plus the Next proxy that
makes it browser-reachable, keyed on the LEDGER ROW ID — a stable identifier the
ledger API already returns — rather than a raw natural key exposed because it
was convenient. Its own router, so `routes/ledger.js` stays free of lineage
entirely and the grade-badge guard keeps its teeth. Every response declares
`authority: LOCAL, authority_scope: ANCESTRY_ONLY`.
THREE TEETH CAME BACK GREEN AND ALL THREE WERE MY TESTS, NOT SAFE DEFECTS.
The badge guard was CASE-SENSITIVE, so `LINEAGE_ANCESTRY` and `readAncestry`
walked straight past it. `try/finally` is valid JavaScript, so removing the
monitor's catch produced no load error and nothing asserted the containment.
And the multi-date cohort check was a grep for `.gte('game_date'` that the
head query satisfied on its own. All three replaced with behavioural tests,
including a scheduler double whose fake client HONOURS its filters — a
pass-through would have made a narrowed cohort walk look correct.
Suite 398/5,522/0 · tsc 0 · web build 0 · teeth 14/14 and 15/15.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
|
||
|
|
930d526b01 |
Lineage productization: a live graph, an observer that doesn't trust it, and a surface that owns only what it knows
The authority review found there was nothing to switch: lineage is a
write-only graph with no living permanent writer and no product consumer.
Authority theater would have been a switch on a consumer that does not exist,
reading a store that is not being written. So: make the graph live, measure it
from outside, and expose the one category it alone owns.
WRITE-PATH FAILURE SEMANTICS, TRACED FIRST. persist(:857) -> the authoritative
cacheSet snapshot:latest(:1404) -> the lineage gate(:1426) -> ledger(:1473).
Lineage failure cannot fail base retention (earlier, separate upsert), cannot
fail publication (the product write precedes the gate), cannot fail the Ledger
(lineageIndex defaults null; the ledger has its own guard), and cannot create a
new partial row (blankLineage() first, atomicity sweep after the catch). The
isolation this tranche needed already existed; only a mode was missing.
THREE MODES, ONE EVALUATOR. `lineageWriteMode` distinguishes OFF /
CANARY_LEASED / PERSISTENT_SHADOW, and the write gate and the status surface
both read it, so they cannot disagree. The canary is CONSULTED, never
converted: its <=4h absolute expiry, its dynamic evaluation and its
fail-closed parse are untouched.
AN AMBIGUOUS CONFIGURATION FAILS CLOSED. If a sport is named by both persistent
mode and an active lease, the two instructions disagree about WHEN WRITING
STOPS — the lease says 22:45, persistent says never. The dangerous reading is
the quiet one: an operator sets a bounded lease believing writing will stop
while persistent keeps it going. We cannot know which they meant, so that sport
writes nothing until the configuration says one thing. The sport allowlist is
the canary's own, so persistent mode can never widen past it.
THE OBSERVER MAY NOT ASK THE WRITER HOW IT DID. settleLedger returned
{settled:0,pending:0} — byte-identical to a healthy "nothing to settle" — while
1,444 rows sat unprocessed, and the watchdog believed it. So `lineageCoverage`
reads durable retained state only, and THE DENOMINATOR MAY NOT CONSULT
lineage_action: eligibility is "the row was published AND a natural key is
derivable from its own identity columns", neither of which the lineage path
writes. If expectation were derived from whether lineage exists, coverage would
be 100% by construction and the metric would be decoration. Zero-expected and
zero-written are kept as different answers.
THE LEGACY BOUNDARY IS OBSERVED, NOT DECLARED. `publication_id` is stamped only
by commitPublication, so the row itself says whether lineage ran. Verified on
production: 5,353 rows carry it — 4,234 complete actions plus exactly the 1,119
historical partial rows — and zero actions exist without one. No epoch constant
is invented; a date would have been a guess about when the writer was on.
publication_id NULL -> LEGACY_UNVERIFIED. Stamped but incomplete ->
LINEAGE_UNAVAILABLE, which is the honest answer for the 1,119 and is never
quietly rewritten as legacy.
THE GRADE-SHIFT BADGE IS UNTOUCHED. revised_from_grade answers "did the letter
change"; lineage answers "which published claim superseded which". Different
questions, and a test now fails if either route learns the word lineage.
Suite 397/5,496/0 · tsc 0 · 15/15 teeth.
TWO OF MY OWN TESTS WERE VACUOUS AND A TOOTH FOUND IT. Tooth 2 came back green
because the isolation tests asserted the slate was published — true whether or
not the exception propagated — while never reaching the lineage gate at all:
the fake grader never fired `onGraded`, so the collector stayed empty and
persistedRows stayed null. Fixed by firing the hook and counting the commit.
A green teeth run means the test is missing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQJeAG8vcDoL5zkiaJyVb8
|
||
|
|
352016790a |
MLB canonical event identity, impossible-binding refusal, event-aware dedupe, publication commit
Release-isolated slice built from
|