Skip to content

fix(spec): regenerate drifted reference docs and gate them in CI#3134

Merged
os-zhuang merged 2 commits into
mainfrom
claude/agitated-neumann-14a097
Jul 17, 2026
Merged

fix(spec): regenerate drifted reference docs and gate them in CI#3134
os-zhuang merged 2 commits into
mainfrom
claude/agitated-neumann-14a097

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

The bug

content/docs/references/** is generated from packages/spec and committed, but no CI job ever regenerated and diffed it:

$ grep -rlE "gen:docs|gen:schema" .github/workflows/
(nothing)

So the public reference docs drift silently while main stays green. They have been drifting since #3014 (2026-07-16).

The clearest symptom: RowCrudActionOverride is entirely missing from the docs. It is a real exported type (@objectstack/spec/data, added by #3076 on 2026-07-17), but it appears in neither the TypeScript-usage import line nor as its own properties section — users cannot discover it at all.

1. Regenerate (2b5ced2c9)

gen:schema && gen:docs dirties 7 files. Every change traces to a spec change that shipped without re-running the generator:

File Drift
data/object.mdx RowCrudActionOverride missing entirely (#3076)
api/discovery.mdx ServiceSelfInfo missing entirely
ui/dashboard.mdx ChartWidget.filterBindings, DashboardFilter.name missing
data/field.mdx readonly — now server-enforced on UPDATE (#2948/#3003)
security/permission.mdx allowTransfer — enforced now, docs still said "pending M2" (#3004)
integration/{connector,misc}.mdx connector ADR-0096 → ADR-0097; expanded providerConfig prose

The ADR renumber is a correctness fix, not churn: ADR-0096 is execution-surface identity admission, ADR-0097 is declarative connector instances (#2977). Both ADRs exist and are distinct — the published docs have been pointing readers at the wrong one.

No hand edits. Verified deterministic: two consecutive runs produce byte-identical output, so the drift is real rather than generator noise (a nondeterministic generator would have made the gate below unusable).

2. Gate it (5a4667236)

build-docs.ts --check, following the sibling convention (check:skill-docs, check:api-surface, …).

Every write now goes through emit() and every wiped folder through manageDir(), so write and check run identical generation logic and differ only in the final disposition — write to disk, or compare against it. That shared path is what makes the gate trustworthy: it cannot pass on output a real run would not produce. Verified output-identical to the previous generator, byte-for-byte across all 258 files.

Proven to fail before being trusted

A gate that cannot go red is worse than no gate, so each drift class was reproduced:

Scenario Result
Stale content (the #3076 case, replayed) ✅ exit 1 — ~ data/object.mdx (out of date)
Missing page (spec adds a type) ✅ exit 1 — + data/field.mdx (missing — spec adds it)
Stale page (type removed from spec) ✅ exit 1 — - data/ghost-type.mdx (stale — …)
json-schema/ absent ✅ exit 1, not a vacuous pass
In-sync tree ✅ exit 0 — 258 files

The last two are why this is not git diff --exit-code as originally suggested: that misses untracked files, so a brand-new page would slip through. json-schema/ is gitignored, so check:docs runs gen:schema first, and a run that finds no schemas errors rather than passing vacuously.

Placement matters

In lint.yml's "TypeScript Type Check", not ci.yml's "Build Docs":

  • "Build Docs" is gated on a docs paths-filter that excludes packages/spec/** — it skips exactly the spec-only PRs that cause this drift (feat(spec): userActions.edit/delete accept per-record CEL predicates (objectui#2614) #3076 was one). Putting the gate there leaves it dormant.
  • The typecheck job has no paths filter and is one of only four required status checks (TypeScript Type Check, Build Core, Test Core, Dogfood Regression Gate) — so the gate both always fires and actually blocks merge. A new standalone job would not be required, and would be advisory only.
  • It needs no build (reads src/ + json-schema/ via tsx), so it runs before the workspace build and fails in ~2s.

3. Same hole in the sibling job

Both artifacts are currently in sync, but were unguarded on the PRs that can break them:

  • check:spec-changes / check:upgrade-guide read the ADR-0087 registries and protocol version, but ran under a filter listing only skills/**a protocol bump or new migration could not trigger the job that verifies them.
  • The filter watched content/docs/guides/skills.mdx, a path docs(site): restructure IA into module-first single sidebar #2584 moved. Hand-edits to the real generated block in content/docs/ai/skills-reference.mdx went unchecked from then until now.

Job renamed check-skill-docscheck-generated (safe — not a required check, referenced only within ci.yml): it has guarded the protocol artifacts for a while, and a name that hid them is part of why their paths went missing from the filter.

check:api-surface was audited and is fine — lint.yml has no paths filter, so it already runs on every PR.

Verification

  • tsc --noEmit, check:docs, and eslint all green locally
  • The generated paths-filter block was parsed as YAML exactly the way dorny/paths-filter parses it, to confirm all 12 paths land
  • This PR touches packages/spec, so the new step exercises itself — see "TypeScript Type Check" below

🤖 Generated with Claude Code

os-zhuang and others added 2 commits July 17, 2026 20:19
…eSelfInfo, ADR-0097)

content/docs/references/ is generated from packages/spec by `gen:schema && gen:docs`,
but nothing in CI regenerates and diffs it, so the output has been drifting since
#3014 (2026-07-16). Regenerating dirties 7 files; every change traces to a spec
change that shipped without re-running the generator:

- data/object.mdx      RowCrudActionOverride missing entirely (#3076) — the type is
                       exported from @objectstack/spec/data but undiscoverable in docs
- api/discovery.mdx    ServiceSelfInfo missing entirely
- ui/dashboard.mdx     ChartWidget.filterBindings, DashboardFilter.name missing
- data/field.mdx       readonly: server-enforced on UPDATE (#2948/#3003)
- security/permission  allowTransfer: enforced now, was "pending M2" (#3004)
- integration/*        connector ADR-0096 → ADR-0097, expanded providerConfig prose

The ADR renumber is a correctness fix, not churn: 0096 is execution-surface identity
admission, 0097 is declarative connector instances (#2977). The published docs have
been pointing readers at the wrong ADR.

Generated output only — no hand edits. Verified deterministic: two consecutive runs
produce byte-identical output, so the drift is real rather than generator noise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…enerated gates

content/docs/references/** is generated from packages/spec and committed, but no CI
job ever regenerated and diffed it — `grep -rlE "gen:docs|gen:schema" .github/workflows/`
returned nothing. So the public reference docs drifted silently while main stayed
green: #3076 added RowCrudActionOverride to the spec and the docs never learned the
type existed. The parent commit regenerates; this one stops it recurring.

build-docs.ts --check
  Follows the sibling convention (check:skill-docs / check:api-surface / …). Every
  write now goes through emit() and every wiped folder through manageDir(), so both
  modes run identical generation logic and differ only in the final disposition —
  write, or compare. That shared path is what makes the gate trustworthy: it cannot
  pass on output a real run would not produce. Verified output-identical to the
  previous generator (byte-for-byte across all 258 files).

  Catches all three drift classes, each proven to fail before being trusted:
  stale content (the #3076 case), a missing page, and a page left behind by a type
  removed from spec. The last two are why this is not `git diff --exit-code`: that
  misses untracked files. json-schema/ is gitignored, so `check:docs` runs gen:schema
  first and a run that finds no schemas errors rather than passing vacuously.

Placement
  In lint.yml's "TypeScript Type Check", not ci.yml's "Build Docs". Build Docs is
  gated on a `docs` paths-filter that excludes packages/spec/**, so it skips exactly
  the spec-only PRs that cause this drift — #3076 was one. The typecheck job has no
  paths filter and is a required status check, so the gate cannot go dormant. It reads
  src/ + json-schema/ via tsx and needs no build, so it runs before the workspace
  build and fails in ~2s.

Same hole found in the sibling job (fixed here, both currently in sync but unguarded):
  - check:spec-changes / check:upgrade-guide read the ADR-0087 registries and the
    protocol version, but ran under a filter listing only skills/** — a protocol bump
    or new migration could not trigger the job that verifies them.
  - the filter watched content/docs/guides/skills.mdx, a path #2584 moved; hand-edits
    to the real generated block in content/docs/ai/skills-reference.mdx went unchecked.
  Job renamed check-skill-docs → check-generated: it has guarded the protocol
  artifacts for a while, and a name that hid them is part of why their paths went
  missing from the filter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@os-zhuang os-zhuang added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Jul 17, 2026
@vercel

vercel Bot commented Jul 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Building Building Preview, Comment Jul 17, 2026 12:25pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file tooling size/m and removed documentation Improvements or additions to documentation ci/cd dependencies Pull requests that update a dependency file tooling size/m labels Jul 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

102 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit c22e2c3 into main Jul 17, 2026
20 of 21 checks passed
@os-zhuang
os-zhuang deleted the claude/agitated-neumann-14a097 branch July 17, 2026 12:51
xuyushun441-sys pushed a commit that referenced this pull request Jul 17, 2026
The 243 generated reference pages carried ~92 links to a page that never
existed (`[__schema0](./__schema0)`), 6 self-links to `(./#)`, and every
inline object rendered as an opaque `Object`. Root causes, all in
build-docs.ts:

- `formatType` turned `$ref` into `./<schemaName>`, but pages are named
  after the *zod file* — so no `$ref` link could ever resolve. Named refs
  now resolve through the schemaCategoryMap/schemaZodFileMap that
  scanCategories() already built (dead code until now) to
  `/docs/references/<category>/<file>#<schema>`, and fall back to plain
  text rather than a 404 when no page exists.
- `__schemaN` refs are Zod-hoisted inline schemas with no page at all;
  they are now expanded structurally, with a cycle guard (these schemas
  are recursive — a node contains nodes — and naive inlining blows the
  stack).
- `$ref: "#"` (self-reference) now links to the section's own anchor.
- Inline objects render their shape one level deep
  (`{ label: string; value: string; color?: string; … }`) instead of
  `Object`; const variants render their literal, so discriminated unions
  read as `'a' | 'b'` rather than `Object | Object`.
- JSDoc `{@link ../automation/sync.zod.ts}` linked to a repo path that
  404s on the site; source paths now rewrite to their docs route, and a
  bare `@see` renders as "See also:" prose instead of a stray tag.
- Property type cells escape backslashes before pipes, matching the
  neighbouring `desc` escaping (and its comment) — CodeQL's
  js/incomplete-sanitization on the old order.

Counts after regenerating: __schemaN links 92 → 0, (./#) 6 → 0,
zod.ts links → 0. Passes the new `--check` gate from #3134.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 17, 2026
)

The 243 generated reference pages carried ~92 links to a page that never
existed (`[__schema0](./__schema0)`), 6 self-links to `(./#)`, and every
inline object rendered as an opaque `Object`. Root causes, all in
build-docs.ts:

- `formatType` turned `$ref` into `./<schemaName>`, but pages are named
  after the *zod file* — so no `$ref` link could ever resolve. Named refs
  now resolve through the schemaCategoryMap/schemaZodFileMap that
  scanCategories() already built (dead code until now) to
  `/docs/references/<category>/<file>#<schema>`, and fall back to plain
  text rather than a 404 when no page exists.
- `__schemaN` refs are Zod-hoisted inline schemas with no page at all;
  they are now expanded structurally, with a cycle guard (these schemas
  are recursive — a node contains nodes — and naive inlining blows the
  stack).
- `$ref: "#"` (self-reference) now links to the section's own anchor.
- Inline objects render their shape one level deep
  (`{ label: string; value: string; color?: string; … }`) instead of
  `Object`; const variants render their literal, so discriminated unions
  read as `'a' | 'b'` rather than `Object | Object`.
- JSDoc `{@link ../automation/sync.zod.ts}` linked to a repo path that
  404s on the site; source paths now rewrite to their docs route, and a
  bare `@see` renders as "See also:" prose instead of a stray tag.
- Property type cells escape backslashes before pipes, matching the
  neighbouring `desc` escaping (and its comment) — CodeQL's
  js/incomplete-sanitization on the old order.

Counts after regenerating: __schemaN links 92 → 0, (./#) 6 → 0,
zod.ts links → 0. Passes the new `--check` gate from #3134.

Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
xuyushun441-sys pushed a commit that referenced this pull request Jul 17, 2026
`skills/` is generated from the spec by `gen:skill-refs` and `gen:react-blocks`
and committed, but neither had a `check:` sibling and nothing in CI regenerated
them. Both existing gates miss this surface: `check:docs` (#3134) covers only
content/docs/references/, and `check:skill-docs` only SKILL.md frontmatter →
README + skills-reference.mdx. So it drifted — 8 committed files were stale on
main.

This matters more than the content/docs case: `skills/` is published to third
parties via `npx skills add objectstack-ai/framework --all`, so stale output
ships to users.

Fix the drift's root cause, not the output
------------------------------------------
Two published skills pointed agents at `data/dataset.zod.ts`, which #1620
renamed to `data/seed.zod.ts`. The generator warned and skipped, staying green,
so objectstack-data and objectstack-platform silently lost their seed schema
pointer and told agents to Read a path that no longer exists. SKILL_MAP now
names seed.zod.ts, and a missing mapped file is a hard error instead of a
warning — that half-rename is exactly what warn-and-skip is good at hiding.

Add --check to both generators
------------------------------
Following the convention #3134 established in build-docs.ts: every write goes
through emit(), every regenerated folder through manageDir(), and nothing
touches the tree until flush() — so check and write share byte-for-byte
identical generation logic and differ only in final disposition. Not
`git diff --exit-code`, which sees only tracked files and would miss a new or
leftover page.

The sink is extracted to scripts/lib/generated-output.ts since both generators
need it; manageDir() takes a predicate because a skill's references/ folder is a
selective wipe, not a wholesale one — hand-written siblings (data-hooks.md,
plugin-hooks.md) and the other generator's react-blocks.md live there and must
survive.

Wire into "TypeScript Type Check", not ESLint
---------------------------------------------
main requires exactly 4 status checks (TypeScript Type Check, Build Core, Test
Core, Dogfood Regression Gate). ESLint is not one of them, so a gate placed
there runs but cannot block a merge. Same job as check:docs, same reason: no
paths filter, required, and both read src/ via tsx with no build (~2s).

Proven able to go red before shipping: tampered content, deleted file, leftover
file, leftover in a sub-folder, stale SKILL_MAP entry, and both vacuous cases
(empty SKILL_MAP / empty REACT_BLOCKS) each exit 1; a hand-written .md dropped
in references/ stays green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 17, 2026
…t, and gate them in CI (#3138)

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.

Gate mechanics follow build-docs.ts (#3134): every write goes through emit(),
every wholesale-regenerated folder through manageDir(), 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. 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" (no paths filter + required), not
ci.yml's check-generated: that job's filter lists specific spec paths but no
schema dirs, so a PR touching src/data/** or src/ui/** never triggers it, and it
is not required either. Both gates need no build, 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.

Follow-up: #3139 (import regex is blind to multi-line imports).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation skip-changeset PR has no user-facing published change; bypasses the changeset gate tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant