instar 1.3.874 → 1.3.876

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.874",
3
+ "version": "1.3.876",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-18T20:20:52.277Z",
5
- "instarVersion": "1.3.874",
4
+ "generatedAt": "2026-07-18T20:43:31.622Z",
5
+ "instarVersion": "1.3.876",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -11,7 +11,7 @@
11
11
  "domain": "identity",
12
12
  "sourcePath": "src/core/PostUpdateMigrator.ts",
13
13
  "installedPath": ".instar/hooks/instar/session-start.sh",
14
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
14
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
15
15
  "since": "2025-01-01"
16
16
  },
17
17
  "hook:dangerous-command-guard": {
@@ -20,7 +20,7 @@
20
20
  "domain": "safety",
21
21
  "sourcePath": "src/core/PostUpdateMigrator.ts",
22
22
  "installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
23
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
23
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
24
24
  "since": "2025-01-01"
25
25
  },
26
26
  "hook:grounding-before-messaging": {
@@ -29,7 +29,7 @@
29
29
  "domain": "safety",
30
30
  "sourcePath": "src/core/PostUpdateMigrator.ts",
31
31
  "installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
32
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
32
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
33
33
  "since": "2025-01-01"
34
34
  },
35
35
  "hook:compaction-recovery": {
@@ -38,7 +38,7 @@
38
38
  "domain": "identity",
39
39
  "sourcePath": "src/core/PostUpdateMigrator.ts",
40
40
  "installedPath": ".instar/hooks/instar/compaction-recovery.sh",
41
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
41
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
42
42
  "since": "2025-01-01"
43
43
  },
44
44
  "hook:external-operation-gate": {
@@ -47,7 +47,7 @@
47
47
  "domain": "safety",
48
48
  "sourcePath": "src/core/PostUpdateMigrator.ts",
49
49
  "installedPath": ".instar/hooks/instar/external-operation-gate.js",
50
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
50
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
51
51
  "since": "2025-01-01"
52
52
  },
53
53
  "hook:deferral-detector": {
@@ -56,7 +56,7 @@
56
56
  "domain": "safety",
57
57
  "sourcePath": "src/core/PostUpdateMigrator.ts",
58
58
  "installedPath": ".instar/hooks/instar/deferral-detector.js",
59
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
59
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
60
60
  "since": "2025-01-01"
61
61
  },
62
62
  "hook:self-stop-guard": {
@@ -65,7 +65,7 @@
65
65
  "domain": "coherence",
66
66
  "sourcePath": "src/core/PostUpdateMigrator.ts",
67
67
  "installedPath": ".instar/hooks/instar/self-stop-guard.js",
68
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
68
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
69
69
  "since": "2025-01-01"
70
70
  },
71
71
  "hook:post-action-reflection": {
@@ -74,7 +74,7 @@
74
74
  "domain": "evolution",
75
75
  "sourcePath": "src/core/PostUpdateMigrator.ts",
76
76
  "installedPath": ".instar/hooks/instar/post-action-reflection.js",
77
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
77
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
78
78
  "since": "2025-01-01"
79
79
  },
80
80
  "hook:external-communication-guard": {
@@ -83,7 +83,7 @@
83
83
  "domain": "safety",
84
84
  "sourcePath": "src/core/PostUpdateMigrator.ts",
85
85
  "installedPath": ".instar/hooks/instar/external-communication-guard.js",
86
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
86
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
87
87
  "since": "2025-01-01"
88
88
  },
89
89
  "hook:scope-coherence-collector": {
@@ -92,7 +92,7 @@
92
92
  "domain": "coherence",
93
93
  "sourcePath": "src/core/PostUpdateMigrator.ts",
94
94
  "installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
95
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
95
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
96
96
  "since": "2025-01-01"
97
97
  },
98
98
  "hook:scope-coherence-checkpoint": {
@@ -101,7 +101,7 @@
101
101
  "domain": "coherence",
102
102
  "sourcePath": "src/core/PostUpdateMigrator.ts",
103
103
  "installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
104
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
104
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
105
105
  "since": "2025-01-01"
106
106
  },
107
107
  "hook:free-text-guard": {
@@ -110,7 +110,7 @@
110
110
  "domain": "safety",
111
111
  "sourcePath": "src/core/PostUpdateMigrator.ts",
112
112
  "installedPath": ".instar/hooks/instar/free-text-guard.sh",
113
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
113
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
114
114
  "since": "2025-01-01"
115
115
  },
116
116
  "hook:claim-intercept": {
@@ -119,7 +119,7 @@
119
119
  "domain": "coherence",
120
120
  "sourcePath": "src/core/PostUpdateMigrator.ts",
121
121
  "installedPath": ".instar/hooks/instar/claim-intercept.js",
122
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
122
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
123
123
  "since": "2025-01-01"
124
124
  },
125
125
  "hook:claim-intercept-response": {
@@ -128,7 +128,7 @@
128
128
  "domain": "coherence",
129
129
  "sourcePath": "src/core/PostUpdateMigrator.ts",
130
130
  "installedPath": ".instar/hooks/instar/claim-intercept-response.js",
131
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
131
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
132
132
  "since": "2025-01-01"
133
133
  },
134
134
  "hook:stop-gate-router": {
@@ -137,7 +137,7 @@
137
137
  "domain": "safety",
138
138
  "sourcePath": "src/core/PostUpdateMigrator.ts",
139
139
  "installedPath": ".instar/hooks/instar/stop-gate-router.js",
140
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
140
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
141
141
  "since": "2025-01-01"
142
142
  },
143
143
  "hook:auto-approve-permissions": {
@@ -146,7 +146,7 @@
146
146
  "domain": "safety",
147
147
  "sourcePath": "src/core/PostUpdateMigrator.ts",
148
148
  "installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
149
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
149
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -1562,7 +1562,7 @@
1562
1562
  "type": "subsystem",
1563
1563
  "domain": "updates",
1564
1564
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1565
- "contentHash": "b8e7e8d2210384e18a9a676f344c306005757886bebdb97a5afb71678069a3f2",
1565
+ "contentHash": "e63a480f47775520068fe640a60c1f95edac847024de9fdb61dcfd5fe5e3e745",
1566
1566
  "since": "2025-01-01"
1567
1567
  },
1568
1568
  "subsystem:scheduler": {
@@ -5,6 +5,31 @@
5
5
 
6
6
  ## What Changed
7
7
 
8
+ The `mcp-health-autorefresh.sh` built-in hook (auto-restart-on-MCP-inaccessible: at
9
+ session start it probes `claude mcp list` and, when an allowlisted MCP like playwright
10
+ failed to connect, performs ONE loop-guarded `/sessions/refresh` so the tool re-registers)
11
+ was **silently inert in production on coreutils-less Macs** — the platform instar agents
12
+ actually run on. Its probe ran `timeout 45 claude mcp list`; bare `timeout` is a GNU
13
+ coreutils binary absent on stock macOS, the command-not-found was swallowed by
14
+ `2>/dev/null || true`, and the empty capture hit the script's quiet-exit guard. No error,
15
+ no log — the recovery feature simply never ran. Linux CI never saw it because `timeout`
16
+ always exists there.
17
+
18
+ The generated script (authored in `src/core/PostUpdateMigrator.ts` →
19
+ `getMcpHealthAutorefreshHook()`) now bounds the probe with the same portable timeout
20
+ LADDER the autonomous stop hook's real-check runner uses: `timeout` → `gtimeout` →
21
+ perl-alarm fallback (fork + setpgrp + group-KILL on a 45s alarm, exit 124 on timeout,
22
+ and the correct 128+signal exit mapping for a signal-killed child — GNU-timeout
23
+ semantics). With no bounded runner present at all, the script stays dark rather than run
24
+ the probe unbounded. All safety properties are untouched: dark by default,
25
+ explicit-false wins, allowlist-scoped, hard once-per-(session, failed-set) loop-guard.
26
+
27
+ Migration parity: this hook is always-overwrite in `migrateHooks()`, so every deployed
28
+ agent gets the fixed script automatically on this update — no manual step.
29
+
30
+ This also fixes the deterministic macOS-only failure of
31
+ `tests/unit/PostUpdateMigrator-mcpAutorefresh.test.ts`.
32
+
8
33
  The autonomous stop hook's real-check verification runner is now portable across the
9
34
  timeout-ladder rungs on the exit-status contract for signal-death. On macOS (no GNU
10
35
  `timeout`/`gtimeout`), the perl fallback rung mapped a check command killed by a signal to
@@ -37,6 +62,12 @@ This is PR-A of a two-PR staged landing. The runtime apprenticeship gate, accept
37
62
 
38
63
  ## What to Tell Your User
39
64
 
65
+ If your agent runs on a Mac: a small self-healing feature that was accidentally asleep
66
+ now works. When an important tool server (like the browser tool) fails to come up at the
67
+ start of a session, the agent can restart that session once — automatically and at most
68
+ once — so the tool comes back, instead of quietly running without it. Nothing to
69
+ configure; the feature still respects its existing off-by-default/allowlist settings.
70
+
40
71
  Nothing visible changes in day-to-day use. On Macs, autonomous work sessions are now
41
72
  stricter about proving they're really done: a verification check that gets cut off
42
73
  mid-output can no longer be mistaken for a passing check, so a session can't slip out
@@ -47,6 +78,9 @@ No user-visible behavior changes in this release. This is infrastructure honesty
47
78
 
48
79
  ## Summary of New Capabilities
49
80
 
81
+ - No new capabilities — a portability fix that makes the existing (config-gated)
82
+ MCP auto-refresh recovery actually run on macOS, identically to Linux.
83
+
50
84
  - No new capabilities — a safety/portability fix. The autonomous completion guarantee
51
85
  ("a failing real check always means keep working") now holds identically on macOS and
52
86
  Linux.
@@ -57,6 +91,16 @@ No user-visible behavior changes in this release. This is infrastructure honesty
57
91
 
58
92
  ## Evidence
59
93
 
94
+ - Root cause reproduced on macOS 26 (no `timeout`/`gtimeout` installed): the probe line
95
+ produced an empty LIST and the script exited silently before any observable action.
96
+ - Perl-rung contract proven live on this machine: hung command bounded (exit 124),
97
+ normal exit codes passed through (3 → 3), signal-death mapped to 128+signal
98
+ (SIGTERM → 143), stdout captured intact.
99
+ - `tests/unit/PostUpdateMigrator-mcpAutorefresh.test.ts`: 9/9 pass (previously 1
100
+ deterministic failure on macOS), including `bash -n` syntax validity and the
101
+ always-overwrite migration-parity pin.
102
+ - 14 targeted migrator + stop-hook sibling test files: 139/139 pass on this branch.
103
+
60
104
  - Instrumented reproduction on macOS 26 (Node 24): the shipped hook returned the
61
105
  allow-exit message for `printf "\xe4\xb8\xad%.0s" $(seq 1 100000); exit 1`
62
106
  (`PIPESTATUS[0]=0` from the perl rung) before the fix; after the fix it returns a valid
@@ -0,0 +1,50 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Added `docs/AI-EMPLOYEE-ROADMAP.md` — the program-level roadmap that maps the
9
+ apprenticeship program onto instar's top-level goal: an agent that works as a
10
+ fully engaged AI employee. It defines the three capabilities that make up that
11
+ posture — multi-machine coherence (3–4 machines, one identity), first-class
12
+ chat-platform citizenship (Telegram today, Slack as the primary workplace
13
+ surface next), and multi-principal service (every staff member served by the
14
+ same agent with no identity bleed) — and lays each out as a stage ladder
15
+ (A1→A4, B1→B3, C1→C3) with an explicit, evidence-gated exit bar. The method is
16
+ prove-it-on-the-apprentice-first: every capability is developed and de-risked
17
+ on a prototype agent under observation, through the same user channels a human
18
+ would use, before any production agent inherits the configuration. Graduation
19
+ is serial and evidence-gated — recorded, artifact-backed acceptances, never a
20
+ vibe.
21
+
22
+ This is documentation only. No code, config, hook, job, template, or test
23
+ changes; no runtime surface; no behavior change for any deployed agent.
24
+
25
+ ## What to Tell Your User
26
+
27
+ Nothing changes in how your agent behaves. The project now carries a public
28
+ roadmap document describing where the platform is headed — an agent that works
29
+ like a real employee: present on several machines as one coherent identity, a
30
+ well-mannered citizen of workplace chat (Slack next), and able to serve a whole
31
+ team without mixing people up — and how each step gets proven on a supervised
32
+ prototype before it ever reaches a production agent.
33
+
34
+ ## Summary of New Capabilities
35
+
36
+ - None (documentation only). New artifact: `docs/AI-EMPLOYEE-ROADMAP.md`, the
37
+ program-level map from the apprenticeship program to the full AI-employee
38
+ posture, with evidence-gated graduation criteria per capability.
39
+
40
+ ## Evidence
41
+
42
+ - `docs/AI-EMPLOYEE-ROADMAP.md` — the roadmap itself (deliberately
43
+ organization-agnostic for this public repo).
44
+ - `docs/specs/ai-employee-roadmap.eli16.md` — plain-English explainer.
45
+ - `upgrades/side-effects/ai-employee-roadmap.md` — side-effects review; every
46
+ question resolves to "documentation-only, no runtime surface";
47
+ multi-machine posture unified-via-git; rollback = revert the doc.
48
+ - Sanity: the whole-tree stall-coverage CI ratchet
49
+ (`tests/unit/stall-coverage-ratchet.test.ts`) runs green on this tree —
50
+ the change coexists with the freshly-landed PR-A ratchet.
@@ -0,0 +1,86 @@
1
+ # Side-Effects Review — ai-employee-roadmap (docs-only)
2
+
3
+ **Change:** adds `docs/AI-EMPLOYEE-ROADMAP.md` — the program-level roadmap from
4
+ the apprenticeship program to a full AI-employee posture (multi-machine
5
+ coherence, first-class Slack citizenship, multi-principal service), with
6
+ per-capability stage ladders and evidence-gated exit bars. Plus the standard
7
+ artifacts (this review, the ELI16, the release fragment). **No source, config,
8
+ template, hook, job, or test files are touched.** Documentation-only, no
9
+ runtime surface.
10
+
11
+ ## Phase 1 principle check (recorded)
12
+
13
+ Does this change involve a decision point? **No.** The document describes a
14
+ program and its graduation criteria; it ships no validator, gate, sentinel, or
15
+ any code that evaluates anything. The graduation decisions it describes are
16
+ explicitly human/overseer acceptances recorded as artifacts — and none of that
17
+ machinery ships here. Signal-vs-authority is not implicated: nothing here can
18
+ block, allow, or judge.
19
+
20
+ ## 1. Over-block
21
+
22
+ Nothing can be over-blocked: documentation-only, no runtime surface. The change
23
+ introduces no blocking surface of any kind — no CI check, no gate, no hook. The
24
+ only "block" it could ever exert is social (a reader citing the roadmap), which
25
+ is outside the runtime.
26
+
27
+ ## 2. Under-block
28
+
29
+ Nothing can be under-blocked: documentation-only, no runtime surface. No
30
+ enforcement is promised by this change, so there is no enforcement to be
31
+ incomplete. The exit bars the document names are enforced (or not) by the
32
+ machinery of their own workstreams, each with its own specs and reviews.
33
+
34
+ ## 3. Level-of-abstraction fit
35
+
36
+ Right layer. A program-level roadmap belongs in `docs/` at the repo root
37
+ (`docs/AI-EMPLOYEE-ROADMAP.md`), above the individual capability specs it
38
+ references and below nothing — it is the map that points at the specs, not a
39
+ duplicate of any of them. It deliberately contains no schedule and no
40
+ organization-specific content (agent names, staffing, rollout order stay with
41
+ the operator, outside this public repo).
42
+
43
+ ## 4. Signal vs authority compliance
44
+
45
+ Compliant vacuously: documentation-only, no runtime surface. The change creates
46
+ no authority (nothing blocks) and no signal (nothing observes). The document
47
+ itself *describes* the signal→authority discipline of the apprenticeship
48
+ (observe-only guards graduating to enforcing on evidence), which is consistent
49
+ with `docs/signal-vs-authority.md`, but describing it is not implementing it.
50
+
51
+ ## 5. Interactions
52
+
53
+ None at runtime: documentation-only, no runtime surface. No job, sentinel,
54
+ route, or hook reads this file. Repo-level interactions are benign: it cites
55
+ existing specs (e.g. the apprenticeship scaffold spec, framework stall-coverage
56
+ work) by path; if those move, the references go stale — a docs-freshness
57
+ concern (the cartographer sweep's domain), not a behavior risk.
58
+
59
+ ## 6. External surfaces
60
+
61
+ None: documentation-only, no runtime surface. No API route, no config key, no
62
+ message to any user, no notification, no npm-shipped runtime change (the file
63
+ rides the package inertly as documentation). The document was deliberately
64
+ written organization-agnostic for this public repo — it names no organization,
65
+ person, or deployed agent.
66
+
67
+ ## 7. Multi-machine posture
68
+
69
+ **Unified-via-git.** The document is a repo-tracked file; every machine sees
70
+ the same content at the same SHA. No per-machine runtime state is created, so
71
+ there is nothing to strand, sync, or reconcile.
72
+
73
+ ## 8. Rollback cost
74
+
75
+ Revert the doc (one revert of this commit). No data migration, no agent state,
76
+ no config, no deployed-behavior change to unwind. Cheapest possible rollback
77
+ class.
78
+
79
+ ## Second-pass review
80
+
81
+ **Not required.** The second-pass trigger is for changes that wire
82
+ block/allow decisions, session-lifecycle, messaging, or dispatch behavior —
83
+ this change wires nothing: documentation-only, no runtime surface, no decision
84
+ point, no enforcement. There is no code for a second reviewer to contradict
85
+ against the artifact; the only reviewable claim ("the doc says what the ELI16
86
+ and fragment say it says") is verified by reading the three files side by side.
@@ -0,0 +1,126 @@
1
+ # Side-Effects Review — MCP Auto-Refresh Hook macOS Timeout Portability
2
+
3
+ **Version / slug:** `mcp-autorefresh-timeout-macos`
4
+ **Date:** `2026-07-18`
5
+ **Author:** Echo (autonomous, Tier-1 fix cycle, tracked ref CMT-896)
6
+ **Second-pass reviewer:** self-reviewed-final-diff (session-lifecycle adjacent — the hook can trigger a /sessions/refresh — second pass required; performed as a genuinely fresh re-read of this artifact against the final diff; see "Second-pass review" below)
7
+
8
+ ## Summary of the change
9
+
10
+ `tests/unit/PostUpdateMigrator-mcpAutorefresh.test.ts` ("DEV agent auto-enables…") failed
11
+ deterministically on macOS while Linux CI was green. Root cause: the generated
12
+ `mcp-health-autorefresh.sh` (authored in
13
+ `src/core/PostUpdateMigrator.ts` → `getMcpHealthAutorefreshHook()`) ran its health probe
14
+ as `LIST=$(timeout 45 "$CLAUDE_BIN" mcp list 2>/dev/null || true)`. Bare `timeout` is GNU
15
+ coreutils — absent on coreutils-less Macs (this machine has neither `timeout` nor
16
+ `gtimeout` nor Homebrew). The command-not-found error was swallowed by `2>/dev/null || true`,
17
+ LIST stayed empty, and the script's `[ -n "$LIST" ] || exit 0` guard exited silently —
18
+ so the auto-restart-on-MCP-inaccessible feature was **silently inert in production on
19
+ macOS**, the platform instar agents actually run on. Same platform-gap family as the
20
+ autonomous stop hook's real-check runner fix (previous cycle).
21
+
22
+ Files modified (single source file):
23
+ - `src/core/PostUpdateMigrator.ts` — the generated hook's probe line becomes a portable
24
+ bounded-runner LADDER mirroring the stop hook: `timeout` → `gtimeout` → perl-alarm
25
+ fallback. The perl rung forks, `setpgrp` + group-KILL on a 45s alarm (exit 124), and
26
+ maps child status with `exit(($?&127) ? 128+($?&127) : ($?>>8))` — GNU-timeout
27
+ semantics, so a signal-killed probe is never mistaken for a clean exit. If NO bounded
28
+ runner exists, the script stays dark (exit 0) — it never runs the probe unbounded.
29
+
30
+ ## The eight questions
31
+
32
+ 1. **Over-block** — None identified. On Linux (and Macs with coreutils) the first rung is
33
+ byte-identical to the old behavior. On coreutils-less Macs the change strictly
34
+ *enables* previously-dead functionality; it rejects nothing new. The no-runner-at-all
35
+ case (no timeout, no gtimeout, no perl) exits 0 exactly as the script effectively did
36
+ before — but now by explicit design with a comment, not by accident.
37
+ 2. **Under-block** — The fix closes the silent-inert hole. Remaining, pre-existing and
38
+ unchanged: a `claude mcp list` that exits 0 but prints garbage is still trusted as a
39
+ listing (grep simply won't match); the 45s bound is unchanged. The perl rung's
40
+ KILL-on-alarm is stricter than GNU `timeout`'s default TERM-then-KILL — acceptable
41
+ here because the probe is read-only (`mcp list` mutates nothing worth a graceful
42
+ shutdown). No issue identified.
43
+ 3. **Level-of-abstraction fit** — Correct layer: the bounded-runner contract lives inside
44
+ the generated script at the single probe callsite, exactly parallel to the stop hook's
45
+ ladder (the established in-repo pattern for "bound a command portably"). A shared
46
+ sourced library for the two ladders would be a bigger refactor of generated-script
47
+ plumbing than this fix warrants and would couple two independently-shipped hooks;
48
+ deliberately not done.
49
+ 4. **Signal-vs-authority compliance** — Not a message-flow decision point; deterministic
50
+ exit-status plumbing in an existing dark-by-default hook. The hook's authority shape
51
+ is unchanged: dark default, explicit-false wins, allowlist scope, hard loop-guard
52
+ (at most ONE refresh per (session, failed-set)). No brittle blocking heuristic added
53
+ (`docs/signal-vs-authority.md` reviewed — this adds no gate). No issue identified.
54
+ 5. **Interactions** — The ladder only changes HOW the probe is bounded, not what
55
+ downstream sees: LIST parsing, allowlist matching, marker loop-guard, and the
56
+ /sessions/refresh call are untouched. On machines with `timeout` (all of CI, most
57
+ Linux) the executed bytes are the same as before, so zero interaction delta there.
58
+ The perl rung's process-group KILL cannot touch the parent script (child is
59
+ `setpgrp`'d into its own group). No double-fire: rungs are exclusive `elif`s.
60
+ 6. **External surfaces** — None new. No network, config, API, or route changes. The
61
+ generated file's content changes (comment + ladder), which the existing unit suite
62
+ re-pins (`bash -n` syntax validity, safety-invariant greps, migration parity). Agents'
63
+ observable behavior change: on coreutils-less Macs an allowlisted failed MCP can now
64
+ actually trigger the (config-gated, loop-guarded) single session refresh — i.e. the
65
+ feature works as its spec and config already documented.
66
+ 7. **Multi-machine posture (Cross-Machine Coherence)** — Machine-local BY DESIGN: the
67
+ hook runs at session start on the machine hosting the session, probing THAT machine's
68
+ MCP registrations; its marker state (`.instar/state/mcp-autorefresh-marker.json`) is
69
+ per-machine and must not replicate (another machine's MCP health is meaningless here).
70
+ The fix makes behavior machine-uniform across the pool (a Mac and a Linux box now run
71
+ the same probe contract). No user-facing notice, no durable cross-machine state, no
72
+ URLs.
73
+ 8. **Rollback cost** — Low. Single-file revert of one commit restores the prior generated
74
+ script; the next migration pass always-overwrites the deployed copy back (same
75
+ delivery path as the fix). No data migration, no state repair — the marker file format
76
+ is unchanged. Reverting re-opens the silent-inert-on-macOS hole, so the back-out plan
77
+ is revert-and-re-fix.
78
+
79
+ ## Migration Parity (explicit)
80
+
81
+ `migrateHooks()` writes this hook with an unconditional `fs.writeFileSync` into
82
+ `.instar/hooks/instar/mcp-health-autorefresh.sh` on every migration run (always-overwrite,
83
+ never install-if-missing) — verified in code (src/core/PostUpdateMigrator.ts, the
84
+ migrateHooks try-block) and pinned by the passing test "migration parity: migrateHooks
85
+ always-overwrites the hook into hooks/instar/". Deployed Macs therefore receive the fixed
86
+ script automatically on their next instar update; no config or manual step.
87
+
88
+ ## Class-Closure Declaration
89
+
90
+ - **defectClass:** `unbounded-self-action` — **closure: n/a** (negative declaration).
91
+ No new self-action is introduced: the diff's added `kill()` is the perl timeout rung
92
+ reaping its OWN bounded child probe (process hygiene inside a one-shot session-start
93
+ probe), not a controller emit. The hook's pre-existing self-triggered action (the
94
+ single `/sessions/refresh`) is unchanged and remains hard-bounded by the
95
+ once-per-(session, failed-set) marker loop-guard — it structurally cannot loop.
96
+ Mirrors the machine-readable declaration in the instar-dev trace.
97
+
98
+ ## Second-pass review (self-reviewed-final-diff)
99
+
100
+ Fresh re-read of the final `git diff` against this artifact:
101
+
102
+ - **Template-literal escaping audited character-by-character**: every shell `$` in the
103
+ added block is escaped `\$` (TS template literal), including all perl variables
104
+ (`\$t`, `\$p`, `\$SIG`, `\$?`); no bare `${` remains that TS would interpolate; the
105
+ perl program contains no single quotes so the bash single-quoted `-e '…'` wrapping is
106
+ sound. The generated output was syntax-checked via the suite's `bash -n` test (passes).
107
+ - **Live contract proof re-run** (this machine, no timeout/gtimeout): perl rung returns
108
+ 124 on a hung `sleep 30` with a 2s bound; passes through exit 3; maps SIGTERM death to
109
+ 143; captures stdout correctly. The dev-gate unit test exercises the full script path
110
+ through the perl rung end-to-end (mock `claude` → probe → dead-port session resolution).
111
+ - **First-pass omission caught and fixed in this artifact**: the initial draft of Q2 did
112
+ not name the KILL-vs-TERM strictness difference between the perl rung and GNU timeout's
113
+ default; added with the read-only-probe justification.
114
+ - **Honest scope note**: this branch (off origin/main) does not contain the previous
115
+ cycle's stop-hook fix — `tests/unit/autonomous-stop-hook-realcheck.test.ts` still shows
116
+ that one known failure HERE (1 failed | 23 passed), which is the other PR's subject and
117
+ resolves when both merge. All 14 targeted sibling/migrator files (139 tests) pass on
118
+ this branch, including the previously-failing mcpAutorefresh suite (9/9).
119
+ - **Checked for other bare-`timeout` callsites in generated scripts** (grep for
120
+ `timeout N` across `src/core/PostUpdateMigrator.ts`, `src/data/http-hook-templates.ts`,
121
+ `src/scaffold/`, `src/templates/`, `templates/`, excluding curl's `--connect-timeout`/
122
+ `--max-time` flags): the line fixed here was the ONLY bare coreutils-`timeout`
123
+ invocation; no other generated script carries this defect class. Sweep converged clean
124
+ in one re-pass. <!-- tracked: CMT-896 -->
125
+ - Conclusion: artifact accurate against the final diff; no unlisted side effects found.
126
+ Reviewer concurs with shipping.