Skip to content

Commit bd4096f

Browse files
os-muskclaude
andauthored
fix(metadata-protocol): the three recovery doors announce their writes on the mutation choke point (#14411)
* fix(metadata-protocol): emit onMetadataMutation from the three recovery doors (#14179) rollbackMetaItem, revertCommit (both limbs) and deleteMetaItem's legacy raw-engine exit mutate live state and never reached emitMetadataMutation — the documented choke point and, since #13331, the cluster publish point. Each now announces after its write, with the same org scope and singular type key the write used. Row-absent exits stay silent; the cluster receive path is untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68 * test(metadata-protocol): name the boot topology instead of passing an id that a default parameter swallows (#14179) A default parameter fires on an explicitly passed `undefined`, so the harness's bootstrap-mode cases were built on an environment boot and measured the two-tier gate's 403 rather than the legacy exit. The factory now takes a named mode and asserts the topology it constructed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68 * test(metadata-protocol): declare the ablation direction per case before running it (#14179) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68 * chore: record the new pin file's three engine doubles in the RETAINED ledger (#14179) `check:engine-double-contract` reds until the ledger learns about a file that pins engine doubles, or the pin never protects it. Regenerated with `--write`: 3 rows added, all naming the new test file, 0 lost. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0112hMx9hjJ9BgB28X97DS68 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent a69dfde commit bd4096f

4 files changed

Lines changed: 817 additions & 0 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
"@objectstack/metadata-protocol": patch
3+
---
4+
5+
fix(metadata-protocol): the three recovery doors announce their writes on the mutation choke point (#14179)
6+
7+
`emitMetadataMutation` documents itself as "the ONE choke point every authoring
8+
surface funnels through", and since #13331 it is also the `metadata.mutated`
9+
cluster publish point. Three live write paths never reached it:
10+
11+
- **`rollbackMetaItem`** — ran the registry write-through ("a rollback is a live
12+
write like any other") and announced nothing. A rolled-back `hook` row left the
13+
OLD hook bound in every boot-cached consumer until restart, while the registry
14+
and the stored row already served the restored body.
15+
- **`revertCommit`** — same miss on both limbs: the per-item restore
16+
(write-through) and the per-item soft-remove (`repo.delete` + registry heal).
17+
- **`deleteMetaItem`'s legacy raw-engine exit** — the `else` side of
18+
`useRepoPath`, which really deletes the row, may drop the physical storage and
19+
heals the registry view locally. Its repository-path twin has emitted since
20+
#2588.
21+
22+
Each door now emits after its write, with the same org scope the write received
23+
and the same singular type key the registry was written under: `state: 'active'`
24+
for a restore, `state: 'deleted'` for a removal — mirroring the emitting siblings
25+
rather than inventing an event shape. That single seam repairs both halves at
26+
once: local `onMetadataMutation` consumers (the authored hook/action re-bind)
27+
re-sync after a recovery write, and the #13331 publisher fans the same signal out
28+
so peer replicas converge instead of serving the rolled-back-FROM body until an
29+
unrelated mutation or a restart.
30+
31+
Deliberately unchanged, and pinned: the row-absent exits stay silent (nothing
32+
mutated, so no peer is woken to converge on a no-op), and the cluster RECEIVE
33+
path (`applyRemoteMetadataMutation`) still replays locally only — emitting there
34+
would re-broadcast every received event and ping-pong across replicas.
35+
36+
Reachability of the legacy delete exit, recorded as NOT MEASURED when the door
37+
was found, is now measured: on a normal boot (`environmentId` defined) the
38+
two-tier delete authorization refuses every type that would reach it
39+
(`NOT_OVERRIDABLE` or `NOT_CREATABLE`, both 403), so that door's exposure is
40+
control-plane bootstrap mode — narrower than feared, and exactly the topology
41+
whose registry every organization shares.

0 commit comments

Comments
 (0)