Skip to content

fix(spec): the OData @example Programmatic Use bag is spelled with the $ prefixes the schema declares - #19058

Merged
os-bill merged 2 commits into
mainfrom
claude/issue-19028-odata-example-dollar-prefixes
Sep 18, 2026
Merged

os-bill merged 2 commits into
mainfrom
claude/issue-19028-odata-example-dollar-prefixes

Conversation

@os-bill

@os-bill os-bill commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes #19028

Clause-②: no

The file-level docblock of packages/spec/src/api/odata.zod.ts carried an @example Programmatic Use block that wrote every ODataQuery key unprefixed — select, filter, orderby, top, skip, expand, count — while every key the schema declares carries a $. An author who copied it got a query that asked for nothing, and nothing anywhere said so.

The defect, measured

Three legs, all through ODataQuerySchema.safeParse, at base abb01f105c. The subject bag is not retyped: the probe extracts the object literal out of the docblock itself, so what is fed is byte-for-byte what the file teaches.

leg bag result
SUBJECT the docblock literal, extracted verbatim success: true, data: {} — 0 of 7 keys kept
LIT control the same bag with $ prefixes success: true, all 7 keys kept
DARK control one fabricated key, zzz_not_a_real_odata_key success: true, data: {}

SUBJECT and DARK are the same reading. The bag the documentation taught and a bag of pure nonsense parsed identically — accepted, silently emptied, no error and no warning. The LIT leg is what makes that a statement about the example rather than about the instrument: the schema does populate when it is handed keys it declares.

The fix

The correct spelling was already ten lines above, in the same docblock: the @example OData Query block spells the URL conventions $select=, $filter=, $orderby=, $top=, $skip=, $expand=, $count=. Only the second example contradicted the schema. Seven lines of docblock prose now carry the prefixes, and pnpm --filter @objectstack/spec gen:docs reprojects the block into the reference page the same docblock feeds.

After the change, on the same probe:

leg result
SUBJECT (the corrected docblock literal) success: true, all 7 keys kept
LIT control success: true, all 7 keys kept — unmoved
DARK control success: true, data: {} — unmoved
the pre-change bag, pinned in the probe success: true, data: {} — unmoved

The last two rows are the boundary legs: the schema's behaviour toward a key it does not declare is byte-for-byte what it was. That is the claim "no behaviour change" being measured rather than asserted.

Regeneration

gen:docs wrote 224 files; exactly one moved — content/docs/references/api/odata.mdx, lines 57-69, the same seven keys. The page was already the projection of this docblock before the change (Programmatic Use read 1 on the page, with OData Query reading 1 as the lit control), so the regeneration leg confirms the projection rather than assuming it.

Scope, deliberately held

ODataQuerySchema is untouched: no .strict(), no change to the accept set, no refusal behaviour added. Whether an undeclared key should be refused instead of stripped is a different question and is not answered here. The @example OData Query block above is untouched — it was already correct, and it is the in-file evidence for what the correct spelling is.

Publishing

Per-file reading of this diff against what each package actually ships, measured with npm pack --dry-run --ignore-scripts --json in packages/spec (2039 files in the tarball):

file ships? how it was measured
packages/spec/src/api/odata.zod.ts YES present in the tarball file list; matches src/**/*.zod.ts in @objectstack/spec's files[], and that package is not private
content/docs/references/api/odata.mdx no zero tarball entries under content/docs; the path lives under the private root package @objectstack/spec-monorepo, which declares no files[]
.changeset/odata-example-programmatic-use-dollar-prefixes.md no changeset input, consumed at version time

Positive control for that reading: 214 dist/ entries are present in the same listing. Negative control: zero .test.ts entries. So a published file is in scope of this diff, the skip-changeset judgement does not apply, and this PR carries a patch changeset.

Verification

  • Gate sweep: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 101 commands for this change set; all 101 were run with the exit code captured before any pipe, and all 101 exited 0. --ran reconciliation over the recorded codes: 101 derived, 101 run, 0 NOT-MEASURED, 0 UNRUN.
  • Six of those gates first exited on a prerequisite rather than a verdict (PREREQUISITE NOT MET, exit 3, plus check:skill-examples refusing on an unbuilt client-react): a whole-repo pnpm build (73/73 tasks) cleared them and all six were re-run to a real exit 0. Their first result is recorded as not measured, not as a pass.
  • pnpm --filter @objectstack/spec test — 491 files, 14295 tests, all passed. No test assertion needed editing; this diff contains no test file and no schema byte.
  • pnpm --filter @objectstack/spec typecheck — passes, test layer included.
  • pnpm --filter @objectstack/spec check:generated — clean, and the working tree is clean after a full build, so no generated artifact moved on its own.
  • pnpm lint (eslint . --no-inline-config, the whole repository, not a narrowed subset) — exit 0, run on the final tree at 84f244a07d.

Acceptance notes

Noted while working here, deliberately not filed and not fixed:

  • The @example blocks in this docblock are not in the type-checked set. check:skill-examples type-checks 258 marked blocks across three surfaces, 10 of them TSDoc blocks in packages/spec/src; a block is marked by an HTML comment on the line directly above its fence, and this one carries none. That is why a seven-key example contradicting the schema in the same file could sit green. Marking it is not a prose change: the block would have to gain an import for ODataQuery to compile standalone, which changes what the reference page shows, and it adds a verification surface this card did not ask for. An observation about gate coverage, not a reproducible defect, a contract violation or an authoring trap — so it is recorded here rather than filed.

Generated by Claude Code

The file-level docblock of `packages/spec/src/api/odata.zod.ts` carried an
`@example Programmatic Use` block writing every `ODataQuery` key unprefixed —
`select`, `filter`, `orderby`, `top`, `skip`, `expand`, `count` — while every
key the schema declares carries a `$`. `ODataQuerySchema.safeParse` on that bag
succeeded and returned `{}`: all seven keys stripped, no error, no warning.
Measured against a bag of one fabricated key, the documented bag parsed
identically.

The correct spelling was already ten lines above in the same docblock: the
`@example OData Query` block spells the URL conventions `$select=`, `$filter=`,
`$orderby=`, `$top=`, `$skip=`, `$expand=`, `$count=`. Only the second example
was wrong; this commit prefixes its seven keys and regenerates the reference
page the same docblock feeds.

Example prose only — the schema, its accept set and its unknown-key behaviour
are untouched, so there is no behaviour change.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
…ngeset

`pnpm --filter @objectstack/spec gen:docs` reprojects the corrected docblock
into `content/docs/references/api/odata.mdx`; of the 224 files the generator
wrote, that page is the only one that moved.

`packages/spec` ships `src/**/*.zod.ts` in its `files[]` and the corrected file
is in the tarball, so this publishes and takes a patch changeset.

Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Sep 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/api/odata.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/api/odata.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 — 136 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 b14610255101483c94dccf282bb3e68859641411packageMentionDocs.

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

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

2 participants