instar 1.3.762 → 1.3.764

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 (134) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +92 -1
  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 +28 -0
  6. package/dist/config/ConfigDefaults.js.map +1 -1
  7. package/dist/core/FileClassifier.d.ts.map +1 -1
  8. package/dist/core/FileClassifier.js +5 -0
  9. package/dist/core/FileClassifier.js.map +1 -1
  10. package/dist/core/PostUpdateMigrator.d.ts +12 -0
  11. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  12. package/dist/core/PostUpdateMigrator.js +61 -2
  13. package/dist/core/PostUpdateMigrator.js.map +1 -1
  14. package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
  15. package/dist/core/WriteDomainRegistry.js +16 -0
  16. package/dist/core/WriteDomainRegistry.js.map +1 -1
  17. package/dist/core/componentCategories.d.ts.map +1 -1
  18. package/dist/core/componentCategories.js +1 -0
  19. package/dist/core/componentCategories.js.map +1 -1
  20. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  21. package/dist/core/devGatedFeatures.js +6 -0
  22. package/dist/core/devGatedFeatures.js.map +1 -1
  23. package/dist/core/types.d.ts +50 -0
  24. package/dist/core/types.d.ts.map +1 -1
  25. package/dist/core/types.js.map +1 -1
  26. package/dist/data/llmBenchCoverage.d.ts.map +1 -1
  27. package/dist/data/llmBenchCoverage.js +18 -0
  28. package/dist/data/llmBenchCoverage.js.map +1 -1
  29. package/dist/monitoring/ExternalHogArmMarker.d.ts +65 -0
  30. package/dist/monitoring/ExternalHogArmMarker.d.ts.map +1 -0
  31. package/dist/monitoring/ExternalHogArmMarker.js +0 -0
  32. package/dist/monitoring/ExternalHogArmMarker.js.map +1 -0
  33. package/dist/monitoring/ExternalHogArmStore.d.ts +46 -0
  34. package/dist/monitoring/ExternalHogArmStore.d.ts.map +1 -0
  35. package/dist/monitoring/ExternalHogArmStore.js +124 -0
  36. package/dist/monitoring/ExternalHogArmStore.js.map +1 -0
  37. package/dist/monitoring/ExternalHogClassifier.d.ts +62 -0
  38. package/dist/monitoring/ExternalHogClassifier.d.ts.map +1 -0
  39. package/dist/monitoring/ExternalHogClassifier.js +0 -0
  40. package/dist/monitoring/ExternalHogClassifier.js.map +1 -0
  41. package/dist/monitoring/ExternalHogClassifierPrompt.d.ts +29 -0
  42. package/dist/monitoring/ExternalHogClassifierPrompt.d.ts.map +1 -0
  43. package/dist/monitoring/ExternalHogClassifierPrompt.js +70 -0
  44. package/dist/monitoring/ExternalHogClassifierPrompt.js.map +1 -0
  45. package/dist/monitoring/ExternalHogCpuDelta.d.ts +50 -0
  46. package/dist/monitoring/ExternalHogCpuDelta.d.ts.map +1 -0
  47. package/dist/monitoring/ExternalHogCpuDelta.js +79 -0
  48. package/dist/monitoring/ExternalHogCpuDelta.js.map +1 -0
  49. package/dist/monitoring/ExternalHogFactBuilder.d.ts +71 -0
  50. package/dist/monitoring/ExternalHogFactBuilder.d.ts.map +1 -0
  51. package/dist/monitoring/ExternalHogFactBuilder.js +111 -0
  52. package/dist/monitoring/ExternalHogFactBuilder.js.map +1 -0
  53. package/dist/monitoring/ExternalHogFloor.d.ts +87 -0
  54. package/dist/monitoring/ExternalHogFloor.d.ts.map +1 -0
  55. package/dist/monitoring/ExternalHogFloor.js +123 -0
  56. package/dist/monitoring/ExternalHogFloor.js.map +1 -0
  57. package/dist/monitoring/ExternalHogGuardStatus.d.ts +29 -0
  58. package/dist/monitoring/ExternalHogGuardStatus.d.ts.map +1 -0
  59. package/dist/monitoring/ExternalHogGuardStatus.js +27 -0
  60. package/dist/monitoring/ExternalHogGuardStatus.js.map +1 -0
  61. package/dist/monitoring/ExternalHogKillFunnel.d.ts +77 -0
  62. package/dist/monitoring/ExternalHogKillFunnel.d.ts.map +1 -0
  63. package/dist/monitoring/ExternalHogKillFunnel.js +72 -0
  64. package/dist/monitoring/ExternalHogKillFunnel.js.map +1 -0
  65. package/dist/monitoring/ExternalHogKillLedger.d.ts +76 -0
  66. package/dist/monitoring/ExternalHogKillLedger.d.ts.map +1 -0
  67. package/dist/monitoring/ExternalHogKillLedger.js +84 -0
  68. package/dist/monitoring/ExternalHogKillLedger.js.map +1 -0
  69. package/dist/monitoring/ExternalHogNoticeCoalescer.d.ts +46 -0
  70. package/dist/monitoring/ExternalHogNoticeCoalescer.d.ts.map +1 -0
  71. package/dist/monitoring/ExternalHogNoticeCoalescer.js +67 -0
  72. package/dist/monitoring/ExternalHogNoticeCoalescer.js.map +1 -0
  73. package/dist/monitoring/ExternalHogOwnership.d.ts +48 -0
  74. package/dist/monitoring/ExternalHogOwnership.d.ts.map +1 -0
  75. package/dist/monitoring/ExternalHogOwnership.js +60 -0
  76. package/dist/monitoring/ExternalHogOwnership.js.map +1 -0
  77. package/dist/monitoring/ExternalHogProcTable.d.ts +37 -0
  78. package/dist/monitoring/ExternalHogProcTable.d.ts.map +1 -0
  79. package/dist/monitoring/ExternalHogProcTable.js +65 -0
  80. package/dist/monitoring/ExternalHogProcTable.js.map +1 -0
  81. package/dist/monitoring/ExternalHogRealAdapters.d.ts +91 -0
  82. package/dist/monitoring/ExternalHogRealAdapters.d.ts.map +1 -0
  83. package/dist/monitoring/ExternalHogRealAdapters.js +247 -0
  84. package/dist/monitoring/ExternalHogRealAdapters.js.map +1 -0
  85. package/dist/monitoring/ExternalHogSampler.d.ts +62 -0
  86. package/dist/monitoring/ExternalHogSampler.d.ts.map +1 -0
  87. package/dist/monitoring/ExternalHogSampler.js +0 -0
  88. package/dist/monitoring/ExternalHogSampler.js.map +1 -0
  89. package/dist/monitoring/ExternalHogScanTick.d.ts +89 -0
  90. package/dist/monitoring/ExternalHogScanTick.d.ts.map +1 -0
  91. package/dist/monitoring/ExternalHogScanTick.js +126 -0
  92. package/dist/monitoring/ExternalHogScanTick.js.map +1 -0
  93. package/dist/monitoring/ExternalHogSentinel.d.ts +127 -0
  94. package/dist/monitoring/ExternalHogSentinel.d.ts.map +1 -0
  95. package/dist/monitoring/ExternalHogSentinel.js +168 -0
  96. package/dist/monitoring/ExternalHogSentinel.js.map +1 -0
  97. package/dist/monitoring/ExternalHogServerPrimitives.d.ts +50 -0
  98. package/dist/monitoring/ExternalHogServerPrimitives.d.ts.map +1 -0
  99. package/dist/monitoring/ExternalHogServerPrimitives.js +93 -0
  100. package/dist/monitoring/ExternalHogServerPrimitives.js.map +1 -0
  101. package/dist/monitoring/ExternalHogSustained.d.ts +49 -0
  102. package/dist/monitoring/ExternalHogSustained.d.ts.map +1 -0
  103. package/dist/monitoring/ExternalHogSustained.js +62 -0
  104. package/dist/monitoring/ExternalHogSustained.js.map +1 -0
  105. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  106. package/dist/monitoring/guardManifest.js +24 -0
  107. package/dist/monitoring/guardManifest.js.map +1 -1
  108. package/dist/scaffold/templates.d.ts.map +1 -1
  109. package/dist/scaffold/templates.js +3 -2
  110. package/dist/scaffold/templates.js.map +1 -1
  111. package/dist/server/AgentServer.d.ts +3 -0
  112. package/dist/server/AgentServer.d.ts.map +1 -1
  113. package/dist/server/AgentServer.js +1 -0
  114. package/dist/server/AgentServer.js.map +1 -1
  115. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  116. package/dist/server/CapabilityIndex.js +1 -0
  117. package/dist/server/CapabilityIndex.js.map +1 -1
  118. package/dist/server/routes.d.ts +3 -0
  119. package/dist/server/routes.d.ts.map +1 -1
  120. package/dist/server/routes.js +79 -5
  121. package/dist/server/routes.js.map +1 -1
  122. package/dist/testing/selfActionRegistry.d.ts.map +1 -1
  123. package/dist/testing/selfActionRegistry.js +51 -0
  124. package/dist/testing/selfActionRegistry.js.map +1 -1
  125. package/package.json +1 -1
  126. package/scripts/lint-scrape-fixture-realness.js +14 -0
  127. package/src/data/builtin-manifest.json +64 -64
  128. package/src/data/llmBenchCoverage.ts +18 -0
  129. package/src/scaffold/templates.ts +3 -2
  130. package/upgrades/1.3.763.md +23 -0
  131. package/upgrades/1.3.764.md +45 -0
  132. package/upgrades/side-effects/actionclaim-config-shape-fix.eli16.md +50 -0
  133. package/upgrades/side-effects/actionclaim-config-shape-fix.md +149 -0
  134. package/upgrades/side-effects/external-hog-sentinel.md +832 -0
@@ -0,0 +1,23 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Added the **External-Hog Zombie Auto-Kill Sentinel** (CMT-1901) — a background watcher that surfaces sustained EXTERNAL CPU hogs (broad observability) and auto-kills exactly one narrow class: orphaned Electron editor extension-host wrappers (the 2026-07-03 VS Code MongoDB-extension zombie that pinned ~2.2 cores for ~24h). The intelligence decides kill/leave/alert WITHIN a mechanical veto-only safety floor; a kill fires iff `floor_pass && classifier==='kill'` — the model can only ever SPARE a process, never widen the target set. Kill-SAFETY is carried entirely by the deterministic floor (same-uid non-root, orphaned-owner, launchctl-unmanaged, sustained N-window CPU, code-defined allowlist class, a kill-time CPU re-confirm); the model carries EFFECTIVENESS.
9
+
10
+ Ships **dev-gated DARK on the fleet, watch-only `dryRun` on a development agent** (`monitoring.externalHogSentinel.enabled` OMITTED → `resolveDevAgentGate`; `dryRun:true` is the kill-safety canary). Nothing is killed until a deliberate **PIN-gated arm**. New routes: `GET /external-hog` (status), `POST /external-hog/arm` (PIN-gated — a Bearer token cannot arm a real kill), `POST /external-hog/disarm` (Bearer — the safe direction). New config block `monitoring.externalHogSentinel` (enabled dev-gate-resolved; dryRun + kill-gate knobs via applyDefaults; a dev-gate strip migration for existing agents). Registered in `/guards` (dev-gated), and in the CLAUDE.md agent-awareness template.
11
+
12
+ ## What to Tell Your User
13
+
14
+ Nothing on the fleet — the feature ships **dark**: every route 503s and it is a strict no-op until deliberately enabled. On an agent where it is live, it is **watch-only**: it observes and reports sustained CPU hogs but kills nothing until the operator arms it with their dashboard PIN — and even armed, only the one narrow orphaned-editor-helper class, never anything else.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ - **Observability**: `GET /external-hog` reports sustained external CPU hogs (killed or left-alive) plus the durable arm state and an honest guard posture (`on-stale` when blind, never a false `on-confirmed`).
19
+ - **Operator control (dashboard PIN)**: arm the live kill with `POST /external-hog/arm` (PIN-gated; the marker binds the PIN consent to the current allowlist-class content-hashes) and disarm back to watch-only with `POST /external-hog/disarm`. A disarm can never be silently un-done (epoch monotonicity — returning to live-kill needs a fresh PIN arm).
20
+
21
+ ## Evidence
22
+
23
+ Built across 25 independently-reviewed checkpoints. ~246 external-hog unit/integration tests across 23 modules + a Tier-3 "feature is alive" E2E over the real `AgentServer` (GET 200 with a live status, the arm→disarm→re-arm epoch lifecycle, dark → 503, Bearer + PIN auth). **6 real bugs were caught by mandatory second-pass reviews of kill-adjacent code** (a fail-OPEN floor invariant, a false-HIGH CPU reading, a brake-off breaker, an invisible-hog drop, a non-boolean-laundering gate, and shell-caught deferral tracking) plus 1 self-caught §4.5 kill-time CPU re-confirm gap. Spec: `docs/specs/external-hog-zombie-autokill-sentinel.md` (converged 11 rounds + operator-approved).
@@ -0,0 +1,45 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Fixed a config-shape bug that made the **Action-Claim Follow-Through Sentinel** (including the
9
+ Slack-followthrough registration lane) impossible to enable on real installs. The sentinel gated on
10
+ `messaging.actionClaim.enabled`, but on every real install `messaging` is a JSON **array** of adapter
11
+ configs — so the dot-path `messaging.actionClaim.*` was unreachable (an array has no `actionClaim`
12
+ property), and the read always returned the `false` default. Because the sentinel defaults OFF, its
13
+ master switch could never be turned on. The tests didn't catch it because they all used an
14
+ object-shaped `messaging`, which no real install uses. The enable/config now lives at a reachable
15
+ **top-level `actionClaim`** block (the legacy object-shaped `messaging.actionClaim` is still honored
16
+ for back-compat).
17
+
18
+ ## What to Tell Your User
19
+
20
+ Nothing proactive — this is an internal enablement fix for a feature that ships off by default. If a
21
+ user asks why the promise follow-through tracker (the thing that turns "I'll post that in about five
22
+ minutes" into a durable commitment) never activated even after they tried to switch it on, the answer
23
+ is that the on-switch was written in a spot the program could never actually read; it now lives in a
24
+ reachable place and can genuinely be turned on (tried on a development agent first, before any wider
25
+ rollout).
26
+
27
+ ## Summary of New Capabilities
28
+
29
+ - The Action-Claim / Slack-followthrough sentinel is now **enablable** on real (array-`messaging`)
30
+ installs via top-level `actionClaim.enabled` (plus `actionClaim.slack`, `actionClaim.perTopicCap`,
31
+ `actionClaim.expiresHours`).
32
+ - Legacy object-shaped `messaging.actionClaim` config keeps working unchanged.
33
+ - No behavior change while the feature stays dark (its default); this only makes the switch reachable.
34
+
35
+ ## Evidence
36
+
37
+ - `tests/integration/action-claim-config-shape.test.ts` — with array-shaped `messaging` + top-level
38
+ `actionClaim.enabled:true`, a promise like "I'll restart the server now" registers a durable
39
+ commitment (returns `feature-disabled` before the fix); tuning knobs honored; explicit-false
40
+ off-switch works; object-shaped `messaging.actionClaim` back-compat verified.
41
+ - `tests/unit/action-claim-hook-slack.test.ts` — the generated Stop hook resolves config array-safely
42
+ (reads top-level `cfg.actionClaim`, `Array.isArray`-guards the legacy fallback).
43
+ - Existing route (14) + e2e lifecycle (4) + generated-hooks-parse (25) + migration (5) tests stay
44
+ green; `tsc --noEmit` clean.
45
+ - Side-effects review: `upgrades/side-effects/actionclaim-config-shape-fix.md`.
@@ -0,0 +1,50 @@
1
+ # ELI16 — Why the "I'll do that in 5 minutes" tracker couldn't be turned on
2
+
3
+ ## The one-sentence version
4
+
5
+ There's a safety feature that watches for promises the agent makes ("I'll restart it", "I'll post
6
+ that in about 5 minutes") and quietly writes them down so they survive a restart — and it turned out
7
+ you literally could not switch it on. This change fixes the switch.
8
+
9
+ ## What was broken
10
+
11
+ Think of the config file as a form. Most settings live in labeled boxes you can fill in. The switch
12
+ for this promise-tracker was written as "fill in the box `messaging → actionClaim → enabled`."
13
+
14
+ The problem: `messaging` isn't a box that holds other boxes. It's a **list** — one row per chat
15
+ platform (Telegram, Slack, WhatsApp). You can't write "actionClaim" *inside a list*; there's nowhere
16
+ to put it. So when the program looked for `messaging → actionClaim → enabled`, it always found
17
+ nothing, and "nothing" means "off." No matter what you did, the feature stayed off.
18
+
19
+ Why nobody noticed for so long: every automated test filled the form out the *wrong* way — it made
20
+ `messaging` a box instead of a list, so in the tests the switch worked fine. But no real install
21
+ looks like that. Real installs always use the list. So the tests were green while the real thing was
22
+ un-turn-on-able. Two sibling features have the same quirk, but they default to **on**, so nobody ever
23
+ had to find the switch — this promise-tracker is the first one that defaults to **off** and actually
24
+ needs its switch to work.
25
+
26
+ ## What this change does
27
+
28
+ It moves the switch to a box that actually exists: a **top-level `actionClaim`** setting, right
29
+ alongside the other real settings — not buried inside the platform list. The old (broken) location
30
+ is still honored if anyone used it, so nothing that already worked breaks.
31
+
32
+ Two places read that switch: the live server route that receives the promise, and a small "when a
33
+ turn finishes" hook script. Both now look in the new top-level spot first, and both are careful never
34
+ to trip over the list.
35
+
36
+ ## Why it's safe
37
+
38
+ - The feature is *signal-only*: it just writes a note; it never blocks or changes a message. So there
39
+ is no risk of it wrongly rejecting something.
40
+ - It still ships **off by default** — this change only makes the "on" switch reachable, it doesn't
41
+ turn anything on.
42
+ - Old configs keep working (the old location is a fallback), so it's backwards compatible.
43
+ - If it's ever wrong, the fix is a plain code revert — there's no saved data to clean up.
44
+
45
+ ## How we know it works now
46
+
47
+ A new test fills the form out the **real** way — `messaging` as a list — and flips the new top-level
48
+ switch, then checks that a promise like "I'll restart the server now" actually gets written down. It
49
+ fails without the fix and passes with it. Older tests (the ones using the box shape) still pass, so
50
+ the backwards-compatibility promise holds.
@@ -0,0 +1,149 @@
1
+ # Side-Effects Review — Action-Claim sentinel enablable on array-shaped `messaging`
2
+
3
+ **Version / slug:** `actionclaim-config-shape-fix`
4
+ **Date:** `2026-07-04`
5
+ **Author:** `Echo`
6
+ **Second-pass reviewer:** `not required (Tier-1)`
7
+
8
+ ## Summary of the change
9
+
10
+ The Action-Claim Follow-Through Sentinel (including the Slack-followthrough lane from #1361)
11
+ gated on the config path `messaging.actionClaim.enabled`. On every real install `messaging` is a
12
+ JSON **array** of adapter configs, so `messaging.actionClaim.*` is unreachable — `LiveConfig`'s
13
+ `getNestedValue` walks `messaging`, gets the array, evaluates `array['actionClaim']` → `undefined`,
14
+ and returns the `false` default. Because this sentinel defaults OFF, the master gate could never be
15
+ set true: the feature was **structurally un-enablable in production**. CI never caught it because
16
+ every test wrote an object-shaped `messaging`, which no real install uses. Fix: read the config from
17
+ a reachable **top-level `actionClaim`** block (canonical), honoring the legacy object-shaped
18
+ `messaging.actionClaim` as a back-compat fallback. Files: `src/server/routes.ts` (the
19
+ `/action-claim/observe` reads, via a small `acGet` live-read helper), `src/core/PostUpdateMigrator.ts`
20
+ (the generated Stop hook's raw-file resolution + the CLAUDE-template enable-key text),
21
+ `src/scaffold/templates.ts` (the scaffold CLAUDE-template enable-key text), plus tests.
22
+
23
+ ## Decision-point inventory
24
+
25
+ - `POST /action-claim/observe` config reads (`src/server/routes.ts`) — **modify** — master `enabled`,
26
+ `slack.enabled` dev-gate value, `slack.dryRun`, `perTopicCap`, `expiresHours` now resolve
27
+ top-level-first via `acGet`.
28
+ - Generated `action-claim-followthrough.js` Stop hook (`PostUpdateMigrator.getActionClaimFollowthroughHook`)
29
+ — **modify** — the raw-file `enabled` resolution reads top-level `cfg.actionClaim` and Array-guards
30
+ the legacy `cfg.messaging.actionClaim` fallback.
31
+ - The `messaging.actionClaim.slack.enabled` dev-gate (`resolveDevAgentGate`) — **pass-through** — value
32
+ now sourced via `acGet` but the `undefined → live-on-dev, dark-fleet` semantics are unchanged.
33
+
34
+ ---
35
+
36
+ ## 1. Over-block
37
+
38
+ No block/allow surface — over-block not applicable. The change only affects whether a
39
+ signal-only, never-blocking sentinel can be turned ON. An explicit top-level `actionClaim.enabled:false`
40
+ correctly keeps it off (covered by a test).
41
+
42
+ ## 2. Under-block
43
+
44
+ No block/allow surface — under-block not applicable. The sentinel remains dark by default (absent
45
+ config → `false`); the fix does not change detection precision, only config reachability.
46
+
47
+ ## 3. Level-of-abstraction fit
48
+
49
+ Right layer. This is a config-resolution fix at the exact read sites that were broken; it introduces
50
+ no new authority and reuses the existing `LiveConfig` getter and the raw-file read in the generated
51
+ hook. It does not re-implement config parsing — it adds a top-level-first fallback around the
52
+ existing getters.
53
+
54
+ ## 4. Signal vs authority compliance
55
+
56
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
57
+
58
+ - [x] No — this change has no block/allow surface. It changes config reachability for a signal-only
59
+ sentinel (the Stop hook always `exit(0)`; the observe route never blocks a message). No brittle
60
+ logic gains blocking authority.
61
+
62
+ ## 5. Interactions
63
+
64
+ - **Shadowing:** none. The `acGet` helper reads top-level first, then falls back to the old
65
+ `messaging.actionClaim` path with the same default — a superset of prior behavior. Object-shaped
66
+ configs (existing tests) resolve identically via the fallback.
67
+ - **Double-fire:** none. Single read path per field; no new emitter.
68
+ - **Races:** none. Reads are per-request via `LiveConfig` (live, no shared mutable state added).
69
+ - **Feedback loops:** none.
70
+
71
+ ## 6. External surfaces
72
+
73
+ - **Other agents / install base:** the generated Stop hook is regenerated on every migration
74
+ (`instar/` hooks are always-overwritten), so existing agents pick up the array-safe resolution on
75
+ their next update — no per-agent config migration required (a fresh top-level `actionClaim` enable
76
+ is purely additive).
77
+ - **External systems:** none changed. Slack/Telegram delivery paths untouched.
78
+ - **Persistent state:** none. No new ledger/column/file.
79
+ - **Operator surface:** no operator-facing action added — enabling is a config edit (dev-first soak),
80
+ same as before, now at a reachable key. "No operator-facing actions" — the CLAUDE-template text was
81
+ corrected so agents point operators at the reachable `actionClaim.enabled` key.
82
+
83
+ ## 6b. Operator-surface quality
84
+
85
+ No operator surface — not applicable. No dashboard renderer, approval page, or grant/secret form is
86
+ touched.
87
+
88
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
89
+
90
+ **machine-local BY DESIGN.** Config (`.instar/config.json`) is per-machine, and the Action-Claim
91
+ sentinel already runs per-machine on the machine that owns the responding session (it registers under
92
+ that session's own bind token — slack-followthrough-generalization §4.5). This change only alters
93
+ *where in the local config file* the enable flag is read; it introduces no cross-machine state, no
94
+ user-facing notice, no durable state, and no URLs. Enabling it on one machine does not and should not
95
+ implicitly enable it on another — each machine's config is authoritative for its own sessions.
96
+
97
+ ## 8. Rollback cost
98
+
99
+ Pure code change — revert and ship as a patch. No persistent state, no data migration, no user-visible
100
+ regression during the rollback window. The generated hook is regenerated on the next migration in
101
+ either direction. A deployed agent that had set top-level `actionClaim.enabled:true` would, on
102
+ rollback, simply return to un-enablable (the pre-fix state) — no cleanup needed.
103
+
104
+ ## Conclusion
105
+
106
+ The review confirms a low-risk, additive config-resolution fix that makes a previously un-enablable
107
+ default-off sentinel actually turnable-on on real (array-`messaging`) installs, with the legacy
108
+ object-shape fully back-compatible. It adds the missing test coverage (array-shaped `messaging`) that
109
+ would have caught the original bug. Clear to ship. Follow-up worth tracking: the sibling default-ON
110
+ `messaging.*` sentinels (`toneGate`, `outboundAdvisory`) share the same latent unreachability but are
111
+ masked by their on-by-default posture — noted here, not fixed in this change (out of scope).
112
+
113
+ ---
114
+
115
+ ## Second-pass review (if required)
116
+
117
+ **Reviewer:** not required (Tier-1)
118
+ **Independent read of the artifact: n/a**
119
+
120
+ ---
121
+
122
+ ## Evidence pointers
123
+
124
+ - `tests/integration/action-claim-config-shape.test.ts` — array-shaped `messaging` + top-level
125
+ `actionClaim`: enablement, tuning-knob read, explicit-false off-switch, object-shape back-compat.
126
+ - `tests/unit/action-claim-hook-slack.test.ts` — hook-body array-safe resolution assertion.
127
+ - Existing `tests/integration/action-claim-route.test.ts` (14) + `tests/e2e/action-claim-lifecycle.test.ts`
128
+ (4) + `tests/unit/generated-hooks-parse.test.ts` (25) + `tests/unit/migrate-actionclaim-slack-devgate.test.ts`
129
+ (5) all stay green; `tsc --noEmit` clean.
130
+ - `docs/investigations/s7-slack-delivery-repro-2026-07-04.md` — the S7 keystone investigation that
131
+ surfaced this bug (the merged #1361 fix could not be turned on).
132
+
133
+ ---
134
+
135
+ ## Class-Closure Declaration (display-only mirror)
136
+
137
+ - **`defectClass`** — `config-unreachable-on-shape` (`novel`; nearestExistingClass:
138
+ `feature-un-enablable`; includes: a config gate whose dot-path is unreachable given the container's
139
+ real runtime shape, e.g. a key nested under an array-valued parent; excludes: a feature disabled by a
140
+ correctly-read explicit flag). Enters `status: "unconfirmed"` pending operator confirmation, so this
141
+ fix carries `closure: gap` (below), not `closure: guard`.
142
+ - **`closure`** — `gap` — the class-level guard (a lint that flags a `messaging.<x>` dot-path read when
143
+ `messaging` is array-shaped in the shipped config, or a shape-fuzzing test harness for config gates)
144
+ is out of scope for this fix.
145
+ - **`guardEvidence`** — n/a for `closure: gap`.
146
+ - **`gap`** — tracked as a standards-gap follow-up: "config-gate shape-reachability lint/fuzz — a
147
+ default-off feature gated on an unreachable dot-path is un-enablable; add a guard that fails when a
148
+ gate reads `messaging.<child>.*` given `messaging` ships as an array." (This change ships the direct
149
+ regression test for THIS feature; the class-level guard is the tracked gap.)