Skip to content

feat(spec): retire the orphan CLICommandContributionSchema export after the contributes.commands tombstone (#12007, ADR-0049) - #12613

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-12007-cli-command-contribution-retire
Aug 26, 2026
Merged

feat(spec): retire the orphan CLICommandContributionSchema export after the contributes.commands tombstone (#12007, ADR-0049)#12613
os-zhuang merged 4 commits into
mainfrom
claude/issue-12007-cli-command-contribution-retire

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#12007

ADR-0049 enforce-or-remove, dispatched on the triage charter's graded route (enforce-or-remove channel; not a decision card). Contract-review tier (clause-②): this PR stays draft — no ready-flip, no auto-merge arming by any AI seat.

What

Retires the two orphan exports of packages/spec/src/kernel/cli-extension.zod.ts:

  • CLICommandContributionSchema (schema const)
  • CLICommandContribution (type)

The pair described a "CLI Command Contribution declaration in the manifest" and claimed retention "for describing command metadata in plugin manifests" — but since the manifest.contributes.commandsretiredKey() tombstone landed (#10724 remains addressed by its own family PR, not here), no manifest surface could legally carry these entries: the exported schema advertised a shape whose only declared carrier rejects it. The manifest never referenced this schema even before the tombstone — its inline commands item schema was an independent duplicate. This is the recorded orphan-value-schema class (#3950: an exported schema with no consumer reads as a capability).

Kept, per the charter: the module docblock's Commander.js-migration prose (cli-extension.zod.ts) — it is load-bearing, cited verbatim by the contributes.commands tombstone, so full-file deletion was explicitly not the shape. OclifPluginConfigSchema / OclifPluginConfig (the live package.jsonoclif section, same module) are out of scope and untouched — pinned as survivors.

Premise re-verification (rule: issue body is a lead, not a spec)

Re-verified on origin/main at 146f448a5 (base) — all four premises hold:

  • exports present at cli-extension.zod.ts line 75 (schema) and line 128 (type); test file present
  • the contributes.commands tombstone is live in manifest.zod.ts
  • zero consumers outside spec's own test + generated artifacts + generated reference docs — measured with positive controls: objectstack (git grep, control OclifPluginConfigSchema hits), objectui at the pinned sha 190fbd01d (zero hits; control @objectstack/spec hits), cloud (zero hits; control hits)
  • no liveness-ledger rows exist for the def (nothing to re-classify)

The retirement kit (route 3 — whole-def deletion)

No carrier key, no authored document for a D2 conversion to rewrite, so no tombstone and no conversion — the registry entries ARE the declaration (the AdvancedPluginLifecycleConfig / identity ApiKey family shape):

  • RETIRED_DEFS_BY_MAJOR[18] entry kernel/CLICommandContribution (entry file under entries/retired-defs/, registry regenerated by gen:migration-registry)
  • D3 semantic entry cli-command-contribution-retired (entry file under entries/semantic/)
  • deliberate same-PR deletions the gates demanded and then accepted: the json-schema.manifest/kernel.json def line and the three authorable-surface/kernel.json rows (name, description, module) — both gates fired first and went green only after the registry entry + deletions landed together, which is the route's own evidence trail
  • generated artifacts regenerated via check:generated --fix (only the proved-stale set): api-surface/kernel.json, export-origins/kernel.json, the two generated reference docs pages (their entries disappear), the strictness-ledger counts. spec-changes.json / upgrade guide are unchanged as expected — major-18 rows materialize at the protocol bump (family precedent)
  • test disposition: the retired half of cli-extension.test.ts removed (the Oclif half stays); new retirement pin cli-command-contribution-retirement.test.ts (zero holders for both names on every public entry via export-origins, survivors pinned, anti-vacuity guards) — the AdvancedPluginLifecycleConfig is an authorable surface with no runtime consumer — nothing reads .health, and the kernel never constructs PluginHealthMonitor #11825 form
  • ADR-0122 pin Iso385 removed from type-alias-convention.pin.test.ts; pin count 838 to 837 with a history receipt (the count assertion went red on the full suite first, then green — a real measured direction)
  • changeset cli-command-contribution-retired.md, @objectstack/specminor per the launch-window convention (the family precedent's bump class — BREAKING export removal riding the 17.x line, prescription registered at major 18), FROM/TO mapping, one-line fix, and the adr-0087 registered marker naming the D3 entry

Verification

All commands via the shared verify lock; exit codes captured before any pipe; verdict lines quoted from the gates' own output. Final head 0ef62965a (merge of current origin/main immediately before this PR; two incoming spec commits, disjoint files, clean merge, no os-regen deferrals).

At final head 0ef62965a:

  • pnpm --filter @objectstack/spec build — exit 0
  • pnpm --filter @objectstack/spec check:generated — "All 14 generated artifacts are up to date." (includes authorable-surface, api-surface, export-origins, docs, spec-changes, upgrade-guide, migration-registry, liveness, strictness-ledger)
  • pnpm --filter @objectstack/spec typecheck — exit 0 (tsc + scripts + test typecheck)
  • pnpm --filter @objectstack/spec test — "Test Files 434 passed (434) · Tests 11514 passed (11514)"
  • pnpm check:type-check-debt --re-measure on the built workspace closure (result stated in the report comment on the issue)

Derived-gate sweep (node scripts/pm/dispatch-gates.mjs, derivation stderr pinned to this repo at 74a374594): 44 additional families run with per-gate exit capture — adr-0087-registration, changeset gates, cross-package-test-inputs, doc gates, spec-parsed-alias, test-source-alias, engine-double-contract, where-matcher, query-options-erasure, type-check-coverage, nul-bytes, and the rest — all EXIT=0. Sweep measured at the pre-merge tree (74a374594 + the pin-count fix); the ratchet families (generated artifacts, typecheck, tests, type-check debt) re-ran at the final merged head as listed above.

Declared narrowing: downstream-consumer sweep is by symbol grep rather than a monorepo-wide typecheck — the removed names have zero references outside packages/spec in objectstack, objectui (pinned sha) and cloud, each grep with a firing positive control, so no dependent package's compile can observe the removal; the workspace closure (70 packages) also built green at the pre-merge tree.

Scope

File surface as claimed on the issue: cli-extension.zod.ts, its test file + the new retirement pin + the ADR-0122 pin registry line, the two ADR-0087 entry files (+ regenerated registry), generated artifacts, one changeset. Queued sibling #12497 (allowRestore/allowPurge) is hard-serialized behind this card and its surfaces are untouched here. content/docs/releases/ untouched. Out of scope, not addressed here: #10724 (landed), #12497 (queued).


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

4 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️5 changed file(s) yielded no anchor (packages/spec/api-surface/kernel.json, packages/spec/authorable-surface/kernel.json, packages/spec/export-origins/kernel.json, …), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 5 changed file(s) yielded no anchor (packages/spec/api-surface/kernel.json, packages/spec/authorable-surface/kernel.json, packages/spec/export-origins/kernel.json, …) — pages documenting those are invisible to this run
  • 4 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 47 of 219 client-bound route-ledger rows — the other 172 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 172: 14 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 56 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 102 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d7b3963c2d4f2b8f043f04fa708d54f642bd97e9packageMentionDocs.

Which tree this was computed on

This run read content/docs from 7bb14f94c83ad324db9c5abba733d0447491ca8b — the merge of head 0ef62965a34a38be26cd6c722cf38f1becfb98b9 into base d7b3963c2d4f2b8f043f04fa708d54f642bd97e9, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7bb14f94c83ad324db9c5abba733d0447491ca8b && git checkout 7bb14f94c83ad324db9c5abba733d0447491ca8b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d7b3963c2d4f2b8f043f04fa708d54f642bd97e9 0ef62965a34a38be26cd6c722cf38f1becfb98b9 && git checkout -B drift-repro d7b3963c2d4f2b8f043f04fa708d54f642bd97e9 && git merge --no-ff 0ef62965a34a38be26cd6c722cf38f1becfb98b9
node scripts/docs-audit/affected-docs.mjs --json d7b3963c2d4f2b8f043f04fa708d54f642bd97e9

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 26, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review August 26, 2026 22:12
@os-zhuang
os-zhuang added this pull request to the merge queueAug 26, 2026
Merged via the queue into main with commit 7a25e7dAug 26, 2026
35 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-12007-cli-command-contribution-retire branch August 26, 2026 22:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLICommandContributionSchema is an orphan export after the contributes.commands tombstone — retire or re-document

2 participants

@os-zhuang@claude