mixdog 0.9.34 → 0.9.35
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/README.md +6 -0
- package/package.json +4 -2
- package/scripts/_devtools-stub.mjs +1 -0
- package/scripts/_jitter-fuzz.jsx +42 -0
- package/scripts/_jitter-fuzz.mjs +44410 -0
- package/scripts/_jitter-fuzz2.jsx +30 -0
- package/scripts/_jitter-fuzz2.mjs +44400 -0
- package/scripts/_jitter-probe.jsx +35 -0
- package/scripts/_jitter-probe.mjs +44397 -0
- package/scripts/_jp2.jsx +16 -0
- package/scripts/_jp2.mjs +45614 -0
- package/scripts/agent-live-arg-guard-smoke.mjs +20 -0
- package/scripts/agent-live-path-suffix-smoke.mjs +34 -0
- package/scripts/agent-live-toolcall-args-smoke.mjs +45 -0
- package/scripts/apply-patch-edit-smoke.mjs +71 -0
- package/scripts/async-notify-settlement-test.mjs +99 -0
- package/scripts/forwarder-rebind-tail-test.mjs +67 -0
- package/scripts/live-worker-smoke.mjs +1 -1
- package/scripts/pending-completion-drop-test.mjs +46 -27
- package/scripts/provider-toolcall-test.mjs +1 -0
- package/scripts/recall-bench-cases.json +1 -0
- package/scripts/session-bench.mjs +44 -0
- package/scripts/shell-hardening-test.mjs +209 -0
- package/scripts/ship-mode-test.mjs +98 -0
- package/scripts/steering-drain-buckets-test.mjs +59 -0
- package/scripts/tool-smoke.mjs +46 -10
- package/scripts/worker-notify-rejection-test.mjs +51 -0
- package/src/lib/mixdog-debug.cjs +69 -0
- package/src/rules/agent/00-common.md +4 -5
- package/src/rules/agent/00-core.md +13 -20
- package/src/rules/agent/20-skip-protocol.md +3 -8
- package/src/rules/agent/30-explorer.md +31 -54
- package/src/rules/lead/01-general.md +3 -6
- package/src/rules/lead/lead-brief.md +10 -16
- package/src/rules/lead/lead-tool.md +3 -5
- package/src/rules/shared/01-tool.md +7 -9
- package/src/runtime/agent/orchestrator/agent-trace-io.mjs +13 -2
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +19 -23
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +21 -5
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +13 -13
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +21 -7
- package/src/runtime/agent/orchestrator/tools/bash-policy-scan.mjs +1 -5
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +71 -1
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +17 -9
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +127 -4
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +105 -28
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-exec-policy.mjs +7 -3
- package/src/runtime/memory/lib/memory-embed.mjs +1 -1
- package/src/runtime/memory/lib/query-handlers.mjs +25 -10
- package/src/runtime/memory/tool-defs.mjs +3 -3
- package/src/runtime/shared/background-tasks.mjs +21 -1
- package/src/runtime/shared/tool-execution-contract.mjs +29 -16
- package/src/session-runtime/model-route-api.mjs +3 -3
- package/src/session-runtime/provider-auth-api.mjs +13 -0
- package/src/session-runtime/runtime-core.mjs +40 -6
- package/src/session-runtime/tool-catalog.mjs +3 -2
- package/src/session-runtime/workflow-agents-api.mjs +2 -2
- package/src/standalone/agent-tool/notify.mjs +14 -1
- package/src/tui/dist/index.mjs +63 -25
- package/src/tui/engine/session-flow.mjs +26 -13
- package/src/tui/engine/turn.mjs +7 -8
- package/src/tui/engine.mjs +4 -2
- package/src/vendor/statusline/bin/statusline-route.mjs +60 -4
- package/src/vendor/statusline/src/gateway/route-meta.mjs +37 -8
- package/src/workflows/default/WORKFLOW.md +26 -32
- package/src/workflows/solo/WORKFLOW.md +12 -13
package/src/tui/engine/turn.mjs
CHANGED
|
@@ -137,16 +137,15 @@ export function createRunTurn(bag) {
|
|
|
137
137
|
const deferredEntries = []; // creation-order list; each is pushed at most once
|
|
138
138
|
// Push this entry AND every earlier-created still-deferred entry, in order,
|
|
139
139
|
// so transcript order always matches call order even when a later card's
|
|
140
|
-
// result/timer fires before an earlier one's.
|
|
140
|
+
// result/timer fires before an earlier one's. Commit the collected cards in
|
|
141
|
+
// ONE state update: emitting one pushItem() per deferred card made a tool
|
|
142
|
+
// batch climb into view one row/card at a time ("툭툭" upward row jitter).
|
|
141
143
|
const flushDeferredUpTo = (entry) => {
|
|
142
144
|
if (!entry) return;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (e.timer) { clearTimeout(e.timer); e.timer = null; }
|
|
148
|
-
try { e.push(); } catch {}
|
|
149
|
-
}
|
|
145
|
+
const specs = collectDeferredUpTo(entry);
|
|
146
|
+
if (!specs.length) return;
|
|
147
|
+
flags.pushingFromDeferredEntry = true;
|
|
148
|
+
try { appendItemsBatch(specs); } finally { flags.pushingFromDeferredEntry = false; }
|
|
150
149
|
};
|
|
151
150
|
flags.flushDeferredBeforeImmediatePush = () => {
|
|
152
151
|
if (!deferredEntries.length) return;
|
package/src/tui/engine.mjs
CHANGED
|
@@ -114,10 +114,12 @@ const TOOL_APPROVAL_TIMEOUT_MS = (() => {
|
|
|
114
114
|
// runTurn holding busy=true with no unwind, so submit() only ever queues and
|
|
115
115
|
// the UI is permanently input-dead. On trip we abort the in-flight run through
|
|
116
116
|
// the SAME interrupt path Esc uses, force busy=false, and drain the queue.
|
|
117
|
-
//
|
|
117
|
+
// Default is intentionally finite (5min): 30min made a stuck provider/worker
|
|
118
|
+
// look like the Lead session had frozen mid-turn. Env-overridable for long
|
|
119
|
+
// local experiments.
|
|
118
120
|
const LEAD_TURN_TIMEOUT_MS = (() => {
|
|
119
121
|
const value = Number(process.env.MIXDOG_LEAD_TURN_TIMEOUT_MS);
|
|
120
|
-
return Number.isFinite(value) && value > 0 ? Math.max(10_000, Math.round(value)) :
|
|
122
|
+
return Number.isFinite(value) && value > 0 ? Math.max(10_000, Math.round(value)) : 5 * 60_000;
|
|
121
123
|
})();
|
|
122
124
|
|
|
123
125
|
// Opt-in diagnostic trace for the hang chain (runTurn start/end, busy-queue
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
compactBoundaryDenominator,
|
|
16
16
|
defaultEffectiveContextWindowPercent,
|
|
17
17
|
} from '../src/gateway/route-meta.mjs';
|
|
18
|
+
import { getModelMetadataSync } from '../../../runtime/agent/orchestrator/providers/model-catalog.mjs';
|
|
18
19
|
|
|
19
20
|
function positiveInt(value) {
|
|
20
21
|
const n = parseInt(String(value || ''), 10);
|
|
@@ -196,6 +197,8 @@ function routeContextMeta(provider, info = {}, inherited = {}) {
|
|
|
196
197
|
const rawContextWindow = firstPositiveWindow(
|
|
197
198
|
inherited.rawContextWindow,
|
|
198
199
|
inherited.raw_context_window,
|
|
200
|
+
info.context_window,
|
|
201
|
+
info.max_context_window,
|
|
199
202
|
info.contextWindow,
|
|
200
203
|
info.maxContextWindow,
|
|
201
204
|
info.max_input_tokens,
|
|
@@ -463,6 +466,26 @@ function configuredGatewayStatus(options = {}) {
|
|
|
463
466
|
? presets.find(p => p?.provider === provider && p?.model === model)
|
|
464
467
|
: null);
|
|
465
468
|
const info = loadCachedModel(provider, model) || {};
|
|
469
|
+
// Catalog/known metadata is authoritative for the context window. The cached
|
|
470
|
+
// model file can hold a STALE window (e.g. Opus 4.8 cached at 272k after its
|
|
471
|
+
// window grew to the catalog's 1M); routeContextMeta reads info.contextWindow,
|
|
472
|
+
// so reconcile it against the catalog before deriving the boundary. A live
|
|
473
|
+
// provider API window on the cached row (context_window / max_context_window)
|
|
474
|
+
// still outranks the catalog.
|
|
475
|
+
const _catalog = getModelMetadataSync(model, provider);
|
|
476
|
+
const _catalogWindow = num(
|
|
477
|
+
_catalog?.contextWindow
|
|
478
|
+
?? _catalog?.maxContextWindow
|
|
479
|
+
?? _catalog?.context_window
|
|
480
|
+
?? _catalog?.max_context_window,
|
|
481
|
+
0,
|
|
482
|
+
);
|
|
483
|
+
const _apiWindow = num(info?.context_window ?? info?.max_context_window, 0);
|
|
484
|
+
const _cachedWindow = num(info?.contextWindow ?? info?.maxContextWindow, 0);
|
|
485
|
+
if (!_apiWindow && _catalogWindow > 0 && _cachedWindow !== _catalogWindow) {
|
|
486
|
+
info.contextWindow = _catalogWindow;
|
|
487
|
+
info.maxContextWindow = _catalogWindow;
|
|
488
|
+
}
|
|
466
489
|
const effort = aliasTarget
|
|
467
490
|
? cleanString(aliasTarget.effort || gateway.effort || gateway.displayEffort || preset?.effort)
|
|
468
491
|
: inherit
|
|
@@ -546,8 +569,18 @@ export function loadGatewayStatus(options = {}) {
|
|
|
546
569
|
const routeMatchesConfigured = configured
|
|
547
570
|
? configured.provider === active.gateway_provider && configured.model === active.gateway_model
|
|
548
571
|
: true;
|
|
572
|
+
const activeRouteBoundary = compactBoundaryForStatus({
|
|
573
|
+
autoCompactTokenLimit: active.gateway_auto_compact_token_limit,
|
|
574
|
+
contextWindow: active.gateway_context_window,
|
|
575
|
+
rawContextWindow: active.gateway_raw_context_window,
|
|
576
|
+
});
|
|
577
|
+
const configuredRouteBoundary = configured ? compactBoundaryForStatus(configured) : null;
|
|
578
|
+
const routeBoundaryMatchesConfigured = !configured
|
|
579
|
+
|| !configuredRouteBoundary
|
|
580
|
+
|| !activeRouteBoundary
|
|
581
|
+
|| configuredRouteBoundary === activeRouteBoundary;
|
|
549
582
|
const metricsOwnCurrentSession = !!(sessionStatus || gatewayCcSessionMatch || gatewayTranscriptMatch || activeTranscriptMatch);
|
|
550
|
-
const metricsMatch = gatewayClientHostMatch && metricsOwnCurrentSession && routeMatchesConfigured;
|
|
583
|
+
const metricsMatch = gatewayClientHostMatch && metricsOwnCurrentSession && routeMatchesConfigured && routeBoundaryMatchesConfigured;
|
|
551
584
|
// Strong ownership = this session's own status file or an explicit session/
|
|
552
585
|
// transcript id match from the gateway advert. `activeTranscriptMatch` (the
|
|
553
586
|
// global active-instance transcript merely naming the current session) is NOT
|
|
@@ -555,12 +588,35 @@ export function loadGatewayStatus(options = {}) {
|
|
|
555
588
|
// session while its stored gateway metrics (context pct, last usage) still
|
|
556
589
|
// belong to the previous one.
|
|
557
590
|
const strongSessionOwnership = !!(sessionStatus || gatewayCcSessionMatch || gatewayTranscriptMatch);
|
|
558
|
-
|
|
591
|
+
// A model switch can keep strong session ownership while the active gateway
|
|
592
|
+
// advert still contains the previous route's lastUsage.compact. Do not let
|
|
593
|
+
// that stale compact boundary override the configured/current route window.
|
|
594
|
+
const lastUsage = gatewayClientHostMatch && strongSessionOwnership && routeMatchesConfigured && routeBoundaryMatchesConfigured && active.gateway_last_usage && typeof active.gateway_last_usage === 'object'
|
|
559
595
|
? active.gateway_last_usage
|
|
560
596
|
: null;
|
|
561
|
-
const
|
|
597
|
+
const rawLastCompact = lastUsage?.compact && typeof lastUsage.compact === 'object'
|
|
562
598
|
? lastUsage.compact
|
|
563
599
|
: null;
|
|
600
|
+
// A model/window switch updates the active route fields (context/raw window)
|
|
601
|
+
// but can leave the PREVIOUS route's boundary inside gateway_last_usage.compact.
|
|
602
|
+
// routeBoundaryMatchesConfigured only checks the active route fields, so that
|
|
603
|
+
// stale compact telemetry would otherwise survive and, via compactBoundaryTokens,
|
|
604
|
+
// resurrect the previous boundary in compactBoundaryForStatus below. Drop the
|
|
605
|
+
// compact telemetry when its own implied boundary contradicts the active route
|
|
606
|
+
// window.
|
|
607
|
+
const lastCompactBoundary = rawLastCompact
|
|
608
|
+
? compactBoundaryForStatus({}, rawLastCompact)
|
|
609
|
+
: null;
|
|
610
|
+
const lastCompact = rawLastCompact
|
|
611
|
+
&& (!activeRouteBoundary || !lastCompactBoundary || lastCompactBoundary === activeRouteBoundary)
|
|
612
|
+
? rawLastCompact
|
|
613
|
+
: null;
|
|
614
|
+
const statusLastUsage = lastUsage
|
|
615
|
+
? {
|
|
616
|
+
...lastUsage,
|
|
617
|
+
compact: lastCompact,
|
|
618
|
+
}
|
|
619
|
+
: null;
|
|
564
620
|
const contextBoundary = compactBoundaryForStatus({
|
|
565
621
|
autoCompactTokenLimit: active.gateway_auto_compact_token_limit,
|
|
566
622
|
contextWindow: active.gateway_context_window,
|
|
@@ -616,7 +672,7 @@ export function loadGatewayStatus(options = {}) {
|
|
|
616
672
|
contextUsedPct: metricsMatch
|
|
617
673
|
? recomputedContextUsedPct ?? (strongSessionOwnership ? num(active.gateway_context_used_pct, null) : null)
|
|
618
674
|
: null,
|
|
619
|
-
lastUsage,
|
|
675
|
+
lastUsage: statusLastUsage,
|
|
620
676
|
quotaWindows: activeQuotaWindows.length ? activeQuotaWindows : (configuredStatus?.quotaWindows || []),
|
|
621
677
|
// Provenance for monotonic hysteresis: live active-instance windows are
|
|
622
678
|
// own-instance data timestamped by the advert's updatedAt; otherwise inherit
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
estimateMessagesTokens,
|
|
10
10
|
estimateRequestReserveTokens,
|
|
11
11
|
} from '../../../../runtime/agent/orchestrator/session/context-utils.mjs';
|
|
12
|
-
import { DEFAULT_EFFECTIVE_CONTEXT_WINDOW_PERCENT } from '../../../../runtime/agent/orchestrator/session/compact/constants.mjs';
|
|
13
12
|
import { CLAUDE_CURRENT_MODE } from './claude-current.mjs';
|
|
14
13
|
|
|
15
14
|
const GATEWAY_USAGE_FILE = 'gateway-usage.local.json';
|
|
@@ -100,11 +99,11 @@ function boundedPercent(value, fallback = null) {
|
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
export function defaultEffectiveContextWindowPercent(_provider) {
|
|
103
|
-
// Gateway
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
return
|
|
102
|
+
// Gateway/statusline should report the full model boundary. The 10% safety
|
|
103
|
+
// headroom belongs to semantic-agent compact triggers, not to the main
|
|
104
|
+
// recall-fasttrack denominator.
|
|
105
|
+
void _provider;
|
|
106
|
+
return 100;
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
function effectiveContextWindowPercent(provider, info = {}, seed = {}) {
|
|
@@ -265,11 +264,34 @@ function mergeModelInfo(provider, model, providerObj) {
|
|
|
265
264
|
const fromProvider = modelInfoFromProvider(providerObj, model);
|
|
266
265
|
const fromCache = loadCachedModel(provider, model);
|
|
267
266
|
const fromCatalog = getModelMetadataSync(model, provider);
|
|
268
|
-
|
|
267
|
+
const merged = {
|
|
269
268
|
...(fromCatalog || {}),
|
|
270
269
|
...(fromCache || {}),
|
|
271
270
|
...(fromProvider || {}),
|
|
272
271
|
};
|
|
272
|
+
// Catalog/known metadata is authoritative for the context window. Spreading
|
|
273
|
+
// fromCache after fromCatalog otherwise lets a STALE cached window (e.g. Opus
|
|
274
|
+
// 4.8 cached at 272k after its window grew to the catalog's 1M) override the
|
|
275
|
+
// catalog. Only a live provider API window (context_window / max_context_window)
|
|
276
|
+
// outranks the catalog; when the provider info supplies no such window and the
|
|
277
|
+
// catalog disagrees with the merged (cached) window, prefer the catalog.
|
|
278
|
+
const providerApiWindow = num(
|
|
279
|
+
fromProvider?.context_window ?? fromProvider?.max_context_window,
|
|
280
|
+
0,
|
|
281
|
+
);
|
|
282
|
+
const catalogWindow = num(
|
|
283
|
+
fromCatalog?.contextWindow
|
|
284
|
+
?? fromCatalog?.maxContextWindow
|
|
285
|
+
?? fromCatalog?.context_window
|
|
286
|
+
?? fromCatalog?.max_context_window,
|
|
287
|
+
0,
|
|
288
|
+
);
|
|
289
|
+
const mergedWindow = num(merged?.contextWindow ?? merged?.maxContextWindow, 0);
|
|
290
|
+
if (!providerApiWindow && catalogWindow > 0 && mergedWindow !== catalogWindow) {
|
|
291
|
+
merged.contextWindow = catalogWindow;
|
|
292
|
+
merged.maxContextWindow = catalogWindow;
|
|
293
|
+
}
|
|
294
|
+
return merged;
|
|
273
295
|
}
|
|
274
296
|
|
|
275
297
|
export function readGatewayRouteInfo(seed = {}, providerObj = null) {
|
|
@@ -312,7 +334,14 @@ export function readGatewayRouteInfo(seed = {}, providerObj = null) {
|
|
|
312
334
|
?? cleanBool(preset?.fast)
|
|
313
335
|
?? false;
|
|
314
336
|
const info = mergeModelInfo(provider, model, providerObj);
|
|
315
|
-
const rawContextWindow = num(
|
|
337
|
+
const rawContextWindow = num(
|
|
338
|
+
info?.context_window
|
|
339
|
+
?? info?.max_context_window
|
|
340
|
+
?? info?.contextWindow
|
|
341
|
+
?? info?.maxContextWindow
|
|
342
|
+
?? info?.max_input_tokens,
|
|
343
|
+
0,
|
|
344
|
+
)
|
|
316
345
|
|| num(seed.contextWindow, 0);
|
|
317
346
|
const effectivePercent = effectiveContextWindowPercent(provider, info, seed);
|
|
318
347
|
const contextWindow = effectiveContextWindow(rawContextWindow, effectivePercent);
|
|
@@ -7,39 +7,33 @@ agents: worker, heavy-worker, reviewer, debugger, maintainer
|
|
|
7
7
|
|
|
8
8
|
# Default Workflow
|
|
9
9
|
|
|
10
|
-
HARD APPROVAL GATE —
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
HARD APPROVAL GATE — before explicit go-ahead ("do it", "proceed", "ㄱㄱ"),
|
|
11
|
+
only read-only exploration; no changes, state mutations, or delegation.
|
|
12
|
+
Diagnosis agreement/problem-pointing is NOT approval.
|
|
13
13
|
|
|
14
|
-
Lead supervises
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- Reviewer: verify implementation scopes. Debugger: very high complexity, or
|
|
21
|
-
root-causing already failed once.
|
|
14
|
+
Lead supervises/delegates/coordinates/judges/decides. After approval route by
|
|
15
|
+
complexity: Lead directly only one-step single-turn fixes plus coordination,
|
|
16
|
+
config, and git deployment; everything else delegates. Worker = multi-step or
|
|
17
|
+
multi-file implementation; Heavy Worker = high-complexity scopes; Reviewer =
|
|
18
|
+
implementation verification; Debugger = very high complexity or root-cause
|
|
19
|
+
after a failed fix.
|
|
22
20
|
|
|
23
|
-
1. Plan — present a draft
|
|
24
|
-
|
|
25
|
-
2. Delegate — maximize distribution: split
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
4. Report — final report briefs the whole work vs the approved plan and the
|
|
41
|
-
verified result, distinct from interim updates. Never forward raw agent
|
|
42
|
-
output. Ask about ship/deploy when relevant; deploy/build/commit only on an
|
|
43
|
-
explicit user request, after feedback with no issues.
|
|
21
|
+
1. Plan — present a draft before ANY implementation; revise/re-present until
|
|
22
|
+
explicit go-ahead.
|
|
23
|
+
2. Delegate — maximize parallel distribution: split independent implementation
|
|
24
|
+
scopes to separate worker/heavy-worker agents, all spawned in the SAME turn.
|
|
25
|
+
Sequential steps only inside one inseparable complex scope, gated
|
|
26
|
+
build/test-green; say when a scope is inseparable. Briefs follow Lead brief
|
|
27
|
+
contract. After spawning async agents, END THE TURN.
|
|
28
|
+
3. Review — once scopes land, spawn one reviewer per implementation scope, all
|
|
29
|
+
in the same turn. Cross-check results yourself; send fixes to the original
|
|
30
|
+
scope and loop fix -> re-verify until clean. Skip only simple low-risk work.
|
|
31
|
+
Use Debugger first when asked for debugging or a bug survives 2+ fix cycles.
|
|
32
|
+
On each agent report, relay scope+verdict and next work as in-progress,
|
|
33
|
+
never as a conclusion.
|
|
34
|
+
4. Report — final report covers work vs approved plan and verified result,
|
|
35
|
+
separate from interim updates. Never forward raw agent output. Ask about
|
|
36
|
+
ship/deploy when relevant; deploy/build/commit only on explicit user request
|
|
37
|
+
after feedback with no issues.
|
|
44
38
|
|
|
45
39
|
On major direction shifts mid-work, pause and re-consult the user.
|
|
@@ -7,22 +7,21 @@ agents:
|
|
|
7
7
|
|
|
8
8
|
# Solo Workflow
|
|
9
9
|
|
|
10
|
-
HARD APPROVAL GATE —
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
HARD APPROVAL GATE — before explicit go-ahead ("do it", "proceed", "ㄱㄱ"),
|
|
11
|
+
only read-only exploration; no changes or state mutations. Diagnosis
|
|
12
|
+
agreement/problem-pointing is NOT approval.
|
|
13
13
|
|
|
14
|
-
1. Plan — present a draft
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
updates are marked in-progress — never phrased as conclusions.
|
|
14
|
+
1. Plan — present a draft before ANY implementation; revise/re-present until
|
|
15
|
+
explicit go-ahead. If ambiguous, restate the plan and ask.
|
|
16
|
+
2. Execute — Lead does all work directly; delegation forbidden. Interim updates
|
|
17
|
+
are in-progress, never conclusions.
|
|
19
18
|
3. Verify — check and fix directly until clean or a blocker is reported.
|
|
20
|
-
4. Report — final report
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
4. Report — final report covers work vs approved plan, verification result, and
|
|
20
|
+
remaining risk/next step, distinct from interim updates. Deploy/build/commit
|
|
21
|
+
only after user feedback with no issues.
|
|
23
22
|
|
|
24
23
|
On major direction shifts mid-work, pause and re-consult the user.
|
|
25
24
|
|
|
26
25
|
Delegation rule:
|
|
27
|
-
- Never delegate
|
|
28
|
-
|
|
26
|
+
- Never delegate/spawn/send or ask agents to work; ignore available-agent
|
|
27
|
+
sections while this workflow is active.
|