Skip to content

Commit d516483

Browse files
os-litantclaude
andauthored
fix(spec): give the client-SDK surface a page-scoped docs root so SDK pages can opt into check:skill-examples (#12339)
* fix(spec): give the client-SDK surface a page-scoped docs root `check:skill-examples` resolves modules per SURFACE, and a root was always a whole subtree — so "which packages may this page import?" was a property of the tree a page lives in. `content/docs/**` resolves against `@objectstack/spec` alone, and spec does not depend on `@objectstack/client`, so a marker on any docs fence importing the SDK red with TS2307 on correct code. Two pages recorded that in prose and left their SDK blocks deliberately unmarked. `SourceRoot.pages` makes a root a page SET rather than a tree, so the two SDK pages join the client-SDK surface that already resolves those packages for its 19 TSDoc blocks — no new resolution environment and no new extraction code. The scoped root's `pages` and the broad root's `excludePages` read one shared constant, and two guards prove the partition every run: no file may be scanned by two surfaces, and every scoped page must exist. Opts in the four fences that are self-contained (Quick Start, the `createFilter()` chain and the React Hooks block on the SDK page; the `services.data` example on the data-service page). The remaining nine are continuation fragments that read Quick Start's `client` and stay unmarked; both pages' notes now record the measurement rather than the old constraint. * fix(spec): the scoped-page guard must skip a root whose dir is absent `assertScopedPagesExist()` asserted SDK_DOCS_PAGES unconditionally, but this script is run against repo-SHAPED sandbox trees as well as the repo: the #7181 dist-freshness pins build one that seeds skills/, packages/spec/src and the two client packages and has no content/docs at all. There the guard reported both SDK pages missing and — being an assert that runs before everything else — spoke ahead of the three verdicts those tests pin, hijacking a positive control, a staleness refusal and an orphan-marker finding alike. `sourceFiles()` already skips a root whose `dir` does not exist. The defect was two predicates disagreeing about whether a root is present in this checkout at all, the same shape as the two fence closers (#11690) and the two fence-ownership notions (#11355) this file has already collapsed. The guard now restates that one rule. The rename protection is untouched: content/docs always exists in a real checkout, so a page renamed inside it is still judged and still reds. Pinned in both directions, with a control — an absent dir is silent in BOTH predicates, while the identical page list under a dir that DOES exist is still flagged, so the exemption is the dir and not a predicate gone quiet. --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e3430a2 commit d516483

3 files changed

Lines changed: 483 additions & 45 deletions

File tree

content/docs/api/client-sdk.mdx

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,42 +24,48 @@ pnpm add @objectstack/client
2424
```
2525

2626
{/*
27-
CONTRIBUTOR NOTE — none of this page's TypeScript fences carries an
28-
`os:check` marker, and that is a recorded decision rather than an omission.
29-
30-
`check:skill-examples` compiles marked blocks per SURFACE. `content/docs/**`
31-
belongs to the "skills + docs" surface, whose resolution dir and `paths` map
32-
are derived from `@objectstack/spec` alone — and `@objectstack/spec` does not
33-
depend on `@objectstack/client`. So a marker on any fence that imports the SDK
34-
reds with TS2307 "Cannot find module '@objectstack/client'" — a
35-
surface-resolution gap, not doc-vs-SDK drift.
36-
37-
Every other fence is a deliberate continuation fragment: Quick Start
38-
establishes `client` once and each later block continues that implied context,
39-
so a marker there reds with TS2304 "Cannot find name 'client'". Making either
40-
class compile would mean hand-declaring the SDK's own types, or injecting
41-
casts into prose whose subject IS the real API — pinning each example to
42-
itself and teaching worse code than the page teaches now.
43-
44-
Measured on this page (all 13 fences marked, then reverted): 128 diagnostics,
45-
every one TS2307 / TS2304 / TS18004 / TS18046 / TS2591 / TS7006 / TS7026 /
46-
TS2875. Not one was a doc-vs-SDK divergence.
47-
48-
The React Hooks block near the end is fenced tsx, not typescript, because it
49-
IS JSX: the gate writes every block out with its fence's own extension, and
50-
JSX in a .ts file is a syntax error. That reaches past this page — tsc stops
51-
at syntax errors and never runs the semantic pass, so one such block would
52-
suppress type-checking for every marked block across skills/ and
53-
content/docs/ (measured here: 128 semantic diagnostics collapse to 0). Please
54-
do not retag it back.
55-
56-
The marker becomes worth adding here the day the docs surface can resolve
57-
`@objectstack/client` — the same condition recorded in
58-
content/docs/kernel/runtime-services/data-service.mdx.
27+
CONTRIBUTOR NOTE — three of this page's fences carry an `os:check` marker and
28+
are compiled by `check:skill-examples` against the real SDK declarations; the
29+
rest deliberately do not. Both halves are measured, not assumed.
30+
31+
This page belongs to the client-SDK SURFACE, not to the broad
32+
`content/docs/**` one. That surface resolves `@objectstack/client`,
33+
`@objectstack/client-react` and react's real types, so a marked block here
34+
imports the SDK exactly as a reader's own code does. It was not always so:
35+
`content/docs/**` resolves against `@objectstack/spec` alone, spec does not
36+
depend on the client, and every SDK import here used to red with TS2307
37+
"Cannot find module '@objectstack/client'". The page is carved out by name
38+
(`SDK_DOCS_PAGES` in packages/spec/scripts/check-skill-examples.ts) — moving
39+
or renaming it without updating that list fails the gate loudly rather than
40+
silently returning the page to the surface that cannot resolve it.
41+
42+
What IS marked: Quick Start, the `createFilter()` builder chain, and the
43+
React Hooks block — the three that stand alone. What is not: every block that
44+
continues Quick Start's implied context. Quick Start establishes `client`
45+
once and each later block reads it, so a marker there reds with TS2304
46+
"Cannot find name 'client'"; the error-handling blocks additionally read a
47+
`catch` binding that is `unknown` (TS18046). Making those compile would mean
48+
hand-declaring the SDK's own types or injecting casts into prose whose
49+
subject IS the real API — pinning each example to itself and teaching worse
50+
code than the page teaches now.
51+
52+
Measured with all 13 fences marked, then reverted: 114 diagnostics, TS2304 /
53+
TS18046 / TS18004 / TS2591, spread over the nine continuation blocks — and
54+
ZERO TS2307. Before the carve-out the same sweep produced 128 diagnostics
55+
including TS2307 on every SDK import. Not one diagnostic in either sweep was
56+
a doc-vs-SDK divergence; that is what the three marked blocks now hold.
57+
58+
The React Hooks block is fenced tsx, not typescript, because it IS JSX: the
59+
gate writes every block out with its fence's own extension, and JSX in a .ts
60+
file is a syntax error. That reaches past this page — tsc stops at syntax
61+
errors and never runs the semantic pass, so one such block would suppress
62+
type-checking for every marked block on its whole surface. Please do not
63+
retag it back.
5964
*/}
6065

6166
## Quick Start
6267

68+
{/* os:check */}
6369
```typescript
6470
import { ObjectStackClient } from '@objectstack/client';
6571

@@ -513,6 +519,7 @@ const results = await client.data.query('account', query);
513519

514520
The `FilterBuilder` provides a rich set of filter methods:
515521

522+
{/* os:check */}
516523
```typescript
517524
import { createFilter } from '@objectstack/client';
518525

@@ -669,6 +676,7 @@ For React applications, use `@objectstack/client-react`:
669676
pnpm add @objectstack/client-react
670677
```
671678

679+
{/* os:check */}
672680
```tsx
673681
import { ObjectStackProvider, useClient, useQuery } from '@objectstack/client-react';
674682
import { ObjectStackClient } from '@objectstack/client';

content/docs/kernel/runtime-services/data-service.mdx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ Call these methods from code that **holds** the binding — a managed runtime ha
146146
a hook body: a hook has no `services` key to reach through (see above), and reads other
147147
objects via `ctx.api`.
148148
149+
{/* os:check */}
149150
```ts
150151
import type { ObjectStackClient } from '@objectstack/client';
151152

@@ -179,11 +180,17 @@ export async function recentOrdersForContact(data: DataService, contactId: strin
179180
}
180181
```
181182
182-
The block carries no `{/* os:check */}` marker, and that is a measurement rather than an
183-
omission: `check:skill-examples` compiles marked blocks against the built
184-
`@objectstack/spec` declarations only — its `paths` map is derived from that package's own
185-
`exports`, and `@objectstack/spec` does not depend on `@objectstack/client`. A marked
186-
block here would therefore have to hand-declare `DataService` instead of importing it,
187-
which pins the example to itself and nothing else. The marker becomes worth adding the day
188-
this surface has a spec-side contract to import (see the
189-
[Canonical source](#canonical-source) note).
183+
The block carries an `{/* os:check */}` marker, so `check:skill-examples` compiles it
184+
against the real `@objectstack/client` declarations on every CI run: if `data.get` /
185+
`data.find` / `data.query` change shape, this example reds rather than rotting. It used to
186+
carry no marker, and that was a measurement rather than an omission — marked blocks under
187+
`content/docs/**` were compiled against `@objectstack/spec` alone, which does not depend
188+
on `@objectstack/client`, so importing `ObjectStackClient` here red with TS2307 and
189+
hand-declaring `DataService` instead would have pinned the example to itself and nothing
190+
else. This page is now carved out by name to the client-SDK surface (`SDK_DOCS_PAGES` in
191+
`packages/spec/scripts/check-skill-examples.ts`), which resolves the SDK; renaming or
192+
moving the page without updating that list fails the gate rather than silently dropping
193+
the check.
194+
195+
The signature listing under [Methods](#methods) stays unmarked: it is a listing of method
196+
shapes, not a compilable statement, and it cannot parse at all.

0 commit comments

Comments
 (0)