instar 1.3.813 → 1.3.814

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.813",
3
+ "version": "1.3.814",
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-11T03:54:14.492Z",
5
- "instarVersion": "1.3.813",
4
+ "generatedAt": "2026-07-11T04:35:17.292Z",
5
+ "instarVersion": "1.3.814",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
14
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
23
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
32
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
41
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
50
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
59
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
68
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
77
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
86
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
95
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
104
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
113
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
122
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
131
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
140
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
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": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
149
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
150
150
  "since": "2025-01-01"
151
151
  },
152
152
  "job:health-check": {
@@ -1242,7 +1242,7 @@
1242
1242
  "type": "template",
1243
1243
  "domain": "operations",
1244
1244
  "sourcePath": "src/templates/scripts/telegram-reply.sh",
1245
- "contentHash": "89849c10aa30cc83a07d6e7721aa3ebbfd07ab897250c0d0f3e234f079dba153",
1245
+ "contentHash": "24a638766fc8a2473e23e032dde39ff7ef046c37e893ff878323d18d9dad2d52",
1246
1246
  "since": "2025-01-01"
1247
1247
  },
1248
1248
  "template:whatsapp-reply.sh": {
@@ -1562,7 +1562,7 @@
1562
1562
  "type": "subsystem",
1563
1563
  "domain": "updates",
1564
1564
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1565
- "contentHash": "c56abb8d920e024e09f5d88beb426798c57ca6d55aa1221912977afa4ffdce18",
1565
+ "contentHash": "93f638d73e5fd2f3b55f893c91ad3358c2124721ca6c7222841d3e3b67260de7",
1566
1566
  "since": "2025-01-01"
1567
1567
  },
1568
1568
  "subsystem:scheduler": {
@@ -133,7 +133,21 @@ sys.stdout.write(base64.b64decode(raw, validate=True).decode("utf-8"))
133
133
  MSG="$DECODED_MSG"
134
134
  fi
135
135
 
136
- # Resolve config-derived values from .instar/config.json (single python3
136
+ # Resolve the owning agent home before reading config or recovery state.
137
+ # Explicit launcher context wins. Otherwise, ONLY the structural .worktrees
138
+ # marker may move us upward; a general config search could cross tenant roots
139
+ # on a multi-agent host. The ordinary agent-home cwd remains unchanged.
140
+ if [ -n "${INSTAR_AGENT_HOME:-}" ]; then
141
+ AGENT_HOME="$INSTAR_AGENT_HOME"
142
+ else
143
+ case "$PWD" in
144
+ */.worktrees/*) AGENT_HOME="${PWD%%/.worktrees/*}" ;;
145
+ *) AGENT_HOME="$PWD" ;;
146
+ esac
147
+ fi
148
+ CONFIG_PATH="$AGENT_HOME/.instar/config.json"
149
+
150
+ # Resolve config-derived values from the owning agent's config (single python3
137
151
  # invocation). Env > config > 4040-warn for port. Auth: INSTAR_AUTH_TOKEN env
138
152
  # first (SessionManager injects it per spawned session; survives the
139
153
  # secret-externalization refactor that moved authToken out of config.json into
@@ -143,11 +157,11 @@ fi
143
157
  AUTH_TOKEN="${INSTAR_AUTH_TOKEN:-}"
144
158
  AGENT_ID=""
145
159
  CONFIG_PORT=""
146
- if [ -f ".instar/config.json" ]; then
160
+ if [ -f "$CONFIG_PATH" ]; then
147
161
  CONFIG_VALUES=$(python3 -c "
148
162
  import json, sys
149
163
  try:
150
- c = json.load(open('.instar/config.json'))
164
+ c = json.load(open(sys.argv[1]))
151
165
  except Exception:
152
166
  sys.exit(0)
153
167
  v = c.get('authToken', '')
@@ -156,7 +170,7 @@ print(c.get('projectName', ''))
156
170
  print(c.get('port', ''))
157
171
  t = (((c.get('messaging') or {}).get('outboundAdvisory') or {}).get('timeoutMs', ''))
158
172
  print(t if isinstance(t, (int, float)) else '')
159
- " 2>/dev/null)
173
+ " "$CONFIG_PATH" 2>/dev/null)
160
174
  CONFIG_AUTH=$(printf '%s\n' "$CONFIG_VALUES" | sed -n '1p')
161
175
  [ -z "$AUTH_TOKEN" ] && AUTH_TOKEN="$CONFIG_AUTH"
162
176
  AGENT_ID=$(printf '%s\n' "$CONFIG_VALUES" | sed -n '2p')
@@ -170,7 +184,7 @@ elif [ -n "$CONFIG_PORT" ]; then
170
184
  PORT="$CONFIG_PORT"
171
185
  else
172
186
  PORT=4040
173
- echo "WARN: telegram-reply.sh — no INSTAR_PORT env and no port in .instar/config.json; falling back to 4040" >&2
187
+ echo "WARN: telegram-reply.sh — no INSTAR_PORT env and no port in $CONFIG_PATH; falling back to 4040" >&2
174
188
  fi
175
189
 
176
190
  # ── Outbound advisory preflight (inform-only; spec outbound-jargon-filepath-gap §2.4) ──
@@ -464,10 +478,15 @@ except Exception:
464
478
  # Enqueue (spec § Layer 2b). Path: <stateDir>/state/pending-relay.<agentId>.sqlite
465
479
  # Mode 0600 enforced by the Node-side store; the CLI inherits umask, so
466
480
  # we explicitly chmod after first create as well.
467
- QUEUE_DIR=".instar/state"
468
- mkdir -p "$QUEUE_DIR" 2>/dev/null
469
481
  # Sanitize agent-id for filename (mirrors src/messaging/pending-relay-store.ts).
470
482
  SAFE_AGENT_ID=$(printf '%s' "${AGENT_ID:-unknown}" | tr -c 'A-Za-z0-9._-' '_')
483
+ if [ "$SAFE_AGENT_ID" = "unknown" ]; then
484
+ echo "Failed (HTTP $HTTP_CODE): $BODY" >&2
485
+ echo " (also: agent id is unknown; refusing to create an undrainable pending-relay.unknown.sqlite store)" >&2
486
+ exit 1
487
+ fi
488
+ QUEUE_DIR="$AGENT_HOME/.instar/state"
489
+ mkdir -p "$QUEUE_DIR" 2>/dev/null
471
490
  QUEUE_DB="${QUEUE_DIR}/pending-relay.${SAFE_AGENT_ID}.sqlite"
472
491
 
473
492
  # delivery_id — the id was minted BEFORE the initial POST and sent on it
@@ -0,0 +1,24 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Telegram replies launched from inside an Instar worktree now resolve the owning agent home before reading relay configuration or writing recovery state. Recovery also refuses loudly when the agent identity is unavailable instead of creating an orphan queue that a server cannot drain.
9
+
10
+ ## What to Tell Your User
11
+
12
+ Replies sent while development is running inside a worktree now use the same live relay configuration as the owning agent. If identity is genuinely unavailable, the send fails visibly in the session instead of leaving a hidden message that might reappear days later.
13
+
14
+ ## Summary of New Capabilities
15
+
16
+ - Honors `INSTAR_AGENT_HOME` as the authoritative relay home.
17
+ - Constrains automatic walk-up to the structural `/.worktrees/` marker.
18
+ - Writes recoverable messages into the owning agent's drainable queue.
19
+ - Refuses `pending-relay.unknown.sqlite` creation with a clear non-zero failure.
20
+ - Re-stamps the corrected script onto existing unmodified installs during update.
21
+
22
+ ## Evidence
23
+
24
+ Real-script integration coverage proves normal agent-home behavior, worktree resolution, explicit-home precedence, and loud unknown-id refusal. Migration tests and the shipped-template SHA ratchet prove fresh installs and existing agents receive the same corrected script.
@@ -0,0 +1,19 @@
1
+ # ELI16 — Worktree replies return to the owning agent
2
+
3
+ ## What Changed
4
+
5
+ Instar agents use a small relay script to send a conversational response back to Telegram. That script normally runs from the agent's home directory, where it can read the live server port and agent identity. During development, however, a session can run from a nested Git worktree. The old script treated that worktree as if it were a separate agent home. It could miss the real port, fail its HTTP request, and then save the reply into a database named for an `unknown` agent inside the worktree. No live server owns or drains that database, so the message becomes a ghost row that could surface much later as a duplicate.
6
+
7
+ The relay now chooses its home conservatively. An explicit `INSTAR_AGENT_HOME` from the launcher wins. Without that variable, the script walks upward only when the current path contains the exact `/.worktrees/` structural marker, stopping immediately before that marker. In every ordinary directory it keeps today's behavior and uses the current directory. It never performs a broad upward search, because that could select another agent's configuration on a shared machine.
8
+
9
+ ## Safety Behavior
10
+
11
+ Recovery still queues a transiently failed reply when the owning agent identity is known. If the identity is missing and would become `unknown`, the script prints a clear reason and exits non-zero without creating a database. The original message remains visible in the caller's transcript, making the failure recoverable and observable instead of silently stranded.
12
+
13
+ ## Deployment
14
+
15
+ Fresh installs already source the canonical relay template. Existing agents receive the same template through PostUpdateMigrator: the v1.3.813 shipped-template hash is registered as a known safe predecessor, so an unmodified installed script is backed up and replaced during update while customized scripts retain the existing non-destructive `.new` behavior.
16
+
17
+ ## Evidence
18
+
19
+ Integration tests execute the real Bash template against a real local HTTP server and SQLite recovery store. They cover worktree cwd resolution, explicit-home precedence, ordinary agent-home behavior, and unknown-id refusal with no orphan database. Unit tests verify migration output contains both safeguards and that historical shipped-template hashes remain complete.
@@ -0,0 +1,77 @@
1
+ # Side-Effects Review — Worktree-safe Telegram relay recovery
2
+
3
+ **Version / slug:** `telegram-reply-worktree-home`
4
+ **Date:** `2026-07-10`
5
+ **Author:** `instar-codey`
6
+ **Second-pass reviewer:** `framework_guard_review`
7
+
8
+ ## Summary of the change
9
+
10
+ The canonical `telegram-reply.sh` now resolves its owning agent home from explicit `INSTAR_AGENT_HOME`, otherwise from the exact `/.worktrees/` path marker, otherwise from the unchanged current directory. Config reads and recovery queue writes use that home. Recovery refuses an `unknown` agent id loudly before creating state. PostUpdateMigrator registers the v1.3.813 template SHA so existing unmodified installs receive the fix. Integration and migration tests cover all boundaries.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - Agent-home resolution — modify — explicit launcher state wins; only a structural worktree marker permits walk-up.
15
+ - Recoverable relay enqueue — modify — known agents retain durable enqueue; unknown identity exits non-zero without an undrainable store.
16
+ - Existing-script migration — modify — the current shipped SHA becomes an allowed predecessor for safe backup-and-replace.
17
+
18
+ ## 1. Over-block
19
+
20
+ A recoverable relay attempt with a genuinely missing `projectName` exits non-zero rather than queueing locally. This is intentional because a live server cannot drain an `unknown`-keyed queue. The message remains in the calling transcript and the stderr reason is explicit. Agent ids literally named `unknown` are also refused; that reserved value is already the absence fallback and cannot safely identify a drain owner.
21
+
22
+ ## 2. Under-block
23
+
24
+ An incorrectly supplied but non-empty `INSTAR_AGENT_HOME` can still point at the wrong agent; launcher-provided identity is authoritative and this script cannot independently authenticate filesystem ownership. A cwd with a nonstandard worktree layout lacking the exact marker remains unchanged rather than guessed upward. Customized deployed relay scripts are preserved and receive a `.new` candidate, so their operator must reconcile the update through the existing degradation path.
25
+
26
+ ## 3. Level-of-abstraction fit
27
+
28
+ The fix lives in the installed relay template because both the config lookup and recovery path are shell-side before the server can participate. It reuses the existing PostUpdateMigrator hash-safe deployment authority rather than adding another installer. The narrow structural marker is the least-powerful resolver that covers the defined worktree convention without cross-tenant discovery.
29
+
30
+ ## 4. Signal vs authority compliance
31
+
32
+ Required reference: [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
33
+
34
+ - [x] This is hard-invariant validation at a transport boundary, not a judgment about message meaning.
35
+
36
+ The unknown-id refusal has deterministic blocking authority because a queue keyed `unknown` is mechanically undrainable. It does not classify conversational content or intent. The worktree resolver likewise selects from explicit structural ownership signals and performs no semantic judgment.
37
+
38
+ ## 5. Interactions
39
+
40
+ - **Shadowing:** home resolution runs before config-derived port/auth/id values, so all later paths share one owner. Explicit port/auth environment overrides keep their existing precedence.
41
+ - **Double-fire:** the change prevents an orphan queue from later double-firing; known-id enqueue and delivery-failed emission retain their existing single path and delivery id.
42
+ - **Races:** the change introduces zero shared mutable structures. The queue retains its existing SQLite concurrency and permission behavior.
43
+ - **Feedback loops:** a refused unknown-id attempt cannot enter the redrive loop; it remains loud in the caller transcript instead.
44
+
45
+ ## 6. External surfaces
46
+
47
+ Worktree-launched Telegram replies now reach the correct local server and recovery database. Unknown-id failures gain a clearer stderr explanation and non-zero status; they create zero persistent database files. Existing unmodified agent scripts are backed up and replaced on update. Routes, credentials, network destinations, and operator actions remain unchanged.
48
+
49
+ ## 6b. Operator-surface quality
50
+
51
+ Operator surface unchanged; this criterion is not applicable.
52
+
53
+ ## 7. Multi-machine posture
54
+
55
+ **Machine-local by design:** an agent home, server port, auth injection, and pending-relay database belong to the machine executing the script. The message route continues to use the local owning server, whose existing messaging layer handles user delivery. The change emits zero additional notices, creates zero cross-machine durable records, leaves topic transfer unchanged, and generates zero URLs.
56
+
57
+ ## 8. Rollback cost
58
+
59
+ Pure script/template and migration-allowlist rollback: revert and ship a patch. Correctly queued rows remain compatible with the existing drain path. Schema and state repair are unnecessary. A rollback would reintroduce the worktree orphan risk until deployed scripts update again.
60
+
61
+ ## Conclusion
62
+
63
+ The fix closes both halves of issue #1086 without broad filesystem discovery: worktree sessions resolve the owning agent home, and identity-less recovery fails visibly instead of persisting an undrainable ghost. Normal cwd behavior and customized-script preservation remain intact. Clear to ship after independent messaging-path review and CI.
64
+
65
+ ## Second-pass review
66
+
67
+ **Reviewer:** framework_guard_review
68
+ **Independent read of the artifact:** concur
69
+
70
+ Home resolution is conservative and correctly ordered: explicit launcher home, exact `/.worktrees/` structural owner, then unchanged cwd. Config and recovery state share that owner; unknown identity stays transcript-visible, exits non-zero, and creates no undrainable queue. The v1.3.813 template SHA matches the migration allowlist entry, customized scripts retain the `.new` path, and the reviewer's focused suite passed 26/26.
71
+
72
+ ## Evidence pointers
73
+
74
+ - `tests/integration/telegram-reply-end-to-end.test.ts`
75
+ - `tests/unit/PostUpdateMigrator-telegramReply.test.ts`
76
+ - `tests/unit/lint-template-sha-history.test.ts`
77
+ - `tests/unit/migration-relay-script-hash.test.ts`