Skip to content

docs(spec): book.json's liveness header names the dead row, not a pair of integers - #16982

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-16136-book-liveness-note-counts
Sep 8, 2026
Merged

zhuangjianguo merged 1 commit into
mainfrom
claude/issue-16136-book-liveness-note-counts

Conversation

@zhuangjianguo

Copy link
Copy Markdown
Collaborator

Fixes #16136

Clause-②: no
The change rewrites one prose sentence in the _note header of a liveness ledger.
No accept set moves, no export is added, no schema arm, bound or behaviour changes,
and every per-prop status row stays byte-for-byte as it was. packages/spec's
published surface changes only in the shipped text of liveness/book.json.

The reading, re-taken on this branch's base (50dc2141a)

The _note opened with, verbatim:

15 of 17 live; the two dead entries are both inline translations maps that LOOK like the doc-level mechanism that works (doc.translations, resolveDocLocale) but have no resolver anywhere.

My own recount, walked at every nesting level of the ledger's own rows, with a live
control proving the parse worked:

top-level props:                    8   (name, label, description, slug, icon, order, audience, groups)
rows carrying a status, all levels: 14   ->  live 13 · dead 1
the one dead row:                   props.groups.children.translations
live control:                       `resolveBookTree` occurs 13x in the same read

The gate's own report beside it — check-liveness.mts --json, types.book.byStatus,
the counting method this ledger family documents and publishes in
liveness/state-counts.md:

book: { "classified": 21, "unclassified": 0, "byStatus": { "live": 20, "dead": 1 } }

which is exactly the published row | book | 20 | 0 | 0 | 1 | 0 | 21 |. So 15 and 17
appear in neither granularity — 13 of 14 by ledger rows, 20 of 21 by the gate — and
"the two dead entries" is plural where the file records one. The plural is the half a
reader acts on: it sends them hunting for a second dead inline translations map that
the ledger does not carry.

The acceptance condition: did a second dead entry ever exist?

Yes — and it was not lost. This decides the deliverable, so it is answered with
evidence rather than assumed.

Route taken: a complete clone. This container's checkout is no longer shallow —
git rev-parse --is-shallow-repository returns false, the root commit 1598cabe4
("Initial commit", 2026-01-18) is reachable, and 13,316 commits are reachable from
HEAD — so git log here is a history reading. Corroborated independently of git by
the ledger README, below.

Recounting liveness/book.json at every revision in its history:

revision date top-level props rows live dead
4f13be22b (#4488 seeding) 2026-08-01 9 15 13 2
7d2158146 (#4667) 2026-08-03 8 14 13 1
3de535b86, 9c249a69b, 8cb96ec41 → today 8 14 13 1

At seeding the ledger carried a second dead row, props.translations (book-level inline
translations), status: dead with authorWarn: true. It was removed by 7d2158146,
whose own commit message states the ledger discipline that governed the removal:

book.groups[].translations and app.homePageId are TOMBSTONED (retiredKey: never at compile time, the prescription at parse time) and keep their ledger rows, because the key stays in the walked shape. … The other four are strict deletions carrying guidance, and their rows are deleted.

So the row is absent because its key is absent from the walked shape, which is
precisely what this ledger records — not lost, not merged away. Three independent
confirmations:

  1. The schema. BookSchema carries only a comment where the key was
    (// translations removed in 17.0.0 (#4667)); BookGroupSchema.translations survives
    as retiredKey(BOOK_TRANSLATIONS_RETIRED), which is why exactly that one keeps a row.
  2. The ledger README's own book row, in writing, independent of git history:
    "清空剩余 6 条 authorWarn 死键 —— book ×2 / job.id / translation.validationMessages / app.homePageId / app.areas[].order(ADR-0049,v17 限时) #4667: both inline translation maps retired — book-level row DELETED (BookSchema
    is strictObject), group-level row KEPT as a tombstone".
  3. The gate. unclassified: 0 for book, and check:liveness enforces both
    directions — "every governed-type property at the walk's one-level granularity is
    classified … no ledger row outlives its property".

⇒ No row is missing. The clause-② fence does not fire: the ledger was complete all
along and only the sentence had gone stale, on the day the second key was retired. The
prose change is the whole deliverable.

Worth recording for the next reader: the two dead entries was true when written and
went false on 2026-08-03. 15 of 17 was never true at any granularity — the same PR that
seeded it published | book | 13 | – | 2 | – | in the README table. I did not run the
seeding-era gate to recover where that pair came from; its provenance is not established
here.

What the replacement says, and deliberately does not

Per the family precedent (#15775) and this ledger README's counting-method section — "The
Notes cell is not a place to restate a number" — the new sentence states the
boundary and restates no total. Writing "13 of 14" would have reproduced this card
with a later date.

groups[].translations is dead: an inline map that LOOKS like the doc-level mechanism that works (doc.translations, resolveDocLocale) but has no resolver anywhere. Its book-level twin was the same trap and was retired in the same pass (#4667) — that one is a strict deletion, so it left the walked shape and holds no row here, while the group-level key is TOMBSTONED (retiredKey; BookGroupSchema is a plain z.object with no .strict()) and stays in the shape this ledger walks. No total is restated in this header: state-counts.md publishes the counts and check:liveness proves that artifact fresh on every run.

The doc.translations / resolveDocLocale contrast is kept — it is real, hand-measured
content and the reason the trap works. The last clause is the anti-recurrence device: it
tells the next author why no integer is here, so one is not helpfully restored.

Scope held

Everything outside _note is byte-identical (asserted mechanically during the edit: the
parsed document minus _note serializes identically before and after). No status value
moves, no schema changes, no other liveness ledger is touched, and
liveness/state-counts.md is not hand-edited — check:liveness reports it current,
so no regeneration was owed.

Changeset — decided with both halves, measured

A changeset is owed, and the deciding tree is the published liveness/ directory, not
dist.

  1. Path in files[]? Yes. Measured from a real npm pack of packages/spec
    (276 files): liveness/book.json PRESENT; positive controls llms.txt, README.md
    PRESENT; negative control scripts/liveness/check-liveness.mts ABSENT.
  2. Is the changed text in what ships? Yes. Unpacked the real tarball
    (objectstack-spec-17.3.0.tgz) and grepped it: the new sentence is present at
    liveness/book.json, the old sentence is gone from the whole package. Positive
    control (pre-existing published text in the same file, "ADR-0046 §6 documentation
    spine") present; negative control proofErrors: [] as string[] — a string that exists
    in the working tree only inside the unpublished scripts/liveness/check-liveness.mts —
    present in the working tree, absent from the packed tree. The probe discriminates.

Verification

Gate families derived from the real change set with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
(re-derived after the changeset existed: 54 runnable commands, 6 of them new).

  • 53 of 54 green. Foremost pnpm --filter @objectstack/spec check:liveness — its own
    verdict lines: "✓ every governed-type property at the walk's one-level granularity is
    classified … no ledger row outlives its property …" and "✓
    packages/spec/liveness/state-counts.md is current — the same 36 row(s), no count column
    left in the README."
  • 1 NOT MEASURED, not red: pnpm check:dual-build-cjs-loads exits 3 with
    "PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/
    … ⛔ This is NOT a pass: nothing was measured" (87 packages unbuilt; that is a
    whole-repo build, CI's run). pnpm check:lean-entry-closure hit the same prerequisite,
    so @objectstack/objectql was built and it was re-run into a real reading: "✓ 2
    published condition(s) measured from a real load."
  • pnpm --filter @objectstack/spec test — 467 files / 13100 tests passed.
    pnpm --filter @objectstack/spec typecheck — clean (tsc --noEmit +
    check:scripts-typecheck + check:test-typecheck).
  • Build of the affected closure (pnpm --filter '@objectstack/spec...' build) and both
    test/typecheck runs went through scripts/pm/os-verify-lock.sh; every one printed
    VERDICT command-exit 0.
  • pnpm check:nul-bytes green, plus a direct control-byte self-scan over both changed
    files (grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', no hits).
  • The key families were re-run on the final commit 542b5dbf9 — liveness,
    empty-state, nul-bytes, published-files, merge-driver, doc-authoring, the two changeset
    gates, objectui-changeset, lean-entry-closure, adr-0087-registration — all exit 0.
  • pnpm lint (repo-scan) is CI's run; the local narrowing is declared and measured.
    (i) eslint's own config declares a JS/TS-only population — every files block is
    **/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs} or narrower, with no .json and no .md block.
    (ii) eslint --no-inline-config --format json over both changed paths: 2 results, 0
    errors, both "File ignored because no matching configuration was supplied" — zero files
    of this diff are in the linted population. (iii) Type-aware linting is not enabled
    anywhere in this repo (no parserOptions.project, stated in eslint.config.mjs and
    measured there with a positive control), so this diff cannot move the verdict on any
    untouched file.

Out of scope, noted and not filed

The liveness README's book Notes row still opens with "Dead 2 = BOTH inline
translations maps" before its own "#4667:" update corrects the disposition two sentences
later — the same restated-count shape as this card, one file over, in a file this card
fences off. Left for the PM to route: the card's surface is book.json's header only, and
the README is the carrier of a different family member. Successor: whoever takes the next
liveness/README.md prose card.


Generated by Claude Code

…r of integers

The `_note` opened with "15 of 17 live; the two dead entries are both inline
`translations` maps". Neither half survives a re-read of the ledger it describes:
the file carries 13 live and 1 dead row across all nesting levels, and the gate's
own report (`check-liveness.mts --json`, `types.book.byStatus`, published in
`liveness/state-counts.md`) reads `live 20 … dead 1 … classified 21`. 15 and 17
appear in neither granularity, and the plural sends a reader looking for a second
dead inline `translations` map the ledger does not record.

The second dead entry did exist and was NOT lost. `book.translations` was seeded
`dead`/`authorWarn` beside `groups[].translations` on 2026-08-01 (#4488); #4667
retired both by two deliberately different routes, stated in that PR's own commit
message: the book-level key is a strict deletion, so it left the walked shape and
its ledger row was deleted with it, while the group-level key is tombstoned
(`retiredKey`) because `BookGroupSchema` is a plain `z.object` with no `.strict()`,
where a bare delete would have zod silently strip the key. The liveness README's
`book` row records that disposition in writing, and `check:liveness` reports
`unclassified: 0` for the type while enforcing that no ledger row outlives its
property. The ledger is complete; only the sentence had gone stale, on the day the
second key was retired.

The replacement states the boundary — which row is dead, and why its twin carries
no row — and restates no total, per the ledger README's counting-method section
("The Notes cell is not a place to restate a number"). No `status` value moves, no
schema changes, and `state-counts.md` is untouched and reported current.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
@github-actions github-actions Bot added the size/s label Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/liveness/book.json), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/liveness/book.json) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 131 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json eda26cef07771f812c8091f97d935bc14900eb77 → packageMentionDocs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Sep 8, 2026
@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 8, 2026 22:50
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 8, 2026
Merged via the queue into main with commit 3030369 Sep 8, 2026
36 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-16136-book-liveness-note-counts branch September 8, 2026 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

2 participants