Skip to content

docs(readme): make the published README TypeScript examples compile - #18968

Merged
os-try-charles merged 2 commits into
mainfrom
claude/issue-18915-published-readme-examples-compile
Sep 18, 2026
Merged

os-try-charles merged 2 commits into
mainfrom
claude/issue-18915-published-readme-examples-compile

Conversation

@os-try-charles

@os-try-charles os-try-charles commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator

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:

handwritten stratum   blocks 282   files 54   raw 195   tolerant 76   well-formed-and-wrong 58
changelog  stratum    blocks 720   (out of scope)

Split by publication — a block is published when its document is inside its package's files[]:

reading total published internal
tolerant failures 76 54 22
syntactically valid and wrong 58 44 14

The split is unambiguous in this repo: every non-private package's files[] is ["dist","README.md","CHANGELOG.md"] (only @objectstack/spec lists more), so the published package-root Markdown is exactly README.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 private packages/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:

npm pack --dry-run --json, packages/core
  README.md                   in tarball: True     # positive control
  ADVANCED_FEATURES.md        in tarball: False    # same population, must be absent
  PHASE2_IMPLEMENTATION.md    in tarball: False

No count in the split is zero, so no zero needed pairing.

packages/spec/liveness/README.md (PR #18938's surface) measures as publishedliveness is a files[] entry, and npm pack puts liveness/README.md and liveness/state-counts.md in the tarball. It is nonetheless not in this card's population: the census population is Markdown at a package root (a directory carrying a package.json), packages/spec/liveness is 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:

reading before after
published, syntactically valid and wrong 44 1
published, tolerant failures 54 11
internal, syntactically valid and wrong 14 14 (untouched)
internal, tolerant failures 22 22 (untouched)

The 11 remaining published tolerant failures are 10 syntax-only blocks — bare type-signature fragments in service-automation, trigger-record-change, trigger-schedule and service-job, the needs-explicit-partial-tag class 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:

  • Legacy option vocabulary. @objectstack/client-react's hooks take fields / orderBy / limit / where; the README still wrote select / sort / top / filters, and read PaginatedResult.value where the member is records. Also timeout to timeoutMs (service-job), attempts to maxAttempts (service-queue), filter to where (IDataEngine.find).
  • An async API used as a chainable one. ObjectKernel.use() is async and resolves to the kernel, so kernel.use(a).use(b) does not type-check at all; and ObjectKernelConfig has no plugins member.
  • Interfaces implemented but never imported. Four plugin examples wrote implements Plugin with no import — which silently bound to the DOM's Plugin — and three omitted the required init. PluginContext.getService is declared with a type parameter that has no default, so every example that read a service back left it unknown.
  • Removed or never-existing API, rewritten rather than left as a fossil. @objectstack/driver-memory's default export is a legacy onEnable object that kernel.use() refuses on both the type and the boot path — the quick start now registers through DriverPlugin, 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 under persistence.adapter. defineStack has no driver key. @objectstack/rest's RestServer takes the host IHttpServer as its first argument and registerRoutes() takes none; RouteManager is constructed on a server. ObjectSchema.parse() returns the value — the { success, data } envelope belongs to safeParse. useMutation has no onMutate and no mutation context, so the "Optimistic Updates" example was rebuilt on the options it does have.
  • Untyped parameters under --strict in 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/objects barrel. The forgiven TS2307 leaves the namespace any, and Object.values then 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-react blocks (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 as any. Leaving data.value and select: 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.md writes source.options.datasetId. That is what the shipped adapter reads (extractRagflowOptions casts the source to a shape carrying an optional options record, and its error text names source.options.datasetId), and it is not what KnowledgeSourceSchema declares — the declared key is adapterConfig, and the schema is a plain z.object, so a parse would strip options outright.

Correcting the document to adapterConfig would 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 #18915 and not Fixes.

Changeset — measured for this diff, not inherited

The house skip-changeset argument for docs cards is "no package's files[] reaches content/docs/**". It inverts here. README.md is listed in files[] for every one of the 20 packages touched, so the bytes this PR changes are inside the published tarball — measured above with npm pack --dry-run and 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 a patch changeset naming all twenty, and ⛔ no skip-changeset label.

Scope

  • Touched: packages/*/README.md only, plus the changeset. ⛔ No internal document, ⛔ no CHANGELOG.md, ⛔ no content/docs/**, ⛔ no runtime code, ⛔ no gate or CI wiring.
  • The changeset file is the one path outside the claim's declared file surface (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.md documents data.find()'s legacy vocabulary (select / filters / sort / top). Unlike the client-react case this compilesQueryOptions still accepts it — so it is out of this card's set, but find itself carries @deprecated and data.query() is the canonical call. Noted, not filed.
  • The check:undeclared-dep-imports family is not affected: no package.json moved.

Verification

Tree: a8b75f978 (origin/main merged in, workspace rebuilt, pnpm install --frozen-lockfile after 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):

handwritten  blocks 284  files 54  raw 172  tolerant 33  well-formed-and-wrong 15
   published                                tolerant 11  well-formed-and-wrong  1
   internal                                 tolerant 22  well-formed-and-wrong 14

284 rather than 282 because the observability wiring block, which redeclared metrics four 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 --ran with 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-gates is 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 tsc program or vitest source set moves. Two suites do read a README this PR edits, found by grepping every test file in packages/ for README.md (19 hits, triaged by the path each one reads), and both were run:

pnpm --filter @objectstack/client exec vitest run --maxWorkers=2 src/readme-package-install-example.test.ts
  Test Files 1 passed (1) · Tests 6 passed (6) · CLIENT_README_EXIT=0
pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/api/package-api.test.ts src/kernel/plugin-structure.test.ts
  Test Files 2 passed (2) · Tests 81 passed (81) · SPEC_TARGETED_EXIT=0

The first one parses packages/client/README.md with 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#calculateConfigForFile
  packages/types/README.md                             rules: 0  ignored: true
  .changeset/18915-published-readme-examples-compile.md rules: 0  ignored: true
  packages/types/src/index.ts                          rules: 6  ignored: false   # control

eslint.config.mjs scopes 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 -naP for 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-bytes is among the 63 green gates.

Authored by Claude Code, session session_017ef78bLdybu3AffehKkhfk.


Generated by Claude Code

claude Bot and others added 2 commits September 18, 2026 08:25
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>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tooling labels Sep 18, 2026
@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 20 changed file(s) yielded no anchor (packages/cli/README.md, packages/client-react/README.md, packages/client/README.md, …), 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 20 changed package(s)).

What this run could not see
  • 20 changed file(s) yielded no anchor (packages/cli/README.md, packages/client-react/README.md, packages/client/README.md, …) — 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 — 154 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 106717c3aaa992543fe66499ffbf25d8840a1f04packageMentionDocs.

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/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants