audit-tools 0.52.5 → 0.53.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/dist/audit/cli/auditStep.d.ts +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.d.ts +2 -0
- package/dist/audit/cli/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.js +1 -1
- package/dist/audit/cli/dispatch/hostHandoff.js.map +1 -1
- package/dist/audit/cli/dispatch/packetFilter.d.ts +1 -1
- package/dist/audit/cli/dispatch/packetFilter.d.ts.map +1 -1
- package/dist/audit/cli/dispatch/packetFilter.js +1 -1
- package/dist/audit/cli/dispatch/packetFilter.js.map +1 -1
- package/dist/audit/cli/nextStepCommand.d.ts.map +1 -1
- package/dist/audit/cli/nextStepCommand.js +42 -20
- package/dist/audit/cli/nextStepCommand.js.map +1 -1
- package/dist/audit/cli/nextStepHelpers.d.ts +3 -3
- package/dist/audit/cli/nextStepHelpers.d.ts.map +1 -1
- package/dist/audit/cli/nextStepHelpers.js +50 -75
- package/dist/audit/cli/nextStepHelpers.js.map +1 -1
- package/dist/audit/cli/prompts.d.ts +1 -2
- package/dist/audit/cli/prompts.d.ts.map +1 -1
- package/dist/audit/cli/prompts.js +2 -12
- package/dist/audit/cli/prompts.js.map +1 -1
- package/dist/audit/cli/sampleRunCommand.d.ts +2 -2
- package/dist/audit/cli/semanticReviewStep.d.ts +11 -2
- package/dist/audit/cli/semanticReviewStep.d.ts.map +1 -1
- package/dist/audit/cli/semanticReviewStep.js +14 -10
- package/dist/audit/cli/semanticReviewStep.js.map +1 -1
- package/dist/audit/contracts/workerSchemas.d.ts +14 -14
- package/dist/audit/contracts/wrapperResponse.d.ts +6 -6
- package/dist/audit/extractors/graphRoutes.d.ts.map +1 -1
- package/dist/audit/extractors/graphRoutes.js +1 -3
- package/dist/audit/extractors/graphRoutes.js.map +1 -1
- package/dist/audit/io/artifacts.d.ts.map +1 -1
- package/dist/audit/io/artifacts.js +2 -3
- package/dist/audit/io/artifacts.js.map +1 -1
- package/dist/audit/orchestrator/architectureDiscovery.d.ts +11 -0
- package/dist/audit/orchestrator/architectureDiscovery.d.ts.map +1 -0
- package/dist/audit/orchestrator/architectureDiscovery.js +174 -0
- package/dist/audit/orchestrator/architectureDiscovery.js.map +1 -0
- package/dist/audit/orchestrator/designReviewProjection.d.ts +2 -6
- package/dist/audit/orchestrator/designReviewProjection.d.ts.map +1 -1
- package/dist/audit/orchestrator/designReviewProjection.js +2 -6
- package/dist/audit/orchestrator/designReviewProjection.js.map +1 -1
- package/dist/audit/orchestrator/designReviewSnapshot.d.ts +2 -3
- package/dist/audit/orchestrator/designReviewSnapshot.d.ts.map +1 -1
- package/dist/audit/orchestrator/designReviewSnapshot.js +2 -3
- package/dist/audit/orchestrator/designReviewSnapshot.js.map +1 -1
- package/dist/audit/orchestrator/executorRunners.d.ts.map +1 -1
- package/dist/audit/orchestrator/executorRunners.js +1 -22
- package/dist/audit/orchestrator/executorRunners.js.map +1 -1
- package/dist/audit/orchestrator/executors.d.ts.map +1 -1
- package/dist/audit/orchestrator/executors.js +1 -13
- package/dist/audit/orchestrator/executors.js.map +1 -1
- package/dist/audit/orchestrator/nextStep.d.ts +2 -28
- package/dist/audit/orchestrator/nextStep.d.ts.map +1 -1
- package/dist/audit/orchestrator/nextStep.js +5 -37
- package/dist/audit/orchestrator/nextStep.js.map +1 -1
- package/dist/audit/orchestrator/obligationDerive.d.ts +2 -3
- package/dist/audit/orchestrator/obligationDerive.d.ts.map +1 -1
- package/dist/audit/orchestrator/obligationDerive.js +2 -3
- package/dist/audit/orchestrator/obligationDerive.js.map +1 -1
- package/dist/audit/orchestrator/pendingTasks.d.ts +2 -0
- package/dist/audit/orchestrator/pendingTasks.d.ts.map +1 -1
- package/dist/audit/orchestrator/pendingTasks.js +5 -1
- package/dist/audit/orchestrator/pendingTasks.js.map +1 -1
- package/dist/audit/orchestrator/planningExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/planningExecutors.js +9 -0
- package/dist/audit/orchestrator/planningExecutors.js.map +1 -1
- package/dist/audit/orchestrator/requeueCommand.d.ts +1 -1
- package/dist/audit/orchestrator/resultBaseline.d.ts +5 -5
- package/dist/audit/orchestrator/resultBaseline.d.ts.map +1 -1
- package/dist/audit/orchestrator/resultBaseline.js +24 -47
- package/dist/audit/orchestrator/resultBaseline.js.map +1 -1
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.d.ts.map +1 -1
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.js +2 -0
- package/dist/audit/orchestrator/selectiveDeepening/findingFollowup.js.map +1 -1
- package/dist/audit/orchestrator/state.d.ts.map +1 -1
- package/dist/audit/orchestrator/state.js +2 -0
- package/dist/audit/orchestrator/state.js.map +1 -1
- package/dist/audit/orchestrator/synthesisExecutors.d.ts.map +1 -1
- package/dist/audit/orchestrator/synthesisExecutors.js +3 -0
- package/dist/audit/orchestrator/synthesisExecutors.js.map +1 -1
- package/dist/audit/types/auditState.d.ts +6 -6
- package/dist/audit/types/flowCoverage.d.ts +6 -6
- package/dist/audit/types.d.ts +12 -12
- package/dist/remediate/contractPipeline/executionPlan.d.ts +1908 -0
- package/dist/remediate/contractPipeline/executionPlan.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/executionPlan.js +467 -0
- package/dist/remediate/contractPipeline/executionPlan.js.map +1 -0
- package/dist/remediate/contractPipeline/runtimePlanAuthority.d.ts +12 -0
- package/dist/remediate/contractPipeline/runtimePlanAuthority.d.ts.map +1 -0
- package/dist/remediate/contractPipeline/runtimePlanAuthority.js +41 -0
- package/dist/remediate/contractPipeline/runtimePlanAuthority.js.map +1 -0
- package/dist/remediate/dedup/crossLensDedup.d.ts +3 -16
- package/dist/remediate/dedup/crossLensDedup.d.ts.map +1 -1
- package/dist/remediate/dedup/crossLensDedup.js +2 -32
- package/dist/remediate/dedup/crossLensDedup.js.map +1 -1
- package/dist/remediate/index.d.ts +2 -19
- package/dist/remediate/index.d.ts.map +1 -1
- package/dist/remediate/index.js +22 -138
- package/dist/remediate/index.js.map +1 -1
- package/dist/remediate/intake.d.ts +10 -10
- package/dist/remediate/intent/intentOrdering.d.ts +6 -8
- package/dist/remediate/intent/intentOrdering.d.ts.map +1 -1
- package/dist/remediate/intent/intentOrdering.js +24 -47
- package/dist/remediate/intent/intentOrdering.js.map +1 -1
- package/dist/remediate/phases/close.d.ts +25 -17
- package/dist/remediate/phases/close.d.ts.map +1 -1
- package/dist/remediate/phases/close.js +278 -218
- package/dist/remediate/phases/close.js.map +1 -1
- package/dist/remediate/phases/closeAcceptance.d.ts +42 -0
- package/dist/remediate/phases/closeAcceptance.d.ts.map +1 -0
- package/dist/remediate/phases/closeAcceptance.js +66 -0
- package/dist/remediate/phases/closeAcceptance.js.map +1 -0
- package/dist/remediate/phases/closeReviewProvenance.d.ts +1 -1
- package/dist/remediate/phases/closeReviewProvenance.d.ts.map +1 -1
- package/dist/remediate/phases/closeReviewProvenance.js +9 -8
- package/dist/remediate/phases/closeReviewProvenance.js.map +1 -1
- package/dist/remediate/phases/closeVerifyAnalyzerLeads.d.ts.map +1 -1
- package/dist/remediate/phases/closeVerifyAnalyzerLeads.js +11 -9
- package/dist/remediate/phases/closeVerifyAnalyzerLeads.js.map +1 -1
- package/dist/remediate/phases/closeVerifyHeadEvidence.d.ts +21 -86
- package/dist/remediate/phases/closeVerifyHeadEvidence.d.ts.map +1 -1
- package/dist/remediate/phases/closeVerifyHeadEvidence.js +30 -19
- package/dist/remediate/phases/closeVerifyHeadEvidence.js.map +1 -1
- package/dist/remediate/phases/plan.d.ts +3 -60
- package/dist/remediate/phases/plan.d.ts.map +1 -1
- package/dist/remediate/phases/plan.js +3 -227
- package/dist/remediate/phases/plan.js.map +1 -1
- package/dist/remediate/phases/triage.d.ts.map +1 -1
- package/dist/remediate/phases/triage.js +19 -30
- package/dist/remediate/phases/triage.js.map +1 -1
- package/dist/remediate/riskSignal.d.ts +9 -43
- package/dist/remediate/riskSignal.d.ts.map +1 -1
- package/dist/remediate/riskSignal.js +7 -28
- package/dist/remediate/riskSignal.js.map +1 -1
- package/dist/remediate/state/disposition.d.ts +2 -1
- package/dist/remediate/state/disposition.d.ts.map +1 -1
- package/dist/remediate/state/disposition.js +37 -1
- package/dist/remediate/state/disposition.js.map +1 -1
- package/dist/remediate/state/runIdentity.d.ts +2 -13
- package/dist/remediate/state/runIdentity.d.ts.map +1 -1
- package/dist/remediate/state/runIdentity.js +3 -13
- package/dist/remediate/state/runIdentity.js.map +1 -1
- package/dist/remediate/state/store.d.ts +12 -36
- package/dist/remediate/state/store.d.ts.map +1 -1
- package/dist/remediate/state/store.js +58 -150
- package/dist/remediate/state/store.js.map +1 -1
- package/dist/remediate/state/types.d.ts +406 -504
- package/dist/remediate/state/types.d.ts.map +1 -1
- package/dist/remediate/state/types.js +24 -104
- package/dist/remediate/state/types.js.map +1 -1
- package/dist/remediate/steps/contractPipeline.d.ts +7 -661
- package/dist/remediate/steps/contractPipeline.d.ts.map +1 -1
- package/dist/remediate/steps/contractPipeline.js +259 -3854
- package/dist/remediate/steps/contractPipeline.js.map +1 -1
- package/dist/remediate/steps/contractPipelinePrompts.d.ts +20 -142
- package/dist/remediate/steps/contractPipelinePrompts.d.ts.map +1 -1
- package/dist/remediate/steps/contractPipelinePrompts.js +48 -581
- package/dist/remediate/steps/contractPipelinePrompts.js.map +1 -1
- package/dist/remediate/steps/dispatch/contractConformanceReview.d.ts +4 -1
- package/dist/remediate/steps/dispatch/contractConformanceReview.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/contractConformanceReview.js +6 -3
- package/dist/remediate/steps/dispatch/contractConformanceReview.js.map +1 -1
- package/dist/remediate/steps/dispatch/hostContracts.d.ts +1 -1
- package/dist/remediate/steps/dispatch/hostContracts.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts +4 -21
- package/dist/remediate/steps/dispatch/hostHandoff.d.ts.map +1 -1
- package/dist/remediate/steps/dispatch/hostHandoff.js +161 -383
- package/dist/remediate/steps/dispatch/hostHandoff.js.map +1 -1
- package/dist/remediate/steps/finalGate.d.ts +34 -0
- package/dist/remediate/steps/finalGate.d.ts.map +1 -1
- package/dist/remediate/steps/finalGate.js +44 -4
- package/dist/remediate/steps/finalGate.js.map +1 -1
- package/dist/remediate/steps/frictionCloseout.d.ts +1 -30
- package/dist/remediate/steps/frictionCloseout.d.ts.map +1 -1
- package/dist/remediate/steps/frictionCloseout.js +6 -99
- package/dist/remediate/steps/frictionCloseout.js.map +1 -1
- package/dist/remediate/steps/nextStep.d.ts +2 -15
- package/dist/remediate/steps/nextStep.d.ts.map +1 -1
- package/dist/remediate/steps/nextStep.js +255 -1028
- package/dist/remediate/steps/nextStep.js.map +1 -1
- package/dist/remediate/steps/prompts.js +12 -12
- package/dist/remediate/steps/prompts.js.map +1 -1
- package/dist/remediate/steps/stepUtils.d.ts +1 -1
- package/dist/remediate/steps/stepUtils.d.ts.map +1 -1
- package/dist/remediate/steps/types.d.ts +1 -1
- package/dist/remediate/steps/types.d.ts.map +1 -1
- package/dist/remediate/steps/types.js +1 -1
- package/dist/remediate/steps/types.js.map +1 -1
- package/dist/remediate/types/options.d.ts +9 -0
- package/dist/remediate/types/options.d.ts.map +1 -1
- package/dist/remediate/validation/artifacts.d.ts.map +1 -1
- package/dist/remediate/validation/artifacts.js +10 -56
- package/dist/remediate/validation/artifacts.js.map +1 -1
- package/dist/remediate/validation/remediationState.d.ts +2 -2
- package/dist/remediate/validation/remediationState.d.ts.map +1 -1
- package/dist/remediate/validation/remediationState.js +17 -77
- package/dist/remediate/validation/remediationState.js.map +1 -1
- package/dist/remediate/validation/verificationReport.d.ts +3 -0
- package/dist/remediate/validation/verificationReport.d.ts.map +1 -0
- package/dist/remediate/validation/verificationReport.js +28 -0
- package/dist/remediate/validation/verificationReport.js.map +1 -0
- package/dist/shared/analyzers/types.d.ts +10 -10
- package/dist/shared/engine/obligationEngine.d.ts +2 -2
- package/dist/shared/friction/triage.d.ts +7 -28
- package/dist/shared/friction/triage.d.ts.map +1 -1
- package/dist/shared/friction/triage.js +7 -28
- package/dist/shared/friction/triage.js.map +1 -1
- package/dist/shared/graph/orderedReachability.js +1 -1
- package/dist/shared/graph/orderedReachability.js.map +1 -1
- package/dist/shared/index.d.ts +5 -6
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +3 -4
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/loopCorePaths.d.ts.map +1 -1
- package/dist/shared/loopCorePaths.js +6 -0
- package/dist/shared/loopCorePaths.js.map +1 -1
- package/dist/shared/prompts.d.ts +1 -2
- package/dist/shared/prompts.d.ts.map +1 -1
- package/dist/shared/prompts.js +1 -2
- package/dist/shared/prompts.js.map +1 -1
- package/dist/shared/reReview/projectionDiff.d.ts.map +1 -1
- package/dist/shared/reReview/projectionDiff.js +6 -14
- package/dist/shared/reReview/projectionDiff.js.map +1 -1
- package/dist/shared/types/executionPlan.d.ts +416 -0
- package/dist/shared/types/executionPlan.d.ts.map +1 -0
- package/dist/shared/types/executionPlan.js +132 -0
- package/dist/shared/types/executionPlan.js.map +1 -0
- package/dist/shared/types/remediationOutcome.d.ts +1378 -12
- package/dist/shared/types/remediationOutcome.d.ts.map +1 -1
- package/dist/shared/types/remediationOutcome.js +29 -1
- package/dist/shared/types/remediationOutcome.js.map +1 -1
- package/dist/shared/types/{contractPipeline/verification.d.ts → verificationReport.d.ts} +9 -37
- package/dist/shared/types/verificationReport.d.ts.map +1 -0
- package/dist/shared/types/verificationReport.js +4 -0
- package/dist/shared/types/verificationReport.js.map +1 -0
- package/dist/shared/validation/findingGrounding.d.ts +3 -5
- package/dist/shared/validation/findingGrounding.d.ts.map +1 -1
- package/dist/shared/validation/findingGrounding.js +4 -7
- package/dist/shared/validation/findingGrounding.js.map +1 -1
- package/package.json +1 -1
- package/dist/remediate/contractPipeline/artifactNames.d.ts +0 -8
- package/dist/remediate/contractPipeline/artifactNames.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/artifactNames.js +0 -28
- package/dist/remediate/contractPipeline/artifactNames.js.map +0 -1
- package/dist/remediate/contractPipeline/artifactStore.d.ts +0 -219
- package/dist/remediate/contractPipeline/artifactStore.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/artifactStore.js +0 -436
- package/dist/remediate/contractPipeline/artifactStore.js.map +0 -1
- package/dist/remediate/contractPipeline/changeClassification.d.ts +0 -130
- package/dist/remediate/contractPipeline/changeClassification.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/changeClassification.js +0 -446
- package/dist/remediate/contractPipeline/changeClassification.js.map +0 -1
- package/dist/remediate/contractPipeline/contractReviewBinding.d.ts +0 -28
- package/dist/remediate/contractPipeline/contractReviewBinding.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/contractReviewBinding.js +0 -75
- package/dist/remediate/contractPipeline/contractReviewBinding.js.map +0 -1
- package/dist/remediate/contractPipeline/counterexampleFingerprint.d.ts +0 -27
- package/dist/remediate/contractPipeline/counterexampleFingerprint.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/counterexampleFingerprint.js +0 -37
- package/dist/remediate/contractPipeline/counterexampleFingerprint.js.map +0 -1
- package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts +0 -131
- package/dist/remediate/contractPipeline/cyclicSeamResolution.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/cyclicSeamResolution.js +0 -257
- package/dist/remediate/contractPipeline/cyclicSeamResolution.js.map +0 -1
- package/dist/remediate/contractPipeline/derive.d.ts +0 -173
- package/dist/remediate/contractPipeline/derive.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/derive.js +0 -477
- package/dist/remediate/contractPipeline/derive.js.map +0 -1
- package/dist/remediate/contractPipeline/finalizedContractFields.d.ts +0 -50
- package/dist/remediate/contractPipeline/finalizedContractFields.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/finalizedContractFields.js +0 -77
- package/dist/remediate/contractPipeline/finalizedContractFields.js.map +0 -1
- package/dist/remediate/contractPipeline/idRegistry.d.ts +0 -144
- package/dist/remediate/contractPipeline/idRegistry.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/idRegistry.js +0 -214
- package/dist/remediate/contractPipeline/idRegistry.js.map +0 -1
- package/dist/remediate/contractPipeline/obligationKinds.d.ts +0 -27
- package/dist/remediate/contractPipeline/obligationKinds.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/obligationKinds.js +0 -18
- package/dist/remediate/contractPipeline/obligationKinds.js.map +0 -1
- package/dist/remediate/contractPipeline/phaseCut.d.ts +0 -125
- package/dist/remediate/contractPipeline/phaseCut.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/phaseCut.js +0 -339
- package/dist/remediate/contractPipeline/phaseCut.js.map +0 -1
- package/dist/remediate/contractPipeline/phaseCutArtifact.d.ts +0 -31
- package/dist/remediate/contractPipeline/phaseCutArtifact.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/phaseCutArtifact.js +0 -48
- package/dist/remediate/contractPipeline/phaseCutArtifact.js.map +0 -1
- package/dist/remediate/contractPipeline/repairState.d.ts +0 -110
- package/dist/remediate/contractPipeline/repairState.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/repairState.js +0 -185
- package/dist/remediate/contractPipeline/repairState.js.map +0 -1
- package/dist/remediate/contractPipeline/reviewSnapshot.d.ts +0 -79
- package/dist/remediate/contractPipeline/reviewSnapshot.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/reviewSnapshot.js +0 -140
- package/dist/remediate/contractPipeline/reviewSnapshot.js.map +0 -1
- package/dist/remediate/contractPipeline/semanticProjection.d.ts +0 -64
- package/dist/remediate/contractPipeline/semanticProjection.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/semanticProjection.js +0 -136
- package/dist/remediate/contractPipeline/semanticProjection.js.map +0 -1
- package/dist/remediate/contractPipeline/sketchSource.d.ts +0 -194
- package/dist/remediate/contractPipeline/sketchSource.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/sketchSource.js +0 -262
- package/dist/remediate/contractPipeline/sketchSource.js.map +0 -1
- package/dist/remediate/contractPipeline/testPlanCarry.d.ts +0 -17
- package/dist/remediate/contractPipeline/testPlanCarry.d.ts.map +0 -1
- package/dist/remediate/contractPipeline/testPlanCarry.js +0 -72
- package/dist/remediate/contractPipeline/testPlanCarry.js.map +0 -1
- package/dist/remediate/steps/dispatch/marshal.d.ts +0 -7
- package/dist/remediate/steps/dispatch/marshal.d.ts.map +0 -1
- package/dist/remediate/steps/dispatch/marshal.js +0 -11
- package/dist/remediate/steps/dispatch/marshal.js.map +0 -1
- package/dist/remediate/validation/contractPipeline.d.ts +0 -35
- package/dist/remediate/validation/contractPipeline.d.ts.map +0 -1
- package/dist/remediate/validation/contractPipeline.js +0 -613
- package/dist/remediate/validation/contractPipeline.js.map +0 -1
- package/dist/remediate/validation/contractPipelineGates.d.ts +0 -272
- package/dist/remediate/validation/contractPipelineGates.d.ts.map +0 -1
- package/dist/remediate/validation/contractPipelineGates.js +0 -1397
- package/dist/remediate/validation/contractPipelineGates.js.map +0 -1
- package/dist/shared/types/contractPipeline/design.d.ts +0 -79
- package/dist/shared/types/contractPipeline/design.d.ts.map +0 -1
- package/dist/shared/types/contractPipeline/design.js +0 -16
- package/dist/shared/types/contractPipeline/design.js.map +0 -1
- package/dist/shared/types/contractPipeline/goal.d.ts +0 -41
- package/dist/shared/types/contractPipeline/goal.d.ts.map +0 -1
- package/dist/shared/types/contractPipeline/goal.js +0 -10
- package/dist/shared/types/contractPipeline/goal.js.map +0 -1
- package/dist/shared/types/contractPipeline/implementation.d.ts +0 -118
- package/dist/shared/types/contractPipeline/implementation.d.ts.map +0 -1
- package/dist/shared/types/contractPipeline/implementation.js +0 -13
- package/dist/shared/types/contractPipeline/implementation.js.map +0 -1
- package/dist/shared/types/contractPipeline/obligations.d.ts +0 -283
- package/dist/shared/types/contractPipeline/obligations.d.ts.map +0 -1
- package/dist/shared/types/contractPipeline/obligations.js +0 -84
- package/dist/shared/types/contractPipeline/obligations.js.map +0 -1
- package/dist/shared/types/contractPipeline/verification.d.ts.map +0 -1
- package/dist/shared/types/contractPipeline/verification.js +0 -10
- package/dist/shared/types/contractPipeline/verification.js.map +0 -1
- package/dist/shared/types/contractPipeline.d.ts +0 -48
- package/dist/shared/types/contractPipeline.d.ts.map +0 -1
- package/dist/shared/types/contractPipeline.js +0 -32
- package/dist/shared/types/contractPipeline.js.map +0 -1
- package/dist/shared/types/obligationLedger.d.ts +0 -39
- package/dist/shared/types/obligationLedger.d.ts.map +0 -1
- package/dist/shared/types/obligationLedger.js +0 -49
- package/dist/shared/types/obligationLedger.js.map +0 -1
|
@@ -4,15 +4,18 @@ import { corroborateHostResult, corroborateNoChangeClaim } from "./hostCorrobora
|
|
|
4
4
|
import { runRequiredTest, rerunRequiredTests, requiredTestIssue, requiredTestVerdictKey } from "./requiredTests.js";
|
|
5
5
|
import { readIntentCheckpoint } from "../../../shared/types/intentCheckpoint.js";
|
|
6
6
|
import { checkContractConformance, conformanceReviewPaths } from "./contractConformanceReview.js";
|
|
7
|
+
import { executionPlanReferenceIssues } from "../../../shared/types/executionPlan.js";
|
|
8
|
+
import { executionPlanContextIssues } from "../../contractPipeline/executionPlan.js";
|
|
9
|
+
import { assertApprovedRuntimePlan as assertCurrentPlanAuthority, RemediationPlanAuthorityError } from "../../contractPipeline/runtimePlanAuthority.js";
|
|
7
10
|
// sites-pinned: tests/remediate/host-handoff-corroboration.test.ts, tests/remediate/host-handoff.test.ts
|
|
8
11
|
// host-handoff-corroboration: the bounded required-test failure message.
|
|
9
12
|
// host-handoff: the "landing gates" block fails when the close-owns-the-gates prompt line
|
|
10
13
|
// or the id-glossary write scope is reverted.
|
|
11
14
|
import { mkdir } from "node:fs/promises";
|
|
12
15
|
import { isAbsolute, join } from "node:path";
|
|
13
|
-
import { headCommit, commandLeavesDeclaredShape,
|
|
16
|
+
import { headCommit, commandLeavesDeclaredShape, SUBMISSION_ISSUE_REMEDY, WORKLOAD_ISSUE_REMEDY, bindWorkerPrompt, deriveResultId, SUBMISSION_LEDGER_EVENT_CONTRACT_VERSION, appendSubmissionEvent, enrichMissingSubmissionIssues, isMissingObservation, compareCodeUnits, contentSha256, deriveLaneDemand, estimateTokensFromBytes, discoverLandingGates, hasExactKeys, identityFailureDiagnostic, hostHandoffResultPath, idsAreStrictlyAscending, isCommit, isGitRepo, isRecord, isSha256, LaneDemandSchema, normalizeRepoPath, parseAllWorkloadItems, parseWorkloadEnvelope, readSubmissionDocument, readJsonFile, readSubmissionLedger, readTrailingSubmissionRefusals, recoveryMarkMatches, recordHostResultOutcomes, repoRelativePath, resolveContainedPath, resolveHostHandoffPaths, sameStrings, scanBoundSubmission, SEVERITIES, severityRank, stringArray, stableStringify, writeJsonFile, } from "audit-tools/shared";
|
|
14
17
|
import { REMEDIATION_STATE_CONTRACT_VERSION, } from "../../state/store.js";
|
|
15
|
-
import {
|
|
18
|
+
import { REMEDIATION_HOST_HANDOFF_RECORD_V1ALPHA2, REMEDIATION_HOST_SCOPE_SEMANTICS, RemediationHostHandoffRecordSchema, ConformanceReviewBindingSchema, RemediationPlanSchema, isClarificationCategory, } from "../../state/types.js";
|
|
16
19
|
import { ITEM_STATUSES, isTerminalStatus, isVerifiedCompleteStatus, } from "../../state/itemStatus.js";
|
|
17
20
|
import { REMEDIATION_HOST_DECISION_CONTRACT_VERSION as DECISION_CONTRACT_VERSION, REMEDIATION_HOST_RESULT_CONTRACT_VERSION as RESULT_CONTRACT_VERSION, REMEDIATION_HOST_WORKLOAD_CONTRACT_VERSION as WORKLOAD_CONTRACT_VERSION, } from "../types.js";
|
|
18
21
|
// The state contract version is the STORE's declaration, not a second literal
|
|
@@ -82,6 +85,8 @@ const CURRENT_STATE_KEYS = new Set([
|
|
|
82
85
|
"closing_plan",
|
|
83
86
|
"contract_version",
|
|
84
87
|
"items",
|
|
88
|
+
"finding_dispositions",
|
|
89
|
+
"source_verifications",
|
|
85
90
|
"host_handoff",
|
|
86
91
|
"conformance_review",
|
|
87
92
|
"plan",
|
|
@@ -92,7 +97,7 @@ const CURRENT_STATE_KEYS = new Set([
|
|
|
92
97
|
"step_count",
|
|
93
98
|
]);
|
|
94
99
|
const CURRENT_ITEM_KEYS = new Set([
|
|
95
|
-
"
|
|
100
|
+
"unit_id",
|
|
96
101
|
"clarification_context",
|
|
97
102
|
"clarification_question",
|
|
98
103
|
"completed_at",
|
|
@@ -106,10 +111,8 @@ const CURRENT_ITEM_KEYS = new Set([
|
|
|
106
111
|
"host_landed_files",
|
|
107
112
|
"host_result_evidence",
|
|
108
113
|
"conformance_review",
|
|
109
|
-
"finding_id",
|
|
110
114
|
"incomplete_coverage_attempts",
|
|
111
115
|
"last_successful_step",
|
|
112
|
-
"mechanical_verification",
|
|
113
116
|
"rework_count",
|
|
114
117
|
"started_at",
|
|
115
118
|
"status",
|
|
@@ -143,37 +146,32 @@ function parseCurrentState(value) {
|
|
|
143
146
|
return null;
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
return null;
|
|
150
|
-
blockById.set(block.block_id, block);
|
|
151
|
-
}
|
|
149
|
+
const unitIds = new Set(parsedPlan.data.units.map(unit => unit.id));
|
|
150
|
+
if (unitIds.size !== parsedPlan.data.units.length)
|
|
151
|
+
return null;
|
|
152
152
|
const knownStatuses = new Set(ITEM_STATUSES);
|
|
153
|
-
for (const [
|
|
154
|
-
if (!isRecord(item) ||
|
|
155
|
-
!
|
|
156
|
-
item.finding_id !== findingId ||
|
|
157
|
-
typeof item.block_id !== "string" ||
|
|
158
|
-
!knownStatuses.has(String(item.status))) {
|
|
153
|
+
for (const [unitId, item] of Object.entries(stateItems)) {
|
|
154
|
+
if (!isRecord(item) || !hasOnlyKnownKeys(item, CURRENT_ITEM_KEYS) ||
|
|
155
|
+
item.unit_id !== unitId || !unitIds.has(unitId) || !knownStatuses.has(String(item.status)))
|
|
159
156
|
return null;
|
|
160
|
-
}
|
|
161
157
|
if (item.conformance_review !== undefined && !AcceptedConformanceReviewSchema.safeParse(item.conformance_review).success)
|
|
162
158
|
return null;
|
|
163
|
-
const block = blockById.get(item.block_id);
|
|
164
|
-
if (!block || !block.items.includes(findingId))
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
for (const block of parsedPlan.data.blocks) {
|
|
168
|
-
if (block.items.some((findingId) => {
|
|
169
|
-
const item = stateItems[findingId];
|
|
170
|
-
return !isRecord(item) || item.block_id !== block.block_id;
|
|
171
|
-
})) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
159
|
}
|
|
160
|
+
if ([...unitIds].some(id => !stateItems[id]))
|
|
161
|
+
return null;
|
|
175
162
|
return value;
|
|
176
163
|
}
|
|
164
|
+
/** Preserve the host boundary's public repair error while sharing its authority policy. */
|
|
165
|
+
async function assertApprovedRuntimePlan(artifactsDir, state) {
|
|
166
|
+
try {
|
|
167
|
+
return await assertCurrentPlanAuthority(artifactsDir, state);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
if (!(error instanceof RemediationPlanAuthorityError))
|
|
171
|
+
throw error;
|
|
172
|
+
throw new RemediationHostPreparationError(error.code, error.message);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
177
175
|
function normalizeDeclaredPath(root, candidate, label) {
|
|
178
176
|
if (candidate.length === 0 || isAbsolute(candidate)) {
|
|
179
177
|
throw new Error(`${label} must be a non-empty repository-relative path`);
|
|
@@ -181,79 +179,6 @@ function normalizeDeclaredPath(root, candidate, label) {
|
|
|
181
179
|
const normalized = repoRelativePath(root, candidate, label);
|
|
182
180
|
return candidate.endsWith("/") ? `${normalized}/` : normalized;
|
|
183
181
|
}
|
|
184
|
-
function deriveLegacyDirectoryPathsForBlock(state, blockId, declaredPaths) {
|
|
185
|
-
const binding = state.host_handoff;
|
|
186
|
-
if (binding?.contract_version !== REMEDIATION_HOST_HANDOFF_RECORD_V1ALPHA1) {
|
|
187
|
-
return [];
|
|
188
|
-
}
|
|
189
|
-
const block = state.plan.blocks.find((entry) => entry.block_id === blockId);
|
|
190
|
-
if (!block)
|
|
191
|
-
return [];
|
|
192
|
-
const hashedDirectoryPaths = new Set();
|
|
193
|
-
for (const findingId of block.items) {
|
|
194
|
-
const finding = state.plan.findings.find((entry) => entry.id === findingId);
|
|
195
|
-
if (!finding)
|
|
196
|
-
continue;
|
|
197
|
-
for (const affectedFile of finding.affected_files) {
|
|
198
|
-
if (affectedFile.path.endsWith("/") &&
|
|
199
|
-
isSha256(affectedFile.hash_at_plan_time)) {
|
|
200
|
-
hashedDirectoryPaths.add(affectedFile.path);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return declaredPaths.flatMap((path) => {
|
|
205
|
-
const directoryPath = `${path}/`;
|
|
206
|
-
return !path.endsWith("/") && hashedDirectoryPaths.has(directoryPath)
|
|
207
|
-
? [directoryPath]
|
|
208
|
-
: [];
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
function deriveLegacyDirectoryScopeRecovery(state, workItem) {
|
|
212
|
-
if (!state.host_handoff?.work_item_ids.includes(workItem.id)) {
|
|
213
|
-
return { workItem, directoryPaths: [] };
|
|
214
|
-
}
|
|
215
|
-
const directoryPaths = deriveLegacyDirectoryPathsForBlock(state, workItem.id, workItem.allowed_files);
|
|
216
|
-
const recovered = new Set(directoryPaths);
|
|
217
|
-
const allowedFiles = workItem.allowed_files.map((allowed) => {
|
|
218
|
-
const directoryPath = `${allowed}/`;
|
|
219
|
-
return recovered.has(directoryPath) ? directoryPath : allowed;
|
|
220
|
-
});
|
|
221
|
-
return {
|
|
222
|
-
workItem: sameStrings(allowedFiles, workItem.allowed_files)
|
|
223
|
-
? workItem
|
|
224
|
-
: { ...workItem, allowed_files: allowedFiles },
|
|
225
|
-
directoryPaths,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
function effectiveBoundWorkload(state, workload) {
|
|
229
|
-
if (!state.host_handoff)
|
|
230
|
-
return workload;
|
|
231
|
-
return {
|
|
232
|
-
...workload,
|
|
233
|
-
work_items: workload.work_items.map((workItem) => deriveLegacyDirectoryScopeRecovery(state, workItem).workItem),
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
/**
|
|
237
|
-
* Persist the same directory intent for every block in a legacy plan before
|
|
238
|
-
* its final active workload is cleared. Dependency-blocked blocks are included
|
|
239
|
-
* because their next workload will be minted under v1alpha2 and cannot use
|
|
240
|
-
* legacy inference. This must run only on the final drain: changing a currently
|
|
241
|
-
* bound block sooner would break byte-for-byte canonical re-derivation.
|
|
242
|
-
*/
|
|
243
|
-
function migrateLegacyDirectoryScopesAfterFinalDrain(state) {
|
|
244
|
-
state.plan.blocks = state.plan.blocks.map((block) => {
|
|
245
|
-
const recovered = new Set(deriveLegacyDirectoryPathsForBlock(state, block.block_id, block.touched_files));
|
|
246
|
-
if (recovered.size === 0)
|
|
247
|
-
return block;
|
|
248
|
-
const touchedFiles = block.touched_files.map((path) => !path.endsWith("/") && recovered.has(`${path}/`) ? `${path}/` : path);
|
|
249
|
-
return sameStrings(touchedFiles, block.touched_files)
|
|
250
|
-
? block
|
|
251
|
-
: {
|
|
252
|
-
...block,
|
|
253
|
-
touched_files: [...new Set(touchedFiles)].sort(compareCodeUnits),
|
|
254
|
-
};
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
182
|
/**
|
|
258
183
|
* A block that arrived outside the shape this boundary CONSUMES.
|
|
259
184
|
*
|
|
@@ -283,42 +208,42 @@ class BlockContractError extends Error {
|
|
|
283
208
|
* becomes a work item and its commands never run.
|
|
284
209
|
*
|
|
285
210
|
* COVERS THE HANDOFF BOUNDARY ONLY. The other consumer of the same
|
|
286
|
-
* `block.
|
|
211
|
+
* `block.required_tests` — `reverifyBlockedItemAgainstTree` in
|
|
287
212
|
* `src/remediate/phases/triage.ts` — asks the same declared command-shape rule
|
|
288
213
|
* before spawning and then runs each command through {@link runRequiredTest}
|
|
289
214
|
* (argv-split, no shell, deadline-bounded), so a command this boundary would
|
|
290
215
|
* refuse is refused there too rather than reaching a shell.
|
|
291
216
|
*/
|
|
292
217
|
function assertBlockContract(root, block) {
|
|
293
|
-
for (const raw of block.
|
|
218
|
+
for (const raw of block.allowed_files) {
|
|
294
219
|
if (typeof raw !== "string" || raw.trim().length === 0) {
|
|
295
|
-
throw new BlockContractError(block.
|
|
220
|
+
throw new BlockContractError(block.id, "touched_files carries an empty entry");
|
|
296
221
|
}
|
|
297
222
|
if (isAbsolute(raw)) {
|
|
298
|
-
throw new BlockContractError(block.
|
|
223
|
+
throw new BlockContractError(block.id, `touched_files entry ${JSON.stringify(raw)} is absolute, not repository-relative`);
|
|
299
224
|
}
|
|
300
225
|
let normalized;
|
|
301
226
|
try {
|
|
302
|
-
normalized = normalizeDeclaredPath(root, raw, `${block.
|
|
227
|
+
normalized = normalizeDeclaredPath(root, raw, `${block.id}.touched_files[]`);
|
|
303
228
|
}
|
|
304
229
|
catch {
|
|
305
|
-
throw new BlockContractError(block.
|
|
230
|
+
throw new BlockContractError(block.id, `touched_files entry ${JSON.stringify(raw)} does not resolve beneath the repository root`);
|
|
306
231
|
}
|
|
307
232
|
if (normalized !== raw) {
|
|
308
|
-
throw new BlockContractError(block.
|
|
233
|
+
throw new BlockContractError(block.id, `touched_files entry ${JSON.stringify(raw)} is not in normalized repo-relative form ` +
|
|
309
234
|
`(${JSON.stringify(normalized)})`);
|
|
310
235
|
}
|
|
311
236
|
}
|
|
312
|
-
for (const command of block.
|
|
237
|
+
for (const command of block.required_tests ?? []) {
|
|
313
238
|
if (typeof command !== "string" || command.trim().length === 0) {
|
|
314
|
-
throw new BlockContractError(block.
|
|
239
|
+
throw new BlockContractError(block.id, "targeted_commands carries an empty command");
|
|
315
240
|
}
|
|
316
241
|
// THE declared-command-shape rule (`audit-tools/shared`), not a local copy:
|
|
317
242
|
// the producer that promotes these commands and the triage path that also
|
|
318
243
|
// spawns them ask the same predicate, so a command cannot clear one boundary
|
|
319
244
|
// and dead-end at another.
|
|
320
245
|
if (commandLeavesDeclaredShape(command)) {
|
|
321
|
-
throw new BlockContractError(block.
|
|
246
|
+
throw new BlockContractError(block.id, `targeted_command ${JSON.stringify(command)} leaves the declared shape — it chains, ` +
|
|
322
247
|
"redirects or substitutes, and this boundary executes commands verbatim through a shell");
|
|
323
248
|
}
|
|
324
249
|
}
|
|
@@ -344,22 +269,20 @@ function assertBlockContract(root, block) {
|
|
|
344
269
|
* always named" true rather than usually true.
|
|
345
270
|
*/
|
|
346
271
|
function planBlockIssues(root, state) {
|
|
347
|
-
const blockIds = new Set(state.plan.
|
|
272
|
+
const blockIds = new Set(state.plan.units.map((block) => block.id));
|
|
348
273
|
const boundIds = new Set(state.host_handoff?.work_item_ids ?? []);
|
|
349
274
|
const issues = [];
|
|
350
|
-
for (const block of state.plan.
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
});
|
|
355
|
-
if (!unsettled && !boundIds.has(block.block_id))
|
|
275
|
+
for (const block of state.plan.units) {
|
|
276
|
+
const status = state.items[block.id]?.status;
|
|
277
|
+
const unsettled = status !== undefined && !isTerminalStatus(status);
|
|
278
|
+
if (!unsettled && !boundIds.has(block.id))
|
|
356
279
|
continue;
|
|
357
280
|
const missing = (block.dependencies ?? []).filter((dependencyId) => !blockIds.has(dependencyId));
|
|
358
281
|
if (missing.length > 0) {
|
|
359
282
|
issues.push({
|
|
360
283
|
code: "dependency_missing",
|
|
361
|
-
work_item_id: block.
|
|
362
|
-
message: `block '${block.
|
|
284
|
+
work_item_id: block.id,
|
|
285
|
+
message: `block '${block.id}' declares ${missing.length === 1 ? "a dependency" : "dependencies"} ` +
|
|
363
286
|
`${missing.map((id) => `'${id}'`).join(", ")} present in no block of the plan, so it can ` +
|
|
364
287
|
"never be dependency-verified and is never scheduled",
|
|
365
288
|
});
|
|
@@ -373,11 +296,15 @@ function planBlockIssues(root, state) {
|
|
|
373
296
|
throw error;
|
|
374
297
|
issues.push({
|
|
375
298
|
code: "block_contract_invalid",
|
|
376
|
-
work_item_id: block.
|
|
299
|
+
work_item_id: block.id,
|
|
377
300
|
message: error.message,
|
|
378
301
|
});
|
|
379
302
|
}
|
|
380
303
|
}
|
|
304
|
+
for (const message of executionPlanReferenceIssues(state.plan, state.plan.findings.map(finding => finding.id))) {
|
|
305
|
+
if (!issues.some(issue => issue.message === message))
|
|
306
|
+
issues.push({ code: "block_contract_invalid", message });
|
|
307
|
+
}
|
|
381
308
|
return issues;
|
|
382
309
|
}
|
|
383
310
|
/**
|
|
@@ -470,171 +397,64 @@ export function remediationHostResultFilePath(params) {
|
|
|
470
397
|
* verified its prerequisites.
|
|
471
398
|
*/
|
|
472
399
|
export function hostDependencyLevels(state) {
|
|
473
|
-
const plan = state
|
|
474
|
-
const items = state.items;
|
|
400
|
+
const { plan, items } = state;
|
|
475
401
|
if (!plan || !items)
|
|
476
402
|
return [];
|
|
477
|
-
const
|
|
478
|
-
const
|
|
479
|
-
const isVerifiedNow = (block) => block.items.every((findingId) => isVerifiedCompleteStatus(items[findingId]?.status));
|
|
480
|
-
const isPending = (block) => block.items.some((findingId) => items[findingId]?.status === "pending");
|
|
481
|
-
const phaseOf = (block) => block.phase_ordinal ?? 0;
|
|
482
|
-
const lowerPhaseBlocks = (phase) => plan.blocks.filter((block) => phaseOf(block) < phase);
|
|
483
|
-
const phaseBarrierClear = (phase) => lowerPhaseBlocks(phase).every(isVerifiedNow);
|
|
484
|
-
const phaseBarrierUnsatisfiable = (phase) => lowerPhaseBlocks(phase).some((block) => !isVerifiedNow(block) && !isPending(block));
|
|
485
|
-
const permanentlyIneligible = (block) => {
|
|
486
|
-
for (const dependencyId of block.dependencies ?? []) {
|
|
487
|
-
const dependency = blockById.get(dependencyId);
|
|
488
|
-
// An id that resolves to NO block is not a harmless declaration — it is a
|
|
489
|
-
// prerequisite that can never be verified, so the block can never become
|
|
490
|
-
// eligible. Guarding on `dependency &&` skipped exactly this case, which
|
|
491
|
-
// is the second half of the same hole as the readiness predicate below:
|
|
492
|
-
// closing only one leaves the block reaching the host anyway.
|
|
493
|
-
if (dependency === undefined)
|
|
494
|
-
return true;
|
|
495
|
-
if (!isVerifiedNow(dependency) && !isPending(dependency)) {
|
|
496
|
-
return true;
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
return phaseBarrierUnsatisfiable(phaseOf(block));
|
|
500
|
-
};
|
|
501
|
-
const levels = [];
|
|
403
|
+
const byId = new Map(plan.units.map(unit => [unit.id, unit]));
|
|
404
|
+
const lowerPhases = (unit) => plan.units.filter(lower => (lower.phase_ordinal ?? 0) < (unit.phase_ordinal ?? 0));
|
|
502
405
|
const placed = new Set();
|
|
503
|
-
let remaining =
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
// never verified — silently, because no other check looks at it.
|
|
512
|
-
if (dependency === undefined)
|
|
513
|
-
return false;
|
|
514
|
-
if (isVerifiedNow(dependency))
|
|
515
|
-
return true;
|
|
516
|
-
return dependency.items.every((findingId) => isVerifiedCompleteStatus(items[findingId]?.status) ||
|
|
517
|
-
(items[findingId]?.status === "pending" &&
|
|
518
|
-
placed.has(dependency.block_id)));
|
|
519
|
-
}));
|
|
520
|
-
if (ready.length === 0)
|
|
406
|
+
let remaining = plan.units.filter(unit => items[unit.id]?.status === "pending");
|
|
407
|
+
const levels = [];
|
|
408
|
+
while (remaining.length) {
|
|
409
|
+
// A phase is an integration boundary: even projected later dependency levels
|
|
410
|
+
// wait until every earlier phase actually verified on the current tree.
|
|
411
|
+
const ready = remaining.filter(unit => lowerPhases(unit).every(lower => isVerifiedCompleteStatus(items[lower.id]?.status)) &&
|
|
412
|
+
unit.dependencies.every(id => byId.has(id) && (isVerifiedCompleteStatus(items[id]?.status) || placed.has(id))));
|
|
413
|
+
if (!ready.length)
|
|
521
414
|
break;
|
|
522
415
|
levels.push(ready);
|
|
523
|
-
for (const
|
|
524
|
-
placed.add(
|
|
525
|
-
remaining = remaining.filter(
|
|
416
|
+
for (const unit of ready)
|
|
417
|
+
placed.add(unit.id);
|
|
418
|
+
remaining = remaining.filter(unit => !placed.has(unit.id));
|
|
526
419
|
}
|
|
527
420
|
return levels;
|
|
528
421
|
}
|
|
529
|
-
/**
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
* boundary share one eligibility semantics and cannot disagree (the 2026-08-23
|
|
533
|
-
* empty-frontier incident: the old edge-only sweep predicate missed the phase
|
|
534
|
-
* barrier and dependency existence, so a frontier the builder refused looked
|
|
535
|
-
* dispatchable to the guard and next-step threw instead of pausing).
|
|
536
|
-
*
|
|
537
|
-
* Optimistic liveness fixpoint: an item counts as still SATISFIABLE while it is
|
|
538
|
-
* verified-complete, `pending`, or `needs_clarification` — an unanswered
|
|
539
|
-
* question is "awaiting an answer", never "upstream failed" (the 175cfb89
|
|
540
|
-
* pin). A block is LIVE once every one of its items is satisfiable, every
|
|
541
|
-
* declared dependency resolves to a live block, and every lower-phase block is
|
|
542
|
-
* live. What never enters the live set is exactly what can never reach the
|
|
543
|
-
* host: an obstacle chain that bottoms out in a terminal non-verified item
|
|
544
|
-
* (`blocked` or a SKIP — INV-RS-01), a dependency id that resolves to no
|
|
545
|
-
* block, or a dependency cycle.
|
|
546
|
-
*/
|
|
547
|
-
export function permanentlyDeadPendingBlocks(state) {
|
|
548
|
-
const plan = state.plan;
|
|
549
|
-
const items = state.items;
|
|
422
|
+
/** Questions remain live; skipped/failed prerequisites never authorize a dependent. */
|
|
423
|
+
export function permanentlyDeadPendingUnits(state) {
|
|
424
|
+
const { plan, items } = state;
|
|
550
425
|
if (!plan || !items)
|
|
551
426
|
return [];
|
|
552
|
-
const
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
// Fully-verified blocks seed the live set unconditionally: their work already
|
|
558
|
-
// landed, so their own declared dependencies are history, not obstacles.
|
|
559
|
-
const live = new Set(plan.blocks
|
|
560
|
-
.filter((block) => block.items.every((findingId) => isVerifiedCompleteStatus(items[findingId]?.status)))
|
|
561
|
-
.map((block) => block.block_id));
|
|
562
|
-
// Least fixpoint: grow the live set until stable. A cycle never enters it.
|
|
563
|
-
for (let grew = true; grew;) {
|
|
564
|
-
grew = false;
|
|
565
|
-
for (const block of plan.blocks) {
|
|
566
|
-
if (live.has(block.block_id))
|
|
567
|
-
continue;
|
|
568
|
-
if (!block.items.every((findingId) => satisfiable(items[findingId]?.status))) {
|
|
427
|
+
const live = new Set(plan.units.filter(unit => isVerifiedCompleteStatus(items[unit.id]?.status)).map(unit => unit.id));
|
|
428
|
+
for (let changed = true; changed;) {
|
|
429
|
+
changed = false;
|
|
430
|
+
for (const unit of plan.units) {
|
|
431
|
+
if (live.has(unit.id))
|
|
569
432
|
continue;
|
|
570
|
-
|
|
571
|
-
const
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
const lowerPhasesLive = plan.blocks
|
|
576
|
-
.filter((lower) => phaseOf(lower) < phaseOf(block))
|
|
577
|
-
.every((lower) => live.has(lower.block_id));
|
|
578
|
-
if (dependenciesLive && lowerPhasesLive) {
|
|
579
|
-
live.add(block.block_id);
|
|
580
|
-
grew = true;
|
|
433
|
+
const status = items[unit.id]?.status;
|
|
434
|
+
const lowerPhasesLive = plan.units.filter(lower => (lower.phase_ordinal ?? 0) < (unit.phase_ordinal ?? 0)).every(lower => live.has(lower.id));
|
|
435
|
+
if ((status === "pending" || status === "needs_clarification") && lowerPhasesLive && unit.dependencies.every(id => live.has(id))) {
|
|
436
|
+
live.add(unit.id);
|
|
437
|
+
changed = true;
|
|
581
438
|
}
|
|
582
439
|
}
|
|
583
440
|
}
|
|
584
|
-
return plan.
|
|
585
|
-
block.items.some((findingId) => items[findingId]?.status === "pending"));
|
|
441
|
+
return plan.units.filter(unit => !live.has(unit.id) && items[unit.id]?.status === "pending");
|
|
586
442
|
}
|
|
587
443
|
function buildPrompt(item) {
|
|
588
|
-
const assignment = stableStringify({
|
|
589
|
-
...(item.implementationContext ? { implementation_context: item.implementationContext } : {}),
|
|
590
|
-
allowed_files: item.allowedFiles,
|
|
591
|
-
assignments: item.assignments,
|
|
592
|
-
baseline_commit: item.baselineCommit,
|
|
593
|
-
finding_ids: item.findingIds,
|
|
594
|
-
id: item.blockId,
|
|
595
|
-
// The approved contract rides the sha-bound prompt (the evidence-coverage
|
|
596
|
-
// entry in docs/backlog/open-bugs.md): the binding then covers exactly the
|
|
597
|
-
// interface the worker saw.
|
|
598
|
-
...(item.moduleContracts.length > 0
|
|
599
|
-
? { module_contracts: item.moduleContracts }
|
|
600
|
-
: {}),
|
|
601
|
-
...(item.obligationIds.length > 0
|
|
602
|
-
? { obligation_ids: item.obligationIds }
|
|
603
|
-
: {}),
|
|
604
|
-
required_tests: item.requiredTests,
|
|
605
|
-
result_path: item.resultPath,
|
|
606
|
-
});
|
|
607
|
-
// The BODY only. The result template is appended by `bindWorkerPrompt`, and
|
|
608
|
-
// the prompt digest covers exactly this text (owner review of prompt 20,
|
|
609
|
-
// 2026-09-18: plain language, rules as bullets, no word a worker cannot act
|
|
610
|
-
// on).
|
|
611
444
|
return [
|
|
612
|
-
`# Implement
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
"```",
|
|
619
|
-
"",
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
'-
|
|
623
|
-
|
|
624
|
-
...(item.
|
|
625
|
-
? [
|
|
626
|
-
"- Conform to each contract in `module_contracts`: every declared input, output, invariant, side effect, validation boundary, failure mode and seam adjustment. Code that breaks a contract is a defect, even when the build and the tests pass.",
|
|
627
|
-
]
|
|
628
|
-
: []),
|
|
629
|
-
...(item.requiredTests.length > 0
|
|
630
|
-
? [
|
|
631
|
-
"- Run each command in `required_tests` until it passes. The tool runs each command again before it accepts your result.",
|
|
632
|
-
]
|
|
633
|
-
: []),
|
|
634
|
-
"- Make one commit on top of `baseline_commit`, with all your edits in it. Merge it so that HEAD contains it.",
|
|
635
|
-
...(item.hasLandingGates
|
|
636
|
-
? ["- Do not run the landing gates. The close phase runs them once, on the merged tree."]
|
|
637
|
-
: []),
|
|
445
|
+
`# Implement execution unit \`${item.unit.id}\``, "", "Assignment:", "", "```json",
|
|
446
|
+
stableStringify({
|
|
447
|
+
unit: item.unit, requirements: item.requirements, source_findings: item.sourceFindings,
|
|
448
|
+
accepted_counterexamples: item.counterexamples,
|
|
449
|
+
review_revision_sha256: item.revision, baseline_commit: item.baselineCommit,
|
|
450
|
+
...item.context, result_path: item.resultPath,
|
|
451
|
+
}), "```", "", "Rules:", "",
|
|
452
|
+
'- Edit only `unit.allowed_files`. A trailing "/" permits files below that directory; every other entry permits exactly that file.',
|
|
453
|
+
'- Read `unit.read_paths`, implement the reviewed unit description, and satisfy every linked requirement and scoped positive/negative assertion. Original source findings are provenance, not substitute execution instructions.',
|
|
454
|
+
'- Preserve every declared affected interface and address the named counterexamples. Code violating a requirement is a defect even if tests pass.',
|
|
455
|
+
...(item.unit.required_tests.length ? ['- Run every `unit.required_tests` command until it passes. The tool reruns each before accepting your result.'] : []),
|
|
456
|
+
'- Make one commit on top of `baseline_commit`, with all your edits in it. Merge it so HEAD contains it.',
|
|
457
|
+
...(item.hasLandingGates ? ['- Do not run the landing gates. The close phase runs them once, on the merged tree.'] : []),
|
|
638
458
|
].join("\n");
|
|
639
459
|
}
|
|
640
460
|
/**
|
|
@@ -727,7 +547,7 @@ export function severityRiskWeight(severity) {
|
|
|
727
547
|
: (severityRank(severity) - 1) / ladder;
|
|
728
548
|
}
|
|
729
549
|
function blockRiskScore(state, block) {
|
|
730
|
-
const scores = block.
|
|
550
|
+
const scores = block.source_finding_ids
|
|
731
551
|
.map((findingId) => state.plan.findings.find((entry) => entry.id === findingId)?.severity)
|
|
732
552
|
.flatMap((severity) => severity === undefined ? [] : [severityRiskWeight(severity)]);
|
|
733
553
|
if (scores.length === 0)
|
|
@@ -739,104 +559,41 @@ function blockRiskScore(state, block) {
|
|
|
739
559
|
const corroborating = scores.filter((score) => score >= worst / 2).length - 1;
|
|
740
560
|
return Math.min(1, worst + Math.max(0, corroborating) * 0.1);
|
|
741
561
|
}
|
|
742
|
-
function
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
? { clarification_context: item.clarification_context }
|
|
753
|
-
: {}),
|
|
754
|
-
...(item.failure_context
|
|
755
|
-
? { failure_context: item.failure_context }
|
|
756
|
-
: {}),
|
|
757
|
-
};
|
|
562
|
+
function buildWorkItem(paths, runId, unit, baselineCommit, state) {
|
|
563
|
+
assertBlockContract(paths.root, unit);
|
|
564
|
+
const item = state.items[unit.id];
|
|
565
|
+
if (!item)
|
|
566
|
+
throw new Error(`Execution unit ${unit.id} has no runtime item`);
|
|
567
|
+
const requirements = unit.requirement_ids.map(id => {
|
|
568
|
+
const requirement = state.plan.requirements.find(entry => entry.id === id);
|
|
569
|
+
if (!requirement)
|
|
570
|
+
throw new Error(`Execution unit ${unit.id} references unknown requirement ${id}`);
|
|
571
|
+
return requirement;
|
|
758
572
|
});
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
assertBlockContract(paths.root, block);
|
|
765
|
-
// THE ID-GLOSSARY SCOPE. A block whose contract COINS an invariant id writes
|
|
766
|
-
// it in `src/`, and the glossary document that has to document it sits
|
|
767
|
-
// outside every module's file scope — so without this the item is
|
|
768
|
-
// structurally unable to satisfy the id-glossary gate. Read off the block's
|
|
769
|
-
// own contract and obligations, never guessed; the ids the document already
|
|
770
|
-
// carries are subtracted inside `withGlossaryScope`, so a contract that only
|
|
771
|
-
// MENTIONS an existing id (a seam adjustment citing `INV-COVERAGE`, say) gets
|
|
772
|
-
// no widening — it coins nothing and needs no row.
|
|
773
|
-
const declaredIds = declaredInvariantIds({
|
|
774
|
-
obligations: block.items.flatMap((findingId) => state.plan.findings.find((entry) => entry.id === findingId)
|
|
775
|
-
?.contract_obligation_ids ?? []),
|
|
776
|
-
module_contracts: block.module_contracts ?? [],
|
|
573
|
+
const sourceFindings = unit.source_finding_ids.map(id => {
|
|
574
|
+
const finding = state.plan.findings.find(entry => entry.id === id);
|
|
575
|
+
if (!finding)
|
|
576
|
+
throw new Error(`Execution unit ${unit.id} references unknown source finding ${id}`);
|
|
577
|
+
return finding;
|
|
777
578
|
});
|
|
778
|
-
const
|
|
779
|
-
const
|
|
780
|
-
// THE LANDING GATES ARE NOT THIS ITEM'S. `check:deadcode`, `check:depgraph`,
|
|
781
|
-
// lint and the id-glossary gate state facts about the WHOLE tree, so the
|
|
782
|
-
// boundary that owns them is the CLOSE, on the merged tree — never a
|
|
783
|
-
// per-item dispatch. Folding them in here was tried and refused a wave item
|
|
784
|
-
// that added an export whose only consumer lands in a LATER item: no edit
|
|
785
|
-
// inside the item's scope could pass, and another item's fault could refuse
|
|
786
|
-
// this one. See CLAUDE.md, *A gate states the boundary it OWNS*; the close
|
|
787
|
-
// leg is `verifyLandingGates` in `src/remediate/phases/close.ts`.
|
|
788
|
-
//
|
|
789
|
-
// The per-item required tests are the block's OWN commands, unchanged, which
|
|
790
|
-
// is what this field meant before the gates were folded in and what the
|
|
791
|
-
// tool reruns at ingestion.
|
|
792
|
-
//
|
|
793
|
-
// ONE FACT still rides the emitted prompt: whether the target root declares
|
|
794
|
-
// any landing gate at all, so the host knows a close will run them.
|
|
795
|
-
const hasLandingGates = discoverLandingGates(paths.root).length > 0;
|
|
796
|
-
const requiredTests = [...(block.targeted_commands ?? [])];
|
|
797
|
-
const assignments = buildFindingAssignments(state, block);
|
|
798
|
-
// The obligation demand is bound here, once, from the same plan findings the
|
|
799
|
-
// assignments render — ingestion then re-derives this exact set through the
|
|
800
|
-
// byte-for-byte work-item comparison, so the result's evidence coverage is
|
|
801
|
-
// checked against a tool-owned binding, never the result's own claim.
|
|
802
|
-
const obligationIds = [
|
|
803
|
-
...new Set(block.items.flatMap((findingId) => state.plan.findings.find((entry) => entry.id === findingId)
|
|
804
|
-
?.contract_obligation_ids ?? [])),
|
|
805
|
-
].sort(compareCodeUnits);
|
|
579
|
+
const resultPath = resultPathFor(paths, unit.id);
|
|
580
|
+
const obligationIds = [...unit.requirement_ids].sort(compareCodeUnits);
|
|
806
581
|
const prompt = bindWorkerPrompt(buildPrompt({
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
resultPath,
|
|
816
|
-
moduleContracts: block.module_contracts ?? [],
|
|
817
|
-
implementationContext: block.implementation_context,
|
|
818
|
-
}), (promptDigest) => renderResultTemplate({
|
|
819
|
-
runId,
|
|
820
|
-
blockId: block.block_id,
|
|
821
|
-
resultPath,
|
|
822
|
-
obligationIds,
|
|
823
|
-
promptDigest,
|
|
824
|
-
}));
|
|
582
|
+
unit, requirements, sourceFindings, revision: state.plan.review_revision_sha256,
|
|
583
|
+
counterexamples: (state.plan.review_counterexamples ?? []).filter(example => unit.addresses_counterexample_ids.includes(example.id)),
|
|
584
|
+
context: {
|
|
585
|
+
...(item.clarification_context ? { clarification_context: item.clarification_context } : {}),
|
|
586
|
+
...(item.failure_context ? { failure_context: item.failure_context } : {}),
|
|
587
|
+
}, baselineCommit, resultPath, hasLandingGates: discoverLandingGates(paths.root).length > 0,
|
|
588
|
+
}), promptDigest => renderResultTemplate({ runId, blockId: unit.id, resultPath, obligationIds, promptDigest }));
|
|
589
|
+
const tokenEstimate = estimateTokensFromBytes(Buffer.byteLength(prompt.text, "utf8"));
|
|
825
590
|
return {
|
|
826
|
-
id:
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
required_tests: requiredTests,
|
|
833
|
-
result_path: resultPath,
|
|
834
|
-
demand: deriveLaneDemand({
|
|
835
|
-
tokenEstimate: block.token_estimate ?? 0,
|
|
836
|
-
fileCount: allowedFiles.length,
|
|
837
|
-
riskScore: blockRiskScore(state, block),
|
|
838
|
-
}),
|
|
839
|
-
token_estimate: block.token_estimate ?? 0,
|
|
591
|
+
id: unit.id, source_finding_ids: [...unit.source_finding_ids],
|
|
592
|
+
allowed_files: [...unit.allowed_files], baseline_commit: baselineCommit,
|
|
593
|
+
obligation_ids: obligationIds, prompt: { text: prompt.text, sha256: prompt.sha256 },
|
|
594
|
+
required_tests: [...unit.required_tests], result_path: resultPath,
|
|
595
|
+
demand: deriveLaneDemand({ tokenEstimate, fileCount: unit.allowed_files.length, riskScore: blockRiskScore(state, unit) }),
|
|
596
|
+
token_estimate: tokenEstimate,
|
|
840
597
|
};
|
|
841
598
|
}
|
|
842
599
|
function buildCanonicalWorkload(params) {
|
|
@@ -844,12 +601,12 @@ function buildCanonicalWorkload(params) {
|
|
|
844
601
|
? new Set(params.workItemIds)
|
|
845
602
|
: null;
|
|
846
603
|
const sourceBlocks = requestedIds
|
|
847
|
-
? params.state.plan.
|
|
604
|
+
? params.state.plan.units.filter((block) => requestedIds.has(block.id))
|
|
848
605
|
: hostDependencyLevels(params.state)[0] ?? [];
|
|
849
|
-
const blocks = [...sourceBlocks].sort((left, right) => compareCodeUnits(left.
|
|
606
|
+
const blocks = [...sourceBlocks].sort((left, right) => compareCodeUnits(left.id, right.id));
|
|
850
607
|
if (requestedIds &&
|
|
851
608
|
(blocks.length !== requestedIds.size ||
|
|
852
|
-
blocks.some((block) => !requestedIds.has(block.
|
|
609
|
+
blocks.some((block) => !requestedIds.has(block.id)))) {
|
|
853
610
|
throw new Error("Trusted remediation host workload references an unknown block");
|
|
854
611
|
}
|
|
855
612
|
return {
|
|
@@ -864,7 +621,7 @@ function parseWorkItem(value, paths, runId, state, expectedBaselineCommit) {
|
|
|
864
621
|
"allowed_files",
|
|
865
622
|
"baseline_commit",
|
|
866
623
|
"demand",
|
|
867
|
-
"
|
|
624
|
+
"source_finding_ids",
|
|
868
625
|
"id",
|
|
869
626
|
"obligation_ids",
|
|
870
627
|
"prompt",
|
|
@@ -875,8 +632,8 @@ function parseWorkItem(value, paths, runId, state, expectedBaselineCommit) {
|
|
|
875
632
|
typeof value.id !== "string" ||
|
|
876
633
|
!LaneDemandSchema.safeParse(value.demand).success ||
|
|
877
634
|
!isCommit(value.baseline_commit) ||
|
|
878
|
-
!Array.isArray(value.
|
|
879
|
-
!value.
|
|
635
|
+
!Array.isArray(value.source_finding_ids) ||
|
|
636
|
+
!value.source_finding_ids.every((entry) => typeof entry === "string") ||
|
|
880
637
|
!Array.isArray(value.obligation_ids) ||
|
|
881
638
|
!value.obligation_ids.every((entry) => typeof entry === "string") ||
|
|
882
639
|
!Array.isArray(value.allowed_files) ||
|
|
@@ -892,7 +649,7 @@ function parseWorkItem(value, paths, runId, state, expectedBaselineCommit) {
|
|
|
892
649
|
!isSha256(value.prompt.sha256)) {
|
|
893
650
|
return null;
|
|
894
651
|
}
|
|
895
|
-
const block = state.plan.
|
|
652
|
+
const block = state.plan.units.find((candidate) => candidate.id === value.id);
|
|
896
653
|
if (!block)
|
|
897
654
|
return null;
|
|
898
655
|
let expected;
|
|
@@ -1184,7 +941,7 @@ function unresolvedFrontierWorkItemIds(state, record) {
|
|
|
1184
941
|
const items = state.items;
|
|
1185
942
|
const pendingBlockIds = new Set(Object.values(items)
|
|
1186
943
|
.filter((item) => item?.status === "pending")
|
|
1187
|
-
.map((item) => item.
|
|
944
|
+
.map((item) => item.unit_id));
|
|
1188
945
|
return [...record.work_item_ids]
|
|
1189
946
|
.filter((id) => pendingBlockIds.has(id))
|
|
1190
947
|
.sort(compareCodeUnits);
|
|
@@ -1205,6 +962,7 @@ export async function precomputeRecoveryTestVerdicts(params) {
|
|
|
1205
962
|
if (!state)
|
|
1206
963
|
return "unsupported_retired_state";
|
|
1207
964
|
const paths = resolveBoundaryPaths(params);
|
|
965
|
+
await assertApprovedRuntimePlan(paths.artifactsDir, state);
|
|
1208
966
|
const verdicts = new MintedRequiredTestVerdicts();
|
|
1209
967
|
const workloadRead = await readSubmissionDocument(paths.workloadPath);
|
|
1210
968
|
if (workloadRead.kind !== "value")
|
|
@@ -1214,7 +972,7 @@ export async function precomputeRecoveryTestVerdicts(params) {
|
|
|
1214
972
|
return verdicts;
|
|
1215
973
|
const commands = [];
|
|
1216
974
|
for (const workItem of workload.work_items) {
|
|
1217
|
-
const hasPending =
|
|
975
|
+
const hasPending = state.items[workItem.id]?.status === "pending";
|
|
1218
976
|
if (!hasPending)
|
|
1219
977
|
continue;
|
|
1220
978
|
const absoluteResultPath = resolveContainedPath(paths.root, workItem.result_path, `result path for ${workItem.id}`);
|
|
@@ -1262,11 +1020,21 @@ export async function prepareRemediationHostHandoff(params) {
|
|
|
1262
1020
|
const state = parseCurrentState(params.state);
|
|
1263
1021
|
if (!state)
|
|
1264
1022
|
return "unsupported_retired_state";
|
|
1023
|
+
const paths = resolveBoundaryPaths(params);
|
|
1024
|
+
const approved = await assertApprovedRuntimePlan(paths.artifactsDir, state);
|
|
1265
1025
|
if (!isCommit(params.baselineCommit)) {
|
|
1266
1026
|
throw new Error("Remediation host baselineCommit must be a full commit id");
|
|
1267
1027
|
}
|
|
1268
|
-
const paths = resolveBoundaryPaths(params);
|
|
1269
1028
|
const existingRecord = state.host_handoff;
|
|
1029
|
+
if (!existingRecord) {
|
|
1030
|
+
const accepted = state.plan.units.flatMap(unit => {
|
|
1031
|
+
const item = state.items[unit.id];
|
|
1032
|
+
return item?.host_landed_commit ? [{ allowed_files: [...unit.allowed_files], landed_commit: item.host_landed_commit }] : [];
|
|
1033
|
+
});
|
|
1034
|
+
const contextIssues = await executionPlanContextIssues(paths.root, approved.canonical, accepted);
|
|
1035
|
+
if (contextIssues.length)
|
|
1036
|
+
throw new RemediationHostPreparationError("plan_repair_required", contextIssues.join("; "));
|
|
1037
|
+
}
|
|
1270
1038
|
if (existingRecord && existingRecord.run_id !== params.runId) {
|
|
1271
1039
|
throw new Error("Trusted remediation host handoff belongs to another run");
|
|
1272
1040
|
}
|
|
@@ -1277,6 +1045,9 @@ export async function prepareRemediationHostHandoff(params) {
|
|
|
1277
1045
|
}
|
|
1278
1046
|
}
|
|
1279
1047
|
const baselineCommit = existingRecord?.baseline_commit ?? params.baselineCommit;
|
|
1048
|
+
const planIssues = planBlockIssues(paths.root, state);
|
|
1049
|
+
if (planIssues.length)
|
|
1050
|
+
throw new RemediationHostPreparationError("plan_repair_required", planIssues.map(issue => issue.message).join("; "));
|
|
1280
1051
|
let workload;
|
|
1281
1052
|
try {
|
|
1282
1053
|
workload = buildCanonicalWorkload({
|
|
@@ -1356,6 +1127,7 @@ export async function prepareRemediationHostHandoff(params) {
|
|
|
1356
1127
|
work_item_ids: workload.work_items.map((item) => item.id),
|
|
1357
1128
|
};
|
|
1358
1129
|
await mkdir(paths.resultDir, { recursive: true });
|
|
1130
|
+
await assertApprovedRuntimePlan(paths.artifactsDir, state);
|
|
1359
1131
|
await recordHostRootLogBoundary({ ...paths, runId: params.runId, phase: "prepare" });
|
|
1360
1132
|
await writeJsonFile(paths.workloadPath, workload);
|
|
1361
1133
|
return {
|
|
@@ -1411,6 +1183,8 @@ export async function ingestRemediationHostResults(params) {
|
|
|
1411
1183
|
const state = parseCurrentState(params.state);
|
|
1412
1184
|
if (!state)
|
|
1413
1185
|
return "unsupported_retired_state";
|
|
1186
|
+
const paths = resolveBoundaryPaths(params);
|
|
1187
|
+
await assertApprovedRuntimePlan(paths.artifactsDir, state);
|
|
1414
1188
|
// The verdict table is the ONE input whose validity the type system cannot
|
|
1415
1189
|
// check: a hand-built map of all-green verdicts asserts tests ran that never
|
|
1416
1190
|
// did. Refuse it up front — before any ledger append, any git probe, and any
|
|
@@ -1421,7 +1195,6 @@ export async function ingestRemediationHostResults(params) {
|
|
|
1421
1195
|
throw new Error("recovery.requiredTestVerdicts must come from precomputeRecoveryTestVerdicts: " +
|
|
1422
1196
|
"a caller-supplied verdict table asserts required tests ran that no runner produced");
|
|
1423
1197
|
}
|
|
1424
|
-
const paths = resolveBoundaryPaths(params);
|
|
1425
1198
|
if (state.conformance_review && state.conformance_review.run_id !== params.runId) {
|
|
1426
1199
|
throw new Error("Conformance review policy belongs to another run; refusing result acceptance.");
|
|
1427
1200
|
}
|
|
@@ -1456,6 +1229,9 @@ export async function ingestRemediationHostResults(params) {
|
|
|
1456
1229
|
recordedRecoveryMarks: null,
|
|
1457
1230
|
};
|
|
1458
1231
|
const verdicts = await executeHostVerificationReruns(validated.ctx, acc);
|
|
1232
|
+
// Tests and independent review involve awaits. A superseding plan/source
|
|
1233
|
+
// invalidates the entire acceptance before any accepted ledger event is minted.
|
|
1234
|
+
await assertApprovedRuntimePlan(paths.artifactsDir, state);
|
|
1459
1235
|
const issues = await recordAndEnrichHostIssues(params.artifactsDir, params.runId, acc.issues, acc.completed);
|
|
1460
1236
|
const summary = await commitRemediationStateUpdates(validated.ctx, acc, verdicts, issues);
|
|
1461
1237
|
await recordHostRootLogBoundary({ ...paths, runId: params.runId, phase: "ingest" });
|
|
@@ -1602,8 +1378,8 @@ async function validateHostResultBundle(input) {
|
|
|
1602
1378
|
recovery: input.recovery !== undefined,
|
|
1603
1379
|
state,
|
|
1604
1380
|
nextState,
|
|
1605
|
-
effectiveWorkload:
|
|
1606
|
-
eligibleIds: new Set((hostDependencyLevels(state)[0] ?? []).map((block) => block.
|
|
1381
|
+
effectiveWorkload: workload,
|
|
1382
|
+
eligibleIds: new Set((hostDependencyLevels(state)[0] ?? []).map((block) => block.id)),
|
|
1607
1383
|
// Can this ingest be corroborated against ground truth AT ALL? A git root
|
|
1608
1384
|
// supplies the tree; a persisted `host_handoff` supplies the trusted
|
|
1609
1385
|
// binding. With NEITHER there is nothing to check a host's claim against,
|
|
@@ -1640,7 +1416,7 @@ async function validateHostResultBundle(input) {
|
|
|
1640
1416
|
* the result from scratch.
|
|
1641
1417
|
*/
|
|
1642
1418
|
function hasLandedCommitFor(state, workItem) {
|
|
1643
|
-
return
|
|
1419
|
+
return typeof state.items[workItem.id]?.host_landed_commit === "string";
|
|
1644
1420
|
}
|
|
1645
1421
|
async function requiredConformanceReview(ctx, workItem, result) {
|
|
1646
1422
|
if (!ctx.state.conformance_review?.enabled)
|
|
@@ -1648,14 +1424,17 @@ async function requiredConformanceReview(ctx, workItem, result) {
|
|
|
1648
1424
|
return checkContractConformance({
|
|
1649
1425
|
root: ctx.paths.root, artifactsDir: ctx.paths.artifactsDir, runId: ctx.runId,
|
|
1650
1426
|
item: workItem, result,
|
|
1651
|
-
|
|
1427
|
+
requirements: ctx.state.plan.requirements.filter(requirement => workItem.obligation_ids.includes(requirement.id)),
|
|
1428
|
+
unit: ctx.state.plan.units.find(unit => unit.id === workItem.id),
|
|
1429
|
+
revision: ctx.state.plan.review_revision_sha256,
|
|
1430
|
+
counterexamples: (ctx.state.plan.review_counterexamples ?? []).filter(example => ctx.state.plan.units.find(unit => unit.id === workItem.id).addresses_counterexample_ids.includes(example.id)),
|
|
1652
1431
|
});
|
|
1653
1432
|
}
|
|
1654
1433
|
async function executeHostVerificationReruns(ctx, acc) {
|
|
1655
1434
|
const { paths, nextState, state } = ctx;
|
|
1656
1435
|
const verdicts = [];
|
|
1657
1436
|
for (const workItem of ctx.effectiveWorkload.work_items) {
|
|
1658
|
-
const pendingItems = workItem.
|
|
1437
|
+
const pendingItems = [workItem.id].filter((findingId) => nextState.items[findingId]?.status === "pending" &&
|
|
1659
1438
|
!acc.settledFindingIds.has(findingId));
|
|
1660
1439
|
if (pendingItems.length === 0)
|
|
1661
1440
|
continue;
|
|
@@ -1942,11 +1721,10 @@ function commitRemediationStateUpdates(ctx, acc, verdicts, issues) {
|
|
|
1942
1721
|
nextState.applied_edit_surface = [...acc.landedFiles].sort(compareCodeUnits);
|
|
1943
1722
|
}
|
|
1944
1723
|
const pendingWorkItemIds = ctx.effectiveWorkload.work_items
|
|
1945
|
-
.filter((workItem) => workItem.
|
|
1724
|
+
.filter((workItem) => [workItem.id].some((findingId) => nextState.items[findingId]?.status === "pending"))
|
|
1946
1725
|
.map((workItem) => workItem.id);
|
|
1947
1726
|
let stateChanged = acc.completed.length > 0;
|
|
1948
1727
|
if (nextState.host_handoff && pendingWorkItemIds.length === 0) {
|
|
1949
|
-
migrateLegacyDirectoryScopesAfterFinalDrain(nextState);
|
|
1950
1728
|
delete nextState.host_handoff;
|
|
1951
1729
|
stateChanged = true;
|
|
1952
1730
|
}
|