docs(readme): make the published README TypeScript examples compile - #18968
Merged
os-try-charles merged 2 commits intoSep 18, 2026
Merged
Conversation
Splits PR #18751's census by publication (a block is published when its document is inside its package's `files[]`) and corrects the published half: 43 of 44 syntactically-valid-and-wrong blocks across 20 package READMEs. Internal documents (ADVANCED_FEATURES.md, PHASE2_IMPLEMENTATION.md, V3_MIGRATION_GUIDE.md, ARCHITECTURE.md, …) are untouched, and no gate, ratchet or CI wiring is added — #18715 ruling F. Claude-Session: https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk Co-authored-by: Claude <noreply@anthropic.com>
…blished-readme-examples-compile
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 154 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
This was referenced Sep 18, 2026
os-try-charles
marked this pull request as ready for review
September 18, 2026 09:17
os-try-charles
deleted the
claude/issue-18915-published-readme-examples-compile
branch
September 18, 2026 09:41
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.
Part of #18915
Clause-②: no
Executes maintainer decision batch #156 item 2 — ruling F on #18715. No gate, no ratchet, no CI wiring is added: this is the user-facing half of PR #18751's census, corrected.
Act 1 — the split, re-derived
PR #18751's instrument re-run on a fresh
origin/main(node scripts/measure-markdown-ts-blocks.mjs --json, workspace built first, all three controls behaving: GREEN clean, FIRING reports TS2341, UNPUBLISHED_SUBPATH reports a counted TS2307 on each of its three specifiers).The card's numbers reproduce exactly:
Split by publication — a block is published when its document is inside its package's
files[]:The split is unambiguous in this repo: every non-private package's
files[]is["dist","README.md","CHANGELOG.md"](only@objectstack/speclists more), so the published package-root Markdown is exactlyREADME.md, and every other package-root document —ADVANCED_FEATURES.md,PHASE2_IMPLEMENTATION.md,V3_MIGRATION_GUIDE.md,ARCHITECTURE.md,DEVELOPMENT_PLAN.md,PLUGIN_STANDARDS.md,REST_API_PLUGIN.md,ZOD_SCHEMA_AUDIT_REPORT.md,STACKBLITZ.md,CLIENT_SPEC_COMPLIANCE.md,ROADMAP.md, plus the privatepackages/qa/*READMEs — is internal.Confirmed against the packer rather than asserted from
package.json, with a control from the same population that must read the other way:No count in the split is zero, so no zero needed pairing.
packages/spec/liveness/README.md(PR #18938's surface) measures as published —livenessis afiles[]entry, andnpm packputsliveness/README.mdandliveness/state-counts.mdin the tarball. It is nonetheless not in this card's population: the census population is Markdown at a package root (a directory carrying apackage.json),packages/spec/livenessis not one, and the file therefore contributes none of the 76/58. No overlap with #18938, and nothing of theirs is touched here.Act 2 — the published corrections
43 of the 44 published syntactically-valid-and-wrong blocks now compile; 20 READMEs changed. Re-measured on the same instrument:
The 11 remaining published tolerant failures are 10 syntax-only blocks — bare type-signature fragments in
service-automation,trigger-record-change,trigger-scheduleandservice-job, theneeds-explicit-partial-tagclass the instrument's own forward convention describes — plus the one block below. Syntax-only blocks are outside act 2's mandate, which is the syntactically-valid-and-wrong set.What was wrong, by class:
@objectstack/client-react's hooks takefields/orderBy/limit/where; the README still wroteselect/sort/top/filters, and readPaginatedResult.valuewhere the member isrecords. AlsotimeouttotimeoutMs(service-job),attemptstomaxAttempts(service-queue),filtertowhere(IDataEngine.find).ObjectKernel.use()is async and resolves to the kernel, sokernel.use(a).use(b)does not type-check at all; andObjectKernelConfighas nopluginsmember.implements Pluginwith no import — which silently bound to the DOM'sPlugin— and three omitted the requiredinit.PluginContext.getServiceis declared with a type parameter that has no default, so every example that read a service back left itunknown.@objectstack/driver-memory's default export is a legacyonEnableobject thatkernel.use()refuses on both the type and the boot path — the quick start now registers throughDriverPlugin, and the "Key Exports" row that called it a drop-in plugin is corrected with it. Its persistence adapters take an options bag and hang underpersistence.adapter.defineStackhas nodriverkey.@objectstack/rest'sRestServertakes the hostIHttpServeras its first argument andregisterRoutes()takes none;RouteManageris constructed on a server.ObjectSchema.parse()returns the value — the{ success, data }envelope belongs tosafeParse.useMutationhas noonMutateand no mutation context, so the "Optimistic Updates" example was rebuilt on the options it does have.--strictin React and handler examples, annotated.Two of the 44 (
packages/cli,packages/mcp) were measurement artefacts worth stating plainly:objects: Object.values(objects)over an elided./src/objectsbarrel. The forgiven TS2307 leaves the namespaceany, andObject.valuesthen infers its type parameter from the union-shaped contextual type, producing a mismatch a reader's own resolvable barrel would not produce. Both now name the objects they import, which is typed and clearer either way.Beyond the counted blocks, the same defect class was corrected in three further
client-reactblocks (Master-Detail, Search with Debounce, and the Type Safety comment) that the census does not flag only because they import nothing and so type-check asany. Leavingdata.valueandselect:standing one section below a corrected copy of themselves was not defensible; this is called out because it is work outside the measured set.The one block deliberately left, and why
packages/plugins/knowledge-ragflow/README.mdwritessource.options.datasetId. That is what the shipped adapter reads (extractRagflowOptionscasts the source to a shape carrying an optionaloptionsrecord, and its error text namessource.options.datasetId), and it is not whatKnowledgeSourceSchemadeclares — the declared key isadapterConfig, and the schema is a plainz.object, so a parse would stripoptionsoutright.Correcting the document to
adapterConfigwould make it compile and stop working. Correcting the adapter is a runtime change, out of this card's scope, and picks a winner between two live spellings. Contract-first says the defect is upstream, so the block is left as it stands and the conflict is reported for the maintainer instead of being papered over in a docs PR.That is why this PR says
Part of #18915and notFixes.Changeset — measured for this diff, not inherited
The house
skip-changesetargument for docs cards is "no package'sfiles[]reachescontent/docs/**". It inverts here.README.mdis listed infiles[]for every one of the 20 packages touched, so the bytes this PR changes are inside the published tarball — measured above withnpm pack --dry-runand a same-population control that reads the other way.AGENTS.md:
skip-changeset"is for a diff that publishes nothing from any released package". This diff publishes changed bytes from twenty released packages, and those bytes are what an upgrading agent reads. So this PR carries apatchchangeset naming all twenty, and ⛔ noskip-changesetlabel.Scope
packages/*/README.mdonly, plus the changeset. ⛔ No internal document, ⛔ noCHANGELOG.md, ⛔ nocontent/docs/**, ⛔ no runtime code, ⛔ no gate or CI wiring.packages/**/README.md); it is the companion artefact the measurement above obliges, and it is named here rather than slipped in.Acceptance notes
packages/client/README.mddocumentsdata.find()'s legacy vocabulary (select/filters/sort/top). Unlike theclient-reactcase this compiles —QueryOptionsstill accepts it — so it is out of this card's set, butfinditself carries@deprecatedanddata.query()is the canonical call. Noted, not filed.check:undeclared-dep-importsfamily is not affected: nopackage.jsonmoved.Verification
Tree:
a8b75f978(origin/mainmerged in, workspace rebuilt,pnpm install --frozen-lockfileafter the lockfile moved). Every number below is from that tree.The census, final run.
node scripts/measure-markdown-ts-blocks.mjs --json, exit 0, all three controls behaving (green=clean firing=fires unpublished-subpath=fires):284 rather than 282 because the
observabilitywiring block, which redeclaredmetricsfour times in one fence, is now three fences — one per deployment, which is how a reader picks between them.Gate families, derived in-worktree from this tree with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(no stale-tree warning after the merge): 63 derived, 63 run, all exit 0, reconciled back through--ranwith each command's exit code captured before any pipe — "63 derived familt(ies) accounted for — 63 run, 0 NOT-MEASURED (a DERIVED zero — all 63 recorded an exit code and none of them is 3)".check:pm-dispatch-gatesis not among the derived families for this change set. That reconciliation answers one link only; it is not a complete account of CI.Tests. The diff changes no TypeScript, so no package's
tscprogram or vitest source set moves. Two suites do read a README this PR edits, found by grepping every test file inpackages/forREADME.md(19 hits, triaged by the path each one reads), and both were run:The first one parses
packages/client/README.mdwith the TypeScript parser and validates the manifest it finds against the install contract — it is the pin that a README edit in that package could break.Lint. Zero files in this diff are in eslint's population, measured from eslint's own config rather than assumed, with a control from the same tree that must read the other way:
eslint.config.mjsscopes every block to{ts,tsx,mts,cts,js,jsx,mjs,cjs}, so no configuration in this diff can move an untouched file's verdict either.Control bytes.
grep -naPfor the C0 range over every changed path: no hits; a fixture carrying one byte in that range hits, so the scan is live.pnpm check:nul-bytesis among the 63 green gates.Authored by Claude Code, session
session_017ef78bLdybu3AffehKkhfk.Generated by Claude Code