Skip to content

#8146's hatch-aware remedy on the CREATE side is unreachable from saveMetaItem — the ADR-0070 D1 gate shadows readOnlyBaseCreateError on every kernel #8361

Description

@os-zhuang

Observation found while implementing #8184 (PR #8353). Filed, not fixed: it lives in saveMetaItem's ADR-0070 D1 gate, a different region of protocol.ts from #8184's fenced one, and adjacent to #7748's declared surface.

What is shadowed

#8146 (7f02367c1) gave BOTH package-door emitters in SysMetadataRepository a hatchOpen remedy selection:

That second clause cannot be reached through saveMetaItem on any topology. The ADR-0070 D1 gate a few hundred lines above the repository call throws first, on a strictly wider condition:

intent === 'runtime-only' && request.packageId != null && !this.isWritablePackage(request.packageId)

The repository's create door fires on the same predicate plus namedBase (non-empty string) plus "no registry limb returned". Every write that would reach it has already been thrown by D1 — which is topology-independent, so this is not a per-kernel divergence like #8184 was.

Why it is worth recording

The code and status agree (WRITABLE_PACKAGE_REQUIRED / 422), and D1's sentence does not prescribe setting OS_METADATA_WRITABLE, so this is not the retry-forever false-prescription trap #8146 closed on the override side. It is the milder half: an operator who has the hatch open and attempts a runtime-only create into a read-only base is told the base is read-only, and never told that the hatch they set does not reach the package dimension. The override side explains it; the create side does not.

Secondary: it means the create-side hatch clause is only exercised by direct repo.put callers (promoteDraft / restoreVersion / revertCommit), not by the authoring surface it was written for — so a change to that sentence would read as covered while the surface that matters never emits it.

Not proposing a shape

Two readings, and neither is obvious enough to act on unasked: teach D1 the same hatchOpen selection, or let D1 delegate to the repository emitter the way #8184 just did on the override side. The second is the one-emitter direction this lane keeps choosing, but D1 fires before the repository exists in the call and carries its own docs pointer, so it is a real design call rather than a mechanical move.

Related


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions