instar 1.3.543 → 1.3.545

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 (39) hide show
  1. package/dist/commands/server.js +3 -3
  2. package/dist/commands/server.js.map +1 -1
  3. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  4. package/dist/config/ConfigDefaults.js +9 -5
  5. package/dist/config/ConfigDefaults.js.map +1 -1
  6. package/dist/core/CredentialRebalancer.d.ts +116 -0
  7. package/dist/core/CredentialRebalancer.d.ts.map +1 -0
  8. package/dist/core/CredentialRebalancer.js +159 -0
  9. package/dist/core/CredentialRebalancer.js.map +1 -0
  10. package/dist/core/CredentialRebalancerPolicy.d.ts +137 -0
  11. package/dist/core/CredentialRebalancerPolicy.d.ts.map +1 -0
  12. package/dist/core/CredentialRebalancerPolicy.js +284 -0
  13. package/dist/core/CredentialRebalancerPolicy.js.map +1 -0
  14. package/dist/core/CredentialRebalancerSnapshot.d.ts +66 -0
  15. package/dist/core/CredentialRebalancerSnapshot.d.ts.map +1 -0
  16. package/dist/core/CredentialRebalancerSnapshot.js +111 -0
  17. package/dist/core/CredentialRebalancerSnapshot.js.map +1 -0
  18. package/dist/core/PostUpdateMigrator.d.ts +12 -0
  19. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  20. package/dist/core/PostUpdateMigrator.js +49 -1
  21. package/dist/core/PostUpdateMigrator.js.map +1 -1
  22. package/dist/core/devGatedFeatures.d.ts.map +1 -1
  23. package/dist/core/devGatedFeatures.js +10 -5
  24. package/dist/core/devGatedFeatures.js.map +1 -1
  25. package/dist/scaffold/templates.js +1 -1
  26. package/dist/server/CapabilityIndex.js +1 -1
  27. package/dist/server/CapabilityIndex.js.map +1 -1
  28. package/dist/server/routes.js +2 -2
  29. package/dist/server/routes.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/data/builtin-manifest.json +63 -63
  32. package/src/scaffold/templates.ts +1 -1
  33. package/upgrades/1.3.544.md +27 -0
  34. package/upgrades/1.3.545.md +68 -0
  35. package/upgrades/side-effects/ws52-incb-b1-rebalancer-policy.md +44 -0
  36. package/upgrades/side-effects/ws52-incb-b2-default-eviction.md +42 -0
  37. package/upgrades/side-effects/ws52-incb-b3a-rebalancer-orchestrator.md +44 -0
  38. package/upgrades/side-effects/ws52-incb-b3b-snapshot-mappers.md +37 -0
  39. package/upgrades/side-effects/ws52-regate-dev-live.md +42 -0
@@ -0,0 +1,284 @@
1
+ /**
2
+ * CredentialRebalancerPolicy — the §2.4 "stock-trader loop" decision core, as a PURE
3
+ * function (Increment B, step B1 of live credential re-pointing).
4
+ *
5
+ * Spec: docs/specs/live-credential-repointing-rebalancer.md §2.4 (the balancer).
6
+ *
7
+ * ── What this is ──
8
+ * Given a read-only snapshot of a pass (per-account quota + reset proximity, per-slot
9
+ * tenancy/verify/activity, cooldown state, resolved+clamped config), this computes the
10
+ * ZERO-OR-MORE swap decisions for ONE pass. It performs NO IO and holds NO authority:
11
+ * it DECIDES; a separate actuator (step B3) routes an accepted decision through the
12
+ * Step-5 CredentialSwapExecutor under the dark/dry-run gate. Splitting the decision out
13
+ * makes the entire policy — every threshold, cap, cooldown, and eligibility rule —
14
+ * exhaustively unit-testable without a keychain (Tier-0 supervision, §2.4: a
15
+ * deterministic policy over enumerable numeric thresholds).
16
+ *
17
+ * ── Priority of objectives (§2.4) ──
18
+ * 1. Wall avoidance — a tenant over the high-water mark gets the highest-headroom
19
+ * eligible account. A tenant over the CRITICAL mark triggers a wall-OVERRIDE that
20
+ * bypasses the cooldowns + the 1-swap/pass cap, bounded by its own caps
21
+ * (fresh-data gate, maxForcedSwapsPerPass, maxForcedOverridesPerWindow).
22
+ * 2. Use-it-or-lose-it drain — an account whose WEEKLY window resets soon with unused
23
+ * headroom is dealt to the busiest slot (weekly only; 5h windows regenerate).
24
+ * 3. Default-slot preference — keep the designated default account in `~/.claude`.
25
+ *
26
+ * Non-forced objectives are bounded to ONE swap per pass (acting twice on one sensor
27
+ * reading is noise). Only the wall-override may emit up to `maxForcedSwapsPerPass`.
28
+ *
29
+ * Dead-default eviction, the correlated-oracle-outage floor, quarantine-exit, the P19
30
+ * breaker, and the scheduled identity audit are step B2 (this module decides swaps; B2
31
+ * adds the degraded-state machinery). This module surfaces the terminal "nothing to do"
32
+ * / "no eligible target" states so B2/B3 can act on them.
33
+ */
34
+ function sortedPair(a, b) {
35
+ return a < b ? `${a}|${b}` : `${b}|${a}`;
36
+ }
37
+ /** Max utilization across the two windows (the wall is whichever is closer). */
38
+ function maxUtil(acc) {
39
+ return Math.max(acc.fiveHrPct ?? 0, acc.weeklyPct ?? 0);
40
+ }
41
+ /** A slot whose verify is recent AND not divergent is a valid swap-in target (§2.4 recency gate). */
42
+ function targetVerifiedRecent(slot, now, auditCadenceMs) {
43
+ return (!slot.quarantined &&
44
+ !slot.lastAuditDivergent &&
45
+ slot.lastVerifiedAt !== null &&
46
+ now - slot.lastVerifiedAt <= auditCadenceMs);
47
+ }
48
+ /**
49
+ * Decide the swap(s) for one pass. Pure: same input → same output, no IO.
50
+ * A pass with no actuation returns `decisions: []` + a `noActuationReason` (the caller
51
+ * audits the no-op pass and performs ZERO keychain/CLI operations — the §2.4 invariant).
52
+ */
53
+ export function decidePass(input) {
54
+ const { now, slots, accounts, cooldowns, config, auditCadenceMs } = input;
55
+ const degraded = [];
56
+ const attention = [];
57
+ const accById = new Map(accounts.map((a) => [a.accountId, a]));
58
+ // Eligibility (§2.4): a tenant that is needs-reauth/disabled never participates; a
59
+ // quarantined/unverified slot never participates; a slot with no tenant can't move.
60
+ const participatingSlots = slots.filter((s) => {
61
+ if (s.tenantAccountId === null)
62
+ return false;
63
+ const acc = accById.get(s.tenantAccountId);
64
+ if (!acc)
65
+ return false;
66
+ return acc.status === 'ok';
67
+ });
68
+ // A slot is a valid swap-in TARGET only if its quota is fresh (stale headroom may mask a
69
+ // wall — the anti-conservative direction → SOURCE-only) AND its identity verify is recent.
70
+ const isFreshQuota = (acc) => now - acc.measuredAt <= config.staleQuotaMs;
71
+ // ── Objective 0: dead/quarantined-default eviction (the slot that must never be empty) ──
72
+ // Keep `~/.claude` serving a HEALTHY VERIFIED tenant so manual `claude` keeps working
73
+ // (goal 3 beats slot symmetry + the quarantine-exclusion rule, but ONLY for the default
74
+ // slot). Runs FIRST: a frozen default freezes the operator's manual invocations.
75
+ if (input.desiredDefaultAccountId) {
76
+ const defaultSlot = slots.find((s) => s.isDefault);
77
+ if (defaultSlot) {
78
+ const defTenant = defaultSlot.tenantAccountId ? accById.get(defaultSlot.tenantAccountId) : undefined;
79
+ const defaultDead = defaultSlot.quarantined ||
80
+ !defTenant ||
81
+ defTenant.status === 'needs-reauth' ||
82
+ defTenant.status === 'disabled';
83
+ if (defaultDead) {
84
+ // A healthy VERIFIED tenant to deal in (identity-verified THIS pass before the move —
85
+ // a "healthy per stale ledger" target that is actually dead would re-quarantine the
86
+ // default; the recency gate is that pre-check in the pure policy).
87
+ const healthy = slots
88
+ .filter((s) => s.slot !== defaultSlot.slot && !s.quarantined && s.tenantAccountId !== null)
89
+ .filter((s) => {
90
+ const a = accById.get(s.tenantAccountId);
91
+ return a?.status === 'ok' && targetVerifiedRecent(s, now, auditCadenceMs);
92
+ })
93
+ .sort((a, b) => maxUtil(accById.get(a.tenantAccountId)) - maxUtil(accById.get(b.tenantAccountId)))[0];
94
+ if (healthy) {
95
+ return {
96
+ decisions: [{
97
+ targetSlot: defaultSlot.slot,
98
+ sourceSlot: healthy.slot,
99
+ objective: 'default-eviction',
100
+ forced: 'default-eviction',
101
+ reason: `default slot ${defaultSlot.slot} is ${defaultSlot.quarantined ? 'quarantined' : 'dead (' + (defTenant?.status ?? 'no-tenant') + ')'}; dealing healthy verified ${healthy.tenantAccountId} in to keep manual claude working`,
102
+ }],
103
+ degraded: [],
104
+ attention: [`default slot ${defaultSlot.slot} was ${defaultSlot.quarantined ? 'quarantined' : 'dead'} — rescued with ${healthy.tenantAccountId}; the displaced credential is parked and needs re-auth/re-probe`],
105
+ };
106
+ }
107
+ // Correlated-oracle-outage floor: NO slot is currently oracle-verifiable (an
108
+ // identity-oracle endpoint storm quarantines every probe at once). Do NOT empty/churn the
109
+ // default — preserve its last-known-good assignment + surface; honest bound: this is
110
+ // "preserve last KNOWN-GOOD + flag", NOT "manual claude is certified working".
111
+ const anyVerifiable = slots.some((s) => targetVerifiedRecent(s, now, auditCadenceMs));
112
+ if (!anyVerifiable) {
113
+ return {
114
+ decisions: [],
115
+ degraded: ['no slot is oracle-verifiable — default-slot eviction suspended (correlated-outage floor)'],
116
+ attention: [`oracle unavailable for every slot; ${defaultSlot.slot} preserved at its last-known-good${defaultSlot.lastKnownGoodAccountId ? ' (' + defaultSlot.lastKnownGoodAccountId + ')' : ''} — NOT certified live; no eviction until the oracle returns`],
117
+ noActuationReason: 'correlated oracle outage — default preserved at last-known-good, no eviction',
118
+ };
119
+ }
120
+ // Verifiable slots exist but none is an eligible healthy tenant: surface, do not act.
121
+ return {
122
+ decisions: [],
123
+ degraded: [],
124
+ attention: [`default slot ${defaultSlot.slot} is dead/quarantined and no healthy verified tenant is available to rescue it`],
125
+ noActuationReason: 'default slot dead but no eligible healthy tenant to deal in',
126
+ };
127
+ }
128
+ }
129
+ }
130
+ // ── Objective 1: wall avoidance ───────────────────────────────────────────────
131
+ // Slots whose tenant exceeds the high-water mark, worst-first.
132
+ const walling = participatingSlots
133
+ .map((s) => ({ slot: s, acc: accById.get(s.tenantAccountId), util: maxUtil(accById.get(s.tenantAccountId)) }))
134
+ .filter((x) => x.util >= config.highWaterPct)
135
+ .sort((a, b) => b.util - a.util);
136
+ // Eligible rescue targets: an account with the most headroom whose CURRENT slot is a
137
+ // verified-recent, fresh-quota, non-walling slot we can exchange with.
138
+ const rescueTargets = participatingSlots
139
+ .map((s) => ({ slot: s, acc: accById.get(s.tenantAccountId) }))
140
+ .filter((x) => maxUtil(x.acc) < config.highWaterPct && isFreshQuota(x.acc) && targetVerifiedRecent(x.slot, now, auditCadenceMs))
141
+ .sort((a, b) => maxUtil(a.acc) - maxUtil(b.acc)); // lowest utilization (most headroom) first
142
+ const decisions = [];
143
+ const actedSlots = new Set();
144
+ const actedTenants = new Set();
145
+ // Wall-override: critical-mark slots bypass cooldowns + the 1-swap cap, bounded by
146
+ // maxForcedSwapsPerPass + the fresh-data gate + maxForcedOverridesPerWindow.
147
+ const critical = walling.filter((x) => x.util >= config.criticalPct);
148
+ let overridesLeft = Math.max(0, cooldowns.maxForcedOverridesPerWindow - cooldowns.forcedOverridesInWindow);
149
+ let forcedThisPass = 0;
150
+ for (const w of critical) {
151
+ if (forcedThisPass >= config.maxForcedSwapsPerPass)
152
+ break;
153
+ if (overridesLeft <= 0) {
154
+ degraded.push('wall-override budget exhausted — no durable rescue available');
155
+ attention.push(`wall-override budget exhausted for slot ${w.slot.slot} — a thrashing tenant the rescue can't durably help`);
156
+ break;
157
+ }
158
+ // Fresh-data gate: act on a NEW critical reading only (the tenant's quota must be newer
159
+ // than its last actuation), so the override never re-fires on the same snapshot.
160
+ const lastAct = cooldowns.lastActuationByTenant[w.acc.accountId] ?? -Infinity;
161
+ if (w.acc.measuredAt <= lastAct)
162
+ continue;
163
+ const target = rescueTargets.find((t) => !actedSlots.has(t.slot.slot) && t.slot.slot !== w.slot.slot && !actedTenants.has(t.acc.accountId));
164
+ if (!target) {
165
+ attention.push(`no eligible non-walling rescue target for critical slot ${w.slot.slot}`);
166
+ continue;
167
+ }
168
+ decisions.push({
169
+ targetSlot: w.slot.slot,
170
+ sourceSlot: target.slot.slot,
171
+ objective: 'wall',
172
+ forced: 'wall-override',
173
+ reason: `critical wall ${w.util}%≥${config.criticalPct}% on ${w.acc.accountId}; rescued with ${target.acc.accountId} (${maxUtil(target.acc)}%) — cooldowns bypassed`,
174
+ });
175
+ actedSlots.add(w.slot.slot);
176
+ actedSlots.add(target.slot.slot);
177
+ actedTenants.add(w.acc.accountId);
178
+ actedTenants.add(target.acc.accountId);
179
+ forcedThisPass += 1;
180
+ overridesLeft -= 1;
181
+ }
182
+ // If a forced override already acted this pass, we are done (the override is the highest
183
+ // priority; non-forced objectives wait for the next pass to respect 1-swap hygiene).
184
+ if (decisions.length > 0) {
185
+ return { decisions, degraded, attention };
186
+ }
187
+ // Non-forced wall avoidance (85–95%): respects per-pair + per-tenant cooldowns, 1 swap/pass.
188
+ const cooldownOk = (_slotA, _slotB, accA, accB) => {
189
+ // The per-pair cooldown keys on the TENANT pair (the two accounts being exchanged),
190
+ // consistent with the per-tenant cooldown — "don't re-exchange these two tenants too
191
+ // soon" — NOT on the fixed slot seats.
192
+ const pairLast = cooldowns.lastActuationByPair[sortedPair(accA, accB)] ?? -Infinity;
193
+ if (now - pairLast < config.perPairCooldownMs)
194
+ return false;
195
+ const tA = cooldowns.lastActuationByTenant[accA] ?? -Infinity;
196
+ const tB = cooldowns.lastActuationByTenant[accB] ?? -Infinity;
197
+ if (now - tA < config.perTenantCooldownMs || now - tB < config.perTenantCooldownMs)
198
+ return false;
199
+ return true;
200
+ };
201
+ // Fresh-data gate for non-forced moves: both tenants' quota newer than their last actuation.
202
+ const freshDataOk = (accA, accB) => {
203
+ const lA = cooldowns.lastActuationByTenant[accA.accountId] ?? -Infinity;
204
+ const lB = cooldowns.lastActuationByTenant[accB.accountId] ?? -Infinity;
205
+ return accA.measuredAt > lA && accB.measuredAt > lB;
206
+ };
207
+ // The non-forced path handles ONLY the [highWater, critical) band. A critical (≥95%)
208
+ // slot is the override path's responsibility; if the override couldn't act (budget /
209
+ // fresh-data / no target) it was surfaced above and WAITS — it is never silently
210
+ // downgraded to a cooldown-respecting rescue in the same pass (that would re-churn the
211
+ // exact thrashing slot the override budget gave up on).
212
+ for (const w of walling.filter((x) => x.util < config.criticalPct)) {
213
+ const target = rescueTargets.find((t) => t.slot.slot !== w.slot.slot);
214
+ if (!target) {
215
+ attention.push(`no eligible non-walling rescue target for slot ${w.slot.slot}`);
216
+ break;
217
+ }
218
+ if (!cooldownOk(w.slot.slot, target.slot.slot, w.acc.accountId, target.acc.accountId))
219
+ continue;
220
+ if (!freshDataOk(w.acc, target.acc))
221
+ continue;
222
+ decisions.push({
223
+ targetSlot: w.slot.slot,
224
+ sourceSlot: target.slot.slot,
225
+ objective: 'wall',
226
+ forced: null,
227
+ reason: `wall ${w.util}%≥${config.highWaterPct}% on ${w.acc.accountId}; rescued with ${target.acc.accountId} (${maxUtil(target.acc)}%)`,
228
+ });
229
+ return { decisions, degraded, attention };
230
+ }
231
+ // ── Objective 2: use-it-or-lose-it drain ──────────────────────────────────────
232
+ // An account whose WEEKLY window resets within the horizon with ≥ headroom-min unused,
233
+ // dealt to the busiest eligible slot that is NOT itself a drain-in-progress destination.
234
+ const drainable = accounts
235
+ .filter((a) => a.status === 'ok' && a.weeklyResetsInHours !== null && a.weeklyResetsInHours <= config.drainHorizonHours)
236
+ .filter((a) => a.weeklyPct !== null && 100 - a.weeklyPct >= config.drainHeadroomMinPct)
237
+ .filter((a) => isFreshQuota(a))
238
+ .sort((a, b) => (a.weeklyResetsInHours - b.weeklyResetsInHours)); // most-reset-proximate first
239
+ if (drainable.length > 0) {
240
+ const drainAcc = drainable[0];
241
+ // The drain SOURCE slot currently holding that account (the one whose tenant we deal out).
242
+ const drainSourceSlot = participatingSlots.find((s) => s.tenantAccountId === drainAcc.accountId);
243
+ // Busiest eligible destination: not the source, not drain-in-progress-held, verified-recent.
244
+ const dest = participatingSlots
245
+ .filter((s) => s.tenantAccountId !== drainAcc.accountId && !s.drainInProgress && targetVerifiedRecent(s, now, auditCadenceMs))
246
+ .sort((a, b) => b.busyness - a.busyness)[0];
247
+ if (drainSourceSlot && dest) {
248
+ const accDest = accById.get(dest.tenantAccountId);
249
+ // Drain respects cooldowns + fresh-data + the min improvement floor (urgency-clamped).
250
+ if (cooldownOk(drainSourceSlot.slot, dest.slot, drainAcc.accountId, accDest.accountId) && freshDataOk(drainAcc, accDest)) {
251
+ const hoursUntil = Math.max(config.urgencyClampHours, drainAcc.weeklyResetsInHours);
252
+ const urgency = 1 / hoursUntil;
253
+ const score = (100 - drainAcc.weeklyPct) * urgency * 100; // headroom × clamped urgency
254
+ if (score >= config.minScoreDelta) {
255
+ decisions.push({
256
+ targetSlot: dest.slot,
257
+ sourceSlot: drainSourceSlot.slot,
258
+ objective: 'drain',
259
+ forced: null,
260
+ reason: `drain ${drainAcc.accountId} (weekly resets in ${drainAcc.weeklyResetsInHours}h, ${100 - drainAcc.weeklyPct}% unused) → busiest slot ${dest.slot}`,
261
+ });
262
+ return { decisions, degraded, attention };
263
+ }
264
+ }
265
+ }
266
+ }
267
+ // ── Objective 3: default-slot preference ──────────────────────────────────────
268
+ // Keep the designated default account in `~/.claude` when neither (1) nor (2) overrode.
269
+ // (The pure policy only signals the preference when the default slot does NOT already
270
+ // hold the default account AND the move clears the floor; B3 supplies which account is
271
+ // "the default" via the slot.isDefault marker + a desiredDefaultAccountId in config-land.
272
+ // In B1 we surface the preference as a no-op reason when nothing else acted.)
273
+ return {
274
+ decisions: [],
275
+ degraded,
276
+ attention,
277
+ noActuationReason: walling.length > 0
278
+ ? 'walling slots present but every candidate move was held by a cooldown / fresh-data gate / missing eligible target'
279
+ : drainable.length > 0
280
+ ? 'drainable account present but the move did not clear cooldown / fresh-data / min-improvement'
281
+ : 'no wall, no drainable window, slots balanced — zero actuation',
282
+ };
283
+ }
284
+ //# sourceMappingURL=CredentialRebalancerPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CredentialRebalancerPolicy.js","sourceRoot":"","sources":["../../src/core/CredentialRebalancerPolicy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * CredentialRebalancerSnapshot — pure mappers from the live system's state into the
3
+ * balancer's read-only pass snapshot (Increment B, step B3b wiring helper).
4
+ *
5
+ * Spec: docs/specs/live-credential-repointing-rebalancer.md §2.4.
6
+ *
7
+ * The CredentialRebalancer orchestrator (B3a) consumes injected `listSlots` / `listAccounts`
8
+ * / `resolveConfig` providers. These pure functions ARE those providers — they translate
9
+ * the CredentialLocationLedger assignments and the SubscriptionPool accounts into the
10
+ * policy's `SlotState` / `AccountState`, and clamp the configured balancer knobs into the
11
+ * resolved config. Kept pure + out of server.ts so the mapping (the place a units/sign
12
+ * bug would silently mis-steer the balancer) is unit-testable.
13
+ */
14
+ import type { SlotState, AccountState } from './CredentialRebalancerPolicy.js';
15
+ import type { RebalancerResolvedConfig } from './CredentialRebalancer.js';
16
+ import type { SubscriptionAccount, SubscriptionAccountStatus } from './SubscriptionPool.js';
17
+ import type { CredentialAssignment } from './CredentialLocationLedger.js';
18
+ /**
19
+ * Map the pool account lifecycle status into the policy's eligibility status.
20
+ * Only needs-reauth/disabled are INELIGIBLE (dead credentials). rate-limited is `ok`:
21
+ * a walled account must stay eligible so wall-avoidance can RESCUE its slot (its high
22
+ * utilization % drives the wall objective; excluding it would strand the very slot that
23
+ * needs help).
24
+ */
25
+ export declare function mapAccountStatus(s: SubscriptionAccountStatus): AccountState['status'];
26
+ /** One pool account → the policy's AccountState. */
27
+ export declare function mapAccount(account: SubscriptionAccount, now: number): AccountState;
28
+ export declare function mapAccounts(accounts: readonly SubscriptionAccount[], now: number): AccountState[];
29
+ export interface SlotMapOptions {
30
+ /** The config-home slot that is the default (`~/.claude`), so isDefault is set. */
31
+ defaultSlot?: string | null;
32
+ /** Optional per-slot busyness (recent activity); absent ⇒ 0 (drain has no busiest preference). */
33
+ busynessBySlot?: Record<string, number>;
34
+ /** Optional per-slot "drain in progress" hold (balancer-tracked); absent ⇒ false. */
35
+ drainInProgressBySlot?: Record<string, boolean>;
36
+ /** Optional per-slot last-audit-divergent flag (scheduled-audit-tracked); absent ⇒ false. */
37
+ auditDivergentBySlot?: Record<string, boolean>;
38
+ }
39
+ /** One ledger assignment → the policy's SlotState. */
40
+ export declare function mapSlot(a: CredentialAssignment, opts: SlotMapOptions): SlotState;
41
+ export declare function mapSlots(assignments: readonly CredentialAssignment[], opts: SlotMapOptions): SlotState[];
42
+ /** The raw balancer config block (subscriptionPool.credentialRepointing.balancer + siblings). */
43
+ export interface RawRebalancerConfig {
44
+ passIntervalMs?: number;
45
+ highWaterPct?: number;
46
+ criticalPct?: number;
47
+ maxForcedSwapsPerPass?: number;
48
+ minScoreDelta?: number;
49
+ drainHorizonHours?: number;
50
+ drainHeadroomMinPct?: number;
51
+ staleQuotaPollPeriods?: number;
52
+ urgencyClampHours?: number;
53
+ maxForcedOverridesPerWindow?: number;
54
+ breakerThreshold?: number;
55
+ auditCadenceMs?: number;
56
+ desiredDefaultAccountId?: string | null;
57
+ /** Number of slots — clamps maxForcedSwapsPerPass upper bound. */
58
+ slotCount?: number;
59
+ }
60
+ /**
61
+ * Clamp the configured knobs into the resolved config the orchestrator/policy use.
62
+ * Cooldowns are DERIVED from the poll interval (per-pair ≥1×, per-tenant ≥2× — the
63
+ * lag-sensored controller floors, §2.4); stale-quota is N poll periods.
64
+ */
65
+ export declare function resolveRebalancerConfig(raw: RawRebalancerConfig): RebalancerResolvedConfig;
66
+ //# sourceMappingURL=CredentialRebalancerSnapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CredentialRebalancerSnapshot.d.ts","sourceRoot":"","sources":["../../src/core/CredentialRebalancerSnapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAC/E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAI1E;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,yBAAyB,GAAG,YAAY,CAAC,QAAQ,CAAC,CAUrF;AAaD,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,CAYlF;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,SAAS,mBAAmB,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,CAEjG;AAED,MAAM,WAAW,cAAc;IAC7B,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,kGAAkG;IAClG,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChD,6FAA6F;IAC7F,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChD;AAED,sDAAsD;AACtD,wBAAgB,OAAO,CAAC,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,CAahF;AAED,wBAAgB,QAAQ,CAAC,WAAW,EAAE,SAAS,oBAAoB,EAAE,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,EAAE,CAExG;AAOD,iGAAiG;AACjG,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,GAAG,wBAAwB,CAsB1F"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * CredentialRebalancerSnapshot — pure mappers from the live system's state into the
3
+ * balancer's read-only pass snapshot (Increment B, step B3b wiring helper).
4
+ *
5
+ * Spec: docs/specs/live-credential-repointing-rebalancer.md §2.4.
6
+ *
7
+ * The CredentialRebalancer orchestrator (B3a) consumes injected `listSlots` / `listAccounts`
8
+ * / `resolveConfig` providers. These pure functions ARE those providers — they translate
9
+ * the CredentialLocationLedger assignments and the SubscriptionPool accounts into the
10
+ * policy's `SlotState` / `AccountState`, and clamp the configured balancer knobs into the
11
+ * resolved config. Kept pure + out of server.ts so the mapping (the place a units/sign
12
+ * bug would silently mis-steer the balancer) is unit-testable.
13
+ */
14
+ const HOUR_MS = 3600_000;
15
+ /**
16
+ * Map the pool account lifecycle status into the policy's eligibility status.
17
+ * Only needs-reauth/disabled are INELIGIBLE (dead credentials). rate-limited is `ok`:
18
+ * a walled account must stay eligible so wall-avoidance can RESCUE its slot (its high
19
+ * utilization % drives the wall objective; excluding it would strand the very slot that
20
+ * needs help).
21
+ */
22
+ export function mapAccountStatus(s) {
23
+ switch (s) {
24
+ case 'needs-reauth': return 'needs-reauth';
25
+ case 'disabled': return 'disabled';
26
+ case 'active':
27
+ case 'warming':
28
+ case 'rate-limited':
29
+ default:
30
+ return 'ok';
31
+ }
32
+ }
33
+ function pctOrNull(v) {
34
+ return typeof v === 'number' && Number.isFinite(v) ? v : null;
35
+ }
36
+ function hoursUntil(resetsAt, now) {
37
+ if (!resetsAt)
38
+ return null;
39
+ const t = Date.parse(resetsAt);
40
+ if (Number.isNaN(t))
41
+ return null;
42
+ return Math.max(0, (t - now) / HOUR_MS);
43
+ }
44
+ /** One pool account → the policy's AccountState. */
45
+ export function mapAccount(account, now) {
46
+ const q = account.lastQuota ?? null;
47
+ const measuredAt = q?.measuredAt ? Date.parse(q.measuredAt) : NaN;
48
+ return {
49
+ accountId: account.id,
50
+ status: mapAccountStatus(account.status),
51
+ fiveHrPct: pctOrNull(q?.fiveHour?.utilizationPct),
52
+ weeklyPct: pctOrNull(q?.sevenDay?.utilizationPct),
53
+ weeklyResetsInHours: hoursUntil(q?.sevenDay?.resetsAt, now),
54
+ // No quota reading at all ⇒ measuredAt 0 (epoch) ⇒ always STALE ⇒ source-only.
55
+ measuredAt: Number.isNaN(measuredAt) ? 0 : measuredAt,
56
+ };
57
+ }
58
+ export function mapAccounts(accounts, now) {
59
+ return accounts.map((a) => mapAccount(a, now));
60
+ }
61
+ /** One ledger assignment → the policy's SlotState. */
62
+ export function mapSlot(a, opts) {
63
+ const lastVerifiedAt = a.lastVerifiedAt ? Date.parse(a.lastVerifiedAt) : NaN;
64
+ return {
65
+ slot: a.slot,
66
+ // The ledger uses '' for a quarantined-but-unassigned slot; normalize to null.
67
+ tenantAccountId: a.accountId ? a.accountId : null,
68
+ isDefault: opts.defaultSlot != null && a.slot === opts.defaultSlot,
69
+ quarantined: a.quarantined,
70
+ lastVerifiedAt: Number.isNaN(lastVerifiedAt) ? null : lastVerifiedAt,
71
+ lastAuditDivergent: opts.auditDivergentBySlot?.[a.slot] ?? false,
72
+ drainInProgress: opts.drainInProgressBySlot?.[a.slot] ?? false,
73
+ busyness: opts.busynessBySlot?.[a.slot] ?? 0,
74
+ };
75
+ }
76
+ export function mapSlots(assignments, opts) {
77
+ return assignments.map((a) => mapSlot(a, opts));
78
+ }
79
+ function clamp(v, lo, hi, dflt) {
80
+ const n = typeof v === 'number' && Number.isFinite(v) ? v : dflt;
81
+ return Math.min(hi, Math.max(lo, n));
82
+ }
83
+ /**
84
+ * Clamp the configured knobs into the resolved config the orchestrator/policy use.
85
+ * Cooldowns are DERIVED from the poll interval (per-pair ≥1×, per-tenant ≥2× — the
86
+ * lag-sensored controller floors, §2.4); stale-quota is N poll periods.
87
+ */
88
+ export function resolveRebalancerConfig(raw) {
89
+ const passIntervalMs = clamp(raw.passIntervalMs, 60_000, 3_600_000, 300_000);
90
+ const slotCount = Math.max(1, raw.slotCount ?? 1);
91
+ const stalePeriods = clamp(raw.staleQuotaPollPeriods, 1, 10, 2);
92
+ return {
93
+ policy: {
94
+ highWaterPct: clamp(raw.highWaterPct, 50, 99, 85),
95
+ criticalPct: clamp(raw.criticalPct, 85, 99, 95),
96
+ drainHorizonHours: clamp(raw.drainHorizonHours, 1, 96, 24),
97
+ drainHeadroomMinPct: clamp(raw.drainHeadroomMinPct, 0, 100, 30),
98
+ minScoreDelta: clamp(raw.minScoreDelta, 0, 1000, 10),
99
+ maxForcedSwapsPerPass: clamp(raw.maxForcedSwapsPerPass, 1, slotCount, 1),
100
+ perPairCooldownMs: passIntervalMs, // ≥1× poll interval
101
+ perTenantCooldownMs: passIntervalMs * 2, // ≥2× poll interval (defeats 3-way rotation)
102
+ staleQuotaMs: passIntervalMs * stalePeriods,
103
+ urgencyClampHours: clamp(raw.urgencyClampHours, 1, 24, 4),
104
+ },
105
+ auditCadenceMs: clamp(raw.auditCadenceMs, HOUR_MS, 24 * HOUR_MS, 6 * HOUR_MS),
106
+ desiredDefaultAccountId: raw.desiredDefaultAccountId ?? null,
107
+ maxForcedOverridesPerWindow: clamp(raw.maxForcedOverridesPerWindow, 1, 100, 5),
108
+ breakerThreshold: clamp(raw.breakerThreshold, 1, 20, 3),
109
+ };
110
+ }
111
+ //# sourceMappingURL=CredentialRebalancerSnapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CredentialRebalancerSnapshot.js","sourceRoot":"","sources":["../../src/core/CredentialRebalancerSnapshot.ts"],"names":[],"mappings":"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"}
@@ -53,6 +53,18 @@ export interface MigratorConfig {
53
53
  * A stripped seamlessness block left empty is removed so the file stays clean.
54
54
  */
55
55
  export declare function migrateConfigWs44PoolLinks(config: Record<string, unknown>): boolean;
56
+ /**
57
+ * Live credential re-pointing was re-gated from DARK_GATE_EXCLUSIONS (off+dry-run for
58
+ * everyone) to the developmentAgent gate (live-on-dev in dry-run, dark fleet) per the
59
+ * 2026-06-13 operator directive. Existing agents that ran the old ConfigDefaults carry an
60
+ * explicit `subscriptionPool.credentialRepointing.enabled: false`, which (being explicit)
61
+ * would keep resolveDevAgentGate DARK even on a dev agent. Strip that default-shaped
62
+ * `false` so the gate resolves (live on dev, dark on fleet) — mirroring the ws44PoolLinks
63
+ * strip. An explicit `true` is preserved (an operator who deliberately turned it on). The
64
+ * separate `dryRun`/`manualLeversEnabled` fields are left untouched (dryRun stays the
65
+ * write-safety canary). Idempotent.
66
+ */
67
+ export declare function migrateConfigCredentialRepointingDevGate(config: Record<string, unknown>): boolean;
56
68
  export declare class PostUpdateMigrator {
57
69
  private config;
58
70
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PostUpdateMigrator.d.ts","sourceRoot":"","sources":["../../src/core/PostUpdateMigrator.ts"],"names":[],"mappings":"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"}
@@ -104,6 +104,32 @@ export function migrateConfigWs44PoolLinks(config) {
104
104
  delete mm.seamlessness;
105
105
  return true;
106
106
  }
107
+ /**
108
+ * Live credential re-pointing was re-gated from DARK_GATE_EXCLUSIONS (off+dry-run for
109
+ * everyone) to the developmentAgent gate (live-on-dev in dry-run, dark fleet) per the
110
+ * 2026-06-13 operator directive. Existing agents that ran the old ConfigDefaults carry an
111
+ * explicit `subscriptionPool.credentialRepointing.enabled: false`, which (being explicit)
112
+ * would keep resolveDevAgentGate DARK even on a dev agent. Strip that default-shaped
113
+ * `false` so the gate resolves (live on dev, dark on fleet) — mirroring the ws44PoolLinks
114
+ * strip. An explicit `true` is preserved (an operator who deliberately turned it on). The
115
+ * separate `dryRun`/`manualLeversEnabled` fields are left untouched (dryRun stays the
116
+ * write-safety canary). Idempotent.
117
+ */
118
+ export function migrateConfigCredentialRepointingDevGate(config) {
119
+ const sp = config.subscriptionPool;
120
+ if (!sp || typeof sp !== 'object')
121
+ return false;
122
+ const cr = sp.credentialRepointing;
123
+ if (!cr || typeof cr !== 'object')
124
+ return false;
125
+ if (!Object.prototype.hasOwnProperty.call(cr, 'enabled'))
126
+ return false;
127
+ // Only a default-shaped `false` is stripped; an explicit `true` is preserved.
128
+ if (cr.enabled !== false)
129
+ return false;
130
+ delete cr.enabled;
131
+ return true;
132
+ }
107
133
  export class PostUpdateMigrator {
108
134
  config;
109
135
  /**
@@ -5872,10 +5898,23 @@ Create worktrees for collaborator repos with \`instar worktree create <branch>\`
5872
5898
  // migration is idempotent and skips template-generated CLAUDE.md files. Harmless
5873
5899
  // on agents where the feature is dark (every lever 503s).
5874
5900
  if (!content.includes('Live Credential Re-pointing (move a pool account')) {
5875
- content += `\n**Live Credential Re-pointing (move a pool account's login between config-home "slots" without restarting — WS5.2)** — Beyond the subscription pool's session-MOVING, this MOVES the credential itself: it exchanges which pool account's OAuth login sits in which config-home "slot" via a staged keychain swap, so the sessions already reading that slot pick up the new account on their NEXT API call — no restart, no re-login, nothing on your screen. The unit shuffled is the CREDENTIAL (always a clean SWAP between two slots, never a copy — one home per credential), verified by identity after every move (quarantine-never-repair when the identity oracle can't confirm). **Ships DARK** behind \`subscriptionPool.credentialRepointing.enabled\` every lever 503s/no-ops while disabled (byte-for-byte today's behavior); going live needs a deliberate \`enabled:true\` + \`dryRun:false\` flip, and that ON decision is yours, separate from any build.\n- **Which account is in which slot?** (Registry First — read it, never guess) \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/credentials/locations\` → the ledger census (slot ↔ account, since, lastVerifiedAt, quarantine state, journal tail, mode).\n- **Flip your default account (zero-touch)** — \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/credentials/set-default -H 'Content-Type: application/json' -d '{"toAccountId":"<account>"}'\` swaps which account \`~/.claude\` serves, with no restart of the session you're talking to.\n- **Swap two slots' credentials live** — \`POST /credentials/swap\` \`{"slotA":"<home>","slotB":"<home>"}\` (the staged §2.3 exchange). **Restore the enrollment layout** — \`POST /credentials/restore-enrollment\` (parks any identity-incoherent blob one-directionally; never exchanges it into a healthy slot). All levers are DETECTIVE controls — operator-notified + audited + param-validated + per-pair cooldown + a force budget on \`force:true\`. No token material ever exits any \`/credentials/*\` surface (the single CredentialAuditEmit scrub chokepoint).\n- **The autonomous balancer surface** — \`GET /credentials/rebalancer\` (the use-it-or-lose-it drainer is Increment B; this surfaces the env-token applicability gate's verdict + WHY re-pointing would refuse, when enabled).\n- **When to use** (PROACTIVE — these are the triggers): "flip my default account to X" / "make X my default" → \`POST /credentials/set-default\`; "which account is this session/slot on?" / "where does ~/.claude point?" → \`GET /credentials/locations\` (read it, don't infer from \`claude auth status\` — that reads a metadata file, not the live credential). Single-account agents are a no-op. (Spec: \`docs/specs/live-credential-repointing-rebalancer.md\`.)\n`;
5901
+ content += `\n**Live Credential Re-pointing (move a pool account's login between config-home "slots" without restarting — WS5.2)** — Beyond the subscription pool's session-MOVING, this MOVES the credential itself: it exchanges which pool account's OAuth login sits in which config-home "slot" via a staged keychain swap, so the sessions already reading that slot pick up the new account on their NEXT API call — no restart, no re-login, nothing on your screen. The unit shuffled is the CREDENTIAL (always a clean SWAP between two slots, never a copy — one home per credential), verified by identity after every move (quarantine-never-repair when the identity oracle can't confirm). **On a development agent it runs LIVE in dry-run** (the developmentAgent gate, \`subscriptionPool.credentialRepointing.enabled\` omitted resolves live-on-dev / dark-fleet) — the \`/credentials/*\` levers return real data and the balancer runs its full decision loop, but the executor performs ZERO credential writes while \`dryRun\` holds (the write-safety canary; on the fleet every lever 503s). Actually MOVING a credential needs a deliberate \`dryRun:false\` that decision is yours (gated behind running the §5 livetest battery first).\n- **Which account is in which slot?** (Registry First — read it, never guess) \`curl -H "Authorization: Bearer $AUTH" http://localhost:${port}/credentials/locations\` → the ledger census (slot ↔ account, since, lastVerifiedAt, quarantine state, journal tail, mode).\n- **Flip your default account (zero-touch)** — \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/credentials/set-default -H 'Content-Type: application/json' -d '{"toAccountId":"<account>"}'\` swaps which account \`~/.claude\` serves, with no restart of the session you're talking to.\n- **Swap two slots' credentials live** — \`POST /credentials/swap\` \`{"slotA":"<home>","slotB":"<home>"}\` (the staged §2.3 exchange). **Restore the enrollment layout** — \`POST /credentials/restore-enrollment\` (parks any identity-incoherent blob one-directionally; never exchanges it into a healthy slot). All levers are DETECTIVE controls — operator-notified + audited + param-validated + per-pair cooldown + a force budget on \`force:true\`. No token material ever exits any \`/credentials/*\` surface (the single CredentialAuditEmit scrub chokepoint).\n- **The autonomous balancer surface** — \`GET /credentials/rebalancer\` (the use-it-or-lose-it drainer is Increment B; this surfaces the env-token applicability gate's verdict + WHY re-pointing would refuse, when enabled).\n- **When to use** (PROACTIVE — these are the triggers): "flip my default account to X" / "make X my default" → \`POST /credentials/set-default\`; "which account is this session/slot on?" / "where does ~/.claude point?" → \`GET /credentials/locations\` (read it, don't infer from \`claude auth status\` — that reads a metadata file, not the live credential). Single-account agents are a no-op. (Spec: \`docs/specs/live-credential-repointing-rebalancer.md\`.)\n`;
5876
5902
  patched = true;
5877
5903
  result.upgraded.push('CLAUDE.md: added Live Credential Re-pointing awareness section');
5878
5904
  }
5905
+ // In-place re-word for agents that ALREADY have the credential section with the stale
5906
+ // "Ships DARK ... enabled:true + dryRun:false" wording (pre-2026-06-13 re-gate). Replace
5907
+ // that one sentence with the live-on-dev-dry-run truth; idempotent (the new text lacks the
5908
+ // old phrase, so a second run is a no-op).
5909
+ {
5910
+ const stale = '**Ships DARK** behind `subscriptionPool.credentialRepointing.enabled` — every lever 503s/no-ops while disabled (byte-for-byte today\'s behavior); going live needs a deliberate `enabled:true` + `dryRun:false` flip, and that ON decision is yours, separate from any build.';
5911
+ const fresh = '**On a development agent it runs LIVE in dry-run** (the developmentAgent gate, `subscriptionPool.credentialRepointing.enabled` omitted → resolves live-on-dev / dark-fleet) — the `/credentials/*` levers return real data and the balancer runs its full decision loop, but the executor performs ZERO credential writes while `dryRun` holds (the write-safety canary; on the fleet every lever 503s). Actually MOVING a credential needs a deliberate `dryRun:false` — that decision is yours (gated behind running the §5 livetest battery first).';
5912
+ if (content.includes(stale)) {
5913
+ content = content.replace(stale, fresh);
5914
+ patched = true;
5915
+ result.upgraded.push('CLAUDE.md: re-worded Live Credential Re-pointing to live-on-dev dry-run (2026-06-13 re-gate)');
5916
+ }
5917
+ }
5879
5918
  if (patched) {
5880
5919
  try {
5881
5920
  fs.writeFileSync(claudeMdPath, content);
@@ -6795,6 +6834,15 @@ Create worktrees for collaborator repos with \`instar worktree create <branch>\`
6795
6834
  else {
6796
6835
  result.skipped.push('config.json: multiMachine.seamlessness.ws44PoolLinks dev-gate already correct (omitted or operator-set)');
6797
6836
  }
6837
+ // Live credential re-pointing re-gated to the developmentAgent gate (2026-06-13 operator
6838
+ // directive): strip a default-shaped enabled:false so it resolves live-on-dev / dark-fleet.
6839
+ if (migrateConfigCredentialRepointingDevGate(config)) {
6840
+ patched = true;
6841
+ result.upgraded.push('config.json: stripped default-shaped subscriptionPool.credentialRepointing.enabled=false so the developmentAgent gate resolves it (live-on-dev dry-run, dark fleet)');
6842
+ }
6843
+ else {
6844
+ result.skipped.push('config.json: subscriptionPool.credentialRepointing.enabled dev-gate already correct (omitted or operator-set)');
6845
+ }
6798
6846
  if (patched) {
6799
6847
  try {
6800
6848
  // Atomic write: backup, then write to tmp, then rename