@aragon-agent/cli 0.6.21 → 0.6.23

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.
@@ -24,13 +24,20 @@
24
24
  * is 72 000 bytes, so a character-denominated cap would let the executor chop
25
25
  * the report mid-section and take the failure count with it.
26
26
  */
27
+ /**
28
+ * The two factors of the dispatch-total look budget (R-P1-6), hoisted only so
29
+ * `TEAM_LIMITS.overseerMaxLooksPerDispatch` can state their product without a
30
+ * second copy of either number. Not for export: the authority is TEAM_LIMITS.
31
+ */
32
+ const HARD_MAX_SUBAGENTS = 10;
33
+ const OVERSEER_MAX_LOOKS_PER_CHILD = 12;
27
34
  export const TEAM_LIMITS = {
28
35
  /**
29
36
  * The requirement's ceiling (R-g). Enforced in `clampTeamConfig` AND in
30
37
  * `normalizeSubagentSpecs`, so neither a hand-edited file nor a model asking
31
38
  * for thirty can exceed it.
32
39
  */
33
- hardMaxSubagents: 10,
40
+ hardMaxSubagents: HARD_MAX_SUBAGENTS,
34
41
  // --- Spec normalization (§3.3.1) ---
35
42
  /** `SubagentSpec.description`, clamped (never rejected). */
36
43
  descriptionChars: 60,
@@ -106,13 +113,14 @@ export const TEAM_LIMITS = {
106
113
  * nothing a re-dispatch by the lead would not buy better. */
107
114
  maxColdStartRetries: 1,
108
115
  retryBackoffMs: 2_000,
109
- // --- The dispatch supervisor (team-overseer) ---
116
+ // --- The dispatch supervisor (team-overseer / subagent-overseer-v2) ---
110
117
  /**
111
- * Wall-clock budget of everything one inspection may carry. The digest holds
112
- * run facts, the supervisor's own memory and the tail of the child's live
113
- * history; unbounded, one look at a child that read five big files would
114
- * make the "cheap" supervision call cost more than the child (the argument
115
- * FAST_LIMITS.digestMaxChars makes, one level up).
118
+ * Wall-clock budget of everything one SINGLE inspection may carry (the
119
+ * silence-triggered path). The digest holds run facts, the supervisor's own
120
+ * memory and the tail of the child's live history; unbounded, one look at a
121
+ * child that read five big files would make the "cheap" supervision call
122
+ * cost more than the child (the argument FAST_LIMITS.digestMaxChars makes,
123
+ * one level up).
116
124
  */
117
125
  overseerDigestBytes: 8_000,
118
126
  /** Clamp on a `nudge` guidance text. Advice, not a second brief. */
@@ -120,11 +128,48 @@ export const TEAM_LIMITS = {
120
128
  /** Clamp on the decision `reason` recorded in the report. */
121
129
  overseerReasonChars: 200,
122
130
  /**
123
- * Inspections PER CHILD per dispatch. An indecisive supervisor must stop
124
- * burning fast-tier calls; past the budget the child simply runs under its
125
- * hard ceilings and the supervisor goes quiet.
131
+ * Per-child slice of a BATCH digest (D-3 / R-P2-5). 6.7x tighter than the
132
+ * single-inspection budget above: a batch carries up to ten children in one
133
+ * call, and memory plus the history tail are the first to give way (the
134
+ * facts-first assembly order already puts them last).
135
+ */
136
+ overseerPerChildDigestBytes: 1_200,
137
+ /** Whole-batch digest ceiling (D-3): 10 children x 1 200 B fits exactly. */
138
+ overseerBatchDigestBytes: 12_000,
139
+ /**
140
+ * Output budget of ONE batch inspection (R-P0-1). The single-inspection path
141
+ * keeps `FAST_LIMITS.reviewOutputTokens` (512); a batch must return up to
142
+ * ten decision objects, and 512 tokens cannot physically hold ten x
143
+ * (reason <= 200 + guidance <= 1200). A truncated batch reply fails
144
+ * "first `[` to last `]`" parsing and degrades to all-wait - exactly the
145
+ * failure this separate, larger budget exists to prevent.
146
+ */
147
+ overseerBatchOutputTokens: 2_048,
148
+ /** Tighter `reason` clamp inside the batch protocol (R-P0-1). */
149
+ overseerBatchReasonChars: 80,
150
+ /** Tighter `guidance` clamp inside the batch protocol (R-P0-1). */
151
+ overseerBatchGuidanceChars: 400,
152
+ /**
153
+ * LOOKS per child per dispatch (D-5). A look is cost, not mutation: every
154
+ * inspection of a child - silence-triggered, cadence tick or post-mortem -
155
+ * spends one, including a call that failed softly. Twelve with the cadence
156
+ * ladder covers hours of healthy slow work; past the budget the supervisor
157
+ * says so once (`trigger: 'quiet'`) and stops waking that child up.
158
+ */
159
+ overseerMaxLooksPerChild: 12,
160
+ /**
161
+ * LOOKS per dispatch, the fool-proof total (R-P1-6):
162
+ * hardMaxSubagents x overseerMaxLooksPerChild = 120. A mathematical upper
163
+ * bound, not a tuning knob - the per-child budget always binds first; this
164
+ * one exists so a bug cannot loop calls forever. When it trips, the whole
165
+ * MonitorLoop stops with one aggregate notice.
126
166
  */
127
- overseerMaxInspectionsPerChild: 4,
167
+ overseerMaxLooksPerDispatch: HARD_MAX_SUBAGENTS * OVERSEER_MAX_LOOKS_PER_CHILD,
168
+ /**
169
+ * NUDGES per child per dispatch (D-5). Advice is cheap but not free: a
170
+ * supervisor that steers the same child forever is one that never decided.
171
+ */
172
+ overseerMaxNudgesPerChild: 3,
128
173
  /**
129
174
  * Rebuilds PER CHILD per dispatch. One: a replacement that also stalls dies
130
175
  * on its own watchdog rather than ping-ponging fresh children at a task the
@@ -132,13 +177,25 @@ export const TEAM_LIMITS = {
132
177
  */
133
178
  overseerMaxReplacementsPerChild: 1,
134
179
  /**
135
- * First wall-clock check when `team.subagentTimeoutMs === 0` (the shipped
136
- * default): the supervisor still looks even when no ceiling was configured.
180
+ * Abandons PER CHILD per dispatch (D-5). One, so a supervisor that has
181
+ * already given up on a brief cannot keep re-killing bodies of it.
182
+ */
183
+ overseerMaxAbandonsPerChild: 1,
184
+ /**
185
+ * Cadence ladder growth factor (D-2). Each no-action inspection schedules
186
+ * the next `previous * ratio` out, so a healthy slow child is looked at
187
+ * logarithmically in its run time rather than every five minutes.
188
+ */
189
+ overseerCadenceRatio: 1.6,
190
+ /**
191
+ * First cadence check when neither `team.overseerIntervalMs` nor
192
+ * `team.subagentTimeoutMs` names one (the shipped defaults): the supervisor
193
+ * still looks even when no ceiling was configured.
137
194
  */
138
195
  overseerDefaultCheckMs: 300_000,
139
- /** Clamp on the model-chosen `nextCheckMs`, lower bound. */
196
+ /** Clamp on a ladder step / model-chosen `nextCheckMs`, lower bound. */
140
197
  overseerNextCheckMinMs: 60_000,
141
- /** Clamp on the model-chosen `nextCheckMs`, upper bound. */
198
+ /** Clamp on a ladder step / model-chosen `nextCheckMs`, upper bound. */
142
199
  overseerNextCheckMaxMs: 900_000,
143
200
  /**
144
201
  * A child's OWN idle watchdog, multiplied by this while the supervisor is
@@ -148,6 +205,16 @@ export const TEAM_LIMITS = {
148
205
  */
149
206
  overseerWatchdogFactor: 4,
150
207
  };
208
+ /**
209
+ * The pseudo-label the runtime's AGGREGATE supervisor notices travel under
210
+ * (subagent-overseer-v2 D-5 / R-P1-6): the dispatch-total look-budget notice
211
+ * is one fact about the whole roster, not a row any child owns. RESERVED at
212
+ * normalization (`normalizeSubagentSpecs` seeds `dedupeLabel` with it), so a
213
+ * spec asking for the bare label `team` is handed `team-2` instead - the
214
+ * report ledger and the exec stream can then never attribute an aggregate
215
+ * notice to a real child, or swallow that child's own quiet note.
216
+ */
217
+ export const TEAM_AGGREGATE_LABEL = 'team';
151
218
  /**
152
219
  * The two comm tools, which are POLICY-EXEMPT inside a child (§3.11).
153
220
  *
@@ -24,7 +24,7 @@
24
24
  * honest reading of a stale key is silence, not a report line about a
25
25
  * capability that no longer exists.
26
26
  */
27
- import { TEAM_LIMITS } from './limits.js';
27
+ import { TEAM_AGGREGATE_LABEL, TEAM_LIMITS } from './limits.js';
28
28
  function asString(value) {
29
29
  return typeof value === 'string' ? value : '';
30
30
  }
@@ -88,7 +88,12 @@ export function normalizeSubagentSpecs(raw, max) {
88
88
  return { specs: [], requested: 0 };
89
89
  const requested = raw.length;
90
90
  const kept = [];
91
- const taken = new Set();
91
+ // SEEDED WITH THE RESERVED AGGREGATE LABEL (subagent-overseer-v2 D-5 /
92
+ // R-P1-6): the runtime's dispatch-total supervisor notices travel under
93
+ // `TEAM_AGGREGATE_LABEL`, so no child may wear that slug - `dedupeLabel`
94
+ // hands a spec asking for it the suffixed form instead, the same namespace
95
+ // fix it already applies to any other collision.
96
+ const taken = new Set([TEAM_AGGREGATE_LABEL]);
92
97
  for (let i = 0; i < raw.length; i += 1) {
93
98
  const item = raw[i];
94
99
  if (!item || typeof item !== 'object')
@@ -1,33 +1,58 @@
1
1
  /**
2
- * The dispatch supervisor (team-overseer).
2
+ * The dispatch supervisor (team-overseer, upgraded by subagent-overseer-v2).
3
3
  *
4
4
  * ASCII ONLY: `src/team/**` is inside the glyph scanner's scope
5
5
  * (`glyphs.test.ts`), so no literal in this tree may hold a non-ASCII byte.
6
6
  *
7
7
  * A TIME CEILING ON A CHILD IS AN INSPECTION TRIGGER, NOT A DEATH SENTENCE.
8
- * When a child stalls (event silence) or simply runs long (the wall clock),
9
- * the supervisor looks at it through ONE bounded fast-tier call and decides:
8
+ * When a child stalls (event silence) or a cadence tick comes due, the
9
+ * supervisor looks at it through ONE bounded fast-tier call and decides:
10
10
  * keep waiting, steer a nudge in to help it recover, rebuild it with an
11
11
  * amended brief, or abandon it with a recorded reason. Only the supervisor
12
12
  * "decides"; the RUNTIME applies (see `runtime.ts`), because every child
13
13
  * lifecycle change must funnel through the worker loop that awaits it
14
14
  * (I-OV1).
15
15
  *
16
+ * THE SUPERVISOR IS A NO-LOOP, BOUNDED, REMEMBERED CALLEE - NOT AN AGENT
17
+ * (subagent-overseer-v2 D-1). The requirement says "a dedicated supervising
18
+ * subagent on the fast model"; it is satisfied by a per-dispatch, remembered,
19
+ * cadence-woken caller on the fast tier rather than a real `Agent.prompt()`
20
+ * loop, because a supervisor that can itself wedge needs a second supervisor.
21
+ *
22
+ * TWO INSPECTION SHAPES (D-3). Event silence triggers a SINGLE-child look
23
+ * (fast reaction to a suspected stall, unchanged from round 1); the cadence
24
+ * ladder triggers a BATCH look that carries every live child in one digest
25
+ * and returns one JSON array of per-child decisions. The batch call carries
26
+ * its own output budget (`overseerBatchOutputTokens`, R-P0-1): a full
27
+ * ten-child reply does not physically fit in the single-inspection 512
28
+ * tokens, and a truncated reply would parse to nothing - all wait, exactly
29
+ * when help is most needed.
30
+ *
16
31
  * THE TRANSPORT IS THE REVIEWER'S, DELIBERATELY. One `complete` call, no
17
- * tools, thinking off, temperature 0, output capped at
18
- * `FAST_LIMITS.reviewOutputTokens` and wall clock at
19
- * `FAST_LIMITS.reviewTimeoutMs` — a supervision call that could itself hang
20
- * would need a second supervisor, which is the regress this design refuses.
32
+ * tools, thinking off, temperature 0, output capped (512 single /
33
+ * 2048 batch) and wall clock at `FAST_LIMITS.reviewTimeoutMs` — a
34
+ * supervision call that could itself hang would need a second supervisor,
35
+ * which is the regress this design refuses.
21
36
  *
22
37
  * REPAIR, NEVER REJECT (the `normalizeSubagentSpecs` rule). An unparseable
23
38
  * or out-of-budget decision becomes `wait` with the default interval: the
24
39
  * failure mode of a supervisor must be "looked and let it run", never
25
- * "looked and killed it" (I-OV2).
40
+ * "looked and killed it" (I-OV2). In a batch, one bad ENTRY degrades only
41
+ * that entry; a wholly unparseable reply degrades the whole batch to wait
42
+ * with zero action side effects (R-P0-1 / AC-13).
26
43
  */
27
- import type { AssistantMessage, LLMRequest, Message } from '@aragon-agent/core';
44
+ import type { AssistantMessage, LLMRequest, Message, TokenUsage } from '@aragon-agent/core';
28
45
  import type { ModelRole } from '../config/model-profiles.js';
29
46
  import type { CliConfig } from '../config/schema.js';
30
47
  import type { OverseerAction, OverseerDecision, SubagentRun, SubagentSpec } from './types.js';
48
+ /**
49
+ * Bumped whenever either supervisor protocol prompt changes (D-9), so a
50
+ * behaviour report can be tied to a prompt revision with one grep.
51
+ * `TEAM_BLOCK_VERSION` covers only the LEAD's `<team>` block, not these.
52
+ *
53
+ * v3 adds the turn-cap trigger to the single-inspection prompt (F-8 A'2).
54
+ */
55
+ export declare const OVERSEER_PROMPT_VERSION = "v3-2026-10";
31
56
  /** One remembered decision, so the second look knows the first happened. */
32
57
  export interface OverseerMemoryEntry {
33
58
  /** Seconds into the dispatch. */
@@ -40,7 +65,7 @@ export interface ChildDigestInput {
40
65
  run: SubagentRun;
41
66
  /** False only in the post-mortem inspection, after the child settled. */
42
67
  childAlive: boolean;
43
- trigger: 'silence' | 'clock' | 'postmortem';
68
+ trigger: 'silence' | 'clock' | 'turncap' | 'postmortem';
44
69
  /** The child's LIVE history (`SubagentAgentLike.state.messages`). */
45
70
  messages: readonly Message[];
46
71
  memory: readonly OverseerMemoryEntry[];
@@ -57,6 +82,38 @@ export interface ChildDigestInput {
57
82
  * is worse than one missing the fifth message back.
58
83
  */
59
84
  export declare function buildChildDigest(input: ChildDigestInput): string;
85
+ /**
86
+ * The per-child sections of one batch payload (D-3).
87
+ *
88
+ * SORTED BY LABEL so the same roster produces the byte-identical payload -
89
+ * the batch is the one place where ordering is observable to the model and
90
+ * to every test that asserts on it. Each child's digest is clamped to
91
+ * `overseerPerChildDigestBytes` (facts first, history tail last - R-P2-5).
92
+ * The whole-batch ceiling is applied by the joiner in the provider request.
93
+ */
94
+ export declare function buildBatchSections(children: readonly ChildDigestInput[]): Array<{
95
+ label: string;
96
+ goal: string;
97
+ digest: string;
98
+ }>;
99
+ /**
100
+ * The FIRST cadence check, from the D-8 priority: `overseerIntervalMs` when
101
+ * the user named one; otherwise a positive `subagentTimeoutMs` (compat with
102
+ * users who already treated it as a trigger); otherwise the structural
103
+ * default. Read-only derivation - the user's stored config is never
104
+ * rewritten to "resolve" this.
105
+ */
106
+ export declare function resolveOverseerFirstCheckMs(team: {
107
+ overseerIntervalMs: number;
108
+ subagentTimeoutMs: number;
109
+ }): number;
110
+ /**
111
+ * The next ladder step after one that produced no action: grow by
112
+ * `overseerCadenceRatio`, clamped to the structural range. With the shipped
113
+ * 300 s base the checks land at 300 / 780 / 1548 / 2448 / ... seconds - a
114
+ * healthy slow child is looked at logarithmically in its run time (AC-11).
115
+ */
116
+ export declare function nextOverseerLadderStepMs(previousMs: number): number;
60
117
  /** Clamp a model-chosen next check into the structural range. */
61
118
  export declare function clampNextCheckMs(ms: unknown): number | undefined;
62
119
  /**
@@ -66,6 +123,10 @@ export declare function clampNextCheckMs(ms: unknown): number | undefined;
66
123
  * replaced or abandoned, never waited on or nudged, so those normalize to
67
124
  * `abandon` rather than being rejected — a post-mortem answer the protocol
68
125
  * cannot honour must still produce a decision the runtime can apply.
126
+ *
127
+ * The single-inspection char limits (200/1200) are the defaults here; the
128
+ * batch path calls `normalizeWithLimits` directly with the tighter protocol
129
+ * limits (R-P0-1).
69
130
  */
70
131
  export declare function normalizeOverseerDecision(raw: unknown, childAlive: boolean): OverseerDecision;
71
132
  /**
@@ -76,16 +137,47 @@ export declare function normalizeOverseerDecision(raw: unknown, childAlive: bool
76
137
  * `wait` — the caller never sees a throw from parsing.
77
138
  */
78
139
  export declare function parseOverseerDecisionText(text: string, childAlive: boolean): OverseerDecision;
79
- /** The slice the runtime needs: "can you look?" and "decide". */
140
+ /**
141
+ * Parse the model's answer text as a JSON ARRAY of per-child decisions (D-3).
142
+ *
143
+ * Same forgiving span rule as the single path - first `[` to last `]` - and
144
+ * the same failure semantics: a reply that is not an array (prose, a single
145
+ * object, or TRUNCATED output with no closing `]`) is `[]`, which the caller
146
+ * turns into all-wait with zero action side effects (R-P0-1 / AC-13). Never
147
+ * throws.
148
+ */
149
+ export declare function parseOverseerBatchText(text: string): unknown[];
150
+ /**
151
+ * The slice the runtime needs: "can you look?", "decide", "what did looking
152
+ * cost?". The provider is the CALL boundary; `TeamOverseer` owns budgets,
153
+ * memory and normalization, so a stub in a test scripts decisions by
154
+ * returning objects or arrays and nothing else.
155
+ */
80
156
  export interface OverseerProvider {
81
- /** Live predicate, re-read per dispatch AND per inspection. */
157
+ /** Live predicate, re-read per tick: this, not the dispatch-time value, decides assisted vs unassisted (R-P0-2). */
82
158
  active(): boolean;
83
- /** One bounded decision call. Implementations must not throw. */
159
+ /** One bounded SINGLE-child decision call (silence path). Must not throw. */
84
160
  inspect(req: {
85
161
  label: string;
86
162
  goal: string;
87
163
  digest: string;
88
164
  }): Promise<OverseerDecision>;
165
+ /**
166
+ * One bounded BATCH call (cadence path, D-3). Returns the RAW reply - the
167
+ * fast provider answers the assistant TEXT - for `TeamOverseer` to parse
168
+ * and normalize. Must not throw.
169
+ */
170
+ inspectBatch(req: ReadonlyArray<{
171
+ label: string;
172
+ goal: string;
173
+ digest: string;
174
+ }>): Promise<unknown>;
175
+ /**
176
+ * Everything this provider has spent on inspection calls (D-7, honest
177
+ * accounting). Read once by the runtime at dispatch end; there is exactly
178
+ * one accounting of it and no second aggregation path.
179
+ */
180
+ usage(): TokenUsage;
89
181
  }
90
182
  /** Everything the fast-tier-backed provider needs from the session. */
91
183
  export interface FastOverseerDeps {
@@ -102,13 +194,18 @@ export interface FastOverseerDeps {
102
194
  * The fast-tier-backed provider, mirroring `createChildReviewer`'s shape so
103
195
  * the controller wires it the same way: shared transport, live predicates,
104
196
  * fail-soft (any failure resolves to `wait` — I-OV2).
197
+ *
198
+ * USAGE IS ACCUMULATED HERE (D-7), off every `AssistantMessage` the shared
199
+ * transport returns, along the same `usageOf` / `accumulateUsage` path the
200
+ * fast reviewer already proved. A reply without a usage block contributes
201
+ * nothing rather than a fabricated zero-cost total.
105
202
  */
106
203
  export declare function createFastOverseerProvider(deps: FastOverseerDeps): OverseerProvider;
107
204
  /** One inspection request, as the runtime builds it. */
108
205
  export interface OverseerInspectRequest {
109
206
  run: SubagentRun;
110
207
  messages: readonly Message[];
111
- trigger: 'silence' | 'clock' | 'postmortem';
208
+ trigger: 'silence' | 'clock' | 'turncap' | 'postmortem';
112
209
  childAlive: boolean;
113
210
  }
114
211
  export interface TeamOverseerOptions {
@@ -123,27 +220,70 @@ export declare const OVERSEER_DEFAULT_NEXT_CHECK_MS: 300000;
123
220
  * THE CLASS NEVER TOUCHES A CHILD (I-OV1). It looks and decides; `runtime.ts`
124
221
  * steers, flags, aborts and rebuilds, because only the worker loop can apply
125
222
  * a lifecycle change without orphaning the replacement.
223
+ *
224
+ * LOOKS AND ACTIONS ARE SEPARATE LEDGERS (D-5). A LOOK is cost: every
225
+ * inspection of a child spends one, including a call that failed softly -
226
+ * which is what closes G-6 (a flaky transport used to burn the budget the
227
+ * same as a decision, and the supervisor went quiet exactly when the team
228
+ * was hardest to see). An ACTION is a mutation (nudge / replace / abandon)
229
+ * and is counted only when the runtime APPLIES it, through the `note*`
230
+ * methods below. A label skipped because an inspection is already in flight
231
+ * spends NOTHING (R-P1-4).
126
232
  */
127
233
  export declare class TeamOverseer {
128
234
  private readonly provider;
129
235
  private readonly options;
130
236
  private readonly memory;
131
- private readonly inspections;
237
+ private readonly looks;
238
+ private readonly nudges;
132
239
  private readonly replacements;
240
+ private readonly abandons;
133
241
  private readonly inFlight;
242
+ private looksTotal;
243
+ private callCount;
134
244
  constructor(provider: OverseerProvider, options: TeamOverseerOptions);
135
245
  /** Never throws: a provider bug must not take the dispatch down. */
136
246
  isActive(): boolean;
137
- inspectionsExhausted(label: string): boolean;
247
+ /** Whether ANY inspection of `label` is in flight (single or batch). */
248
+ isInFlight(label: string): boolean;
249
+ /** Per-child look budget spent (D-5). */
250
+ looksExhausted(label: string): boolean;
251
+ /** The fool-proof dispatch-wide total (R-P1-6). */
252
+ dispatchLooksExhausted(): boolean;
253
+ nudgesLeft(label: string): boolean;
138
254
  replacementsLeft(label: string): boolean;
255
+ abandonsLeft(label: string): boolean;
256
+ /** Called by the runtime when it APPLIES a nudge, not when it merely reads one. */
257
+ noteNudge(label: string): void;
139
258
  /** Called by the runtime when it APPLIES a replace, not when it merely reads one. */
140
259
  noteReplacement(label: string): void;
260
+ /** Called by the runtime when it APPLIES an abandon, not when it merely reads one. */
261
+ noteAbandon(label: string): void;
262
+ /** The provider's own accumulated inspection spend (D-7), zero when unreadable. */
263
+ usage(): TokenUsage;
264
+ /** Provider invocations, including ones that failed softly (D-7). */
265
+ calls(): number;
141
266
  /**
142
- * ONE inspection. `null` means QUIET — not active, no budget left, or one
143
- * already in flight for this child — and the caller then does nothing,
267
+ * ONE single-child inspection (the silence-triggered path, round-1
268
+ * behaviour preserved). `null` means QUIET — not active, no budget left, or
269
+ * one already in flight for this child — and the caller then does nothing,
144
270
  * which is exactly what quiet should do.
145
271
  */
146
272
  inspect(req: OverseerInspectRequest): Promise<OverseerDecision | null>;
273
+ /**
274
+ * ONE batch inspection over every requested child (the cadence path, D-3):
275
+ * a single fast-tier call, a JSON array back, one decision per child.
276
+ *
277
+ * SKIPS FIRST, CALLS SECOND (R-P1-4): a label whose single inspection is
278
+ * still in flight, or whose look budget is spent, simply gets NO entry -
279
+ * no decision, no look charged, ladder untouched by the caller. A label
280
+ * that IS carried but whose reply entry is missing or garbage gets `wait`
281
+ * (repair, never reject). A wholly unparseable or truncated reply is ALL
282
+ * wait with zero action side effects (R-P0-1 / AC-13).
283
+ */
284
+ inspectBatch(reqs: readonly OverseerInspectRequest[]): Promise<Map<string, OverseerDecision>>;
285
+ private spendLook;
286
+ private remember;
147
287
  }
148
288
  /**
149
289
  * Prepend the supervisor's note to a spec's prompt, bounding the TOTAL to