instar 1.3.655 → 1.3.657

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 (40) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +21 -0
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/LiveTestHarness.d.ts +55 -1
  5. package/dist/core/LiveTestHarness.d.ts.map +1 -1
  6. package/dist/core/LiveTestHarness.js +71 -2
  7. package/dist/core/LiveTestHarness.js.map +1 -1
  8. package/dist/core/RealChannelDriver.d.ts +15 -0
  9. package/dist/core/RealChannelDriver.d.ts.map +1 -1
  10. package/dist/core/RealChannelDriver.js +16 -0
  11. package/dist/core/RealChannelDriver.js.map +1 -1
  12. package/dist/core/SlackLiveSender.d.ts +29 -0
  13. package/dist/core/SlackLiveSender.d.ts.map +1 -1
  14. package/dist/core/SlackLiveSender.js +68 -3
  15. package/dist/core/SlackLiveSender.js.map +1 -1
  16. package/dist/core/TelegramLiveSender.d.ts +18 -0
  17. package/dist/core/TelegramLiveSender.d.ts.map +1 -1
  18. package/dist/core/TelegramLiveSender.js +60 -0
  19. package/dist/core/TelegramLiveSender.js.map +1 -1
  20. package/dist/core/rateLimitFalsePositiveMatrix.d.ts +28 -0
  21. package/dist/core/rateLimitFalsePositiveMatrix.d.ts.map +1 -0
  22. package/dist/core/rateLimitFalsePositiveMatrix.js +74 -0
  23. package/dist/core/rateLimitFalsePositiveMatrix.js.map +1 -0
  24. package/dist/monitoring/CompactionSentinel.d.ts +9 -0
  25. package/dist/monitoring/CompactionSentinel.d.ts.map +1 -1
  26. package/dist/monitoring/CompactionSentinel.js +8 -0
  27. package/dist/monitoring/CompactionSentinel.js.map +1 -1
  28. package/dist/monitoring/QuotaCollector.d.ts.map +1 -1
  29. package/dist/monitoring/QuotaCollector.js +21 -8
  30. package/dist/monitoring/QuotaCollector.js.map +1 -1
  31. package/dist/monitoring/RateLimitSentinel.d.ts +25 -0
  32. package/dist/monitoring/RateLimitSentinel.d.ts.map +1 -1
  33. package/dist/monitoring/RateLimitSentinel.js +44 -0
  34. package/dist/monitoring/RateLimitSentinel.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/data/builtin-manifest.json +2 -2
  37. package/upgrades/1.3.656.md +68 -0
  38. package/upgrades/1.3.657.md +32 -0
  39. package/upgrades/side-effects/false-ratelimit-recovery-completed-sessions.md +113 -0
  40. package/upgrades/side-effects/real-channel-absence-collect.md +73 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.655",
3
+ "version": "1.3.657",
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-06-24T16:39:12.372Z",
5
- "instarVersion": "1.3.655",
4
+ "generatedAt": "2026-06-24T22:34:53.907Z",
5
+ "instarVersion": "1.3.657",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,68 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ A shared safety helper that rescues sessions blocked by an AI-provider throttle was
9
+ mis-firing: a session that had already FINISHED sits idle with the old throttle message
10
+ still on its screen, so the helper kept trying to "rescue" a session that was simply
11
+ done and pinged the user with *"the temporary server throttle should have cleared —
12
+ please continue where you left off."* Because the helper is shared, the false alarm
13
+ showed up fleet-wide (it was also seen on AI Guy).
14
+
15
+ The fix makes a finished/killed session structurally incapable of being a rescue target:
16
+ the helper now checks the session is still running at every point it can act (when it
17
+ decides to rescue, before each retry, AND before the "did it respond?" check) and bails
18
+ out silently if the session ended. When a session completes, the helpers stop watching
19
+ it immediately. A separate noisy "rate limit" log that fired on harmless quota-meter
20
+ hiccups is also quieted (it now only logs on a sustained problem).
21
+
22
+ It also adds a reusable prevention capability: the user-channel test harness can now
23
+ prove that NO unwanted background message (like the false throttle nudge) appears over a
24
+ time window — so this class of "a background feature messages you by mistake" is caught
25
+ by the ship gate before it reaches the fleet.
26
+
27
+ ## What to Tell Your User
28
+
29
+ You should stop seeing phantom "throttle cleared, continue" messages that don't match
30
+ anything actually happening in your session. Real throttles are still handled — genuine
31
+ rescues still run and still tell you. Nothing you need to do; it takes effect on update.
32
+
33
+ ## Summary of New Capabilities
34
+
35
+ - Finished/killed sessions can no longer trigger a false throttle/error recovery, and a
36
+ rescue whose session ends mid-flight stops silently instead of sending a stray
37
+ "still can't get through" message.
38
+ - (Agent/dev) The live-test harness gained an absence-assertion: a scenario can drive a
39
+ real conversation and assert that no message matching a pattern arrives within a
40
+ window, with the result feeding the existing "is this done?" gate.
41
+
42
+ ## Evidence
43
+
44
+ **Reproduction (observed incident, 2026-06-24, topic 28130):** the Mac Mini's Claude
45
+ account was quota-walled, so its session for the topic finished. The finished session
46
+ sat idle with a throttle line still on its terminal; the RateLimitSentinel read that
47
+ stale scrollback, classified the done session as "throttled," and began resume attempts
48
+ that produced repeated *"the temporary server throttle should have cleared — please
49
+ continue where you left off."* nudges across every topic the Mini owned. Server logs
50
+ corroborated the second trigger: 716 "rate limit" hits were almost entirely
51
+ `QuotaCollector.collect.oauth: OAuth usage returned 429 retry-after: 0` — the quota-meter
52
+ endpoint briefly saying no, not a real rate limit (a genuine limit carries a meaningful
53
+ retry-after). One healthy working session was false-flagged 54 times, confirming the
54
+ detector — not any one agent — was the cause (it also surfaced on AI Guy).
55
+
56
+ **Before:** a completed session, having no new terminal output, was indistinguishable
57
+ from a throttled one and stayed a recovery target indefinitely (never cleared from the
58
+ topic map) → repeated phantom nudges; junk `retry-after:0` 429s logged as rate limits.
59
+
60
+ **After (verified):** the new `isSessionRecoverable` guard NO-OPS recovery for any session
61
+ not in the live running set, at all three fire points (decide-to-rescue, pre-retry,
62
+ pre-verify) — proven both-sides by `RateLimitSentinel-recoverable-guard` /
63
+ `CompactionSentinel-recoverable-guard` unit tests; the finished-during-verify race is
64
+ reproduced and locked by a dedicated test; the absence-assertion integration test drives
65
+ a regressed build (false nudge reintroduced) and confirms the done gate VETOES it. The
66
+ `retry-after:0` 429 is reclassified as a transient blip (log-level only). 16 unit + 2
67
+ integration tests, no regression across the existing watcher/quota/harness suites, clean
68
+ typecheck.
@@ -0,0 +1,32 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The live-test harness gained the ability to run its **absence proof** — "after this conversation, prove the agent sent NO unwanted background message (e.g. the false throttle nudge)" — over a **real** Telegram or Slack channel. Previously that assertion only worked against a simulated driver; the production channel driver had no way to collect a window of channel messages, so a real-channel absence scenario was reported as unverifiable.
9
+
10
+ A new `collectMessages` step (on the Telegram and Slack live senders, exposed through `RealChannelDriver`) polls the channel's history over a window and gathers every agent-authored message, so the harness can prove none of them matches a forbidden pattern. Because the only dangerous failure of an absence proof is a silent **false PASS**, every way the read could be incomplete is forced to BLOCK ("can't verify") instead of passing:
11
+
12
+ - a **paginated/truncated** read (more messages than one page) → BLOCKED;
13
+ - an **edited** message can't launder its earlier text away (every version is kept);
14
+ - a **Slack background post** under a `bot_id` (not a user id) is now matched;
15
+ - a **failed** history read → BLOCKED;
16
+ - a reused, long-lived demo channel no longer trips a false "too busy" alarm (the Telegram check is bounded to where the test message sits in history).
17
+
18
+ ## What to Tell Your User
19
+
20
+ Nothing changes in day-to-day use — this is testing infrastructure that runs before code ships, not something on the live conversation path. The benefit is indirect: the "no surprise background message" guarantee can now be proven over a real channel, and it refuses to give a green light it can't actually justify — one more way a feature side-effect is caught before it reaches the fleet.
21
+
22
+ ## Summary of New Capabilities
23
+
24
+ - `RealChannelDriver.collectMessages` + `SurfaceSender.collectMessages` on the Telegram and Slack live senders — collect a window of agent-authored channel messages for the harness absence assertion.
25
+ - A second typed harness signal, `AbsenceUnverifiableError`: a sender raises it for an incomplete/failed read so the harness records BLOCKED (never a false PASS); `DriverCapabilityError` stays the capability-layer "no collector on this surface" signal; a plain error stays a FAIL.
26
+ - Absence scenarios are demo-channel-only (a whole-history read never touches a live operator channel).
27
+
28
+ ## Evidence
29
+
30
+ - **Reproduction (the gap):** before this change, an absence scenario pointed at a real Telegram/Slack channel returned `BLOCKED — driver does not support collectMessages`; the proof could only be exercised against the fake driver in `rate-limit-false-positive-prevention.test.ts`.
31
+ - **Before → after (the false-PASS holes, found in review):** a naive `collectMessages` that returned a single 100-entry page, kept last-write-wins text, matched Slack by user id only, and ignored failed reads would PASS an absence scenario even when a spurious message existed (on a paginated read, an edited message, a `bot_id` post, or a failed read). After: each of those four paths now produces BLOCKED, proven by dedicated tests (`Telegram: a FULL page … → AbsenceUnverifiableError`, `Telegram: … marker IN-PAGE does NOT block`, `Slack: ok:false → AbsenceUnverifiableError`, `Slack: next_cursor → AbsenceUnverifiableError`, `Slack: bot_id … IS collected`, `harness: a SAFE absence scenario on a NON-demo channel is refused`).
32
+ - **Verified:** 22 unit tests across the collect path (both sides of every guard boundary), no regression across the existing harness/sender/gate suites, clean typecheck. Multi-angle spec review (6 internal lenses + 2 non-Claude models, 3 rounds) converged with zero material findings.
@@ -0,0 +1,113 @@
1
+ # Side-Effects Review — Fix false rate-limit/error recovery on finished sessions + user-channel proof harness
2
+
3
+ **Version / slug:** `false-ratelimit-recovery-completed-sessions`
4
+ **Date:** `2026-06-24`
5
+ **Author:** Echo (autonomous, 8-hour run)
6
+ **Spec:** `docs/specs/false-ratelimit-recovery-completed-sessions.md` (review-convergence + approved)
7
+ **Second-pass reviewer:** REQUIRED (touches "sentinel"/"guard"/session-recovery) — verdict appended below.
8
+
9
+ ## Summary of the change
10
+
11
+ A finished/idle session sitting at a prompt with a stale throttle string in its
12
+ scrollback was mistaken for a live-but-throttled session, so `RateLimitSentinel` (and
13
+ its sibling `CompactionSentinel`) ran a futile recovery and spammed the user with
14
+ `RATE_LIMIT_RESUME_NUDGE` ("the temporary server throttle should have cleared…").
15
+ Fleet-wide (shared detector). Fix makes a terminal session structurally incapable of
16
+ being a recovery target, and adds a reusable test capability that catches spurious
17
+ background messages before deploy.
18
+
19
+ Files modified:
20
+ - `src/monitoring/RateLimitSentinel.ts` — new optional `isSessionRecoverable?` dep,
21
+ consulted in `report()` (no-op + no notice for a non-recoverable session),
22
+ `attemptResume()` and `verify()` (silent `abort()` if the session finished mid-flight
23
+ — new `rate-limit:aborted` event; `abort()` keeps the `recentReports` dedupe entry as
24
+ a flap cooldown).
25
+ - `src/monitoring/CompactionSentinel.ts` — the SAME `isSessionRecoverable?` guard in
26
+ `report()`.
27
+ - `src/commands/server.ts` — defines `isSessionRecoverable = (name) =>
28
+ sessionManager.listRunningSessions().some(...)`; passes it to BOTH sentinels; adds a
29
+ `sessionComplete` handler that clears both sentinels (the completion cleanup that had
30
+ zero callers).
31
+ - `src/monitoring/QuotaCollector.ts` — the OAuth-429 `DegradationReport` now fires only
32
+ when the 3-strike breaker trips (kills the `retry-after:0` log spam); the error is
33
+ still recorded in `errors[]`, breaker + quota accounting unchanged.
34
+ - `src/core/LiveTestHarness.ts` — the prevention layer: an optional
35
+ `ChannelDriver.collectMessages` + a scenario `absenceWindowMs` + `expect.noMessageMatching`
36
+ / `expect.replyMustNotContain`. An absence scenario collects every channel message over
37
+ the window and FAILs if any matches; an unsupported driver yields BLOCKED (never a
38
+ silent pass).
39
+
40
+ Files added:
41
+ - `src/core/rateLimitFalsePositiveMatrix.ts` — the rate-limit user-role scenario matrix
42
+ (happy-path reply + absence regression, optional Slack parity).
43
+ - `tests/unit/RateLimitSentinel-recoverable-guard.test.ts`,
44
+ `tests/unit/CompactionSentinel-recoverable-guard.test.ts`,
45
+ `tests/unit/rate-limit-false-positive-matrix.test.ts`,
46
+ `tests/unit/sentinel-recoverable-wiring.test.ts`,
47
+ `tests/integration/rate-limit-false-positive-prevention.test.ts`.
48
+ - Spec + ELI16 + convergence report.
49
+
50
+ ## Decision-point inventory
51
+
52
+ - **Added** `isSessionRecoverable` guard — a bounded NO-OP that SUPPRESSES a recovery
53
+ action; it never adds an authoritative block over a user. Signal-vs-authority: it
54
+ removes a spurious action, the safe direction.
55
+ - **Added** harness absence assertion → a PASS/FAIL SIGNAL the already-dark, dry-run-
56
+ default `LiveTestGate` consumes. BLOCKED (not silent-pass) when unverifiable. No new
57
+ blocking authority.
58
+ - **Modified** `QuotaCollector` 429 path — a LOG-LEVEL decision only (report vs not);
59
+ accounting + breaker untouched.
60
+
61
+ ## Side effects & blast radius
62
+
63
+ - **Behavior change (intended):** a finished/killed session no longer receives recovery
64
+ nudges; a recovery whose session ends mid-flight aborts silently (no escalation ping).
65
+ - **Preserved:** a genuinely-throttled RUNNING session still recovers — the notify
66
+ templates are byte-for-byte unchanged; dep-absent installs (bare/test) behave exactly
67
+ as before (regression-locked by tests).
68
+ - **Fail direction:** `listRunningSessions()` fails OPEN on a transient tmux error, so a
69
+ hiccup cannot drop a live session and suppress a real recovery; only genuine
70
+ termination removes it.
71
+ - **Machine-local:** each machine runs its own sentinels over its own running set; no
72
+ cross-machine state introduced. The QuotaCollector poll is already per-machine.
73
+ - **Residual (scoped to CMT-1785):** a still-RUNNING idle session with stale throttle
74
+ scrollback can still trigger one self-correcting "back online" message (not the
75
+ 6-nudge spam). The known fix (adopt the watchdog `evaluateThrottleSettle` settle-gate
76
+ on the idle path) is tracked, driven evidence-first by the new absence harness.
77
+
78
+ ## Migration parity
79
+
80
+ None required. All changes are server-internal wiring + a log-level change — no
81
+ `.claude/settings.json` hook, `.instar/config.json` default, CLAUDE.md template, or
82
+ built-in-skill change ships. Existing agents pick this up on the normal code-update path.
83
+
84
+ ## Rollback
85
+
86
+ Each fix is independently revertible: F1 is additive (dep-absent = old behavior); F2 is
87
+ a pure cleanup addition; F4 is log-level only; the harness extension is additive (the
88
+ absence path only runs when a scenario sets `absenceWindowMs`).
89
+
90
+ ## Tests
91
+
92
+ 16 unit (guards both-sides + verify/abort lifecycle + harness absence + matrix + wiring-
93
+ integrity) + 2 integration (harness → signed artifact → `LiveTestGate` ALLOW on clean /
94
+ VETO on a reintroduced regression). No regression across the existing sentinel (96),
95
+ quota (53), and harness/gate (30) suites; clean `tsc`.
96
+
97
+ ---
98
+
99
+ ## Second-pass review
100
+
101
+ **Concur with the review.** Independent audit of the diff verified: the
102
+ `isSessionRecoverable` guard uses running-set membership (the correct criterion) and
103
+ genuinely fails OPEN via `isSessionAlive`'s catch-returns-true path, so no genuine
104
+ recovery is suppressed by a transient tmux error — only actual termination removes a
105
+ session. The `verify()`/`attemptResume()` abort returns BEFORE any user-facing
106
+ `notify()` (no escalation/"still throttled" ping for a finished session); `abort()`
107
+ correctly keeps `recentReports` as the flap cooldown. The `sessionComplete` cleanup is
108
+ best-effort try/catch and cannot break completion. The QuotaCollector change preserves
109
+ the 429 signal in `errors[]` + the breaker, suppressing only transient per-poll log
110
+ spam (no other consumer keys on that feature). The notify templates are byte-for-byte
111
+ unchanged (a genuinely-throttled RUNNING session recovers as before). The harness
112
+ returns BLOCKED (never a silent pass) when absence is unverifiable. All 322 relevant
113
+ tests green. — independent second-pass reviewer, 2026-06-24.
@@ -0,0 +1,73 @@
1
+ # Side-Effects Review — Real-channel collectMessages (absence proof over a live channel)
2
+
3
+ **Version / slug:** `real-channel-absence-collect`
4
+ **Date:** `2026-06-24`
5
+ **Author:** Echo (autonomous, 8-hour run)
6
+ **Spec:** `docs/specs/real-channel-absence-collect.md` (review-convergence + approved)
7
+ **Second-pass reviewer:** REQUIRED (touches the LiveTestHarness verdict path) — verdict appended below.
8
+
9
+ ## Summary of the change
10
+
11
+ The `LiveTestHarness` absence assertion (PR #1262) could only run against a fake driver,
12
+ because the production `RealChannelDriver` had no `collectMessages`. This adds it, so the
13
+ "no spurious background message" proof runs over a REAL Telegram/Slack channel. The whole
14
+ risk of an absence proof is a silent **false PASS** (reporting "no spurious message" over
15
+ an incomplete read), so every under-collection path is forced to BLOCK, never PASS.
16
+
17
+ Files modified:
18
+ - `src/core/LiveTestHarness.ts` — new `AbsenceUnverifiableError` (a sender's
19
+ read-incompleteness signal) + the absence-path catch now maps BOTH it and
20
+ `DriverCapabilityError` to **BLOCKED**; a plain `Error` stays a FAIL. The §5.3
21
+ pre-flight now treats any `absenceWindowMs != null` scenario as demo-only regardless of
22
+ its `safe` tag (a whole-history read must never touch a live channel).
23
+ - `src/core/RealChannelDriver.ts` — new `collectMessages(surface, channelId, opts)`
24
+ delegating to the surface sender; raises `DriverCapabilityError` for a surface whose
25
+ sender has no collector; new optional `SurfaceSender.collectMessages`.
26
+ - `src/core/TelegramLiveSender.ts` — `collectMessages`: polls `getHistory` across the
27
+ window, keeps ALL text versions per messageId (anti edit-laundering), skips non-finite
28
+ ids, clamps the window to 300s, and BLOCKS (AbsenceUnverifiableError) on a
29
+ marker-bounded full-page truncation (full page whose oldest entry is still after the
30
+ marker — so a reused demo topic is not wrongly blocked).
31
+ - `src/core/SlackLiveSender.ts` — `collectMessages` (mirror): `oldest`-bounded read,
32
+ BLOCKS on `ok:false` (failed read) or `next_cursor`/full-page (truncation); new
33
+ `isAgentAuthored` helper matches `user` OR an injected `agentBotId` (a background nudge
34
+ may carry only `bot_id`) — applied to `collectMessages` AND `awaitReply` for parity;
35
+ optional `agentBotId` dep.
36
+
37
+ Files added:
38
+ - `tests/unit/realchannel-collect-messages.test.ts` — 22 unit tests: collect semantics,
39
+ late-nudge polling, anti-laundering, truncation→BLOCK (marker-bounded), reused-topic
40
+ no-mis-fire, Slack bot_id / ok:false / next_cursor, §5.3 absence-demo guard, and the
41
+ end-to-end harness PASS/FAIL/BLOCKED over a RealChannelDriver.
42
+ - `docs/specs/real-channel-absence-collect.md` (+ `.eli16.md`, convergence report).
43
+
44
+ ## Blast radius
45
+
46
+ - **Production runtime:** none. `collectMessages` is reachable ONLY via
47
+ `LiveTestHarness.run` → `RealChannelDriver`, constructed per-request in the live-test
48
+ route and the `instar dev` runner. No sentinel, gate, scheduler, or request path calls
49
+ it (verified by the scalability + integration reviewers).
50
+ - **Existing callers:** unchanged. `RealChannelDriver`'s constructor signature is
51
+ untouched; `collectMessages` is a new instance method. The harness's `!driver.collectMessages`
52
+ BLOCKED path still fires for FAKE drivers (RealChannelDriver now routes per-surface
53
+ "unsupported" through the typed error instead). `awaitReply`'s new `bot_id` matching is
54
+ additive — unset `agentBotId` → byte-identical prior behavior (existing tests green).
55
+ - **Multi-machine:** machine-local-by-design — a live channel read happens on the serving
56
+ machine against that channel's live history; no replicated/proxied state.
57
+
58
+ ## Rollback
59
+
60
+ Fully additive and revertible: drop the three `collectMessages` method bodies, the
61
+ `AbsenceUnverifiableError` class + its catch clause, the §5.3 `absenceWindowMs` predicate,
62
+ and the `agentBotId` dep. No config defaults, hooks, CLAUDE.md template, migration, or
63
+ dashboard surface touched, so no Migration Parity obligation. Reverting the commit is
64
+ sufficient; nothing ships dark or irreversible.
65
+
66
+ ## Second-pass reviewer verdict
67
+
68
+ Multi-angle spec-converge (6 internal lenses + codex-cli:gpt-5.5 + gemini-2.5-pro across
69
+ 3 rounds) converged with zero material findings in the final round. Round 1 surfaced 5
70
+ material false-PASS holes (truncation, edit-laundering, Slack `bot_id`, Slack `ok:false`,
71
+ §5.3 safe-bypass) — all fixed + tested. Round 2 surfaced 1 material (Telegram full-page
72
+ guard mis-firing on a reused demo topic) — fixed marker-bounded + tested. Round 3
73
+ verified resolution. Standards-Conformance Gate: 0 flags all rounds. Verdict: APPROVED.