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
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { assertApprovedRuntimePlan, RemediationPlanAuthorityError } from "../contractPipeline/runtimePlanAuthority.js";
|
|
2
|
+
import { executionPlanContextIssues } from "../contractPipeline/executionPlan.js";
|
|
3
|
+
import { contentSha256 } from "../../shared/submission/hostHandoffCore.js";
|
|
1
4
|
import { AcceptedConformanceReviewSchema, ContractReviewOutcomeSchema } from "../../shared/types/reviewIndependence.js";
|
|
2
5
|
import { readContractReviewOutcomes } from "./closeReviewProvenance.js";
|
|
3
6
|
import { dirname, extname, isAbsolute, join, relative } from "node:path";
|
|
4
7
|
import { readFileSync, existsSync } from "node:fs";
|
|
5
|
-
import { AGENT_FEEDBACK_FILENAME, normalizeRepoPath, parseReflectionsNdjson, readOptionalJsonFile, readOptionalTextFile, renderProcessFeedbackSection, reportDiscardedReflections, stagedAndUntracked, writeJsonFile, writeTextFile, RemediationOutcomeStatusSchema, countBy, commandLeavesDeclaredShape, parseCommandString, runTrackedAsync, compareCodeUnits, runAdmittedProjectTestCommand, runAdmittedProjectE2eCommand, readSubmissionLedger, } from "audit-tools/shared";
|
|
8
|
+
import { AGENT_FEEDBACK_FILENAME, normalizeRepoPath, parseReflectionsNdjson, readOptionalJsonFile, readOptionalTextFile, renderProcessFeedbackSection, reportDiscardedReflections, stagedAndUntracked, writeJsonFile, writeTextFile, RemediationOutcomeStatusSchema, REMEDIATION_OUTCOMES_CONTRACT_VERSION, countBy, commandLeavesDeclaredShape, parseCommandString, runTrackedAsync, compareCodeUnits, runAdmittedProjectTestCommand, runAdmittedProjectE2eCommand, readSubmissionLedger, } from "audit-tools/shared";
|
|
6
9
|
import { CONTRACT_PIPELINE_VERIFICATION_REPORT_VERSION } from "audit-tools/shared";
|
|
7
10
|
import { FAILURE_OUTPUT_TAIL_CHARS } from "./constants.js";
|
|
8
11
|
import { verifyAnalyzerLeads } from "./closeVerifyAnalyzerLeads.js";
|
|
@@ -21,6 +24,7 @@ import { ABSENT_FINAL_GATE_REPORT, FinalGateReportSchema, NO_RECOVERY, carriesGa
|
|
|
21
24
|
// cycle — and the alternative, a second `"final-gate-outcome.json"` literal
|
|
22
25
|
// here, is exactly the drift the layout registry exists to prevent.
|
|
23
26
|
import { finalGateOutcomePath } from "../steps/finalGate.js";
|
|
27
|
+
import { runCloseAcceptance } from "./closeAcceptance.js";
|
|
24
28
|
// Derived from the single source so the key list can never drift from the
|
|
25
29
|
// RemediationOutcomeStatus contract (A6).
|
|
26
30
|
const OUTCOME_KEYS = [
|
|
@@ -42,6 +46,8 @@ const FINAL_STATUS_BY_OUTCOME = {
|
|
|
42
46
|
inappropriate: "skipped",
|
|
43
47
|
ignored: "ignored",
|
|
44
48
|
blocked: "failed",
|
|
49
|
+
pending: "pending",
|
|
50
|
+
deferred: "deferred",
|
|
45
51
|
verified_already_fixed: "fixed",
|
|
46
52
|
refuted: "skipped",
|
|
47
53
|
};
|
|
@@ -223,26 +229,111 @@ finalGate = ABSENT_FINAL_GATE_REPORT,
|
|
|
223
229
|
// empty set — never an omitted key, which a reader could not tell from a
|
|
224
230
|
// release that did not record recovery at all.
|
|
225
231
|
recovery = NO_RECOVERY, contractReviews = []) {
|
|
226
|
-
const findingsById = new Map((state.plan?.findings ?? []).map((finding) => [finding.id, finding]));
|
|
227
|
-
const blocksById = new Map((state.plan?.blocks ?? []).map((block) => [block.block_id, block]));
|
|
228
232
|
const outcomes = [];
|
|
229
233
|
const closeReason = closingStatusReason(closingResult);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
234
|
+
const executionOutcomes = (state.plan?.units ?? []).map(unit => {
|
|
235
|
+
const item = state.items?.[unit.id];
|
|
236
|
+
return {
|
|
237
|
+
unit_id: unit.id, title: unit.title, source_finding_ids: [...unit.source_finding_ids],
|
|
238
|
+
status: item?.status ?? "pending",
|
|
239
|
+
required_tests: [...unit.required_tests], evidence: [...(item?.host_result_evidence ?? [])],
|
|
240
|
+
rework_count: item?.rework_count ?? 0,
|
|
241
|
+
...(item?.host_landed_commit ? { landed_commit: item.host_landed_commit } : {}),
|
|
242
|
+
...(item?.host_landed_files ? { landed_files: [...item.host_landed_files] } : {}),
|
|
243
|
+
...(item?.failure_reason ? { reason: item.failure_reason } : !item ? { reason: "No execution state was recorded for this reviewed unit." } : !isVerifiedCompleteStatus(item.status) && !isSkipStatus(item.status) ? { reason: `Execution unit remains ${item.status}.` } : {}),
|
|
244
|
+
...(item?.conformance_review ? { conformance_review: AcceptedConformanceReviewSchema.parse(item.conformance_review) } : {}),
|
|
245
|
+
...(item?.started_at ? { started_at: item.started_at } : {}),
|
|
246
|
+
...(item?.completed_at ? { completed_at: item.completed_at } : {}),
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
let requestOutcome;
|
|
250
|
+
const requestDisposition = state.plan?.request_disposition;
|
|
251
|
+
if (state.plan?.request || requestDisposition) {
|
|
252
|
+
const units = state.plan?.units ?? [];
|
|
253
|
+
const items = units.map(unit => state.items?.[unit.id]);
|
|
254
|
+
const settled = items.length > 0 && items.every(item => item && (isVerifiedCompleteStatus(item.status) || isSkipStatus(item.status)));
|
|
255
|
+
const skipped = items.filter(item => item && isSkipStatus(item.status));
|
|
256
|
+
const status = requestDisposition?.status ??
|
|
257
|
+
(items.some(item => !item || isUnsuccessfulEndStatus(item.status)) ? "blocked" :
|
|
258
|
+
settled && skipped.length > 0 ? "ignored" : settled ? "resolved" : "pending");
|
|
259
|
+
requestOutcome = {
|
|
260
|
+
status,
|
|
261
|
+
reason: requestDisposition?.reason ?? (status === "ignored"
|
|
262
|
+
? skipped.map(item => item.failure_reason ?? "Owner declined this execution unit").join("; ")
|
|
263
|
+
: status === "resolved" ? "All reviewed execution units were verified."
|
|
264
|
+
: "The request still has unfinished execution work."),
|
|
265
|
+
evidence: requestDisposition?.evidence ?? executionOutcomes.flatMap(unit => unit.evidence),
|
|
266
|
+
unit_ids: units.map(unit => unit.id),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const sourceFindings = new Map((state.plan?.findings ?? []).map(finding => [finding.id, finding]));
|
|
270
|
+
for (const entry of state.plan_coverage?.entries ?? []) {
|
|
271
|
+
const original = sourceFindings.get(entry.finding_id);
|
|
272
|
+
if (entry.finding && original && contentSha256(entry.finding) !== contentSha256(original)) {
|
|
273
|
+
throw new Error(`Conflicting original source payload for ${entry.finding_id}; refusing an ambiguous outcome.`);
|
|
274
|
+
}
|
|
275
|
+
if (entry.finding && !original)
|
|
276
|
+
sourceFindings.set(entry.finding_id, entry.finding);
|
|
277
|
+
}
|
|
278
|
+
for (const finding of sourceFindings.values()) {
|
|
279
|
+
const units = (state.plan?.units ?? []).filter(unit => unit.source_finding_ids.includes(finding.id));
|
|
280
|
+
const linked = units.map(unit => state.items?.[unit.id]);
|
|
281
|
+
const coverage = state.plan_coverage?.entries.find(entry => entry.finding_id === finding.id);
|
|
282
|
+
const coverageDrop = coverage && DROP_REASON_BY_DISPOSITION[coverage.disposition];
|
|
283
|
+
const settledWithOwnerSkip = linked.length > 0 && linked.every(item => item && (isVerifiedCompleteStatus(item.status) || isSkipStatus(item.status))) && linked.some(item => item && isSkipStatus(item.status));
|
|
284
|
+
const unitOwnerDisposition = settledWithOwnerSkip ? {
|
|
285
|
+
status: linked.every(item => item?.status === "deemed_inappropriate") ? "declined" : "ignored",
|
|
286
|
+
reason: linked.filter(item => item && isSkipStatus(item.status)).map(item => item.failure_reason ?? "Owner declined this execution unit").join("; "),
|
|
287
|
+
} : undefined;
|
|
288
|
+
const ownerDisposition = state.finding_dispositions?.[finding.id] ?? unitOwnerDisposition ??
|
|
289
|
+
(coverageDrop ? { status: "ignored", reason: coverage.rationale ?? `Source was not scheduled: ${coverageDrop}` } : undefined);
|
|
290
|
+
const semanticDisposition = state.plan?.source_dispositions?.find(entry => entry.finding_id === finding.id);
|
|
291
|
+
const recorded = state.source_verifications?.[finding.id];
|
|
292
|
+
const verified = recorded?.review_revision_sha256 === state.plan?.review_revision_sha256 &&
|
|
293
|
+
recorded?.source_sha256 === contentSha256(finding) ? recorded : undefined;
|
|
294
|
+
const allVerified = linked.length > 0 && linked.every(item => item && isVerifiedCompleteStatus(item.status));
|
|
295
|
+
const starts = linked.flatMap(item => item?.started_at ? [item.started_at] : []).sort();
|
|
296
|
+
const ends = linked.flatMap(item => item?.completed_at ? [item.completed_at] : []).sort();
|
|
297
|
+
const hasBlocked = linked.some(item => !item || isUnsuccessfulEndStatus(item.status));
|
|
298
|
+
const sourceDeferred = semanticDisposition?.status === "deferred";
|
|
299
|
+
const sourcePending = !ownerDisposition && !semanticDisposition && units.length > 0 && !hasBlocked && !sourceDeferred && !allVerified;
|
|
300
|
+
const sharedStatus = linked.length > 0 && linked.every(item => item?.status === linked[0]?.status) ? linked[0]?.status : undefined;
|
|
301
|
+
const status = ownerDisposition ? ownerDisposition.status === "declined" ? "deemed_inappropriate" : "ignored"
|
|
302
|
+
: semanticDisposition?.status === "deferred" ? "blocked"
|
|
303
|
+
: semanticDisposition ? "resolved_no_change"
|
|
304
|
+
: allVerified ? linked.every(item => item?.status === "resolved_no_change") ? "resolved_no_change" : "resolved"
|
|
305
|
+
: sourcePending ? sharedStatus ?? "pending" : sharedStatus && isUnsuccessfulEndStatus(sharedStatus) ? sharedStatus : "blocked";
|
|
306
|
+
// A source aggregation is not an execution item. Evidence remains keyed by
|
|
307
|
+
// original source identity, so shared units cannot overwrite another source.
|
|
308
|
+
const item = {
|
|
309
|
+
status,
|
|
310
|
+
...verified,
|
|
311
|
+
disposition_override: ownerDisposition ? undefined : semanticDisposition?.status === "already_fixed" ? "verified_already_fixed"
|
|
312
|
+
: semanticDisposition?.status === "refuted" ? "refuted" : verified?.disposition_override,
|
|
313
|
+
failure_reason: ownerDisposition?.reason ?? semanticDisposition?.reason ??
|
|
314
|
+
(!allVerified ? units.length === 0 ? "No reviewed execution unit or source disposition covers this finding."
|
|
315
|
+
: "Not every required execution unit was verified: " + units.map((unit, i) => `${unit.id}=${linked[i]?.status ?? "missing"}${linked[i]?.failure_reason ? ` (${linked[i].failure_reason})` : ""}`).join(", ") : undefined),
|
|
316
|
+
rework_count: linked.reduce((sum, item) => sum + (item?.rework_count ?? 0), 0),
|
|
317
|
+
started_at: starts[0], completed_at: linked.length > 0 && ends.length === linked.length ? ends.at(-1) : undefined,
|
|
318
|
+
};
|
|
319
|
+
// Source verdicts retain pending/deferred separately from blocked. A
|
|
320
|
+
// successful source requires every linked unit verified, or an independently
|
|
321
|
+
// corroborated explicit source disposition; an empty link set never passes.
|
|
238
322
|
let outcome;
|
|
239
323
|
let originalState;
|
|
240
324
|
let evidence;
|
|
241
325
|
let recordedByModule;
|
|
242
326
|
let evidenceRefusalReason;
|
|
243
|
-
if (!
|
|
327
|
+
if (sourceDeferred && !ownerDisposition) {
|
|
328
|
+
outcome = "deferred";
|
|
329
|
+
}
|
|
330
|
+
else if (sourcePending) {
|
|
331
|
+
outcome = "pending";
|
|
332
|
+
originalState = sharedStatus;
|
|
333
|
+
}
|
|
334
|
+
else if (!isTerminalStatus(item.status)) {
|
|
244
335
|
outcome = "blocked";
|
|
245
|
-
originalState =
|
|
336
|
+
originalState = sharedStatus;
|
|
246
337
|
}
|
|
247
338
|
else {
|
|
248
339
|
const disposition = resolveDisposition(item.status, item.disposition_override);
|
|
@@ -284,7 +375,6 @@ recovery = NO_RECOVERY, contractReviews = []) {
|
|
|
284
375
|
}
|
|
285
376
|
}
|
|
286
377
|
}
|
|
287
|
-
const finding = findingsById.get(item.finding_id);
|
|
288
378
|
const fileExts = [
|
|
289
379
|
...new Set((finding?.affected_files ?? [])
|
|
290
380
|
.map((file) => extname(file.path).toLowerCase())
|
|
@@ -306,7 +396,7 @@ recovery = NO_RECOVERY, contractReviews = []) {
|
|
|
306
396
|
reason = DEFAULT_REASON_BY_OUTCOME[outcome];
|
|
307
397
|
}
|
|
308
398
|
const base = {
|
|
309
|
-
finding_id:
|
|
399
|
+
finding_id: finding.id,
|
|
310
400
|
lens: finding?.lens ?? "unknown",
|
|
311
401
|
file_exts: fileExts,
|
|
312
402
|
outcome,
|
|
@@ -322,22 +412,15 @@ recovery = NO_RECOVERY, contractReviews = []) {
|
|
|
322
412
|
: {}),
|
|
323
413
|
...(evidence ? { evidence } : {}),
|
|
324
414
|
...(recordedByModule ? { recorded_by_module: recordedByModule } : {}),
|
|
325
|
-
...((outcome === "resolved" || outcome === "verified_no_change") && item.conformance_review
|
|
326
|
-
? { conformance_review: AcceptedConformanceReviewSchema.parse(item.conformance_review) } : {}),
|
|
327
415
|
};
|
|
328
|
-
if (!finding) {
|
|
329
|
-
// Degenerate (corrupt state): without the plan finding there is no payload
|
|
330
|
-
// to carry — emit the lean per-finding outcome rather than inventing one.
|
|
331
|
-
outcomes.push(base);
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
416
|
const enriched = {
|
|
335
417
|
...base,
|
|
336
418
|
finding,
|
|
337
|
-
|
|
338
|
-
|
|
419
|
+
unit_ids: units.map(unit => unit.id),
|
|
420
|
+
unit_dependencies: [...new Set(units.flatMap(unit => unit.dependencies))],
|
|
421
|
+
unit_statuses: Object.fromEntries(units.map((unit, i) => [unit.id, linked[i]?.status ?? "missing"])),
|
|
339
422
|
final_status: FINAL_STATUS_BY_OUTCOME[outcome],
|
|
340
|
-
|
|
423
|
+
original_state: originalState,
|
|
341
424
|
};
|
|
342
425
|
outcomes.push(enriched);
|
|
343
426
|
}
|
|
@@ -387,7 +470,7 @@ recovery = NO_RECOVERY, contractReviews = []) {
|
|
|
387
470
|
? durationBetweenMs(aggregateStarted.value, aggregateCompleted.value)
|
|
388
471
|
: undefined;
|
|
389
472
|
return {
|
|
390
|
-
contract_version:
|
|
473
|
+
contract_version: REMEDIATION_OUTCOMES_CONTRACT_VERSION,
|
|
391
474
|
total: outcomes.length,
|
|
392
475
|
by_outcome: byOutcome,
|
|
393
476
|
by_lens: byLens,
|
|
@@ -398,6 +481,10 @@ recovery = NO_RECOVERY, contractReviews = []) {
|
|
|
398
481
|
recovery,
|
|
399
482
|
...(contractReviews.length > 0 ? { contract_reviews: contractReviews.map(review => ContractReviewOutcomeSchema.parse(review)) } : {}),
|
|
400
483
|
outcomes,
|
|
484
|
+
execution_outcomes: executionOutcomes,
|
|
485
|
+
...(requestDisposition ? { request_disposition: requestDisposition } : {}),
|
|
486
|
+
...(requestOutcome ? { request_outcome: requestOutcome } : {}),
|
|
487
|
+
...(state.plan ? { objective: state.plan.objective, ...(state.plan.request ? { request: state.plan.request } : {}) } : {}),
|
|
401
488
|
};
|
|
402
489
|
}
|
|
403
490
|
/** Drop-reason discriminator per never-planned coverage disposition. */
|
|
@@ -723,24 +810,14 @@ function repoPathExactKey(path) {
|
|
|
723
810
|
* Falls back to a generic message when there are no findings to summarize.
|
|
724
811
|
*/
|
|
725
812
|
function generateCommitMessage(state) {
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
const resolved = findings.filter((f) => resolvedFindingIds.has(f.id));
|
|
732
|
-
if (resolved.length === 0) {
|
|
813
|
+
const resolved = (state.plan?.units ?? []).filter(unit => {
|
|
814
|
+
const item = state.items?.[unit.id];
|
|
815
|
+
return item && isVerifiedCompleteStatus(item.status);
|
|
816
|
+
});
|
|
817
|
+
if (resolved.length === 0)
|
|
733
818
|
return "Remediation complete";
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
return `Fix: ${resolved[0].title ?? resolved[0].id}`;
|
|
737
|
-
}
|
|
738
|
-
const titles = resolved
|
|
739
|
-
.slice(0, 3)
|
|
740
|
-
.map((f) => f.title ?? f.id)
|
|
741
|
-
.join(", ");
|
|
742
|
-
const suffix = resolved.length > 3 ? ` (+${resolved.length - 3} more)` : "";
|
|
743
|
-
return `Fix: ${titles}${suffix}`;
|
|
819
|
+
const titles = resolved.slice(0, 3).map(unit => unit.title).join(", ");
|
|
820
|
+
return `Fix: ${titles}${resolved.length > 3 ? ` (+${resolved.length - 3} more)` : ""}`;
|
|
744
821
|
}
|
|
745
822
|
/**
|
|
746
823
|
* Actions that require user confirmation before executing. `custom` is not
|
|
@@ -764,11 +841,19 @@ async function checkClosingPreview(state, options) {
|
|
|
764
841
|
return undefined;
|
|
765
842
|
const { files, leftover } = await collectStagingFiles(options.root, resolveEditSurfaceManifest(state), toolDeliverablePaths(options));
|
|
766
843
|
const commitMessage = generateCommitMessage(state);
|
|
767
|
-
|
|
844
|
+
const preview = {
|
|
845
|
+
action: closingPlan.action,
|
|
846
|
+
...(closingPlan.custom_command ? { custom_command: closingPlan.custom_command } : {}),
|
|
768
847
|
files,
|
|
769
848
|
commit_message: commitMessage,
|
|
770
849
|
...(leftover.length > 0 ? { leftover_files: leftover } : {}),
|
|
771
850
|
};
|
|
851
|
+
if (options.finalizeClosing && closingPlan.closing_action_preview &&
|
|
852
|
+
JSON.stringify(preview) === JSON.stringify(closingPlan.closing_action_preview)) {
|
|
853
|
+
closingPlan.pre_authorized = true;
|
|
854
|
+
return undefined;
|
|
855
|
+
}
|
|
856
|
+
return preview;
|
|
772
857
|
}
|
|
773
858
|
/**
|
|
774
859
|
* Execute the run's closing action.
|
|
@@ -931,6 +1016,7 @@ export async function runCombinedTestSuite(state, options) {
|
|
|
931
1016
|
return {
|
|
932
1017
|
ran: true,
|
|
933
1018
|
passed,
|
|
1019
|
+
exit_code: admitted.exit_code,
|
|
934
1020
|
suite_name: suiteName,
|
|
935
1021
|
duration_ms: Date.now() - startedAt,
|
|
936
1022
|
output: passed
|
|
@@ -951,12 +1037,12 @@ export async function runCombinedTestSuite(state, options) {
|
|
|
951
1037
|
});
|
|
952
1038
|
const durationMs = Date.now() - startedAt;
|
|
953
1039
|
if (result.status === 0) {
|
|
954
|
-
return { ran: true, passed: true, suite_name: suiteName, duration_ms: durationMs, output: "" };
|
|
1040
|
+
return { ran: true, passed: true, exit_code: result.status, suite_name: suiteName, duration_ms: durationMs, output: "" };
|
|
955
1041
|
}
|
|
956
1042
|
const output = ((result.stdout?.toString() ?? "") + (result.stderr?.toString() ?? ""))
|
|
957
1043
|
.trim()
|
|
958
1044
|
.slice(-FAILURE_OUTPUT_TAIL_CHARS);
|
|
959
|
-
return { ran: true, passed: false, suite_name: suiteName, duration_ms: durationMs, output };
|
|
1045
|
+
return { ran: true, passed: false, exit_code: result.status, suite_name: suiteName, duration_ms: durationMs, output };
|
|
960
1046
|
}
|
|
961
1047
|
/**
|
|
962
1048
|
* Parse test output to extract implicated file paths. Looks for common test
|
|
@@ -1041,12 +1127,12 @@ export function blockResolvedItemsOnCombinedFailure(state, testOutput) {
|
|
|
1041
1127
|
return false;
|
|
1042
1128
|
const implicatedPaths = extractImplicatedPaths(testOutput);
|
|
1043
1129
|
const now = new Date().toISOString();
|
|
1044
|
-
const
|
|
1130
|
+
const touchedFilesByUnit = new Map((state.plan?.units ?? []).map((unit) => [unit.id, unit.allowed_files]));
|
|
1045
1131
|
// Attempt attribution: find items whose block touched an implicated path.
|
|
1046
1132
|
let attributed = [];
|
|
1047
1133
|
if (implicatedPaths.length > 0) {
|
|
1048
1134
|
for (const item of resolvedItems) {
|
|
1049
|
-
const touchedFiles =
|
|
1135
|
+
const touchedFiles = touchedFilesByUnit.get(item.unit_id) ?? [];
|
|
1050
1136
|
const overlaps = touchedFiles.some((tf) => implicatedPaths.some((ip) => touchedPathMatchesImplicated(tf, ip)));
|
|
1051
1137
|
if (overlaps)
|
|
1052
1138
|
attributed.push(item);
|
|
@@ -1137,10 +1223,10 @@ function collectReportEntries(state, options) {
|
|
|
1137
1223
|
};
|
|
1138
1224
|
for (const item of Object.values(state.items ?? {})) {
|
|
1139
1225
|
if (isVerifiedCompleteStatus(item.status)) {
|
|
1140
|
-
const
|
|
1141
|
-
const title =
|
|
1226
|
+
const unit = state.plan?.units.find((u) => u.id === item.unit_id);
|
|
1227
|
+
const title = unit?.title ?? item.unit_id;
|
|
1142
1228
|
let verificationEvidence = item.host_result_evidence;
|
|
1143
|
-
const verificationResultPath = join(options.artifactsDir, `result_${item.
|
|
1229
|
+
const verificationResultPath = join(options.artifactsDir, `result_${item.unit_id}_verify_code_against_documentation.json`);
|
|
1144
1230
|
if (existsSync(verificationResultPath)) {
|
|
1145
1231
|
try {
|
|
1146
1232
|
const verRes = JSON.parse(readFileSync(verificationResultPath, "utf8"));
|
|
@@ -1153,7 +1239,7 @@ function collectReportEntries(state, options) {
|
|
|
1153
1239
|
}
|
|
1154
1240
|
}
|
|
1155
1241
|
const entry = {
|
|
1156
|
-
|
|
1242
|
+
unit_id: item.unit_id,
|
|
1157
1243
|
summary: title,
|
|
1158
1244
|
verification_evidence: verificationEvidence,
|
|
1159
1245
|
};
|
|
@@ -1166,19 +1252,19 @@ function collectReportEntries(state, options) {
|
|
|
1166
1252
|
}
|
|
1167
1253
|
else if (item.status === "deemed_inappropriate") {
|
|
1168
1254
|
entries.inappropriate.push({
|
|
1169
|
-
|
|
1255
|
+
unit_id: item.unit_id,
|
|
1170
1256
|
rationale: item.failure_reason ?? "Deemed inappropriate",
|
|
1171
1257
|
});
|
|
1172
1258
|
}
|
|
1173
1259
|
else if (item.status === "ignored") {
|
|
1174
1260
|
entries.ignored.push({
|
|
1175
|
-
|
|
1261
|
+
unit_id: item.unit_id,
|
|
1176
1262
|
rationale: item.failure_reason ?? "Ignored by user",
|
|
1177
1263
|
});
|
|
1178
1264
|
}
|
|
1179
1265
|
else if (item.status === "blocked") {
|
|
1180
1266
|
entries.blocked.push({
|
|
1181
|
-
|
|
1267
|
+
unit_id: item.unit_id,
|
|
1182
1268
|
rationale: item.failure_reason ?? "Blocked",
|
|
1183
1269
|
});
|
|
1184
1270
|
}
|
|
@@ -1189,15 +1275,32 @@ function collectReportEntries(state, options) {
|
|
|
1189
1275
|
* Render `remediation-report.md` from the partitioned entries, closing action,
|
|
1190
1276
|
* e2e result, and per-finding outcomes. Pure string builder (no I/O).
|
|
1191
1277
|
*/
|
|
1192
|
-
function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed, outcomesReport, combinedTest, reflections = [], landingGates = { commands: [], gates: [], passed: true }) {
|
|
1278
|
+
export function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed, outcomesReport, combinedTest, reflections = [], landingGates = { commands: [], gates: [], passed: true }) {
|
|
1193
1279
|
let reportContent = `# Remediation Report\n\n`;
|
|
1280
|
+
if (outcomesReport.request_outcome) {
|
|
1281
|
+
const request = outcomesReport.request_outcome;
|
|
1282
|
+
reportContent += `## Request outcome\n\n${request.status}: ${request.reason}\n`;
|
|
1283
|
+
for (const evidence of request.evidence)
|
|
1284
|
+
reportContent += `- ${evidence}\n`;
|
|
1285
|
+
reportContent += "\n";
|
|
1286
|
+
}
|
|
1287
|
+
const executionUnits = outcomesReport.execution_outcomes;
|
|
1288
|
+
const completedUnits = executionUnits.filter(unit => unit.status === "resolved" || unit.status === "resolved_no_change").length;
|
|
1289
|
+
const skippedUnits = executionUnits.filter(unit => unit.status === "ignored" || unit.status === "deemed_inappropriate").length;
|
|
1290
|
+
reportContent += `## Execution units\n\n${executionUnits.length} unit(s): ${completedUnits} verified complete, ${skippedUnits} skipped, ${executionUnits.length - completedUnits - skippedUnits} unfinished.\n\n`;
|
|
1291
|
+
for (const unit of outcomesReport.execution_outcomes ?? []) {
|
|
1292
|
+
reportContent += `- **${unit.unit_id}** ${unit.title}: ${unit.status}${unit.reason ? ` — ${unit.reason}` : ""}\n`;
|
|
1293
|
+
}
|
|
1294
|
+
if (!(outcomesReport.execution_outcomes ?? []).length)
|
|
1295
|
+
reportContent += "No execution units were required.\n";
|
|
1296
|
+
reportContent += "\n";
|
|
1194
1297
|
// Host results are accepted only after the claimed commit is mechanically
|
|
1195
1298
|
// corroborated as reachable from HEAD. A no-change/skip-only run has no
|
|
1196
1299
|
// changed commit to review.
|
|
1197
1300
|
if (entries.resolved.length > 0) {
|
|
1198
1301
|
reportContent += `## Review\n\nAll code changes were accepted through the provider-neutral host handoff and corroborated as landed commits reachable from the repository HEAD. Review the resulting diff and commit history.\n\n`;
|
|
1199
1302
|
}
|
|
1200
|
-
const resultReviews = outcomesReport.
|
|
1303
|
+
const resultReviews = outcomesReport.execution_outcomes.filter(outcome => outcome.conformance_review);
|
|
1201
1304
|
if (outcomesReport.contract_reviews?.length || resultReviews.length) {
|
|
1202
1305
|
reportContent += `## Declared Review Context\n\nThese are host-declared review contexts bound to accepted artifacts/results, not verified reviewer identities.\n\n`;
|
|
1203
1306
|
for (const review of outcomesReport.contract_reviews ?? []) {
|
|
@@ -1205,7 +1308,7 @@ function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed
|
|
|
1205
1308
|
}
|
|
1206
1309
|
for (const outcome of resultReviews) {
|
|
1207
1310
|
const review = outcome.conformance_review;
|
|
1208
|
-
reportContent += `- ${outcome.
|
|
1311
|
+
reportContent += `- ${outcome.unit_id} conformance: required independent; declared ${review.review.mode}. ${review.summary}\n`;
|
|
1209
1312
|
}
|
|
1210
1313
|
reportContent += "\n";
|
|
1211
1314
|
}
|
|
@@ -1215,7 +1318,7 @@ function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed
|
|
|
1215
1318
|
}
|
|
1216
1319
|
else {
|
|
1217
1320
|
for (const entry of entries.resolved) {
|
|
1218
|
-
reportContent += `- **${entry.
|
|
1321
|
+
reportContent += `- **${entry.unit_id}**: ${entry.summary}\n`;
|
|
1219
1322
|
if (entry.verification_evidence) {
|
|
1220
1323
|
for (const check of entry.verification_evidence) {
|
|
1221
1324
|
reportContent += ` - *Verification*: ${check}\n`;
|
|
@@ -1226,7 +1329,7 @@ function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed
|
|
|
1226
1329
|
if (entries.verifiedNoChange.length > 0) {
|
|
1227
1330
|
reportContent += `\n## Verified Already Correct (no changes made)\n\n`;
|
|
1228
1331
|
for (const entry of entries.verifiedNoChange) {
|
|
1229
|
-
reportContent += `- **${entry.
|
|
1332
|
+
reportContent += `- **${entry.unit_id}**: ${entry.summary}\n`;
|
|
1230
1333
|
if (entry.verification_evidence) {
|
|
1231
1334
|
for (const check of entry.verification_evidence) {
|
|
1232
1335
|
reportContent += ` - *Verification*: ${check}\n`;
|
|
@@ -1237,13 +1340,13 @@ function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed
|
|
|
1237
1340
|
if (entries.inappropriate.length > 0) {
|
|
1238
1341
|
reportContent += `\n## Deemed Inappropriate\n\n`;
|
|
1239
1342
|
for (const entry of entries.inappropriate) {
|
|
1240
|
-
reportContent += `- **${entry.
|
|
1343
|
+
reportContent += `- **${entry.unit_id}**: ${entry.rationale}\n`;
|
|
1241
1344
|
}
|
|
1242
1345
|
}
|
|
1243
1346
|
if (entries.ignored.length > 0) {
|
|
1244
1347
|
reportContent += `\n## Ignored\n\n`;
|
|
1245
1348
|
for (const entry of entries.ignored) {
|
|
1246
|
-
reportContent += `- **${entry.
|
|
1349
|
+
reportContent += `- **${entry.unit_id}**: ${entry.rationale}\n`;
|
|
1247
1350
|
}
|
|
1248
1351
|
}
|
|
1249
1352
|
const skippedByCheckpoint = (state.plan_coverage?.entries ?? []).filter((e) => e.disposition === "dropped_by_checkpoint");
|
|
@@ -1355,7 +1458,7 @@ function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed
|
|
|
1355
1458
|
}
|
|
1356
1459
|
const o = outcomesReport.by_outcome;
|
|
1357
1460
|
reportContent += `\n## Remediation Outcomes\n\n`;
|
|
1358
|
-
reportContent += `Of ${outcomesReport.total} finding(s): ${o.resolved} resolved, ${o.verified_no_change} verified already correct, ${o.inappropriate} deemed inappropriate, ${o.ignored} ignored, ${o.blocked} blocked.\n`;
|
|
1461
|
+
reportContent += `Of ${outcomesReport.total} finding(s): ${o.resolved} resolved, ${o.verified_no_change} verified already correct, ${o.inappropriate} deemed inappropriate, ${o.ignored} ignored, ${o.blocked} blocked, ${o.pending} pending, ${o.deferred} deferred.\n`;
|
|
1359
1462
|
const lensNames = Object.keys(outcomesReport.by_lens).sort();
|
|
1360
1463
|
if (lensNames.length > 0) {
|
|
1361
1464
|
reportContent += `\nBy lens:\n`;
|
|
@@ -1421,7 +1524,7 @@ function buildRemediationReportMarkdown(state, entries, closingResult, e2ePassed
|
|
|
1421
1524
|
* apply to — the same rule the combined-suite leg follows for a run with no
|
|
1422
1525
|
* configured suite.
|
|
1423
1526
|
*/
|
|
1424
|
-
export async function cleanupTempBranchesAndArtifacts(options, completeState, combinedTest, e2eResult, closingResult, runLogger, landingGates = { commands: [], gates: [], passed: true }) {
|
|
1527
|
+
export async function cleanupTempBranchesAndArtifacts(options, completeState, combinedTest, e2eResult, closingResult, runLogger, landingGates = { commands: [], gates: [], passed: true }, sourceOutcomes = buildRemediationOutcomesReport(completeState, closingResult)) {
|
|
1425
1528
|
// Write final state before deleting the artifacts directory so the completion
|
|
1426
1529
|
// is durable even if cleanup partially fails.
|
|
1427
1530
|
try {
|
|
@@ -1467,18 +1570,27 @@ export async function cleanupTempBranchesAndArtifacts(options, completeState, co
|
|
|
1467
1570
|
// classification (see closingActionCompleted): success, or the skipped
|
|
1468
1571
|
// action=none no-op — never a skipped non-none close.
|
|
1469
1572
|
const closingCompleted = closingActionCompleted(closingResult);
|
|
1573
|
+
const unresolvedSources = sourceOutcomes.outcomes.some(outcome => ["blocked", "pending", "deferred"].includes(outcome.outcome));
|
|
1574
|
+
const unresolvedRequest = sourceOutcomes.request_outcome && ["blocked", "pending", "deferred"].includes(sourceOutcomes.request_outcome.status);
|
|
1575
|
+
const unresolvedUnits = (completeState.plan?.units ?? []).some(unit => {
|
|
1576
|
+
const item = completeState.items?.[unit.id];
|
|
1577
|
+
return !item || (!isVerifiedCompleteStatus(item.status) && !isSkipStatus(item.status));
|
|
1578
|
+
});
|
|
1470
1579
|
const fullyGreen = combinedTest.passed &&
|
|
1471
1580
|
e2eResult.passed &&
|
|
1472
1581
|
landingGates.passed &&
|
|
1473
1582
|
closingCompleted &&
|
|
1474
|
-
!anyBlocked
|
|
1583
|
+
!anyBlocked &&
|
|
1584
|
+
!unresolvedSources &&
|
|
1585
|
+
!unresolvedRequest &&
|
|
1586
|
+
!unresolvedUnits;
|
|
1475
1587
|
if (!fullyGreen) {
|
|
1476
1588
|
runLogger?.event({
|
|
1477
1589
|
phase: "close",
|
|
1478
1590
|
kind: "artifact_write",
|
|
1479
1591
|
obligation: "closing",
|
|
1480
1592
|
artifact: options.artifactsDir,
|
|
1481
|
-
note: `Artifacts directory preserved for diagnosis (combinedTest.passed=${combinedTest.passed}, e2e.passed=${e2eResult.passed}, landingGates.passed=${landingGates.passed}, closing=${closingResult.status}, closingAction=${closingResult.action}, anyBlocked=${anyBlocked})`,
|
|
1593
|
+
note: `Artifacts directory preserved for diagnosis (combinedTest.passed=${combinedTest.passed}, e2e.passed=${e2eResult.passed}, landingGates.passed=${landingGates.passed}, closing=${closingResult.status}, closingAction=${closingResult.action}, anyBlocked=${anyBlocked}, unresolvedSources=${unresolvedSources}, unresolvedUnits=${unresolvedUnits})`,
|
|
1482
1594
|
});
|
|
1483
1595
|
return {};
|
|
1484
1596
|
}
|
|
@@ -1548,158 +1660,85 @@ export async function cleanupTempBranchesAndArtifacts(options, completeState, co
|
|
|
1548
1660
|
* items have at least one passing trace. "failed" otherwise.
|
|
1549
1661
|
*/
|
|
1550
1662
|
export function buildVerificationReport(state, options, closingResult, combinedTest) {
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
const
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
// get a single trace recording the user's settled decision and a
|
|
1562
|
-
// first-class overall_status of "skipped" (see FindingVerificationTrace
|
|
1563
|
-
// doc comment in src/shared/types/contractPipeline/verification.ts).
|
|
1564
|
-
// The trace's own `status` stays "failed" because it did not verify
|
|
1565
|
-
// anything (there is no passing evidence); the finding-level
|
|
1566
|
-
// "skipped" is what excludes it from the report-level verdict below.
|
|
1663
|
+
const units = (state.plan?.units ?? []).map(unit => {
|
|
1664
|
+
const item = state.items?.[unit.id];
|
|
1665
|
+
const passed = !!item && isVerifiedCompleteStatus(item.status) && combinedTest.passed;
|
|
1666
|
+
const skipped = !!item && isSkipStatus(item.status);
|
|
1667
|
+
const traces = [{
|
|
1668
|
+
trace_id: `${unit.id}:combined-tests`, kind: "task", label: combinedTest.suite_name ?? "combined test suite",
|
|
1669
|
+
evidence: [combinedTest.ran ? combinedTest.passed ? "Suite passed" : combinedTest.output : "No combined suite ran"],
|
|
1670
|
+
status: combinedTest.ran && combinedTest.passed ? "passed" : "failed",
|
|
1671
|
+
}];
|
|
1672
|
+
for (const requirementId of unit.requirement_ids)
|
|
1567
1673
|
traces.push({
|
|
1568
|
-
trace_id: `${
|
|
1569
|
-
|
|
1570
|
-
label: item.status === "ignored" ? "ignored by user" : "deemed inappropriate",
|
|
1571
|
-
evidence: [item.failure_reason ?? item.status],
|
|
1572
|
-
status: "failed",
|
|
1573
|
-
});
|
|
1574
|
-
findings.push({
|
|
1575
|
-
finding_id: item.finding_id,
|
|
1576
|
-
traces,
|
|
1577
|
-
overall_status: "skipped",
|
|
1674
|
+
trace_id: `${unit.id}:requirement:${requirementId}`, kind: "requirement", label: requirementId,
|
|
1675
|
+
evidence: [...(item?.host_result_evidence ?? [])], status: passed ? "passed" : "failed",
|
|
1578
1676
|
});
|
|
1579
|
-
|
|
1580
|
-
}
|
|
1581
|
-
// Combined test suite trace. A never-configured suite (`ran:false`) is
|
|
1582
|
-
// NEVER labelled "passed" here — `combinedTest.passed` stays `true` for
|
|
1583
|
-
// that case only so the pre-existing fullyGreen/itemPassed formulas below
|
|
1584
|
-
// keep their vacuously-green behavior; this trace's own evidence/status is
|
|
1585
|
-
// what tells a reader "nothing ran" apart from "it ran and passed"
|
|
1586
|
-
// (`status` stays the file's established "failed" for any non-affirmative
|
|
1587
|
-
// case — see the identical choice on the skipped-item trace above — the
|
|
1588
|
-
// finding-level verdict is driven by `itemPassed`, not by this one trace).
|
|
1589
|
-
const suiteLabel = combinedTest.suite_name ?? "combined test suite";
|
|
1590
|
-
traces.push({
|
|
1591
|
-
trace_id: `${item.finding_id}:combined-tests`,
|
|
1592
|
-
kind: "task",
|
|
1593
|
-
label: suiteLabel,
|
|
1594
|
-
evidence: !combinedTest.ran
|
|
1595
|
-
? [combinedTest.output || "no combined test suite configured for this run"]
|
|
1596
|
-
: combinedTest.passed
|
|
1597
|
-
? [`${suiteLabel} passed`]
|
|
1598
|
-
: [`${suiteLabel} failed`, ...(combinedTest.output ? [combinedTest.output.slice(-500)] : [])],
|
|
1599
|
-
status: combinedTest.ran && combinedTest.passed ? "passed" : "failed",
|
|
1600
|
-
});
|
|
1601
|
-
const contractGoalId = finding?.contract_goal_id ?? state.plan?.goal_id;
|
|
1602
|
-
if (contractGoalId) {
|
|
1677
|
+
for (const [i, command] of unit.required_tests.entries())
|
|
1603
1678
|
traces.push({
|
|
1604
|
-
trace_id: `${
|
|
1605
|
-
|
|
1606
|
-
label: "contract-pipeline goal",
|
|
1607
|
-
evidence: [`goal_id=${contractGoalId}`],
|
|
1608
|
-
status: itemPassed ? "passed" : "failed",
|
|
1679
|
+
trace_id: `${unit.id}:command:${i}`, kind: "command", label: command,
|
|
1680
|
+
evidence: [...(item?.host_result_evidence ?? [])], status: passed ? "passed" : "failed",
|
|
1609
1681
|
});
|
|
1610
|
-
}
|
|
1611
|
-
if (finding?.contract_obligation_ids?.length) {
|
|
1612
|
-
traces.push({
|
|
1613
|
-
trace_id: `${item.finding_id}:contract-obligations`,
|
|
1614
|
-
kind: "requirement",
|
|
1615
|
-
label: "contract-pipeline obligations satisfied by task",
|
|
1616
|
-
evidence: finding.contract_obligation_ids,
|
|
1617
|
-
status: itemPassed ? "passed" : "failed",
|
|
1618
|
-
});
|
|
1619
|
-
}
|
|
1620
|
-
if (finding?.verification_obligation_ids?.length) {
|
|
1621
|
-
traces.push({
|
|
1622
|
-
trace_id: `${item.finding_id}:verification-obligations`,
|
|
1623
|
-
kind: "invariant",
|
|
1624
|
-
label: "contract-pipeline verification obligations",
|
|
1625
|
-
evidence: finding.verification_obligation_ids,
|
|
1626
|
-
status: itemPassed ? "passed" : "failed",
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1629
|
-
for (const [index, command] of (finding?.targeted_commands ?? []).entries()) {
|
|
1630
|
-
traces.push({
|
|
1631
|
-
trace_id: `${item.finding_id}:targeted-command-${index + 1}`,
|
|
1632
|
-
kind: "command",
|
|
1633
|
-
label: "implementation DAG targeted command",
|
|
1634
|
-
evidence: [`planned command: ${command}`],
|
|
1635
|
-
status: itemPassed ? "passed" : "failed",
|
|
1636
|
-
});
|
|
1637
|
-
}
|
|
1638
|
-
// Verification result file evidence (verify_code_against_documentation).
|
|
1639
|
-
const verificationResultPath = join(options.artifactsDir, `result_${item.finding_id}_verify_code_against_documentation.json`);
|
|
1682
|
+
const verificationResultPath = join(options.artifactsDir, `result_${unit.id}_verify_code_against_documentation.json`);
|
|
1640
1683
|
if (existsSync(verificationResultPath)) {
|
|
1641
1684
|
try {
|
|
1642
|
-
const
|
|
1643
|
-
const evidence = Array.isArray(
|
|
1644
|
-
traces.push({
|
|
1645
|
-
trace_id: `${item.finding_id}:verify-doc`,
|
|
1646
|
-
kind: "file",
|
|
1647
|
-
label: `verify_code_against_documentation for ${item.finding_id}`,
|
|
1648
|
-
evidence,
|
|
1649
|
-
status: evidence.length > 0 ? "passed" : "failed",
|
|
1650
|
-
});
|
|
1651
|
-
}
|
|
1652
|
-
catch {
|
|
1653
|
-
// Non-fatal: evidence file malformed
|
|
1685
|
+
const result = JSON.parse(readFileSync(verificationResultPath, "utf8"));
|
|
1686
|
+
const evidence = Array.isArray(result.reason) ? result.reason.filter((v) => typeof v === "string") : [];
|
|
1687
|
+
traces.push({ trace_id: `${unit.id}:verify-doc`, kind: "file", label: "verify_code_against_documentation", evidence, status: evidence.length ? "passed" : "failed" });
|
|
1654
1688
|
}
|
|
1689
|
+
catch { /* malformed optional evidence cannot establish a passing trace */ }
|
|
1655
1690
|
}
|
|
1656
|
-
|
|
1657
|
-
// Status keys on the single-sourced completion classification: a skipped
|
|
1658
|
-
// NON-none closing action did not complete, so its trace is red — not
|
|
1659
|
-
// "passed" merely because it didn't literally report "failed"
|
|
1660
|
-
// (COR-fb656e3f-2).
|
|
1661
|
-
if (closingResult.action !== "none") {
|
|
1691
|
+
if (closingResult.action !== "none")
|
|
1662
1692
|
traces.push({
|
|
1663
|
-
trace_id: `${
|
|
1664
|
-
|
|
1665
|
-
label: `closing action: ${closingResult.action}`,
|
|
1666
|
-
evidence: [`status=${closingResult.status}`],
|
|
1667
|
-
status: closingActionCompleted(closingResult) ? "passed" : "failed",
|
|
1693
|
+
trace_id: `${unit.id}:closing`, kind: "command", label: `closing action: ${closingResult.action}`,
|
|
1694
|
+
evidence: [`status=${closingResult.status}`], status: closingActionCompleted(closingResult) ? "passed" : "failed",
|
|
1668
1695
|
});
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
// Derive goal_id from the plan if available.
|
|
1689
|
-
const goalId = state.plan?.goal_id;
|
|
1696
|
+
return { unit_id: unit.id, source_finding_ids: [...unit.source_finding_ids], traces,
|
|
1697
|
+
overall_status: skipped ? "skipped" : passed ? "passed" : "failed" };
|
|
1698
|
+
});
|
|
1699
|
+
const outcomeReport = buildRemediationOutcomesReport(state, closingResult);
|
|
1700
|
+
const findings = outcomeReport.outcomes.map(outcome => ({
|
|
1701
|
+
finding_id: outcome.finding_id,
|
|
1702
|
+
traces: [
|
|
1703
|
+
...units.filter(unit => unit.source_finding_ids.includes(outcome.finding_id)).flatMap(unit => unit.traces),
|
|
1704
|
+
...(outcome.evidence ? [{ trace_id: `${outcome.finding_id}:source-verification`, kind: "file",
|
|
1705
|
+
label: outcome.evidence.mechanism, evidence: [`${outcome.evidence.file}:${outcome.evidence.line}`, outcome.evidence.mechanism_detail ?? ""],
|
|
1706
|
+
status: outcome.outcome === "verified_already_fixed" || outcome.outcome === "refuted" ? "passed" : "failed" }] : []),
|
|
1707
|
+
...(outcome.reason ? [{ trace_id: `${outcome.finding_id}:source-disposition`, kind: "task", label: outcome.outcome, evidence: [outcome.reason], status: "failed" }] : []),
|
|
1708
|
+
],
|
|
1709
|
+
overall_status: outcome.outcome === "ignored" || outcome.outcome === "inappropriate" ? "skipped"
|
|
1710
|
+
: ["blocked", "pending", "deferred"].includes(outcome.outcome) ? "failed" : "passed",
|
|
1711
|
+
}));
|
|
1712
|
+
const requestUnfinished = outcomeReport.request_outcome && ["blocked", "pending", "deferred"].includes(outcomeReport.request_outcome.status);
|
|
1713
|
+
const overallPassed = !requestUnfinished && combinedTest.passed && closingActionCompleted(closingResult) &&
|
|
1714
|
+
units.every(unit => unit.overall_status !== "failed") && findings.every(finding => finding.overall_status !== "failed");
|
|
1690
1715
|
return {
|
|
1691
1716
|
contract_version: CONTRACT_PIPELINE_VERIFICATION_REPORT_VERSION,
|
|
1692
|
-
...(
|
|
1693
|
-
findings,
|
|
1717
|
+
...(state.plan?.goal_id ? { goal_id: state.plan.goal_id } : {}),
|
|
1718
|
+
findings, units,
|
|
1694
1719
|
overall_status: overallPassed ? "passed" : "failed",
|
|
1695
1720
|
created_at: new Date().toISOString(),
|
|
1696
1721
|
};
|
|
1697
1722
|
}
|
|
1723
|
+
// sites-pinned: tests/remediate/close-plan-authority.test.ts
|
|
1724
|
+
/** Closing observes reviewed context, allowing only changes explained by accepted landed work. */
|
|
1725
|
+
async function assertClosingPlanAuthority(state, options) {
|
|
1726
|
+
const approved = await assertApprovedRuntimePlan(options.artifactsDir, state);
|
|
1727
|
+
const accepted = approved.canonical.plan.units.flatMap(unit => {
|
|
1728
|
+
const item = state.items?.[unit.id];
|
|
1729
|
+
return item?.host_landed_commit ? [{ allowed_files: [...unit.allowed_files], landed_commit: item.host_landed_commit }] : [];
|
|
1730
|
+
});
|
|
1731
|
+
const issues = await executionPlanContextIssues(options.root, approved.canonical, accepted);
|
|
1732
|
+
if (issues.length)
|
|
1733
|
+
throw new RemediationPlanAuthorityError(issues.join("; "));
|
|
1734
|
+
}
|
|
1698
1735
|
export async function runClosePhase(state, options, runLogger) {
|
|
1699
1736
|
console.log("Running Close Phase...");
|
|
1700
1737
|
if (!state.plan || !state.items || !state.closing_plan) {
|
|
1701
1738
|
throw new Error("Cannot run close phase: missing plan, items, or closing_plan from state.");
|
|
1702
1739
|
}
|
|
1740
|
+
// Check before preview, verification, state mutation, action execution or promotion.
|
|
1741
|
+
await assertClosingPlanAuthority(state, options);
|
|
1703
1742
|
// CDC-19 (advisory): a planned finding with no corresponding item in
|
|
1704
1743
|
// state.items would be left uncounted by every module's INV-COVERAGE join
|
|
1705
1744
|
// — a module that was blocked or never dispatched must not silently vanish
|
|
@@ -1707,7 +1746,7 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1707
1746
|
// runLogger is actually wired, so it changes nothing for a caller that
|
|
1708
1747
|
// doesn't ask for it.
|
|
1709
1748
|
{
|
|
1710
|
-
const findingIds = new Set((state.plan.
|
|
1749
|
+
const findingIds = new Set((state.plan.units ?? []).map((unit) => unit.id));
|
|
1711
1750
|
const itemIds = new Set(Object.keys(state.items));
|
|
1712
1751
|
const uncounted = [...findingIds].filter((id) => !itemIds.has(id));
|
|
1713
1752
|
if (uncounted.length > 0) {
|
|
@@ -1715,7 +1754,7 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1715
1754
|
phase: "close",
|
|
1716
1755
|
kind: "error",
|
|
1717
1756
|
obligation: "closing",
|
|
1718
|
-
note: `${uncounted.length} planned
|
|
1757
|
+
note: `${uncounted.length} planned execution unit(s) have no corresponding item in state.items and would be left uncounted by every module's coverage join: ${uncounted.slice(0, 10).join(", ")}`,
|
|
1719
1758
|
});
|
|
1720
1759
|
}
|
|
1721
1760
|
}
|
|
@@ -1735,8 +1774,17 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1735
1774
|
const updatedClosingPlan = { ...state.closing_plan, closing_action_preview: preview };
|
|
1736
1775
|
return { ...state, closing_plan: updatedClosingPlan };
|
|
1737
1776
|
}
|
|
1738
|
-
// 2.
|
|
1739
|
-
|
|
1777
|
+
// 2. Acceptance begins only after preview/host pauses. The floor owns its
|
|
1778
|
+
// failure: stop before the combined-suite triage branch can re-block items.
|
|
1779
|
+
const acceptance = await runCloseAcceptance({
|
|
1780
|
+
state, options, runLogger,
|
|
1781
|
+
runCombined: () => runCombinedTestSuite(state, options),
|
|
1782
|
+
});
|
|
1783
|
+
if (acceptance.gate && !acceptance.gate.passed) {
|
|
1784
|
+
await options.onFinalGateRed?.(acceptance.gate);
|
|
1785
|
+
return state;
|
|
1786
|
+
}
|
|
1787
|
+
const combinedTest = acceptance.combinedTest ?? await runCombinedTestSuite(state, options);
|
|
1740
1788
|
if (!combinedTest.passed) {
|
|
1741
1789
|
console.log("Full test suite failed. Transitioning back to triage.");
|
|
1742
1790
|
if (blockResolvedItemsOnCombinedFailure(state, combinedTest.output)) {
|
|
@@ -1765,17 +1813,21 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1765
1813
|
if (analyzerVerify.ran) {
|
|
1766
1814
|
const now = new Date().toISOString();
|
|
1767
1815
|
for (const [findingId, verdict] of Object.entries(analyzerVerify.verdicts)) {
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1816
|
+
state.source_verifications ??= {};
|
|
1817
|
+
const source = state.plan.findings.find(finding => finding.id === findingId);
|
|
1818
|
+
state.source_verifications[findingId] = {
|
|
1819
|
+
...state.source_verifications[findingId], mechanical_verification: verdict,
|
|
1820
|
+
review_revision_sha256: state.plan.review_revision_sha256, source_sha256: contentSha256(source),
|
|
1821
|
+
};
|
|
1772
1822
|
if (verdict.status === "lead_persists") {
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1823
|
+
for (const unit of state.plan.units.filter(unit => unit.source_finding_ids.includes(findingId))) {
|
|
1824
|
+
const item = state.items[unit.id];
|
|
1825
|
+
if (!item || !isVerifiedCompleteStatus(item.status))
|
|
1826
|
+
continue;
|
|
1827
|
+
item.status = "blocked";
|
|
1828
|
+
item.completed_at = now;
|
|
1829
|
+
item.failure_reason = `Mechanical re-verify: analyzer '${verdict.analyzer_id}' still reports source ${findingId}. Rework the linked execution unit.`;
|
|
1830
|
+
}
|
|
1779
1831
|
}
|
|
1780
1832
|
}
|
|
1781
1833
|
if (analyzerVerify.persisting.length > 0) {
|
|
@@ -1870,6 +1922,12 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1870
1922
|
}
|
|
1871
1923
|
}
|
|
1872
1924
|
}
|
|
1925
|
+
// Verification may await arbitrary repository commands. Revalidate the same
|
|
1926
|
+
// current authority immediately before the consequential closing boundary.
|
|
1927
|
+
// Once the authorized action runs, its real outcome is persisted and reported;
|
|
1928
|
+
// expected publish/version effects do not retroactively revoke that operation.
|
|
1929
|
+
const contractReviews = await readContractReviewOutcomes(options.artifactsDir);
|
|
1930
|
+
await assertClosingPlanAuthority(state, options);
|
|
1873
1931
|
// 4. Execute the closing action and record exact command outcomes before
|
|
1874
1932
|
// reporting success.
|
|
1875
1933
|
console.log(`Executing closing action: ${state.closing_plan.action}`);
|
|
@@ -1889,8 +1947,14 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1889
1947
|
// set: the alternative makes "the ledger was unreadable" report as "this run
|
|
1890
1948
|
// was clean", which is the collapse the ledger exists to prevent.
|
|
1891
1949
|
const recovery = await readRunRecoveryFacts(options.artifactsDir, state);
|
|
1950
|
+
// Hydrate original coverage-only sources before ANY outcome or verification
|
|
1951
|
+
// projection. Reading them after building outcomes silently loses excluded
|
|
1952
|
+
// originals from the otherwise self-contained source report.
|
|
1953
|
+
const outcomeCoverage = await buildOutcomeCoverageLedger(state, options);
|
|
1954
|
+
if (outcomeCoverage)
|
|
1955
|
+
state.plan_coverage = outcomeCoverage;
|
|
1892
1956
|
const finalGate = await readFinalGateReport(options.artifactsDir);
|
|
1893
|
-
const outcomesReport = buildRemediationOutcomesReport(state, closingResult, finalGate, recovery,
|
|
1957
|
+
const outcomesReport = buildRemediationOutcomesReport(state, closingResult, finalGate, recovery, contractReviews);
|
|
1894
1958
|
// No run-log line for the gate here ON PURPOSE: the gate already records its
|
|
1895
1959
|
// own outcome at evaluation time (`recordFinalGateOutcome`), so a second line
|
|
1896
1960
|
// at close would be a duplicate — and `kind: "outcome"` at close means "one
|
|
@@ -1914,10 +1978,6 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1914
1978
|
: { reflections: [], discarded: [] };
|
|
1915
1979
|
reportDiscardedReflections(closeFeedback.discarded, "remediate-code");
|
|
1916
1980
|
const reportContent = buildRemediationReportMarkdown(state, entries, closingResult, e2eResult.ran ? e2eResult.passed : undefined, outcomesReport, combinedTest, closeFeedback.reflections, landingGates);
|
|
1917
|
-
// Enrich the coverage ledger with never-planned payloads NOW, from the live
|
|
1918
|
-
// state and intake artifacts — both are deleted at the end of close, so this
|
|
1919
|
-
// must happen strictly before cleanup.
|
|
1920
|
-
const outcomeCoverage = await buildOutcomeCoverageLedger(state, options);
|
|
1921
1981
|
const outcomesFile = {
|
|
1922
1982
|
...outcomesReport,
|
|
1923
1983
|
...(state.started_at ? { started_at: state.started_at } : {}),
|
|
@@ -1976,7 +2036,7 @@ export async function runClosePhase(state, options, runLogger) {
|
|
|
1976
2036
|
});
|
|
1977
2037
|
console.log("Remediation report generated.");
|
|
1978
2038
|
// 6. Clean up temporary branches and artifact directory (only when fully green).
|
|
1979
|
-
await cleanupTempBranchesAndArtifacts(options, completeState, combinedTest, e2eResult, closingResult, runLogger, landingGates);
|
|
2039
|
+
await cleanupTempBranchesAndArtifacts(options, completeState, combinedTest, e2eResult, closingResult, runLogger, landingGates, outcomesReport);
|
|
1980
2040
|
return completeState;
|
|
1981
2041
|
}
|
|
1982
2042
|
//# sourceMappingURL=close.js.map
|