Skip to content

Commit e7eb4e9

Browse files
docs(api): make the client-sdk packages.install example parse as a manifest (#18803)
Fixes #18776 ## What was wrong `content/docs/api/client-sdk.mdx:337` — the `client.packages` fenced block on the SDK page an integrator reads before the README — showed: ```ts await client.packages.install({ id: 'com.objectstack.plugin-auth', version: '1.0.0' }); ``` Parsed against the contract that door itself declares — `PackageInstallRequestSchema`, whose `manifest` key is `ManifestSchema` (`packages/spec/src/kernel/manifest.zod.ts:244`) — the literal is refused twice: ``` invalid_value at [manifest, type] invalid_type at [manifest, name] ``` `type` and `name` are both required root manifest keys and both were absent, so the example fails when copied verbatim. Same kind as #18607, one page along. ## The repair Two required keys added, nothing else, in the key order the package's own published README uses for the same door (`packages/client/README.md:247`, landed by #18607) so the two copies of this example agree: ```ts await client.packages.install({ id: 'com.objectstack.plugin-auth', type: 'plugin', name: 'Auth Plugin', version: '1.0.0', }); ``` ⛔ No schema was touched. This card is an example that is wrong, not a contract that is wrong, and the measurement below did not invert that. ## Triage's escalation probe — the second deliverable Triage attached a mandatory escalation condition: parse every install/bootstrap example across `content/docs/api/**`, and if more than this one is refused, the finding is not one broken example but a published-example surface with no gate. **Method** (⛔ not an eye-pass). A throwaway AST probe over all 13 files of `content/docs/api/**`: `ts/typescript/tsx` fences are parsed with the TypeScript compiler API, every call site in the population below is located mechanically, and its argument literal is parsed against the contract that call site declares. An object member shape the reader does not model **throws** rather than passing quietly, and an empty population **throws** — a probe that measures nothing must not read as green. | door | population | contract it is parsed against | |:---|---:|:---| | `packages.install(<literal>)` | 1 | `PackageInstallRequestSchema` (`manifest: ManifestSchema`) | | `packages.enable/disable/uninstall(<arg>)` | 3 | the declared `id: string` | | `packages.list(<arg?>)` | 2 | the declared `filters?: { status, type, enabled }` | | `new ObjectStackClient(<literal>)` | 4 | `ClientConfig`, read out of `packages/client/src/index.ts` itself | | `defineStack(<literal>)` | 2 | `ObjectStackDefinitionSchema` | | shell fences `pnpm add` / `npm install` | 2 | the named workspace package exists and is not `private` | | **total** | **14** across 3 files | | **Positive control** — the probe must catch the refusal we already know about, or it is not measuring this. It does: ``` BEFORE tree /home/user/objectstack-18776-base @ 6de7a2d (origin/main at the branch point) population: 14 example(s) across 3 file(s) REFUSED: 1 content/docs/api/client-sdk.mdx:337 [packages.install] -> invalid_value at [manifest, type] -> invalid_type at [manifest, name] AFTER tree /home/user/objectstack-issue-18776 @ fd887ab population: 14 example(s) across 3 file(s) (unchanged — the repair moved a verdict, not the corpus) REFUSED: 0 ``` **Verdict: exactly one refusal across `content/docs/api/**`, and it is the one this card names.** The escalation condition is **not met** — nothing here re-grades the card or calls for the separate "published examples have no executability gate" carrier. Two things are reported rather than silently excluded: - `content/docs/api/metadata-api.mdx:108` and `:116` carry the install and publish request bodies as **inline prose with an explicit ellipsis** — `{ manifest: { id: "plugin-auth", name: "Plugin Auth", version: "1.0.0", ... }, ... }`. They omit `type`, but the ellipsis is written in, they are not valid TS/JSON as printed, and nothing can be copied verbatim out of them. On this lane's boundary that is 不完整, not 错误 — outside the probe's parseable population and left alone. - `content/docs/api/environment-routing.mdx:31` is a `defineStack` example whose manifest is an explicit `// ...your manifest, objects, apis, etc.` placeholder. It is accepted by `ObjectStackDefinitionSchema` as written (that key is optional), so it is a pass, not a waiver. ⛔ No gate was built, wired or modified. The card measured why three existing gates cannot see this class and recorded that wiring a census into a **required** gate is a maintainer's floor decision; this PR does not take that decision, and it deliberately does not extend #18607's README pin to this page for the same reason. ## Verification - **Gate families** — `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derives **39** families for this change set (1 path). All 39 run on the final commit `fd887ab61`, each exit code captured before any pipe: **39 exit 0**. `--ran` reconciliation: `39 derived, 39 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)`. - Four of them first answered a **prerequisite**, not a finding — `check:doc-formula-expressions`, `check:doc-security-posture` and `check:docs-transcript-drift` exited **3** (`@objectstack/lint` / `@objectstack/formula` not built) and `check:skill-examples` exited 1 on the same shape (`packages/client-react/dist` holds no `.d.ts`). Built what each one named, re-ran, all four exit 0. `check:skill-examples` is the gate whose `SDK_DOCS_PAGES` population contains this page. - **`pnpm lint` is CI's run; the local narrowing is measured, not skipped.** ① The universe read from eslint's own config: every `files:` block in `eslint.config.mjs` names `{ts,tsx,mts,cts,js,jsx,mjs,cjs}` and **zero** of them name `md` or `mdx`. ② `eslint --no-inline-config --format json content/docs/api/client-sdk.mdx` reports 1 file, 0 errors, 1 warning — *"File ignored because no matching configuration was supplied."* ③ Invariance: neither `projectService` nor `parserOptions.project` appears in `eslint.config.mjs`, so type-aware linting is off and this diff cannot move the verdict on any untouched file — and the changed file is outside the linted set entirely. - **`check:pm-dispatch-gates`** is not in this change set's derived families (it is not reachable from a `content/docs/**` path), so its detached-run prescription does not apply here. - **Merged `origin/main` at `9846f2763`** before opening; no conflict, and nothing on `main` had touched this file since the branch point. Re-derived the families from the merged tree with `main`'s newer `scripts/pm/dispatch-gates.mjs`: the same 39, no additions. Rebuilt `spec` / `lint` / `formula` / `client-react` after the merge and re-ran all 39 on the merge commit — the reading above is that run. - **No same-file collision with #18792**, which edits `:767-783` of this file. Untouched here. ## Changeset — measured, not defaulted `skip-changeset`. The criterion is whether anything published moves. - **Positive control** (the instrument can say "this ships"): `npm pack --dry-run --ignore-scripts --json` in `packages/client` lists `README.md` in the tarball — a documentation file that really does publish, and the one that carried the sibling instance in #18607. - **Reading**: that same listing contains **zero** `content/docs` entries; no `package.json` in the repo declares a `files[]` entry naming `content/docs` or escaping its own directory; `content/` contains no `package.json` at all; and its only consumer, `apps/docs`, is `private: true`. Nothing copies `content/docs/**` into a tarball at build time. ⇒ this diff publishes nothing from any released package. ## Acceptance notes - `content/docs/api/metadata-api.mdx:108` / `:116` omit the required `manifest.type` inside an explicitly-abbreviated inline body. Noted, not filed: 不完整, not an example that fails when copied, and the carrier for the class (published examples parsed by nothing) is the open question already recorded on #18607's PR — not a new card from this one. - The probe lives in this session's scratchpad and is deliberately not committed: turning it into a test is the census-into-a-required-gate decision this card says is the maintainer's. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk --- _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ Co-authored-by: claude[bot] <noreply@anthropic.com>
1 parent e08fae8 commit e7eb4e9

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

‎content/docs/api/client-sdk.mdx‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,12 @@ console.log(explained.sql, explained.params); // { sql, params }
334334

335335
```typescript
336336
const packages = await client.packages.list();
337-
await client.packages.install({ id: 'com.objectstack.plugin-auth', version: '1.0.0' });
337+
await client.packages.install({
338+
id: 'com.objectstack.plugin-auth',
339+
type: 'plugin',
340+
name: 'Auth Plugin',
341+
version: '1.0.0',
342+
});
338343
await client.packages.enable('com.objectstack.plugin-auth');
339344
await client.packages.disable('com.objectstack.plugin-auth');
340345
await client.packages.uninstall('com.objectstack.plugin-auth');

0 commit comments

Comments
 (0)