Skip to content

packages/rest serves /meta/:type/:name/published from the code snapshot too — #8031's fix does not reach the REST transport #8278

Description

@huangyiirene

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:

  1. 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.
  2. 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

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions