instar 1.3.457 → 1.3.458

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.
@@ -0,0 +1,64 @@
1
+ # Side-effects review — Proactive pre-limit account swap
2
+
3
+ ## Blast radius when DISABLED (default)
4
+
5
+ Strict no-op. `subscriptionPool.proactiveSwap.enabled` defaults to absent/false →
6
+ the `ProactiveSwapMonitor` is never constructed, never started, never wired into
7
+ the AgentServer ctx. The two new routes answer `200 { enabled:false }` (never
8
+ 503). No new background loop, no polling, no session restarts. An agent that
9
+ doesn't set the flag behaves byte-for-byte as before.
10
+
11
+ ## Blast radius when ENABLED
12
+
13
+ - **It restarts live sessions.** A proactive swap drives the same
14
+ `SessionRefresh` account-swap path the reactive `autoSwapOnRateLimit` already
15
+ uses (kill → respawn with `--resume`, conversation preserved via the topic's
16
+ resume UUID). Same authority and same disruption profile as the already-shipped
17
+ reactive swap — only the trigger is earlier (a measured threshold vs. an actual
18
+ rate-limit escalation). This is why it is opt-in.
19
+ - **It can move UNTAGGED sessions.** An untagged session's effective account is
20
+ resolved from the default-config login via `InUseAccountResolver` (cached
21
+ `claude auth status`). A wrong/blank resolution degrades to "no default
22
+ account" → that session is simply not a candidate (fail-safe, never a wrong
23
+ swap). After a swap the session becomes tagged with its new account.
24
+
25
+ ## Bounding / anti-footgun
26
+
27
+ - `maxSwapsPerCycle` (default 3) caps restarts per pass; per-session `cooldownMs`
28
+ (default 10m) prevents double-swapping a session whose restart is still
29
+ settling; an alternate-must-be-below-threshold guard prevents moving onto a
30
+ nearly-full login (anti-thrash). Near the wall the monitor refreshes the poll
31
+ before deciding so a fast burn isn't missed.
32
+ - Complements (never conflicts with) the reactive swap: once proactive moves a
33
+ session off a hot login, the reactive escalation for that login can't fire for
34
+ it. Both can be enabled together.
35
+
36
+ ## Interactions
37
+
38
+ - Reads `state.listSessions({status:'running'})`, `subscriptionPool.list()`,
39
+ `inUseAccountResolver.resolve()`, and calls `quotaPoller.pollAll()` +
40
+ `quotaAwareScheduler.onQuotaPressure()` — all existing surfaces, no schema
41
+ changes. Adds `subscriptionAccountId`-keyed logic but writes no new state.
42
+ - CapabilityIndex gains two endpoints + a `proactiveSwap` flag; the subscription
43
+ capability description is extended. No prefix added (rides `/subscription-pool`).
44
+
45
+ ## Migration parity
46
+
47
+ New `subscriptionPool.proactiveSwap` config is purely additive (absence = off →
48
+ no `migrateConfig` needed). CLAUDE.md awareness ships in the template AND via a
49
+ dedicated idempotent `migrateClaudeMd` patch for existing agents (the
50
+ section-install guard skips agents that already have the section).
51
+
52
+ ## Framework generality
53
+
54
+ Does not touch the framework launch/inject abstraction. The pool is
55
+ Claude-subscription-specific by nature (claude-code accounts); the monitor only
56
+ considers `framework === 'claude-code'` (or legacy undefined) sessions, so
57
+ codex-cli / gemini-cli / pi-cli sessions are correctly ignored.
58
+
59
+ ## Tests
60
+
61
+ Unit (16) — both sides of every boundary incl. the untagged→default-login
62
+ resolution; integration (6) — full HTTP for both routes incl. dark 200s; e2e (2)
63
+ — feature-alive in dark + live. Sibling subscription/quota suites + all 358
64
+ PostUpdateMigrator tests stay green.