fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST - #14737

Draft
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc
Draft

fix(spec): give data/query.zod.ts a module header so its pointer rows name the query AST#14737
os-sam wants to merge 2 commits into
mainfrom
claude/issue-14441-query-zod-file-jsdoc

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#14441

What was wrong

packages/spec/src/data/query.zod.ts carries the whole QueryAST, but every published
pointer row for it read "Sort Node" — the description of a single { field, order }
pair. The public reference page content/docs/references/data/query.mdx opened on it too.

The generators publish the module's OWN doc block: top-level, in the header zone,
documenting no symbol (packages/spec/scripts/lib/file-description.ts selects it).
query.zod.ts had no block of its own, and SortNodeSchema's block qualified — the
file's long rationale comments sit between that block and its schema, so nothing attached
it to a symbol.

The mechanism was understood when the file was written: a warning comment sits directly
under that block saying the first block becomes the page description. What was not
noticed is the ordering — the first block belonged to a symbol, and a comment warning
about a rule is not the same as satisfying it.

Cost, in the skills' own terms: the skill tells an agent to Read the source for exact
field shapes, so a pointer labelled "Sort Node" makes it skip the one file that carries
the AST.

What this PR does

  • Adds a short file-level header to data/query.zod.ts, reusing the sentence
    QueryAST's own type block already carried further down the file.
  • Regenerates. Four published skill indexes (objectstack-query, -data, -api,
    -ui) and the reference page now name the query AST. The _index.md files are
    generated and were not hand-edited — check:skill-refs and check:docs both
    green prove the checked-in bytes are exactly the generators' output.
  • SortNode's block is untouched and still documents the schema it belongs to.
  • Corrects the warning comment beside it: it named two of the selector's three
    conditions, omitting the header zone — the one this defect turned on. A block
    documenting no symbol is published only while no declaration precedes it.
  • Adds packages/spec/scripts/query-pointer-row.test.ts, a two-leg pin.

Why a pin, when two gates already cover these artifacts

check:skill-refs and check:docs compare the artifact against the generator, and the
generator reproduced the wrong block faithfully — the same blind spot #5059 and #12201
found one layer up. So the pin asserts the fact the artifact must state, not the pipeline
that states it. Its two legs fail differently and both were measured:

  • SOURCE leg reds the moment the header is deleted or demoted — no regeneration needed.
  • CORPUS leg stays green through that (it reads checked-in bytes) and reds on the state
    this card actually found: an index regenerated from a file with no header of its own.

Landing shape — GOVERNED

node scripts/pm/check-governed-merges.mjs --test on this PR's 8 paths, verdict line:

governed-surface predicate: 4 of 8 path(s) hit the register (5 surfaces, repo-agnostic).
GOVERNED — a human merge is the review record for this PR (#9495 regime).
skills/** x4 — the published skills catalog

Draft PR, no ready flip, no auto-merge, not enqueued. Note the generated-surface
exception (#11705) did not lift the four skills/** paths: the predicate sees a
co-edited file under the generator's own directory (the new pin test lives in
packages/spec/scripts/), so it declines to certify a regeneration produced by the tree
under test. Governed either way here.

Published skills bundle — the two readings

Line counts are net zero; the change is 4 generated rows getting a longer, correct
description.

Per changed file, whole-file lines (before to after):

filebeforeafterdelta
skills/objectstack-api/references/_index.md49490
skills/objectstack-data/references/_index.md65650
skills/objectstack-query/references/_index.md35350
skills/objectstack-ui/references/_index.md56560

Whole published bundle: all skills/**/SKILL.md8801 to 8801 lines (+0); every file
under skills/14334 to 14334 lines (+0).

Tokens, in the ratchet's own convention ceil(utf8 bytes / 4): the four indexes go
888/1483/518/1205 to 899/1494/529/1215, and the whole published bundle 159648 to 159691
(+43)
. check-skills-token-ratchet classifies references/_index.md as
generator-owned — measured, not ratcheted, so no ceiling is in play; the ratcheted
(authored) bucket is unchanged at 141214 / 165532.

Verification

All readings below are on head 01a03f98e, worktree clean, exit codes captured before
any pipe.

checkverdict
pnpm --filter @objectstack/spec exec vitest run (whole package)Test Files 458 passed (458) · Tests 12279 passed (12279)
pnpm --filter @objectstack/spec run typecheckexit 0 — tsc --noEmit + check:scripts-typecheck + check:test-typecheck
pnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:docs229 generated files in sync with packages/spec
pnpm --filter @objectstack/spec run check:generatedexit 0 (after pnpm --filter @objectstack/spec build)
pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s)
node scripts/check-skills-token-ratchet.mjs31 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted
pnpm check:pm-skill-ratchetexit 0
pnpm check:nul-bytesscanned 8044 text file(s) ... no raw ASCII control bytes
pnpm check:doc-authoringexit 0
pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob

The new pin reads skills/ from inside packages/spec; that escape is already covered —
$TURBO_ROOT$/skills/** is a declared input of @objectstack/spec#test, and the gate
above confirms turbo.json hashes it. The test file is compiled by
packages/spec/tsconfig.scripts.json (confirmed with --listFilesOnly), so
check:scripts-typecheck really did type-check it.

The full derived family — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack,
75 commands — was run. 68 green. The other 7 measured nothing and are declared, not green:
six are the same precondition (the workspace is not fully built in this container —
66 of 67 packages have no dist/), and one is structural:

  • exit 3, PREREQUISITE NOT MET: check:dual-build-cjs-loads, check:type-check-debt,
    @objectstack/lint's check:doc-formula-expressions and check:doc-security-posture
    (needs @objectstack/formula built).
  • exit 1, same cause: check-dev-prereqs ("The workspace is not built").
  • exit 3: check-test-completeness grades a saved turbo run test log and the family
    names it with no argument — its own text says this branch is NOT MEASURED and is not a
    red.

None of the seven reads a path this diff touches. CI runs the farm regardless.

Reverse verification (measured, not asserted)

Header block deleted on disk, then restored. Mutation proven on disk before any reading —
header-sentence grep -c 0 (want 0), SortNode block still 1, and the blob hash moved
341bb947 to a8c9c601. The script carried a trap ... EXIT INT TERM with absolute
paths throughout.

legresult
SOURCE leg, pre-regenerationRED — 1 failed / 3 passed: opens on the QueryAST sentence, not on SortNode
regeneration (gen:skill-refs, exit 0)index row flips back to data/query.zod.ts — Sort Node — the exact defect reproduced
CORPUS leg, post-regenerationRED — 2 failed / 2 passed: both the source and the published-catalog assertion
after restore4 passed; and with file-description.test.ts, 97 passed

Restore proven, not assumed: git checkout HEAD -- REPO_ROOT, then both blob hashes
equal to their HEAD blobs (341bb947..., 0287454b...), git diff HEAD 0 files, 0
untracked.

Note for the reviewer

This branch was taken over. Two earlier sessions died in container restarts leaving the
worktree with one unverified commit and no PR. Every reading in this PR was produced
after the takeover, on the final head; the inherited commit was reviewed hunk by hunk and
kept, with one correction (the warning comment's missing header-zone condition, its own
commit).

Changeset: @objectstack/spec: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE


Generated by Claude Code

…ws name the query AST
The skill reference indexes and the generated `data/query` reference page
described the file carrying the whole `QueryAST` as "Sort Node": the generators
publish the module's own doc block, this file had none, and `SortNodeSchema`'s
block qualified because the file's rationale comments separate it from its
schema.
Adds one short file-level block reusing the sentence `QueryAST`'s type block
already carried, regenerates the four published indexes and the reference page,
and pins the row. `SortNode`'s block is untouched.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
… warning
The warning comment beside `SortNode`'s block said the generator publishes
"the FIRST doc block that documents no symbol". That is the condition this
card's defect turned on, but it is only two of the selector's three: a block
documenting no symbol is published only while it is still in the HEADER ZONE,
which the first declaration closes (`scripts/lib/file-description.ts`). Left
as it was, the next author could put a block documenting nothing below a
declaration and expect it on the page.
Comment-only: no doc block changes, so no generated artifact moves.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RbbUMnxkUnWhE4j94v8FE
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️1 changed file(s) yielded no anchor (packages/spec/src/data/query.zod.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/data/query.zod.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 — 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 dbf115284295b1989d4648dbfbd7e5f3f96357dcpackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/mteststooling

Projects

None yet

2 participants

@os-sam@claude