You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(spec): regenerate drifted skill references + react-blocks contract, and gate them in CI
skills/*/references/_index.md and the objectstack-ui react-blocks contract are
generated from packages/spec/src and committed, but nothing regenerated them in
CI — no workflow referenced either generator, the spec `build` script does not
run them, and neither had a `check:` mode. They drifted. Unlike the reference
docs (#3134), these ship to third parties via `npx skills add`, so the drift is
served straight to consumers' agents.
An independent oracle over the committed indexes: 6 of 113 schema pointers named
files that no longer exist — `automation/workflow.zod.ts` (deleted by #1398),
`system/masking.zod.ts` (deleted), `data/dataset.zod.ts` (renamed to
`data/seed.zod.ts` by #1620). After this change: 126 pointers, 0 broken.
Regenerating alone was not enough. SKILL_MAP still named `data/dataset.zod.ts`,
and the generator warned-and-skipped on the missing file, so a plain regen would
have quietly dropped seed coverage from objectstack-data — whose own SKILL.md
advertises `defineSeed()` authoring — and the new gate would then have locked
that in as correct. Point the map at `data/seed.zod.ts` and make a dangling entry
a hard failure in both modes: the map is authored config, so a dangling entry is
always a bug in it, never a spec change to absorb.
Gate mechanics follow build-docs.ts (#3134): every write goes through `emit()`,
every wholesale-regenerated folder through `manageDir()`, and nothing touches
disk until `flush()` — so write and --check share all generation logic and
differ only in disposition. Extracted to scripts/lib/generated-output.ts rather
than copy-pasted. `manageDir()` takes an ownership predicate because a skill's
references/ folder is only partially generated: `_index.md` is ours, but
`react-blocks.md` (sibling generator) and hand-written notes must survive.
Placed in lint.yml's "TypeScript Type Check", not ci.yml's check-generated job.
That job is paths-filtered on skills/** and build-skill-docs.ts but NOT on
packages/spec/src/**, so it would skip exactly the spec-only PRs that cause this
drift — and it is not a required check, so it could be merged past anyway. The
type-check job has no paths filter and IS required. Both gates read src/ via tsx
and need no build (verified with every workspace dist/ removed), so they run
before the workspace build and fail in seconds.
Each gate was proven to go red before being trusted (13/13): stale content,
missing file, stale untracked leftover, dangling SKILL_MAP entry, missing skill
dir, and a spec change the contract had not absorbed. The stale-leftover case is
why manageDir exists — `git diff --exit-code` returns 0 on it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
// zod v4 may wrap the root in { $ref: '#/$defs/X', $defs: { X: {...}}}.
@@ -100,7 +105,7 @@ const contract = {
100
105
note: "Props each component accepts in kind:'react' page source. Reference blocks by their PascalCase tag. kind: data=declarative config (from the spec schema) · binding=connects to data · controlled=React state · callback=React function. These blocks are for DATA. Live data: const adapter = useAdapter(); adapter.find/findOne/create/update. STYLING (ADR-0065) — a page's source is runtime metadata, so the console's build-time Tailwind NEVER scans it: utility classNAMES silently produce no CSS. Do NOT use Tailwind className in page source. (a) Layout/chrome: inline style={} with hsl(var(--token)) theme colors — e.g. color:'hsl(var(--foreground))', background:'hsl(var(--card))', border:'1px solid hsl(var(--border))', and px/flex for layout. (b) Overlays: render <ObjectForm formType='drawer'|'modal' open onOpenChange> (a pre-styled Sheet/Dialog) — never hand-roll a fixed inset-0 backdrop.",
L.push('`React` · `useAdapter` · `data` · `variables` · `page`. Kanban/calendar/gantt/timeline/map of an object = `<ListView navigation={…} />` with the matching visualization, or `<Block type="object-kanban" …/>`.');
0 commit comments