instar 1.3.1313 → 1.3.1314
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/core/types.d.ts +2 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/feedback-factory/drain/FeedbackDrainService.d.ts +16 -0
- package/dist/feedback-factory/drain/FeedbackDrainService.d.ts.map +1 -1
- package/dist/feedback-factory/drain/FeedbackDrainService.js +109 -45
- package/dist/feedback-factory/drain/FeedbackDrainService.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +2 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/upgrades/1.3.1314.md +52 -0
- package/upgrades/feedback-arbiter-chunking.eli16.md +35 -0
- package/upgrades/side-effects/feedback-arbiter-chunking.md +224 -0
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-10-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-10-02T05:08:31.181Z",
|
|
5
|
+
"instarVersion": "1.3.1314",
|
|
6
6
|
"entryCount": 203,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -1539,7 +1539,7 @@
|
|
|
1539
1539
|
"type": "subsystem",
|
|
1540
1540
|
"domain": "server",
|
|
1541
1541
|
"sourcePath": "src/server/AgentServer.ts",
|
|
1542
|
-
"contentHash": "
|
|
1542
|
+
"contentHash": "015d93053813a521d0f06087f9bea72a07bd76cc7ca424d584ffd9ea06e76508",
|
|
1543
1543
|
"since": "2025-01-01"
|
|
1544
1544
|
},
|
|
1545
1545
|
"subsystem:session-manager": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"generatedFrom": "source-tree",
|
|
4
4
|
"registrySha256": "35448db940d659661ebdfb09761439033f93a15157540ee2f6eecf825488e1e6",
|
|
5
|
-
"packageVersion": "1.3.
|
|
5
|
+
"packageVersion": "1.3.1314",
|
|
6
6
|
"guards": [
|
|
7
7
|
{
|
|
8
8
|
"ref": "docs/audits/phase-b/f10-triage.md",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sha256": "
|
|
2
|
+
"sha256": "7fe553525422086106fb8b43578a16daaea997b7f6ef9f77c93399071cc9f00e",
|
|
3
3
|
"registrySha256": "35448db940d659661ebdfb09761439033f93a15157540ee2f6eecf825488e1e6",
|
|
4
|
-
"packageVersion": "1.3.
|
|
4
|
+
"packageVersion": "1.3.1314"
|
|
5
5
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The feedback drain's readiness stage sent all due clusters, up to the authority's
|
|
9
|
+
`maxBatch`, to the registered model in one call. Live, at about 3-4 s per candidate, a
|
|
10
|
+
50-candidate call hit the 60 s call budget every time, and the run degraded with
|
|
11
|
+
`readiness-authority-failed`.
|
|
12
|
+
|
|
13
|
+
- A tick now reviews its due clusters in sequential calls of at most
|
|
14
|
+
`feedbackFactory.drain.readinessChunkSize` (default 10). The total per tick is still capped
|
|
15
|
+
at the authority's `maxBatch`.
|
|
16
|
+
- Later calls are sized from the pace measured earlier in the same tick, so the last call
|
|
17
|
+
still fits the tick's wall clock. 20 s is kept for the stages after readiness. Rows not
|
|
18
|
+
reached stay due for the next tick.
|
|
19
|
+
- Each call's decisions apply as it returns. A later failure no longer discards them.
|
|
20
|
+
- Spend is reserved per call, against the same daily cap.
|
|
21
|
+
- A contract violation still demotes the authority at once. A tick with any successful call
|
|
22
|
+
resets the transient-failure count. A tick in which every call failed counts once (3 in a
|
|
23
|
+
row demote).
|
|
24
|
+
- `feedbackFactory.drain.maxWallClockMs` is now honoured. It was declared (90 s, as the spec
|
|
25
|
+
says) but ignored, so the service ran on 115 s.
|
|
26
|
+
|
|
27
|
+
Prompt and schema versions are unchanged, so the registered authority stays valid.
|
|
28
|
+
|
|
29
|
+
## What to Tell Your User
|
|
30
|
+
|
|
31
|
+
The feedback sorter was asking its model about too many feedback groups at once, and the
|
|
32
|
+
model ran out of time every time. It now asks about ten at a time and keeps going while time
|
|
33
|
+
allows. Earlier answers are kept even if a later question fails. Nothing for you to do.
|
|
34
|
+
|
|
35
|
+
## Summary of New Capabilities
|
|
36
|
+
|
|
37
|
+
- The feedback drain reviews readiness in time-bounded chunks (`feedbackFactory.drain.readinessChunkSize`, default 10).
|
|
38
|
+
|
|
39
|
+
## Evidence
|
|
40
|
+
|
|
41
|
+
From the Mac Studio's live store (a read-only copy):
|
|
42
|
+
- Runs 2b4bebb3 and 0e7b229a: 50 candidates, 60.1 s each, both timeouts.
|
|
43
|
+
- Run 20c4fac7: 10 candidates, 32.6 s, succeeded.
|
|
44
|
+
|
|
45
|
+
Tests replay the recorded gpt-6-astra replies with that latency shape:
|
|
46
|
+
- At a 90 s tick, the calls are 10, 10 and 2 (22 clusters decided).
|
|
47
|
+
- A timeout on the second call keeps the first call's 5 `ready` decisions and resets the
|
|
48
|
+
failure count.
|
|
49
|
+
- The old single 50-candidate call times out.
|
|
50
|
+
|
|
51
|
+
Unit (11), integration (2) and e2e (1) cover this. Of the original 11, 10 fail on the pre-fix
|
|
52
|
+
source; the 11th guards the unchanged demotion rule.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# ELI16 — the feedback sorter asks about ten groups at a time
|
|
2
|
+
|
|
3
|
+
## The problem
|
|
4
|
+
|
|
5
|
+
The feedback sorter ("drain") groups similar bug reports. Then it asks a model which groups
|
|
6
|
+
are ready to become a task. It used to put up to 50 groups into one question.
|
|
7
|
+
|
|
8
|
+
The model takes about 3 to 4 seconds per group. Fifty groups need about three minutes, but
|
|
9
|
+
each question is allowed one minute. So the big question ran out of time every time. The
|
|
10
|
+
run failed and no group got a verdict. With ten groups per question, the answer came back
|
|
11
|
+
in about half a minute.
|
|
12
|
+
|
|
13
|
+
## The fix
|
|
14
|
+
|
|
15
|
+
The sorter now asks about at most ten groups per question, one question after another. It
|
|
16
|
+
keeps going until it reaches the run's group limit or runs low on time. Each answer is saved
|
|
17
|
+
as soon as it arrives. If a later question fails, the earlier answers still count.
|
|
18
|
+
|
|
19
|
+
Before each question it checks the clock. If the next question would not finish in time, it
|
|
20
|
+
stops and leaves the remaining groups for the next run. That run starts with them.
|
|
21
|
+
|
|
22
|
+
The rule for "the model is broken, stop trusting it" counts whole runs:
|
|
23
|
+
- A run where at least one question worked shows the model is fine, and resets the count.
|
|
24
|
+
- A run where every question failed counts once.
|
|
25
|
+
- Three such runs in a row switch the model off.
|
|
26
|
+
- A wrong-shaped answer still switches it off at once.
|
|
27
|
+
|
|
28
|
+
A setting for the run's time limit (90 seconds) existed but was never used. The sorter
|
|
29
|
+
quietly used 115 seconds. It now follows the setting.
|
|
30
|
+
|
|
31
|
+
## What does not change
|
|
32
|
+
|
|
33
|
+
The question wording, the answer format, the daily spending cap and the approved group
|
|
34
|
+
limit are the same. The spending cap is now checked before each question rather than once
|
|
35
|
+
per run.
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Side-Effects Review — feedback readiness reviewed in chunks
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `feedback-arbiter-chunking`
|
|
4
|
+
**Date:** `2026-10-01`
|
|
5
|
+
**Author:** `Echo`
|
|
6
|
+
**Second-pass reviewer:** `independent reviewer subagent (see below)`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
The operated feedback drain asks the registered readiness authority (gpt-6-astra via
|
|
11
|
+
codex-cli) which clusters are ready to become work. It sent every due candidate, up to the
|
|
12
|
+
authority's `maxBatch` (50), in ONE model call. Live on 2026-10-01 the model took about 3-4 s
|
|
13
|
+
per candidate: 10 candidates finished in ~31 s (run 20c4fac7, 32.6 s end to end) and 50 hit
|
|
14
|
+
the 60 s call budget twice in a row (runs 2b4bebb3 and 0e7b229a, 60.1 s each, both
|
|
15
|
+
`readiness-authority-failed`). A 50-candidate call can never fit the call budget.
|
|
16
|
+
|
|
17
|
+
`FeedbackDrainService` now reviews a tick's due candidates (still capped at the authority's
|
|
18
|
+
`maxBatch`) in sequential calls of at most `readinessChunkSize` (default 10). Before each call
|
|
19
|
+
it checks the time left for readiness (the tick's wall clock minus one 20 s stage budget kept
|
|
20
|
+
for the stages after readiness). The first call is a full chunk; later calls are sized from
|
|
21
|
+
the pace observed so far in that tick, with a 25% margin. Each call's budget is also capped by
|
|
22
|
+
the time left. When the next call would not fit, the loop stops cleanly: rows not reached stay
|
|
23
|
+
due, untouched, for the next tick. Each call's decisions are applied as soon as it returns. A
|
|
24
|
+
failed call stops the tick, and its own rows are marked `readiness-authority-failed`
|
|
25
|
+
(re-review in 15 min). Spend is reserved per call: one `estimatedReadinessBatchUsd` per call,
|
|
26
|
+
plus that call's decision count. Daily usage is still counted per decision.
|
|
27
|
+
|
|
28
|
+
Failure accounting: a contract violation (wrong model, schema, ids) still demotes the authority
|
|
29
|
+
at once in any call. A transient failure (timeout, provider error) counts ONE toward the
|
|
30
|
+
consecutive-failure limit only if no call in that tick succeeded. A tick with at least one
|
|
31
|
+
successful call resets the counter.
|
|
32
|
+
|
|
33
|
+
Also: `feedbackFactory.drain.maxWallClockMs` (90 s in config defaults, and 90 s in the approved
|
|
34
|
+
spec §203) was declared but never passed to the service. The service ran on its own 115 s
|
|
35
|
+
default. It is wired now, together with the new optional `readinessChunkSize`.
|
|
36
|
+
|
|
37
|
+
Files: `src/feedback-factory/drain/FeedbackDrainService.ts`, `src/server/AgentServer.ts`
|
|
38
|
+
(wiring), `src/core/types.ts` (config type). Prompt id, schema id, parser and
|
|
39
|
+
`FeedbackReadinessArbiter` are unchanged.
|
|
40
|
+
|
|
41
|
+
## Decision-point inventory
|
|
42
|
+
|
|
43
|
+
- `FeedbackReadinessArbiter.decideBatch` (`feedback-cluster-readiness`): pass-through. The
|
|
44
|
+
same prompt and schema now receive packets of at most 10 candidates instead of up to 50.
|
|
45
|
+
Every packet stays inside the registered `maxBatch` envelope.
|
|
46
|
+
- Authority transient-failure demotion (`FeedbackDrainService`): modify. The counter is now
|
|
47
|
+
per tick (any successful call resets it; an all-failed tick counts once) instead of per
|
|
48
|
+
single call.
|
|
49
|
+
- Spend brake (`reserveAuthoritySpend`): modify (granularity only). It is reserved per call
|
|
50
|
+
instead of per tick. The same cap applies, and a brake mid-tick keeps the earlier calls'
|
|
51
|
+
decisions.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 1. Over-block
|
|
56
|
+
|
|
57
|
+
No block/allow surface on user content. The one gating effect is on throughput: a tick can
|
|
58
|
+
now review fewer candidates than `maxBatch` when the wall clock runs short. Those rows are
|
|
59
|
+
not rejected; they stay due and the next tick reviews them first (the due order is
|
|
60
|
+
`next_review_at, cluster_id`).
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 2. Under-block
|
|
65
|
+
|
|
66
|
+
- A chunk that keeps timing out after one healthy chunk in every tick never reaches the
|
|
67
|
+
demotion limit. This is intentional: the tick is making progress. Each such tick still ends
|
|
68
|
+
`degraded` with `readiness-authority-failed`, and the job reports it as failed, so the
|
|
69
|
+
pattern stays visible.
|
|
70
|
+
- The per-candidate pace comes from earlier calls in the same tick. A sudden slowdown on a
|
|
71
|
+
later call can still overrun its slot. That call's budget is capped at the time left, so it
|
|
72
|
+
fails as a transient failure rather than blowing the tick's wall clock.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. Level-of-abstraction fit
|
|
77
|
+
|
|
78
|
+
This is the right layer. Batching is a drain-service concern: the service owns the tick
|
|
79
|
+
budget, the spend reservation and the failure accounting. The arbiter stays a single-call
|
|
80
|
+
authority adapter with its unchanged envelope check (`candidates.length <= maxBatch`). No
|
|
81
|
+
parallel gate is introduced.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 4. Signal vs authority compliance
|
|
86
|
+
|
|
87
|
+
- [x] No — this change has no block/allow surface.
|
|
88
|
+
|
|
89
|
+
The readiness judgment stays with the registered LLM authority. This change only decides how
|
|
90
|
+
many candidates go into each call and when to stop for the tick's time budget. Those are
|
|
91
|
+
resource limits, not judgments about the content.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 4b. Judgment-point check (Judgment Within Floors standard)
|
|
96
|
+
|
|
97
|
+
No new static heuristic at a competing-signals decision point. Chunk sizing is a resource
|
|
98
|
+
bound over a measured pace (time left / observed per-candidate latency). The readiness
|
|
99
|
+
decision itself remains the LLM authority's.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 5. Interactions
|
|
104
|
+
|
|
105
|
+
- Cancellation and ownership: `stopIfCancelled()` (owner fence, wall-clock assert, run-lease
|
|
106
|
+
heartbeat) runs after every call. A long tick therefore heartbeats its 120 s run lease after
|
|
107
|
+
each call, not only once.
|
|
108
|
+
- Later stages: readiness ends at least one 20 s stage budget before the tick's wall clock.
|
|
109
|
+
This guarantees each later stage its own per-stage budget, but not the whole tail (claims
|
|
110
|
+
allow up to maxClaims x 20 s, plus compaction). Before this change the unwired 115 s tick
|
|
111
|
+
left about 50 s after a 65 s call. Now, with the spec's 90 s, readiness can fill to 70 s
|
|
112
|
+
and leave 20 s. With the consumer in dry-run (live today), the tail is milliseconds. A
|
|
113
|
+
live consumer with slow claims could trip the wall-clock assert and fail the run. That is
|
|
114
|
+
named here; a later tick retries.
|
|
115
|
+
- Ownership loss, cancellation or the wall-clock assert after a call ends the run (failed or
|
|
116
|
+
cancelled), exactly like any later stage. It is not counted as a provider failure, and the
|
|
117
|
+
undecided chunk is left untouched.
|
|
118
|
+
- Job body (`feedback-factory-process`): unchanged. A tick that stops on the wall clock is
|
|
119
|
+
`succeeded` (or `no-op`). A failed call still yields `degraded` /
|
|
120
|
+
`readiness-authority-failed`, which the job reports.
|
|
121
|
+
- New reason `readiness-wall-clock-exhausted`. It appears only when earlier stages used the
|
|
122
|
+
whole readiness window and no call was made. The run is degraded and no transient failure
|
|
123
|
+
is counted.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 6. External surfaces
|
|
128
|
+
|
|
129
|
+
- Model spend: about 2-3 calls per tick instead of one. At the default $0.01 per call and 48
|
|
130
|
+
ticks a day, that is about $1.44/day, under the authority's $5/day cap. The cap is still
|
|
131
|
+
enforced, now before each call.
|
|
132
|
+
- Config: new optional `feedbackFactory.drain.readinessChunkSize`. There is no default in
|
|
133
|
+
ConfigDefaults (the code default is 10), so no migration is needed.
|
|
134
|
+
`maxWallClockMs` now takes effect: agents with the shipped 90 s default go from 115 s to
|
|
135
|
+
90 s per tick, which matches spec §203.
|
|
136
|
+
- No change to prompts, the schema, routes, the dashboard, messaging or the CLAUDE.md
|
|
137
|
+
template. The template's "three timeouts or provider errors in a row" wording still
|
|
138
|
+
describes the behaviour.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 6b. Operator-surface quality
|
|
143
|
+
|
|
144
|
+
Not applicable. No operator surface is touched.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
149
|
+
|
|
150
|
+
Unchanged. The drain runs only on the canonical owner machine (owner fence + epoch). Chunking
|
|
151
|
+
is internal to one owner's tick. Proxied ticks behave as before.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 8. Rollback cost
|
|
156
|
+
|
|
157
|
+
Low. Revert the commit. Setting `readinessChunkSize` to 50 gives back one call per tick
|
|
158
|
+
(which times out live), with no revert needed. No data shape changes: readiness rows, daily
|
|
159
|
+
usage rows and authority records are written with the same columns and meanings.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Conclusion
|
|
164
|
+
|
|
165
|
+
The change makes the operated readiness stage able to finish on real latency. It respects the
|
|
166
|
+
approved authority envelope (prompt, schema, `maxBatch`, spend cap). Earlier decisions are no
|
|
167
|
+
longer thrown away when a later call fails, and timeouts are not over-counted toward
|
|
168
|
+
demotion. It also brings the tick's wall clock back to the spec's 90 s.
|
|
169
|
+
|
|
170
|
+
Throughput, measured at ~3.1 s per candidate:
|
|
171
|
+
- About 22 candidates per tick at 90 s, about 30 at 115 s.
|
|
172
|
+
- Every tick is still capped by the authority's `maxBatch`. The live gen 3 authority is
|
|
173
|
+
narrowed to 10, so the drain stays at 10 per tick (480 a day at the 30-minute cadence)
|
|
174
|
+
until a generation with a larger `maxBatch` is registered.
|
|
175
|
+
|
|
176
|
+
## Second-pass review (if required)
|
|
177
|
+
|
|
178
|
+
**Reviewer:** independent reviewer subagent
|
|
179
|
+
**Independent read of the artifact: concur**
|
|
180
|
+
|
|
181
|
+
"Concur with the review". The reviewer ran the three new test files (8/8, 2/2, 1/1). The
|
|
182
|
+
non-blocking notes and what was done:
|
|
183
|
+
- Non-numeric `readinessChunkSize` / `maxWallClockMs` from config produced NaN, which stalls
|
|
184
|
+
or demotes. Fixed: they fall back to 10 and 115 s (unit test).
|
|
185
|
+
- A store error while applying decisions still counted as a success, and re-marked
|
|
186
|
+
already-approved rows. Fixed: success is counted after apply, and only rows still
|
|
187
|
+
`collecting` are marked failed (unit test).
|
|
188
|
+
- Ownership loss or the wall-clock assert inside the call's try was counted as a provider
|
|
189
|
+
failure. Fixed: `stopIfCancelled()` now runs outside it, so the run fails or cancels
|
|
190
|
+
(unit test).
|
|
191
|
+
- The §5 later-stage wording was inaccurate. Corrected above (named exposure for a live
|
|
192
|
+
consumer).
|
|
193
|
+
- Left as is (named):
|
|
194
|
+
- The first call is not sized to the time left (rare; bounded; one transient failure).
|
|
195
|
+
- When the time left is under 60 s, the service timer fires before the arbiter's own
|
|
196
|
+
timeout and the codex child keeps running. This is unchanged from before, and 30-minute
|
|
197
|
+
ticks never overlap.
|
|
198
|
+
|
|
199
|
+
## Evidence pointers
|
|
200
|
+
|
|
201
|
+
- Live latency shapes: the Mac Studio store's `drain_runs` (a read-only `.backup` copy). Runs
|
|
202
|
+
2b4bebb3 and 0e7b229a: 60.1 s, degraded `readiness-authority-failed` (50 candidates). Run
|
|
203
|
+
20c4fac7: 32.6 s, succeeded (10 candidates). The authority records show gen 3 with
|
|
204
|
+
`max_batch` 10.
|
|
205
|
+
- `tests/unit/feedback-factory/drain-readiness-chunking.test.ts` (11): fake clock at 3.1 s
|
|
206
|
+
per candidate, with a 60 s `CodexExecJsonTimeoutError`. Recorded gpt-6-astra decisions are
|
|
207
|
+
replayed through the unchanged parser. Of the first 8, 7 fail on the pre-fix source; the
|
|
208
|
+
8th guards the unchanged all-failed demotion rule. The last 3 cover the review fixes.
|
|
209
|
+
- `tests/integration/feedback-drain-readiness-chunking.test.ts` (2): AgentServer wiring of
|
|
210
|
+
both config fields and HTTP ticks. Both fail on the pre-fix source.
|
|
211
|
+
- `tests/e2e/feedback-drain-readiness-chunking.test.ts` (1): production wiring, the recorded
|
|
212
|
+
live reports and recorded replies. The second call times out, the first chunk survives, and
|
|
213
|
+
the next tick finishes the pass. It fails on the pre-fix source.
|
|
214
|
+
|
|
215
|
+
## Class-Closure Declaration (display-only mirror)
|
|
216
|
+
|
|
217
|
+
No agent-authored-artifact defect: the defect is in the drain's TypeScript batching. The
|
|
218
|
+
change modifies a bounded retry path inside a scheduled controller, so its convergence is
|
|
219
|
+
stated here:
|
|
220
|
+
- Control-loop edge: one tick makes at most `ceil(maxBatch / readinessChunkSize)` calls
|
|
221
|
+
(5 at most), and stops earlier on the wall clock.
|
|
222
|
+
- Steady-state bound: any failed call ends the tick's readiness stage.
|
|
223
|
+
- Settling brake: the authority demotes to proposal-only after 3 consecutive ticks with no
|
|
224
|
+
successful call, after any contract violation, or at the daily spend cap.
|