instar 1.3.591 → 1.3.592

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,123 @@
1
+ # Side-Effects Review — Pool-Aware Quota Throttle
2
+
3
+ **Version / slug:** `pool-aware-quota-throttle`
4
+ **Date:** `2026-06-16`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** spec-converge multi-reviewer panel (6 internal + codex GPT-5.5), 3 rounds — see docs/specs/reports/POOL-AWARE-QUOTA-THROTTLE-convergence.md
7
+
8
+ ## Summary of the change
9
+
10
+ Makes the global quota brake (`QuotaTracker.shouldSpawnSession`) pool-aware. Instead of stopping the
11
+ whole agent when ONE account's usage is high, it consults a new `poolHeadroom` helper in the placement
12
+ module (via an injected provider wired in `server.ts`). `poolHeadroom` shares `selectAccount`'s EXACT
13
+ eligibility predicate — so `placeable ⟺ selectAccount() !== null` (the never-loop invariant) — but
14
+ gates on the MOST-HEADROOM eligible account, so non-critical work runs whenever ANY account has room
15
+ (the 2026-06-16 live-proof fix: gating on `selectAccount`'s use-it-or-lose-it drain-first winner
16
+ wrongly shed medium/autonomous work even with a fresh 0% reserve). Placement (`selectAccount`) still
17
+ drains the soonest-to-reset account. A non-authoritative/implausible/missing reading triggers a
18
+ BOUNDED degraded mode (shed low priority, allow medium+, honor an authoritative 5h wall) rather than
19
+ an unbounded fail-open or a whole-agent stall. Files: `src/monitoring/QuotaTracker.ts` (provider +
20
+ bounded helper + data-quality guard), `src/core/QuotaAwareScheduler.ts` (the shared `poolHeadroom`
21
+ helper), `src/commands/server.ts` (wiring), `src/scaffold/templates.ts` (CLAUDE.md awareness).
22
+ Decision point: the spawn/job quota gate.
23
+
24
+ ## Decision-point inventory
25
+
26
+ - `QuotaTracker.shouldSpawnSession` (the spawn/job quota brake) — **modify** — now reasons over pool
27
+ placeability (shared with placement's `selectAccount`) instead of a single account's usage; adds a
28
+ bounded degraded mode. This is the only decision surface touched.
29
+
30
+ ---
31
+
32
+ ## 1. Over-block
33
+
34
+ **What legitimate inputs does this change reject that it shouldn't?**
35
+
36
+ The change REDUCES over-block — its whole purpose is to stop the brake from falsely halting the agent
37
+ when fresh accounts exist. New possible over-block: if EVERY account is status `rate-limited` (not
38
+ just high-usage), `selectAccount` returns null → STOP. This is correct (placement genuinely can't
39
+ land), and it is NOT latched — it re-evaluates every call and self-clears when a window resets. The
40
+ bounded degraded mode sheds `low` priority during untrustworthy readings — intended, conservative.
41
+
42
+ ## 2. Under-block
43
+
44
+ **What failure modes does this still miss?**
45
+
46
+ A throttle "allow" guarantees placeability AT DECISION TIME; a concurrent spawn could consume the last
47
+ account before placement runs — placement then returns null, which the caller handles as a normal
48
+ back-off (NOT the old respawn loop, which came from throttle/placement disagreeing — now impossible).
49
+ The provider trusts the pool's own quota-poll freshness (same data placement already relies on); a
50
+ genuinely stale-but-present reading is the pool layer's concern, not newly introduced here.
51
+
52
+ ## 3. Level-of-abstraction fit
53
+
54
+ The fix lives in the existing quota-gating module (`QuotaTracker`) and the existing server wiring —
55
+ the correct layer. It reuses placement's `selectAccount`/`bindingUtilization` rather than duplicating
56
+ eligibility logic, so there is one source of truth for "is this account placeable."
57
+
58
+ ## 4. Signal vs authority compliance
59
+
60
+ `QuotaTracker` is an EXISTING authority (it gates real spawns). The change does not add a new brittle
61
+ blocking check — it makes the existing authority's decision pool-aware and adds fail-open/bounded
62
+ behavior in the safe direction. Fail-open on degraded data is exactly the Signal-vs-Authority guidance
63
+ (don't let an expensive false-positive stop everything). Lessons-aware reviewer confirmed PASS across 3
64
+ rounds.
65
+
66
+ ## 5. Interactions
67
+
68
+ - **Placement (`QuotaAwareScheduler.selectAccount`):** now shared by the throttle — by construction
69
+ they cannot diverge (closes the respawn-loop band). No change to selectAccount itself.
70
+ - **SubscriptionPool:** read-only (`list()`); no mutation.
71
+ - **QuotaCollector / QuotaManager:** unchanged (the earlier collector edit was reverted). The file
72
+ path (single-account / legacy) is byte-identical except the bounded degraded mode.
73
+ - **Scheduler / can-start / spawn gates:** all consume `shouldSpawnSession`/`canRunJob` and benefit
74
+ automatically; no signature change.
75
+
76
+ ## 6. External surfaces
77
+
78
+ No new routes, no new config keys, no new dashboard surface. The only user-facing surface is the
79
+ CLAUDE.md template awareness blurb (additive). No external network calls added (the provider reads the
80
+ in-memory pool synchronously).
81
+
82
+ ## 6b. Operator-surface quality
83
+
84
+ No operator-facing UI/route changes. The behavior the operator observes ("the agent no longer freezes
85
+ when one account maxes out; idle accounts get used") is the intended improvement, documented in the
86
+ CLAUDE.md awareness section so an agent can explain it conversationally.
87
+
88
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
89
+
90
+ **Machine-local BY DESIGN.** `quota-state.json` and the SubscriptionPool the throttle reads are
91
+ per-machine: each host polls its own account credentials and places sessions locally. Replicating
92
+ would be wrong (machine A's stale view would gate machine B's spawns). The existing
93
+ `GET /subscription-pool?scope=pool` is the unchanged cross-machine quota surface. No durable state is
94
+ introduced that could strand on a topic transfer. Documented in the spec's "Multi-machine posture"
95
+ section.
96
+
97
+ ## 8. Rollback cost
98
+
99
+ Low. Pure code change, no persisted-state migration. Disable per-agent by leaving the provider unset
100
+ (or `setPoolQuotaProvider(undefined)`) → file-based gating returns. Full revert = revert the commit +
101
+ rebuild + restart sessions. Solo (single-account) agents are unaffected (no provider wired). No
102
+ dark-gate flag (this is a correctness fix, default-on, fail-safe — the prior behavior was the bug).
103
+
104
+ ## Conclusion
105
+
106
+ The change removes a false-positive whole-agent halt, shares placement's exact eligibility so the
107
+ throttle and placer can't diverge (no respawn loop), and bounds degraded-data behavior in the safe
108
+ direction. Reviewed to convergence over 3 rounds (the first two designs were rejected and redesigned).
109
+ All three test tiers green; 253 quota tests pass with no regressions.
110
+
111
+ ## Second-pass review (if required)
112
+
113
+ Done — the spec-converge panel (6 internal reviewers + codex GPT-5.5 external) served as the
114
+ multi-reviewer second pass across 3 rounds; both high-signal reviewers returned "CONVERGED — no
115
+ material findings" in the final round. Concurred: true.
116
+
117
+ ## Evidence pointers
118
+
119
+ - Spec: `docs/specs/POOL-AWARE-QUOTA-THROTTLE-SPEC.md` (review-convergence + approved)
120
+ - ELI16: `docs/specs/POOL-AWARE-QUOTA-THROTTLE-SPEC.eli16.md`
121
+ - Convergence report: `docs/specs/reports/POOL-AWARE-QUOTA-THROTTLE-convergence.md`
122
+ - Round-1 findings: `docs/specs/reports/POOL-AWARE-QUOTA-THROTTLE-round1-findings.md`
123
+ - Tests: `tests/unit/quota-tracker-pool-aware.test.ts`, `tests/unit/quota-tracker-invalid-input.test.ts`, `tests/integration/pool-aware-quota-canstart.test.ts`