instar 1.3.273 → 1.3.274
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 +27 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/MachinePoolRegistry.d.ts +3 -0
- package/dist/core/MachinePoolRegistry.d.ts.map +1 -1
- package/dist/core/MachinePoolRegistry.js +1 -0
- package/dist/core/MachinePoolRegistry.js.map +1 -1
- package/dist/core/PlacementExecutor.d.ts.map +1 -1
- package/dist/core/PlacementExecutor.js +28 -6
- package/dist/core/PlacementExecutor.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +14 -2
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/types.d.ts +11 -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/package.json +1 -1
- package/src/data/builtin-manifest.json +19 -19
- package/src/scaffold/templates.ts +1 -0
- package/upgrades/1.3.274.md +47 -0
- package/upgrades/side-effects/quota-aware-placement.md +99 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The multi-machine session pool no longer places conversations onto a machine
|
|
9
|
+
whose LLM account is rate-limited or quota-blocked. Each machine's 30-second
|
|
10
|
+
capacity heartbeat now self-reports a `quotaState` (provider block in effect,
|
|
11
|
+
or the 5-hour window ≥95% — read strictly from that machine's OWN quota
|
|
12
|
+
tracker), and the placement engine:
|
|
13
|
+
|
|
14
|
+
- drops quota-blocked machines from the candidate pool (new placements,
|
|
15
|
+
soft preferences, AND stickiness — a conversation currently on a machine
|
|
16
|
+
that becomes blocked moves off it on the next message);
|
|
17
|
+
- still honors an explicit hard pin to a blocked machine (the user's command
|
|
18
|
+
wins), flagged `pinned-machine-quota-blocked` so the user can be told why
|
|
19
|
+
it's quiet;
|
|
20
|
+
- falls back to least-loaded-among-blocked when EVERY machine is blocked,
|
|
21
|
+
flagged `all-machines-quota-blocked`.
|
|
22
|
+
|
|
23
|
+
Older machines that don't report the field are treated as not blocked —
|
|
24
|
+
mixed-version pools behave exactly as before. `GET /pool` shows each
|
|
25
|
+
machine's `quotaState`.
|
|
26
|
+
|
|
27
|
+
## What to Tell Your User
|
|
28
|
+
|
|
29
|
+
Your messages stop landing on a machine whose AI account has hit its limit —
|
|
30
|
+
the pool quietly routes conversations to a machine that can actually answer.
|
|
31
|
+
The only way to stay on a rate-limited machine is to have pinned the
|
|
32
|
+
conversation there yourself, and then I can tell you exactly why it's quiet
|
|
33
|
+
and when the limit resets.
|
|
34
|
+
|
|
35
|
+
## Summary of New Capabilities
|
|
36
|
+
|
|
37
|
+
- Per-machine `quotaState` in capacity heartbeats + `GET /pool`.
|
|
38
|
+
- Placement avoids quota-blocked machines; blocked owners lose stickiness.
|
|
39
|
+
- Hard pins win with a `pinned-machine-quota-blocked` flag; all-blocked
|
|
40
|
+
pools place least-loaded with `all-machines-quota-blocked`.
|
|
41
|
+
|
|
42
|
+
## Evidence
|
|
43
|
+
|
|
44
|
+
`tests/unit/PlacementExecutor.test.ts` +8 (including the verbatim incident
|
|
45
|
+
case — a quota-blocked current owner loses stickiness) with all 29
|
|
46
|
+
pre-existing placement tests green; `tests/unit/MachinePoolRegistry.test.ts`
|
|
47
|
+
+1 (passthrough + clears on a quota-free heartbeat). tsc + lint clean.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Side-Effects Review — Quota-aware placement
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `quota-aware-placement`
|
|
4
|
+
**Date:** `2026-06-05`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required` (pure-function gate + additive optional field; absent field = bit-identical behavior; every boundary side test-pinned)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Capacity heartbeats self-report a per-machine `quotaState` (from THIS
|
|
11
|
+
machine's own QuotaTracker: provider block active OR 5-hour ≥95%), the
|
|
12
|
+
registry passes it through to `MachineCapacity`, and `PlacementExecutor`
|
|
13
|
+
drops quota-blocked machines from the candidate pool — with a
|
|
14
|
+
place-somewhere fallback when ALL are blocked (`all-machines-quota-blocked`)
|
|
15
|
+
and a pin-wins exception (`pinned-machine-quota-blocked`).
|
|
16
|
+
|
|
17
|
+
## Decision-point inventory
|
|
18
|
+
|
|
19
|
+
1. Heartbeat quota computation: block active / 5h exhausted / neither /
|
|
20
|
+
tracker absent / tracker throws. All produce defined outputs (blocked /
|
|
21
|
+
blocked / not-blocked / omitted / omitted); the omitted side = not blocked.
|
|
22
|
+
2. Gate: blocked machine vs not vs absent-field vs `blocked:false`. All four
|
|
23
|
+
pinned.
|
|
24
|
+
3. All-blocked fallback vs some-unblocked. Both pinned.
|
|
25
|
+
4. Hard pin to blocked (honored+flagged) vs soft preference (degrades) vs
|
|
26
|
+
sticky owner blocked (loses stickiness — the incident case). All pinned.
|
|
27
|
+
5. Pin path capability check preserved (never capability-blind). Pinned.
|
|
28
|
+
|
|
29
|
+
## 1. Over-block
|
|
30
|
+
|
|
31
|
+
A quota-blocked machine still serves: hard pins, the all-blocked fallback,
|
|
32
|
+
and every EXISTING session (placement only affects new/re-placements — the
|
|
33
|
+
gate cannot strand a running conversation). A false `blocked: true`
|
|
34
|
+
self-report (tracker over-reporting) shifts new placements to peers, which is
|
|
35
|
+
exactly the desired degraded behavior; the worst case equals today's behavior
|
|
36
|
+
when all machines report blocked.
|
|
37
|
+
|
|
38
|
+
## 2. Under-block
|
|
39
|
+
|
|
40
|
+
- A false `blocked: false` (stale tracker file) reproduces today's behavior —
|
|
41
|
+
never worse than the status quo.
|
|
42
|
+
- The signal refreshes every 30s heartbeat; a block that begins mid-window is
|
|
43
|
+
seen at most 30s late.
|
|
44
|
+
- A topic already on a machine that becomes blocked moves only on its NEXT
|
|
45
|
+
message (placement is per-message by design) — no proactive eviction here.
|
|
46
|
+
|
|
47
|
+
## 3. Level-of-abstraction fit
|
|
48
|
+
|
|
49
|
+
The quota READ lives on the machine that owns the account (heartbeat
|
|
50
|
+
producer); the DECISION lives in the one pure placement function every
|
|
51
|
+
placement flows through; the registry is a dumb passthrough. No new
|
|
52
|
+
cross-machine channel — the signal rides the existing heartbeat.
|
|
53
|
+
|
|
54
|
+
## 4. Signal vs authority compliance
|
|
55
|
+
|
|
56
|
+
**Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
|
|
57
|
+
|
|
58
|
+
The gate redirects NEW placements only; it never kills, blocks a message, or
|
|
59
|
+
overrides the user (pin wins). Failure modes degrade to current behavior
|
|
60
|
+
(absent/unknown = not blocked); the heartbeat computation is try/caught with
|
|
61
|
+
an explicit unknown ≠ blocked rule.
|
|
62
|
+
|
|
63
|
+
## 5. Interactions
|
|
64
|
+
|
|
65
|
+
- Stickiness intentionally weakened for blocked owners — that IS the incident
|
|
66
|
+
fix; hysteresis still applies among unblocked candidates.
|
|
67
|
+
- The gemini quota-conflation lesson honored: each machine reads only its own
|
|
68
|
+
QuotaTracker — no cross-machine quota file reads.
|
|
69
|
+
- Mixed-version pools safe: older machines simply omit the field.
|
|
70
|
+
- `GET /pool` and the Machines tab now show `quotaState` (additive).
|
|
71
|
+
|
|
72
|
+
## 6. External surfaces
|
|
73
|
+
|
|
74
|
+
One optional field on `MachineCapacity`/`HeartbeatObservation` (additive,
|
|
75
|
+
visible in `GET /pool`). No config, no routes, no migration (absence =
|
|
76
|
+
default). CLAUDE.md template line + idempotent append migration.
|
|
77
|
+
|
|
78
|
+
## 7. Rollback cost
|
|
79
|
+
|
|
80
|
+
Trivial — revert the PR; the field disappears from heartbeats and the gate
|
|
81
|
+
from decide(). No state, no schema.
|
|
82
|
+
|
|
83
|
+
## Conclusion
|
|
84
|
+
|
|
85
|
+
The quota-blind placement hole closed at the pure-function layer with
|
|
86
|
+
strictly-degrading failure modes: every uncertain case behaves exactly like
|
|
87
|
+
today.
|
|
88
|
+
|
|
89
|
+
## Second-pass review (if required)
|
|
90
|
+
|
|
91
|
+
Not required — see header.
|
|
92
|
+
|
|
93
|
+
## Evidence pointers
|
|
94
|
+
|
|
95
|
+
- `tests/unit/PlacementExecutor.test.ts` (+8, incl. the verbatim incident
|
|
96
|
+
case: a blocked current owner loses stickiness).
|
|
97
|
+
- `tests/unit/MachinePoolRegistry.test.ts` (+1 passthrough + clears-on-next-heartbeat).
|
|
98
|
+
- 29 pre-existing placement tests green; tsc + lint clean.
|
|
99
|
+
- `docs/specs/quota-aware-placement.md` + `.eli16.md`.
|