fix: align degraded runtime route policy
This commit is contained in:
@@ -28,14 +28,28 @@ function resolveRuntimeRoute({ governance, runtime, repoRootOverride }) {
|
|||||||
return createNotAttemptedResult('runtime execution not attempted');
|
return createNotAttemptedResult('runtime execution not attempted');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (governance.preflight?.status !== 'pass') {
|
if (governance.preflight?.status === 'fail_closed') {
|
||||||
return createNotAttemptedResult('runtime execution not attempted: compatibility preflight did not pass');
|
return createNotAttemptedResult('runtime execution not attempted: compatibility preflight failed closed');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!governance.deploymentBinding) {
|
if (!governance.deploymentBinding) {
|
||||||
return createNotAttemptedResult('runtime execution not attempted: deployment binding is missing');
|
return createNotAttemptedResult('runtime execution not attempted: deployment binding is missing');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!['pass', 'degraded'].includes(governance.preflight?.status)) {
|
||||||
|
return createNotAttemptedResult('runtime execution not attempted: compatibility preflight did not produce a runnable status');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (governance.preflight?.status === 'degraded') {
|
||||||
|
const adapterActions = Array.isArray(governance.contract?.adapter_actions)
|
||||||
|
? governance.contract.adapter_actions
|
||||||
|
: [];
|
||||||
|
|
||||||
|
if (adapterActions.length === 0) {
|
||||||
|
return createNotAttemptedResult('runtime execution not attempted: degraded compatibility preflight produced no adapter_action route');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const adapterActions = Array.isArray(governance.contract?.adapter_actions)
|
const adapterActions = Array.isArray(governance.contract?.adapter_actions)
|
||||||
? governance.contract.adapter_actions
|
? governance.contract.adapter_actions
|
||||||
: [];
|
: [];
|
||||||
|
|||||||
@@ -190,6 +190,24 @@ function createStubRuntime() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createDegradedDescriptor() {
|
||||||
|
return {
|
||||||
|
...capabilityDescriptor,
|
||||||
|
metadata: {
|
||||||
|
...capabilityDescriptor.metadata,
|
||||||
|
id: 'degraded-openclaw-watchdog-reference'
|
||||||
|
},
|
||||||
|
capabilities: {
|
||||||
|
...capabilityDescriptor.capabilities,
|
||||||
|
notification_path: {
|
||||||
|
...capabilityDescriptor.capabilities.notification_path,
|
||||||
|
sender_binding: { supported: false, level: 'none' },
|
||||||
|
direct_send: { supported: false, level: 'none' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
test('runtime-integrated route matrix: no runtime stays planning-only', () => {
|
test('runtime-integrated route matrix: no runtime stays planning-only', () => {
|
||||||
const result = executeRuntimeIntegratedGovernance(createBaseArgs());
|
const result = executeRuntimeIntegratedGovernance(createBaseArgs());
|
||||||
|
|
||||||
@@ -199,7 +217,7 @@ test('runtime-integrated route matrix: no runtime stays planning-only', () => {
|
|||||||
assert.equal(result.runtimeExecution, null);
|
assert.equal(result.runtimeExecution, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('runtime-integrated route matrix: preflight fail blocks runtime route', () => {
|
test('runtime-integrated route matrix: preflight fail_closed blocks runtime route', () => {
|
||||||
const result = executeRuntimeIntegratedGovernance(createBaseArgs({
|
const result = executeRuntimeIntegratedGovernance(createBaseArgs({
|
||||||
profile: {
|
profile: {
|
||||||
...strictProfileArtifact,
|
...strictProfileArtifact,
|
||||||
@@ -213,7 +231,7 @@ test('runtime-integrated route matrix: preflight fail blocks runtime route', ()
|
|||||||
|
|
||||||
assert.equal(result.preflight.status, 'fail_closed');
|
assert.equal(result.preflight.status, 'fail_closed');
|
||||||
assert.equal(result.runtimeIntegration.attempted, false);
|
assert.equal(result.runtimeIntegration.attempted, false);
|
||||||
assert.equal(result.runtimeIntegration.reason, 'runtime execution not attempted: compatibility preflight did not pass');
|
assert.equal(result.runtimeIntegration.reason, 'runtime execution not attempted: compatibility preflight failed closed');
|
||||||
assert.equal(result.runtimeExecution, null);
|
assert.equal(result.runtimeExecution, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -252,6 +270,48 @@ test('runtime-integrated route matrix: unknown adapter_action stays planning-onl
|
|||||||
assert.equal(result.runtimeExecution, null);
|
assert.equal(result.runtimeExecution, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('runtime-integrated route matrix: degraded preflight still runs queue/bridge route honestly', () => {
|
||||||
|
const root = createFixtureRoot();
|
||||||
|
try {
|
||||||
|
mkdirs(root, ['evidence', 'events', 'queue', 'spool', 'receipts']);
|
||||||
|
const statePath = writeState(root);
|
||||||
|
|
||||||
|
const result = executeRuntimeIntegratedGovernance(createBaseArgs({
|
||||||
|
capabilityDescriptor: createDegradedDescriptor(),
|
||||||
|
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,
|
||||||
|
dryRun: true,
|
||||||
|
now: '2026-05-07T08:20:00.000Z',
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
assert.equal(result.preflight.status, 'degraded');
|
||||||
|
assert.equal(result.contract.adapter_actions[0], 'notify_operator');
|
||||||
|
assert.equal(result.contract.delivery_state, 'pending_external_send');
|
||||||
|
assert.equal(result.runtimeIntegration.attempted, true);
|
||||||
|
assert.equal(result.runtimeIntegration.adapter, 'orchestrator');
|
||||||
|
assert.equal(result.runtimeIntegration.action, 'notify_operator');
|
||||||
|
assert.equal(result.runtimeExecution.ok, true);
|
||||||
|
assert.equal(result.runtimeExecution.result.dispatcher.dispatchedCount, 1);
|
||||||
|
assert.equal(result.runtimeExecution.result.supervisor.pendingCount, 1);
|
||||||
|
|
||||||
|
const queueItem = readSingleJson(path.join(root, 'queue'));
|
||||||
|
assert.equal(queueItem.status, 'dispatched');
|
||||||
|
|
||||||
|
const receipt = readSingleJson(path.join(root, 'receipts'));
|
||||||
|
assert.equal(receipt.state, 'pending_external_send');
|
||||||
|
assert.equal(receipt.supervisor_mode, 'dry_run');
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(root, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('runtime-integrated route matrix: matched adapter_action runs orchestrator adapter runner', () => {
|
test('runtime-integrated route matrix: matched adapter_action runs orchestrator adapter runner', () => {
|
||||||
const root = createFixtureRoot();
|
const root = createFixtureRoot();
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user