diff --git a/plugins/reporting-governance/src/core/runtime-integrated.mjs b/plugins/reporting-governance/src/core/runtime-integrated.mjs index b7ade2a..8d52b7d 100644 --- a/plugins/reporting-governance/src/core/runtime-integrated.mjs +++ b/plugins/reporting-governance/src/core/runtime-integrated.mjs @@ -70,6 +70,38 @@ function resolveRuntimeRoute({ governance, runtime, repoRootOverride }) { return createNotAttemptedResult('runtime execution not attempted: no adapter_action matched an adapter runner route'); } +function promoteTruthStateFromRuntime(governance, routeResult) { + const supervisor = routeResult.runtimeExecution?.result?.supervisor ?? null; + if (!routeResult.attempted || !supervisor) { + return governance; + } + + if ((supervisor.ackedCount ?? 0) > 0) { + return { + ...governance, + planning: { + ...governance.planning, + receipt: { + ...governance.planning?.receipt, + status: 'acked', + delivery_state: 'acked', + notes: [ + ...(Array.isArray(governance.planning?.receipt?.notes) ? governance.planning.receipt.notes : []), + 'Runtime execution produced sender-backed ack evidence; truth state promoted to acked.' + ], + }, + }, + contract: { + ...governance.contract, + receipt_status: 'acked', + delivery_state: 'acked', + }, + }; + } + + return governance; +} + export function executeRuntimeIntegratedGovernance({ event, evidence = [], @@ -98,8 +130,10 @@ export function executeRuntimeIntegratedGovernance({ repoRootOverride, }); + const truthStateIntegrated = promoteTruthStateFromRuntime(governance, routeResult); + return { - ...governance, + ...truthStateIntegrated, runtimeExecution: routeResult.runtimeExecution, runtimeIntegration: { attempted: routeResult.attempted, @@ -114,4 +148,5 @@ export const __testables = { ADAPTER_ACTION_RUNNER_ROUTES, createNotAttemptedResult, resolveRuntimeRoute, + promoteTruthStateFromRuntime, }; diff --git a/plugins/reporting-governance/test/runtime-integrated.integration.test.mjs b/plugins/reporting-governance/test/runtime-integrated.integration.test.mjs index 2682eac..81c442e 100644 --- a/plugins/reporting-governance/test/runtime-integrated.integration.test.mjs +++ b/plugins/reporting-governance/test/runtime-integrated.integration.test.mjs @@ -256,12 +256,28 @@ function assertDeferredTruthState(result) { assertNoAckedOrFinalDeliveredClaim(result); } +function assertAckedTruthState(result) { + assert.equal(result.contract.delivery_state, 'acked'); + assert.equal(result.contract.receipt_status, 'acked'); + assert.equal(result.planning.receipt.delivery_state, 'acked'); + assert.equal(result.planning.receipt.status, 'acked'); + assert.match( + result.planning.receipt.notes.at(-1) ?? '', + /truth state promoted to acked/ + ); +} + const futureTruthStateMatrix = Object.freeze({ deferred: { contractDeliveryState: 'pending_external_send', attempted: true, terminalClaimForbidden: ['acked', 'final_delivered'] }, + acked: { + contractDeliveryState: 'acked', + attempted: true, + terminalClaimRequired: ['acked'] + }, planningOnly: { attempted: false, terminalClaimForbidden: ['acked', 'final_delivered'] @@ -414,6 +430,45 @@ test('runtime-integrated route matrix: matched adapter_action runs orchestrator } }); +test('runtime-integrated route matrix: full sender capability promotes truth state to acked', () => { + const root = createFixtureRoot(); + try { + mkdirs(root, ['evidence', 'events', 'queue', 'spool', 'receipts']); + const statePath = writeState(root); + + const result = executeRuntimeIntegratedGovernance(createBaseArgs({ + runtime: { + state: statePath, + evidenceDir: path.join(root, 'evidence'), + eventDir: path.join(root, 'events'), + queueDir: path.join(root, 'queue'), + spoolDir: path.join(root, 'spool'), + receiptDir: path.join(root, 'receipts'), + writeState: true, + senderCommand: `node -e "process.stdout.write(JSON.stringify({state:'sent'}))"`, + now: '2026-05-07T08:20:00.000Z', + }, + })); + + assert.equal(result.preflight.status, 'pass'); + assert.equal(result.runtimeIntegration.attempted, futureTruthStateMatrix.acked.attempted); + assert.equal(result.runtimeExecution.ok, true); + assert.equal(result.runtimeExecution.result.dispatcher.dispatchedCount, 1); + assert.equal(result.runtimeExecution.result.supervisor.ackedCount, 1); + assertAckedTruthState(result); + + const queueItem = readSingleJson(path.join(root, 'queue')); + assert.equal(queueItem.status, 'acked'); + + const receipt = readSingleJson(path.join(root, 'receipts')); + assert.equal(receipt.state, 'acked'); + assert.equal(receipt.sender_binding.state, 'sent'); + assert.equal(receipt.sender_status, 0); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } +}); + test('runtime-integrated route matrix: degraded without adapter_action stays not attempted', () => { const result = executeRuntimeIntegratedGovernance(createBaseArgs({