fix(reporting-governance): tighten ack truth-state promotion guardrail
This commit is contained in:
@@ -70,13 +70,23 @@ function resolveRuntimeRoute({ governance, runtime, repoRootOverride }) {
|
|||||||
return createNotAttemptedResult('runtime execution not attempted: no adapter_action matched an adapter runner route');
|
return createNotAttemptedResult('runtime execution not attempted: no adapter_action matched an adapter runner route');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canPromoteAckedFromSupervisor(supervisor) {
|
||||||
|
const ackedCount = Number(supervisor?.ackedCount ?? 0);
|
||||||
|
const blockedCount = Number(supervisor?.blockedCount ?? 0);
|
||||||
|
const pendingCount = Number(supervisor?.pendingCount ?? 0);
|
||||||
|
|
||||||
|
// Current runtime contract is a single notice settlement path.
|
||||||
|
// Only promote the overall truth state when the observed terminal set is fully acked.
|
||||||
|
return ackedCount > 0 && blockedCount === 0 && pendingCount === 0;
|
||||||
|
}
|
||||||
|
|
||||||
function promoteTruthStateFromRuntime(governance, routeResult) {
|
function promoteTruthStateFromRuntime(governance, routeResult) {
|
||||||
const supervisor = routeResult.runtimeExecution?.result?.supervisor ?? null;
|
const supervisor = routeResult.runtimeExecution?.result?.supervisor ?? null;
|
||||||
if (!routeResult.attempted || !supervisor) {
|
if (!routeResult.attempted || !supervisor) {
|
||||||
return governance;
|
return governance;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((supervisor.ackedCount ?? 0) > 0) {
|
if (canPromoteAckedFromSupervisor(supervisor)) {
|
||||||
return {
|
return {
|
||||||
...governance,
|
...governance,
|
||||||
planning: {
|
planning: {
|
||||||
@@ -87,7 +97,7 @@ function promoteTruthStateFromRuntime(governance, routeResult) {
|
|||||||
delivery_state: 'acked',
|
delivery_state: 'acked',
|
||||||
notes: [
|
notes: [
|
||||||
...(Array.isArray(governance.planning?.receipt?.notes) ? governance.planning.receipt.notes : []),
|
...(Array.isArray(governance.planning?.receipt?.notes) ? governance.planning.receipt.notes : []),
|
||||||
'Runtime execution produced sender-backed ack evidence; truth state promoted to acked.'
|
'Runtime execution produced sender-backed ack evidence; truth state promoted to acked only after all observed terminal outcomes were fully acked.'
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -148,5 +158,6 @@ export const __testables = {
|
|||||||
ADAPTER_ACTION_RUNNER_ROUTES,
|
ADAPTER_ACTION_RUNNER_ROUTES,
|
||||||
createNotAttemptedResult,
|
createNotAttemptedResult,
|
||||||
resolveRuntimeRoute,
|
resolveRuntimeRoute,
|
||||||
|
canPromoteAckedFromSupervisor,
|
||||||
promoteTruthStateFromRuntime,
|
promoteTruthStateFromRuntime,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import path from 'node:path';
|
|||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
|
|
||||||
import { executeRuntimeIntegratedGovernance } from '../src/index.mjs';
|
import { executeRuntimeIntegratedGovernance } from '../src/index.mjs';
|
||||||
|
import { __testables as runtimeIntegratedTestables } from '../src/core/runtime-integrated.mjs';
|
||||||
import capabilityDescriptor from '../capabilities/openclaw-watchdog-reference.json' with { type: 'json' };
|
import capabilityDescriptor from '../capabilities/openclaw-watchdog-reference.json' with { type: 'json' };
|
||||||
|
|
||||||
const packageRoot = path.resolve(import.meta.dirname, '..');
|
const packageRoot = path.resolve(import.meta.dirname, '..');
|
||||||
@@ -267,6 +268,34 @@ function assertAckedTruthState(result) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test('truth-state promotion guardrail: mixed terminal outcomes must not promote overall state to acked', () => {
|
||||||
|
assert.equal(runtimeIntegratedTestables.canPromoteAckedFromSupervisor({
|
||||||
|
ackedCount: 1,
|
||||||
|
pendingCount: 1,
|
||||||
|
blockedCount: 0,
|
||||||
|
}), false);
|
||||||
|
|
||||||
|
assert.equal(runtimeIntegratedTestables.canPromoteAckedFromSupervisor({
|
||||||
|
ackedCount: 1,
|
||||||
|
pendingCount: 0,
|
||||||
|
blockedCount: 1,
|
||||||
|
}), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('truth-state promotion guardrail: only fully acked observed terminal set may promote to acked', () => {
|
||||||
|
assert.equal(runtimeIntegratedTestables.canPromoteAckedFromSupervisor({
|
||||||
|
ackedCount: 0,
|
||||||
|
pendingCount: 0,
|
||||||
|
blockedCount: 0,
|
||||||
|
}), false);
|
||||||
|
|
||||||
|
assert.equal(runtimeIntegratedTestables.canPromoteAckedFromSupervisor({
|
||||||
|
ackedCount: 1,
|
||||||
|
pendingCount: 0,
|
||||||
|
blockedCount: 0,
|
||||||
|
}), true);
|
||||||
|
});
|
||||||
|
|
||||||
const futureTruthStateMatrix = Object.freeze({
|
const futureTruthStateMatrix = Object.freeze({
|
||||||
deferred: {
|
deferred: {
|
||||||
contractDeliveryState: 'pending_external_send',
|
contractDeliveryState: 'pending_external_send',
|
||||||
|
|||||||
Reference in New Issue
Block a user