instar 1.3.590 → 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.
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +39 -12
- package/dist/commands/server.js.map +1 -1
- package/dist/core/OwnershipApplier.d.ts +10 -1
- package/dist/core/OwnershipApplier.d.ts.map +1 -1
- package/dist/core/OwnershipApplier.js +11 -1
- package/dist/core/OwnershipApplier.js.map +1 -1
- package/dist/core/QuotaAwareScheduler.d.ts +25 -0
- package/dist/core/QuotaAwareScheduler.d.ts.map +1 -1
- package/dist/core/QuotaAwareScheduler.js +36 -0
- package/dist/core/QuotaAwareScheduler.js.map +1 -1
- package/dist/core/ownershipApplierWiring.d.ts +44 -0
- package/dist/core/ownershipApplierWiring.d.ts.map +1 -0
- package/dist/core/ownershipApplierWiring.js +20 -0
- package/dist/core/ownershipApplierWiring.js.map +1 -0
- package/dist/monitoring/QuotaTracker.d.ts +56 -0
- package/dist/monitoring/QuotaTracker.d.ts.map +1 -1
- package/dist/monitoring/QuotaTracker.js +112 -4
- package/dist/monitoring/QuotaTracker.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +2 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/src/scaffold/templates.ts +2 -1
- package/upgrades/1.3.591.md +34 -0
- package/upgrades/1.3.592.md +40 -0
- package/upgrades/side-effects/ownership-applier-meshself-ordering-fix.md +52 -0
- package/upgrades/side-effects/pool-aware-quota-throttle.md +123 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-06-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-06-16T08:21:53.499Z",
|
|
5
|
+
"instarVersion": "1.3.592",
|
|
6
6
|
"entryCount": 201,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -802,8 +802,9 @@ I declare owner/blockedOn at commitment creation; a later state change goes thro
|
|
|
802
802
|
- **Continuity guarantee** — a long session that hits its account's quota resumes on another eligible account (conversation preserved via \`--resume\`), never dies. Manual lever: \`POST /subscription-pool/swap\` \`{"sessionName":"...","exhaustedAccountId":"..."}\`. Auto-swap on rate-limit ships OFF (opt-in via \`subscriptionPool.autoSwapOnRateLimit\` — it moves a live session, real authority).
|
|
803
803
|
- **Pre-limit (proactive) swap** — beyond the reactive swap above, I can move a session OFF an account BEFORE it walls, at a lag-aware measured threshold (default 80% — the polled reading trails real usage, so the swap completes with margin). It also covers the UNTAGGED interactive session (resolves its account from the default login), so the session you talk to doesn't wedge at the wall. Opt-in via \`subscriptionPool.proactiveSwap.enabled\` (same authority as auto-swap, earlier trigger). Status: \`GET /subscription-pool/proactive-swap\`; run a pass now: \`POST /subscription-pool/proactive-swap/check\`.
|
|
804
804
|
- **Enroll a new account from your phone** — \`POST /subscription-pool/enroll\` \`{"id","label","provider","framework","configHome"}\` starts a login and returns a public code/URL (never a token); \`GET /subscription-pool/pending-logins\` is the surface; expired codes are auto-reissued. Mark done with \`POST /subscription-pool/enroll/:id/complete\`.
|
|
805
|
+
- **Pool-aware quota brake (the global load-shed is NOT account-blind)** — the global quota throttle (\`QuotaTracker.shouldSpawnSession\`) that decides "can I run work right now?" gates on the **best-available account's headroom across the whole pool**, NOT a single account. So one maxed account can NEVER stop the whole agent while another account still has room — the subscription pool just places the work on the account with the most headroom. A non-authoritative/implausible usage reading (a JSONL token-estimate, or any value >100%) **fails open** rather than slamming the brake on a guess. (A solo, single-account agent keeps the exact legacy single-account gating.) The collector folds every account's live usage into \`quota-state.json\` → \`accounts[]\` so the brake can see the whole pool.
|
|
805
806
|
- **Dashboard**: the **Subscriptions tab** shows live quota bars (5h + weekly + reset countdown), status, and the Pending Logins panel — share the dashboard URL + PIN.
|
|
806
|
-
- **When to use** (PROACTIVE): "how much quota is left across my accounts?" / "am I about to hit a limit?" → \`GET /subscription-pool\`; the user wants to add another subscription → drive the enrollment wizard (never ask them to paste a token); a long job is at risk of a quota wall → the continuity guarantee + \`/swap\` keep it alive. Single-account pools are a no-op.
|
|
807
|
+
- **When to use** (PROACTIVE): "how much quota is left across my accounts?" / "am I about to hit a limit?" → \`GET /subscription-pool\`; the user wants to add another subscription → drive the enrollment wizard (never ask them to paste a token); a long job is at risk of a quota wall → the continuity guarantee + \`/swap\` keep it alive. **"Why didn't the agent stall / get stuck with one account maxed out?"** → the pool-aware quota brake above: it only stops work when EVERY account in the pool is at capacity, so idle accounts get used instead of the agent halting. Single-account pools are a no-op.
|
|
807
808
|
|
|
808
809
|
**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).
|
|
809
810
|
- **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).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
Fixed a boot-ordering bug that left the cross-machine `OwnershipApplier` permanently
|
|
9
|
+
un-wired: a topic moved between machines was reported moved but the destination never took
|
|
10
|
+
ownership, so the conversation went silent on arrival. The applier's on-switch now depends on
|
|
11
|
+
the durable ownership store alone (extracted into a testable `wireOwnershipApplier` factory),
|
|
12
|
+
and the machine id it uses for logging is late-bound, so the wiring can't be broken by code
|
|
13
|
+
reordering. Caught by applying the Live-User-Channel Proof gold standard to a real
|
|
14
|
+
Laptop→Mini transfer (the second, deeper bug after the dev-gate-darkness fix in v1.3.590).
|
|
15
|
+
|
|
16
|
+
## What to Tell Your User
|
|
17
|
+
|
|
18
|
+
If you move a conversation between your machines, the destination now genuinely takes over and
|
|
19
|
+
answers there. Before this, a moved conversation could report success but then go quiet on the
|
|
20
|
+
new machine, because the new machine never realized it owned the conversation. Single-machine
|
|
21
|
+
setups are unaffected.
|
|
22
|
+
|
|
23
|
+
## Summary of New Capabilities
|
|
24
|
+
|
|
25
|
+
| Capability | How to Use |
|
|
26
|
+
|-----------|-----------|
|
|
27
|
+
| Moving a conversation between machines actually lands it on the destination | Move a topic to another machine as usual; the destination now takes ownership and serves it |
|
|
28
|
+
|
|
29
|
+
## Evidence
|
|
30
|
+
|
|
31
|
+
- 6 new unit/wiring tests (`tests/unit/ownershipApplierWiring.test.ts`) + 7 existing applier
|
|
32
|
+
tests stay green; tsc clean.
|
|
33
|
+
- Release gate: a live two-machine re-run asserts the destination materializes the seat and a
|
|
34
|
+
reply serves from it (Telegram + Slack).
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The global quota brake (`QuotaTracker.shouldSpawnSession`) was account-blind: it stopped the WHOLE agent
|
|
9
|
+
on a single account's usage, so when one Claude account hit its weekly limit the agent froze even though
|
|
10
|
+
other pooled accounts sat at 0% (the 2026-06-15 "two accounts untouched while work stalls" incident; a
|
|
11
|
+
degraded JSONL estimate reading 186% jammed it harder). It now reasons over the whole pool by asking the
|
|
12
|
+
placement layer's OWN `selectAccount` predicate (via a provider wired in `server.ts`): the brake never
|
|
13
|
+
halts the agent while a placeable account has headroom, and never allows work placement can't land — the
|
|
14
|
+
90–95% "allowed-but-unplaceable" respawn-loop band is closed by construction (`allowed ⟹ placeable`).
|
|
15
|
+
Missing/implausible/degraded readings trigger a BOUNDED mode (shed low priority, allow medium+, honor an
|
|
16
|
+
authoritative 5-hour wall) instead of a stall or unbounded fail-open.
|
|
17
|
+
|
|
18
|
+
## What to Tell Your User
|
|
19
|
+
|
|
20
|
+
If you run several Claude accounts pooled together, the agent no longer freezes when one account hits its
|
|
21
|
+
weekly limit — it keeps working on the accounts that still have room, and it won't get stuck in the
|
|
22
|
+
"session respawned" restart loop. Single-account agents are completely unaffected (byte-identical
|
|
23
|
+
behavior). Nothing to configure; it's on by default because it removes a bug.
|
|
24
|
+
|
|
25
|
+
## Summary of New Capabilities
|
|
26
|
+
|
|
27
|
+
- `QuotaTracker.setPoolQuotaProvider()` — the brake shares placement's exact eligibility predicate, so a
|
|
28
|
+
maxed account can never stop the whole agent while a placeable account exists.
|
|
29
|
+
- Bounded degraded-data handling (shared by the pool and single-account paths): non-authoritative /
|
|
30
|
+
out-of-range / missing readings shed low priority and allow medium+, instead of stalling or running blind.
|
|
31
|
+
- The "use-it-or-lose-it" optimizations (drain near-reset accounts first, burn-rate balancing) are the
|
|
32
|
+
tracked SECOND PR — this one is the robust+safe foundation.
|
|
33
|
+
|
|
34
|
+
## Evidence
|
|
35
|
+
|
|
36
|
+
Converged over 3 `/spec-converge` rounds (6 internal reviewers + codex GPT-5.5); the first two designs were
|
|
37
|
+
rejected by review (one dead in production, one with a staleness/loop gap) and redesigned. 253 quota tests
|
|
38
|
+
pass with no regressions, including a test proving `allowed ⟹ placeable` across a 0→100 usage sweep and the
|
|
39
|
+
90–95% band → stop. Spec: `docs/specs/POOL-AWARE-QUOTA-THROTTLE-SPEC.md`. Acceptance: the two previously-idle
|
|
40
|
+
accounts demonstrably carry load after the fix (live proof).
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Side-Effects Review — OwnershipApplier mesh-self ordering fix
|
|
2
|
+
|
|
3
|
+
**Slug:** ownership-applier-meshself-ordering-fix
|
|
4
|
+
**Spec:** docs/specs/ownership-applier-meshself-ordering-fix.md
|
|
5
|
+
**Parent principle:** Wiring Integrity — a dependency-injected component must actually run, not be a silently-skipped no-op.
|
|
6
|
+
|
|
7
|
+
## What changed
|
|
8
|
+
|
|
9
|
+
A boot-ordering bug in `src/commands/server.ts` meant the transfer-fix §7.2 `OwnershipApplier`
|
|
10
|
+
was never constructed or ticked at runtime (its guard read `_meshSelfId` ~650 lines before
|
|
11
|
+
the boot sequence assigns it, so the guard was always false). Result: a topic transferred
|
|
12
|
+
between machines was recorded on the SOURCE and replicated to the DESTINATION's journal, but
|
|
13
|
+
the destination never materialized ownership → it never knew it owned the session → the seat
|
|
14
|
+
died on arrival. Caught by applying the Live-User-Channel Proof gold standard to a real
|
|
15
|
+
Laptop→Mini transfer.
|
|
16
|
+
|
|
17
|
+
Fix (order-independent — Structure > Willpower):
|
|
18
|
+
- `src/core/OwnershipApplier.ts` — `selfMachineId` accepts a late-bound getter (label-only;
|
|
19
|
+
materialization never needs it); resolved per-tick instead of captured stale at construction.
|
|
20
|
+
- `src/core/ownershipApplierWiring.ts` (new) — `wireOwnershipApplier()` factory gates
|
|
21
|
+
construction on the durable store ALONE (the correct condition), extracted so the invariant
|
|
22
|
+
is unit-testable (the inline condition was untestable, which is how the bug shipped).
|
|
23
|
+
- `src/commands/server.ts` — calls the factory in place of the inline guard.
|
|
24
|
+
|
|
25
|
+
## Blast radius
|
|
26
|
+
|
|
27
|
+
- **Multi-machine destinations (the target):** a transferred seat now materializes durable
|
|
28
|
+
ownership on the destination and is served there. This was BROKEN before — net improvement.
|
|
29
|
+
- **Single machine:** the durable store may be active but there are no peer placements; the
|
|
30
|
+
applier ticks and finds nothing — a harmless no-op. No behavior change.
|
|
31
|
+
- **Transfer SOURCE:** unchanged (it writes ownership directly via the tclaim path).
|
|
32
|
+
- **No new route, config flag, state schema, URL, or migration.** Pure internal wiring +
|
|
33
|
+
one new internal module (no agent-facing surface → no CLAUDE.md template change required).
|
|
34
|
+
- **Backward compatibility:** `OwnershipApplier`'s `selfMachineId` still accepts a plain
|
|
35
|
+
string; all existing callers/tests are unaffected (7 existing applier tests stay green).
|
|
36
|
+
|
|
37
|
+
## Reversibility
|
|
38
|
+
|
|
39
|
+
No flag (it only activates the durable-ownership path that already ships pool-consistent for
|
|
40
|
+
replication-on pools / dark for single-machine). Revertable by reverting the three-file diff;
|
|
41
|
+
no durable state is written that would outlive a revert (ownership records are re-derived from
|
|
42
|
+
the replicated journal on the next tick).
|
|
43
|
+
|
|
44
|
+
## Risk / monitoring
|
|
45
|
+
|
|
46
|
+
Low. The applier is off the hot path (boot tick + 15s interval), never throws (degrades to
|
|
47
|
+
"materialized fewer this tick"), and fast-forward-CAS guards against clobbering a fresher
|
|
48
|
+
local decision. Observable via `[ownership-applier] materialized …` / `[OwnershipApplier]
|
|
49
|
+
materialized N/M …` in `logs/server.log` — their appearance is itself the proof the wiring is
|
|
50
|
+
now alive (the bug's signature was their total absence). Release gate: the live two-machine
|
|
51
|
+
re-run (deploy both → transfer → assert destination materializes + a reply serves from the
|
|
52
|
+
destination).
|
|
@@ -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`
|