Skip to content

docs(spec): make the SystemIdentifierSchema docblock name the surfaces it actually validates - #14194

Merged
os-support-ai merged 3 commits into
mainfrom
claude/issue-13621-identifier-docblock-truth
Sep 1, 2026
Merged

docs(spec): make the SystemIdentifierSchema docblock name the surfaces it actually validates#14194
os-support-ai merged 3 commits into
mainfrom
claude/issue-13621-identifier-docblock-truth

Conversation

@claude

@claude claude Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #13621

Clause-②: no — a docblock rewrite changes no accept or reject verdict. Declared per the triage instruction (comment 5479051953), which reads the same way, and proven mechanically below rather than asserted: the TypeScript scanner emits a byte-identical 243-token stream for identifiers.zod.ts before and after this change.

What this is

Prose truth restoration on SystemIdentifierSchema's docblock in packages/spec/src/shared/identifiers.zod.ts. The docblock claimed eleven consuming surfaces under the heading "Applies to all metadata that acts as a machine identifier". The per-surface census on #12245 — its os-dev-report comment is the measurement of record, taken on origin/main at e2debee6 — measured exactly one of those eleven as validated by this schema: select option values, SelectOptionSchema.value. Eight go to SnakeCaseIdentifierSchema or to an inline flat regex that forbids dots outright; event keys went to the sibling EventNameSchema.

The census is linked, not re-derived. Two things did have to be re-read on today's tree, because the tree moved after the census was taken: PR #14158 retired EventNameSchema (#13613) and the four branded aliases wrapping this schema (#13612). The rewritten prose states post-retirement truth.

What the docblock now says

  • The whole bound list, as a table. SelectOptionSchema.value (data/field.zod.ts) plus three keys the old prose never claimed at all: LifecyclePolicyRuleSchema.id, BucketConfigSchema.name, ObjectStorageConfigSchema.name (system/object-storage.zod.ts). Select option values are the only one with a real authored population; the object-storage three are recorded as bound in declaration with nothing authoring them — the census's own "nothing to census", never "censused clean".
  • Where each unbound surface is actually validated, so a reader who came here for the object-name rule leaves with the right file: the inline /^[a-z_][a-z0-9_]*$/ sites, SnakeCaseIdentifierSchema, MetadataItemNameSchema, and — for event keys — the closed DataEventType / BulkDataEventType enums, which are not a grammar at all.
  • That these are different accept sets, not looser spellings of one another, with the measured delta between this schema and MetadataItemNameSchema named: a., a..b, a.1b, a._b are accepted here and refused there.
  • That the dot is unexercised on the one live surface: 0 of 1218 authored select option values contain one.

The Event keys | dot.notation row of the naming-convention table and the 'order.created' (for events) example both asserted a binding that no longer exists; both now state what is true. The storage-owned length-ceiling note (#12144) is carried through unchanged.

Derived judgments — zero accept-set change, item by item

  1. .regex(/^[a-z][a-z0-9_.]*$/) — untouched. Same pattern, same flags.
  2. .min(2, ...) — untouched. Same floor, same message.
  3. .describe(...) — untouched. This is the string the generated reference page and the JSON Schema read, so leaving it alone is what keeps the generated artifacts byte-stable.
  4. .regex() message string — untouched, deliberately: it is runtime-visible output and appears in generated baselines, and it is not false (it illustrates the grammar, and it does not claim an event binding).
  5. Sibling schemas — untouched. SnakeCaseIdentifierSchema, MetadataItemNameSchema, ITEM_NAME_SEGMENT and both derived patterns are not in the diff.
  6. Whole-file proof. Every changed line in identifiers.zod.ts begins with the JSDoc continuation marker, and the TypeScript scanner run with trivia skipped yields 243 tokens before and 243 after, identical position by position. Nothing a compiler or a Zod parse can observe differs. That also settles the two gates below that read built output: this diff cannot reach them.

Three of the census's own out-of-scope items are honoured and not re-litigated: narrowing either regex, the dot-free question on option values, and the 46-site inline flat-grammar unification.

Verification

Gate union re-run after the final commit, at 00d8f0891 (which includes a merge of origin/main taken minutes before push). 40 families, derived mechanically with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack rather than from the dispatch list — the derivation found 6 families the dispatch list did not name (check:objectui-changeset, check:pm-half-states, check-changeset-no-major, check-empty-changeset, pm/check-half-states, pm/release-rehearsal-clone --self-test), and all 6 are green. Exit codes captured by redirecting first and reading the status before any pipe.

38 of 40 green. The two that did not produce a reading both stopped on the same precondition and printed it themselves:

  • node scripts/check-dev-prereqs.mjs — "The workspace is not built ... 66 of 67 workspace packages declare an entry point under dist/ that is not on disk". Reads built output for the whole workspace.
  • pnpm check:dual-build-cjs-loads — exit 3, "PREREQUISITE NOT MET ... Run pnpm build first. This is NOT a pass: nothing was measured". Its self-test passed 93 cases; only the tree-wide leg was unreachable. Note this gate distinguishes 3 from a finding's 1 precisely so the two are not confused.

Both are recorded as NOT MEASURED locally, not as red, and left to CI, which builds the workspace first. Item 6 above is the reason the omission is safe rather than merely convenient: the emitted bytes cannot differ from a comment-only edit. Measured directly as well — no emitted .d.ts or .d.cts in packages/spec/dist carries any docblock from this file, so the published type surface is untouched (and the changeset says so; an earlier draft of it claimed the opposite and was corrected once measured).

A third gate, node scripts/check-test-completeness.mjs, exits 3 by design when run without a test log and prints "the local reading for this gate is NOT MEASURED ... It is not a red, and there is nothing here to fix". Recorded as such.

Tests:

  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2448 test files / 12033 tests passed, run at 685d54bd, the commit carrying the entire change set of this PR.
  • After merging origin/main (which moved packages/spec/src/ui/component.zod.ts underneath the branch), the run was narrowed at 00d8f0891 to identifiers.test.ts, field.test.ts, object-storage.test.ts, type-alias-convention.pin.test.ts and door-reachability.testkit.test.ts5 files / 297 tests passed. Narrowing declared: a full second 12033-test pass exceeded the container's foreground window in one attempt, and the merged-in commit arrived with its own CI. CI runs the full farm on this branch regardless.
  • pnpm --filter @objectstack/spec run typecheck — green at 00d8f0891, including check:test-typecheck over tsconfig.test.json, so the test layer was actually compiled and not excluded.
  • pnpm --filter @objectstack/spec run check:docs green and the working tree clean after the build's gen:schema ran: the generated content/docs/references/shared/identifiers.mdx reads .describe(), not the docblock, so this change owes it no regeneration. Measured, not assumed.
  • node scripts/check-nul-bytes.mjs green (7751 files), plus a direct control-character scan of both edited files.

No test asserts docblock text, so nothing needed updating to match.

Changeset: patch on @objectstack/spec.


Generated by Claude Code

…und surfaces

The docblock claimed eleven consuming surfaces. The per-surface census
(its os-dev-report comment, measured on origin/main @ e2debee) measured
exactly ONE of the eleven as validated by this schema: select option
values (SelectOptionSchema.value). Eight go to SnakeCaseIdentifierSchema
or an inline flat regex that forbids dots outright; event keys went to the
sibling EventNameSchema, since retired unbound.

Rewrite the prose to name the whole bound list as it stands today
(SelectOptionSchema.value plus the three object-storage keys the old prose
never claimed, recorded as bound-but-unauthored), to point each unbound
surface at the schema that really validates it, and to state that these are
different accept sets rather than looser spellings of one grammar. Drop the
Event keys row of the naming table and the 'for events' example, both of
which asserted a binding that no longer exists.

Comment lines only: no regex change, no accept-set change, no .describe()
change. The storage-owned length-ceiling note is carried through unchanged.
The first draft of this changeset said the docblock ships into
@objectstack/spec's .d.ts and so reached consumers' editor tooltips. Measured
after the build: it does not -- no emitted .d.ts or .d.cts carries any docblock
from identifiers.zod.ts. The corrected note states the real audience (readers
of this source, human and agent), which is the audience the card was filed for.
@github-actions github-actions Bot added the size/m label Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 2 documentable anchor(s).

24 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: node scripts/docs-audit/affected-docs.mjs --json 9dd022aea05251a8bc8ee2161bd93931abd031b9.

3 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails.

What this run could not see
  • 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 — 128 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 9dd022aea05251a8bc8ee2161bd93931abd031b9packageMentionDocs.

Which tree this was computed on

This run read content/docs from a0dfc6479b80e08b18a2b622375011a3e17b2622 — the merge of head 00d8f0891db21b04ee5c94887efba93f179fdd52 into base 9dd022aea05251a8bc8ee2161bd93931abd031b9, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin a0dfc6479b80e08b18a2b622375011a3e17b2622 && git checkout a0dfc6479b80e08b18a2b622375011a3e17b2622
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9dd022aea05251a8bc8ee2161bd93931abd031b9 00d8f0891db21b04ee5c94887efba93f179fdd52 && git checkout -B drift-repro 9dd022aea05251a8bc8ee2161bd93931abd031b9 && git merge --no-ff 00d8f0891db21b04ee5c94887efba93f179fdd52

node scripts/docs-audit/affected-docs.mjs --json 9dd022aea05251a8bc8ee2161bd93931abd031b9

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 9dd022aea05251a8bc8ee2161bd93931abd031b9 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Sep 1, 2026
@os-support-ai
os-support-ai marked this pull request as ready for review September 1, 2026 11:36
@os-support-ai
os-support-ai added this pull request to the merge queue Sep 1, 2026
Merged via the queue into main with commit c41b42e Sep 1, 2026
35 checks passed
@os-support-ai
os-support-ai deleted the claude/issue-13621-identifier-docblock-truth branch September 1, 2026 12:22
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/m tooling

Projects

None yet

2 participants