instar 1.3.32 → 1.3.34

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 (42) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +47 -1
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/types.d.ts +16 -0
  5. package/dist/core/types.d.ts.map +1 -1
  6. package/dist/core/types.js.map +1 -1
  7. package/dist/feedback-factory/dryrun/dryRunCompare.d.ts +82 -0
  8. package/dist/feedback-factory/dryrun/dryRunCompare.d.ts.map +1 -0
  9. package/dist/feedback-factory/dryrun/dryRunCompare.js +88 -0
  10. package/dist/feedback-factory/dryrun/dryRunCompare.js.map +1 -0
  11. package/dist/feedback-factory/processor/parity.d.ts +111 -0
  12. package/dist/feedback-factory/processor/parity.d.ts.map +1 -0
  13. package/dist/feedback-factory/processor/parity.js +118 -0
  14. package/dist/feedback-factory/processor/parity.js.map +1 -0
  15. package/dist/feedback-factory/store/ReadOnlyShadowStore.d.ts +59 -0
  16. package/dist/feedback-factory/store/ReadOnlyShadowStore.d.ts.map +1 -0
  17. package/dist/feedback-factory/store/ReadOnlyShadowStore.js +88 -0
  18. package/dist/feedback-factory/store/ReadOnlyShadowStore.js.map +1 -0
  19. package/dist/messaging/TelegramAdapter.d.ts +12 -1
  20. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  21. package/dist/messaging/TelegramAdapter.js +28 -7
  22. package/dist/messaging/TelegramAdapter.js.map +1 -1
  23. package/dist/monitoring/StopNotifier.d.ts +88 -0
  24. package/dist/monitoring/StopNotifier.d.ts.map +1 -0
  25. package/dist/monitoring/StopNotifier.js +105 -0
  26. package/dist/monitoring/StopNotifier.js.map +1 -0
  27. package/dist/server/AgentServer.d.ts +2 -0
  28. package/dist/server/AgentServer.d.ts.map +1 -1
  29. package/dist/server/AgentServer.js +1 -0
  30. package/dist/server/AgentServer.js.map +1 -1
  31. package/dist/server/routes.d.ts +4 -0
  32. package/dist/server/routes.d.ts.map +1 -1
  33. package/dist/server/routes.js +13 -0
  34. package/dist/server/routes.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/data/builtin-manifest.json +47 -47
  37. package/upgrades/1.3.31.md +9 -10
  38. package/upgrades/1.3.33.md +36 -0
  39. package/upgrades/1.3.34.md +37 -0
  40. package/upgrades/side-effects/feedback-factory-dryrun.md +93 -0
  41. package/upgrades/side-effects/notify-on-stop-layer-b.md +34 -0
  42. package/upgrades/side-effects/telegram-adapter-multi-instance.md +61 -0
@@ -0,0 +1,34 @@
1
+ # Side-Effects Review — Notify-on-Stop, Layer B (gate-fed unjustified-stall notice)
2
+
3
+ **Spec:** docs/specs/NOTIFY-ON-STOP-SPEC.md (approved: true) — Layer B of two. Layer A (autonomous-run-ended notice) shipped in a prior PR.
4
+
5
+ When the UnjustifiedStopGate (shadow/enforce) classifies a stop as unjustified-but-unblockable (`continue` in `shadow` — the gate wants to continue but shadow can't block, so the session silently stalls) or ambiguous (`escalate`), an UNATTENDED session can go quiet mid-task and the user never hears about it. Layer B turns those specific classifications into ONE coalesced heads-up.
6
+
7
+ ## What changed
8
+ - `src/monitoring/StopNotifier.ts` (new) — thin DECISION layer: `isNotifyWorthyStop` (shadow+continue OR escalate; everything else silent) + attended-gate (unattended/autonomous only, default) + per-session dedup (30-min cooldown) + master enable (default ON). Delivery is delegated to an injected `escalate` sink.
9
+ - `src/commands/server.ts` — constructs a dedicated `SentinelNotifier` (telegramEscalation **on** — distinct from the housekeeping sentinel notifier, which stays default-off) reusing the lifeline-topic `sendConsolidated` transport + a JSONL log; wraps it in a `StopNotifier`. Null when telegram isn't wired or config disables it.
10
+ - `src/server/routes.ts` — the `/internal/stop-gate/evaluate` route computes `autonomousActive` (via `getHotPathState`) and, after the authority decision, calls `ctx.stopNotifier?.maybeNotify({ sessionId, mode, decision, autonomousActive })`. Fire-and-forget; never affects the gate decision or the HTTP response.
11
+ - `src/server/AgentServer.ts` — accepts + forwards `stopNotifier` to the routes ctx.
12
+ - `src/core/types.ts` — `monitoring.notifyOnStop?: { enabled?, unattendedOnly?, cooldownMs? }`.
13
+ - Tests: `StopNotifier.test.ts` (21 — both sides of every decision boundary, attended-gate, dedup window/expiry/per-session, master gate, throwing-sink safety) + `stop-notifier-wiring.test.ts` (6 — route→notifier→sink→server→AgentServer chain, guards the PR#334 dead-code failure mode).
14
+
15
+ ## Signal vs authority
16
+ The Stop-hook router is a dumb thin client; the decision to ALARM the user lives server-side in StopNotifier, where the gate decision + attended-state + dedup ledger all exist. StopNotifier adds NO blocking authority — it's a delivery decision only. It never changes the gate's `decision`.
17
+
18
+ ## Near-silent compliance
19
+ Default-on is the deliberate exception Justin explicitly asked for ("tell me why it stopped"), and it is tightly bounded: only two genuinely-stuck decision classes, only unattended sessions, at most once per session per 30 min, coalesced into one message on the single lifeline topic. Routine turn-ends (`allow`), blocked-and-continued (`continue` in enforce), continue-ceiling (`force_allow`), and fail-open are all silent. A single config flag (`monitoring.notifyOnStop.enabled=false`) kills it with no redeploy.
20
+
21
+ ## Over/under-notify
22
+ - OVER: a shadow-mode `continue` could occasionally be a gate misjudgment (the CONTINUE_CEILING exists because the authority can be wrong). Mitigated by attended-gate + 30-min dedup; the alternative (a silent autonomous stall) is exactly what Justin wants eliminated.
23
+ - UNDER: when the gate is `off` (no evaluate call) there's no Layer B notice — but Layer A still covers autonomous terminal exits, and the gate runs in `shadow` on real agents.
24
+
25
+ ## Migration parity
26
+ Default-on works WITHOUT any config key present (`enabled !== false` ⇒ true when undefined), so existing agents get it on update to this version with no migrateConfig step. The wiring is server-side; no agent-installed-file change.
27
+
28
+ ## Rollback
29
+ `monitoring.notifyOnStop.enabled=false` (instant, no redeploy) or revert the 6 files + 2 tests.
30
+
31
+ ## Tests / verification
32
+ - Tier 1 unit: StopNotifier.test.ts (decision matrix both sides + gates).
33
+ - Wiring-integrity: stop-notifier-wiring.test.ts (no dead code).
34
+ - Tier 3 live: test-as-self before merge — drive a synthetic shadow+continue on an autonomous session through the real route and confirm the lifeline-topic heads-up fires once (and a routine `allow` stays silent).
@@ -0,0 +1,61 @@
1
+ # Side-Effects Review — TelegramAdapter multi-instance isolation + Message-type extension (PR 2a)
2
+
3
+ **Spec:** `docs/specs/MENTOR-LIVE-READINESS-SPEC.md` §Fix 2b "Implementation surface" items
4
+ 1-2 + round-2 integration F1 (converged, approved). PR 2 of the staged build, part a.
5
+ **Change:** Make `TelegramAdapter` safe to run as a second (non-primary) instance in one
6
+ process, and expose the Telegram fields the a2a spoof-defense needs. **Ships dark** — no
7
+ caller passes the new options yet; the new Message fields are additive-optional.
8
+ **Files:** `src/messaging/TelegramAdapter.ts`, `tests/unit/telegram-adapter-multi-instance.test.ts` (new).
9
+
10
+ ## What changed
11
+
12
+ 1. **Constructor opts `{ subDir?, suppressLifelineAutoCreate? }`** (3rd param, optional). When
13
+ `subDir` is set, the four per-bot state files (registry / message-log / poll-offset /
14
+ attention) live under `{stateDir}/{subDir}/` via a new `botStateDir`. The PRIMARY bot
15
+ (no `subDir`) gets `botStateDir === stateDir` → **paths are byte-for-byte unchanged**.
16
+ 2. **`suppressLifelineAutoCreate`** — `start()` skips `ensureLifelineTopic()` when true, so a
17
+ non-primary bot can't create a second Lifeline topic in the chat.
18
+ 3. **Message-type extension** — `message.from.is_bot?: boolean` + `message.sender_chat?` added
19
+ to `TelegramUpdate`. These are the structural inputs to the a2a user-spoof defense (a
20
+ human typing an `[a2a:…]` marker has `is_bot:false` and no `sender_chat`).
21
+
22
+ ## The seven questions
23
+
24
+ 1. **Over-block.** N/A — no gate. The only behavior gate is `suppressLifelineAutoCreate`,
25
+ default false (primary unaffected).
26
+ 2. **Under-block.** The reviewer-flagged collision (two adapters sharing
27
+ `telegram-poll-offset.json` → `poll()`'s cross-token detection fires continuously) is
28
+ eliminated: non-primary state is namespaced. Test asserts the two adapters share NO
29
+ state-file path.
30
+ 3. **Level-of-abstraction fit.** The isolation is at construction (one place), not scattered
31
+ per-callsite. `botStateDir` is the single source for per-bot paths.
32
+ 4. **Signal vs authority.** N/A.
33
+ 5. **Interactions — THE risk, and how it's bounded.** This file runs Echo's own (primary)
34
+ Telegram — the channel to the user. The change is built so the primary path is
35
+ **identical** (when `subDir` is undefined, `botStateDir === stateDir`). A dedicated test
36
+ asserts the four primary paths are byte-for-byte the historical `{stateDir}/...` values,
37
+ and the existing TelegramAdapter suites (71 tests across 5 files) pass unchanged — the
38
+ regression guard for "did I break my own comms." The new code only branches when `subDir`
39
+ is set, and nothing sets it yet (dark). Media/dashboard dirs still resolve off `stateDir`
40
+ inline — NOT isolated — which is fine: the reviewer flagged only the four constructor
41
+ state files, and the mentor bot (the only future `subDir` user) does no media/dashboard.
42
+ 6. **External surfaces.** None. No routes, no config consumed yet. The Message-type fields
43
+ are additive-optional (every existing reader ignores them).
44
+ 7. **Rollback cost.** Trivial — revert restores the 2-param constructor; no data, no migration
45
+ (the primary never wrote to a subDir).
46
+
47
+ ## Testing
48
+
49
+ - `tests/unit/telegram-adapter-multi-instance.test.ts` (3 tests): **primary paths byte-for-byte
50
+ unchanged** (the load-bearing safety assertion); subDir namespaces all four state files +
51
+ shares no path with primary + creates the sub-dir; `suppressLifelineAutoCreate` recorded
52
+ (false default for primary).
53
+ - Regression: existing Telegram suites (`TelegramAdapter`, `telegram-format-wireup`,
54
+ `telegram-adapter`) + the PR-1 `AgentTelegramComms` suite — 71 tests, all green.
55
+ - `tsc --noEmit` clean.
56
+
57
+ ## Migration parity
58
+
59
+ None — additive constructor option + additive optional Message fields. No agent-installed
60
+ file change, no config consumed yet. PR 2b wires `sendAgentMessage` + the recipient handler;
61
+ PR 3's config/migration is per the spec's §Migration parity.