feat: add workflow dry-run observability

This commit is contained in:
john
2026-07-24 22:44:26 +08:00
parent c9ad841543
commit 19706eb3a0
15 changed files with 725 additions and 41 deletions
@@ -72,6 +72,7 @@ test('shadow boundary returns an auditable dry-run plan without calling LangGrap
runId: 'run-dry-1',
requestId: 'request-dry-1',
userId: 'user-1',
taskType: 'repo_refactor',
});
assert.equal(result.observed, false);
assert.deepEqual(result.executionPlan, {
@@ -83,12 +84,49 @@ test('shadow boundary returns an auditable dry-run plan without calling LangGrap
candidateReason: 'user_allowlist',
configVersion: 8,
bucket: 42,
taskType: 'repo_refactor',
dryRun: true,
handoffAllowed: false,
});
assert.equal(fetchCalls, 0);
});
test('shadow boundary records non-selected canary decisions for a complete rate denominator', async () => {
const observer = createWorkflowShadowObserver({
configService: {
async selectEngine() {
return {
engine: 'native',
candidateEngine: 'native',
shadowEngine: null,
fallbackEngine: 'native',
reason: 'canary_not_selected',
candidateReason: null,
mode: 'canary',
configVersion: 9,
bucket: 88,
dryRun: false,
};
},
async getRuntimeState() {
throw new Error('must not load runtime config');
},
},
});
const result = await observer({
runId: 'run-native-1',
requestId: 'request-native-1',
userId: 'user-1',
taskType: 'code_analysis',
});
assert.equal(result.observed, false);
assert.equal(result.executionPlan.dryRun, true);
assert.equal(result.executionPlan.candidateEngine, 'native');
assert.equal(result.executionPlan.reason, 'canary_not_selected');
assert.equal(result.executionPlan.taskType, 'code_analysis');
});
test('shadow observer sends a bounded observe-only RunSpec to LangGraph service', async () => {
let capturedUrl = null;
let capturedInit = null;