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.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +42 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +16 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/ProactiveSwapMonitor.d.ts +149 -0
- package/dist/core/ProactiveSwapMonitor.d.ts.map +1 -0
- package/dist/core/ProactiveSwapMonitor.js +208 -0
- package/dist/core/ProactiveSwapMonitor.js.map +1 -0
- package/dist/core/devGatedFeatures.d.ts +41 -0
- package/dist/core/devGatedFeatures.d.ts.map +1 -0
- package/dist/core/devGatedFeatures.js +76 -0
- package/dist/core/devGatedFeatures.js.map +1 -0
- package/dist/core/types.d.ts +27 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +1 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +1 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +4 -1
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +27 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.457.md +45 -0
- package/upgrades/1.3.458.md +62 -0
- package/upgrades/side-effects/dev-gated-features-registry.md +70 -0
- 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.
|