instar 1.3.1036 → 1.3.1037

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.
@@ -2,5 +2,5 @@
2
2
  "sha256": "b75c147afd1f5a9843ca4eac372159f3623f24731fe63b2f59e48043ae488af9",
3
3
  "articleCount": 82,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1036"
5
+ "packageVersion": "1.3.1037"
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.1036",
3
+ "version": "1.3.1037",
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",
@@ -33,6 +33,56 @@ import { checkEli16Overview } from '../../../scripts/eli16-overview-check.mjs';
33
33
 
34
34
  export const API_PORT = Number(process.env.INSTAR_PORT) || 4042;
35
35
 
36
+ /** Relay locations, in resolution order (the second is the documented older-install path). */
37
+ const RELAY_RELATIVE_PATHS = ['.instar/scripts/telegram-reply.sh', '.claude/scripts/telegram-reply.sh'];
38
+
39
+ /**
40
+ * Locate telegram-reply.sh by walking UP from `startDir`.
41
+ *
42
+ * It used to be spawned as the bare relative path `.instar/scripts/telegram-reply.sh`,
43
+ * which only resolves when cwd IS the agent home. instar-dev work is REQUIRED to happen
44
+ * in a worktree (docs/specs/AGENT-WORKTREE-CONVENTION-SPEC.md), and a worktree has no
45
+ * `.instar/scripts/`, so every send from one failed with ENOENT. Walking up from a
46
+ * worktree at `<agent-home>/.worktrees/<slug>` reaches `<agent-home>`, which has it.
47
+ *
48
+ * Returns an absolute path, or null when no relay exists above `startDir`.
49
+ */
50
+ export function resolveRelayScript(startDir = process.cwd(), existsSync = fs.existsSync) {
51
+ const envHome = process.env.INSTAR_AGENT_HOME;
52
+ const roots = [];
53
+ if (envHome) roots.push(path.resolve(envHome));
54
+ let dir = path.resolve(startDir);
55
+ for (;;) {
56
+ roots.push(dir);
57
+ const parent = path.dirname(dir);
58
+ if (parent === dir) break;
59
+ dir = parent;
60
+ }
61
+ for (const root of roots) {
62
+ for (const rel of RELAY_RELATIVE_PATHS) {
63
+ const candidate = path.join(root, rel);
64
+ if (existsSync(candidate)) return candidate;
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+
70
+ /**
71
+ * Did the relay actually deliver?
72
+ *
73
+ * The relay prints `Sent <n> chars to topic <id>` on a real send. Requiring that
74
+ * marker — not merely a zero exit — is deliberate: this script's whole job is
75
+ * handing the operator something to approve, and it previously printed
76
+ * "[published] … delivered" straight after an ENOENT, so a dropped approval ask
77
+ * was indistinguishable from a delivered one. Filed three times in fifteen days
78
+ * (ACT-616 2026-07-13, ACT-1390 2026-07-27, ACT-1517 2026-07-28) before this fix.
79
+ */
80
+ export function relayDelivered(result) {
81
+ if (!result || result.error) return false;
82
+ if (result.status !== 0) return false;
83
+ return /Sent\s+\d+\s+chars?\s+to\s+topic/i.test(`${result.stdout || ''}${result.stderr || ''}`);
84
+ }
85
+
36
86
  /** Split a spec file into its frontmatter body and the rest. */
37
87
  export function extractFrontmatter(specText) {
38
88
  const m = specText.match(/^---\n([\s\S]*?)\n---/);
@@ -144,11 +194,30 @@ async function main() {
144
194
  console.error('--send requires --topic <id>');
145
195
  process.exit(2);
146
196
  }
147
- const reply = spawnSync('bash', ['.instar/scripts/telegram-reply.sh', String(args.topic)], {
197
+ const relay = resolveRelayScript();
198
+ if (!relay) {
199
+ console.error(
200
+ 'REFUSING to claim delivery: no telegram-reply.sh found at or above this directory ' +
201
+ `(looked for ${RELAY_RELATIVE_PATHS.join(' / ')}). The spec was NOT sent.`,
202
+ );
203
+ console.error('The composed message follows so the ask is not lost — send it yourself.');
204
+ console.log(message);
205
+ process.exit(1);
206
+ }
207
+ const reply = spawnSync('bash', [relay, String(args.topic)], {
148
208
  input: message, encoding: 'utf8',
149
209
  });
150
210
  process.stderr.write(reply.stdout || '');
151
211
  process.stderr.write(reply.stderr || '');
212
+ if (!relayDelivered(reply)) {
213
+ const why = reply.error
214
+ ? reply.error.message
215
+ : `relay exited ${reply.status} without a send confirmation`;
216
+ console.error(`\n[NOT DELIVERED] the spec was NOT sent to topic ${args.topic}: ${why}`);
217
+ console.error('The composed message follows so the ask is not lost — send it yourself.');
218
+ console.log(message);
219
+ process.exit(1);
220
+ }
152
221
  console.error(`\n[published] ELI16 link verified (HTTP 200) and delivered to topic ${args.topic}.`);
153
222
  } else {
154
223
  // Print the message + the verified link for the caller to send.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-28T18:31:33.781Z",
5
- "instarVersion": "1.3.1036",
4
+ "generatedAt": "2026-07-28T18:42:16.061Z",
5
+ "instarVersion": "1.3.1037",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -2,5 +2,5 @@
2
2
  "sha256": "b75c147afd1f5a9843ca4eac372159f3623f24731fe63b2f59e48043ae488af9",
3
3
  "articleCount": 82,
4
4
  "generatedFrom": "docs/STANDARDS-REGISTRY.md",
5
- "packageVersion": "1.3.1036"
5
+ "packageVersion": "1.3.1037"
6
6
  }
@@ -0,0 +1,53 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ `skills/spec-converge/scripts/publish-spec-review.mjs` spawned the relay script as a bare
9
+ relative path (`.instar/scripts/telegram-reply.sh`) and then printed
10
+ `[published] … delivered to topic N` without inspecting the spawn result.
11
+
12
+ instar-dev work is required to happen in a worktree, and a worktree has no
13
+ `.instar/scripts/`, so every send from one failed with ENOENT and was reported as
14
+ delivered. Reproduced live: the ENOENT line and the "delivered" line printed one after the
15
+ other, and the operator received nothing.
16
+
17
+ This matters because the script sits on a hook-enforced path — `grounding-before-messaging`
18
+ blocks a hand-written spec-review message and directs the agent here — so the one tool
19
+ whose job is delivering approval asks could silently drop them, leaving work "awaiting
20
+ operator approval" that the operator was never actually asked for.
21
+
22
+ Two changes:
23
+
24
+ - `resolveRelayScript()` walks up from cwd until it finds the relay, so a worktree reaches
25
+ the agent home. Honors `INSTAR_AGENT_HOME` first and falls back to the documented
26
+ `.claude/scripts/` path for older installs. Returns null rather than a guessed path.
27
+ - `relayDelivered()` requires the relay's own `Sent <n> chars to topic <id>` confirmation,
28
+ not merely exit 0. On any failure the script prints `[NOT DELIVERED]` with the reason,
29
+ emits the composed message so the ask is not lost, and exits 1 — it fails closed instead
30
+ of failing silent.
31
+
32
+ The script already refused a broken link, a missing overview, and a stub overview — and
33
+ then did not check whether the message sent. Filed three times in fifteen days (ACT-616
34
+ 2026-07-13, ACT-1390 2026-07-27, ACT-1517 2026-07-28) before being fixed.
35
+
36
+ ## What to Tell Your User
37
+
38
+ None — internal change (no user-facing surface).
39
+
40
+ ## Summary of New Capabilities
41
+
42
+ None — internal change (no user-facing surface).
43
+
44
+ ## Evidence
45
+
46
+ - 11 unit tests over both exported functions, including the exact production failure
47
+ (ENOENT → not delivered), the worktree walk-up that shipped broken, the `.claude`
48
+ fallback, precedence when both exist, and exit-0-with-no-confirmation.
49
+ - Proven against the real filesystem from the actual worktree: `resolveRelayScript`
50
+ returns the agent home's relay and it exists on disk.
51
+ - The fix direction was confirmed before the code was written — the unmodified script run
52
+ from the agent home printed `Sent 408 chars to topic 29723` and genuinely delivered,
53
+ while the same command from the worktree printed ENOENT followed by "delivered".
@@ -0,0 +1,96 @@
1
+ # Side-effects review — publish-spec-review honest send
2
+
3
+ **Change.** `publish-spec-review.mjs` spawned `.instar/scripts/telegram-reply.sh` as a
4
+ bare relative path and then printed `[published] … delivered to topic N` without
5
+ inspecting the spawn result. Now the relay is resolved by walking up from cwd (with the
6
+ documented `.claude/scripts/` fallback), and delivery is only claimed when the relay's own
7
+ `Sent <n> chars to topic <id>` confirmation is present.
8
+
9
+ **This bug was filed three times in fifteen days before being fixed:** ACT-616
10
+ (2026-07-13, medium), ACT-1390 (2026-07-27, high), ACT-1517 (2026-07-28, high).
11
+ Reproduced live at 18:09Z: the ENOENT line and the "delivered" line printed one after the
12
+ other, and the operator received nothing.
13
+
14
+ ## 1. Over-block — what legitimate inputs does this reject that it shouldn't?
15
+
16
+ The delivery check requires the relay's `Sent … chars to topic …` marker, so a future
17
+ relay that succeeds *silently* would be reported as NOT delivered — a false negative.
18
+ Accepted deliberately: this script's only job is handing the operator something to
19
+ approve, so a false "didn't send" (which prints the composed message for manual sending
20
+ and exits 1) is strictly safer than a false "sent". If the relay's output contract
21
+ changes, this test fails loudly rather than the ask disappearing quietly.
22
+
23
+ The path walk can in principle find a relay in an unrelated ancestor directory. In the
24
+ agent-home/worktree layout the first match walking up is the agent's own relay, and
25
+ `INSTAR_AGENT_HOME` takes precedence when set.
26
+
27
+ ## 2. Under-block — what failure modes does this still miss?
28
+
29
+ - **The relay can confirm a send that Telegram later drops.** `Sent N chars` means the
30
+ relay accepted and posted it; downstream delivery failure is the relay's own retry
31
+ domain (PendingRelayStore / DeliveryFailureSentinel), not this script's.
32
+ - **A wrong topic id still "delivers"** — to the wrong place. Not addressed here.
33
+ - **Non-`--send` callers are unchanged**: they print the message and the verified link for
34
+ the caller to send, and can still drop it themselves. That path already exits 0
35
+ honestly because it never claims delivery.
36
+
37
+ ## 3. Level-of-abstraction fit
38
+
39
+ Correct layer. "Where does the relay live" is knowledge the spawning process must have,
40
+ and "did the spawn work" is a question only the spawner can ask. Neither belongs to the
41
+ relay or the caller. The walk-up specifically encodes the worktree convention
42
+ (`docs/specs/AGENT-WORKTREE-CONVENTION-SPEC.md`), which is *why* cwd is reliably not the
43
+ agent home.
44
+
45
+ ## 4. Signal vs authority compliance
46
+
47
+ Compliant, and this is the crux. The script sits on a hook-ENFORCED path: the
48
+ `grounding-before-messaging` hook BLOCKS a hand-written spec-review message and directs
49
+ the agent here. So this script holds real authority over whether an operator ever sees an
50
+ approval ask — and it was reporting success without checking. A brittle, unchecked step
51
+ was granted the last word on a human decision point.
52
+
53
+ The fix adds no new blocking authority. It makes an existing authority *honest*: it now
54
+ fails closed (exit 1, message printed for manual sending) instead of failing silent.
55
+
56
+ ## 5. Interactions
57
+
58
+ - **The grounding hook** is the upstream producer of traffic here; unchanged.
59
+ - **telegram-reply.sh** is spawned identically, only via an absolute resolved path. Its
60
+ own duplicate-suppression and tone-gate behaviour are untouched.
61
+ - **No double-send risk:** the delivery check is read-only on the result; it never retries.
62
+ A false negative prints the message for a human to send, which could produce a duplicate
63
+ if the relay *had* silently sent it — bounded by the relay's own exact-duplicate
64
+ suppression window.
65
+ - No shadowing, no race: one synchronous spawn, one verdict.
66
+
67
+ ## 6. External surfaces
68
+
69
+ Developer/agent tooling under `skills/`. No runtime agent behaviour, route, config, job,
70
+ message schema, or persisted state changes. The only externally visible difference is that
71
+ a failed send is now reported as failed — previously it was reported as success.
72
+
73
+ ## 7. Multi-machine posture
74
+
75
+ **Machine-local BY DESIGN.** The question answered is "where on THIS disk is this agent's
76
+ relay script" — a per-machine filesystem fact. Replicating or proxying it would be
77
+ incorrect; a peer's relay path says nothing about this machine's. No durable state, no
78
+ generated URL, no user-facing notice, so nothing strands on a topic transfer. The rendered
79
+ private-view link the script produces is a separate concern and already tunnel-backed.
80
+
81
+ ## 8. Rollback cost
82
+
83
+ Revert the commit. Two pure exported functions and one call site; no persisted state, no
84
+ migration, no config. Reverting restores the false-success behaviour, which is the reason
85
+ not to.
86
+
87
+ ## Verification
88
+
89
+ - 11 unit tests over both exported functions, including the exact production failure
90
+ (ENOENT → `relayDelivered` false) and the worktree walk-up that shipped broken.
91
+ - Proven against the real filesystem from the actual worktree: `resolveRelayScript`
92
+ returns the agent home's relay and `fs.existsSync` on it is true.
93
+ - The end-to-end fix direction was confirmed before writing the code — running the
94
+ unmodified script from the agent home printed `Sent 408 chars to topic 29723` and
95
+ genuinely delivered, while running it from the worktree printed ENOENT followed by
96
+ "delivered".