Skip to content

fix(spec): make check:skill-examples's orphan scan fence-aware - #11354

Merged
os-sam merged 1 commit into
mainfrom
claude/issue-10791-fence-aware-orphan-scan
Aug 23, 2026
Merged

fix(spec): make check:skill-examples's orphan scan fence-aware#11354
os-sam merged 1 commit into
mainfrom
claude/issue-10791-fence-aware-orphan-scan

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#10791

The defect

packages/spec/scripts/check-skill-examples.ts's orphan-marker scan had no fence
awareness. extractFromFile walks every line looking for os:check marker text; the
"is this claimed by a real block" check only looks one line up (is the previous line a
ts/tsx/typescript fence-open), but the orphan scan afterwards runs over every line
in the file with no notion of being inside some other fence. A marker shown as example
text inside a ```md illustration of the convention (e.g. "put this exact line above
your fence: <!-- os:check -->") is not adjacent to any real fence, so it was never
claimed — and the orphan scan flagged it as a misplaced marker, failing the gate. The
os:check convention could not be documented in the very roots it governs (skills/,
content/docs/).

Confirming run — premise re-measurement

The card's premise is source-derived and was latent: today's corpus has all 192 (now 246,
after the #10969 SDK surface landed) markers at top level, so the gate is green on main
with nothing exercising this path.

Reproduced against origin/main's script by adding a temporary fixture
(skills/tmp-fence-repro.md, not part of this PR) with two markers:

  1. a marker shown literally inside a ```md fence, illustrating the convention
  2. a genuine top-level misplaced marker (blank line breaks adjacency)
✗ Found an os:check marker not directly above a ```ts / ```tsx / ```typescript fence
- skills/tmp-fence-repro.md:8 ← the FALSE orphan (marker shown as doc text)
- skills/tmp-fence-repro.md:13 ← the REAL orphan (genuinely misplaced)
EXIT=1

Both were reported — the false orphan confirms the defect exactly as described.

The fix

Lifted the fence-awareness shape from scripts/check-role-word.mjs's #10533 fix (the
maintainer-accepted precedent for the same "this gate's own convention must be
documentable in the roots it governs" problem): a new fenceSpans() walks every line
once, recognizing any CommonMark-shaped opening fence (any language, backtick run
length 3+, with a run-length-aware matching closer — a `````` fence wrapping a ```ts
example closes on its own fence, not the inner one; an unclosed fence runs to EOF per
CommonMark). The orphan scan in `extractFromFile` now skips any line inside such a span.

The real marked-block extraction loop is untouched — it still only recognizes bare
```ts/```tsx/```typescript fences for compilation, so this fix is scoped
exactly to the orphan-scan defect the card describes, not to a broader "nested fence"
extraction concern.

Re-running the same repro with the fix:

✗ Found an os:check marker not directly above a ```ts / ```tsx / ```typescript fence
- skills/tmp-fence-repro.md:13 ← ONLY the real orphan — line 8 no longer flagged
EXIT=1

The false orphan (line 8) is gone; the genuine orphan (line 13) still fails — the gate's
hard-error posture is unweakened. The temporary fixture was then deleted (not part of
this PR).

Self-test coverage

Added a new fixture to the existing --self-test suite in the same file, asserting both
directions in one run: a marker shown inside a ```md illustration must extract 0
blocks and report 0 orphans for that line, while a genuine top-level misplaced marker in
the same fixture must still be reported. Composing both in one fixture catches an
over-wide fix (treating every marker as "documented") as readily as an under-wide one.

Changeset

None — packages/spec/scripts/** is dev/CI tooling, not published (packages/spec's
files allowlist is dist, json-schema, liveness, prompts, llms.txt,
README.md, src/**/*.zod.ts, CHANGELOG.md, api-surface, spec-changes.json — no
scripts/). Matches the precedent for this exact shape of fix, #10787
(fix(gate): let check:role-word exempt marked vendor-wire fences), merged with the
skip-changeset label and no changeset. skip-changeset label applied to this PR via the
additive labels endpoint per repo convention, and read back after size-labeler settled.

Gates

Derived via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack against
the actual diff (packages/spec/scripts/check-skill-examples.ts only).

gateverdict
pnpm --filter @objectstack/spec check:skill-examples (self-test + full run)246 prose examples type-check across 2 surface(s)
pnpm --filter @objectstack/spec typecheck
pnpm --filter @objectstack/spec run check:empty-state
pnpm --filter @objectstack/spec run check:liveness
pnpm --filter @objectstack/spec run check:strictness-ledger
pnpm --filter @objectstack/spec run check:variant-docs
pnpm check:merge-driver
pnpm check:published-files
pnpm check:slot-lookup
pnpm check:test-source-alias
pnpm check:type-source-resolution
node scripts/check-ci-filter-parity.mjs
node scripts/check-dev-prereqs.mjs (needed a full pnpm build first — 67/67 package artifacts)
node scripts/check-plugin-teardown-shape.mjs0 known-unreached
node scripts/docs-audit/check-affected-docs.mjs✅ (pre-existing UNREACHABLE sdk-route-bridge rows are unrelated to this diff)
node scripts/check-nul-bytes.mjs

Exit codes captured before any pipe (cmd > file 2>&1; EXIT=$?); each command run through
scripts/pm/os-verify-lock.sh, verdict read from its own printed VERDICT command-exit N line.

Union re-run at final HEAD 01ade5594 (clean tree) — every family above re-run and green at
that exact commit.

⛔ Not enabled for auto-merge and not marked ready — CI convergence and merge are the PM's.

Generated by Claude Code


Generated by Claude Code

The os:check orphan-marker guard in check-skill-examples.ts scanned every
line for marker text with no notion of being inside some other fence. A
marker shown as example text inside a wrapping fence (e.g. a ```md
illustration of the convention) is not adjacent to any real ts fence, so it
was never claimed -- and the orphan scan flagged it as misplaced, making the
os:check convention undocumentable in the very roots it governs.
Adds fenceSpans(), lifted from check-role-word.mjs's #10533 fence-awareness
shape: tracks every top-level fence of any language (run-length-aware
closing, per CommonMark), and the orphan scan now skips lines inside one. A
genuine top-level misplaced marker -- not inside any fence, just not
adjacent to its own -- is unaffected and still fails loudly.
Confirmed with a run before and after: a temporary repro fixture reproduced
the false orphan against origin/main's script, and the fix removes exactly
that false positive while a real misplaced marker in the same fixture still
fails. New --self-test coverage pins both directions in one fixture.
No changeset: packages/spec/scripts/** is dev/CI tooling, not published.
Matches the skip-changeset precedent set by #10787, the same fence-awareness
shape in check-role-word.mjs.
Fixes#10791
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RadETjNRLALFLhFA3xehZP
@claudeclaudeBot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gatetooling

Projects

None yet

2 participants

@os-sam@claude