Filed unassigned by the os-dev seat implementing #8221 (branch claude/issue-8221-retire-legacy-string-sort). Deliberately NOT fixed there — different defect class, and #8221's diff must stay on the sort retirement.
Measured, with a control at the merge base
node scripts/check-doc-example-types.mjs exits 1 on an unmodified origin/main, one failure:
UNDECLARED FAILURE packages/types/src/zod/imported-defaults.ts:318 stripImportedDefaults
[semantic] packages/types/src/zod/imported-defaults.ts:319:28 TS2304: Cannot find name 'stripImportedDefaults'.
The measurement was taken in a separate detached worktree at f6205c10 (the merge base), pnpm install, then the build the gate itself prescribes (pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2, exit 0), then the gate. Exactly one UNDECLARED FAILURE there, and exactly the same one on the #8221 branch — the delta from that branch is zero, which is what makes this a property of main and not of a pull request.
Control that the gate is not simply refusing everything: on the same run it judged every other @example block in the tree and reported no other failure and no stale ledger row.
The example
packages/types/src/zod/imported-defaults.ts:318-322:
import { ListViewSchema as ImportedSpecListViewSchema } from '@objectstack/spec/ui';
const SpecListViewSchema = stripImportedDefaults(ImportedSpecListViewSchema);
The block imports the spec schema it operates on but never imports stripImportedDefaults, which is the very symbol the example documents. The gate compiles each block in isolation against the built types, so the free identifier is TS2304.
It arrived with PR #8721 (objectui#8317), merged 645087cd at 2026-09-09T02:24Z — about two hours before this reading.
Why nobody saw it
check:doc-examples is declared in package.json and is run by no workflow:
git grep -rn "doc-examples\|check-doc-example-types" -- .github package.json
package.json:68: "check:doc-examples": "node scripts/check-doc-example-types.mjs",
Control that the read fires: the sibling check:doc-snippets is grepped the same way and does appear in .github/workflows/doc-snippet-types.yml. So the absence above is a reading, not a bad grep.
⚠️ The half that IS enforced per PR is scripts/__tests__/check-doc-example-types.test.ts (it runs under pnpm test), and it only asserts that every LEDGER ROW names a real block. It does not assert the absence of undeclared failures, so this class is invisible to CI in both directions.
The two honest routes
- Fix the example — add
import { stripImportedDefaults } from './imported-defaults'; (or make the fenced block a usage fragment that declares it), so the gate goes green on its own terms.
- Declare it — add a ledger row keyed
packages/types/src/zod/imported-defaults.ts:318 stripImportedDefaults carrying codes [2304], a written reason and the card that owns it, which is the escape hatch the gate itself prints.
⚠️ Route 2 on a symbol's OWN example is the weaker one: the ledger's existing rows are all "usage fragment references symbols the example never declares", i.e. context the example deliberately elides. Here the missing name is the documented function itself, which is the one name a reader will copy.
⚠️ Separately worth a decision, and NOT assumed here: whether check:doc-examples should join a workflow at all. A gate with a ledger and a maintained escape hatch that nothing runs is a gate that will keep drifting; but wiring it is a CI-surface decision, so it is named rather than taken.
⛔ Note that the LINE NUMBER in a ledger key moves whenever anything above it in the file moves — #8221 had to re-key packages/types/src/objectql.ts:1604 ObjectFormSchema to :1607 purely because three lines were added higher up. That coupling is a separate observation and is not part of this card.
Dedup
MCP search_issues on repo:objectstack-ai/objectui stripImportedDefaults example returned total_count: 0. Known-hit control on the same tool in the same session: repo:objectstack-ai/objectui convertSortToQueryParams returned total_count: 2 (#8221, #6006), so the zero above is a reading and not a silently cleared query.
Related: #8317 (the card whose PR added the example), #8221 (the card whose seat measured this).
Filed by an agent seat via Claude Code, session session_01Jmxdo7bmeqCQHLSfmLVX9w.
Filed unassigned by the os-dev seat implementing #8221 (branch
claude/issue-8221-retire-legacy-string-sort). Deliberately NOT fixed there — different defect class, and #8221's diff must stay on the sort retirement.Measured, with a control at the merge base
node scripts/check-doc-example-types.mjsexits 1 on an unmodifiedorigin/main, one failure:The measurement was taken in a separate detached worktree at
f6205c10(the merge base),pnpm install, then the build the gate itself prescribes (pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2, exit 0), then the gate. Exactly one UNDECLARED FAILURE there, and exactly the same one on the #8221 branch — the delta from that branch is zero, which is what makes this a property ofmainand not of a pull request.Control that the gate is not simply refusing everything: on the same run it judged every other
@exampleblock in the tree and reported no other failure and no stale ledger row.The example
packages/types/src/zod/imported-defaults.ts:318-322:The block imports the spec schema it operates on but never imports
stripImportedDefaults, which is the very symbol the example documents. The gate compiles each block in isolation against the built types, so the free identifier is TS2304.It arrived with PR #8721 (objectui#8317), merged
645087cdat 2026-09-09T02:24Z — about two hours before this reading.Why nobody saw it
check:doc-examplesis declared inpackage.jsonand is run by no workflow:Control that the read fires: the sibling
check:doc-snippetsis grepped the same way and does appear in.github/workflows/doc-snippet-types.yml. So the absence above is a reading, not a bad grep.scripts/__tests__/check-doc-example-types.test.ts(it runs underpnpm test), and it only asserts that every LEDGER ROW names a real block. It does not assert the absence of undeclared failures, so this class is invisible to CI in both directions.The two honest routes
import { stripImportedDefaults } from './imported-defaults';(or make the fenced block a usage fragment that declares it), so the gate goes green on its own terms.packages/types/src/zod/imported-defaults.ts:318 stripImportedDefaultscarrying codes[2304], a written reason and the card that owns it, which is the escape hatch the gate itself prints.check:doc-examplesshould join a workflow at all. A gate with a ledger and a maintained escape hatch that nothing runs is a gate that will keep drifting; but wiring it is a CI-surface decision, so it is named rather than taken.⛔ Note that the LINE NUMBER in a ledger key moves whenever anything above it in the file moves — #8221 had to re-key
packages/types/src/objectql.ts:1604 ObjectFormSchemato:1607purely because three lines were added higher up. That coupling is a separate observation and is not part of this card.Dedup
MCP
search_issuesonrepo:objectstack-ai/objectui stripImportedDefaults examplereturnedtotal_count: 0. Known-hit control on the same tool in the same session:repo:objectstack-ai/objectui convertSortToQueryParamsreturnedtotal_count: 2(#8221, #6006), so the zero above is a reading and not a silently cleared query.Related: #8317 (the card whose PR added the example), #8221 (the card whose seat measured this).
Filed by an agent seat via Claude Code, session
session_01Jmxdo7bmeqCQHLSfmLVX9w.