mixdog 0.9.39 → 0.9.41
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/package.json +2 -1
- package/scripts/agent-terminal-reap-test.mjs +6 -6
- package/scripts/anthropic-oauth-refresh-race-test.mjs +338 -0
- package/scripts/compact-pressure-test.mjs +128 -0
- package/scripts/compact-trigger-migration-smoke.mjs +8 -8
- package/scripts/execution-resume-esc-integration-test.mjs +4 -2
- package/scripts/internal-comms-smoke.mjs +66 -25
- package/scripts/max-output-recovery-persist-test.mjs +81 -0
- package/scripts/max-output-recovery-test.mjs +222 -0
- package/scripts/provider-toolcall-test.mjs +32 -0
- package/scripts/steering-drain-buckets-test.mjs +140 -5
- package/scripts/tui-transcript-perf-test.mjs +279 -0
- package/src/agents/reviewer/AGENT.md +4 -0
- package/src/rules/lead/lead-brief.md +11 -3
- package/src/rules/lead/lead-tool.md +0 -2
- package/src/rules/shared/01-tool.md +4 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +20 -2
- package/src/runtime/agent/orchestrator/agent-trace-format.mjs +7 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +7 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +144 -7
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +15 -2
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +2 -2
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +57 -25
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +54 -12
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +4 -3
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +106 -8
- package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +12 -1
- package/src/runtime/agent/orchestrator/session/loop/termination.mjs +22 -7
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +26 -1
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +17 -1
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +26 -0
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +31 -4
- package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +2 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +11 -2
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +45 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -1
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +43 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +49 -34
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +9 -10
- package/src/runtime/shared/buffered-appender.mjs +13 -2
- package/src/session-runtime/config-helpers.mjs +6 -6
- package/src/session-runtime/lifecycle-api.mjs +4 -0
- package/src/session-runtime/runtime-core.mjs +1 -0
- package/src/session-runtime/session-turn-api.mjs +12 -0
- package/src/standalone/agent-tool.mjs +8 -1
- package/src/tui/App.jsx +2 -1
- package/src/tui/app/transcript-window.mjs +9 -10
- package/src/tui/app/use-transcript-window.mjs +38 -56
- package/src/tui/dist/index.mjs +354 -163
- package/src/tui/engine/agent-job-feed.mjs +76 -6
- package/src/tui/engine/session-api.mjs +7 -1
- package/src/tui/engine/session-flow.mjs +3 -1
- package/src/tui/engine/tool-card-results.mjs +10 -5
- package/src/tui/engine/turn.mjs +96 -36
- package/src/tui/engine.mjs +136 -37
- package/src/tui/index.jsx +2 -2
- package/src/workflows/bench/WORKFLOW.md +51 -27
- package/src/workflows/default/WORKFLOW.md +29 -24
package/src/tui/engine.mjs
CHANGED
|
@@ -142,6 +142,87 @@ export { parseBackgroundTaskEnvelope };
|
|
|
142
142
|
// so importers/tests keep resolving resolveTuiRuntimeNotificationDelivery from engine.mjs.
|
|
143
143
|
export { resolveTuiRuntimeNotificationDelivery };
|
|
144
144
|
|
|
145
|
+
export function replaceEngineItemsState({
|
|
146
|
+
state,
|
|
147
|
+
items,
|
|
148
|
+
itemIndexById,
|
|
149
|
+
preserveStreamingTail = false,
|
|
150
|
+
extra = {},
|
|
151
|
+
}) {
|
|
152
|
+
const nextItems = Array.isArray(items) ? items : [];
|
|
153
|
+
itemIndexById.clear();
|
|
154
|
+
for (let i = 0; i < nextItems.length; i++) {
|
|
155
|
+
const id = nextItems[i]?.id;
|
|
156
|
+
if (id != null) itemIndexById.set(id, i);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
...state,
|
|
160
|
+
...extra,
|
|
161
|
+
items: nextItems,
|
|
162
|
+
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
163
|
+
streamingTail: preserveStreamingTail ? state.streamingTail : null,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Shared by the live engine and focused transcript tests so revision/tail
|
|
168
|
+
// regressions exercise the exact mutation implementation used in production.
|
|
169
|
+
export function createEngineItemMutators({ getState, set, itemIndexById }) {
|
|
170
|
+
const patchItem = (id, patch) => {
|
|
171
|
+
const state = getState();
|
|
172
|
+
let index = itemIndexById.get(id);
|
|
173
|
+
if (!Number.isInteger(index) || state.items[index]?.id !== id) {
|
|
174
|
+
index = state.items.findIndex((it) => it.id === id);
|
|
175
|
+
if (index >= 0) itemIndexById.set(id, index);
|
|
176
|
+
}
|
|
177
|
+
if (index < 0) return false;
|
|
178
|
+
const current = state.items[index];
|
|
179
|
+
let changed = false;
|
|
180
|
+
for (const [key, value] of Object.entries(patch || {})) {
|
|
181
|
+
if (!Object.is(current[key], value)) {
|
|
182
|
+
changed = true;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (!changed) return false;
|
|
187
|
+
const items = state.items.slice();
|
|
188
|
+
items[index] = { ...current, ...patch };
|
|
189
|
+
set({ items, structureRevision: (Number(state.structureRevision) || 0) + 1 });
|
|
190
|
+
return true;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const settleStreamingTail = (id, patch = {}, extra = {}) => {
|
|
194
|
+
const state = getState();
|
|
195
|
+
const tail = state.streamingTail?.id === id ? state.streamingTail : null;
|
|
196
|
+
// Bulk transcript replacement/reset owns the new transcript. A stale turn
|
|
197
|
+
// must never append into it after replaceItems deliberately cleared its tail.
|
|
198
|
+
if (!tail) return false;
|
|
199
|
+
let existingIndex = itemIndexById.get(id);
|
|
200
|
+
if (!Number.isInteger(existingIndex) || state.items[existingIndex]?.id !== id) {
|
|
201
|
+
existingIndex = state.items.findIndex((item) => item?.id === id);
|
|
202
|
+
}
|
|
203
|
+
if (existingIndex >= 0) return false;
|
|
204
|
+
const item = {
|
|
205
|
+
...(tail || {}),
|
|
206
|
+
...patch,
|
|
207
|
+
kind: 'assistant',
|
|
208
|
+
id,
|
|
209
|
+
streaming: false,
|
|
210
|
+
};
|
|
211
|
+
const index = state.items.length;
|
|
212
|
+
const items = [...state.items, item];
|
|
213
|
+
itemIndexById.set(id, index);
|
|
214
|
+
set({
|
|
215
|
+
items,
|
|
216
|
+
structureRevision: (Number(state.structureRevision) || 0) + 1,
|
|
217
|
+
streamingTail: null,
|
|
218
|
+
...extra,
|
|
219
|
+
});
|
|
220
|
+
return true;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return { patchItem, settleStreamingTail };
|
|
224
|
+
}
|
|
225
|
+
|
|
145
226
|
export async function createEngineSession({
|
|
146
227
|
provider: providerName,
|
|
147
228
|
model,
|
|
@@ -205,6 +286,8 @@ export async function createEngineSession({
|
|
|
205
286
|
};
|
|
206
287
|
let state = {
|
|
207
288
|
items: [],
|
|
289
|
+
structureRevision: 0,
|
|
290
|
+
streamingTail: null,
|
|
208
291
|
toasts: [],
|
|
209
292
|
progressHint: null,
|
|
210
293
|
busy: false,
|
|
@@ -283,13 +366,8 @@ export async function createEngineSession({
|
|
|
283
366
|
};
|
|
284
367
|
|
|
285
368
|
const itemIndexById = new Map();
|
|
286
|
-
const replaceItems = (items) => {
|
|
369
|
+
const replaceItems = (items, { preserveStreamingTail = false } = {}) => {
|
|
287
370
|
const nextItems = Array.isArray(items) ? items : [];
|
|
288
|
-
itemIndexById.clear();
|
|
289
|
-
for (let i = 0; i < nextItems.length; i++) {
|
|
290
|
-
const id = nextItems[i]?.id;
|
|
291
|
-
if (id != null) itemIndexById.set(id, i);
|
|
292
|
-
}
|
|
293
371
|
// Bulk item swap (session load / clear / compact). Derive the prompt-history
|
|
294
372
|
// list from the NEW items and stage it onto state here so App never rescans;
|
|
295
373
|
// the callers that invoke replaceItems always follow with a set({items:...,
|
|
@@ -297,12 +375,21 @@ export async function createEngineSession({
|
|
|
297
375
|
// emit (the accompanying set() diffs the full patch). A bulk swap also
|
|
298
376
|
// discards the old transcript, so drop any tracked active tool calls.
|
|
299
377
|
activeToolCalls.clear();
|
|
300
|
-
state = {
|
|
301
|
-
|
|
378
|
+
state = replaceEngineItemsState({
|
|
379
|
+
state,
|
|
302
380
|
items: nextItems,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
381
|
+
itemIndexById,
|
|
382
|
+
preserveStreamingTail,
|
|
383
|
+
extra: {
|
|
384
|
+
promptHistoryList: buildMergedPromptHistory(recomputePromptHistory(nextItems), loadPromptHistory(state.cwd)),
|
|
385
|
+
activeToolSummary: null,
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
// replaceItems stages the bulk state before its callers compose their
|
|
389
|
+
// accompanying patch. Emit here as well so an items-only replacement
|
|
390
|
+
// (for example removeNotice) cannot be hidden by the outer set seeing the
|
|
391
|
+
// already-installed array identity.
|
|
392
|
+
emit();
|
|
306
393
|
return nextItems;
|
|
307
394
|
};
|
|
308
395
|
// --- Prompt-history list (newest-first, deduped) maintained incrementally ---
|
|
@@ -371,11 +458,39 @@ export async function createEngineSession({
|
|
|
371
458
|
// first — set() diffs against the current state, so a pre-assign would make
|
|
372
459
|
// the references identical and skip emit().
|
|
373
460
|
const promptHistoryList = buildMergedPromptHistory(recomputePromptHistory(items), loadPromptHistory(state.cwd));
|
|
374
|
-
set({ items, promptHistoryList });
|
|
461
|
+
set({ items, structureRevision: state.structureRevision + 1, promptHistoryList });
|
|
375
462
|
} else {
|
|
376
|
-
set({ items });
|
|
463
|
+
set({ items, structureRevision: state.structureRevision + 1 });
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
const updateStreamingTail = (id, patch = {}, extra = {}) => {
|
|
467
|
+
if (id == null) return false;
|
|
468
|
+
const current = state.streamingTail?.id === id
|
|
469
|
+
? state.streamingTail
|
|
470
|
+
: { kind: 'assistant', id, text: '', streaming: true };
|
|
471
|
+
const next = { ...current, ...patch, kind: 'assistant', id, streaming: true };
|
|
472
|
+
let changed = state.streamingTail !== current;
|
|
473
|
+
if (!changed) {
|
|
474
|
+
for (const [key, value] of Object.entries(next)) {
|
|
475
|
+
if (!Object.is(current[key], value)) {
|
|
476
|
+
changed = true;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return set(changed ? { streamingTail: next, ...extra } : extra);
|
|
482
|
+
};
|
|
483
|
+
const clearStreamingTail = (id = null, extra = {}) => {
|
|
484
|
+
if (!state.streamingTail || (id != null && state.streamingTail.id !== id)) {
|
|
485
|
+
return set(extra);
|
|
377
486
|
}
|
|
487
|
+
return set({ streamingTail: null, ...extra });
|
|
378
488
|
};
|
|
489
|
+
const { patchItem, settleStreamingTail } = createEngineItemMutators({
|
|
490
|
+
getState: () => state,
|
|
491
|
+
set,
|
|
492
|
+
itemIndexById,
|
|
493
|
+
});
|
|
379
494
|
const upsertSyntheticToolItem = (text, id = nextId(), parsed = null) => {
|
|
380
495
|
const synthetic = parseSyntheticAgentMessage(text);
|
|
381
496
|
if (!synthetic) return false;
|
|
@@ -513,7 +628,7 @@ export async function createEngineSession({
|
|
|
513
628
|
if (id == null) return false;
|
|
514
629
|
const items = state.items.filter((it) => !(it?.kind === 'notice' && it?.id === id));
|
|
515
630
|
if (items.length === state.items.length) return false;
|
|
516
|
-
set({ items: replaceItems(items) });
|
|
631
|
+
set({ items: replaceItems(items, { preserveStreamingTail: true }) });
|
|
517
632
|
return true;
|
|
518
633
|
};
|
|
519
634
|
// Sticky (non-TTL) input-hint-line progress state, for long-running
|
|
@@ -538,27 +653,6 @@ export async function createEngineSession({
|
|
|
538
653
|
getDisposed: () => flags.disposed,
|
|
539
654
|
timeoutMs: TOOL_APPROVAL_TIMEOUT_MS,
|
|
540
655
|
});
|
|
541
|
-
const patchItem = (id, patch) => {
|
|
542
|
-
let index = itemIndexById.get(id);
|
|
543
|
-
if (!Number.isInteger(index) || state.items[index]?.id !== id) {
|
|
544
|
-
index = state.items.findIndex((it) => it.id === id);
|
|
545
|
-
if (index >= 0) itemIndexById.set(id, index);
|
|
546
|
-
}
|
|
547
|
-
if (index < 0) return false;
|
|
548
|
-
const current = state.items[index];
|
|
549
|
-
let changed = false;
|
|
550
|
-
for (const [key, value] of Object.entries(patch || {})) {
|
|
551
|
-
if (!Object.is(current[key], value)) {
|
|
552
|
-
changed = true;
|
|
553
|
-
break;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
if (!changed) return false;
|
|
557
|
-
const items = state.items.slice();
|
|
558
|
-
items[index] = { ...current, ...patch };
|
|
559
|
-
set({ items });
|
|
560
|
-
return true;
|
|
561
|
-
};
|
|
562
656
|
const toastTimers = new Set();
|
|
563
657
|
lifecycle.runtimePulseTimer = setInterval(() => {
|
|
564
658
|
if (flags.disposed) return;
|
|
@@ -587,6 +681,7 @@ export async function createEngineSession({
|
|
|
587
681
|
updateAgentJobCard,
|
|
588
682
|
buildAgentJobCardPatch,
|
|
589
683
|
subscribeRuntimeNotifications,
|
|
684
|
+
clearExecutionDedupState,
|
|
590
685
|
} = createAgentJobFeed({
|
|
591
686
|
runtime,
|
|
592
687
|
getState: () => state,
|
|
@@ -603,6 +698,7 @@ export async function createEngineSession({
|
|
|
603
698
|
agentStatusState,
|
|
604
699
|
displayedExecutionNotificationKeys,
|
|
605
700
|
pushNotice,
|
|
701
|
+
itemIndexById,
|
|
606
702
|
});
|
|
607
703
|
lifecycle.unsubscribeRuntimeNotifications = subscribeRuntimeNotifications();
|
|
608
704
|
|
|
@@ -627,19 +723,22 @@ export async function createEngineSession({
|
|
|
627
723
|
updateAgentJobCard,
|
|
628
724
|
buildAgentJobCardPatch,
|
|
629
725
|
agentStatusState,
|
|
726
|
+
itemIndexById,
|
|
630
727
|
});
|
|
631
728
|
|
|
632
729
|
|
|
633
730
|
Object.assign(bag, {
|
|
634
731
|
runtime, nextId, tuiDebug, LEAD_TURN_TIMEOUT_MS,
|
|
635
|
-
flags, lifecycle, pending, pendingNotificationKeys, displayedExecutionNotificationKeys, listeners, itemIndexById,
|
|
732
|
+
flags, lifecycle, pending, pendingNotificationKeys, displayedExecutionNotificationKeys, clearExecutionDedupState, listeners, itemIndexById,
|
|
636
733
|
getState: () => state, set,
|
|
637
|
-
pushItem, patchItem, replaceItems,
|
|
734
|
+
pushItem, patchItem, replaceItems, updateStreamingTail, settleStreamingTail, clearStreamingTail,
|
|
735
|
+
pushToast, pushNotice, removeNotice, setProgressHint,
|
|
638
736
|
pushUserOrSyntheticItem, pushAsyncAgentResponse, upsertSyntheticToolItem,
|
|
639
737
|
markToolCallActive, markToolCallDone, clearActiveToolSummary, clearToastTimers,
|
|
640
738
|
autoClearState, agentStatusState, baseRouteState, routeState, syncContextStats,
|
|
641
739
|
presentNextToolApproval, finishToolApproval, denyAllToolApprovals, requestToolApproval,
|
|
642
740
|
patchToolCardResult, flushToolResults,
|
|
741
|
+
clearExecutionDedupState,
|
|
643
742
|
kickExecutionPendingResume, flushDeferredExecutionPendingResumeKick, scheduleExecutionPendingResumeKick, discardExecutionPendingResume, updateAgentJobCard, subscribeRuntimeNotifications,
|
|
644
743
|
});
|
|
645
744
|
Object.assign(bag, createSessionFlow(bag));
|
package/src/tui/index.jsx
CHANGED
|
@@ -281,7 +281,7 @@ function paintBootSplash() {
|
|
|
281
281
|
const rows = Math.max(1, Number(process.stdout.rows) || 24);
|
|
282
282
|
const windowsLikeTerminal = process.platform === 'win32' || Boolean(process.env.WT_SESSION);
|
|
283
283
|
const frameCols = Math.max(1, cols - (windowsLikeTerminal ? 1 : 0));
|
|
284
|
-
const center = (s) => `${' '.repeat(Math.max(0, Math.floor((frameCols - displayWidth(s)) / 2)))}${s}`;
|
|
284
|
+
const center = (s, reserve = 0) => `${' '.repeat(Math.max(0, Math.floor((frameCols - reserve - displayWidth(s)) / 2)))}${s}`;
|
|
285
285
|
const logo = [
|
|
286
286
|
'███╗ ███╗██╗██╗ ██╗██████╗ ██████╗ ██████╗ ',
|
|
287
287
|
'████╗ ████║██║╚██╗██╔╝██╔══██╗██╔═══██╗██╔════╝ ',
|
|
@@ -300,7 +300,7 @@ function paintBootSplash() {
|
|
|
300
300
|
out += `${bold}${fg}${center(logo[i])}${reset}\r\n`;
|
|
301
301
|
}
|
|
302
302
|
out += '\r\n';
|
|
303
|
-
out += `${subtleFg}${center(`mixdog coding agent · v${localPackageVersion()} · ${process.cwd()}
|
|
303
|
+
out += `${subtleFg}${center(`mixdog coding agent · v${localPackageVersion()} · ${process.cwd()}`, 4)}${reset}`;
|
|
304
304
|
|
|
305
305
|
// Park the cursor at home so ink's first frame paints top-down over the
|
|
306
306
|
// splash instead of starting at the bottom row and scrolling the screen.
|
|
@@ -1,36 +1,60 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: bench
|
|
3
3
|
name: Bench
|
|
4
|
-
description: "Autonomous benchmark workflow
|
|
4
|
+
description: "Autonomous headless benchmark workflow with directed execution and parallel cross-verification."
|
|
5
5
|
hidden: true
|
|
6
6
|
agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Bench
|
|
10
10
|
|
|
11
|
-
Autonomous: no user. Never
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
1.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
11
|
+
Autonomous headless run: no user exists. Never ask questions, propose plans
|
|
12
|
+
for approval, or end the turn waiting — decide and proceed. Standing
|
|
13
|
+
pre-approval covers every action: edits, state mutation, delegation, builds.
|
|
14
|
+
Loop until the task is verified complete or provably blocked.
|
|
15
|
+
|
|
16
|
+
The pipeline has exactly three stages. Lead directs and verifies it, but NEVER
|
|
17
|
+
executes the work itself: no edits, answers, or artifact generation, regardless
|
|
18
|
+
of task size, perceived simplicity, or number of steps.
|
|
19
|
+
|
|
20
|
+
## 1. Lead analysis and direction
|
|
21
|
+
Lead performs real analysis first on EVERY task: task structure, required
|
|
22
|
+
deliverables, boundaries, the task's own verification means, and solution
|
|
23
|
+
direction. Convert it into clear execution direction and delegation briefs
|
|
24
|
+
following the Lead brief contract.
|
|
25
|
+
|
|
26
|
+
Hand the direction and briefs to executors. Analysis is not permission for
|
|
27
|
+
Lead to implement any portion of the result: all edits, answer production, and
|
|
28
|
+
artifact generation belong to executor sessions.
|
|
29
|
+
|
|
30
|
+
## 2. Executors perform the work
|
|
31
|
+
Use Worker sessions, or Heavy Worker sessions for broad scopes, to execute the
|
|
32
|
+
directed work. Multiple workers MAY fan out in parallel, one per independent
|
|
33
|
+
scope. Keep ownership clear for each assigned deliverable.
|
|
34
|
+
|
|
35
|
+
Executors build the answer or artifact and perform basic does-it-run checks.
|
|
36
|
+
They are not a verification role and do not own acceptance, requirements
|
|
37
|
+
judgment, or final correctness. Each executor reports its result to Lead.
|
|
38
|
+
|
|
39
|
+
## 3. Lead and Reviewer verify
|
|
40
|
+
|
|
41
|
+
When executors report, Lead and Reviewer start cross-verification IN PARALLEL,
|
|
42
|
+
never serially. Lead personally runs the task's own verification means, such
|
|
43
|
+
as its test suite, grader script, simulator, or self-checkable output.
|
|
44
|
+
Reviewer independently judges the result against every task requirement,
|
|
45
|
+
including intent, correctness, boundaries, and deliverables.
|
|
46
|
+
|
|
47
|
+
Judgment-type answers with no direct ground truth still require parallel
|
|
48
|
+
cross-verification, even for a single small deliverable. Lead evaluates against
|
|
49
|
+
available criteria while Reviewer independently judges requirements;
|
|
50
|
+
perceived simplicity is no exemption.
|
|
51
|
+
|
|
52
|
+
Merge any finding into a clear fix delta and return it to the SAME executor
|
|
53
|
+
session owning the affected scope. The executor applies it and reports again.
|
|
54
|
+
Lead and Reviewer repeat the same parallel cross-verification until both legs
|
|
55
|
+
are clean; Lead never fixes or completes the work directly.
|
|
56
|
+
|
|
57
|
+
Before declaring completion, Lead personally runs the task-required
|
|
58
|
+
verification one final time and checks that every deliverable is present.
|
|
59
|
+
Never end with a question, approval request, or proposed next step. Continue
|
|
60
|
+
until verified complete or stop only when completion is provably blocked.
|
|
@@ -13,33 +13,38 @@ Approval is a later explicit user message after the latest plan ("do it",
|
|
|
13
13
|
approval with a scope change needs a revised plan and fresh approval. Before
|
|
14
14
|
approval: no edits, state mutation, or delegation.
|
|
15
15
|
|
|
16
|
-
Lead
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
Lead orchestrates and verifies. Lead-direct work is allowed only for pure
|
|
17
|
+
read/analysis, git/configuration, or when the user explicitly supplies both the
|
|
18
|
+
exact target and exact replacement/output. Never infer an exemption from a task
|
|
19
|
+
name, file count, or perceived difficulty. Every other implementation, reverse
|
|
20
|
+
engineering, debugging application, or artifact generation delegates to the
|
|
21
|
+
matching agent. Debugger owns diagnosis and reverse engineering; Worker applies
|
|
22
|
+
an established bounded change or fully specified artifact; Heavy Worker owns
|
|
23
|
+
implementation that must establish the change through investigation or staged
|
|
24
|
+
delivery. Applying a Debugger result is implementation, not diagnosis.
|
|
25
25
|
|
|
26
26
|
1. Plan: draft before any implementation; settle scope/plan, ask if ambiguous,
|
|
27
27
|
then await the gate.
|
|
28
|
-
2. Delegate:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
Reviewer + Lead
|
|
41
|
-
|
|
42
|
-
work
|
|
28
|
+
2. Delegate: one agent per ready independent scope; spawn all ready scopes in
|
|
29
|
+
one turn, with no count cap. Serialize only a real dependency, overlapping
|
|
30
|
+
write, or inseparable coupling. Briefs follow the Lead brief contract.
|
|
31
|
+
After async spawn, end the turn.
|
|
32
|
+
3. Review: review is exempt only for pure read/analysis with no edit, artifact,
|
|
33
|
+
or state mutation; git/configuration; or a request where the user explicitly
|
|
34
|
+
supplies both the exact target and exact replacement/output. Every
|
|
35
|
+
non-exempt mutation or artifact, whether produced or applied by Worker,
|
|
36
|
+
Heavy Worker, Debugger, or Lead, gets one Reviewer (all ready reviewers in
|
|
37
|
+
one turn) and Lead
|
|
38
|
+
integration/cross-scope verification in parallel. Debugger analysis cannot
|
|
39
|
+
substitute for implementation review: applying a Debugger result triggers
|
|
40
|
+
the same Reviewer + Lead verification. Reviewer independently judges risk,
|
|
41
|
+
intent, boundaries; Lead checks acceptance/interactions, not duplicate
|
|
42
|
+
same-scope work. High-risk scopes add distinct lenses. Synthesize one
|
|
43
|
+
verdict; send merged fixes to the original live session; loop fix ->
|
|
44
|
+
re-verify (same Reviewer + Lead re-check) until clean. Debugger first for
|
|
45
|
+
requested debugging or a bug surviving 2+ fix cycles. Exempt mutations still
|
|
46
|
+
require shell self-verification before report. Agent reports relay scope,
|
|
47
|
+
verdict, next work as in-progress, never conclusions.
|
|
43
48
|
4. Report: final (not interim) report compares work to approved plan and gives
|
|
44
49
|
verified result; never forward raw agent output. Ask about ship/deploy when
|
|
45
50
|
relevant. Build/deploy/commit/push require an explicit user request after
|