@tea-agent/loop-agent 0.9.0 → 0.10.0-alpha.0
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/AGENTS.md +8 -0
- package/CHANGELOG.md +92 -11
- package/README.md +69 -5
- package/dist/application/dag/args.js +4 -14
- package/dist/application/dag/generate-task-dag.js +32 -2
- package/dist/application/dag/run-dag.js +1 -27
- package/dist/application/dag/validate-dag.js +2 -2
- package/dist/application/loop/run-action.js +0 -4
- package/dist/cli/command-definitions.js +7 -11
- package/dist/cli/program.js +9 -21
- package/dist/commands/cursor-prompt.js +42 -82
- package/dist/commands/dag-approve.js +36 -0
- package/dist/commands/dag-reconcile-run.js +118 -0
- package/dist/commands/delegate.js +75 -77
- package/dist/commands/doctor.js +0 -18
- package/dist/commands/init.js +60 -40
- package/dist/commands/instructions.js +7 -10
- package/dist/commands/loop.js +4 -20
- package/dist/executors/config-core.js +0 -51
- package/dist/executors/dag-pi-executor.js +1 -1
- package/dist/executors/dag.js +0 -1
- package/dist/executors/index.js +0 -2
- package/dist/executors/model-routing.js +9 -9
- package/dist/executors/shell-executor.js +1 -1
- package/dist/governance/checks.js +6 -3
- package/dist/governance/manifest-types.js +33 -2
- package/dist/infrastructure/harness/loop-action-store.js +0 -3
- package/dist/records/harvest.js +2 -23
- package/dist/records/one-shot-runs.js +1 -1
- package/dist/shared/artifacts-core.js +24 -5
- package/dist/shared/output-truncation.js +37 -0
- package/dist/shared/package-metadata.js +353 -0
- package/dist/{executors/cursor-executor.js → sidecars/cursor-prompt/executor.js} +2 -42
- package/dist/sidecars/cursor-prompt/index.js +3 -0
- package/dist/sidecars/cursor-prompt/stream.js +121 -0
- package/dist/task/config-types.js +29 -12
- package/dist/task/delegate.js +9 -21
- package/dist/task/runtime.js +1 -2
- package/dist/worker/cli.js +243 -0
- package/dist/worker/closeout/apply.js +73 -0
- package/dist/worker/closeout/preview.js +30 -0
- package/dist/worker/delivery/final-verification.js +194 -0
- package/dist/worker/delivery/git-transaction.js +354 -0
- package/dist/worker/delivery/package.js +502 -0
- package/dist/worker/feature/decision-loader.js +68 -0
- package/dist/worker/feature/discover.js +14 -0
- package/dist/worker/feature/next-action.js +74 -0
- package/dist/worker/feature/reducer.js +133 -0
- package/dist/worker/feature/review.js +502 -0
- package/dist/worker/feature/run.js +365 -0
- package/dist/worker/feature/types.js +1 -0
- package/dist/worker/follow-up/approve.js +270 -0
- package/dist/worker/follow-up/factory.js +234 -0
- package/dist/worker/follow-up/paths.js +25 -0
- package/dist/worker/follow-up/policy.js +26 -0
- package/dist/worker/follow-up/schema.js +93 -0
- package/dist/worker/follow-up/store.js +96 -0
- package/dist/worker/loop-agent/loop-agent-client.js +329 -126
- package/dist/worker/metrics/projector.js +139 -0
- package/dist/worker/observability/read-model.js +282 -15
- package/dist/worker/observe/paths.js +17 -5
- package/dist/worker/observe/static/app.js +443 -61
- package/dist/worker/observe/static/index.html +3 -1
- package/dist/worker/observe/static/styles.css +85 -18
- package/dist/worker/pool/run-store.js +14 -2
- package/dist/worker/pool/validation.js +59 -0
- package/dist/worker/preflight.js +49 -1
- package/dist/worker/report/morning-report.js +41 -6
- package/dist/worker/run-task/run-task.js +23 -13
- package/dist/worker/runner/run-ready.js +89 -11
- package/dist/worker/task-spec/schema.js +0 -1
- package/dist/workflows/dag/convergence/controller.js +1 -1
- package/dist/workflows/dag/executor-registry.js +0 -2
- package/dist/workflows/dag/governance-profile.js +10 -0
- package/dist/workflows/dag/init-hybrid.js +601 -26
- package/dist/workflows/dag/lifecycle.js +146 -0
- package/dist/workflows/dag/node-execution.js +64 -7
- package/dist/workflows/dag/prompt.js +16 -0
- package/dist/workflows/dag/report.js +2 -0
- package/dist/workflows/dag/runner.js +176 -119
- package/dist/workflows/dag/scheduler.js +7 -2
- package/dist/workflows/dag/skill-snapshot.js +527 -0
- package/dist/workflows/dag/types.js +45 -9
- package/dist/workflows/dag/validate.js +5 -8
- package/dist/workflows/loop/actions/dag-action.js +0 -2
- package/dist/workflows/loop/actions/shared.js +1 -1
- package/dist/workflows/loop/actions.js +14 -31
- package/dist/workflows/loop/benchmark.js +1 -1
- package/dist/workflows/loop/index.js +1 -1
- package/dist/workflows/loop/policy/auto-policy.js +22 -14
- package/dist/workflows/loop/policy/path-patterns.js +13 -0
- package/docs/README.md +35 -16
- package/docs/agent-dag-recovery-playbook.md +1 -1
- package/docs/architecture/README.md +26 -0
- package/docs/architecture/dag-execution.md +134 -0
- package/docs/architecture/evolution.md +52 -0
- package/docs/architecture/facts-and-state.md +58 -0
- package/docs/architecture/runtime-boundaries.md +41 -15
- package/docs/architecture/system-overview.md +93 -0
- package/docs/architecture/worker-and-feature.md +81 -0
- package/docs/cursor-prompt-sidecar.md +36 -0
- package/docs/decisions/README.md +13 -1
- package/docs/design/README.md +39 -13
- package/docs/development-principles.md +1 -1
- package/docs/exec-plans/active/README.md +2 -2
- package/docs/exec-plans/completed/README.md +14 -1
- package/docs/feature-workflow.md +44 -4
- package/docs/init-surface.manifest.json +63 -1
- package/docs/loop-agent-harness.md +65 -3
- package/docs/progress/README.md +27 -0
- package/docs/reports/README.md +74 -8
- package/docs/skills/README.md +2 -1
- package/docs/skills/vetted-skill-registry.md +2 -1
- package/docs/templates/agent-dag-report.schema.json +4 -2
- package/docs/templates/agent-dag.base.json +0 -5
- package/docs/templates/agent-dag.final-verification.json +0 -5
- package/docs/templates/agent-dag.schema.json +1 -2
- package/docs/templates/agent-dag.supervised-implementation.json +1 -6
- package/docs/templates/backend-test-dag.generate-pytest.prompt.md +131 -0
- package/docs/templates/backend-test-dag.json +213 -0
- package/docs/templates/backend-test-dag.retrospect.prompt.md +128 -0
- package/docs/templates/backend-test-dag.review-cases.prompt.md +85 -0
- package/docs/templates/frontend-design-contract.md +33 -0
- package/docs/templates/frontend-task-constraints.md +25 -0
- package/docs/templates/frontend-task-requirement.md +61 -0
- package/docs/templates/harness.schema.json +8 -5
- package/docs/templates/hybrid-dag.json +1 -6
- package/docs/templates/init-evolution-review.md +4 -2
- package/docs/templates/interactive-ui-round2-experiment.md +1 -1
- package/docs/templates/product-line/task.yaml +0 -1
- package/docs/templates/worker-dogfood-evidence.md +28 -0
- package/docs/templates/worker-dogfood-setup.md +20 -0
- package/docs/verification-matrix.md +17 -0
- package/examples/decision-gate-agent-dag.json +87 -33
- package/examples/example-dag.json +0 -5
- package/examples/hybrid-loop-agent-dag.json +0 -5
- package/harness.json +6 -11
- package/package.json +22 -44
- package/scripts/check-product-line-docs.sh +10 -3
- package/skills/agent-worker/SKILL.md +37 -0
- package/skills/agent-worker/references/agent-worker-operator.md +43 -0
- package/skills/frontend-design-review/SKILL.md +59 -0
- package/skills/frontend-design-review/references/review-checklist.md +37 -0
- package/skills/frontend-implementation/SKILL.md +48 -0
- package/skills/frontend-implementation/references/code-standards.md +34 -0
- package/skills/frontend-implementation/references/design-spec.md +46 -0
- package/skills/frontend-implementation/references/node-contracts.md +32 -0
- package/skills/frontend-review/SKILL.md +53 -0
- package/skills/frontend-review/references/review-findings.md +42 -0
- package/skills/frontend-verification/SKILL.md +40 -0
- package/skills/frontend-verification/references/verification-checklist.md +56 -0
- package/skills/grill-me/SKILL.md +10 -0
- package/skills/grill-with-docs/SKILL.md +88 -0
- package/skills/grill-with-docs/adr-format.md +47 -0
- package/skills/grill-with-docs/context-format.md +60 -0
- package/skills/init-capability-evolution/SKILL.md +1 -0
- package/skills/loop-agent/SKILL.md +11 -9
- package/skills/loop-agent/references/command-reference.md +28 -15
- package/skills/loop-agent/references/docs-converge.md +126 -0
- package/skills/loop-agent/references/harness-policy.md +7 -7
- package/skills/loop-agent/references/hybrid-dag.md +13 -15
- package/skills/loop-agent/references/long-running-loop.md +4 -6
- package/skills/loop-agent/references/multi-worktree.md +6 -6
- package/skills/loop-agent/references/orchestrator-and-interventions.md +3 -3
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +14 -11
- package/skills/using-git-worktrees/SKILL.md +215 -0
- package/dist/commands/cursor-worker.js +0 -43
- package/dist/cursor-worker-entry.js +0 -8
- package/dist/executors/cursor-artifacts.js +0 -33
- package/dist/executors/cursor-execution-log.js +0 -81
- package/dist/executors/cursor-executor-artifacts.js +0 -134
- package/dist/executors/cursor-run.js +0 -115
- package/dist/executors/cursor-tool.js +0 -94
- package/dist/executors/cursor-worker-client.js +0 -223
- package/dist/executors/cursor-worker-protocol.js +0 -18
- package/dist/executors/cursor-worker-server.js +0 -54
- package/dist/executors/cursor-worker.js +0 -3
- package/dist/executors/cursor.js +0 -6
- package/dist/executors/dag-cursor-executor.js +0 -87
- package/dist/workflows/loop/actions/cursor-fix.js +0 -191
- package/dist/workflows/loop/policy/cursor-fix-policy.js +0 -31
- package/docs/cursor-executor-usage.md +0 -25
- package/docs/dynamic-workflow-dag-engine-roadmap.md +0 -1749
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import YAML from "yaml";
|
|
5
|
+
import { controllerIdentitiesMatch, controllerIdentityExpectationFailure, resolveControllerIdentity, } from "../loop-agent/loop-agent-client.js";
|
|
5
6
|
import { deriveFailureRoute, deriveFailureRouteFromError, } from "../pool/failure-routing.js";
|
|
6
7
|
import { findRunByWorkerRunId, getTaskPoolRoot, readAllTaskPoolStates, recordTaskPoolRun, writeTaskPoolState, } from "../pool/run-store.js";
|
|
7
8
|
import { runTaskSpec, } from "../run-task/run-task.js";
|
|
@@ -9,7 +10,26 @@ import { formatDuration, noopProgressReporter, } from "../progress-reporter.js";
|
|
|
9
10
|
import { computeReadyQueue } from "../task-graph/ready-queue.js";
|
|
10
11
|
import { taskGraphSpecSchema } from "../task-graph/task-graph-schema.js";
|
|
11
12
|
import { taskSpecSchema } from "../task-spec/schema.js";
|
|
13
|
+
import { preflightTargetRepo } from "../preflight.js";
|
|
12
14
|
export async function runReadyTasks(options) {
|
|
15
|
+
let controllerIdentity = resolveControllerIdentity(options.client, options.controllerIdentity);
|
|
16
|
+
const identityFailure = controllerIdentityExpectationFailure(controllerIdentity, options.controllerExpectation);
|
|
17
|
+
if (identityFailure) {
|
|
18
|
+
throw new Error(`${identityFailure.code}: ${identityFailure.message}`);
|
|
19
|
+
}
|
|
20
|
+
if (!options.skipTaskPreflight && !options.runTask) {
|
|
21
|
+
const preflight = await preflightTargetRepo({
|
|
22
|
+
repoRoot: options.repoRoot,
|
|
23
|
+
client: options.client,
|
|
24
|
+
runCheckRepo: options.runCheckRepo,
|
|
25
|
+
...(options.checkRepoCommand ? { checkRepoCommand: options.checkRepoCommand } : {}),
|
|
26
|
+
...(options.controllerExpectation ? { expectation: options.controllerExpectation } : {}),
|
|
27
|
+
});
|
|
28
|
+
if (!preflight.ok) {
|
|
29
|
+
throw new Error(`target repo preflight failed: ${preflight.code}: ${preflight.message}`);
|
|
30
|
+
}
|
|
31
|
+
controllerIdentity = preflight.controllerIdentity ?? controllerIdentity;
|
|
32
|
+
}
|
|
13
33
|
const now = options.now ?? new Date();
|
|
14
34
|
const startedAt = now.toISOString();
|
|
15
35
|
const batchRunId = options.batchRunId ?? buildBatchRunId(now);
|
|
@@ -43,12 +63,19 @@ export async function runReadyTasks(options) {
|
|
|
43
63
|
const taskSpecPath = path.join(options.featureDir, "tasks", node?.task ?? `${taskId}.yaml`);
|
|
44
64
|
const taskSpec = await loadTaskSpec(taskSpecPath);
|
|
45
65
|
const retryOfWorkerRunId = states[taskId]?.retryOfWorkerRunId;
|
|
46
|
-
|
|
66
|
+
let workerRunId = retryOfWorkerRunId
|
|
47
67
|
? buildRetryWorkerRunId(taskId, retryOfWorkerRunId, now)
|
|
48
68
|
: options.workerRunIdForTask?.(taskId, taskSpec) ??
|
|
49
|
-
buildStableWorkerRunId(taskId, taskSpec, now);
|
|
69
|
+
buildStableWorkerRunId(taskId, taskSpec, now, controllerIdentity);
|
|
50
70
|
if (workerRunId) {
|
|
51
|
-
|
|
71
|
+
let existing = await findRunByWorkerRunId(options.repoRoot, workerRunId);
|
|
72
|
+
if (existing && !controllerRunCanBeReused(existing, controllerIdentity)) {
|
|
73
|
+
workerRunId = buildControllerScopedWorkerRunId(workerRunId, controllerIdentity);
|
|
74
|
+
existing = await findRunByWorkerRunId(options.repoRoot, workerRunId);
|
|
75
|
+
if (existing && !controllerRunCanBeReused(existing, controllerIdentity)) {
|
|
76
|
+
throw new Error(`workerRunId collision has incompatible controller identity: ${workerRunId}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
52
79
|
if (existing) {
|
|
53
80
|
progress.task(`task ${index}/${total} ${taskId}: reuse existing run ${workerRunId}`);
|
|
54
81
|
emit(progress, {
|
|
@@ -66,6 +93,7 @@ export async function runReadyTasks(options) {
|
|
|
66
93
|
status: "reused",
|
|
67
94
|
runRecordPath: existing.runRecordPath,
|
|
68
95
|
});
|
|
96
|
+
await options.onTaskFinalized?.({ status: "reused", taskSpec, workerRunId, ...(existing.runRecordPath ? { runRecordPath: existing.runRecordPath } : {}) });
|
|
69
97
|
continue;
|
|
70
98
|
}
|
|
71
99
|
}
|
|
@@ -80,7 +108,7 @@ export async function runReadyTasks(options) {
|
|
|
80
108
|
workerRunId,
|
|
81
109
|
status: "running",
|
|
82
110
|
});
|
|
83
|
-
progress.step(`
|
|
111
|
+
progress.step(`materialize → dag-run-task → validate → run-dag → report`);
|
|
84
112
|
let result;
|
|
85
113
|
try {
|
|
86
114
|
await writeTaskPoolState(options.repoRoot, {
|
|
@@ -106,12 +134,11 @@ export async function runReadyTasks(options) {
|
|
|
106
134
|
client: options.client,
|
|
107
135
|
now,
|
|
108
136
|
workerRunId,
|
|
109
|
-
preflight:
|
|
110
|
-
runCheckRepo: options.runCheckRepo,
|
|
111
|
-
...(options.checkRepoCommand ? { checkRepoCommand: options.checkRepoCommand } : {}),
|
|
112
|
-
},
|
|
137
|
+
preflight: false,
|
|
113
138
|
progress,
|
|
114
139
|
...(options.piModel ? { piModel: options.piModel } : {}),
|
|
140
|
+
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
141
|
+
...(options.controllerExpectation ? { controllerExpectation: options.controllerExpectation } : {}),
|
|
115
142
|
});
|
|
116
143
|
}
|
|
117
144
|
catch (error) {
|
|
@@ -128,6 +155,7 @@ export async function runReadyTasks(options) {
|
|
|
128
155
|
status: "failed",
|
|
129
156
|
message,
|
|
130
157
|
});
|
|
158
|
+
let recorded = false;
|
|
131
159
|
try {
|
|
132
160
|
await recordTaskPoolRun({
|
|
133
161
|
repoRoot: options.repoRoot,
|
|
@@ -142,18 +170,23 @@ export async function runReadyTasks(options) {
|
|
|
142
170
|
error: message,
|
|
143
171
|
failure,
|
|
144
172
|
...(retryOfWorkerRunId ? { retryOfWorkerRunId } : {}),
|
|
173
|
+
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
145
174
|
},
|
|
146
175
|
});
|
|
176
|
+
recorded = true;
|
|
147
177
|
}
|
|
148
178
|
catch (recordError) {
|
|
179
|
+
await options.onTaskFinalized?.({ status: "run-error", taskSpec, workerRunId });
|
|
149
180
|
tasks.push({
|
|
150
181
|
taskId,
|
|
151
182
|
workerRunId,
|
|
152
183
|
status: "record-error",
|
|
153
184
|
error: errorMessage(recordError),
|
|
154
185
|
});
|
|
155
|
-
|
|
186
|
+
break;
|
|
156
187
|
}
|
|
188
|
+
if (recorded)
|
|
189
|
+
await options.onTaskFinalized?.({ status: "run-error", taskSpec, workerRunId });
|
|
157
190
|
tasks.push({
|
|
158
191
|
taskId,
|
|
159
192
|
workerRunId,
|
|
@@ -206,9 +239,12 @@ export async function runReadyTasks(options) {
|
|
|
206
239
|
...(failure ? { failure } : {}),
|
|
207
240
|
...(retryOfWorkerRunId ? { retryOfWorkerRunId } : {}),
|
|
208
241
|
...(result.failureArtifacts ? { failureArtifacts: result.failureArtifacts } : {}),
|
|
242
|
+
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
209
243
|
};
|
|
244
|
+
let recorded = false;
|
|
210
245
|
try {
|
|
211
246
|
await recordTaskPoolRun({ repoRoot: options.repoRoot, run });
|
|
247
|
+
recorded = true;
|
|
212
248
|
tasks.push({
|
|
213
249
|
taskId,
|
|
214
250
|
workerRunId: result.workerRunId,
|
|
@@ -217,6 +253,7 @@ export async function runReadyTasks(options) {
|
|
|
217
253
|
});
|
|
218
254
|
}
|
|
219
255
|
catch (error) {
|
|
256
|
+
await options.onTaskFinalized?.({ status: result.status, taskSpec, workerRunId: result.workerRunId, runRecordPath: result.runRecordPath });
|
|
220
257
|
tasks.push({
|
|
221
258
|
taskId,
|
|
222
259
|
workerRunId: result.workerRunId,
|
|
@@ -224,7 +261,10 @@ export async function runReadyTasks(options) {
|
|
|
224
261
|
error: errorMessage(error),
|
|
225
262
|
runRecordPath: result.runRecordPath,
|
|
226
263
|
});
|
|
264
|
+
break;
|
|
227
265
|
}
|
|
266
|
+
if (recorded)
|
|
267
|
+
await options.onTaskFinalized?.({ status: result.status, taskSpec, workerRunId: result.workerRunId, runRecordPath: result.runRecordPath });
|
|
228
268
|
}
|
|
229
269
|
const summary = summarize(tasks);
|
|
230
270
|
const batchRunPath = path.join(getTaskPoolRoot(options.repoRoot), "artifacts", batchRunId, "batch-run.json");
|
|
@@ -237,6 +277,7 @@ export async function runReadyTasks(options) {
|
|
|
237
277
|
summary,
|
|
238
278
|
tasks,
|
|
239
279
|
batchRunPath,
|
|
280
|
+
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
240
281
|
};
|
|
241
282
|
await mkdir(path.dirname(batchRunPath), { recursive: true });
|
|
242
283
|
await writeFile(batchRunPath, `${JSON.stringify(output, null, 2)}\n`, "utf-8");
|
|
@@ -260,18 +301,55 @@ function emit(progress, input) {
|
|
|
260
301
|
export function buildBatchRunId(now) {
|
|
261
302
|
return `batch-${now.toISOString().replace(/[-:.]/g, "").slice(0, 15)}`;
|
|
262
303
|
}
|
|
263
|
-
export function buildStableWorkerRunId(taskId, taskSpec, now) {
|
|
304
|
+
export function buildStableWorkerRunId(taskId, taskSpec, now, controllerIdentity) {
|
|
264
305
|
const date = now.toISOString().slice(0, 10).replace(/-/g, "");
|
|
265
306
|
const slug = taskId
|
|
266
307
|
.toLowerCase()
|
|
267
308
|
.replace(/[^a-z0-9]+/g, "-")
|
|
268
309
|
.replace(/^-+|-+$/g, "");
|
|
269
310
|
const hash = createHash("sha256")
|
|
270
|
-
.update(
|
|
311
|
+
.update([
|
|
312
|
+
taskSpec.feature_id,
|
|
313
|
+
taskSpec.id,
|
|
314
|
+
taskSpec.title,
|
|
315
|
+
...(controllerIdentity
|
|
316
|
+
? [
|
|
317
|
+
controllerIdentity.packageName,
|
|
318
|
+
controllerIdentity.packageVersion,
|
|
319
|
+
controllerIdentity.binarySha256,
|
|
320
|
+
controllerIdentity.packageFingerprint.value,
|
|
321
|
+
]
|
|
322
|
+
: []),
|
|
323
|
+
].join(":"))
|
|
271
324
|
.digest("hex")
|
|
272
325
|
.slice(0, 10);
|
|
273
326
|
return `wr-${date}-${slug}-${hash}`;
|
|
274
327
|
}
|
|
328
|
+
function buildControllerScopedWorkerRunId(baseWorkerRunId, controllerIdentity) {
|
|
329
|
+
const hash = createHash("sha256")
|
|
330
|
+
.update(controllerIdentity
|
|
331
|
+
? JSON.stringify({
|
|
332
|
+
packageName: controllerIdentity.packageName,
|
|
333
|
+
binName: controllerIdentity.binName,
|
|
334
|
+
packageVersion: controllerIdentity.packageVersion,
|
|
335
|
+
binarySha256: controllerIdentity.binarySha256,
|
|
336
|
+
packageFingerprint: controllerIdentity.packageFingerprint.value,
|
|
337
|
+
requested: controllerIdentity.requested,
|
|
338
|
+
entry: controllerIdentity.entry,
|
|
339
|
+
realEntry: controllerIdentity.realEntry,
|
|
340
|
+
launch: controllerIdentity.launch,
|
|
341
|
+
packageRoot: controllerIdentity.packageRoot,
|
|
342
|
+
})
|
|
343
|
+
: "legacy-unpinned-controller")
|
|
344
|
+
.digest("hex")
|
|
345
|
+
.slice(0, 10);
|
|
346
|
+
return `${baseWorkerRunId}-controller-${hash}`;
|
|
347
|
+
}
|
|
348
|
+
function controllerRunCanBeReused(existing, controllerIdentity) {
|
|
349
|
+
if (!existing.controllerIdentity && !controllerIdentity)
|
|
350
|
+
return true;
|
|
351
|
+
return controllerIdentitiesMatch(existing.controllerIdentity, controllerIdentity);
|
|
352
|
+
}
|
|
275
353
|
/** A retry is a distinct execution attempt and must not collide with failed evidence. */
|
|
276
354
|
export function buildRetryWorkerRunId(taskId, previousWorkerRunId, now) {
|
|
277
355
|
const date = now.toISOString().slice(0, 10).replace(/-/g, "");
|
|
@@ -97,7 +97,6 @@ export const taskSpecSchema = z
|
|
|
97
97
|
profile_policy: z.literal("mapped"),
|
|
98
98
|
strict_models: z.boolean().optional().default(true),
|
|
99
99
|
strict_governance: z.boolean().optional().default(true),
|
|
100
|
-
no_cursor: z.boolean().optional().default(false),
|
|
101
100
|
max_concurrent: z.number().int().positive().optional().default(1),
|
|
102
101
|
})
|
|
103
102
|
.strict(),
|
|
@@ -5,7 +5,7 @@ import { freshNodeRecord } from "../dynamic-runtime/shared.js";
|
|
|
5
5
|
const CONVERGENCE_CHAIN_NODE_IDS = [
|
|
6
6
|
"process-supervisor-pi",
|
|
7
7
|
"process-gate-shell",
|
|
8
|
-
"repair-
|
|
8
|
+
"repair-pi",
|
|
9
9
|
"hard-verify-shell",
|
|
10
10
|
];
|
|
11
11
|
const CONVERGENCE_NON_RETRY_FAILURES = new Set([
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { executeDagCursorNode } from "../../executors/dag-cursor-executor.js";
|
|
2
1
|
import { executeDagPiNode } from "../../executors/dag-pi-executor.js";
|
|
3
2
|
import { executeDagShellNode } from "../../executors/shell-executor.js";
|
|
4
3
|
import { executeDagStaticNode } from "../../executors/dag-static-executor.js";
|
|
@@ -9,7 +8,6 @@ function requireModel(input) {
|
|
|
9
8
|
return input;
|
|
10
9
|
}
|
|
11
10
|
export const DEFAULT_DAG_EXECUTOR_REGISTRY = {
|
|
12
|
-
cursor: (input, meta) => executeDagCursorNode(requireModel(input), meta),
|
|
13
11
|
pi: (input, meta) => executeDagPiNode(requireModel(input), meta),
|
|
14
12
|
shell: executeDagShellNode,
|
|
15
13
|
static: executeDagStaticNode,
|
|
@@ -147,6 +147,9 @@ function hasPostImplementationShellVerification(spec, ranks) {
|
|
|
147
147
|
}
|
|
148
148
|
return false;
|
|
149
149
|
}
|
|
150
|
+
function hasBackendTestTopology(spec) {
|
|
151
|
+
return spec.tasks.some((task) => /execute-backend-pytest|generate-backend-functional-cases|review-backend-cases|generate-backend-pytest|test-retrospect/i.test(task.id));
|
|
152
|
+
}
|
|
150
153
|
function hasSupervisedTopology(spec) {
|
|
151
154
|
const hasSupervisor = spec.tasks.some((task) => task.role === "supervisor");
|
|
152
155
|
const hasRepairWriter = spec.tasks.some((task) => isRepairNode(task) && isExclusiveWriter(task, spec));
|
|
@@ -302,6 +305,10 @@ function buildProfileReasons(profile, process, delivery, codeChange, supervisedT
|
|
|
302
305
|
reasons.push("supervised topology detected (supervisor + repair + write-set/process/review gates)");
|
|
303
306
|
return reasons;
|
|
304
307
|
}
|
|
308
|
+
if (profile === "backend-test") {
|
|
309
|
+
reasons.push("backend-test topology detected (analyze → functional cases → review → pytest → execute → retrospect)");
|
|
310
|
+
return reasons;
|
|
311
|
+
}
|
|
305
312
|
if (supervisedTopology) {
|
|
306
313
|
reasons.push("partial supervised markers present but topology incomplete; profile downgraded");
|
|
307
314
|
}
|
|
@@ -337,6 +344,9 @@ function buildProfileReasons(profile, process, delivery, codeChange, supervisedT
|
|
|
337
344
|
return reasons;
|
|
338
345
|
}
|
|
339
346
|
function inferProfileName(spec, process, delivery, codeChange, ranks) {
|
|
347
|
+
if (hasBackendTestTopology(spec)) {
|
|
348
|
+
return "backend-test";
|
|
349
|
+
}
|
|
340
350
|
if (hasSupervisedTopology(spec)) {
|
|
341
351
|
return "supervised";
|
|
342
352
|
}
|