auditor-lambda 0.10.3 → 0.10.8
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/audit-code-wrapper-build.mjs +198 -0
- package/audit-code-wrapper-install-hosts.mjs +1140 -0
- package/audit-code-wrapper-io.mjs +155 -0
- package/audit-code-wrapper-legacy.mjs +125 -0
- package/audit-code-wrapper-lib.mjs +22 -1806
- package/audit-code-wrapper-opencode.mjs +255 -0
- package/dispatch/merge-results.mjs +5 -3
- package/dispatch/validate-result.mjs +2 -2
- package/dist/adapters/coverageSummary.js +6 -2
- package/dist/adapters/normalizeExternal.js +16 -1
- package/dist/adapters/npmAudit.js +20 -9
- package/dist/adapters/semgrep.js +26 -1
- package/dist/cli/advanceAuditCommand.d.ts +1 -0
- package/dist/cli/advanceAuditCommand.js +95 -0
- package/dist/cli/args.js +2 -3
- package/dist/cli/auditStep.js +2 -2
- package/dist/cli/cleanup.d.ts +11 -1
- package/dist/cli/cleanup.js +25 -5
- package/dist/cli/cleanupCommand.d.ts +1 -0
- package/dist/cli/cleanupCommand.js +24 -0
- package/dist/cli/dispatch.d.ts +55 -31
- package/dist/cli/dispatch.js +298 -241
- package/dist/cli/dispatchStatusCommand.d.ts +1 -0
- package/dist/cli/dispatchStatusCommand.js +68 -0
- package/dist/cli/explainTaskCommand.d.ts +1 -0
- package/dist/cli/explainTaskCommand.js +33 -0
- package/dist/cli/importExternalAnalyzerCommand.d.ts +1 -0
- package/dist/cli/importExternalAnalyzerCommand.js +20 -0
- package/dist/cli/ingestResultsCommand.d.ts +1 -0
- package/dist/cli/ingestResultsCommand.js +34 -0
- package/dist/cli/intakeCommand.d.ts +1 -0
- package/dist/cli/intakeCommand.js +17 -0
- package/dist/cli/lineIndex.js +19 -12
- package/dist/cli/nextStepCommand.d.ts +139 -0
- package/dist/cli/nextStepCommand.js +281 -234
- package/dist/cli/planCommand.d.ts +1 -0
- package/dist/cli/planCommand.js +16 -0
- package/dist/cli/prepareDispatchCommand.d.ts +1 -0
- package/dist/cli/prepareDispatchCommand.js +25 -0
- package/dist/cli/quotaCommand.d.ts +1 -0
- package/dist/cli/quotaCommand.js +56 -0
- package/dist/cli/requeueCommand.d.ts +1 -0
- package/dist/cli/requeueCommand.js +10 -0
- package/dist/cli/runToCompletion.js +451 -412
- package/dist/cli/sampleRunCommand.d.ts +1 -0
- package/dist/cli/sampleRunCommand.js +93 -0
- package/dist/cli/statusCommand.js +1 -1
- package/dist/cli/steps.js +4 -1
- package/dist/cli/submitPacketCommand.js +16 -15
- package/dist/cli/synthesizeCommand.d.ts +1 -0
- package/dist/cli/synthesizeCommand.js +15 -0
- package/dist/cli/updateRuntimeValidationCommand.d.ts +1 -0
- package/dist/cli/updateRuntimeValidationCommand.js +16 -0
- package/dist/cli/validateCommand.d.ts +1 -0
- package/dist/cli/validateCommand.js +41 -0
- package/dist/cli/validateResultCommand.d.ts +1 -0
- package/dist/cli/validateResultCommand.js +63 -0
- package/dist/cli/validateResultsCommand.d.ts +1 -0
- package/dist/cli/validateResultsCommand.js +31 -0
- package/dist/cli/workerRunCommand.d.ts +15 -1
- package/dist/cli/workerRunCommand.js +40 -4
- package/dist/cli.d.ts +3 -2
- package/dist/cli.js +21 -628
- package/dist/coverage.js +7 -3
- package/dist/extractors/analyzers/css.js +2 -2
- package/dist/extractors/analyzers/html.js +2 -2
- package/dist/extractors/analyzers/python.js +2 -2
- package/dist/extractors/analyzers/registry.js +17 -36
- package/dist/extractors/analyzers/treeSitter.d.ts +10 -1
- package/dist/extractors/analyzers/treeSitter.js +28 -6
- package/dist/extractors/analyzers/typescript.js +104 -85
- package/dist/extractors/browserExtension.js +4 -1
- package/dist/extractors/designAssessment.js +21 -21
- package/dist/extractors/fsIntake.js +35 -11
- package/dist/extractors/graph.js +17 -7
- package/dist/extractors/graphManifestEdges/cargo.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/cargo.js +107 -0
- package/dist/extractors/graphManifestEdges/go.d.ts +5 -0
- package/dist/extractors/graphManifestEdges/go.js +151 -0
- package/dist/extractors/graphManifestEdges/index.d.ts +8 -0
- package/dist/extractors/graphManifestEdges/index.js +11 -0
- package/dist/extractors/graphManifestEdges/jsonc.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/jsonc.js +97 -0
- package/dist/extractors/graphManifestEdges/maven.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/maven.js +73 -0
- package/dist/extractors/graphManifestEdges/packageJson.d.ts +19 -0
- package/dist/extractors/graphManifestEdges/packageJson.js +204 -0
- package/dist/extractors/graphManifestEdges/pnpm.d.ts +2 -0
- package/dist/extractors/graphManifestEdges/pnpm.js +42 -0
- package/dist/extractors/graphManifestEdges/pyproject.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/pyproject.js +83 -0
- package/dist/extractors/graphManifestEdges/toml.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/toml.js +68 -0
- package/dist/extractors/graphManifestEdges/typescript.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/typescript.js +56 -0
- package/dist/extractors/graphManifestEdges/workspace.d.ts +10 -0
- package/dist/extractors/graphManifestEdges/workspace.js +72 -0
- package/dist/extractors/graphManifestEdges/yaml.d.ts +3 -0
- package/dist/extractors/graphManifestEdges/yaml.js +59 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.d.ts +4 -0
- package/dist/extractors/graphManifestEdges/yamlPaths.js +89 -0
- package/dist/extractors/graphPythonImports.js +4 -20
- package/dist/extractors/pathPatterns.js +3 -13
- package/dist/io/artifacts.d.ts +1 -2
- package/dist/io/artifacts.js +8 -4
- package/dist/io/runArtifacts.d.ts +8 -2
- package/dist/io/runArtifacts.js +103 -69
- package/dist/io/toolingManifest.js +2 -1
- package/dist/orchestrator/advance.js +36 -0
- package/dist/orchestrator/artifactFreshness.d.ts +1 -1
- package/dist/orchestrator/artifactFreshness.js +1 -1
- package/dist/orchestrator/artifactMetadata.js +5 -5
- package/dist/orchestrator/auditTaskUtils.d.ts +4 -0
- package/dist/orchestrator/auditTaskUtils.js +8 -12
- package/dist/orchestrator/autoFixExecutor.js +40 -26
- package/dist/orchestrator/dependencyMap.js +1 -1
- package/dist/orchestrator/executorResult.d.ts +33 -0
- package/dist/orchestrator/executors.d.ts +7 -0
- package/dist/orchestrator/executors.js +24 -0
- package/dist/orchestrator/fileAnchors.js +42 -29
- package/dist/orchestrator/fileIntegrity.js +6 -1
- package/dist/orchestrator/flowCoverage.js +1 -2
- package/dist/orchestrator/flowPlanning.js +8 -4
- package/dist/orchestrator/graphEnrichmentExecutor.js +67 -45
- package/dist/orchestrator/ingestionExecutors.js +9 -1
- package/dist/orchestrator/intakeExecutors.d.ts +0 -4
- package/dist/orchestrator/intakeExecutors.js +24 -14
- package/dist/orchestrator/localCommands.d.ts +1 -0
- package/dist/orchestrator/localCommands.js +10 -17
- package/dist/orchestrator/nextStep.js +3 -1
- package/dist/orchestrator/requeueCommand.js +4 -0
- package/dist/orchestrator/reviewPacketGraph.js +50 -18
- package/dist/orchestrator/reviewPackets.js +10 -8
- package/dist/orchestrator/runtimeCommand.js +35 -7
- package/dist/orchestrator/runtimeValidationUpdate.js +6 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +3 -2
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +44 -18
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/state.js +1 -1
- package/dist/orchestrator/syntaxResolutionExecutor.js +17 -24
- package/dist/orchestrator/synthesisExecutors.js +1 -0
- package/dist/orchestrator/taskBuilder.js +5 -4
- package/dist/providers/claudeCodeProvider.js +5 -2
- package/dist/providers/opencodeProvider.js +4 -1
- package/dist/quota/discoveredLimits.js +3 -3
- package/dist/quota/headerExtraction.js +5 -2
- package/dist/quota/headerExtractors/claudeCodeHeaderExtractor.js +3 -0
- package/dist/quota/headerExtractors/index.js +3 -3
- package/dist/quota/index.d.ts +3 -1
- package/dist/quota/index.js +3 -0
- package/dist/reporting/findingRanks.d.ts +3 -0
- package/dist/reporting/findingRanks.js +24 -0
- package/dist/reporting/mergeFindings.js +1 -24
- package/dist/reporting/synthesis.d.ts +3 -1
- package/dist/reporting/synthesis.js +30 -6
- package/dist/reporting/synthesisNarrativePrompt.js +3 -0
- package/dist/reporting/workBlocks.js +1 -14
- package/dist/supervisor/operatorHandoff.js +2 -6
- package/dist/supervisor/runLedger.js +30 -41
- package/dist/types/activeDispatch.d.ts +31 -0
- package/dist/types/activeDispatch.js +2 -0
- package/dist/types.d.ts +21 -4
- package/dist/types.js +24 -16
- package/dist/validation/artifacts.js +3 -0
- package/dist/validation/auditResults.js +8 -2
- package/package.json +2 -2
- package/schemas/audit_findings.schema.json +5 -1
- package/schemas/audit_plan_metrics.schema.json +1 -1
- package/schemas/audit_result.schema.json +5 -6
- package/schemas/audit_task.schema.json +1 -4
- package/schemas/blind_spot_register.schema.json +1 -1
- package/schemas/coverage_matrix.schema.json +2 -8
- package/schemas/finding.schema.json +1 -16
- package/schemas/flow_coverage.schema.json +2 -8
- package/schemas/graph_bundle.schema.json +31 -0
- package/schemas/lens.schema.json +7 -0
- package/schemas/review_packets.schema.json +6 -17
- package/schemas/step_contract.schema.json +8 -2
- package/schemas/unit_manifest.schema.json +1 -4
- package/scripts/postinstall.mjs +4 -3
- package/skills/audit-code/audit-code.prompt.md +3 -4
- package/dist/extractors/graphManifestEdges.d.ts +0 -12
- package/dist/extractors/graphManifestEdges.js +0 -1135
|
@@ -247,55 +247,13 @@ async function recordWaveQuota(params) {
|
|
|
247
247
|
}
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
-
async function
|
|
251
|
-
const { root, artifactsDir, runId,
|
|
250
|
+
async function applyWorkerResult(params) {
|
|
251
|
+
const { root, artifactsDir, runId, obligationId, providerName, preferredExecutor, workerResult, paths, startedAt, auditResultsPath, runtimeUpdatesPath, externalAnalyzerPath, decision, pendingBatchAuditResults, } = params;
|
|
252
252
|
let anyProgress = params.anyProgress;
|
|
253
253
|
let pendingAuditResultsPath = params.pendingAuditResultsPath;
|
|
254
254
|
let pendingRuntimeUpdatesPath = params.pendingRuntimeUpdatesPath;
|
|
255
255
|
let pendingExternalAnalyzerPath = params.pendingExternalAnalyzerPath;
|
|
256
|
-
|
|
257
|
-
const startedAt = new Date().toISOString();
|
|
258
|
-
let workerResult;
|
|
259
|
-
try {
|
|
260
|
-
const result = await runAuditStep({
|
|
261
|
-
root,
|
|
262
|
-
artifactsDir,
|
|
263
|
-
preferredExecutor,
|
|
264
|
-
auditResultsPath,
|
|
265
|
-
runtimeUpdatesPath,
|
|
266
|
-
externalAnalyzerPath,
|
|
267
|
-
analyzers,
|
|
268
|
-
since,
|
|
269
|
-
});
|
|
270
|
-
workerResult = {
|
|
271
|
-
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
272
|
-
run_id: runId,
|
|
273
|
-
obligation_id: obligationId,
|
|
274
|
-
status: result.progress_made ? "completed" : "no_progress",
|
|
275
|
-
progress_made: result.progress_made,
|
|
276
|
-
selected_executor: result.selected_executor,
|
|
277
|
-
artifacts_written: result.artifacts_written,
|
|
278
|
-
summary: result.progress_summary,
|
|
279
|
-
next_likely_step: result.next_likely_step,
|
|
280
|
-
errors: [],
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
catch (error) {
|
|
284
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
285
|
-
workerResult = {
|
|
286
|
-
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
287
|
-
run_id: runId,
|
|
288
|
-
obligation_id: obligationId,
|
|
289
|
-
status: "failed",
|
|
290
|
-
progress_made: false,
|
|
291
|
-
selected_executor: preferredExecutor,
|
|
292
|
-
artifacts_written: [],
|
|
293
|
-
summary: `Inline executor failed for ${preferredExecutor}: ${message}`,
|
|
294
|
-
next_likely_step: decision.selected_obligation,
|
|
295
|
-
errors: [message],
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
await persistWorkerRunArtifacts(paths, workerResult, "inline");
|
|
256
|
+
const artifactsWritten = params.artifactsWritten;
|
|
299
257
|
await appendRunLedgerEntry(artifactsDir, {
|
|
300
258
|
run_id: runId,
|
|
301
259
|
provider: providerName,
|
|
@@ -339,7 +297,7 @@ async function runInlineStep(params) {
|
|
|
339
297
|
executor: workerResult.selected_executor,
|
|
340
298
|
blocker: buildWorkerFailureBlocker(workerResult),
|
|
341
299
|
})
|
|
342
|
-
: bundleAfter.audit_state ?? deriveAuditState(bundleAfter);
|
|
300
|
+
: (bundleAfter.audit_state ?? deriveAuditState(bundleAfter));
|
|
343
301
|
if (shouldBlock) {
|
|
344
302
|
await writeCoreArtifacts(artifactsDir, {
|
|
345
303
|
...bundleAfter,
|
|
@@ -385,6 +343,77 @@ async function runInlineStep(params) {
|
|
|
385
343
|
pendingExternalAnalyzerPath,
|
|
386
344
|
};
|
|
387
345
|
}
|
|
346
|
+
async function runInlineStep(params) {
|
|
347
|
+
const { root, artifactsDir, runId, paths, preferredExecutor, obligationId, auditResultsPath, runtimeUpdatesPath, externalAnalyzerPath, analyzers, since, artifactsWritten, providerName, decision, pendingBatchAuditResults, } = params;
|
|
348
|
+
let anyProgress = params.anyProgress;
|
|
349
|
+
let pendingAuditResultsPath = params.pendingAuditResultsPath;
|
|
350
|
+
let pendingRuntimeUpdatesPath = params.pendingRuntimeUpdatesPath;
|
|
351
|
+
let pendingExternalAnalyzerPath = params.pendingExternalAnalyzerPath;
|
|
352
|
+
await clearDispatchFiles(artifactsDir);
|
|
353
|
+
const startedAt = new Date().toISOString();
|
|
354
|
+
let workerResult;
|
|
355
|
+
try {
|
|
356
|
+
const result = await runAuditStep({
|
|
357
|
+
root,
|
|
358
|
+
artifactsDir,
|
|
359
|
+
preferredExecutor,
|
|
360
|
+
auditResultsPath,
|
|
361
|
+
runtimeUpdatesPath,
|
|
362
|
+
externalAnalyzerPath,
|
|
363
|
+
analyzers,
|
|
364
|
+
since,
|
|
365
|
+
});
|
|
366
|
+
workerResult = {
|
|
367
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
368
|
+
run_id: runId,
|
|
369
|
+
obligation_id: obligationId,
|
|
370
|
+
status: result.progress_made ? "completed" : "no_progress",
|
|
371
|
+
progress_made: result.progress_made,
|
|
372
|
+
selected_executor: result.selected_executor,
|
|
373
|
+
artifacts_written: result.artifacts_written,
|
|
374
|
+
summary: result.progress_summary,
|
|
375
|
+
next_likely_step: result.next_likely_step,
|
|
376
|
+
errors: [],
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
381
|
+
workerResult = {
|
|
382
|
+
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
383
|
+
run_id: runId,
|
|
384
|
+
obligation_id: obligationId,
|
|
385
|
+
status: "failed",
|
|
386
|
+
progress_made: false,
|
|
387
|
+
selected_executor: preferredExecutor,
|
|
388
|
+
artifacts_written: [],
|
|
389
|
+
summary: `Inline executor failed for ${preferredExecutor}: ${message}`,
|
|
390
|
+
next_likely_step: decision.selected_obligation,
|
|
391
|
+
errors: [message],
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
await persistWorkerRunArtifacts(paths, workerResult, "inline");
|
|
395
|
+
return applyWorkerResult({
|
|
396
|
+
root,
|
|
397
|
+
artifactsDir,
|
|
398
|
+
runId,
|
|
399
|
+
obligationId,
|
|
400
|
+
providerName,
|
|
401
|
+
preferredExecutor,
|
|
402
|
+
workerResult,
|
|
403
|
+
paths,
|
|
404
|
+
startedAt,
|
|
405
|
+
anyProgress,
|
|
406
|
+
artifactsWritten,
|
|
407
|
+
pendingBatchAuditResults,
|
|
408
|
+
pendingAuditResultsPath,
|
|
409
|
+
pendingRuntimeUpdatesPath,
|
|
410
|
+
pendingExternalAnalyzerPath,
|
|
411
|
+
auditResultsPath,
|
|
412
|
+
runtimeUpdatesPath,
|
|
413
|
+
externalAnalyzerPath,
|
|
414
|
+
decision,
|
|
415
|
+
});
|
|
416
|
+
}
|
|
388
417
|
async function runSingleWorkerStep(params) {
|
|
389
418
|
const { root, artifactsDir, selfCliPath, runId, paths, preferredExecutor, obligationId, auditResultsPath, runtimeUpdatesPath, externalAnalyzerPath, bundle, timeoutMs, uiMode, provider, artifactsWritten, decision, pendingBatchAuditResults, } = params;
|
|
390
419
|
let anyProgress = params.anyProgress;
|
|
@@ -493,94 +522,355 @@ async function runSingleWorkerStep(params) {
|
|
|
493
522
|
};
|
|
494
523
|
await persistWorkerRunArtifacts(paths, workerResult, "provider-launch");
|
|
495
524
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
525
|
+
return applyWorkerResult({
|
|
526
|
+
root,
|
|
527
|
+
artifactsDir,
|
|
528
|
+
runId,
|
|
529
|
+
obligationId,
|
|
530
|
+
providerName: provider.name,
|
|
531
|
+
preferredExecutor,
|
|
532
|
+
workerResult,
|
|
533
|
+
paths,
|
|
534
|
+
startedAt,
|
|
535
|
+
anyProgress,
|
|
536
|
+
artifactsWritten,
|
|
537
|
+
pendingBatchAuditResults,
|
|
538
|
+
pendingAuditResultsPath,
|
|
539
|
+
pendingRuntimeUpdatesPath,
|
|
540
|
+
pendingExternalAnalyzerPath,
|
|
541
|
+
auditResultsPath: providerAuditResultsPath,
|
|
542
|
+
runtimeUpdatesPath,
|
|
543
|
+
externalAnalyzerPath,
|
|
544
|
+
decision,
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
async function handleLocalSubprocessBlock(params) {
|
|
548
|
+
const { root, artifactsDir, selfCliPath, bundle, argv, obligationId, preferredExecutor, provider, sessionConfig, timeoutMs, runCount, anyProgress, artifactsWritten, } = params;
|
|
549
|
+
if (preferredExecutor !== "agent" || provider.name !== LOCAL_SUBPROCESS_PROVIDER_NAME) {
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
const blocker = buildManualReviewBlocker(provider.name);
|
|
553
|
+
const blockedState = buildBlockedAuditState({
|
|
554
|
+
state: bundle.audit_state ?? deriveAuditState(bundle),
|
|
555
|
+
obligationId,
|
|
556
|
+
executor: preferredExecutor,
|
|
557
|
+
blocker,
|
|
558
|
+
});
|
|
559
|
+
await writeCoreArtifacts(artifactsDir, {
|
|
560
|
+
...bundle,
|
|
561
|
+
audit_state: blockedState,
|
|
562
|
+
});
|
|
563
|
+
const blockRunId = buildRunId(obligationId, runCount + 1);
|
|
564
|
+
const blockPaths = getRunPaths(artifactsDir, blockRunId);
|
|
565
|
+
const blockPendingTasks = await addFileLineCountHints(root, buildPendingAuditTasks(bundle));
|
|
566
|
+
const blockPendingTasksPath = join(blockPaths.runDir, "pending-audit-tasks.json");
|
|
567
|
+
const blockAuditResultsPath = join(blockPaths.runDir, "run-results.json");
|
|
568
|
+
const blockReadPaths = new Set();
|
|
569
|
+
for (const pt of blockPendingTasks) {
|
|
570
|
+
for (const fp of pt.file_paths)
|
|
571
|
+
blockReadPaths.add(fp);
|
|
572
|
+
}
|
|
573
|
+
const blockTask = {
|
|
574
|
+
contract_version: "audit-code-worker/v1alpha1",
|
|
575
|
+
run_id: blockRunId,
|
|
576
|
+
repo_root: root,
|
|
577
|
+
artifacts_dir: artifactsDir,
|
|
499
578
|
obligation_id: obligationId,
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
579
|
+
preferred_executor: preferredExecutor,
|
|
580
|
+
result_path: blockPaths.resultPath,
|
|
581
|
+
worker_command: [
|
|
582
|
+
process.execPath,
|
|
583
|
+
selfCliPath,
|
|
584
|
+
"worker-run",
|
|
585
|
+
"--task",
|
|
586
|
+
blockPaths.taskPath,
|
|
587
|
+
],
|
|
588
|
+
audit_results_path: blockAuditResultsPath,
|
|
589
|
+
pending_audit_tasks_path: blockPendingTasksPath,
|
|
590
|
+
timeout_ms: timeoutMs,
|
|
591
|
+
max_retries: 0,
|
|
592
|
+
access: {
|
|
593
|
+
read_paths: [...blockReadPaths],
|
|
594
|
+
write_paths: [blockAuditResultsPath, blockPaths.resultPath],
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
const blockPrompt = renderWorkerPrompt(blockTask);
|
|
598
|
+
await writeWorkerTaskFiles(blockTask, blockPrompt, blockPaths, artifactsDir, blockPendingTasks);
|
|
599
|
+
await writeJsonFile(blockPendingTasksPath, blockPendingTasks);
|
|
600
|
+
const reviewRun = {
|
|
601
|
+
run_id: blockRunId,
|
|
602
|
+
task_path: blockPaths.taskPath,
|
|
603
|
+
prompt_path: blockPaths.promptPath,
|
|
604
|
+
pending_audit_tasks_path: blockPendingTasksPath,
|
|
605
|
+
audit_results_path: blockAuditResultsPath,
|
|
606
|
+
worker_command: blockTask.worker_command,
|
|
607
|
+
};
|
|
608
|
+
// Render the actionable dispatch / single-task step here instead of
|
|
609
|
+
// leaving the host to issue next-step as a second command. Capability is
|
|
610
|
+
// resolved from flags/config/env with a sane default, so nothing is
|
|
611
|
+
// required from the host to make progress. If rendering fails we still
|
|
612
|
+
// emit the hand-off below — run-to-completion is never worse than before,
|
|
613
|
+
// and next-step will re-render and surface the error loudly.
|
|
614
|
+
try {
|
|
615
|
+
await renderSemanticReviewStep({
|
|
616
|
+
root,
|
|
617
|
+
artifactsDir,
|
|
618
|
+
activeReviewRun: reviewRun,
|
|
619
|
+
hostCanDispatch: resolveHostDispatchCapability({
|
|
620
|
+
explicit: getOptionalBooleanFlag(argv, "--host-can-dispatch-subagents"),
|
|
621
|
+
sessionConfig,
|
|
622
|
+
}),
|
|
623
|
+
hostMaxActiveSubagents: getHostMaxActiveSubagents(argv),
|
|
624
|
+
hostCanRestrictSubagentTools: getOptionalBooleanFlag(argv, "--host-can-restrict-subagent-tools") ?? false,
|
|
625
|
+
hostCanSelectSubagentModel: getOptionalBooleanFlag(argv, "--host-can-select-subagent-model") ?? false,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
catch (stepError) {
|
|
629
|
+
process.stderr.write(`[audit-code] Could not pre-render the review step; the operator hand-off points to next-step instead. ${stepError instanceof Error ? stepError.message : String(stepError)}\n`);
|
|
630
|
+
}
|
|
631
|
+
await emitEnvelope({
|
|
632
|
+
root,
|
|
633
|
+
artifactsDir,
|
|
634
|
+
bundle: {
|
|
635
|
+
...bundle,
|
|
636
|
+
audit_state: blockedState,
|
|
637
|
+
},
|
|
638
|
+
audit_state: blockedState,
|
|
639
|
+
selected_obligation: obligationId,
|
|
640
|
+
selected_executor: preferredExecutor,
|
|
641
|
+
progress_made: anyProgress,
|
|
642
|
+
artifacts_written: Array.from(new Set([...artifactsWritten, "audit_state.json"])),
|
|
643
|
+
progress_summary: blocker,
|
|
644
|
+
next_likely_step: null,
|
|
645
|
+
providerName: provider.name,
|
|
646
|
+
activeReviewRun: reviewRun,
|
|
505
647
|
});
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
async function handleNoExecutor(params) {
|
|
651
|
+
const { root, artifactsDir, bundle, decision, lastResult, anyProgress, artifactsWritten, runCount, providerName, } = params;
|
|
652
|
+
const state = decision.state;
|
|
653
|
+
await clearDispatchFiles(artifactsDir);
|
|
654
|
+
await emitEnvelope({
|
|
655
|
+
root,
|
|
656
|
+
artifactsDir,
|
|
657
|
+
bundle,
|
|
658
|
+
audit_state: state,
|
|
659
|
+
selected_obligation: anyProgress
|
|
660
|
+
? (lastResult?.obligation_id ?? null)
|
|
661
|
+
: null,
|
|
662
|
+
selected_executor: anyProgress
|
|
663
|
+
? (lastResult?.selected_executor ?? null)
|
|
664
|
+
: null,
|
|
665
|
+
progress_made: anyProgress,
|
|
666
|
+
artifacts_written: Array.from(artifactsWritten),
|
|
667
|
+
progress_summary: anyProgress && state.status === "complete"
|
|
668
|
+
? `Completed audit in ${runCount} fresh worker runs.`
|
|
669
|
+
: decision.reason,
|
|
670
|
+
next_likely_step: state.status === "complete" ? null : decision.selected_obligation,
|
|
671
|
+
providerName,
|
|
672
|
+
});
|
|
673
|
+
if (state.status === "complete") {
|
|
674
|
+
await promoteFinalAuditReport({ artifactsDir });
|
|
509
675
|
}
|
|
510
|
-
|
|
511
|
-
|
|
676
|
+
}
|
|
677
|
+
async function runParallelWaveStep(params) {
|
|
678
|
+
const { root, artifactsDir, selfCliPath, bundle, argv, sessionConfig, provider, hostModel, obligationId, parallelWorkers, agentBatchSize, timeoutMs, uiMode, } = params;
|
|
679
|
+
let runCount = params.runCount;
|
|
680
|
+
let anyProgress = params.anyProgress;
|
|
681
|
+
const artifactsWritten = params.artifactsWritten;
|
|
682
|
+
const quotaState = await readQuotaState();
|
|
683
|
+
const normalizedHostModel = hostModel ?? null;
|
|
684
|
+
const providerModelKey = buildProviderModelKey(provider.name, normalizedHostModel);
|
|
685
|
+
const quotaStateEntry = quotaState.entries[providerModelKey] ?? null;
|
|
686
|
+
const allCandidateTasks = buildPendingAuditTasks(bundle);
|
|
687
|
+
const candidateGroups = chunkArray(allCandidateTasks.slice(0, parallelWorkers * agentBatchSize), agentBatchSize);
|
|
688
|
+
const candidateSizeIndex = sizeIndexFromManifest(bundle.repo_manifest);
|
|
689
|
+
const slotTokenEstimates = candidateGroups.map((g) => estimateTaskGroupTokens(g, candidateSizeIndex));
|
|
690
|
+
const providerLimits = await provider.queryLimits?.(normalizedHostModel)
|
|
691
|
+
.then((r) => r ? { ...r, source: "provider_query" } : null)
|
|
692
|
+
.catch(() => null)
|
|
693
|
+
?? null;
|
|
694
|
+
const cachedLimits = await lookupDiscoveredLimits(providerModelKey).catch(() => null);
|
|
695
|
+
const discoveredLimits = mergeDiscoveredLimits(providerLimits, cachedLimits);
|
|
696
|
+
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ?? 24;
|
|
697
|
+
const quotaSource = buildQuotaSource({ halfLifeHours });
|
|
698
|
+
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(providerModelKey).catch(() => null);
|
|
699
|
+
const hostConcurrencyLimit = resolveHostActiveSubagentLimit({ sessionConfig });
|
|
700
|
+
const waveSchedule = scheduleWave({
|
|
701
|
+
providerName: resolveFreshSessionProviderName(getExplicitProvider(argv), sessionConfig),
|
|
702
|
+
sessionConfig,
|
|
703
|
+
hostModel: normalizedHostModel,
|
|
704
|
+
requestedConcurrency: parallelWorkers,
|
|
705
|
+
estimatedSlotTokens: slotTokenEstimates,
|
|
706
|
+
quotaStateEntry,
|
|
707
|
+
hostConcurrencyLimit,
|
|
708
|
+
quotaSourceSnapshot,
|
|
709
|
+
discoveredLimits,
|
|
710
|
+
});
|
|
711
|
+
const waveSize = waveSchedule.wave_size;
|
|
712
|
+
if (waveSchedule.cooldown_until) {
|
|
713
|
+
const waitMs = new Date(waveSchedule.cooldown_until).getTime() - Date.now();
|
|
714
|
+
if (waitMs > 0) {
|
|
715
|
+
const cappedWait = Math.min(waitMs, 120_000);
|
|
716
|
+
process.stderr.write(`[quota] Cooldown active — waiting ${Math.ceil(cappedWait / 1000)}s before next wave.\n`);
|
|
717
|
+
await new Promise((r) => setTimeout(r, cappedWait));
|
|
718
|
+
}
|
|
512
719
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
720
|
+
const taskGroups = candidateGroups.slice(0, waveSize);
|
|
721
|
+
const { slots: workerSlots, runCountAfter } = await buildParallelWaveSlots({
|
|
722
|
+
root,
|
|
723
|
+
artifactsDir,
|
|
724
|
+
selfCliPath,
|
|
725
|
+
taskGroups,
|
|
726
|
+
obligationId,
|
|
727
|
+
runCountStart: runCount,
|
|
728
|
+
timeoutMs,
|
|
729
|
+
});
|
|
730
|
+
runCount = runCountAfter;
|
|
731
|
+
const parallelStartedAt = new Date().toISOString();
|
|
732
|
+
await writeWaveManifest(artifactsDir, {
|
|
733
|
+
obligation_id: obligationId ?? "unknown",
|
|
734
|
+
started_at: parallelStartedAt,
|
|
735
|
+
pid: process.pid,
|
|
736
|
+
slots: workerSlots.map(buildWaveSlotEntry),
|
|
737
|
+
});
|
|
738
|
+
const { results: launchResults } = await runSlidingWindow(workerSlots.map((slot) => () => provider.launch({
|
|
739
|
+
repoRoot: root,
|
|
740
|
+
runId: slot.runId,
|
|
741
|
+
obligationId,
|
|
742
|
+
promptPath: slot.paths.promptPath,
|
|
743
|
+
taskPath: slot.paths.taskPath,
|
|
744
|
+
resultPath: slot.paths.resultPath,
|
|
745
|
+
stdoutPath: slot.paths.stdoutPath,
|
|
746
|
+
stderrPath: slot.paths.stderrPath,
|
|
747
|
+
uiMode,
|
|
748
|
+
timeoutMs,
|
|
749
|
+
})), waveSize);
|
|
750
|
+
const launchErrorsByRunId = new Map();
|
|
751
|
+
for (let index = 0; index < launchResults.length; index++) {
|
|
752
|
+
const outcome = launchResults[index];
|
|
753
|
+
if (outcome?.status === "rejected") {
|
|
754
|
+
launchErrorsByRunId.set(workerSlots[index].runId, outcome.reason instanceof Error
|
|
755
|
+
? outcome.reason.message
|
|
756
|
+
: String(outcome.reason));
|
|
757
|
+
}
|
|
758
|
+
else if (outcome?.status === "fulfilled") {
|
|
759
|
+
const launchExitSummary = summarizeLaunchExit(outcome.value);
|
|
760
|
+
if (launchExitSummary) {
|
|
761
|
+
launchErrorsByRunId.set(workerSlots[index].runId, launchExitSummary);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
522
764
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
765
|
+
const ingestion = await ingestParallelWaveResults({
|
|
766
|
+
root,
|
|
767
|
+
artifactsDir,
|
|
768
|
+
workerSlots,
|
|
769
|
+
launchErrorsByRunId,
|
|
770
|
+
obligationId,
|
|
771
|
+
parallelStartedAt,
|
|
772
|
+
providerName: provider.name,
|
|
773
|
+
anyProgress,
|
|
774
|
+
artifactsWritten,
|
|
775
|
+
});
|
|
776
|
+
const batchProgress = ingestion.batchProgress;
|
|
777
|
+
const batchErrors = ingestion.batchErrors;
|
|
778
|
+
anyProgress = ingestion.anyProgress;
|
|
779
|
+
await recordWaveQuota({
|
|
780
|
+
providerModelKey,
|
|
781
|
+
providerName: provider.name,
|
|
782
|
+
workerSlots,
|
|
783
|
+
slotTokenEstimates,
|
|
784
|
+
batchErrors,
|
|
785
|
+
halfLifeHours: sessionConfig.quota?.empirical_half_life_hours ?? 24,
|
|
786
|
+
});
|
|
787
|
+
await removeWaveManifest(artifactsDir);
|
|
788
|
+
if (batchErrors.length > 0) {
|
|
530
789
|
const bundleAfter = await loadArtifactBundle(artifactsDir);
|
|
531
|
-
const
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
...bundleAfter,
|
|
543
|
-
audit_state: state,
|
|
544
|
-
});
|
|
545
|
-
}
|
|
790
|
+
const blockedState = buildBlockedAuditState({
|
|
791
|
+
state: bundleAfter.audit_state ?? deriveAuditState(bundleAfter),
|
|
792
|
+
obligationId,
|
|
793
|
+
executor: "agent",
|
|
794
|
+
blocker: `Parallel worker batch failed for ${batchErrors.length} run(s). ` +
|
|
795
|
+
batchErrors.slice(0, 3).join(" | "),
|
|
796
|
+
});
|
|
797
|
+
await writeCoreArtifacts(artifactsDir, {
|
|
798
|
+
...bundleAfter,
|
|
799
|
+
audit_state: blockedState,
|
|
800
|
+
});
|
|
546
801
|
await emitEnvelope({
|
|
547
802
|
root,
|
|
548
803
|
artifactsDir,
|
|
549
|
-
bundle:
|
|
550
|
-
|
|
551
|
-
|
|
804
|
+
bundle: { ...bundleAfter, audit_state: blockedState },
|
|
805
|
+
audit_state: blockedState,
|
|
806
|
+
selected_obligation: obligationId,
|
|
807
|
+
selected_executor: "agent",
|
|
808
|
+
progress_made: anyProgress,
|
|
809
|
+
artifacts_written: Array.from(new Set([...ingestion.artifactsWritten, "audit_state.json"])),
|
|
810
|
+
progress_summary: `Parallel worker batch failed for ${batchErrors.length} run(s).\n` +
|
|
811
|
+
batchErrors.join("\n"),
|
|
812
|
+
next_likely_step: null,
|
|
813
|
+
providerName: provider.name,
|
|
814
|
+
});
|
|
815
|
+
return { done: true, runCount, anyProgress, artifactsWritten: ingestion.artifactsWritten };
|
|
816
|
+
}
|
|
817
|
+
if (!batchProgress) {
|
|
818
|
+
const bundleAfter = await loadArtifactBundle(artifactsDir);
|
|
819
|
+
const state = bundleAfter.audit_state ?? deriveAuditState(bundleAfter);
|
|
820
|
+
await emitEnvelope({
|
|
821
|
+
root,
|
|
822
|
+
artifactsDir,
|
|
823
|
+
bundle: bundleAfter,
|
|
552
824
|
audit_state: state,
|
|
553
|
-
selected_obligation:
|
|
554
|
-
selected_executor:
|
|
825
|
+
selected_obligation: obligationId,
|
|
826
|
+
selected_executor: "agent",
|
|
555
827
|
progress_made: anyProgress,
|
|
556
|
-
artifacts_written: Array.from(
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
progress_summary: buildWorkerFailureBlocker(workerResult),
|
|
560
|
-
next_likely_step: shouldBlock ? null : workerResult.next_likely_step,
|
|
828
|
+
artifacts_written: Array.from(ingestion.artifactsWritten),
|
|
829
|
+
progress_summary: "Parallel worker batch made no progress.",
|
|
830
|
+
next_likely_step: obligationId,
|
|
561
831
|
providerName: provider.name,
|
|
562
832
|
});
|
|
563
|
-
return {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
833
|
+
return { done: true, runCount, anyProgress, artifactsWritten: ingestion.artifactsWritten };
|
|
834
|
+
}
|
|
835
|
+
return { done: false, runCount, anyProgress, artifactsWritten: ingestion.artifactsWritten };
|
|
836
|
+
}
|
|
837
|
+
async function handleMaxRunsReached(params) {
|
|
838
|
+
const { root, artifactsDir, lastResult, anyProgress, artifactsWritten, maxRuns, providerName, } = params;
|
|
839
|
+
const bundle = await loadArtifactBundle(artifactsDir);
|
|
840
|
+
const decision = decideNextStep(bundle);
|
|
841
|
+
const state = decision.state;
|
|
842
|
+
// A rendered report is the deliverable: if synthesis already produced one (or
|
|
843
|
+
// the state is formally complete), finish the run on it instead of stranding
|
|
844
|
+
// it in the artifacts dir behind a bare "max run limit" non-completion. This
|
|
845
|
+
// mirrors next-step's terminalStep so both loops present a completed audit the
|
|
846
|
+
// same way, even when finalization churned (runtime_validation <-> synthesis
|
|
847
|
+
// ping-pong, or filesystem-retry revision churn) up to the backstop. With no
|
|
848
|
+
// report yet, the run limit is a genuine non-terminal stop.
|
|
849
|
+
const reportRendered = state.status === "complete" || Boolean(bundle.audit_report);
|
|
850
|
+
if (reportRendered) {
|
|
851
|
+
await clearDispatchFiles(artifactsDir);
|
|
852
|
+
}
|
|
853
|
+
const terminalState = reportRendered && state.status !== "complete"
|
|
854
|
+
? { ...state, status: "complete" }
|
|
855
|
+
: state;
|
|
856
|
+
await emitEnvelope({
|
|
857
|
+
root,
|
|
858
|
+
artifactsDir,
|
|
859
|
+
bundle,
|
|
860
|
+
audit_state: terminalState,
|
|
861
|
+
selected_obligation: lastResult?.obligation_id ?? decision.selected_obligation,
|
|
862
|
+
selected_executor: lastResult?.selected_executor ?? decision.selected_executor,
|
|
863
|
+
progress_made: anyProgress,
|
|
864
|
+
artifacts_written: Array.from(artifactsWritten),
|
|
865
|
+
progress_summary: reportRendered && state.status !== "complete"
|
|
866
|
+
? `Audit report already rendered; completing the run after reaching the max run limit (${maxRuns}) during finalization.`
|
|
867
|
+
: `Reached max run limit (${maxRuns}) before terminal state.`,
|
|
868
|
+
next_likely_step: reportRendered ? null : decision.selected_obligation,
|
|
869
|
+
providerName,
|
|
870
|
+
});
|
|
871
|
+
if (reportRendered) {
|
|
872
|
+
await promoteFinalAuditReport({ artifactsDir });
|
|
573
873
|
}
|
|
574
|
-
return {
|
|
575
|
-
done: false,
|
|
576
|
-
lastResult,
|
|
577
|
-
anyProgress,
|
|
578
|
-
artifactsWritten,
|
|
579
|
-
pendingBatchAuditResults,
|
|
580
|
-
pendingAuditResultsPath,
|
|
581
|
-
pendingRuntimeUpdatesPath,
|
|
582
|
-
pendingExternalAnalyzerPath,
|
|
583
|
-
};
|
|
584
874
|
}
|
|
585
875
|
export async function cmdRunToCompletion(argv) {
|
|
586
876
|
const root = getRootDir(argv);
|
|
@@ -678,287 +968,62 @@ export async function cmdRunToCompletion(argv) {
|
|
|
678
968
|
obligationId = "runtime_validation_current";
|
|
679
969
|
runtimeUpdatesPath = pendingRuntimeUpdatesPath;
|
|
680
970
|
}
|
|
681
|
-
if (
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const blockPendingTasksPath = join(blockPaths.runDir, "pending-audit-tasks.json");
|
|
697
|
-
const blockAuditResultsPath = join(blockPaths.runDir, "run-results.json");
|
|
698
|
-
const blockReadPaths = new Set();
|
|
699
|
-
for (const pt of blockPendingTasks) {
|
|
700
|
-
for (const fp of pt.file_paths)
|
|
701
|
-
blockReadPaths.add(fp);
|
|
702
|
-
}
|
|
703
|
-
const blockTask = {
|
|
704
|
-
contract_version: "audit-code-worker/v1alpha1",
|
|
705
|
-
run_id: blockRunId,
|
|
706
|
-
repo_root: root,
|
|
707
|
-
artifacts_dir: artifactsDir,
|
|
708
|
-
obligation_id: obligationId,
|
|
709
|
-
preferred_executor: preferredExecutor,
|
|
710
|
-
result_path: blockPaths.resultPath,
|
|
711
|
-
worker_command: [
|
|
712
|
-
process.execPath,
|
|
713
|
-
selfCliPath,
|
|
714
|
-
"worker-run",
|
|
715
|
-
"--task",
|
|
716
|
-
blockPaths.taskPath,
|
|
717
|
-
],
|
|
718
|
-
audit_results_path: blockAuditResultsPath,
|
|
719
|
-
pending_audit_tasks_path: blockPendingTasksPath,
|
|
720
|
-
timeout_ms: timeoutMs,
|
|
721
|
-
max_retries: 0,
|
|
722
|
-
access: {
|
|
723
|
-
read_paths: [...blockReadPaths],
|
|
724
|
-
write_paths: [blockAuditResultsPath, blockPaths.resultPath],
|
|
725
|
-
},
|
|
726
|
-
};
|
|
727
|
-
const blockPrompt = renderWorkerPrompt(blockTask);
|
|
728
|
-
await writeWorkerTaskFiles(blockTask, blockPrompt, blockPaths, artifactsDir, blockPendingTasks);
|
|
729
|
-
await writeJsonFile(blockPendingTasksPath, blockPendingTasks);
|
|
730
|
-
const reviewRun = {
|
|
731
|
-
run_id: blockRunId,
|
|
732
|
-
task_path: blockPaths.taskPath,
|
|
733
|
-
prompt_path: blockPaths.promptPath,
|
|
734
|
-
pending_audit_tasks_path: blockPendingTasksPath,
|
|
735
|
-
audit_results_path: blockAuditResultsPath,
|
|
736
|
-
worker_command: blockTask.worker_command,
|
|
737
|
-
};
|
|
738
|
-
// Render the actionable dispatch / single-task step here instead of
|
|
739
|
-
// leaving the host to issue next-step as a second command. Capability is
|
|
740
|
-
// resolved from flags/config/env with a sane default, so nothing is
|
|
741
|
-
// required from the host to make progress. If rendering fails we still
|
|
742
|
-
// emit the hand-off below — run-to-completion is never worse than before,
|
|
743
|
-
// and next-step will re-render and surface the error loudly.
|
|
744
|
-
try {
|
|
745
|
-
await renderSemanticReviewStep({
|
|
746
|
-
root,
|
|
747
|
-
artifactsDir,
|
|
748
|
-
activeReviewRun: reviewRun,
|
|
749
|
-
hostCanDispatch: resolveHostDispatchCapability({
|
|
750
|
-
explicit: getOptionalBooleanFlag(argv, "--host-can-dispatch-subagents"),
|
|
751
|
-
sessionConfig,
|
|
752
|
-
}),
|
|
753
|
-
hostMaxActiveSubagents: getHostMaxActiveSubagents(argv),
|
|
754
|
-
hostCanRestrictSubagentTools: getOptionalBooleanFlag(argv, "--host-can-restrict-subagent-tools") ?? false,
|
|
755
|
-
hostCanSelectSubagentModel: getOptionalBooleanFlag(argv, "--host-can-select-subagent-model") ?? false,
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
catch (stepError) {
|
|
759
|
-
process.stderr.write(`[audit-code] Could not pre-render the review step; the operator hand-off points to next-step instead. ${stepError instanceof Error ? stepError.message : String(stepError)}\n`);
|
|
760
|
-
}
|
|
761
|
-
await emitEnvelope({
|
|
762
|
-
root,
|
|
763
|
-
artifactsDir,
|
|
764
|
-
bundle: {
|
|
765
|
-
...bundle,
|
|
766
|
-
audit_state: blockedState,
|
|
767
|
-
},
|
|
768
|
-
audit_state: blockedState,
|
|
769
|
-
selected_obligation: obligationId,
|
|
770
|
-
selected_executor: preferredExecutor,
|
|
771
|
-
progress_made: anyProgress,
|
|
772
|
-
artifacts_written: Array.from(new Set([...artifactsWritten, "audit_state.json"])),
|
|
773
|
-
progress_summary: blocker,
|
|
774
|
-
next_likely_step: null,
|
|
775
|
-
providerName: provider.name,
|
|
776
|
-
activeReviewRun: reviewRun,
|
|
777
|
-
});
|
|
971
|
+
if (await handleLocalSubprocessBlock({
|
|
972
|
+
root,
|
|
973
|
+
artifactsDir,
|
|
974
|
+
selfCliPath,
|
|
975
|
+
bundle,
|
|
976
|
+
argv,
|
|
977
|
+
obligationId,
|
|
978
|
+
preferredExecutor,
|
|
979
|
+
provider,
|
|
980
|
+
sessionConfig,
|
|
981
|
+
timeoutMs,
|
|
982
|
+
runCount,
|
|
983
|
+
anyProgress,
|
|
984
|
+
artifactsWritten,
|
|
985
|
+
}))
|
|
778
986
|
return;
|
|
779
|
-
}
|
|
780
987
|
if (!preferredExecutor) {
|
|
781
|
-
|
|
782
|
-
await clearDispatchFiles(artifactsDir);
|
|
783
|
-
await emitEnvelope({
|
|
988
|
+
await handleNoExecutor({
|
|
784
989
|
root,
|
|
785
990
|
artifactsDir,
|
|
786
991
|
bundle,
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
? (lastResult?.selected_executor ?? null)
|
|
793
|
-
: null,
|
|
794
|
-
progress_made: anyProgress,
|
|
795
|
-
artifacts_written: Array.from(artifactsWritten),
|
|
796
|
-
progress_summary: anyProgress && state.status === "complete"
|
|
797
|
-
? `Completed audit in ${runCount} fresh worker runs.`
|
|
798
|
-
: decision.reason,
|
|
799
|
-
next_likely_step: state.status === "complete" ? null : decision.selected_obligation,
|
|
992
|
+
decision,
|
|
993
|
+
lastResult,
|
|
994
|
+
anyProgress,
|
|
995
|
+
artifactsWritten,
|
|
996
|
+
runCount,
|
|
800
997
|
providerName: provider.name,
|
|
801
998
|
});
|
|
802
|
-
if (state.status === "complete") {
|
|
803
|
-
await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
|
|
804
|
-
}
|
|
805
999
|
return;
|
|
806
1000
|
}
|
|
807
1001
|
if (preferredExecutor === "agent" && parallelWorkers > 1) {
|
|
808
|
-
const
|
|
809
|
-
const providerModelKey = buildProviderModelKey(provider.name, hostModel);
|
|
810
|
-
const quotaStateEntry = quotaState.entries[providerModelKey] ?? null;
|
|
811
|
-
const allCandidateTasks = buildPendingAuditTasks(bundle);
|
|
812
|
-
const candidateGroups = chunkArray(allCandidateTasks.slice(0, parallelWorkers * agentBatchSize), agentBatchSize);
|
|
813
|
-
const candidateSizeIndex = sizeIndexFromManifest(bundle.repo_manifest);
|
|
814
|
-
const slotTokenEstimates = candidateGroups.map((g) => estimateTaskGroupTokens(g, candidateSizeIndex));
|
|
815
|
-
const providerLimits = await provider.queryLimits?.(hostModel)
|
|
816
|
-
.then((r) => r ? { ...r, source: "provider_query" } : null)
|
|
817
|
-
.catch(() => null)
|
|
818
|
-
?? null;
|
|
819
|
-
const cachedLimits = await lookupDiscoveredLimits(providerModelKey).catch(() => null);
|
|
820
|
-
const discoveredLimits = mergeDiscoveredLimits(providerLimits, cachedLimits);
|
|
821
|
-
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ?? 24;
|
|
822
|
-
const quotaSource = buildQuotaSource({ halfLifeHours });
|
|
823
|
-
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(providerModelKey).catch(() => null);
|
|
824
|
-
const hostConcurrencyLimit = resolveHostActiveSubagentLimit({
|
|
825
|
-
sessionConfig,
|
|
826
|
-
});
|
|
827
|
-
const waveSchedule = scheduleWave({
|
|
828
|
-
providerName: resolveFreshSessionProviderName(getExplicitProvider(argv), sessionConfig),
|
|
829
|
-
sessionConfig,
|
|
830
|
-
hostModel,
|
|
831
|
-
requestedConcurrency: parallelWorkers,
|
|
832
|
-
estimatedSlotTokens: slotTokenEstimates,
|
|
833
|
-
quotaStateEntry,
|
|
834
|
-
hostConcurrencyLimit,
|
|
835
|
-
quotaSourceSnapshot,
|
|
836
|
-
discoveredLimits,
|
|
837
|
-
});
|
|
838
|
-
const waveSize = waveSchedule.wave_size;
|
|
839
|
-
if (waveSchedule.cooldown_until) {
|
|
840
|
-
const waitMs = new Date(waveSchedule.cooldown_until).getTime() - Date.now();
|
|
841
|
-
if (waitMs > 0) {
|
|
842
|
-
const cappedWait = Math.min(waitMs, 120_000);
|
|
843
|
-
process.stderr.write(`[quota] Cooldown active — waiting ${Math.ceil(cappedWait / 1000)}s before next wave.\n`);
|
|
844
|
-
await new Promise((r) => setTimeout(r, cappedWait));
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
const taskGroups = candidateGroups.slice(0, waveSize);
|
|
848
|
-
const { slots: workerSlots, runCountAfter } = await buildParallelWaveSlots({
|
|
1002
|
+
const waveResult = await runParallelWaveStep({
|
|
849
1003
|
root,
|
|
850
1004
|
artifactsDir,
|
|
851
1005
|
selfCliPath,
|
|
852
|
-
|
|
1006
|
+
bundle,
|
|
1007
|
+
argv,
|
|
1008
|
+
sessionConfig,
|
|
1009
|
+
provider,
|
|
1010
|
+
hostModel,
|
|
853
1011
|
obligationId,
|
|
854
|
-
|
|
1012
|
+
parallelWorkers,
|
|
1013
|
+
agentBatchSize,
|
|
1014
|
+
runCount,
|
|
855
1015
|
timeoutMs,
|
|
856
|
-
});
|
|
857
|
-
runCount = runCountAfter;
|
|
858
|
-
const parallelStartedAt = new Date().toISOString();
|
|
859
|
-
await writeWaveManifest(artifactsDir, {
|
|
860
|
-
obligation_id: obligationId ?? "unknown",
|
|
861
|
-
started_at: parallelStartedAt,
|
|
862
|
-
pid: process.pid,
|
|
863
|
-
slots: workerSlots.map(buildWaveSlotEntry),
|
|
864
|
-
});
|
|
865
|
-
const { results: launchResults } = await runSlidingWindow(workerSlots.map((slot) => () => provider.launch({
|
|
866
|
-
repoRoot: root,
|
|
867
|
-
runId: slot.runId,
|
|
868
|
-
obligationId,
|
|
869
|
-
promptPath: slot.paths.promptPath,
|
|
870
|
-
taskPath: slot.paths.taskPath,
|
|
871
|
-
resultPath: slot.paths.resultPath,
|
|
872
|
-
stdoutPath: slot.paths.stdoutPath,
|
|
873
|
-
stderrPath: slot.paths.stderrPath,
|
|
874
1016
|
uiMode,
|
|
875
|
-
timeoutMs,
|
|
876
|
-
})), waveSize);
|
|
877
|
-
const launchErrorsByRunId = new Map();
|
|
878
|
-
for (let index = 0; index < launchResults.length; index++) {
|
|
879
|
-
const outcome = launchResults[index];
|
|
880
|
-
if (outcome?.status === "rejected") {
|
|
881
|
-
launchErrorsByRunId.set(workerSlots[index].runId, outcome.reason instanceof Error
|
|
882
|
-
? outcome.reason.message
|
|
883
|
-
: String(outcome.reason));
|
|
884
|
-
}
|
|
885
|
-
else if (outcome?.status === "fulfilled") {
|
|
886
|
-
const launchExitSummary = summarizeLaunchExit(outcome.value);
|
|
887
|
-
if (launchExitSummary) {
|
|
888
|
-
launchErrorsByRunId.set(workerSlots[index].runId, launchExitSummary);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
const ingestion = await ingestParallelWaveResults({
|
|
893
|
-
root,
|
|
894
|
-
artifactsDir,
|
|
895
|
-
workerSlots,
|
|
896
|
-
launchErrorsByRunId,
|
|
897
|
-
obligationId,
|
|
898
|
-
parallelStartedAt,
|
|
899
|
-
providerName: provider.name,
|
|
900
1017
|
anyProgress,
|
|
901
1018
|
artifactsWritten,
|
|
902
1019
|
});
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
workerSlots,
|
|
910
|
-
slotTokenEstimates,
|
|
911
|
-
batchErrors,
|
|
912
|
-
halfLifeHours: sessionConfig.quota?.empirical_half_life_hours ?? 24,
|
|
913
|
-
});
|
|
914
|
-
await removeWaveManifest(artifactsDir);
|
|
915
|
-
if (batchErrors.length > 0) {
|
|
916
|
-
const bundleAfter = await loadArtifactBundle(artifactsDir);
|
|
917
|
-
const blockedState = buildBlockedAuditState({
|
|
918
|
-
state: bundleAfter.audit_state ?? deriveAuditState(bundleAfter),
|
|
919
|
-
obligationId,
|
|
920
|
-
executor: "agent",
|
|
921
|
-
blocker: `Parallel worker batch failed for ${batchErrors.length} run(s). ` +
|
|
922
|
-
batchErrors.slice(0, 3).join(" | "),
|
|
923
|
-
});
|
|
924
|
-
await writeCoreArtifacts(artifactsDir, {
|
|
925
|
-
...bundleAfter,
|
|
926
|
-
audit_state: blockedState,
|
|
927
|
-
});
|
|
928
|
-
await emitEnvelope({
|
|
929
|
-
root,
|
|
930
|
-
artifactsDir,
|
|
931
|
-
bundle: { ...bundleAfter, audit_state: blockedState },
|
|
932
|
-
audit_state: blockedState,
|
|
933
|
-
selected_obligation: obligationId,
|
|
934
|
-
selected_executor: "agent",
|
|
935
|
-
progress_made: anyProgress,
|
|
936
|
-
artifacts_written: Array.from(new Set([...artifactsWritten, "audit_state.json"])),
|
|
937
|
-
progress_summary: `Parallel worker batch failed for ${batchErrors.length} run(s).\n` +
|
|
938
|
-
batchErrors.join("\n"),
|
|
939
|
-
next_likely_step: null,
|
|
940
|
-
providerName: provider.name,
|
|
941
|
-
});
|
|
942
|
-
return;
|
|
943
|
-
}
|
|
944
|
-
if (!batchProgress) {
|
|
945
|
-
const bundleAfter = await loadArtifactBundle(artifactsDir);
|
|
946
|
-
const state = bundleAfter.audit_state ?? deriveAuditState(bundleAfter);
|
|
947
|
-
await emitEnvelope({
|
|
948
|
-
root,
|
|
949
|
-
artifactsDir,
|
|
950
|
-
bundle: bundleAfter,
|
|
951
|
-
audit_state: state,
|
|
952
|
-
selected_obligation: obligationId,
|
|
953
|
-
selected_executor: "agent",
|
|
954
|
-
progress_made: anyProgress,
|
|
955
|
-
artifacts_written: Array.from(artifactsWritten),
|
|
956
|
-
progress_summary: "Parallel worker batch made no progress.",
|
|
957
|
-
next_likely_step: obligationId,
|
|
958
|
-
providerName: provider.name,
|
|
959
|
-
});
|
|
1020
|
+
runCount = waveResult.runCount;
|
|
1021
|
+
anyProgress = waveResult.anyProgress;
|
|
1022
|
+
artifactsWritten.clear();
|
|
1023
|
+
for (const a of waveResult.artifactsWritten)
|
|
1024
|
+
artifactsWritten.add(a);
|
|
1025
|
+
if (waveResult.done)
|
|
960
1026
|
return;
|
|
961
|
-
}
|
|
962
1027
|
continue;
|
|
963
1028
|
}
|
|
964
1029
|
runCount += 1;
|
|
@@ -1028,39 +1093,13 @@ export async function cmdRunToCompletion(argv) {
|
|
|
1028
1093
|
if (single.done)
|
|
1029
1094
|
return;
|
|
1030
1095
|
}
|
|
1031
|
-
|
|
1032
|
-
const decision = decideNextStep(bundle);
|
|
1033
|
-
const state = decision.state;
|
|
1034
|
-
// A rendered report is the deliverable: if synthesis already produced one (or
|
|
1035
|
-
// the state is formally complete), finish the run on it instead of stranding
|
|
1036
|
-
// it in the artifacts dir behind a bare "max run limit" non-completion. This
|
|
1037
|
-
// mirrors next-step's terminalStep so both loops present a completed audit the
|
|
1038
|
-
// same way, even when finalization churned (runtime_validation <-> synthesis
|
|
1039
|
-
// ping-pong, or filesystem-retry revision churn) up to the backstop. With no
|
|
1040
|
-
// report yet, the run limit is a genuine non-terminal stop.
|
|
1041
|
-
const reportRendered = state.status === "complete" || Boolean(bundle.audit_report);
|
|
1042
|
-
if (reportRendered) {
|
|
1043
|
-
await clearDispatchFiles(artifactsDir);
|
|
1044
|
-
}
|
|
1045
|
-
const terminalState = reportRendered && state.status !== "complete"
|
|
1046
|
-
? { ...state, status: "complete" }
|
|
1047
|
-
: state;
|
|
1048
|
-
await emitEnvelope({
|
|
1096
|
+
await handleMaxRunsReached({
|
|
1049
1097
|
root,
|
|
1050
1098
|
artifactsDir,
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
progress_made: anyProgress,
|
|
1056
|
-
artifacts_written: Array.from(artifactsWritten),
|
|
1057
|
-
progress_summary: reportRendered && state.status !== "complete"
|
|
1058
|
-
? `Audit report already rendered; completing the run after reaching the max run limit (${maxRuns}) during finalization.`
|
|
1059
|
-
: `Reached max run limit (${maxRuns}) before terminal state.`,
|
|
1060
|
-
next_likely_step: reportRendered ? null : decision.selected_obligation,
|
|
1099
|
+
lastResult,
|
|
1100
|
+
anyProgress,
|
|
1101
|
+
artifactsWritten,
|
|
1102
|
+
maxRuns,
|
|
1061
1103
|
providerName: provider.name,
|
|
1062
1104
|
});
|
|
1063
|
-
if (reportRendered) {
|
|
1064
|
-
await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
|
|
1065
|
-
}
|
|
1066
1105
|
}
|