Filed by the PM on behalf of the #8031 dev agent, which measured this but could not file it — its container 403s on every GitHub API call, reads and writes alike. Recovered over git transport as .os-handover/8031-handover.md on branch claude/issue-8031-handover. ⚠️ No domain:* label applied — routing is triage's call. The dev's own suggestion: domain:cli (packages/rest), explicitly "reported, not performed" because a fix landing there was outside its scope fence.
Unassigned.
The defect
packages/rest/src/rest-server.ts mounts both arities of this route —
GET /api/v1/meta/:type/:name/published
GET /api/v1/meta/:type/:section/:name/published
— and resolves them through resolveMetadataService(...) → svc.getPublished(type, name). It never consults the overlay.
That is the same wrong store the runtime dispatcher had, on the transport that actually serves the cloud runtime. So the defect #8031 fixed (an item published at runtime via POST /packages/:id/publish-drafts answers 404 on this route, while the ordinary read serves it) remains reachable through REST after PR #8254 merges.
Why the overlay is authoritative
Unchanged from #8031, and established from the spec rather than from the fact that the write went there:
- ADR-0027 (E)(5) defines sealing a publish as flipping the draft's
sys_metadata rows state:'draft' → 'active'. The flip is the publish.
packages/metadata-protocol/src/sys-metadata-repository.ts, the OverlayState contract: "'active' → the published, live overlay."
- ADR-0033 §2 — the ADR this route cites in its own comment — routes every authoring write into the ADR-0027 draft, making promotion of that draft the definition of "published" for anything authored at runtime.
Suggested shape (mirrors the landed dispatcher fix)
Consult the state:'active' overlay row first; fall through to getPublished on a null overlay, so a code-published item keeps resolving to byte-identical bytes. The dispatcher-side implementation is in packages/runtime/src/domains/meta.ts (PR #8254) and can be read as the reference.
⚠️ Two facts the REST side has that the dispatcher does not:
- A latent second failure mode, independent of this one. REST answers
501 NOT_IMPLEMENTED ("metadata.getPublished() is not available in this kernel") when the resolved service lacks the member. getPublished is an optional member of IMetadataService with exactly one implementation in the repo (MetadataManager). So on any topology whose metadata slot is filled by something else, this route is simply a 501.
- ⛔ Do not widen the 404 into "unpublished".
rest-server.ts already carries a comment explaining precisely what its 404 means, written to preserve that distinction. Keep that semantics intact.
⛔ A trap for whoever picks this up
The #8031 card's own verification arm — "an item that is genuinely unpublished still 404s" — is false for a code-defined item by design: getPublished's documented fallback answers 200 with the current definition. Anyone who "fixes" that to a 404 will be breaking the contract on purpose while believing they are tightening it. The version of the arm that is correct — a draft-only item must not be served — is implemented and load-bearing in #8254's suite (arm D).
Related fragility, recorded (not a bug)
IMetadataService.getPublished? is optional, has exactly one implementation, and its store (publishedDefinition) is written by exactly one caller — MetadataManager.publishPackage, reachable only via POST /packages/:id/publish. Worth someone's attention alongside the 501 above.
Related
#8031 / PR #8254 (the dispatcher-side fix this does not reach) · ADR-0027 (E)(5) · ADR-0033 §2
Filed by the PM on behalf of the #8031 dev agent, which measured this but could not file it — its container 403s on every GitHub API call, reads and writes alike. Recovered over git transport as⚠️ No
.os-handover/8031-handover.mdon branchclaude/issue-8031-handover.domain:*label applied — routing is triage's call. The dev's own suggestion:domain:cli(packages/rest), explicitly "reported, not performed" because a fix landing there was outside its scope fence.Unassigned.
The defect
packages/rest/src/rest-server.tsmounts both arities of this route —GET /api/v1/meta/:type/:name/publishedGET /api/v1/meta/:type/:section/:name/published— and resolves them through
resolveMetadataService(...)→svc.getPublished(type, name). It never consults the overlay.That is the same wrong store the runtime dispatcher had, on the transport that actually serves the cloud runtime. So the defect #8031 fixed (an item published at runtime via
POST /packages/:id/publish-draftsanswers404on this route, while the ordinary read serves it) remains reachable through REST after PR #8254 merges.Why the overlay is authoritative
Unchanged from #8031, and established from the spec rather than from the fact that the write went there:
sys_metadatarowsstate:'draft' → 'active'. The flip is the publish.packages/metadata-protocol/src/sys-metadata-repository.ts, theOverlayStatecontract: "'active'→ the published, live overlay."Suggested shape (mirrors the landed dispatcher fix)
Consult the
state:'active'overlay row first; fall through togetPublishedon a null overlay, so a code-published item keeps resolving to byte-identical bytes. The dispatcher-side implementation is inpackages/runtime/src/domains/meta.ts(PR #8254) and can be read as the reference.501 NOT_IMPLEMENTED("metadata.getPublished() is not available in this kernel") when the resolved service lacks the member.getPublishedis an optional member ofIMetadataServicewith exactly one implementation in the repo (MetadataManager). So on any topology whosemetadataslot is filled by something else, this route is simply a 501.rest-server.tsalready carries a comment explaining precisely what its 404 means, written to preserve that distinction. Keep that semantics intact.⛔ A trap for whoever picks this up
The #8031 card's own verification arm — "an item that is genuinely unpublished still 404s" — is false for a code-defined item by design:
getPublished's documented fallback answers 200 with the current definition. Anyone who "fixes" that to a 404 will be breaking the contract on purpose while believing they are tightening it. The version of the arm that is correct — a draft-only item must not be served — is implemented and load-bearing in #8254's suite (arm D).Related fragility, recorded (not a bug)
IMetadataService.getPublished?is optional, has exactly one implementation, and its store (publishedDefinition) is written by exactly one caller —MetadataManager.publishPackage, reachable only viaPOST /packages/:id/publish. Worth someone's attention alongside the 501 above.Related
#8031 / PR #8254 (the dispatcher-side fix this does not reach) · ADR-0027 (E)(5) · ADR-0033 §2