instar 1.3.501 → 1.3.502

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +537 -9
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  5. package/dist/config/ConfigDefaults.js +41 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/BackupManager.d.ts.map +1 -1
  8. package/dist/core/BackupManager.js +7 -0
  9. package/dist/core/BackupManager.js.map +1 -1
  10. package/dist/core/DeliverMessageHandler.d.ts +13 -1
  11. package/dist/core/DeliverMessageHandler.d.ts.map +1 -1
  12. package/dist/core/DeliverMessageHandler.js +7 -0
  13. package/dist/core/DeliverMessageHandler.js.map +1 -1
  14. package/dist/core/MachinePoolRegistry.d.ts +3 -0
  15. package/dist/core/MachinePoolRegistry.d.ts.map +1 -1
  16. package/dist/core/MachinePoolRegistry.js +1 -0
  17. package/dist/core/MachinePoolRegistry.js.map +1 -1
  18. package/dist/core/OwnerSuspectBreaker.d.ts +37 -0
  19. package/dist/core/OwnerSuspectBreaker.d.ts.map +1 -1
  20. package/dist/core/OwnerSuspectBreaker.js +58 -0
  21. package/dist/core/OwnerSuspectBreaker.js.map +1 -1
  22. package/dist/core/PendingInboundStore.d.ts +310 -0
  23. package/dist/core/PendingInboundStore.d.ts.map +1 -0
  24. package/dist/core/PendingInboundStore.js +715 -0
  25. package/dist/core/PendingInboundStore.js.map +1 -0
  26. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  27. package/dist/core/PostUpdateMigrator.js +13 -0
  28. package/dist/core/PostUpdateMigrator.js.map +1 -1
  29. package/dist/core/QueueDrainLoop.d.ts +247 -0
  30. package/dist/core/QueueDrainLoop.d.ts.map +1 -0
  31. package/dist/core/QueueDrainLoop.js +0 -0
  32. package/dist/core/QueueDrainLoop.js.map +1 -0
  33. package/dist/core/SessionRouter.d.ts +36 -2
  34. package/dist/core/SessionRouter.d.ts.map +1 -1
  35. package/dist/core/SessionRouter.js +34 -9
  36. package/dist/core/SessionRouter.js.map +1 -1
  37. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  38. package/dist/core/devGatedFeatures.js +10 -0
  39. package/dist/core/devGatedFeatures.js.map +1 -1
  40. package/dist/core/inboundQueueBootSweep.d.ts +61 -0
  41. package/dist/core/inboundQueueBootSweep.d.ts.map +1 -0
  42. package/dist/core/inboundQueueBootSweep.js +207 -0
  43. package/dist/core/inboundQueueBootSweep.js.map +1 -0
  44. package/dist/core/inboundQueueConfig.d.ts +78 -0
  45. package/dist/core/inboundQueueConfig.d.ts.map +1 -0
  46. package/dist/core/inboundQueueConfig.js +135 -0
  47. package/dist/core/inboundQueueConfig.js.map +1 -0
  48. package/dist/core/types.d.ts +23 -0
  49. package/dist/core/types.d.ts.map +1 -1
  50. package/dist/core/types.js.map +1 -1
  51. package/dist/messaging/TelegramAdapter.d.ts +4 -0
  52. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  53. package/dist/messaging/TelegramAdapter.js +12 -0
  54. package/dist/messaging/TelegramAdapter.js.map +1 -1
  55. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  56. package/dist/monitoring/guardManifest.js +27 -0
  57. package/dist/monitoring/guardManifest.js.map +1 -1
  58. package/dist/scaffold/templates.d.ts.map +1 -1
  59. package/dist/scaffold/templates.js +6 -0
  60. package/dist/scaffold/templates.js.map +1 -1
  61. package/dist/server/AgentServer.d.ts +2 -0
  62. package/dist/server/AgentServer.d.ts.map +1 -1
  63. package/dist/server/AgentServer.js +1 -0
  64. package/dist/server/AgentServer.js.map +1 -1
  65. package/dist/server/routes.d.ts +4 -0
  66. package/dist/server/routes.d.ts.map +1 -1
  67. package/dist/server/routes.js +25 -0
  68. package/dist/server/routes.js.map +1 -1
  69. package/package.json +1 -1
  70. package/scripts/lint-guard-manifest.js +2 -0
  71. package/src/data/builtin-manifest.json +65 -65
  72. package/src/scaffold/templates.ts +6 -0
  73. package/upgrades/1.3.502.md +75 -0
  74. package/upgrades/side-effects/1.3.492.md +20 -0
  75. package/upgrades/side-effects/durable-inbound-message-queue.md +213 -0
@@ -0,0 +1,75 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ Added the Durable Inbound Message Queue + Hold-for-Stability policy (CMT-1118,
9
+ spec `docs/specs/durable-inbound-message-queue.md`, 10-round convergence). When
10
+ the multi-machine router cannot deliver an inbound message right now (its
11
+ conversation is mid-move, or the owning machine is briefly unhealthy), the
12
+ message now goes into a crash-proof on-disk queue (`PendingInboundStore`,
13
+ SQLite `synchronous=FULL`, 0600) instead of being injected into a possibly-stale
14
+ local session or relying on platform resend — and a suspect-but-alive machine
15
+ gets up to 90 seconds to recover before its conversation is moved (fewer
16
+ machine swaps on 5-second blips). The drain engine carries the full reviewed
17
+ safety set: receipt-before-inject at-most-once acting, transactional
18
+ emergency-stop fences, queued-rows-only pause with cumulative caps, tenure
19
+ clamps (acquisition-generation, never the renewal epoch), six boot-validated
20
+ config invariants (violation = queue stays OFF, loudly), P19 brakes with an
21
+ Eternal-Sentinel declared tick, and every loss window reported — never silent.
22
+ New Bearer route `GET /pool/queue` (503 while dark); capacity heartbeats gain
23
+ queue depth/tenure/top-K; guard manifest + dark-gate registrations included.
24
+ **Ships DARK**: `multiMachine.sessionPool.inboundQueue` defaults
25
+ `enabled:false, dryRun:true`; hold-for-stability trails one rollout stage.
26
+
27
+ ## What to Tell Your User
28
+
29
+ Nothing changes today — this ships off by default. Once enabled (staged rollout,
30
+ dry-run first): messages that arrive while your agent's conversation is moving
31
+ between machines can no longer be lost or delivered to the wrong place — they
32
+ wait in a small crash-proof queue and deliver in order when the move finishes.
33
+ And a machine having a brief network blip gets ~90 seconds to recover before
34
+ its conversations are moved off it, so you'll see far fewer pointless machine
35
+ swaps. If anything ever can't be delivered, you get one plain notice naming
36
+ what to resend — never silence.
37
+
38
+ ## Summary of New Capabilities
39
+
40
+ - `GET /pool/queue` — queue counts (queued/claimed/held/frozen, delivered24h
41
+ which excludes possibly-not-injected), durable counters (incl. dry-run
42
+ `wouldEnqueue`/`wouldHold` promotion evidence, `possiblyNotInjected`,
43
+ `holdBypassedByAttemptsCap`), hold/flap state, tenure. 503 while dark.
44
+ - Capacity heartbeats: `inboundQueue` block (depth, oldest, tenure, top-K) —
45
+ feeds the survivor loss-suspected item + capped session recovery when a
46
+ machine dies holding messages.
47
+ - `DeliverAck` gains the typed `sender-rejected` NACK (receive-side authz
48
+ re-validation of carried sender envelopes).
49
+ - Guard posture: `multiMachine.sessionPool.inboundQueue.enabled` +
50
+ `multiMachine.sessionPool.holdForStability.enabled` rows in `/guards`
51
+ (hold's getter reports the EFFECTIVE state — orphaned config derives
52
+ off-runtime-divergent).
53
+
54
+ ## Evidence
55
+
56
+ - Unit: `pending-inbound-store.test.ts` 32/32 (tri-state, bounds + carve-out
57
+ boundary, AUTOINCREMENT across prunes, claim CAS, eviction-skips-claimed,
58
+ payload hygiene + locator retention, conditional receipt fence, tenure
59
+ derivation incl. A→B→A, cumulative pause accounting across restart, handle
60
+ encapsulation, 0600); `queue-drain-loop.test.ts` 35/35 (dispositions incl.
61
+ delivered-unconfirmed, stop-fence both interleavings, pause scope round-9,
62
+ hold budget across episodes, herd cap, maxHeldTotal degrade, maxAttempts
63
+ forced re-place both arms, tenure clamps, wake clamps, Eternal-Sentinel
64
+ episode latch, mirror reconciliation, P19 sustained-failure hour);
65
+ `inbound-queue-config.test.ts` 10/10 (all six invariants, defaults parity
66
+ with ConfigDefaults); `inbound-queue-boot-sweep.test.ts` 13/13 (gate-expiry
67
+ ×4 reasons, crash-table rows 1–3, stop-scoped PIS veto, pause-aware
68
+ recovery, quarantine + expiry).
69
+ - Integration: `inbound-queue-route.test.ts` 3/3 (ships-dark 503, feature-alive
70
+ 200 over real HTTP + real engine + real SQLite, delivered24h exclusion).
71
+ - E2E: `inbound-queue-lifecycle.test.ts` 2/2 (production-init order: sweep →
72
+ invariants → engine adopts swept store → drain → route truth; and the
73
+ production-default disabled boot: gate-expiry + 503).
74
+ - Lints: `lint-dev-agent-dark-gate` clean (both flags registered);
75
+ `lint-guard-manifest` clean (components listed).
@@ -0,0 +1,20 @@
1
+ # Side-Effects Review — v1.3.492 (version-named pairing)
2
+
3
+ This is the version-named pairing for the v1.3.492 release, completing the
4
+ rename step the release cut is expected to perform alongside the
5
+ `NEXT.md → 1.3.492.md` guide rename (see `scripts/pre-push-gate.js` check 5:
6
+ "the fragment/NEXT.md -> <version>.md rename pairs with an artifact rename").
7
+ The release flow did not perform the artifact half of the pairing, which makes
8
+ check 5 false-positive on every docs-only push from a clean post-release tree.
9
+
10
+ The actual side-effects review for everything shipped in v1.3.492 is:
11
+
12
+ - `upgrades/side-effects/cartographer-sweep-eventloop-safety.md`
13
+ (cited by `upgrades/1.3.492.md` § Evidence — reviewer raised 2 material
14
+ concerns, both fixed before commit)
15
+
16
+ That artifact is left in place under its slug name because the release guide's
17
+ Evidence section cites it by that path. This file exists so the repo state
18
+ matches the gate's documented post-release expectation. The underlying gap
19
+ (release automation never renames artifacts) is logged to the framework-issues
20
+ ledger under dedupKey `pre-push-gate-versioned-artifact-fallback`.
@@ -0,0 +1,213 @@
1
+ # Side-Effects Review — Durable Inbound Message Queue + Hold-for-Stability
2
+
3
+ **Version / slug:** `durable-inbound-message-queue`
4
+ **Date:** `2026-06-12`
5
+ **Author:** `echo (instar-dev agent)`
6
+ **Second-pass reviewer:** `independent reviewer subagent (required — gates dispatch + session lifecycle)`
7
+
8
+ ## Summary of the change
9
+
10
+ Implements the converged + approved spec `docs/specs/durable-inbound-message-queue.md`
11
+ (CMT-1118, 10 convergence rounds): when the session-pool router cannot deliver an
12
+ inbound message right now (`queued`/`placement-blocked` verdicts that today fall
13
+ through to possibly-wrong-place local dispatch), the message is taken into durable
14
+ SQLite custody (`PendingInboundStore`, `synchronous=FULL`, 0600) and a drain engine
15
+ (`QueueDrainLoop`) delivers it when the blockage clears — with hold-for-stability
16
+ giving a suspect-but-alive owner up to `holdMaxMs` (90s) before its conversation is
17
+ re-placed. Ships DARK (`multiMachine.sessionPool.inboundQueue` enabled:false +
18
+ dryRun:true; hold trails one stage). Files: new `src/core/PendingInboundStore.ts`,
19
+ `QueueDrainLoop.ts`, `inboundQueueConfig.ts`, `inboundQueueBootSweep.ts`; edits to
20
+ `SessionRouter.ts`, `OwnerSuspectBreaker.ts`, `DeliverMessageHandler.ts`,
21
+ `MachinePoolRegistry.ts`, `BackupManager.ts`, `ConfigDefaults.ts`,
22
+ `devGatedFeatures.ts`, `guardManifest.ts`, `types.ts`, `TelegramAdapter.ts`,
23
+ `PostUpdateMigrator.ts`, `templates.ts`, `routes.ts`, `AgentServer.ts`,
24
+ `commands/server.ts`, `scripts/lint-guard-manifest.js`; four new test files
25
+ (unit ×4, integration ×1, e2e ×1).
26
+
27
+ ## Decision-point inventory
28
+
29
+ - `SessionRouter.queueMessage` — modify — no-op → tri-state custody taking; router
30
+ sets `acked` only for `queued`/`already-queued` (refused keeps today's un-acked
31
+ fall-through).
32
+ - `Consumption site (server.ts onTopicMessage route consult)` — modify — adds the
33
+ ordering gate, the custody-ack short-circuit, and the custody-aware route-throw
34
+ point read; all three no-op when the engine is null (dark).
35
+ - `OwnerHoldVerdict (new)` — add — hold/failover/deliver at every
36
+ `placeAndClaim('failover')` site; always-`failover` injected when the policy is
37
+ off/dry-run (§4.2 effective-state honesty, /guards getter on the unconditional
38
+ boot path).
39
+ - `DeliverMessageHandler.validateSender` — add — receive-side authz re-validation;
40
+ typed non-retryable `sender-rejected` NACK; only consulted when an envelope is
41
+ present (old peers unaffected).
42
+ - `Emergency-stop custody settle (TelegramAdapter.onSentinelStopCustody)` — add —
43
+ stop transitions queued custody terminal + PIS cleanup; pause is engine-level
44
+ (queued-rows-only freeze) and currently API-driven only (the sentinel 'pause'
45
+ category still Escape-keys the session as before — unchanged behavior).
46
+ - `Boot sweep (runInboundQueueBootSweep)` — add — unconditional boot path, before
47
+ `recoverPendingInjects`; gate-expires custody with named reasons; quarantines a
48
+ corrupt store; vetoes PIS records for operator-stop rows ONLY.
49
+
50
+ ---
51
+
52
+ ## 1. Over-block
53
+
54
+ **What legitimate inputs does this change reject that it shouldn't?**
55
+
56
+ The enqueue path can `refuse` legitimate messages at the caps (`maxPerSession` 50 /
57
+ `maxTotal` 500 / `hardMaxTotal` 1000 / oversize >64KB) — but a refusal is NEVER a
58
+ block: it maps to `acked:false` → today's exact local-dispatch fall-through, so the
59
+ worst case for a legitimate message is the pre-feature behavior (delivery, possibly
60
+ wrong-place, counted in `orderingViolations`). The `sender-rejected` NACK can reject
61
+ a sender deauthorized on the receiving machine but still authorized on the sender's
62
+ — per-machine registry divergence during a deauthorization window; the spec chose
63
+ the conservative side (the receive-side registry wins), the entry terminals
64
+ loss-REPORTED, and an old peer (no envelope) is never affected. The config-seam
65
+ validation refuses to START the queue on a violated invariant — deliberately
66
+ over-blocking the feature itself (OFF = today's behavior) rather than running
67
+ half-configured.
68
+
69
+ ## 2. Under-block
70
+
71
+ **What failure modes does this still miss?**
72
+
73
+ The spec enumerates these as named windows: loss windows 1–6 (machine disk death;
74
+ crash instants around the receipt; restore-to-new-machine silent forfeit) and
75
+ duplicate windows 1–5 (PIS at-least-once replay instant; route-throw point-read
76
+ error fail-open; version-skew receipt boundary). None are silent — each is reported
77
+ or explicitly accepted in the spec with bounds. The hold verdict cannot detect a
78
+ hard-crashed machine faster than the heartbeat staleness window (one hold cycle of
79
+ added latency, named in spec §4.2). The §5.1 survivor arm only sees peers whose
80
+ last heartbeat carried depth fields (old/mesh-less peers are honestly unknown).
81
+
82
+ ## 3. Level-of-abstraction fit
83
+
84
+ The custody store sits at the router verdict layer — the exact seam where the
85
+ no-op `queueMessage` already existed; it does not duplicate the ingress
86
+ exactly-once ledger (bypassed by design for drained entries — the receipt class is
87
+ the drain's own authority) nor the PendingRelayStore (outbound). The hold policy
88
+ feeds the EXISTING OwnerSuspectBreaker signals rather than adding a parallel
89
+ detector. The boot sweep lives on the unconditional boot path because the gated-off
90
+ states are exactly the ones whose components never construct (round-2/round-4
91
+ findings). No higher-layer gate exists that this should feed instead.
92
+
93
+ ## 4. Signal vs authority compliance
94
+
95
+ Every decision is a deterministic policy evaluation over enumerable inputs (route
96
+ outcome enum, heartbeat liveness, breaker state, row state) — no brittle
97
+ pattern-matching holds blocking authority (`docs/signal-vs-authority.md`). The
98
+ fail direction is open-to-today's-behavior everywhere: storage failure → refused →
99
+ fall-through; point-read error → fall-through; invariant violation → queue OFF.
100
+ The flap detector and loss reports are signal-only (attention items, counters).
101
+ The one new blocking-shaped surface — `sender-rejected` — is an authz re-check
102
+ against the durable users registry (existing authority, new enforcement point),
103
+ not a new heuristic. Spec §Supervision documents the Tier-0
104
+ deterministic-evaluator carve-out; the 10-round convergence (including the
105
+ lessons-aware reviewer) audited exactly this question.
106
+
107
+ ## 5. Interactions
108
+
109
+ - The ingress exactly-once ledger: custody COMPLETES the ledger row (the spec's
110
+ §2.2 lifecycle); drained entries bypass the ledger gate by design — the
111
+ injection receipt is a DISTINCT class, so no double-fire.
112
+ - PendingInjectStore: receipt-first ordering pinned (round-7); stop deletes PIS
113
+ records; the boot sweep runs BEFORE `recoverPendingInjects` and vetoes
114
+ operator-stop records only — the pause case deliberately does NOT veto.
115
+ - OwnerSuspectBreaker: `onClose` is additive; `recordSuccess` semantics unchanged.
116
+ - The reaper/respawn machinery: the drain reuses `respawnSessionForTopic` /
117
+ `spawnSessionForTopic` WITH the `spawningTopics` guard, so drain and live spawns
118
+ cannot race a duplicate spawn.
119
+ - Telegram dedup/confirmations: drain deliveries suppress the per-message
120
+ "✓ Delivered" (the §3.1 contract) — no confirmation flood.
121
+ - Double-dispatch: the custody-ack short-circuit only fires when the enqueue
122
+ COMMITTED (acked), and the route-throw catch point-reads the store — the
123
+ enumerated residual is a point-read ERROR failing open (bounded duplicate,
124
+ §5-enumerated).
125
+
126
+ ## 6. External surfaces
127
+
128
+ - New Bearer-gated route `GET /pool/queue` (503 while dark). No payload content is
129
+ ever served — counts, counters, tenure only.
130
+ - Mesh `deliverMessage` envelope gains optional `senderEnvelope`; `DeliverAck`
131
+ gains `'sender-rejected'`. Old peers: never emit the new ack value, ignore the
132
+ new field — both skew directions named in the spec.
133
+ - Capacity heartbeat gains the `inboundQueue` block (depth/oldest/tenure/topK) —
134
+ additive, absent = unknown on old peers.
135
+ - CLAUDE.md template + `migrateClaudeMd` section (Agent Awareness + Migration
136
+ Parity); ConfigDefaults delivers the dark config blocks to existing agents via
137
+ the existing add-missing recursion (verified by test).
138
+ - The store file is excluded from backups via the unconditional
139
+ `BLOCKED_PATH_PREFIXES` (restoring custody to a new machine would claim
140
+ messages it never held).
141
+ - Timing/runtime dependence: drain behavior depends on heartbeat freshness and the
142
+ breaker's suspect windows — exactly the dependencies the spec's hold-budget and
143
+ clamp bounds were designed around.
144
+
145
+ ## 7. Rollback cost
146
+
147
+ Feature is dark by default; nothing changes on deploy until an operator advances
148
+ the rollout. If wrong in production: flip `inboundQueue.enabled:false` (or
149
+ `dryRun:true`) + normal restart — the boot sweep gate-expires any residual custody
150
+ with named, loss-reported reasons (no silent stranding; flag semantics are
151
+ boot-read by design, spec §5.3). No data migration: the SQLite store is created on
152
+ first use and quarantine/prune paths bound its lifetime. The OFF-state is
153
+ byte-for-byte today's behavior except the one-shot residual sweep — verified by
154
+ the gate × behavior matrix tests. Worst-case backout is a hot-fix release deleting
155
+ the wiring; no agent state repair is ever needed (rows are per-machine,
156
+ self-expiring, backup-excluded).
157
+
158
+ ## Known deliberate simplifications (named, not hidden)
159
+
160
+ - The §3.1 "extraction" is implemented as a drain-specific tail
161
+ (`_drainLocalDeliver`) built from the same primitives as the live tail rather
162
+ than relocating the live tail's 150 lines into a shared function — the live
163
+ hot path is byte-untouched (zero regression risk), at the cost of two parallel
164
+ tails to keep in sync. The drain tail enumerates every contract divergence in
165
+ its comment block.
166
+ - The sentinel 'pause' category keeps its existing behavior (Escape key); the
167
+ engine's pause/freeze surface (`onPause`/`onResume`) is fully built + tested
168
+ but not yet bound to a user-facing trigger — binding it is a UX decision the
169
+ operator should make with live dry-run data (the spec's §3.6 pause semantics
170
+ are about WHEN frozen rows behave correctly, which is what ships).
171
+ - `custodyDurability` reports `'unknown'` (no fsync probe in v1) — the spec's
172
+ round-8 field shipped as an honest placeholder rather than a guessed value.
173
+ - The §5.1 survivor re-placement uses empty-payload synthetic messages through
174
+ `SessionRouter.forceReplace` (the router path, honoring pins + CAS) — "session
175
+ recovery without message replay", exactly the spec's framing.
176
+
177
+ ## Known deliberate simplifications — addendum after second-pass review
178
+
179
+ - Lease-acquisition tenure events: `onLeaseAcquired` is called once at engine
180
+ construction (and `handoffInProgress` is unwired); per-acquisition tenure
181
+ bumps + the §3.5 ordered-handoff enqueue gate are pre-promotion work, bounded
182
+ meanwhile by the cross-boot clamp (`boot_session_id`) and the now-wired REAL
183
+ `holdsLease` gate (a non-holder takes no custody at all, which closes the
184
+ §2.2 exposure the reviewer named). <!-- tracked: CMT-1118 (rollout-criteria: dark→dev-dry-run gate; must land before dev-live promotion) -->
185
+
186
+ ## Second-pass review
187
+
188
+ ---
189
+
190
+ **Independent second-pass review (reviewer subagent, 2026-06-12):**
191
+
192
+ Verified against the implementation before raising concerns: MUST 1/3/4/6/7/9/10/11/12 are real — the conditional receipt is one transaction gated on the row still being `claimed` (`src/core/PendingInboundStore.ts`), the drain tail commits the receipt before the PIS record/inject and re-checks stop after it (`src/commands/server.ts` drain tail), the six config-seam invariants are checked at construction and a violation keeps the queue OFF with one loud error per inequality + an attention item, and the boot sweep runs on the unconditional path before `recoverPendingInjects`. The Q1/Q4 fail-open directions are real in code: storage throw → `refused`, null engine → `'refused'`, point-read error → fall-through. Dark-ship holds: all three consumption-site edits are inside the `_sessionRouter && _sessionPoolStage() !== 'dark'` block and additionally null-guarded on `_inboundQueue`; with the default config the engine is never constructed, `/pool/queue` 503s, and the only OFF-state delta is the named boot sweep (a no-op when no store file exists). `sender-rejected` is a registry re-check (existing authority), consulted only when an envelope is present; the hold verdict is a deterministic policy over enumerated inputs — no new brittle blocking authority. Backup exclusion, dev-gate registration, guard manifest, ConfigDefaults, migrator, and the test files all exist as claimed.
193
+
194
+ **Concern raised: the `no-mesh-identity` gate reason is never produced — a fully-enabled queue on a machine without mesh identity strands custody silently.** [...] produce the named gate-expiry (or fold the identity check into the sweep's gate) before live promotion.
195
+
196
+ **Concern raised: the dry-run rollout stage is structurally invisible — its evidence path is dead code.** [...] Either construct the engine in dry-run mode (it never claims custody by design) or name this in "Known deliberate simplifications".
197
+
198
+ **Concern raised: the lease gate is hardwired open and this simplification is not named.** [...] before live promotion either wire the real serving-lease signal (it exists — `leaseCoordinatorRef`) or add this to "Known deliberate simplifications".
199
+
200
+ **Concern raised (minor, latent): MUST 2's no-throw-after-commit is convention, not structure, at the engine layer.** [...] scoping the try to the `store.enqueue` call alone would make the invariant structural. No code change demanded for this dark ship; fix opportunistically.
201
+
202
+ Disposition: the dark-ship contract, fail-open directions, custody/receipt core, and signal-vs-authority compliance all check out in code. The four concerns are pre-promotion obligations (1–3) and a hardening note (4), not dark-deploy blockers.
203
+
204
+ **Author response (iterated per Phase 5, same session):** all four concerns ADDRESSED in code before commit —
205
+ 1. no-mesh-identity: a one-shot 90s orphan-store backstop at the sweep site gate-expires + loss-reports custody whenever the swept store is never adopted by an engine (covers identity-missing AND construction-throw paths) — `server.ts` sweep block.
206
+ 2. dry-run visibility: the engine now constructs in dry-run too (`qcfg.enabled` alone gates construction); the §2.4 counters accumulate and `/pool/queue` serves them — the promotion evidence is live.
207
+ 3. lease gate: `holdsLease` wired to `leaseCoordinatorRef.holdsLease()` (single-machine no-coordinator defaults true); the remaining per-acquisition tenure-event wiring is the named tracked simplification above.
208
+ 4. MUST 2: the refusal-mapping try now covers ONLY the store commit; post-commit bookkeeping throws are logged and can no longer convert a committed enqueue into `refused`.
209
+
210
+ **Post-merge addendum (same session):** marked the queue's three defensive
211
+ catches with the in-brace `@silent-fallback-ok` convention (Eternal-Sentinel
212
+ episode latch; loud-log quarantine failure; normal no-quarantine-dir case) —
213
+ no behavior change; restores no-silent-fallbacks headroom after main moved.