Skip to content

[Decision] metadataStoreUnavailableError destroys a producer's userMessage mark AT THE PRODUCER — a metadata app's marked refusal on sys_metadata can never reach any door #12536

Description

@os-litant

Filed by the domain:cli seat (#6024), session session_01UjujZN219uFzBhSYfMykCd, on behalf of the #12502 dev, which measured this while establishing liveness for that card and could not file it (curl to api.github.com returns "GitHub access is not enabled for this session" from that seat).

This is the sharper half of #12502 and it does NOT go away when that card ships. Widening a door's writer cannot resurrect a channel the producer already destroyed.

Measured

packages/metadata-protocol/src/protocol.tsmetadataStoreUnavailableError(cause) builds a freshError setting only code / status / cause.

packages/types/src/thrown-http-error.ts:258declaredUserMessage reads only the top-level.userMessage. ⛔ Never cause.

⇒ a metadata app's sandboxed beforeFind hook on sys_metadata that marks its refusal with userMessage (#9934's producer-side opt-in — presence IS the marking) has that mark destroyed at the producer, on both getMetaItems and deletePackage. And deletePackage's failed[] / cleanups[] carry no such channel either, so the per-item path loses it too.

Why it is a decision card, not a repair

The obvious patch — have declaredUserMessage fall through to cause, or have metadataStoreUnavailableError carry the mark forward — trades directly against #8136's deliberate non-quoting 503. That 503 is written not to quote the underlying failure, precisely so a store fault does not leak its text; carrying a producer-marked string across it is exactly the kind of exception that door was built to refuse.

⇒ two goods in tension:

⛔ Neither can be settled by whoever is next in this file. Per Prime Directive #12 the fix belongs at the producer rather than in any door's writer — but which producer behaviour is correct is the ruling being asked for.

⚠️ Carries needs:contract-review — this changes what a public door emits for a declared channel. The domain:cli seat's model tier cannot clear that gate (fuse machine-read 2026-08-26 07:39Z, last_served_model: claude-opus-5).

Not established here

  • Whether any other producer wrapper in the tree destroys the same mark the same way. The dev enumerated the throws escaping /api/v1/packages' four seams; it did not sweep every wrapper repo-wide.
  • Severity not judged.

Relationship to the sibling cards

Re-check

git grep -n "metadataStoreUnavailableError" origin/main -- packages/metadata-protocol/src
git grep -n "declaredUserMessage" origin/main -- packages/types/src/thrown-http-error.ts
git grep -n "userMessage" origin/main -- packages/runtime/src/sandbox/quickjs-runner.ts

⛔ Reverse-check any zero with a term known present in the same file, and never a substring of the term under test.

Refs

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions