Skip to content

spec(liveness): bring the plugin manifest into the ledger's governed universe - #11338

Merged
os-sam merged 2 commits into
mainfrom
claude/issue-10728-manifest-liveness-universe
Aug 23, 2026
Merged

spec(liveness): bring the plugin manifest into the ledger's governed universe#11338
os-sam merged 2 commits into
mainfrom
claude/issue-10728-manifest-liveness-universe

Conversation

@os-sam

Copy link
Copy Markdown
Collaborator

Fixes#10728

Adds ManifestSchema to SPEC_ONLY_SCHEMAS + GOVERNED and seeds packages/spec/liveness/manifest.json, so the liveness ratchet can finally ask "who reads this?" about the plugin manifest. This extends the ratchet's universe — a strengthening. No gate was weakened, no manual floor added, no threshold moved.

The fork the triage ruling asked about: the escape hatch CAN host it

The scope ruling said to stop and report if SPEC_ONLY_SCHEMAS structurally could not host the manifest. It can, and this is measured rather than assumed — see the reverse verification below, leg B: with the override entry removed the gate throws metadata type 'manifest' has no registered schema, because getMetadataTypeSchema('manifest') has nothing to return. The override is the only resolution path, which is exactly the position query and qa are already in.

What the gate now measures

manifest 43 classified (live 22, dead 21)
✓ … the README state table carries a row for each of the 31 governed type(s) it claims to index.
✓ packages/spec/liveness/state-counts.md is current — the same 31 row(s) …
DispositionCount
live22
dead21

Six containers are drilled (contributes, capabilities, configuration, navigationContributions, engine, engines); data is a resolved deferral to the governed seed type rather than a duplicated row set — manifest.data[]isSeedSchema, and the gate enforces key-set equality, so a key added to SeedSchema cannot get a verdict on one side and not the other.

Where the rows come from

Dispositions are recorded as PENDING, because they are pending

No contributes tombstone has merged. #10724 (tombstone the nine mechanically-dead members) is open and pm:blocked on the cloud census; #10726 (contributes.routes, recommendation B) routes its removal through #10724. So no row says "retired" — only loading does, because its tombstone really landed (#4914). That is deliberate: a ledger note claiming a retirement before the tombstone merges is the stale-note class this lane just spent a day repairing.

Reverse verification — does the extension bite?

Predicted direction stated before running; mutation proven on disk in both directions (injected-text and deleted-text hit counts), each leg restored under an EXIT INT TERM trap. No build or dist is involved — the gate is run by tsx and imports from src/ — so no rebuild is owed.

LegMutationPredictedMeasured
Adrop 'manifest' from GOVERNEDmanifest rows go unmeasured; README row + counts row become orphans → exit 1✅ exit 1, 0 manifest report lines, ✗ 1 README state-table row(s) that GOVERNED does not back, ✗ 1 row(s) where README.md and state-counts.md disagree
Bdrop manifest: ManifestSchema from SPEC_ONLY_SCHEMASno registry path exists → throws by name✅ exit 1, 0 manifest report lines, Error: metadata type 'manifest' has no registered schema
restoregreen again, rows back✅ exit 0, manifest 43 classified (live 22, dead 21), worktree diff empty

Leg A produced one signal beyond the prediction, reported rather than smoothed over: ✗ 1 stale undrilled-container row(s) — the manifest/data deferral correctly goes stale the moment manifest leaves the universe.

This is also why the PR adds a self-test. Leg A's redness lands on the README row and the count artifact — both repairable by deleting the row and regenerating. Do those three edits together and the gate is green over a ~24-key authoring surface nothing asks about again, which is precisely the state this type was seeded out of. The pin is on membership, not on verdicts, so the ledger's rows stay free to move as the measurement moves.

Findings filed, not fixed

Seeding the ledger is what produced these; none is touched by this PR (all four carry the cloud-measurement precondition):

Verification

Union re-run at the final commit f819e4048, both under the shared verify lock (VERDICT command-exit 0):

  • check:liveness → exit 0, output above.
  • packages/spec full suite → 418 files / 11130 tests passed; the targeted file run names both new cases green (19 passed).
  • Derived gate families (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack on the actual diff, which named more than the dispatch did): check:empty-state, check:strictness-ledger, check:variant-docs, check:merge-driver, check:published-files, check:slot-lookup, check:test-source-alias, check:type-source-resolution, check:nul-bytes, check:query-options-erasure, check:engine-double-contract, check:type-check-coverage, check-ci-filter-parity, check-plugin-teardown-shape, check-affected-docs, pnpm --filter @objectstack/spec typecheckall exit 0.
  • Declared narrowing:check-dev-prereqs exits 1 on this worktree, and it is not a finding about this diff — its own output says "1 unmet precondition, not a list of problems" and names 67 of 67 workspace packages as having no dist/, i.e. the worktree was never built. Nothing in this diff produces a dist. For the same reason check:type-check-debt --re-measure (which refuses outright on an unbuilt closure) was not run repo-wide; its relevant leg is pnpm --filter @objectstack/spec typecheck, which runs tsc --noEmit && check:scripts-typecheck && check:test-typecheck over the package this diff touches and exits 0 — so the new test file type-checks and adds no debt. CI builds before running both.

Changeset

None — skip-changeset, re-derived rather than inherited. The diff is the liveness gate's own tooling plus its ledger; no runtime code, no exported type, and no schema changes (ManifestSchema itself is untouched). Same shape as PR #11209, which changed permission.json + proof-registry.mts + a test and carried no changeset.

File surface

Exactly the declared surface — packages/spec/scripts/liveness/**, the new packages/spec/liveness/manifest.json, and the ledger index files the gate's own reconciliation requires (README.md row + heading, the generated state-counts.md). No packages/spec/src/** path is touched, so the clause-② path limb does not fire.content/docs/releases/ untouched.


Generated by Claude Code

…universe
Seed packages/spec/liveness/manifest.json and add ManifestSchema to
SPEC_ONLY_SCHEMAS + GOVERNED, so the ratchet can finally ask who reads
the plugin manifest's properties. Extends the universe; no gate weakened.
Refs #10728
…to their cards
Add a self-test pinning that the manifest is inside the governed universe
and resolvable only through SPEC_ONLY_SCHEMAS, and point each dead ledger
row at the enforce-or-remove card it produced (#11330-#11333).
Refs #10728
@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 1 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/manifest.json, packages/spec/liveness/state-counts.md) — pages documenting those are invisible to this run

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 9ca161830d308e8ef2af2e0762f8d927413fd73fpackageMentionDocs.

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

Labels

documentationImprovements or additions to documentationsize/mskip-changesetPR has no user-facing published change; bypasses the changeset gateteststooling

Projects

None yet

1 participant

@os-sam