Skip to content

Commit 0fc6219

Browse files
authored
feat(spec): the example type-check gate now covers content/docs, not just skills/ (#3882)
check:skill-examples compiles the TypeScript in prose against the built spec, so an example that stops compiling fails CI instead of quietly teaching code that no longer works. It does its job — it caught the broken defineTool example in #3876. But it only ever walked skills/: skills/ 9 files with ts blocks, 9 compiled content/docs/ 124 files with ts blocks, 0 compiled The identical break in a docs page ships. Docs examples are copied verbatim by humans and AI exactly like skill examples — the same shape as the stale-evidence and orphan-proof warnings fixed in #3857 / #3868: a gate covering a fraction of the surface it appears to cover reads as coverage. The walker is now a SOURCE_ROOTS list, and this lands the first batch: 164 docs blocks across 63 pages, taking the gate from 32 to 196 checked examples. content/docs/references/ is excluded — build-docs.ts regenerates it from the schemas, so it cannot drift independently. THE MARKER IS NOW PER-FORMAT. MDX has no HTML comments: `<!-- os:check -->` in a .mdx does not degrade, it fails the fumadocs build outright ("Unexpected character `!`… to create a comment in MDX, use `{/* text */}`"). Found by building the docs site after the first attempt broke 60+ pages; nothing in the type-check gate would have said so, because block extraction is regex-level and never parses MDX. skills/**/*.md keeps `<!-- os:check -->`; content/docs/**/*.mdx uses `{/* os:check */}`. Both spellings are recognised for ORPHAN detection, so a wrong-format marker fails loudly instead of silently checking nothing. The batch was measured, not guessed: marking all 780 docs blocks and compiling showed which are self-contained. One subtlety — a block that "passes" inside a 780-file program can be leaning on globals declared by OTHER blocks (a file with no import/export is a global script), so the first pass's 564 "passing" blocks collapsed to 164 once compiled as the real, smaller set. Converged by recompiling and dropping newly-failing blocks until green. The remaining blocks are mostly fragments, which the opt-in design anticipates. Whether any are genuine rot is now answerable for the first time.
1 parent cbedd62 commit 0fc6219

65 files changed

Lines changed: 299 additions & 35 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
"@objectstack/spec": patch
3+
---
4+
5+
feat(spec): the example type-check gate now covers `content/docs`, not just `skills/`
6+
7+
`check:skill-examples` compiles the TypeScript in prose against the built spec, so
8+
an example that stops compiling fails CI instead of quietly teaching code that no
9+
longer works. It does its job — it caught the broken `defineTool` example when
10+
`tool.requiresConfirmation` was removed (#3715).
11+
12+
But it only ever walked `skills/`:
13+
14+
| Tree | files with `ts` blocks | compiled |
15+
|---|---|---|
16+
| `skills/` | 9 | **9** |
17+
| `content/docs/` (hand-written) | 124 | **0** |
18+
19+
The identical break in a docs page would have shipped. Docs examples are copied
20+
verbatim by humans and AI exactly like skill examples, so a gate covering a
21+
fraction of the surface it appears to cover reads as coverage — the same shape as
22+
the stale-evidence and orphan-proof warnings fixed in #3857 / #3868.
23+
24+
The walker is now a `SOURCE_ROOTS` list, and this lands the first batch: **164
25+
docs blocks across 63 pages, taking the gate from 32 to 196 checked examples**.
26+
`content/docs/references/` is excluded — `build-docs.ts` regenerates it from the
27+
schemas, so it cannot drift independently of its source.
28+
29+
**The marker is now per-format.** MDX has no HTML comments: `<!-- os:check -->` in
30+
a `.mdx` fails the fumadocs build outright — *"Unexpected character `!`… to create
31+
a comment in MDX, use `{/* text */}`"*. Caught by building the docs site, after
32+
the first attempt broke 60+ pages. `skills/**/*.md` keeps `<!-- os:check -->`;
33+
`content/docs/**/*.mdx` uses `{/* os:check */}`. Both spellings are recognised for
34+
**orphan** detection, so a wrong-format marker fails loudly rather than silently
35+
checking nothing — the existing guard's philosophy, extended to the new failure
36+
mode this change introduces.
37+
38+
The batch was measured rather than guessed: marking all 780 docs blocks and
39+
compiling showed which are self-contained. One subtlety worth recording — a block
40+
that "passes" inside a 780-file program can be leaning on globals declared by
41+
*other* blocks (a file with no import/export is a global script), so the set was
42+
converged by recompiling and dropping newly-failing blocks until green. 164 stand
43+
on their own.
44+
45+
The remaining blocks are mostly fragments (a `columns: [...]` subtree), which the
46+
gate's opt-in design already anticipates. Whether any are genuine rot is worth a
47+
follow-up now that the machinery reaches them.

content/docs/ai/actions-as-tools.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Add an optional `ai:` block to give the model a precise, LLM-facing description
7070
spec; `list_actions` surfaces `ai.description` to the model, falling back to the
7171
UI `label` when it is absent.
7272

73+
{/* os:check */}
7374
```typescript
7475
export const triageCaseAction = {
7576
name: 'triage_case',

content/docs/ai/agents.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ point at, and reach it through `@objectstack/mcp` (BYO-AI).
167167

168168
## Sales Assistant Agent
169169

170+
{/* os:check */}
170171
```typescript
171172
import { defineAgent } from '@objectstack/spec/ai';
172173

content/docs/api/environment-routing.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ depending on request context.
2424

2525
Enable scoped route registration in `objectstack.config.ts`:
2626

27+
{/* os:check */}
2728
```typescript
2829
import { defineStack } from '@objectstack/spec';
2930

content/docs/api/error-handling-client.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ This guide covers best practices for handling ObjectStack API errors in client a
1717

1818
Every error response from ObjectStack follows this shape:
1919

20+
{/* os:check */}
2021
```typescript
2122
interface ErrorResponse {
2223
success: false; // Always false for error responses
@@ -56,6 +57,7 @@ Error `code` values are lowercase snake_case (`validation_error`, `permission_de
5657

5758
Create a typed error parser to extract structured information from API responses:
5859

60+
{/* os:check */}
5961
```typescript
6062
import type { ErrorResponse } from '@objectstack/spec/api';
6163

content/docs/api/error-handling-server.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ lowercase snake_case members of `StandardErrorCode` (see
2323
`@objectstack/spec/api`), e.g. `validation_error`, `resource_conflict`,
2424
`permission_denied`.
2525

26+
{/* os:check */}
2627
```typescript
2728
import type { ErrorResponse, StandardErrorCode } from '@objectstack/spec/api';
2829

@@ -289,6 +290,7 @@ export const EnrichTaskWithAI: Hook = {
289290

290291
Prevent cascading failures when an external service is down:
291292

293+
{/* os:check */}
292294
```typescript
293295
class CircuitBreaker {
294296
private failures = 0;

content/docs/automation/flows.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ A **Flow** is a visual automation that orchestrates business logic through conne
99

1010
## Basic Structure
1111

12+
{/* os:check */}
1213
```typescript
1314
const approvalFlow = {
1415
name: 'order_approval',
@@ -607,6 +608,7 @@ metadata, which `objectstack validate` will point at.
607608

608609
Flows use variables to pass data between nodes and to/from callers:
609610

611+
{/* os:check */}
610612
```typescript
611613
variables: [
612614
{ name: 'input_id', type: 'text', isInput: true, isOutput: false },
@@ -781,6 +783,7 @@ is retired; model the same logic as a Flow.
781783

782784
### Record-change flow
783785

786+
{/* os:check */}
784787
```typescript
785788
import type { Flow } from '@objectstack/spec/automation';
786789

content/docs/automation/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Automation is ObjectStack's process engine: you attach business logic to the dat
99

1010
The smallest useful automation is a hook (from the CRM example app):
1111

12+
{/* os:check */}
1213
```typescript
1314
import type { Hook, HookContext } from '@objectstack/spec/data';
1415

content/docs/automation/workflows.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ This page keeps the historical route but documents the current split.
2121
Use Flow when something should happen after a record event, schedule, button, or
2222
subflow call:
2323

24+
{/* os:check */}
2425
```typescript
2526
import type { Flow } from '@objectstack/spec/automation';
2627

@@ -63,6 +64,7 @@ registration/runtime.
6364
Use `StateMachineSchema` when the core requirement is "this object can only move
6465
through these states by these events."
6566

67+
{/* os:check */}
6668
```typescript
6769
import type { StateMachineConfig } from '@objectstack/spec/automation';
6870

content/docs/concepts/architecture.mdx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ description — data (objects), automation (flows), access (permissions), and in
8888

8989
### Example: Defining a Customer Object
9090

91+
{/* os:check */}
9192
```typescript
9293
// src/objects/customer.object.ts
9394
import { ObjectSchema, Field } from '@objectstack/spec/data';
@@ -148,6 +149,7 @@ That's the job of the other layers.
148149

149150
### Example: Permission Rules
150151

152+
{/* os:check */}
151153
```typescript
152154
// src/permissions/sales_rep.permission.ts
153155
import { definePermissionSet } from '@objectstack/spec';
@@ -175,6 +177,7 @@ export const SalesRepPermission = definePermissionSet({
175177

176178
### Example: Workflow Automation
177179

180+
{/* os:check */}
178181
```typescript
179182
// src/flows/high_value_customer.flow.ts
180183
import { defineFlow } from '@objectstack/spec';
@@ -221,6 +224,7 @@ Kernel **orchestrates** these rules at runtime, independent of the data structur
221224

222225
### Example: List View
223226

227+
{/* os:check */}
224228
```typescript
225229
// src/views/customer.view.ts
226230
import { defineView } from '@objectstack/spec';
@@ -245,6 +249,7 @@ export const CustomerView = defineView({
245249

246250
### Example: Form View
247251

252+
{/* os:check */}
248253
```typescript
249254
// src/views/customer.view.ts
250255
import { defineView } from '@objectstack/spec';
@@ -300,6 +305,7 @@ User clicks "Save"
300305

301306
### Step 2: UI Layer Sends Request
302307

308+
{/* os:check */}
303309
```typescript
304310
// ObjectUI dispatches an action to Kernel
305311
const request = {
@@ -375,6 +381,7 @@ for (const workflow of workflows) {
375381

376382
### Step 7: ObjectUI Updates Display
377383

384+
{/* os:check */}
378385
```typescript
379386
// Kernel returns success response
380387
// UI optimistically updates the screen
@@ -388,6 +395,7 @@ Here's how all three protocols collaborate for a **Kanban Board** feature:
388395

389396
### 1. ObjectQL: Define the Data
390397

398+
{/* os:check */}
391399
```typescript
392400
import { ObjectSchema, Field } from '@objectstack/spec/data';
393401

@@ -426,6 +434,7 @@ export const Opportunity = ObjectSchema.create({
426434

427435
### 2. Kernel: Define Business Rules
428436

437+
{/* os:check */}
429438
```typescript
430439
import { defineFlow } from '@objectstack/spec';
431440

@@ -450,6 +459,7 @@ export const OpportunityWonFlow = defineFlow({
450459

451460
### 3. ObjectUI: Define the Kanban View
452461

462+
{/* os:check */}
453463
```typescript
454464
import { defineView } from '@objectstack/spec';
455465

0 commit comments

Comments
 (0)