instar 1.3.928 → 1.3.930

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-24T04:02:28.049Z",
5
- "instarVersion": "1.3.928",
4
+ "generatedAt": "2026-07-24T04:44:30.524Z",
5
+ "instarVersion": "1.3.930",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
14
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
23
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
32
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
41
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
50
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
59
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
68
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
77
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
86
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
95
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
104
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
113
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
122
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
131
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
140
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
149
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
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": "5fbeb5944f457051b0d8d4cf8151d7900e23e4b3d1849f1013a93d5d5a0107f9",
1565
+ "contentHash": "6f779c5c3de7e6e0fae678ec6867e1798aaeaac45e3a78f1e9e13e44442198fa",
1566
1566
  "since": "2025-01-01"
1567
1567
  },
1568
1568
  "subsystem:scheduler": {
@@ -0,0 +1,22 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Every place the system invents a credential — the dashboard PIN and internal auth tokens — now uses the operating system's cryptographically secure random source instead of the predictable general-purpose one. Externally contributed fix (Marceli Pawlinski, PR #1587), adopted with authorship preserved, plus one additional site the contribution missed (the PIN auto-generated during post-update migration).
9
+
10
+ ## What to Tell Your User
11
+
12
+ Nothing to do. Existing PINs and tokens are untouched; only newly generated ones use the stronger source.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ None — same PINs, same token shapes, just unpredictable ones.
17
+
18
+ ## Evidence
19
+
20
+ - PIN range preserved exactly (6 digits, 100000–999999); token length preserved (32 hex chars).
21
+ - Full-tree sweep for remaining credential-class `Math.random` uses: zero (non-credential uses — tmp suffixes, spawn ids, record ids — reviewed and left).
22
+ - External PR #1587's unit shards ran fully green on CI before adoption (8/8 shards, node 20 + 22).
@@ -0,0 +1,25 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ `WorktreeManager` creates an isolated dev checkout (`git worktree add`, or `git clone` when the source is outside agent home) and fast-copies `node_modules` — but it never regenerated husky's git-ignored `.husky/_` shim. Since `core.hooksPath = .husky/_` points at that shim, a fresh checkout had the tracked `pre-commit`/`pre-push` hook files but not the directory git actually resolves the hooks to. Git then silently ran **no** hook (no error), so the instar-dev pre-commit/pre-push enforcement was bypassed in every fresh worktree until someone ran `npm install`.
9
+
10
+ A new best-effort `seedGitHooks(worktreePath)` step runs right after the create/clone: it resolves the effective `core.hooksPath`, and if it is a relative path present in the source but missing in the fresh checkout, copies the shim directory across (and, on the clone path where the fresh `.git/config` carries no hooksPath, replicates the hooksPath config). It is generic (never names husky), fails open (warns, never blocks worktree creation), is idempotent, path-contained, and a no-op for repos with no relative hooksPath or an absolute one.
11
+
12
+ ## What to Tell Your User
13
+
14
+ Nothing changes in how you use your agent day to day — this is an internal reliability fix for instar development. If you run instar-dev / build worktrees, their local commit/push safety checks now actually run from the first commit instead of being silently skipped until a dependency install. There is no new command, setting, or user-visible behavior.
15
+
16
+ ## Summary of New Capabilities
17
+
18
+ - Fresh dev worktrees/clones get their git-hooks shim seeded automatically, so the instar-dev pre-commit/pre-push gates are live immediately — no `npm install` required to activate them.
19
+ - No new API, config, or operator surface; the seeding is automatic, fail-open, and a no-op for repos that don't use a relative-path hooks framework.
20
+
21
+ ## Evidence
22
+
23
+ - Empirically reproduced: a fresh `git worktree add HEAD` has `pre-commit`/`pre-push` but no `.husky/_` → git runs nothing; a live echo dev worktree was found with dead hooks.
24
+ - New regression test `tests/unit/WorktreeManager-git-hooks-seed.test.ts` (4 tests) exercises the real create path via the two-session harness: clone path (shim seeded + hooksPath replicated), worktree path (shim seeded, hooksPath inherited), and both no-op boundaries (non-husky repo, absolute hooksPath). Verified test-first: the clone + worktree tests fail without the fix, all 4 pass with it.
25
+ - Existing worktree suites (`WorktreeManager`, `InstarWorktreeManager`, `WorktreeManager-merkle` — 64 tests) pass unchanged; full `tsc` build clean.
@@ -0,0 +1,35 @@
1
+ # Side-Effects Review — adopt-secure-random
2
+
3
+ ## Change
4
+
5
+ Replace `Math.random()`-derived credential generation with `node:crypto` CSPRNG
6
+ calls at every credential-generation site:
7
+
8
+ - `src/commands/server.ts` — dashboard PIN regeneration (4 sites) → `randomInt(100000, 1000000)`; auth-token generation → `randomBytes(16).toString('hex')`. (Adopted from external PR #1587, author Marceli Pawlinski, authorship preserved via cherry-pick.)
9
+ - `src/monitoring/CoherenceMonitor.ts` — token generation → `randomBytes` (same adoption).
10
+ - `src/core/PostUpdateMigrator.ts` — the one site #1587 missed: auto-generated dashboard PIN on migration → `crypto.randomInt(100000, 1000000)`.
11
+
12
+ ## Behavior preserved
13
+
14
+ - PIN semantics identical: `randomInt(100000, 1000000)` yields exactly the 6-digit
15
+ range 100000–999999, matching `Math.floor(100000 + Math.random() * 900000)`.
16
+ - Token length identical: `randomBytes(16).toString('hex')` = 32 hex chars, same
17
+ shape as the prior 32-char output.
18
+ - No format, storage, or consumer change: every reader of `dashboardPin` /
19
+ `authToken` sees the same shape.
20
+
21
+ ## Blast radius
22
+
23
+ - Values only become unpredictable (the point of the fix). No API surface, config
24
+ schema, or message format changes.
25
+ - `crypto.randomInt` throws only on invalid ranges; the ranges here are constant
26
+ and valid. `randomBytes(16)` failure modes (entropy exhaustion) are the same
27
+ class Node itself depends on at startup.
28
+ - Migration path: the migrator PIN site runs only when `dashboardPin` is absent
29
+ and `authToken` present — the exact prior trigger. Existing PINs are untouched.
30
+
31
+ ## Not affected
32
+
33
+ - No test fixtures encode specific PIN/token values derived from Math.random.
34
+ - Remaining `Math.random()` uses in src/ are non-credential (tmp-file suffixes,
35
+ spawn ids, store record ids) — reviewed and deliberately left.
@@ -0,0 +1,109 @@
1
+ # Side-Effects Review — Seed git-hooks shim into fresh worktrees/clones
2
+
3
+ **Version / slug:** `worktree-git-hooks-seed`
4
+ **Date:** `2026-07-19`
5
+ **Author:** `Echo (instar-dev agent)`
6
+ **Second-pass reviewer:** `independent reviewer subagent — Concur (see Phase 5 note at end)`
7
+
8
+ ## Summary of the change
9
+
10
+ `WorktreeManager.createBinding` creates an isolated dev environment two ways — `git worktree add` (in-tree) or `git clone` (when the source lives outside agent home) — then fast-copies `node_modules` from the source. It never ran husky's `prepare`, so the git-ignored, generated `.husky/_` shim (the directory `core.hooksPath = .husky/_` actually points at) was absent in every fresh checkout. Git then resolves the hooksPath to a missing directory and silently runs **no** hook — no error — so the instar-dev pre-commit/pre-push enforcement was bypassed until an `npm install` regenerated the shim. This change adds one best-effort call, `seedGitHooks(worktreePath)`, right after the create/clone + `fastCopyDeps` block. It resolves the effective `core.hooksPath`, and if it is a relative path missing in the fresh checkout but present in the source, copies the shim directory across (and, on the clone path where the fresh `.git/config` has no hooksPath, replicates the hooksPath config). Files touched: `src/core/WorktreeManager.ts` (+1 call site, +1 private method); test `tests/unit/WorktreeManager-git-hooks-seed.test.ts`.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `WorktreeManager.seedGitHooks` — **add** — filesystem/setup operation that seeds a hooks shim. It holds **no** block/allow authority: it never rejects, delays, or blocks worktree creation; it only makes an EXISTING decision point (the pre-commit/pre-push gates) able to run. On any uncertainty it warns and returns.
15
+
16
+ ---
17
+
18
+ ## 1. Over-block
19
+
20
+ **What legitimate inputs does this change reject that it shouldn't?**
21
+
22
+ No block/allow surface — over-block not applicable. `seedGitHooks` cannot reject a worktree creation; every failure path (`try/catch`, missing source, path-escape, absolute hooksPath) is a silent `return` or an advisory `warn`, and worktree creation proceeds regardless.
23
+
24
+ ---
25
+
26
+ ## 2. Under-block
27
+
28
+ **What failure modes does this still miss?**
29
+
30
+ No block/allow surface — under-block not applicable in the gate sense. Remaining *coverage* gaps (stated honestly, not deferred):
31
+
32
+ - **Source repo has no shim to copy** (e.g. a genuinely bare source with no on-disk `.husky/_` and no relative hooksPath resolvable in the source): the method emits a warn and the new worktree's hooks stay inactive until an install runs. This is an honest best-effort boundary, not a regression — behavior is no worse than before the fix, and the warn surfaces it.
33
+ - **Worktrees created BEFORE this fix** stay hook-dead until re-created or re-installed. This change seeds NEW worktrees only; it does not retroactively repair existing ones (that would be a scope-separate sweep over live worktrees). Scope boundary, explicitly not silently deferred work.
34
+ - **A repo whose hooks framework is not "regenerate-the-shim-shaped"** (a hooksPath pointing at a dir that legitimately must be regenerated per-checkout rather than copied) would get a copied-but-possibly-stale shim; husky's `_` shims are checkout-independent so this is correct for husky, and the copy is a strict improvement over "no hook at all" for any framework whose hooksPath dir is checkout-independent.
35
+ - **A crafted/malicious `core.hooksPath`** — a `../`-relative value, an absolute value, or a value routed through a tracked `.husky` **symlink** — is refused: both a lexical containment check (`startsWith` the resolved root, trailing-`path.sep` so a sibling-prefix like `wt-evil` can't slip through) AND a symlink-safe realpath check (resolve the real path of the nearest existing ancestor and require it stays within the worktree/source real root, since `path.resolve` is lexical and does not follow symlinks). Not reachable under the trusted-source model, but enforced regardless so the guarantee holds literally.
36
+
37
+ ---
38
+
39
+ ## 3. Level-of-abstraction fit
40
+
41
+ **Is this at the right layer?**
42
+
43
+ Yes. The defect is that the worktree/clone creation primitive produced an environment missing a file git needs — so the fix belongs in the primitive that creates the environment (`WorktreeManager.createBinding`), immediately adjacent to `fastCopyDeps`, which already solves the sibling "the fresh checkout is missing generated content (`node_modules`)" problem the same best-effort way. It is deliberately NOT implemented as husky-specific logic (no husky string), and NOT as a higher-level gate — it is a low-level setup step that RESTORES the higher-level gate's ability to fire. No smarter existing layer owns "seed generated files into a fresh worktree"; `fastCopyDeps` is the only peer and this rides directly after it.
44
+
45
+ ---
46
+
47
+ ## 4. Signal vs authority compliance
48
+
49
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
50
+
51
+ **Does this change hold blocking authority with brittle logic?**
52
+
53
+ - [x] No — this change has no block/allow surface. It is a filesystem setup step that makes the pre-existing pre-commit/pre-push gates operational in a fresh worktree. It produces no verdict and holds no authority. It fails open (warn, never throw) so a seeding failure can never block worktree creation — the safe direction.
54
+
55
+ ---
56
+
57
+ ## 4b. Judgment-point check (Judgment Within Floors standard)
58
+
59
+ No new static heuristic at a competing-signals decision point. The logic is a deterministic invariant with an enumerable domain: "if the effective `core.hooksPath` is a relative path present in the source but missing in the worktree, copy it." There are no competing live signals (work evidence / liveness / ownership) being weighed — it is a pure setup precondition.
60
+
61
+ ---
62
+
63
+ ## 5. Interactions
64
+
65
+ - **Shadowing:** Runs once, after the create/clone + `fastCopyDeps` block and before the binding is signed/emitted. It reads git config and copies a directory; it shadows nothing and is shadowed by nothing.
66
+ - **Double-fire:** Idempotent — if the shim directory already exists it returns immediately (`fs.existsSync(destDir)`), so a re-attach or repeated create never re-copies or clobbers a live shim.
67
+ - **Races:** Operates only on the freshly-created worktree path (not yet published as a binding, no other session attached), so no shared-state race. The source `.husky/_` is read-only from this method's view.
68
+ - **Feedback loops:** None. It writes into the new worktree only; it does not feed any system that feeds back into worktree creation.
69
+ - **SafeGitExecutor/SourceTreeGuard:** the config read uses `SafeGitExecutor.readSync` (`config --get` is in the read-only allowlist); the clone-path config SET uses `SafeGitExecutor.execSync` against the new worktree path (under agent home / stateDir), never the instar source tree — so SourceTreeGuard is not tripped. Both resolved paths are containment-checked (lexical `startsWith` on the resolved root PLUS a symlink-safe realpath check on the nearest existing ancestor) to refuse a hooksPath that escapes either root — via a `../` value, an absolute value, or a tracked symlink.
70
+
71
+ ---
72
+
73
+ ## 6. External surfaces
74
+
75
+ - **Other agents / users:** none. Worktree creation is a local dev operation.
76
+ - **External systems:** none (no Telegram/Slack/GitHub/network surface).
77
+ - **Persistent state:** writes the `.husky/_` shim directory into the new worktree and, on the clone path, sets `core.hooksPath` in the new clone's local `.git/config`. Both are inside the freshly-created worktree/clone — no shared or durable instar state is touched.
78
+ - **Timing:** no timing dependency; synchronous, bounded (3s git timeouts, a single directory copy).
79
+ - **Operator surface (Mobile-Complete):** No operator-facing actions — not applicable.
80
+
81
+ ---
82
+
83
+ ## 6b. Operator-surface quality
84
+
85
+ No operator surface — not applicable. This change touches no dashboard renderer, approval page, or grant/revoke/secret form.
86
+
87
+ ---
88
+
89
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
90
+
91
+ **machine-local BY DESIGN.** A worktree/clone is a physical checkout on one machine's disk; each machine's `WorktreeManager` creates and seeds its own worktrees. There is no cross-machine state to replicate and nothing to proxy on read — the fix is the same code running symmetrically on every machine, each seeding hooks into its own local checkouts. No user-facing notice, no durable state that could strand on topic transfer, no generated URL.
92
+
93
+ ---
94
+
95
+ ## 8. Rollback cost
96
+
97
+ Low. The change is one additive, fail-open method + its call site. To back it out: revert the commit (or, as an in-place escape hatch, the method is a no-op for any repo with no relative `core.hooksPath`, and its only writes are into fresh worktrees — a bad seed is corrected by deleting/recreating the worktree, never a data migration). No schema, no persistent instar state, no release-coupled migration. Worst realistic failure mode (a warn-logged seed miss) leaves behavior exactly as it was before the fix.
98
+
99
+ ---
100
+
101
+ ## Phase 5 — Second-pass review (independent reviewer subagent)
102
+
103
+ **Verdict: Concur with the review.**
104
+
105
+ The reviewer independently traced the logic against `createBinding` and confirmed: (1) correctness on both paths — worktree path seeds the shim with the inherited relative hooksPath (git resolves a relative hooksPath against each worktree's own root), clone path seeds the shim AND sets the hooksPath on the clone's independent config; (2) the config SET can **never** mutate the source repo, because `needsConfigSet` is true only when the worktree's own config read was empty, which on a linked worktree (sharing the source config) is structurally impossible — so it only ever fires against a clone's independent config; (3) fail-open — the entire body is inside `try/catch → emit('warn')` and `'warn'` has no unhandled-emit throw semantics, so the method cannot throw and worktree creation can't break; (4) idempotent on re-attach.
106
+
107
+ Two caveats the reviewer raised were addressed in this change (not merely recorded):
108
+ - **Lexical-only containment** → added a symlink-safe realpath containment check (resolve the nearest existing ancestor's real path, require it stays within the worktree/source real root), so the "escape refused" claim now holds for symlink physical escapes, not just `../`/absolute values.
109
+ - **No negative-path tests** → added two regression tests: an escaping `../evil` hooksPath (refused, nothing written outside, worktree still created) and a source-with-no-shim case (advisory warn, no-op, no throw).