audit-tools 0.35.3 → 0.35.6

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.
Files changed (124) hide show
  1. package/dist/audit/cli/charterDeltaPrompt.d.ts +1 -2
  2. package/dist/audit/cli/charterDeltaPrompt.d.ts.map +1 -1
  3. package/dist/audit/cli/charterDeltaPrompt.js +1 -5
  4. package/dist/audit/cli/charterDeltaPrompt.js.map +1 -1
  5. package/dist/audit/cli/charterExtractionPrompt.d.ts +21 -14
  6. package/dist/audit/cli/charterExtractionPrompt.d.ts.map +1 -1
  7. package/dist/audit/cli/charterExtractionPrompt.js +89 -73
  8. package/dist/audit/cli/charterExtractionPrompt.js.map +1 -1
  9. package/dist/audit/cli/conceptualDispatch.d.ts +0 -6
  10. package/dist/audit/cli/conceptualDispatch.d.ts.map +1 -1
  11. package/dist/audit/cli/conceptualDispatch.js +8 -9
  12. package/dist/audit/cli/conceptualDispatch.js.map +1 -1
  13. package/dist/audit/cli/dispatch/hostFanoutGate.d.ts +1 -1
  14. package/dist/audit/cli/dispatch/hostFanoutGate.d.ts.map +1 -1
  15. package/dist/audit/cli/dispatch/hostFanoutGate.js.map +1 -1
  16. package/dist/audit/cli/dispatch/quotaPool.d.ts +4 -1
  17. package/dist/audit/cli/dispatch/quotaPool.d.ts.map +1 -1
  18. package/dist/audit/cli/dispatch/quotaPool.js +9 -1
  19. package/dist/audit/cli/dispatch/quotaPool.js.map +1 -1
  20. package/dist/audit/cli/dispatch.d.ts.map +1 -1
  21. package/dist/audit/cli/dispatch.js +14 -0
  22. package/dist/audit/cli/dispatch.js.map +1 -1
  23. package/dist/audit/cli/fanoutLanes.d.ts +54 -0
  24. package/dist/audit/cli/fanoutLanes.d.ts.map +1 -0
  25. package/dist/audit/cli/fanoutLanes.js +51 -0
  26. package/dist/audit/cli/fanoutLanes.js.map +1 -0
  27. package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
  28. package/dist/audit/cli/nextStepCommand.js +332 -107
  29. package/dist/audit/cli/nextStepCommand.js.map +1 -1
  30. package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
  31. package/dist/audit/cli/nextStepHelpers.js +83 -15
  32. package/dist/audit/cli/nextStepHelpers.js.map +1 -1
  33. package/dist/audit/cli/prompts.d.ts +8 -16
  34. package/dist/audit/cli/prompts.d.ts.map +1 -1
  35. package/dist/audit/cli/prompts.js +25 -60
  36. package/dist/audit/cli/prompts.js.map +1 -1
  37. package/dist/audit/cli/semanticReviewStep.d.ts +0 -3
  38. package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
  39. package/dist/audit/cli/semanticReviewStep.js +14 -38
  40. package/dist/audit/cli/semanticReviewStep.js.map +1 -1
  41. package/dist/audit/cli/steps.d.ts +4 -4
  42. package/dist/audit/cli/steps.d.ts.map +1 -1
  43. package/dist/audit/cli/steps.js +0 -2
  44. package/dist/audit/cli/steps.js.map +1 -1
  45. package/dist/audit/orchestrator/designReviewPrompt.d.ts +6 -14
  46. package/dist/audit/orchestrator/designReviewPrompt.d.ts.map +1 -1
  47. package/dist/audit/orchestrator/designReviewPrompt.js +9 -23
  48. package/dist/audit/orchestrator/designReviewPrompt.js.map +1 -1
  49. package/dist/audit/orchestrator/hostInputPause.d.ts +2 -2
  50. package/dist/audit/orchestrator/hostInputPause.js +1 -1
  51. package/dist/audit/orchestrator/partitionTaskGraph.d.ts +12 -2
  52. package/dist/audit/orchestrator/partitionTaskGraph.d.ts.map +1 -1
  53. package/dist/audit/orchestrator/partitionTaskGraph.js +31 -23
  54. package/dist/audit/orchestrator/partitionTaskGraph.js.map +1 -1
  55. package/dist/audit/orchestrator/reviewPackets.d.ts +6 -2
  56. package/dist/audit/orchestrator/reviewPackets.d.ts.map +1 -1
  57. package/dist/audit/orchestrator/reviewPackets.js.map +1 -1
  58. package/dist/audit/reporting/synthesis.d.ts +8 -5
  59. package/dist/audit/reporting/synthesis.d.ts.map +1 -1
  60. package/dist/audit/reporting/synthesis.js +21 -10
  61. package/dist/audit/reporting/synthesis.js.map +1 -1
  62. package/dist/audit/reporting/synthesisNarrativePrompt.js +1 -1
  63. package/dist/audit/reporting/synthesisNarrativePrompt.js.map +1 -1
  64. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts +5 -2
  65. package/dist/audit/systemic/secondOrderAdversaryPrompt.d.ts.map +1 -1
  66. package/dist/audit/systemic/secondOrderAdversaryPrompt.js +5 -5
  67. package/dist/audit/systemic/secondOrderAdversaryPrompt.js.map +1 -1
  68. package/dist/remediate/intake.d.ts +1 -1
  69. package/dist/remediate/intake.d.ts.map +1 -1
  70. package/dist/remediate/intake.js +11 -1
  71. package/dist/remediate/intake.js.map +1 -1
  72. package/dist/remediate/phases/triage.d.ts.map +1 -1
  73. package/dist/remediate/phases/triage.js +1 -1
  74. package/dist/remediate/phases/triage.js.map +1 -1
  75. package/dist/remediate/review/reviewGate.d.ts +14 -0
  76. package/dist/remediate/review/reviewGate.d.ts.map +1 -1
  77. package/dist/remediate/review/reviewGate.js +37 -0
  78. package/dist/remediate/review/reviewGate.js.map +1 -1
  79. package/dist/remediate/steps/contractPipeline.d.ts +0 -8
  80. package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
  81. package/dist/remediate/steps/contractPipeline.js +0 -2
  82. package/dist/remediate/steps/contractPipeline.js.map +1 -1
  83. package/dist/remediate/steps/contractPipelinePrompts.d.ts +0 -10
  84. package/dist/remediate/steps/contractPipelinePrompts.d.ts.map +1 -1
  85. package/dist/remediate/steps/contractPipelinePrompts.js +9 -24
  86. package/dist/remediate/steps/contractPipelinePrompts.js.map +1 -1
  87. package/dist/remediate/steps/dispatch/implementPrompt.d.ts.map +1 -1
  88. package/dist/remediate/steps/dispatch/implementPrompt.js +3 -1
  89. package/dist/remediate/steps/dispatch/implementPrompt.js.map +1 -1
  90. package/dist/remediate/steps/dispatch/marshal.d.ts.map +1 -1
  91. package/dist/remediate/steps/dispatch/marshal.js +65 -31
  92. package/dist/remediate/steps/dispatch/marshal.js.map +1 -1
  93. package/dist/remediate/steps/dispatch/writeScope.d.ts +10 -17
  94. package/dist/remediate/steps/dispatch/writeScope.d.ts.map +1 -1
  95. package/dist/remediate/steps/dispatch/writeScope.js +16 -57
  96. package/dist/remediate/steps/dispatch/writeScope.js.map +1 -1
  97. package/dist/remediate/steps/dispatch.d.ts +1 -1
  98. package/dist/remediate/steps/dispatch.d.ts.map +1 -1
  99. package/dist/remediate/steps/dispatch.js +1 -1
  100. package/dist/remediate/steps/dispatch.js.map +1 -1
  101. package/dist/remediate/steps/intakeResolver.d.ts.map +1 -1
  102. package/dist/remediate/steps/intakeResolver.js +1 -1
  103. package/dist/remediate/steps/intakeResolver.js.map +1 -1
  104. package/dist/remediate/steps/nextStep.d.ts.map +1 -1
  105. package/dist/remediate/steps/nextStep.js +89 -22
  106. package/dist/remediate/steps/nextStep.js.map +1 -1
  107. package/dist/remediate/steps/prompts.d.ts +3 -3
  108. package/dist/remediate/steps/prompts.d.ts.map +1 -1
  109. package/dist/remediate/steps/prompts.js +43 -9
  110. package/dist/remediate/steps/prompts.js.map +1 -1
  111. package/dist/remediate/validation/remediationState.d.ts +1 -1
  112. package/dist/remediate/validation/remediationState.d.ts.map +1 -1
  113. package/dist/remediate/validation/remediationState.js +8 -1
  114. package/dist/remediate/validation/remediationState.js.map +1 -1
  115. package/dist/shared/index.d.ts +1 -1
  116. package/dist/shared/index.d.ts.map +1 -1
  117. package/dist/shared/index.js +1 -1
  118. package/dist/shared/index.js.map +1 -1
  119. package/dist/shared/prompts.d.ts +34 -0
  120. package/dist/shared/prompts.d.ts.map +1 -1
  121. package/dist/shared/prompts.js +62 -0
  122. package/dist/shared/prompts.js.map +1 -1
  123. package/docs/audit-pkg/contracts.md +13 -7
  124. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { mkdir, writeFile } from "node:fs/promises";
2
2
  import { join, resolve } from "node:path";
3
- import { resolveSessionConfig, applyGuidanceFile, runWithBlockedStepBackstop, writeBlockedStepContract, } from "audit-tools/shared";
3
+ import { resolveSessionConfig, applyGuidanceFile, runWithBlockedStepBackstop, writeBlockedStepContract, renderFanoutExecutionLines, } from "audit-tools/shared";
4
+ import { materializeFanoutLanes } from "./fanoutLanes.js";
4
5
  import { buildEdgeReasoningPrompt, edgeReasoningContentHash, } from "../orchestrator/edgeReasoning.js";
5
6
  import { renderDesignReviewPrompt, renderContractReviewPrompt, } from "../orchestrator/designReviewPrompt.js";
6
7
  import { prepareConceptualDispatch, resolveConceptualReviewSettings, } from "./conceptualDispatch.js";
@@ -10,7 +11,7 @@ import { deriveIntentEquivalenceStatus } from "../orchestrator/intentEquivalence
10
11
  import { unresolvedConstraintClauses } from "../orchestrator/intentInterpreter.js";
11
12
  import { renderSynthesisNarrativePrompt } from "../reporting/synthesisNarrativePrompt.js";
12
13
  import { renderCriticalFlowFallbackPrompt } from "../reporting/criticalFlowFallbackPrompt.js";
13
- import { renderCharterExtractionPrompt } from "./charterExtractionPrompt.js";
14
+ import { charterExtractionKindsForCeiling, renderCharterKindLanePrompt, } from "./charterExtractionPrompt.js";
14
15
  import { renderCharterDeltaPrompt } from "./charterDeltaPrompt.js";
15
16
  import { renderCharterClarificationPrompt } from "./charterClarificationPrompt.js";
16
17
  import { renderSecondOrderAdversaryPrompt } from "../systemic/secondOrderAdversaryPrompt.js";
@@ -22,7 +23,7 @@ import { persistConfigErrorHandoff, } from "./reviewRun.js";
22
23
  import { renderSemanticReviewStep } from "./semanticReviewStep.js";
23
24
  import { renderConfirmIntentPrompt } from "./confirmIntentStep.js";
24
25
  import { writeCurrentStep, STEP_CONTRACT_VERSION } from "./steps.js";
25
- import { nextStepCommand, renderAnalyzerInstallPrompt, renderEdgeReasoningDispatchPrompt, renderEdgeReasoningStepPrompt, renderPresentReportPrompt, } from "./prompts.js";
26
+ import { nextStepCommand, renderAnalyzerInstallPrompt, renderEdgeReasoningDispatchPrompt, renderPresentReportPrompt, } from "./prompts.js";
26
27
  import { getArtifactsDir, getFlag, getAuditorDescriptor, getHostProvider, getRootDir, getTimeoutMs, resolveHostDispatchCapability, warnIfNotGitRepo, } from "./args.js";
27
28
  import { resolveCurrentWorkPartitionRuntime } from "./workPartitionRuntime.js";
28
29
  // Import the helpers used locally, then re-export the full helper surface so
@@ -362,7 +363,6 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
362
363
  artifactsDir,
363
364
  bundle: result.bundle,
364
365
  settings: conceptualSettings,
365
- hostCanSelectSubagentModel,
366
366
  reReviewSection: conceptualNotesSection || undefined,
367
367
  });
368
368
  const dispatchPrompt = [
@@ -484,7 +484,6 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
484
484
  artifactsDir,
485
485
  bundle: result.bundle,
486
486
  settings: conceptualSettings,
487
- hostCanSelectSubagentModel,
488
487
  reReviewSection: conceptualNotesSection || undefined,
489
488
  });
490
489
  const prompt = [
@@ -533,33 +532,94 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
533
532
  return;
534
533
  }
535
534
  if (result.kind === "charter_extraction") {
536
- // Phase C charter layer (conceptual, teleological): the host extracts the four
537
- // charter families per confident subsystem + the deltas it sees; the tool gates
538
- // + routes them at ingest. Only reached at a deep+ ceiling (shallow omits
539
- // deterministically without a host turn).
540
- await mkdir(join(artifactsDir, "incoming"), { recursive: true });
535
+ // Phase C charter layer (conceptual, teleological): one blind, materialized
536
+ // LANE per charter kind (design resolution 2 independence is the shape of
537
+ // the artifacts, not a merge instruction); the tool merges the per-kind
538
+ // submissions and gates + routes them at ingest. Only reached at a deep+
539
+ // ceiling (shallow omits deterministically without a host turn).
541
540
  const continueCommand = nextStepCommand(root, artifactsDir, hostDescriptor);
542
- const submissionPath = join(artifactsDir, "incoming", "charter-extraction.json");
543
541
  const ceiling = resolveCharterCeiling(result.bundle.intent_checkpoint);
542
+ const kinds = charterExtractionKindsForCeiling(ceiling);
543
+ const laneSpecs = kinds.map((kind) => {
544
+ const submissionPath = join(artifactsDir, "incoming", `charter-extraction-${kind}.json`);
545
+ return {
546
+ id: `charter_extraction_${kind}`,
547
+ label: `Charter ${kind} author (blind lane)`,
548
+ promptFilename: `charter-extraction-${kind}-prompt.md`,
549
+ resultFilename: `charter-extraction-${kind}.json`,
550
+ promptText: renderCharterKindLanePrompt(result.bundle, {
551
+ kind,
552
+ submissionPath,
553
+ }),
554
+ };
555
+ });
556
+ const fanout = await materializeFanoutLanes({
557
+ artifactsDir,
558
+ lanes: laneSpecs,
559
+ });
560
+ const pendingIds = new Set(fanout.pendingLanes.map((lane) => lane.id));
561
+ if (await gateHostFanoutOrPause({
562
+ root,
563
+ artifactsDir,
564
+ sessionConfig: effectiveConfig,
565
+ hostDescriptor,
566
+ continueCommand,
567
+ bundle: result.bundle,
568
+ family: "charter_extraction",
569
+ units: laneSpecs
570
+ .filter((spec) => pendingIds.has(spec.id))
571
+ .map((spec) => ({
572
+ id: spec.id,
573
+ estInputBytes: Buffer.byteLength(spec.promptText, "utf8"),
574
+ })),
575
+ })) {
576
+ return;
577
+ }
578
+ const completedLanes = fanout.lanes.filter((lane) => lane.resultExists);
544
579
  const step = await writeCurrentStep({
545
580
  artifactsDir,
546
581
  stepKind: "charter_extraction",
547
582
  status: "ready",
548
583
  runId: null,
549
584
  allowedCommands: [continueCommand],
550
- stopCondition: "Write the charter families per subsystem to the submission path, then run next-step.",
585
+ stopCondition: "Execute each pending charter lane prompt (one blind agent per kind subagents if available, else sequentially), write each lane's submission to its results path, then run next-step.",
551
586
  repoRoot: root,
552
- artifactPaths: {
553
- charter_extraction_submission: submissionPath,
554
- },
555
- prompt: renderCharterExtractionPrompt(result.bundle, {
556
- submissionPath,
557
- continueCommand,
558
- ceiling,
559
- }),
587
+ artifactPaths: fanout.artifactPaths,
588
+ prompt: [
589
+ "# audit-code charter extraction (per-kind blind lanes)",
590
+ "",
591
+ "Each charter kind is authored by its OWN blind lane: a lane must not see another lane's prompt or output, so the later stated↔revealed delta is genuine disagreement rather than one author's self-consistent story. The tool merges the per-kind submissions at ingest.",
592
+ "",
593
+ ...renderFanoutExecutionLines({
594
+ lanes: fanout.pendingLanes.map((lane) => ({
595
+ label: lane.label,
596
+ promptPath: lane.promptPath,
597
+ resultPath: lane.resultPath,
598
+ })),
599
+ concurrencyHint: hostMaxActiveSubagents,
600
+ }),
601
+ "",
602
+ ...(completedLanes.length > 0
603
+ ? [
604
+ `Already complete (results on disk — do NOT redo these lanes): ${completedLanes
605
+ .map((lane) => lane.label)
606
+ .join(", ")}.`,
607
+ "",
608
+ ]
609
+ : []),
610
+ "When every pending lane's result file exists, run:",
611
+ "",
612
+ ` ${continueCommand}`,
613
+ "",
614
+ "Read and follow only the new step prompt returned by that command.",
615
+ "",
616
+ ].join("\n"),
560
617
  access: {
561
- read_paths: [join(artifactsDir, "structure_decomposition.json")],
562
- write_paths: [submissionPath],
618
+ read_paths: [
619
+ ...fanout.readPaths,
620
+ join(artifactsDir, "structure_decomposition.json"),
621
+ ],
622
+ write_paths: fanout.writePaths,
563
623
  },
564
624
  });
565
625
  console.log(JSON.stringify(step, null, 2));
@@ -571,27 +631,77 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
571
631
  // to the gaps) and mines the pairwise deltas + the goal DAG; the tool routes +
572
632
  // gates them at ingest. Only reached at a deep+ ceiling whose extraction pass
573
633
  // produced ≥1 subsystem (charter_register.deltas_pending).
574
- await mkdir(join(artifactsDir, "incoming"), { recursive: true });
634
+ // Always-materialized (design resolution 2): the miner prompt is a lane FILE.
575
635
  const continueCommand = nextStepCommand(root, artifactsDir, hostDescriptor);
576
636
  const submissionPath = join(artifactsDir, "incoming", "charter-delta.json");
637
+ const lanePrompt = renderCharterDeltaPrompt(result.bundle, { submissionPath });
638
+ const fanout = await materializeFanoutLanes({
639
+ artifactsDir,
640
+ lanes: [
641
+ {
642
+ id: "charter_delta",
643
+ label: "Independent charter delta-miner",
644
+ promptFilename: "charter-delta-prompt.md",
645
+ resultFilename: "charter-delta.json",
646
+ promptText: lanePrompt,
647
+ },
648
+ ],
649
+ });
650
+ if (await gateHostFanoutOrPause({
651
+ root,
652
+ artifactsDir,
653
+ sessionConfig: effectiveConfig,
654
+ hostDescriptor,
655
+ continueCommand,
656
+ bundle: result.bundle,
657
+ family: "charter_delta",
658
+ units: [
659
+ {
660
+ id: "charter_delta",
661
+ estInputBytes: Buffer.byteLength(lanePrompt, "utf8"),
662
+ },
663
+ ],
664
+ })) {
665
+ return;
666
+ }
577
667
  const step = await writeCurrentStep({
578
668
  artifactsDir,
579
669
  stepKind: "charter_delta",
580
670
  status: "ready",
581
671
  runId: null,
582
672
  allowedCommands: [continueCommand],
583
- stopCondition: "Write the mined charter deltas + goal graph to the submission path, then run next-step.",
673
+ stopCondition: "Execute the delta-miner lane prompt (subagent if available, else yourself), write the mined deltas + goal graph to the results path, then run next-step.",
584
674
  repoRoot: root,
585
- artifactPaths: {
586
- charter_delta_submission: submissionPath,
587
- },
588
- prompt: renderCharterDeltaPrompt(result.bundle, {
589
- submissionPath,
590
- continueCommand,
591
- }),
675
+ artifactPaths: fanout.artifactPaths,
676
+ prompt: [
677
+ "# audit-code charter delta-mining",
678
+ "",
679
+ "The assembled charters are ready for the INDEPENDENT delta-miner (it did not author them).",
680
+ "",
681
+ ...renderFanoutExecutionLines({
682
+ lanes: fanout.pendingLanes.map((lane) => ({
683
+ label: lane.label,
684
+ promptPath: lane.promptPath,
685
+ })),
686
+ }),
687
+ "",
688
+ "The executor must write its CharterDeltaSubmission JSON to:",
689
+ "",
690
+ ` ${submissionPath}`,
691
+ "",
692
+ "When the result file exists, run:",
693
+ "",
694
+ ` ${continueCommand}`,
695
+ "",
696
+ "Read and follow only the new step prompt returned by that command.",
697
+ "",
698
+ ].join("\n"),
592
699
  access: {
593
- read_paths: [join(artifactsDir, "charter_register.json")],
594
- write_paths: [submissionPath],
700
+ read_paths: [
701
+ ...fanout.readPaths,
702
+ join(artifactsDir, "charter_register.json"),
703
+ ],
704
+ write_paths: fanout.writePaths,
595
705
  },
596
706
  });
597
707
  console.log(JSON.stringify(step, null, 2));
@@ -638,7 +748,6 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
638
748
  // a SEPARATE adversary agent whose mandate is optimization/better-way; it writes
639
749
  // the round's improvement findings (true-lens) back, and the executor folds them
640
750
  // + decides convergence. An empty submission converges the loop.
641
- await mkdir(join(artifactsDir, "incoming"), { recursive: true });
642
751
  const continueCommand = nextStepCommand(root, artifactsDir, hostDescriptor);
643
752
  const submissionPath = join(artifactsDir, "incoming", "systemic-challenge.json");
644
753
  const metrics = result.bundle.systemic_challenge?.metrics ?? aggregateMetricsDigest(result.bundle);
@@ -647,7 +756,20 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
647
756
  priorFindingCount: result.bundle.systemic_challenge?.findings.length ?? 0,
648
757
  metrics,
649
758
  submissionPath,
650
- continueCommand,
759
+ });
760
+ // Always-materialized (design resolution 2): the adversary prompt is a lane
761
+ // FILE — the adversary is a SEPARATE agent by lane class, on every host.
762
+ const fanout = await materializeFanoutLanes({
763
+ artifactsDir,
764
+ lanes: [
765
+ {
766
+ id: "systemic_challenge",
767
+ label: "Second-order adversary (improvement-seeking challenge)",
768
+ promptFilename: "systemic-challenge-prompt.md",
769
+ resultFilename: "systemic-challenge.json",
770
+ promptText: adversaryPrompt,
771
+ },
772
+ ],
651
773
  });
652
774
  if (await gateHostFanoutOrPause({
653
775
  root,
@@ -672,15 +794,40 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
672
794
  status: "ready",
673
795
  runId: null,
674
796
  allowedCommands: [continueCommand],
675
- stopCondition: "Run a separate second-order-adversary agent (optimization/better-way mandate), write its findings to the submission path, then run next-step. An empty findings array converges the loop.",
797
+ stopCondition: "Execute the second-order-adversary lane prompt (a separate agent from the one that drove this audit), write its findings to the results path, then run next-step. An empty findings array converges the loop.",
676
798
  repoRoot: root,
677
- artifactPaths: {
678
- systemic_challenge_submission: submissionPath,
679
- },
680
- prompt: adversaryPrompt,
799
+ artifactPaths: fanout.artifactPaths,
800
+ prompt: [
801
+ "# audit-code systemic challenge (second-order adversary)",
802
+ "",
803
+ "This round's adversary lane challenges the audit process itself (optimization/better-way mandate). The adversary must NOT be the agent that drove this audit.",
804
+ "",
805
+ ...renderFanoutExecutionLines({
806
+ lanes: fanout.pendingLanes.map((lane) => ({
807
+ label: lane.label,
808
+ promptPath: lane.promptPath,
809
+ })),
810
+ }),
811
+ "",
812
+ "The executor must write its findings JSON to:",
813
+ "",
814
+ ` ${submissionPath}`,
815
+ "",
816
+ "An EMPTY findings array is the deliberate loop terminator (this round found nothing new).",
817
+ "",
818
+ "When the result file exists, run:",
819
+ "",
820
+ ` ${continueCommand}`,
821
+ "",
822
+ "Read and follow only the new step prompt returned by that command.",
823
+ "",
824
+ ].join("\n"),
681
825
  access: {
682
- read_paths: [join(artifactsDir, "systemic_challenge.json")],
683
- write_paths: [submissionPath],
826
+ read_paths: [
827
+ ...fanout.readPaths,
828
+ join(artifactsDir, "systemic_challenge.json"),
829
+ ],
830
+ write_paths: fanout.writePaths,
684
831
  },
685
832
  });
686
833
  console.log(JSON.stringify(step, null, 2));
@@ -744,61 +891,45 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
744
891
  // name it and the shape error in the re-emitted prompt so the producer
745
892
  // fixes the shape instead of resubmitting the same honest mistake forever.
746
893
  const rejectionNotice = await renderEdgeReasoningRejectionNotice(artifactsDir);
747
- if (hostCanDispatch) {
748
- // Dispatch path: isolate the (potentially large) edge-list prompt in a file
749
- // and have the host fan it out to one subagent, mirroring the packet review
750
- // dispatch contract. The subagent writes the rewrites file; next-step applies.
751
- const edgeReasoningPromptPath = join(artifactsDir, "incoming", "edge-reasoning-prompt.md");
752
- await writeFile(edgeReasoningPromptPath, rejectionNotice ? `${basePrompt}\n\n${rejectionNotice}` : basePrompt, "utf8");
753
- const step = await writeCurrentStep({
754
- artifactsDir,
755
- stepKind: "edge_reasoning_dispatch",
756
- status: "ready",
757
- runId: null,
758
- allowedCommands: [continueCommand],
759
- stopCondition: "Dispatch one subagent to write the edge-reasoning rewrites, then run next-step.",
760
- repoRoot: root,
761
- artifactPaths: {
762
- edge_reasoning_prompt: edgeReasoningPromptPath,
763
- edge_reasoning_results: edgeReasoningResultsPath,
764
- },
765
- prompt: renderEdgeReasoningDispatchPrompt({
766
- promptPath: edgeReasoningPromptPath,
767
- resultsPath: edgeReasoningResultsPath,
768
- continueCommand,
769
- contentHash,
770
- candidateCount: result.candidates.length,
771
- }),
772
- access: {
773
- read_paths: [edgeReasoningPromptPath],
774
- write_paths: [edgeReasoningResultsPath],
894
+ // Always-materialized (design resolution 2): the (potentially large)
895
+ // edge-list prompt lives in a lane file on every host — a subagent-capable
896
+ // host fans it out, any other host reads and follows the same file itself.
897
+ // The retired inline `edge_reasoning` step kind was this branch's other
898
+ // arm. Routed through the same lane materializer as every other fan-out
899
+ // step so the K-of-N/result-exists semantics stay single-sourced.
900
+ const fanout = await materializeFanoutLanes({
901
+ artifactsDir,
902
+ lanes: [
903
+ {
904
+ id: "edge_reasoning",
905
+ label: "Edge-reasoning rewrites",
906
+ promptFilename: "edge-reasoning-prompt.md",
907
+ resultFilename: "edge-reasoning.json",
908
+ promptText: rejectionNotice
909
+ ? `${basePrompt}\n\n${rejectionNotice}`
910
+ : basePrompt,
775
911
  },
776
- });
777
- console.log(JSON.stringify(step, null, 2));
778
- return;
779
- }
780
- // One-step fallback (no callable subagent facility): the host produces the
781
- // rewrites itself in a single bounded turn, mirroring the narrative step.
912
+ ],
913
+ });
914
+ const edgeReasoningPromptPath = fanout.lanes[0].promptPath;
782
915
  const step = await writeCurrentStep({
783
916
  artifactsDir,
784
- stepKind: "edge_reasoning",
917
+ stepKind: "edge_reasoning_dispatch",
785
918
  status: "ready",
786
919
  runId: null,
787
920
  allowedCommands: [continueCommand],
788
- stopCondition: "Write the edge-reasoning rewrites to the results path, then run next-step.",
921
+ stopCondition: "Execute the edge-reasoning lane prompt (subagent if available, else yourself), write the rewrites to the results path, then run next-step.",
789
922
  repoRoot: root,
790
- artifactPaths: {
791
- edge_reasoning_results: edgeReasoningResultsPath,
792
- },
793
- prompt: renderEdgeReasoningStepPrompt({
794
- basePrompt,
923
+ artifactPaths: fanout.artifactPaths,
924
+ prompt: renderEdgeReasoningDispatchPrompt({
925
+ promptPath: edgeReasoningPromptPath,
795
926
  resultsPath: edgeReasoningResultsPath,
796
927
  continueCommand,
797
928
  contentHash,
798
- rejectionNotice,
929
+ candidateCount: result.candidates.length,
799
930
  }),
800
931
  access: {
801
- read_paths: [],
932
+ read_paths: [edgeReasoningPromptPath],
802
933
  write_paths: [edgeReasoningResultsPath],
803
934
  },
804
935
  });
@@ -879,12 +1010,13 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
879
1010
  }
880
1011
  if (result.kind === "critical_flow_fallback") {
881
1012
  const fallbackResultsPath = join(artifactsDir, "incoming", "critical-flow-fallback.json");
882
- await mkdir(join(artifactsDir, "incoming"), { recursive: true });
883
1013
  const continueCommand = nextStepCommand(root, artifactsDir, hostDescriptor);
884
1014
  const basePrompt = result.bundle.critical_flows
885
1015
  ? renderCriticalFlowFallbackPrompt(result.bundle.critical_flows)
886
1016
  : "# Critical-flow fallback\n\nNo critical_flows manifest is available; write an empty flows array.";
887
- const fullPrompt = [
1017
+ // Always-materialized (design resolution 2): the (potentially ~340-line)
1018
+ // flow-stub prompt is a lane FILE, never inlined into the step prompt.
1019
+ const lanePrompt = [
888
1020
  basePrompt,
889
1021
  "## Results path",
890
1022
  "",
@@ -892,24 +1024,69 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
892
1024
  "",
893
1025
  ` ${fallbackResultsPath}`,
894
1026
  "",
895
- `Then run: ${continueCommand}`,
896
- "",
897
1027
  ].join("\n");
1028
+ const fanout = await materializeFanoutLanes({
1029
+ artifactsDir,
1030
+ lanes: [
1031
+ {
1032
+ id: "critical_flow_fallback",
1033
+ label: "Critical-flow fallback enrichment",
1034
+ promptFilename: "critical-flow-fallback-prompt.md",
1035
+ resultFilename: "critical-flow-fallback.json",
1036
+ promptText: lanePrompt,
1037
+ },
1038
+ ],
1039
+ });
1040
+ if (await gateHostFanoutOrPause({
1041
+ root,
1042
+ artifactsDir,
1043
+ sessionConfig: effectiveConfig,
1044
+ hostDescriptor,
1045
+ continueCommand,
1046
+ bundle: result.bundle,
1047
+ family: "critical_flow_fallback",
1048
+ units: [
1049
+ {
1050
+ id: "critical_flow_fallback",
1051
+ estInputBytes: Buffer.byteLength(lanePrompt, "utf8"),
1052
+ },
1053
+ ],
1054
+ })) {
1055
+ return;
1056
+ }
898
1057
  const step = await writeCurrentStep({
899
1058
  artifactsDir,
900
1059
  stepKind: "critical_flow_fallback",
901
1060
  status: "ready",
902
1061
  runId: null,
903
1062
  allowedCommands: [continueCommand],
904
- stopCondition: "Write the critical-flow fallback enrichment to the results path, then run next-step.",
1063
+ stopCondition: "Execute the critical-flow lane prompt (subagent if available, else yourself), write the enrichment to the results path, then run next-step.",
905
1064
  repoRoot: root,
906
- artifactPaths: {
907
- critical_flow_fallback_results: fallbackResultsPath,
908
- },
909
- prompt: fullPrompt,
1065
+ artifactPaths: fanout.artifactPaths,
1066
+ prompt: [
1067
+ "# audit-code critical-flow fallback",
1068
+ "",
1069
+ ...renderFanoutExecutionLines({
1070
+ lanes: fanout.pendingLanes.map((lane) => ({
1071
+ label: lane.label,
1072
+ promptPath: lane.promptPath,
1073
+ })),
1074
+ }),
1075
+ "",
1076
+ "The executor must write the CriticalFlowFallbackResult JSON object to:",
1077
+ "",
1078
+ ` ${fallbackResultsPath}`,
1079
+ "",
1080
+ "When the result file exists, run:",
1081
+ "",
1082
+ ` ${continueCommand}`,
1083
+ "",
1084
+ "Read and follow only the new step prompt returned by that command.",
1085
+ "",
1086
+ ].join("\n"),
910
1087
  access: {
911
- read_paths: [],
912
- write_paths: [fallbackResultsPath],
1088
+ read_paths: fanout.readPaths,
1089
+ write_paths: fanout.writePaths,
913
1090
  },
914
1091
  });
915
1092
  console.log(JSON.stringify(step, null, 2));
@@ -917,12 +1094,14 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
917
1094
  }
918
1095
  if (result.kind === "synthesis_narrative") {
919
1096
  const narrativeResultsPath = join(artifactsDir, "incoming", "synthesis-narrative.json");
920
- await mkdir(join(artifactsDir, "incoming"), { recursive: true });
921
1097
  const continueCommand = nextStepCommand(root, artifactsDir, hostDescriptor);
922
1098
  const basePrompt = result.bundle.audit_findings
923
1099
  ? renderSynthesisNarrativePrompt(result.bundle.audit_findings)
924
1100
  : "# Synthesis narrative\n\nNo findings report is available; write an empty themes array.";
925
- const fullPrompt = [
1101
+ // Always-materialized (design resolution 2): the findings digest (up to 120
1102
+ // findings) is a lane FILE, never inlined into the step prompt. This step
1103
+ // previously carried no access block at all — the lane form declares one.
1104
+ const lanePrompt = [
926
1105
  basePrompt,
927
1106
  "## Results path",
928
1107
  "",
@@ -930,21 +1109,70 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
930
1109
  "",
931
1110
  ` ${narrativeResultsPath}`,
932
1111
  "",
933
- `Then run: ${continueCommand}`,
934
- "",
935
1112
  ].join("\n");
1113
+ const fanout = await materializeFanoutLanes({
1114
+ artifactsDir,
1115
+ lanes: [
1116
+ {
1117
+ id: "synthesis_narrative",
1118
+ label: "Synthesis narrative (themes / exec summary / top risks)",
1119
+ promptFilename: "synthesis-narrative-prompt.md",
1120
+ resultFilename: "synthesis-narrative.json",
1121
+ promptText: lanePrompt,
1122
+ },
1123
+ ],
1124
+ });
1125
+ if (await gateHostFanoutOrPause({
1126
+ root,
1127
+ artifactsDir,
1128
+ sessionConfig: effectiveConfig,
1129
+ hostDescriptor,
1130
+ continueCommand,
1131
+ bundle: result.bundle,
1132
+ family: "synthesis_narrative",
1133
+ units: [
1134
+ {
1135
+ id: "synthesis_narrative",
1136
+ estInputBytes: Buffer.byteLength(lanePrompt, "utf8"),
1137
+ },
1138
+ ],
1139
+ })) {
1140
+ return;
1141
+ }
936
1142
  const step = await writeCurrentStep({
937
1143
  artifactsDir,
938
1144
  stepKind: "synthesis_narrative",
939
1145
  status: "ready",
940
1146
  runId: null,
941
1147
  allowedCommands: [continueCommand],
942
- stopCondition: "Write the synthesis narrative to the results path, then run next-step.",
1148
+ stopCondition: "Execute the synthesis-narrative lane prompt (subagent if available, else yourself), write the narrative to the results path, then run next-step.",
943
1149
  repoRoot: root,
944
- artifactPaths: {
945
- synthesis_narrative_results: narrativeResultsPath,
1150
+ artifactPaths: fanout.artifactPaths,
1151
+ prompt: [
1152
+ "# audit-code synthesis narrative",
1153
+ "",
1154
+ ...renderFanoutExecutionLines({
1155
+ lanes: fanout.pendingLanes.map((lane) => ({
1156
+ label: lane.label,
1157
+ promptPath: lane.promptPath,
1158
+ })),
1159
+ }),
1160
+ "",
1161
+ "The executor must write the SynthesisNarrative JSON object to:",
1162
+ "",
1163
+ ` ${narrativeResultsPath}`,
1164
+ "",
1165
+ "When the result file exists, run:",
1166
+ "",
1167
+ ` ${continueCommand}`,
1168
+ "",
1169
+ "Read and follow only the new step prompt returned by that command.",
1170
+ "",
1171
+ ].join("\n"),
1172
+ access: {
1173
+ read_paths: fanout.readPaths,
1174
+ write_paths: fanout.writePaths,
946
1175
  },
947
- prompt: fullPrompt,
948
1176
  });
949
1177
  console.log(JSON.stringify(step, null, 2));
950
1178
  return;
@@ -953,14 +1181,11 @@ async function cmdNextStepBody(argv, root, artifactsDir) {
953
1181
  root,
954
1182
  artifactsDir,
955
1183
  activeReviewRun: result.activeReviewRun,
956
- hostCanDispatch,
957
1184
  hostMaxActiveSubagents,
958
1185
  hostContextTokens,
959
1186
  hostOutputTokens,
960
1187
  hostModelRoster,
961
1188
  hostModelId,
962
- hostCanRestrictSubagentTools,
963
- hostCanSelectSubagentModel,
964
1189
  selectedExecutor: result.selectedExecutor,
965
1190
  inProcessMadeProgress: result.inProcessMadeProgress,
966
1191
  // G2: the RESOLVED descriptor. renderSemanticReviewStep loads the repo INTENT from