instar 1.3.456 → 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.
Files changed (38) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +42 -1
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  5. package/dist/core/PostUpdateMigrator.js +16 -0
  6. package/dist/core/PostUpdateMigrator.js.map +1 -1
  7. package/dist/core/ProactiveSwapMonitor.d.ts +149 -0
  8. package/dist/core/ProactiveSwapMonitor.d.ts.map +1 -0
  9. package/dist/core/ProactiveSwapMonitor.js +208 -0
  10. package/dist/core/ProactiveSwapMonitor.js.map +1 -0
  11. package/dist/core/devGatedFeatures.d.ts +41 -0
  12. package/dist/core/devGatedFeatures.d.ts.map +1 -0
  13. package/dist/core/devGatedFeatures.js +76 -0
  14. package/dist/core/devGatedFeatures.js.map +1 -0
  15. package/dist/core/types.d.ts +27 -0
  16. package/dist/core/types.d.ts.map +1 -1
  17. package/dist/core/types.js.map +1 -1
  18. package/dist/scaffold/templates.d.ts.map +1 -1
  19. package/dist/scaffold/templates.js +1 -0
  20. package/dist/scaffold/templates.js.map +1 -1
  21. package/dist/server/AgentServer.d.ts +1 -0
  22. package/dist/server/AgentServer.d.ts.map +1 -1
  23. package/dist/server/AgentServer.js +1 -0
  24. package/dist/server/AgentServer.js.map +1 -1
  25. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  26. package/dist/server/CapabilityIndex.js +4 -1
  27. package/dist/server/CapabilityIndex.js.map +1 -1
  28. package/dist/server/routes.d.ts +3 -0
  29. package/dist/server/routes.d.ts.map +1 -1
  30. package/dist/server/routes.js +27 -0
  31. package/dist/server/routes.js.map +1 -1
  32. package/package.json +1 -1
  33. package/src/data/builtin-manifest.json +64 -64
  34. package/src/scaffold/templates.ts +1 -0
  35. package/upgrades/1.3.457.md +45 -0
  36. package/upgrades/1.3.458.md +62 -0
  37. package/upgrades/side-effects/dev-gated-features-registry.md +70 -0
  38. package/upgrades/side-effects/proactive-prelimit-swap.md +64 -0
@@ -0,0 +1,62 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: minor -->
5
+
6
+ ## What Changed
7
+
8
+ Adds the **proactive pre-limit swap** — the missing half of the Subscription &
9
+ Auth Standard's continuity guarantee. A new `ProactiveSwapMonitor` moves a session
10
+ OFF an account BEFORE it walls, at a lag-aware measured threshold (`thresholdPct`,
11
+ default 80 — below the real limit because the polled reading trails real usage).
12
+ Critically, it covers the session you actually use: an UNTAGGED session (the
13
+ primary interactive session running on the default login) is resolved to its real
14
+ account via `InUseAccountResolver`, so it is moved pre-emptively instead of wedging
15
+ at the wall. Bounded by a per-cycle cap, per-session cooldown, an
16
+ alternate-must-be-below-threshold anti-thrash guard, and a near-the-wall poll
17
+ refresh. Two routes: `GET /subscription-pool/proactive-swap` (status) and
18
+ `POST /subscription-pool/proactive-swap/check` (run one pass on demand). Gated
19
+ OFF by default behind `subscriptionPool.proactiveSwap.enabled` (moving live
20
+ sessions is real authority — same authority as the reactive `autoSwapOnRateLimit`,
21
+ just an earlier trigger). Disabled → strict no-op; the routes answer
22
+ `200 { enabled:false }`.
23
+
24
+ ## What to Tell Your User
25
+
26
+ Your accounts now swap *before* one runs out, not just after. Before, the agent
27
+ would ride an account all the way to its limit and then either blip onto a fresh
28
+ account — or, if it was the main session you chat with, get stuck until you
29
+ manually switched accounts. Now, when an account crosses ~80% of its limit, I move
30
+ the session to one with room to spare while preserving the conversation, with
31
+ margin to spare (your real usage runs a few points ahead of what I can poll). It's
32
+ off by default; just tell me to turn on proactive swapping and I'll enable it, and
33
+ you can ask me to run a check on demand to watch it work.
34
+
35
+ ## Summary of New Capabilities
36
+
37
+ | Capability | How to Use |
38
+ |-----------|-----------|
39
+ | Proactive pre-limit swap (before the wall) | set `subscriptionPool.proactiveSwap.enabled: true` (restart to apply) |
40
+ | Tune the trigger | `subscriptionPool.proactiveSwap.thresholdPct` (default 80), `maxSwapsPerCycle`, `cooldownMs`, `tickMs`, `watchMarginPct` |
41
+ | See status | `GET /subscription-pool/proactive-swap` |
42
+ | Run one pass now | `POST /subscription-pool/proactive-swap/check` |
43
+
44
+ ## Evidence
45
+
46
+ Reproduction (live, 2026-06-09): the operator's interactive session was running
47
+ on the default login (pointed at SageMind - Adriana). Adriana's 5-hour window
48
+ filled; the session wedged. The reactive auto-swap could not rescue it — it only
49
+ fires after a rate-limit escalation, AND the session carried no
50
+ `subscriptionAccountId` (the main interactive session is untagged), so the swap
51
+ engine had nothing to move. The operator had to swap the default login manually to
52
+ unblock it.
53
+
54
+ After the fix: the monitor resolves the untagged session's effective account from
55
+ the default login and pre-emptively swaps it at the measured threshold. The e2e
56
+ test (`subscription-proactive-swap-lifecycle.test.ts`) drives exactly this case
57
+ end-to-end over HTTP — an untagged session on an at-pressure default login is
58
+ swapped before the wall, conversation preserved. The unit suite asserts both sides
59
+ of every boundary (at-pressure vs. below, tagged vs. untagged-via-default,
60
+ alternate-exists vs. anti-thrash, cap, cooldown, recency ordering, watch-zone poll
61
+ refresh). tsc + lint clean; sibling subscription/quota suites and all 358
62
+ PostUpdateMigrator tests green.
@@ -0,0 +1,70 @@
1
+ # Side-Effects Review — Dev-Gated-Feature Registry + Both-Sides Wiring Test (Slice 2)
2
+
3
+ **Change:** Slice 2 of DEV-AGENT-DARK-GATE-CONFORMANCE-SPEC (the converged +
4
+ operator-approved spec). Adds the layer that catches a dev-gated feature wired to
5
+ resolve **dark on a dev agent** — the gap Slice 1's lint cannot see.
6
+
7
+ - `src/core/devGatedFeatures.ts` (new) — `DEV_GATED_FEATURES` registry (name +
8
+ config path + description) and a `getConfigByPath` reader.
9
+ - `tests/unit/devGatedFeatures-wiring.test.ts` (new) — for each registered
10
+ feature, applies the REAL `getMigrationDefaults` and asserts
11
+ `resolveDevAgentGate(<configPath>)` is **true** under a `developmentAgent: true`
12
+ config and **false** under a fleet config, plus a "teeth" test confirming an
13
+ injected `enabled: false` default fails the live-on-dev assertion (the literal
14
+ #1001 mechanism).
15
+
16
+ **Registry membership (the design decision in this slice):** only features whose
17
+ intent is "dark fleet / LIVE on dev" are included (growthAnalyst, coherenceJournal,
18
+ warmSessionA2A, secretSync, geminiLoopDriver, respawnBuildContext,
19
+ selfKnowledgeSessionContext — verified to omit `enabled` in defaults). Deliberately
20
+ EXCLUDED, with reasons in code: `monitoring.mcpProcessReaper` (destructive — ships
21
+ OFF + dry-run for everyone incl. dev by design) and `monitoring.resourceLedger`
22
+ (ledger defaults `enabled: true`; only sampling rides the gate off the same key).
23
+
24
+ ## 1. Over-block — what legitimate inputs does this reject that it shouldn't?
25
+ The test asserts every registered feature is live-on-dev / dark-on-fleet. A
26
+ feature that legitimately ships dark-everywhere or live-everywhere would fail if
27
+ wrongly added to the registry — but membership is a deliberate, reviewed choice
28
+ (the two non-conforming features are explicitly excluded with documented reasons),
29
+ so the test only constrains features that genuinely follow the convention.
30
+
31
+ ## 2. Under-block — what failure modes does this still miss?
32
+ Catches the hardcoded-default half of the #1001 shape (a `false` baked into the
33
+ feature's default → `applyDefaults` injects it → live-on-dev assertion fails) for
34
+ **registered** features. Still misses: (a) a dev-gated feature never added to the
35
+ registry; (b) the construction-side half where a site reads `enabled === true`
36
+ without any gate (no default to catch) — that is Slice 3's spec-intent cross-check.
37
+ Both limits are named in the spec's layer table.
38
+
39
+ ## 3. Level-of-abstraction fit — right layer?
40
+ Yes — a unit test over the real config-default assembly (`applyDefaults` +
41
+ `getMigrationDefaults`), the same path PostUpdateMigrator uses. It exercises the
42
+ actual default→gate resolution, not a source regex, so it catches the mechanism
43
+ rather than a spelling.
44
+
45
+ ## 4. Signal vs authority compliance
46
+ The test is CI authority (fails the build) over a deterministic, mechanical
47
+ property — same posture as the rest of the suite. The registry is inert data; it
48
+ holds no runtime authority (Slice 3 consumes it read-only).
49
+
50
+ ## 5. Interactions — shadowing, double-fire, races?
51
+ None. `devGatedFeatures.ts` is pure data + a pure path reader; the test builds
52
+ throwaway config objects. No shared state, no runtime wiring in this slice.
53
+
54
+ ## 6. External surfaces — visible to other agents/users/systems?
55
+ None. No routes, no config, no agent-installed files. Repo-internal source + test.
56
+ No Migration Parity entry needed.
57
+
58
+ ## 7. Rollback cost — back-out if wrong?
59
+ Trivial — delete the two files. No runtime behavior, no state, no deployed artifact.
60
+
61
+ ## No deferrals
62
+ Slice 3 (spec-intent cross-check) is the next slice of the same approved spec,
63
+ tracked under CMT-1253 — not a deferral of this slice's scope. <!-- tracked: CMT-1253 -->
64
+
65
+ ## Second-pass review (independent)
66
+ The registry membership was derived by auditing each `resolveDevAgentGate` site's
67
+ default against the convention: the 7 included features verified to omit `enabled`
68
+ (test green on all = no hidden hardcoded default); the 2 excluded features
69
+ (mcpProcessReaper, resourceLedger) inspected and confirmed intentionally NOT
70
+ dark-on-fleet. The teeth test confirms the guard fires on a planted regression.
@@ -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.