docs(spec): translation liveness _note names the live/planned boundary instead of a hand-maintained total - #16138
Merged
huangyiirene merged 1 commit intoSep 6, 2026
Conversation
…ary, not a total The `_note` header claimed "11 of 12 groups live; the twelfth, `datasets`, …", which matches no reading of the file's own `props`: fourteen entries — eleven translation groups plus `locale` and the identity keys `name`/`label` — with exactly one non-`live` row (`flows`), and `datasets` among the groups rather than a twelfth. Second wrong total in the same sentence, so the integers are deleted rather than re-derived, on #7377's precedent: the sentence now names the boundary, which the per-prop rows carry and `state-counts.md` totals. Both former totals survive quoted, as the sentence's correction record. No `status` value moves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T6HeZvT9wdSJD1ZxJb5Eno
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 130 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 6, 2026
huangyiirene
marked this pull request as ready for review
September 6, 2026 03:33
huangyiirene
enabled auto-merge
September 6, 2026 03:33
huangyiirene
deleted the
claude/issue-15775-translation-liveness-group-count
branch
September 6, 2026 04:04
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.
Fixes #15775
packages/spec/liveness/translation.json's_noteheader claimed "11 of 12 groups live; the twelfth,datasets, …". No reading of the file's ownpropsproduces that pair — and this is the second wrong total the same sentence has carried. So the integers are deleted rather than re-derived.One file's prose changes;
propsis byte-identical; nostatusvalue moves.The measurement (verified independently, not taken from the card)
A translation group is a key of
translationDataShape()inpackages/spec/src/system/translation.zod.ts— the functionTranslationItemSchemaspreads before addinglocale, the item-identity keysname/label, and the ADR-0010 protection envelope. Enumerated mechanically from that function at this branch's base (1f2a02ba):Against the ledger's own rows:
propsflows(planned)propsminuslocale/name/label)flows(planned)Neither is "11 of 12", and
datasetsis one of the eleven groups rather than a twelfth. Walked at every nesting level the file has, the non-live rows areflows,flows.children.labelandflows.children.screens— i.e. every non-liverow in the file isflowsor one of its children, which is what makes the boundary sentence true at every granularity rather than at one chosen one.What the sentence became, and why not a corrected pair of integers
The card and its triage both ruled the fix is a boundary, on #7377's precedent — that PR retired this ledger family's other hand-maintained counts by moving them out of prose into the generated
state-counts.md, and the README's counting-method section now says in writing that a Notes cell "is not a place to restate a number". The same shape applies one file down: the per-prop rows carry the verdicts,state-counts.mdcarries this type's totals, and the header states the boundary.The header now reads (one line in the JSON; wrapped here for review):
Both former totals survive quoted, as the sentence's own correction record — the file's established habit, and the reason the first failure was catchable at all. The second one is now recorded too, which it was not before: the pre-existing⚠️ clause described only the
validationMessagesoccurrence, so leaving it untouched would have left the file recording one failure where there were two. That clause is the summary claim's own provenance, so it moved with the claim; no other sentence in the_noteis touched, and the diff is one line.Diff, line by line
packages/spec/liveness/translation.json— the_notestring only.propscompares byte-identical againstHEAD~; the JSON key order, thetypefield and every row are unchanged..changeset/translation-liveness-group-boundary.md—patchon@objectstack/spec. A changeset is owed:livenessis in that package'spackage.jsonfilesarray, so these ledgers ship in the npm tarball and this is published data. That is the ledger's own recorded convention, quoted from two earlier entries inpackages/spec/CHANGELOG.md: "liveness/is in this package'sfilesarray, so these ledgers ship in the npm tarball and this is published data."skip-changesetis therefore wrong here and is not applied.Verification
Final commit
1412bcb6. All figures below were taken at that commit.Gates — derived against the real diff, not recalled.
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 51 families (re-derived after the changeset existed, which added 6). All 51 run; accounted with--ran:49 green, including every gate that actually reads this file:
check:liveness,check:empty-state,check:strictness-ledger,check:variant-docs, pluscheck:nul-bytes,check:published-files,check:merge-driver, the changeset family (check-empty-changeset,check-changeset-no-major,check-adr-0087-registration,check:changeset-gate-self-tests,check:objectui-changeset) and both docs-drift audits.check:livenessreports:2 of the 51 are NOT MEASURED, not green and not red —
check:dts-closureandcheck:dual-build-cjs-loadsboth exit 3 withPREREQUISITE NOT MET, their own words: "⛔ This is NOT a pass and NOT a finding: nothing was swept". Both read a built tree and need every one of the 79 workspace packages to carry adist/; they are matched here only by the coarsepackages/**CI job filter forBuild Core. Declared narrowing: a whole-workspace build is CI'sBuild Corejob, which runs both on the built tree. The diff cannot reach their subject in any case — it adds no export, changes no manifest, and touches no compiled source.node scripts/check-plugin-teardown-shape.mjs --self-testfirst exited 1 on the shallow checkout ("cannot read the positive control at621a4876"), which is a clone-depth refusal and not a finding; aftergit fetch origin 621a4876…it passes 47 cases.Tests.
packages/spec's liveness suites, under the shared verify lock:Declared narrowing on the affected set.
TURBO_SCM_BASE=1f2a02ba pnpm exec turbo ls --affectednames 25+ packages — the whole downstream closure of@objectstack/spec, because the file lives inside that package, not because anything in them reads it. Narrowed deliberately, and the narrowing is proved rather than assumed:propsis byte-identical, and nothing in the tree reads the file-level_note. The two tests that do read the real shipped ledger —packages/cli/test/i18n-flow-liveness-gate.test.tsandi18n-flow-screen-coverage.test.ts— read row fields (status,authorWarn) throughauthorWarnedTranslationGroups;lint-liveness-properties.tsreads a row's ownnote/authorHint, which is a different key from the file-level_note. All of those inputs are unchanged bytes.Declared narrowing on
pnpm lint. Measured, not assumed. The population comes from eslint's own config: every block ineslint.config.mjsis scoped to**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}or narrower — no block names.jsonor.md. Running eslint on exactly the two changed paths with--format jsonreturns 2 file entries, 0 errors, and one message each: "File ignored because no matching configuration was supplied." Invariance: no rule in the config reads a.jsonor.mdfile and no type-aware linting is triggered by them, so this diff cannot move the verdict on any untouched file. The narrowing here is total rather than partial — the diff contributes zero files to the linted population.Reverse verification — the direction is NOT the usual one, and that is the finding. An ablation was run from the committed state: the boundary sentence was replaced on disk with a deliberately absurd claim (
ZZZ 97 of 4 groups live ZZZ), the mutation was proved to have landed (blob hash movedceeeb575→dbf163e8; injected-marker grep count 1, removed-text grep count 0), andcheck:livenesswas re-run. It stayed green, exit 0. Restore leg:git checkout HEAD -- <path>, proved bygit diff HEADempty on the target and by the blob hash returning toceeeb575.So the observed direction is no change, not "turns red" — nothing in this repository can fail on this sentence's content, in either direction. That is precisely why the fix had to be a boundary rather than a fresh pair of integers: there is no gate to catch the third occurrence, only a reader. It is also the mechanism half already recorded as #15765, and the reason this PR adds no test — there is no assertion surface to add one to without inventing the gate that card is about, which is out of this card's scope.
Out of scope, filed not fixed
Two same-class findings surfaced while measuring and were not ridden in — both filed unassigned, both deduped against open and closed issues first:
settingsCommonis a plain strictObject #16135 — the same_note's WALK BOUNDARY sentence claims "every group is a z.record keyed by target names";settingsCommonis a plainstrictObjectwith a closed key set. Fenced out of this PR by the card's scope (the rest of the header stays byte-identical), and its repair is a judgement about the walk boundary rather than a word swap.packages/spec/liveness/book.json's header says "15 of 17 live" and "the two dead entries"; the file holds one dead row (props.groups.children.translations) and the gate reportslive 20 / dead 1 / classified 21. A different ledger file, which this card's scope forbids touching.Neither is addressed here, and neither blocks this PR.
🤖 Generated with Claude Code
Generated by Claude Code