Skip to content

fix(spec): declare MetadataProtocol.getMetaItemLayered; drop the dead 'overlay' lockSource arm (#9740) - #9773

Merged
os-elon merged 3 commits into
mainfrom
claude/issue-9740-layered-interface-member
Aug 18, 2026
Merged

fix(spec): declare MetadataProtocol.getMetaItemLayered; drop the dead 'overlay' lockSource arm (#9740)#9773
os-elon merged 3 commits into
mainfrom
claude/issue-9740-layered-interface-member

Conversation

@os-elon

Copy link
Copy Markdown
Collaborator

Fixes#9740

What

Two mechanical edits, exactly the card's fix shape — declared-surface catch-up, zero runtime behaviour change:

  1. packages/spec/src/api/protocol.zod.tsMetadataProtocol now declares the optional member getMetaItemLayered?(request: GetMetaItemLayeredRequest): Promise< GetMetaItemLayeredResponse > (spelled with the schemas' inferred types), replacing the blocker comment [finding] The spec's three meta-read request schemas omit organizationId, which the protocol implementation accepts and honours #9726's PR left at that exact spot (the comment pointed at MetadataProtocol cannot declare getMetaItemLayered: the implementation's inline lockSource annotation carries an 'overlay' arm its producer never emits #9740; retired with this fix). Optional like its getMetaItemCached / deleteMetaItem siblings — additive to a shipped contract, implementation predating declaration.
  2. packages/metadata-protocol/src/protocol.tsgetMetaItemLayered's inline return-type annotation drops the dead 'overlay' arm on lockSource and annotates with MetadataLockSource directly (type import added).

Plus type-level pins in packages/spec/src/api/protocol.test.ts (the expectTypeOf pattern from translation-typegen.test.ts, compiled by spec's test typecheck): the member's presence/shape against the layered schemas, and the closed lockSource vocabulary (artifact | package | env-forced — no 'overlay' arm).

⛔ Not done, per the card's own analysis and PD#10: widening MetadataLockSourceSchema — a wire-vocabulary change on every metadata read envelope and on stored _lockSource, with no producer needing it. No REST call-site changes (nothing became purely mechanical; left for #9741's track — #9741 is not addressed here and remains open).

Ownership trace for the :10888'overlay' producer (the measurement that could have flipped this card)

Measured on origin/main (2065e31) before editing:

  • packages/metadata-protocol/src/protocol.ts:10888return { lock: p.lock, lockReason: p.lockReason, lockSource: 'overlay' } — sits inside getEffectiveLock (private, declared at :10852, return type annotated lockSource: 'artifact' | 'overlay' | undefined at :10859).
  • getEffectiveLock's only call sites are :11047 (inside lockWriteRefusal, declared :11037) and :11115 (inside assertLockAllowsDelete, declared :11106) — both write/delete-door helpers. Neither feeds any read response.
  • getMetaItemLayered (:6060:6321) never calls getEffectiveLock. Its response's lockSource has exactly one producer: ...(lockState.lockSource !== undefined ? { lockSource: lockState.lockSource } : {}) at :6312, where lockState = resolveLockState(code ?? overlay ?? {}, artifactBacked) (:6269:6270).
  • resolveLockState (packages/spec/src/kernel/metadata-protection.zod.ts:208) returns lockSource: MetadataLockSource | undefined; extractProtection (:141) admits a raw _lockSource only when MetadataLockSourceSchema.options.includes(...) (:166:168), enum ['artifact', 'package', 'env-forced'] (:54). 'overlay' can never come out of it.
  • grep -n "lockSource: 'overlay'" over the whole file: one hit, :10888.

Verdict: the card holds — the 'overlay' arm was an over-wide annotation, not enforced behaviour; the layered read path cannot emit it.

Reverse verification (TS2416, both readings; probe = npx tsc --noEmit in packages/metadata-protocol)

  • Baseline on origin/main sources: 63 errors (exactly the ledgered count in scripts/check-type-check-coverage.mjs), zero TS2416.
  • Interface member added, annotation NOT yet narrowed, spec rebuilt: 64 errors — the +1 is src/protocol.ts(6060,11): error TS2416 whose innermost incompatibility is Type '"overlay"' is not assignable to type '"artifact" | "package" | "env-forced" | undefined' — the exact error the card measured, proven against the rebuilt .d.ts (this is also the cross-package reverse verification: the new spec member reached metadata-protocol's tsc through dist).
  • Annotation narrowed: 63 errors, TS2416 gone. Delta vs ledger: 0.
  • Type-pin reverse check (from committed state): widening the pinned vocabulary to include 'overlay' turns spec's test typecheck red (TS2344 at the pin line); restored from the branch commit.

Verification (all at head e1ed96c unless noted)

  • pnpm --filter @objectstack/spec test: 413 files / 10989 tests passed (ran one tree before head; head differs from that tree only by .changeset/layered-interface-member.md, which no spec test reads — check:cross-package-test-inputs green pins declared test inputs).
  • pnpm --filter @objectstack/spec typecheck at e1ed96c: green (tsc + scripts + test typecheck; test debt held at 55 files / 263, unchanged).
  • pnpm --filter @objectstack/metadata-protocol test: 122 files passed / 2 skipped, 1684 tests passed / 10 skipped.
  • pnpm --filter @objectstack/spec check:generated after rebuild: all 13 artifacts up to date (api-surface regenerated via --fix — records export existence only, so no diff; check:docs, check:liveness, check:strictness-ledger green inside it).
  • Consumer sweep, downstream direction: turbo run build --filter='./packages/*' --filter='./packages/*/*'70/70 build tasks green (all workspace packages, a superset of @objectstack/spec's and @objectstack/metadata-protocol's downstream consumers).
  • pnpm check:type-check-debt --re-measure at head: 33 ledger entries re-measured, none above recorded (metadata-protocol steady at 63).
  • Gate derivation re-run on the actual diff (node scripts/pm/dispatch-gates.mjs, no paths passed): all matched + convention gates run and green — check:filter-alias-parity (new vs dispatch list), check:merge-driver, check:objectui-changeset, check:spec-parsed-alias, check:type-source-resolution, check:cross-package-test-inputs, check:dev-prereqs, check:adr-0087-registration, check:changeset-no-major, check:empty-changeset, docs-audit/check-affected-docs, check:nul-bytes, check:query-options-erasure, check:type-check-coverage, check:engine-double-contract, check:where-matcher, spec check:empty-state / check:liveness / check:strictness-ledger / check:variant-docs.

Changeset: @objectstack/specminor (public type face +1 optional member), @objectstack/metadata-protocolpatch (dead annotation arm dropped; type-level only).


Generated by Claude Code

… 'overlay' lockSource arm
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
… the closed lockSource vocabulary
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016D9wdJR14KKCxz1WgdAzcw
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata-protocol, @objectstack/spec, touching 5 documentable anchor(s).

2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx(via getMetaItemLayered (symbol))
  • content/docs/kernel/services-checklist.mdx(via MetadataProtocol (symbol))

2 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v15.mdx(via MetadataProtocol (symbol))
  • content/docs/releases/v17.mdx(via MetadataProtocol (symbol))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see

Coarse fallback — 116 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 e9534a4acab63aa91a67dfb76110b6695be68df0packageMentionDocs.

Which tree this was computed on

This run read content/docs from 5be3ad513d16044838aa3a599cb1ebca2b478ce5 — the merge of head e1ed96c9fb920f74ba0dab2649e07701f2996c81 into base e9534a4acab63aa91a67dfb76110b6695be68df0, 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 5be3ad513d16044838aa3a599cb1ebca2b478ce5 && git checkout 5be3ad513d16044838aa3a599cb1ebca2b478ce5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e9534a4acab63aa91a67dfb76110b6695be68df0 e1ed96c9fb920f74ba0dab2649e07701f2996c81 && git checkout -B drift-repro e9534a4acab63aa91a67dfb76110b6695be68df0 && git merge --no-ff e1ed96c9fb920f74ba0dab2649e07701f2996c81
node scripts/docs-audit/affected-docs.mjs --json e9534a4acab63aa91a67dfb76110b6695be68df0

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

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs e9534a4acab63aa91a67dfb76110b6695be68df0 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling labels Aug 18, 2026
@os-elon
os-elon marked this pull request as ready for review August 18, 2026 23:00
@os-elon
os-elon enabled auto-merge August 18, 2026 23:00
@os-elon
os-elon added this pull request to the merge queueAug 18, 2026
Merged via the queue into main with commit 11b779eAug 18, 2026
27 checks passed
@os-elon
os-elon deleted the claude/issue-9740-layered-interface-member branch August 18, 2026 23:39
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/steststooling

Projects

None yet

2 participants

@os-elon@claude