fix(spec): the OData @example Programmatic Use bag is spelled with the $ prefixes the schema declares - #19058
Merged
Conversation
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>
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 18, 2026
os-bill
marked this pull request as ready for review
September 18, 2026 15:14
os-bill
deleted the
claude/issue-19028-odata-example-dollar-prefixes
branch
September 18, 2026 15:43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #19028
Clause-②: no
The file-level docblock of
packages/spec/src/api/odata.zod.tscarried an@example Programmatic Useblock that wrote everyODataQuerykey 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 baseabb01f105c. 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.success: true,data: {}— 0 of 7 keys kept$prefixessuccess: true, all 7 keys keptzzz_not_a_real_odata_keysuccess: 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 Queryblock 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, andpnpm --filter @objectstack/spec gen:docsreprojects the block into the reference page the same docblock feeds.After the change, on the same probe:
success: true, all 7 keys keptsuccess: true, all 7 keys kept — unmovedsuccess: true,data: {}— unmovedsuccess: true,data: {}— unmovedThe 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:docswrote 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 Useread 1 on the page, withOData Queryreading 1 as the lit control), so the regeneration leg confirms the projection rather than assuming it.Scope, deliberately held
ODataQuerySchemais 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 Queryblock 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 --jsoninpackages/spec(2039 files in the tarball):packages/spec/src/api/odata.zod.tssrc/**/*.zod.tsin@objectstack/spec'sfiles[], and that package is not privatecontent/docs/references/api/odata.mdxcontent/docs; the path lives under the private root package@objectstack/spec-monorepo, which declares nofiles[].changeset/odata-example-programmatic-use-dollar-prefixes.mdPositive control for that reading: 214
dist/entries are present in the same listing. Negative control: zero.test.tsentries. So a published file is in scope of this diff, theskip-changesetjudgement does not apply, and this PR carries apatchchangeset.Verification
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 101 commands for this change set; all 101 were run with the exit code captured before any pipe, and all 101 exited 0.--ranreconciliation over the recorded codes: 101 derived, 101 run, 0 NOT-MEASURED, 0 UNRUN.PREREQUISITE NOT MET, exit 3, pluscheck:skill-examplesrefusing on an unbuiltclient-react): a whole-repopnpm 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 at84f244a07d.Acceptance notes
Noted while working here, deliberately not filed and not fixed:
@exampleblocks in this docblock are not in the type-checked set.check:skill-examplestype-checks 258 marked blocks across three surfaces, 10 of them TSDoc blocks inpackages/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 forODataQueryto 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