docs(audits): the strictness ledger stops asserting a union flattening the tree no longer does - #16766
Merged
zhuangjianguo merged 2 commits intoSep 8, 2026
Conversation
…g the tree no longer does Three clauses in the unknown-key strictness ledger asserted, in the present tense, that a strict branch's prescription is flattened away behind a union. It is not: `formatZodIssue` descends `invalid_union` and ranks the branches through `selectUnionBranches`, the one policy both spec-side walks import from `packages/spec/src/shared/union-branch-policy.ts`. Each clause is corrected in place, with its own provenance: - the `state-machine.zod.ts` row (written 2026-08-04) and the `view.zod.ts` row's overlay note (written 2026-08-04) were TRUE when written and expired on 2026-08-05, when #4971 / #5014 / #5341 landed. They now say so and name the module that lifted it. - the `chart.zod.ts` row's clause (written 2026-08-08) was already false the day it was written, so the row's own "kept as WRITTEN AT THE TIME" rule cannot rescue it. Its `only` is struck, and the generalisation it grounded — "a general constraint on every remaining union site in this campaign" — is withdrawn, because that generalisation is what seeded a false-premise card and cost a full dispatch cycle. Rows whose claims are framed as what their own batch recorded are untouched, and the os-regen `.counts.md` companion is not edited. No published surface moves; the ledger is a repo-internal audit document. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
…rictness-ledger-stale-flattening
zhuangjianguo
marked this pull request as ready for review
September 8, 2026 04:15
zhuangjianguo
deleted the
claude/issue-14977-strictness-ledger-stale-flattening
branch
September 8, 2026 05:01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #14977 — this delivers the card's narrow ask only. The card's other half, "a decision by the ledger's owner on how a row records a limitation that was later lifted elsewhere", is deliberately not settled here, so the card stays open for that ruling. See Scope below.
Three clauses in
docs/audits/2026-07-unknown-key-strictness-ledger.mdasserted, in the present tense, that a strict union branch's prescription is flattened away before it reaches an author. The tree has not done that since 2026-08-05. Each clause is corrected in place and now namespackages/spec/src/shared/union-branch-policy.tsas what lifted it.Exactly three lines change —
:676,:737,:940, the three the card names. 3 insertions, 3 deletions; the file is 1870 lines before and after. The os-regen companion.counts.mdis untouched.Green is not the evidence here
pnpm --filter @objectstack/spec check:strictness-ledgergrades row structure and the generated counts, not prose, and is green either way. It is reported below for completeness and proves nothing about this diff. The evidence is the reproduction.What the tree actually does — measured on this branch at
88717a548,@objectstack/specfreshly builtA.
defineStack, thestate-machine.zod.tsrow's OWN door (AgentSchema.lifecycle->StateNode.entry[]->ActionRefSchema, a union whose object arm is strict), givenentry: [{ type: 'log', parms: { a: 1 } }]:The key, the surface and the rename all arrive. The union's cost is one wrapper line, not a lost message.
B.
zodIssuesToFields, the wire door #5014 named — same body, prescription delivered as a second entry:[ { "field": "agents.0.lifecycle.states.idle.entry.0", "code": "invalid_shape", "message": "Invalid input" }, { "field": "agents.0.lifecycle.states.idle.entry.0", "code": "unknown_field", "message": "Unrecognized key(s) on this action reference: `parms`. Did you mean `parms` → `params`? ..." } ]C. what zod itself still raises at the top — so the parenthesis each corrected row KEEPS is still true:
D. the
chart.zod.tsrow's own site, with nopackages/lintanywhere in the path —ChartAggregateSchema.safeParse({ field: 'amount', function: 'sum', groupBy: { field: 'stage', dateGranularty: 'month' } })rendered by spec's ownformatZodError:Mechanism:
formatZodIssue(packages/spec/src/shared/error-map.zod.ts:254) descendsinvalid_unionand ranks the branches throughselectUnionBranches;zodIssuesToFields(packages/spec/src/api/zod-issues-to-fields.ts:213) calls the same function. Since #8318 there is one implementation of that policy,packages/spec/src/shared/union-branch-policy.ts.packages/spec/src/automation/state-machine.zod.ts:90-93already records the lift in its own JSDoc — the ledger row is the copy that was never updated.The probe was a scratch file, run and deleted; it is not committed and nothing in this diff is a test.
Provenance — why the three clauses are NOT corrected the same way
git log -Son each clause, against the dates the three flatteners landed::737state-machine.zod.ts— "whichformatZodErrorthen flattens away"5278e11f1(批 10):940view.zod.ts— "the #5014 flattening, so the key that caused it is not in the message the author sees"8064b079f(#5114 hotfix):676chart.zod.ts— "reaches an author only throughpackages/lint/src/zod-issue-format.ts's arm unpacking"e0f300ba5(#5583)The three flatteners the campaign filed: #4971
formatZodErrorat546ab3c49, 2026-08-05 · #5014 the wire mapper at2d2530300, 2026-08-05 · #5341 the CLI at3d94141ec, 2026-08-04.git merge-base --is-ancestor 546ab3c49 e0f300ba5exits 0, so spec's own renderer was already unpacking in the tree of the commit that wrote thechartclause.That asymmetry decides the edit shape:
:737and:940are re-tensed into the batch they belong to and given the file's own✅ ... LIFTEDnote, namingunion-branch-policy.ts.:676cannot be rescued that way. Re-tensing it to "at the time, X" would write a NEW false sentence, and the row's own "the cell below is kept as WRITTEN AT THE TIME" rule does not license that. So itsonlyis struck, and the generalisation it grounded — "a general constraint on every remaining union site in this campaign" — is withdrawn, with a pointer to the dispatch cycle that generalisation cost (stack.devPlugins[]hidesManifestSchema's named unknown-key refusal underinvalid_union— an author sees a keyless "Invalid input" at that one door #14722).Scope — what was deliberately NOT touched
The convention question is not settled, and did not have to be. The file already demonstrates its own idiom for a verdict that later expired, in two places outside this diff: the
chart.zod.tsrow's "✅ That fix landed at #5020, and this row'sno gateverdict is spent", and theapi/row's "the flatwireverdict this row used to carry was correct when written and then silently expired, which is the finding". This diff applies that existing idiom per clause. It adds no rule to the Format contract section and rewrites no row.Not touched, on purpose:
dashboard.zod.tsrow (:673), whosecompareTounion caveat is already framed as "批 14 recorded that ..." and already carries its ownRESOLVEDnote — correct as written;docs/audits/2026-07-unknown-key-strictness-ledger.counts.md(os-regen generated);packages/spec/src/data/analytics.zod.tsandruntime/src/domains/analytics.ts(fenced for PR feat(spec)!: close timeDimensions[].dateRange's string arm to the date-range preset vocabulary (#16041) #16618 / carddriver-memoryanalytics silently accepts an unparseabledateRangeand matches EVERY row — and the platform's own documented spelling'Last 7 days'is one of them #16041).Gates
Derived, not guessed:
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackon the merged tree, then reconciled with--ran.All 17 exit 0. Two verdict lines worth quoting (each printed by the gate itself, not read from
$?):One gate first returned
exit 3—check:doc-formula-expressions,PREREQUISITE NOT MET, its own words for "nothing was measured".@objectstack/formulaand@objectstack/lintwere built as the gate instructed and it was re-run: exit 0. It is recorded as measured only for that second run.The first derivation ran on a stale tree and said so;
origin/mainwas fetched and merged (88717a548) and the derivation re-taken, which cleared the warning.No changeset
skip-changeset. Nothing published moves:docs/audits/**appears in no package'sfiles[](checked across all 70 packages that declare one — zero mentiondocsor..), and the root package isprivate: true. The changed file is a repo-internal audit document.验收备注
A fourth site carries the same stale claim and is NOT corrected here.
docs/audits/2026-07-unknown-key-strictness-ledger.md:973-978, in theui/batch narrative:It is the same claim as
:676, from the same commit (e0f300ba5, 2026-08-08), and therefore also false the day it was written. It is left alone because it is framed as "Two things #5583 recorded that a later batch will need" — a record of what its own batch recorded, which is exactly the shape this PR was told not to touch — and because the card and the dispatch both name three sentences, not four. Flagged rather than fixed: the ledger owner should decide it in the same pass as the convention question, since after this PR the file carries a correctedchartrow and an uncorrected restatement of it 300 lines below. Noted, not filed — a stale prose sentence is not a reproducible defect, a declared-contract violation, or a metadata-authoring trap.The ledger never names #4971. The
state-machine.zod.tsrow said "filed, not fixed here" with no number, which is part of why the filing was hard to follow to its fix. The corrected clause now names it.Generated by Claude Code