Repository navigation
Commit ebf7d98
fix(metadata-protocol): the metadata write refusal reports the package door — ITEM_LOCKED / WRITABLE_PACKAGE_REQUIRED are emitted where they apply (#8185)
* fix(metadata-protocol): the write refusal reports the package door, not only the type's flags (#7682)
`PUT /api/v1/meta/object/showcase_task` answered `403 NOT_OVERRIDABLE`
identically whether `?package=` named a read-only or a writable package:
`SysMetadataRepository.assertAllowed` discriminated on the metadata TYPE's
registry flags and never read the base the caller named. `ITEM_LOCKED` and
`WRITABLE_PACKAGE_REQUIRED` are both registered to this package in the
error-code ledger and neither was ever emitted on this path.
The refusal branch now reads the named base through the shared
`isWritablePackage` predicate (imported from `package-writability.ts`, the same
one `saveMetaItem`'s ADR-0070 D1 gate and the `/packages` lifecycle gate use):
* `override-artifact` into a read-only base -> 403 ITEM_LOCKED, carrying
ADR-0010's reserved `lockSource: 'package'` and the package id. "Pick a
writable base" would be a false prescription here, so the code names the
lock instead.
* `runtime-only` into a read-only base -> 422 WRITABLE_PACKAGE_REQUIRED, the
same code, status and prescription `saveMetaItem` already emits for exactly
this condition, now also stated at the single persistence route.
No ALLOW decision moves: every allow limb returns before this point, so an
ADR-0005 overlay (which names the read-only package it customizes by
construction) and the documented `OS_METADATA_WRITABLE` hatch behave exactly as
before -- both pinned, the hatch because #8146 must be free to move it
deliberately. A write naming no base keeps the previous codes verbatim, and the
DELETE verb is untouched (#6960).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmES43BMDg4bPrxTdi5q7t
* docs(metadata-protocol): mark the OS_METADATA_WRITABLE case as CONTESTED, per the 2026-08-12 #8146 ruling
An in-flight maintainer ruling landed on #7682 after this work started: #8146 is
settled as option B — a hatch write into a read-only package should REFUSE, the
Studio badge is telling the truth, and the hatch is type-level by its own
shipped documentation. The dispatch's instruction to "preserve and pin" that
behaviour is therefore superseded, and the ruling says explicitly not to land a
pin asserting it as correct.
No behaviour change here. The hatch limb was never touched by this PR (it
returns before the new package door), so nothing to revert; what changes is the
CLAIM the suite and the changeset were making about it. The case is relabelled
as a characterization pin of today's answer and kept, deliberately, as the
tripwire the #8146 fix must invert.
Re-measured on current main at that ruling's request, since the original
measurement was against two-week-old builds: it still reproduces end to end
through saveMetaItem on the host-config topology — `success: true`, and the row
lands with `package_id = com.example.showcase`, i.e. bound INTO the read-only
package rather than as the per-org override the variable's documentation
describes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmES43BMDg4bPrxTdi5q7t
* test(metadata-protocol): drop the OS_METADATA_WRITABLE case, record the gap as deliberate (#7682)
PM ruling on PR #8185's patch round. The case asserted that a hatch write into
a read-only package SUCCEEDS — green because the bug is present — and the
2026-08-12 ruling on #8146 said "don't merge it". A better label does not change
what the assertion claims, so it goes.
My tripwire argument for keeping it is answered: #8146 already names "the
refusal plus a rejection pin asserting code and status" as its own deliverable,
so the pin gets written against the FIXED behaviour, which is where it belongs.
The opposite risk is real too — a deliberately-red pin gets "repaired" to green
by someone who never read why it was there.
The suite docblock now states that the hatch path is deliberately uncovered
pending #8146, so the absence reads as a decision rather than an oversight, and
carries the re-measurement: the row lands bound INTO the read-only package
(package_id = com.example.showcase, organization_id = null) rather than as the
per-org override the variable's own documentation describes. The changeset says
the same.
No source change: `assertAllowed` is correct as shipped, and both open questions
were ruled in its favour (the ITEM_LOCKED / WRITABLE_PACKAGE_REQUIRED partition,
and `Part of #7682`). The `permission` case is kept and moved beside its
siblings — with no hatch set it asserts the refusal, which is the card's point.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmES43BMDg4bPrxTdi5q7t
* docs(metadata-protocol): keep the delete bullet with its list in the suite docblock (#7682)
Formatting only, no assertion or source change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmES43BMDg4bPrxTdi5q7t
* fix(metadata-protocol): type the test helper's `type` as MetaRef['type'] (#7682)
CI's TypeScript Type Check went red on my push: the metadata-protocol DEBT
entry records 63 raw tsc errors and `tsc --noEmit` reported 64. The +1 was mine
and real:
sys-metadata-repository.package-writability.test.ts(166,21): error TS2322:
Type 'string' is not assignable to type '"object" | "view" | ... |
"email_template"'.
`putWith`'s `opts.type` was `string`; `MetaRef['type']` is a literal union. The
suite ran green under vitest either way — this package has no `typecheck`
script, so its type surface is only judged by the ledger in CI, which is
exactly the gap that let a widened parameter through a local run.
Fixed at the source, not in the ledger: DEBT is a ratchet that may only shrink,
and raising an entry for a file added in the same PR would be the worst version
of that. `tsc --noEmit` now reports 63 for the package, matching the recorded
entry, with zero errors attributable to either file this PR touches.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AmES43BMDg4bPrxTdi5q7t
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 59ed2e9 commit ebf7d98
3 files changed
Lines changed: 595 additions & 2 deletions
File tree
- .changeset
- packages/metadata-protocol/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
0 commit comments