instar 1.3.640 → 1.3.641
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 +40 -19
- package/dist/commands/server.js.map +1 -1
- package/dist/core/IntelligenceRouter.d.ts +30 -1
- package/dist/core/IntelligenceRouter.d.ts.map +1 -1
- package/dist/core/IntelligenceRouter.js +57 -0
- package/dist/core/IntelligenceRouter.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/types.d.ts +12 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/LlmQueue.d.ts +17 -0
- package/dist/monitoring/LlmQueue.d.ts.map +1 -1
- package/dist/monitoring/LlmQueue.js +36 -0
- package/dist/monitoring/LlmQueue.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.641.md +51 -0
- package/upgrades/side-effects/resilient-degradation-ladder-increment-3.md +108 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: minor -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The last rung of the rate-limit principle: **wait for capacity before falling back.** When an internal
|
|
9
|
+
background check gets rate-limited and has already tried slowing-down-and-retrying and switching
|
|
10
|
+
frameworks, it can now WAIT in a small queue for capacity to free up — instead of immediately giving up
|
|
11
|
+
and dropping to a basic rule. The wait is bounded and rate-aware (it rides the same circuit-breaker
|
|
12
|
+
timing that protects the account), so a burst of queued checks can't re-trip the limit the moment it
|
|
13
|
+
recovers. Only background, non-urgent checks queue; anything the agent is actively waiting on still
|
|
14
|
+
fails fast. If the queue is full or over its daily budget, the check falls through to its basic rule
|
|
15
|
+
exactly as before — never silently dropped.
|
|
16
|
+
|
|
17
|
+
This is **off by default** (on for the dev agent first), reuses the existing wedge-safe queue, and
|
|
18
|
+
changes nothing for any other queue user.
|
|
19
|
+
|
|
20
|
+
## What to Tell Your User
|
|
21
|
+
|
|
22
|
+
Nothing changes unless you turn it on. Once on, if a background check hits a rate limit, it will
|
|
23
|
+
briefly wait its turn for capacity to come back before falling back to a simpler rule — so you lose the
|
|
24
|
+
smart answer less often. Urgent checks you are waiting on still respond fast, and if there is no spare
|
|
25
|
+
capacity the check just uses its basic rule like before.
|
|
26
|
+
|
|
27
|
+
## Summary of New Capabilities
|
|
28
|
+
|
|
29
|
+
- `IntelligenceRouter` DEFERRABLE queue rung (`tryDeferrableQueue`): a non-gating call that exhausts
|
|
30
|
+
backoff + framework-swap enqueues onto a dedicated `LlmQueue` (background lane) and WAITS for
|
|
31
|
+
capacity (the enqueued `provider.evaluate` honors the account-global breaker's `retryAfterMs`)
|
|
32
|
+
before dropping to the caller's heuristic. Inserted at both fall-through points.
|
|
33
|
+
- A GATING call is NEVER queued (`deferrable = !gating && …`, code-enforced — D5). An enqueue
|
|
34
|
+
rejection (daily-cap / interactive-reserve) or queued-call failure falls through to the heuristic,
|
|
35
|
+
never dropped. Two new `onDegrade` reasons (`queued` / `queue-rejected`) for `/metrics/features` (D7).
|
|
36
|
+
- `LlmQueue` opt-in `backgroundDispatchMinGapMs` (§3c herd guard): a jittered minimum gap between
|
|
37
|
+
background dispatches; interactive bypasses; default 0 = off (zero change for existing callers).
|
|
38
|
+
- Config `intelligence.degradationLadder.queue` → `{ enabled?, attemptTimeoutMs?, drainMinGapMs? }`;
|
|
39
|
+
`DEV_GATED_FEATURES` entry `degradationLadderQueue` (live-on-dev / dark-on-fleet).
|
|
40
|
+
|
|
41
|
+
## Evidence
|
|
42
|
+
|
|
43
|
+
**Before:** a deferrable internal call that exhausted backoff + framework-swap dropped STRAIGHT to its
|
|
44
|
+
heuristic — even when capacity would have freed up moments later. **After:** with the rung enabled, it
|
|
45
|
+
WAITS for capacity in a bounded, rate-aware queue first, and only falls back if the queue rejects it or
|
|
46
|
+
the queued call fails. Reproduced by `tests/unit/degradation-ladder.test.ts` (7 queue cases: success +
|
|
47
|
+
auto-resolve; order backoff/swap → queue → success; GATING never queued; enqueue-rejection ⇒ heuristic
|
|
48
|
+
fallthrough; non-deferrable never queued; no-llmQueue no-op; queueEnabled:false not enqueued) and
|
|
49
|
+
`tests/unit/LlmQueue.test.ts` (3 pacing cases). The rung reuses the existing wedge-safe `LlmQueue` and
|
|
50
|
+
never calls the DegradationReporter alert machinery, so the 2026-06-21 event-loop wedge cannot recur.
|
|
51
|
+
Full `tsc` + dark-gate lint green; `no-silent-fallbacks` holds at baseline 476.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Side-Effects Review — Resilient Degradation Ladder Increment 3 (queue rung)
|
|
2
|
+
|
|
3
|
+
**Slug:** `resilient-degradation-ladder-increment-3` · **Tier:** 2 (spec-driven; the spec converged +
|
|
4
|
+
operator-approved, rode Increments 1/2). **Spec:** `docs/specs/resilient-degradation-ladder.md` §3b.3,
|
|
5
|
+
§3c, D1/D5/D7.
|
|
6
|
+
|
|
7
|
+
## Summary of the change
|
|
8
|
+
|
|
9
|
+
The third (and final) rung of the operator's degradation principle — "prefer slowing down over
|
|
10
|
+
falling back". Dark/dev-gated:
|
|
11
|
+
|
|
12
|
+
- `IntelligenceRouter` gains a DEFERRABLE **queue rung** (`tryDeferrableQueue`): a non-gating call
|
|
13
|
+
that has exhausted backoff + framework-swap now WAITS for capacity in a dedicated `LlmQueue`
|
|
14
|
+
(`background` lane) before dropping to the caller's heuristic. The enqueued `provider.evaluate`
|
|
15
|
+
honors the account-global breaker's `retryAfterMs` via `acquireOrWait` — that IS the §3b.3
|
|
16
|
+
rate-awareness. Inserted at BOTH fall-through points (no-swap-configured AND swap-exhausted) before
|
|
17
|
+
the existing `onHeuristicFallthrough` + throw.
|
|
18
|
+
- A structural `DeferrableQueue` interface declared in `core` (the real `LlmQueue` satisfies it) so
|
|
19
|
+
`core` does NOT import `monitoring` (no layering cycle).
|
|
20
|
+
- `LlmQueue` gains an opt-in `backgroundDispatchMinGapMs` (§3c herd guard): a jittered minimum gap
|
|
21
|
+
between BACKGROUND-lane dispatches; interactive bypasses. Default 0 = OFF (today's greedy drain).
|
|
22
|
+
- Server wires a DEDICATED `LlmQueue` for the rung (built ONLY when the gate-resolved `queueEnabled`
|
|
23
|
+
is true), gate-resolves `queueEnabled`/`queueAttemptTimeoutMs` via `resolveDevAgentGate`, and the
|
|
24
|
+
ladder object is now present when ANY rung (backoff OR queue) is active.
|
|
25
|
+
- `DEV_GATED_FEATURES` registration (`degradationLadderQueue`).
|
|
26
|
+
- Config type extended: `degradationLadder.queue` → `{ enabled?, attemptTimeoutMs?, drainMinGapMs? }`.
|
|
27
|
+
|
|
28
|
+
## Decision-point inventory (frozen)
|
|
29
|
+
|
|
30
|
+
D1 (config + dark rollout), D5 (`gating:true` ⇒ queue-skipped, code-enforced), D7 (reason taxonomy
|
|
31
|
+
`queued` / `queue-rejected`). Increment-3 bounds (sensible defaults, dark/reversible, fit D1's
|
|
32
|
+
`{enabled, …bounds}` structure): `queueAttemptTimeoutMs` 60000, dedicated queue `maxConcurrent` 1 +
|
|
33
|
+
`maxDailyCents` 25, `drainMinGapMs` 0 (off).
|
|
34
|
+
|
|
35
|
+
**D9 (new, recorded here) — the §3c herd guard is opt-in, realized two ways:** (1) the PRIMARY
|
|
36
|
+
rate-awareness is the provider-layer `acquireOrWait` — each enqueued `evaluate` waits for the
|
|
37
|
+
account-global breaker window, so queued calls don't hammer a rate-limited account; (2) the dedicated
|
|
38
|
+
queue's `maxConcurrent: 1` serializes deferrable retries (naturally herd-safe); (3) `drainMinGapMs`
|
|
39
|
+
adds an OPTIONAL jittered inter-dispatch gap (off by default). Explicit pacing is opt-in so existing
|
|
40
|
+
`LlmQueue` callers (PresenceProxy / PromiseBeacon) see ZERO behavior change. This faithfully delivers
|
|
41
|
+
§3b.3/§3c without rebuilding shared infrastructure (round-1 "extend, don't rebuild").
|
|
42
|
+
|
|
43
|
+
## 1. Over-block / false positive
|
|
44
|
+
|
|
45
|
+
The rung only ADDS a wait-for-capacity step on a DEFERRABLE call that already exhausted swap; it never
|
|
46
|
+
blocks an interactive/gating call. A queued call that fails or is rejected falls through to exactly
|
|
47
|
+
today's heuristic — strictly no worse than before. No new block surface.
|
|
48
|
+
|
|
49
|
+
## 2. Under-block
|
|
50
|
+
|
|
51
|
+
A GATING call NEVER reaches the queue rung: `deferrable = !gating && options.deferrable === true`, so
|
|
52
|
+
`if (deferrable) …tryDeferrableQueue` is structurally unreachable for a gate (D5). Unit-tested
|
|
53
|
+
(`GATING is NEVER queued`). The gating fail-closed boundary is unchanged.
|
|
54
|
+
|
|
55
|
+
## 4. Signal vs authority
|
|
56
|
+
|
|
57
|
+
The queue rung takes no destructive action — it waits for capacity then returns a real answer, or
|
|
58
|
+
falls through. The two `onDegrade` emissions (`queued` / `queue-rejected`) are observability signals
|
|
59
|
+
(D7), never gates. Consistent with Signal-vs-Authority.
|
|
60
|
+
|
|
61
|
+
## 5. Interactions — wedge-safety
|
|
62
|
+
|
|
63
|
+
Reuses the EXISTING `LlmQueue` (the wedge-safe, bounded, daily-capped queue). The new drain-pacing is
|
|
64
|
+
a bounded `setTimeout` coalesced to at most one pending timer (no stacking), `unref`'d (never holds the
|
|
65
|
+
process open). No new recursion, no growing array, no `report()`/`reportEvent()` call from the rung —
|
|
66
|
+
the 2026-06-21 DegradationReporter wedge class cannot recur here. The dedicated queue is built only
|
|
67
|
+
when the rung is active, so the fleet allocates nothing.
|
|
68
|
+
|
|
69
|
+
## 6. External surfaces
|
|
70
|
+
|
|
71
|
+
No new route. No new egress — a queued call is the SAME provider.evaluate that would otherwise have
|
|
72
|
+
run; it just waits for capacity. The new config (`intelligence.degradationLadder.queue.*`) is opt-in.
|
|
73
|
+
|
|
74
|
+
## Framework generality
|
|
75
|
+
|
|
76
|
+
Framework-agnostic — the rung keys on the resolved framework and enqueues whatever provider the
|
|
77
|
+
component routes to.
|
|
78
|
+
|
|
79
|
+
## 7. Multi-machine posture
|
|
80
|
+
|
|
81
|
+
Machine-local: each machine's router + its dedicated queue are independent. No replicated state, no
|
|
82
|
+
cross-machine contract (the dedicated queue is per-process, same posture as the existing per-sentinel
|
|
83
|
+
queues).
|
|
84
|
+
|
|
85
|
+
## 8. Rollback cost
|
|
86
|
+
|
|
87
|
+
Trivial: dark on the fleet (`queueEnabled` resolves dark; no dedicated queue is built, the ladder's
|
|
88
|
+
`queueEnabled` is false, and `tryDeferrableQueue` returns `{ ok: false }` immediately ⇒ exactly
|
|
89
|
+
today's heuristic-on-exhaustion). Revert = remove an unused-on-fleet code path. `drainMinGapMs` defaults
|
|
90
|
+
0 so existing `LlmQueue` callers are untouched.
|
|
91
|
+
|
|
92
|
+
## Evidence pointers
|
|
93
|
+
|
|
94
|
+
- `tests/unit/degradation-ladder.test.ts` (+7 queue cases): queue success + onResolved; order
|
|
95
|
+
backoff/swap → queue → success; GATING never queued (D5); enqueue REJECTION ⇒ heuristic fallthrough
|
|
96
|
+
+ onHeuristicFallthrough; non-deferrable never queued; queueEnabled-but-no-llmQueue no-op;
|
|
97
|
+
queueEnabled:false not enqueued.
|
|
98
|
+
- `tests/unit/LlmQueue.test.ts` (+3 pacing cases): paces a 2nd background dispatch when the gap is set;
|
|
99
|
+
no pacing when off (both start at once); interactive bypasses pacing.
|
|
100
|
+
- `tests/unit/devGatedFeatures-wiring.test.ts` auto-covers `degradationLadderQueue` (live-on-dev /
|
|
101
|
+
dark-on-fleet). `tests/unit/no-silent-fallbacks.test.ts` stays at baseline 476. Full `tsc` +
|
|
102
|
+
`lint-dev-agent-dark-gate` green.
|
|
103
|
+
|
|
104
|
+
## Conclusion
|
|
105
|
+
|
|
106
|
+
Delivers the final rung of the operator's degradation principle — a deferrable call now WAITS for
|
|
107
|
+
capacity (slow down) before ever dropping to a brittle heuristic, with the provider breaker supplying
|
|
108
|
+
rate-awareness and an opt-in herd gap on top. Dark/dev-gated, no-op when off, wedge-safe. Ship.
|