Skip to content

docs(spec,rest): anchor record-validator citations by symbol, not line - #16956

Merged
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-16441-repoint-record-validator-anchors
Sep 8, 2026
Merged

docs(spec,rest): anchor record-validator citations by symbol, not line#16956
zhuangjianguo merged 2 commits into
mainfrom
claude/issue-16441-repoint-record-validator-anchors

Conversation

@claude

@claude claude Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #16441

Clause-②: no
Comments only. No accept set moves, no export is added or removed, no schema arm,
bound, severity or rule id changes, and the pinned NON-rule (multiselect without
options deliberately unflagged) and its assertion are untouched. 拉回已声明契约 ⇒ 常规档.
The fence triage set held: the quoted runtime text MOVED, it is not gone, so no
re-decision was required. Evidence is the per-site table below — every quoted snippet
still occurs exactly once in record-validator.ts.

What this is

Seven prose/comment citations of packages/objectql/src/validation/record-validator.ts
pointed at line numbers that no longer resolve. Each is now anchored on the enclosing
symbol validateOne plus, where one is load-bearing, a verbatim snippet — the
convention packages/spec/liveness/field.json already uses. A snippet anchor cannot rot
silently the way a path:NNN anchor does: it either still matches or it does not.

packages/objectql/src/validation/record-validator.ts is not touched by this PR. It is
the file being cited.

Re-measured on this branch's base, f36eef55d

The card's own table is stale — the validator moved again after the card was written. These
are this branch's numbers, not the card's.

citation as it stood in the tree card's table said measured on f36eef55d drift at time of fix
record-validator.ts:471free-form (tags without options) 790 844 373 lines
record-validator.ts:452 — the allowed.length gate 772 826 374 lines
record-validator.ts:503-504 — the text-coercion branch not measured on the card 677-678 cited 503-504, actual 677-678

Positive control reproduced rather than assumed: free-form (tags without options) occurs
exactly once in the file (grep -c = 1, line 844). A zero or a multi-hit would have
changed the job; it did neither.

What the stale numbers land on today, which is the whole point of the card — both are
plausible-looking prose inside a comment block, so nothing reads as broken:

452:  * filter, and this validator has no way to tell those apart nor any business
471:  * when the value is not an operator object at all.

The seven sites, before and after, with the evidence each new anchor resolves

All four snippets below occur exactly once in record-validator.ts, and lines 677, 678,
826 and 844 all sit inside validateOne, which spans 585 to 932 (the next top-level
declaration is VALUE_SHAPE_STRICT at 933). grep -c '^function validateOne' = 1.

# site anchor before anchor after resolves because
1 packages/spec/src/kernel/functional-completeness.ts:38 record-validator.ts:452 + elided allowed.length > 0 && … record-validator.ts's validateOne, verbatim allowed.length > 0 && !allowed.includes(String(value)) snippet hits = 1, line 826
2 packages/spec/src/kernel/functional-completeness.ts:41 record-validator.ts:471 record-validator.ts's validateOne, verbatim // free-form (tags without options) snippet hits = 1, line 844
3 packages/spec/src/kernel/functional-completeness.ts:108 record-validator.ts:452 record-validator.ts's validateOne + the same verbatim gate snippet snippet hits = 1, line 826
4 packages/spec/src/kernel/functional-completeness.test.ts:12 record-validator.ts:471 record-validator.ts's validateOne, verbatim quote retained snippet hits = 1, line 844
5 packages/spec/src/kernel/functional-completeness.test.ts:103 record-validator.ts:471 record-validator.ts's validateOne, verbatim quote retained snippet hits = 1, line 844
6 packages/rest/src/rest-hook-script-fault-envelope.test.ts:45 record-validator.ts:503-504 + a hand-elided `if (t === 'text' …) { … }`
7 packages/rest/src/rest-hook-script-fault-envelope.test.ts:401 record-validator.ts:503-504 record-validator.ts's validateOne symbol hits = 1, line 585

Every site got a symbol or a verbatim snippet. No site fell back to a fresh path:NNN,
so there is no residual line-number rot risk introduced by this PR, and nothing to declare
under that heading.

Sites 6 and 7 need one extra sentence, because the guard's SPELLING changed

The old comment illustrated the branch as if (t === 'text' || …). That was already an
author's elision rather than a quote, and the runtime has since generalised the guard to a
spec-owned set: BOUNDED_STRING_FIELD_TYPES.has(t). text is a member of that set
(packages/spec/src/data/field.zod.ts:136), so what the pin asserts is unchanged — a
number in a text field is still coerced by String(value) and still breaks no declared
contract, which is exactly what the two tests assert. The load-bearing half of the old
citation, the coercion line, is present verbatim and was moved, not deleted. This is
therefore inside the repointing fence, not a re-decision; the comment now names the real
guard so the next reader is not sent looking for a disjunction that no longer exists.

Changeset — both halves of the test, for both packages

@objectstack/spec — patch changeset added.

  • Half 1 (is the changed path in files[]?) — no. files[] is
    ['dist','json-schema','liveness','prompts','llms.txt','README.md','src/**/*.zod.ts','CHANGELOG.md','api-surface','spec-changes.json']
    and functional-completeness.ts is not a *.zod.ts.
  • Half 2 (is the changed TEXT in the published dist?) — yes, and this is what decides
    it. The module doc block is emitted verbatim into packages/spec/dist/kernel/index.d.ts
    and dist/kernel/index.d.mts, both of which dist publishes. Measured on a fresh build:
    grep -rlF finds the new text in 2 dist files, the old record-validator.ts:452 /
    :471 strings in 0, and the untouched sibling line objectql/engine.ts:3191 from the
    same block sits three lines above the edit at dist/kernel/index.d.ts:5192 — so the block
    ships verbatim and these lines shipped in their old form. Positive controls from the same
    source file: field/summary-without-operations 6 hits, FUNCTIONAL_COMPLETENESS_RULES
    6 hits.
  • functional-completeness.test.ts is not emitted; the spec changeset already covers the
    package.

@objectstack/rest — no changeset, on both halves.

  • Half 1 — no. files[] is ['dist','README.md','CHANGELOG.md']; the changed file is
    src/rest-hook-script-fault-envelope.test.ts.
  • Half 2 — no, measured, not assumed. record-validator.ts:503-504 = 0 hits in
    packages/rest/dist, rest-hook-script-fault-envelope = 0, the changed sentence
    the honest half = 0. Positive control from the same module: mapDataError = 2 hits,
    VALIDATION_FAILED = 4 hits, so the grep can see published rest text when it is there.
  • One false-positive worth naming so nobody re-derives it as a yes: BOUNDED_STRING_FIELD_TYPES.has(t)
    DOES appear in packages/rest/dist/index.js:60800. That is record-validator.ts's own
    bundled runtime source, not this comment. The comment's copy lives behind a // in a
    test file that is not bundled.

Checks run, by name

Nothing below is reported from absence. Each ran in the foreground on this branch's tree;
the tests and builds went through the shared verify lock.

Build (dependency closure, then both packages):

  • pnpm --filter '@objectstack/spec^...' --filter '@objectstack/rest^...' --workspace-concurrency=2 buildVERDICT command-exit 0
  • pnpm --filter @objectstack/spec --filter @objectstack/rest --workspace-concurrency=2 buildVERDICT command-exit 0

Tests and typecheck (per-part exit codes, not a batch tail):

  • pnpm --filter @objectstack/spec exec vitest run src/kernel/functional-completeness.test.tsTest Files 1 passed (1) · Tests 50 passed (50), exit 0
  • pnpm --filter @objectstack/rest exec vitest run src/rest-hook-script-fault-envelope.test.tsTest Files 1 passed (1) · Tests 18 passed (18), exit 0
  • pnpm --filter @objectstack/spec typecheck — exit 0 (tsc --noEmit + check:scripts-typecheck + check:test-typecheck; the last reports OK — @objectstack/spec's test layer compiles)
  • pnpm --filter @objectstack/rest typecheck — exit 0 (check:test-typecheck: OK — 0 file(s) / 0 error(s))

Lint — the WHOLE-TREE run, not a narrowed one:

  • pnpm lint (eslint . --no-inline-config) — exit 0, zero findings. It completed inside the
    foreground budget, so no narrowing was declared and none is being claimed.

Gates, chosen because they read what this diff changes, plus the four that the changeset's
arrival adds to the derived family (node scripts/pm/dispatch-gates.mjs, re-derived after
the changeset existed). All exit 0:

  • pnpm check:nul-bytesOK (scanned 8384 text file(s) … no raw ASCII control bytes)
  • node scripts/check-comment-mask-adoption.mjsOK … 14 recorded
  • node scripts/check-comment-mask-corpus.mjs6384 files, 0 disagree, 0 unparseable
  • node scripts/check-system-context-census.mjsOK — 107 elevation read sites … over 128 anchors
  • pnpm check:adr-anchors — exit 0 (this file is anchored at scripts/adr-anchors/packages__spec__src__kernel__functional-completeness.ts.json; ADR-0078 still appears 11 times in the file)
  • node scripts/check-keyed-text-bounds.mjs148 keyed text-family columns judged, 148 bounded
  • node scripts/check-changeset-no-major.mjs --base origin/mainintroduces no major bump
  • node scripts/check-closing-keyword-parity.mjsOK (3 parsers agree on all 9 keywords)
  • node scripts/check-empty-changeset.mjs --base origin/mainNo empty-frontmatter changeset introduced
  • node scripts/check-adr-0087-registration.mjs --base origin/mainadds no declared-breaking changeset
  • pnpm check:changeset-gate-self-tests — 3 self-tests pass
  • pnpm check:doc-authoring398 files clean · 15159 customer-facing string(s) … clean
  • pnpm --filter @objectstack/spec run check:api-surfacepublic API surface + factory signatures unchanged
  • pnpm --filter @objectstack/spec run check:authorable-surface — exit 0, and it wrote nothing: git status is clean apart from this PR's own files
  • pnpm --filter @objectstack/spec run check:liveness — exit 0, including every path:NNN citation names a line that file actually has
  • pnpm --filter @objectstack/spec run check:llms-txt97 claim(s) re-derived
  • pnpm --filter @objectstack/spec run check:docs228 generated files in sync
  • pnpm check:published-files70 publishable package(s) … declare a files whitelist

Declared narrowing. dispatch-gates derives 75 families for this changeset. 17 were run
here; the remaining 58 are declared to CI, which runs the full farm. That is an announced
narrowing, not an omission — the ones run are the ones that read comment text, the spec
published surface, the changeset, or the anchored-file register.

验收备注

Out of scope, deliberately not in this diff, recorded for the reviewer:

  • The four docs/audits/** anchors named in the card are untouched. They are dated
    snapshots; rewriting them to today's line numbers would falsify the record. Triage fenced
    them out by name and this PR honours that fence.
  • The same doc block carries three objectql/engine.ts:NNNN anchors that are rotted
    harder than the ones this card is about, and they are NOT fixed here.
    They were never in
    the card's census, which enumerated record-validator.ts anchors only, and fixing them
    would widen a seven-site repointing. Measured read-only on f36eef55d, for whoever picks
    them up: engine.ts is 15020 lines; :3001 cites if (d?.type !== 'summary' || !d.summaryOperations) continue;
    which is at 8520; :3191 cites if (!referenceObject) continue; which is at 8868;
    :346 cites the formula-plan build, whose def?.type === 'formula' && def.expression
    is at 859. Line 3001 today is a sentence of prose, and 3191 is the head of a plain indexed for loop over rows — the same plausible-neighbour shape. Same class, same file, same doc block, one card away.
  • The card's closing question — whether prose and comment path:NNN anchors deserve a
    repo-wide gate — is not answered here and no gate is added.
    It needs its own population
    count and its own card. One datum for that card, since this PR produced it for free: the
    seven sites repointed here all had a symbol or a quotable snippet available, so a
    convention rule ("cite a symbol or a snippet, never a line") would have been satisfiable at
    every one of them without loss of precision. That is an argument for a convention gate
    rather than a line-number-freshness gate, and it is an observation, not a recommendation
    this PR acts on.

Generated by Claude Code

Seven prose/comment citations of
`packages/objectql/src/validation/record-validator.ts` pointed at line
numbers that no longer resolve: the file has moved under them, and a
`path:NNN` anchor rots silently because the line it lands on still looks
like plausible code.

Re-anchor each on something that cannot rot without saying so — the
enclosing symbol `validateOne`, plus the verbatim snippet where one is
load-bearing:

  - `packages/spec/src/kernel/functional-completeness.ts` (3 sites): the
    `select`/`radio` rule and the `multiselect` NON-rule now cite
    `validateOne` and quote `allowed.length > 0 && !allowed.includes(…)`
    and `// free-form (tags without options)` verbatim.
  - `packages/spec/src/kernel/functional-completeness.test.ts` (2 sites):
    same two anchors on the pinned NON-rule's comment.
  - `packages/rest/src/rest-hook-script-fault-envelope.test.ts` (2 sites):
    the text-coercion citation now names `validateOne` and its
    bounded-string branch (`BOUNDED_STRING_FIELD_TYPES.has(t)`, of which
    `text` is a member) and quotes the coercion line verbatim.

Comments only. No rule, assertion, accept set or runtime behaviour moves;
the quoted runtime text is unchanged and still present exactly once each.
`record-validator.ts` itself is not touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
The functional-completeness module doc is emitted verbatim into
`packages/spec/dist/kernel/index.d.ts`, which `files[]` publishes, so the
citation text that moved ships to consumers. Half 1 of the published-text
test says no (the source path is not in `files[]` and is not a
`*.zod.ts`); half 2 says yes, measured on a fresh build. `@objectstack/rest`
answers no on both halves — the changed file is a `.test.ts`, and its text
is absent from `packages/rest/dist` while a positive control from the same
file's module is present.

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/src/kernel/functional-completeness.ts), 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/src/kernel/functional-completeness.ts) — 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 97adce2faa9d27d7811f1f299f5ed806a467f624packageMentionDocs.

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Sep 8, 2026
@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 8, 2026 19:57
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 8, 2026
Merged via the queue into main with commit 22c0279 Sep 8, 2026
36 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-16441-repoint-record-validator-anchors branch September 8, 2026 20:23
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 tests tooling

Projects

None yet

2 participants