oxe-cc 1.2.1 → 1.3.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/.cursor/commands/oxe-ask.md +2 -2
- package/.cursor/commands/oxe-capabilities.md +2 -2
- package/.cursor/commands/oxe-checkpoint.md +2 -2
- package/.cursor/commands/oxe-compact.md +2 -2
- package/.cursor/commands/oxe-dashboard.md +2 -2
- package/.cursor/commands/oxe-debug.md +2 -2
- package/.cursor/commands/oxe-discuss.md +2 -2
- package/.cursor/commands/oxe-execute.md +5 -2
- package/.cursor/commands/oxe-forensics.md +2 -2
- package/.cursor/commands/oxe-help.md +2 -2
- package/.cursor/commands/oxe-loop.md +2 -2
- package/.cursor/commands/oxe-milestone.md +2 -2
- package/.cursor/commands/oxe-next.md +2 -2
- package/.cursor/commands/oxe-obs.md +2 -2
- package/.cursor/commands/oxe-plan-agent.md +2 -2
- package/.cursor/commands/oxe-plan.md +2 -2
- package/.cursor/commands/oxe-project.md +2 -2
- package/.cursor/commands/oxe-quick.md +2 -2
- package/.cursor/commands/oxe-research.md +2 -2
- package/.cursor/commands/oxe-retro.md +2 -2
- package/.cursor/commands/oxe-review-pr.md +2 -2
- package/.cursor/commands/oxe-route.md +2 -2
- package/.cursor/commands/oxe-scan.md +2 -2
- package/.cursor/commands/oxe-security.md +2 -2
- package/.cursor/commands/oxe-session.md +2 -2
- package/.cursor/commands/oxe-ship.md +2 -2
- package/.cursor/commands/oxe-skill.md +2 -2
- package/.cursor/commands/oxe-spec.md +2 -2
- package/.cursor/commands/oxe-ui-review.md +2 -2
- package/.cursor/commands/oxe-ui-spec.md +2 -2
- package/.cursor/commands/oxe-update.md +2 -2
- package/.cursor/commands/oxe-validate-gaps.md +2 -2
- package/.cursor/commands/oxe-verify.md +5 -2
- package/.cursor/commands/oxe-workstream.md +2 -2
- package/.cursor/commands/oxe.md +2 -2
- package/.github/copilot-instructions.md +13 -13
- package/.github/prompts/oxe-ask.prompt.md +2 -2
- package/.github/prompts/oxe-capabilities.prompt.md +2 -2
- package/.github/prompts/oxe-checkpoint.prompt.md +2 -2
- package/.github/prompts/oxe-compact.prompt.md +2 -2
- package/.github/prompts/oxe-dashboard.prompt.md +2 -2
- package/.github/prompts/oxe-debug.prompt.md +2 -2
- package/.github/prompts/oxe-discuss.prompt.md +2 -2
- package/.github/prompts/oxe-execute.prompt.md +5 -2
- package/.github/prompts/oxe-forensics.prompt.md +2 -2
- package/.github/prompts/oxe-help.prompt.md +2 -2
- package/.github/prompts/oxe-loop.prompt.md +2 -2
- package/.github/prompts/oxe-milestone.prompt.md +2 -2
- package/.github/prompts/oxe-next.prompt.md +2 -2
- package/.github/prompts/oxe-obs.prompt.md +2 -2
- package/.github/prompts/oxe-plan-agent.prompt.md +2 -2
- package/.github/prompts/oxe-plan.prompt.md +2 -2
- package/.github/prompts/oxe-project.prompt.md +2 -2
- package/.github/prompts/oxe-quick.prompt.md +2 -2
- package/.github/prompts/oxe-research.prompt.md +2 -2
- package/.github/prompts/oxe-retro.prompt.md +2 -2
- package/.github/prompts/oxe-review-pr.prompt.md +2 -2
- package/.github/prompts/oxe-route.prompt.md +2 -2
- package/.github/prompts/oxe-scan.prompt.md +2 -2
- package/.github/prompts/oxe-security.prompt.md +2 -2
- package/.github/prompts/oxe-session.prompt.md +2 -2
- package/.github/prompts/oxe-ship.prompt.md +2 -2
- package/.github/prompts/oxe-skill.prompt.md +2 -2
- package/.github/prompts/oxe-spec.prompt.md +2 -2
- package/.github/prompts/oxe-ui-review.prompt.md +2 -2
- package/.github/prompts/oxe-ui-spec.prompt.md +2 -2
- package/.github/prompts/oxe-update.prompt.md +2 -2
- package/.github/prompts/oxe-validate-gaps.prompt.md +2 -2
- package/.github/prompts/oxe-verify.prompt.md +5 -2
- package/.github/prompts/oxe-workstream.prompt.md +2 -2
- package/.github/prompts/oxe.prompt.md +2 -2
- package/CHANGELOG.md +52 -17
- package/README.md +610 -551
- package/bin/banner.txt +1 -1
- package/bin/lib/oxe-agent-install.cjs +69 -69
- package/bin/lib/oxe-azure.cjs +1445 -1445
- package/bin/lib/oxe-context-engine.cjs +867 -867
- package/bin/lib/oxe-dashboard.cjs +76 -28
- package/bin/lib/oxe-operational.cjs +2144 -1340
- package/bin/lib/oxe-project-health.cjs +483 -1
- package/bin/lib/oxe-runtime-semantics.cjs +12 -0
- package/bin/oxe-cc.js +554 -152
- package/commands/oxe/ask.md +2 -2
- package/commands/oxe/capabilities.md +2 -2
- package/commands/oxe/checkpoint.md +2 -2
- package/commands/oxe/compact.md +2 -2
- package/commands/oxe/dashboard.md +2 -2
- package/commands/oxe/debug.md +2 -2
- package/commands/oxe/discuss.md +2 -2
- package/commands/oxe/execute.md +5 -2
- package/commands/oxe/forensics.md +2 -2
- package/commands/oxe/help.md +2 -2
- package/commands/oxe/loop.md +2 -2
- package/commands/oxe/milestone.md +2 -2
- package/commands/oxe/next.md +2 -2
- package/commands/oxe/obs.md +2 -2
- package/commands/oxe/oxe.md +2 -2
- package/commands/oxe/plan-agent.md +2 -2
- package/commands/oxe/plan.md +2 -2
- package/commands/oxe/project.md +2 -2
- package/commands/oxe/quick.md +2 -2
- package/commands/oxe/research.md +2 -2
- package/commands/oxe/retro.md +2 -2
- package/commands/oxe/review-pr.md +2 -2
- package/commands/oxe/route.md +2 -2
- package/commands/oxe/scan.md +2 -2
- package/commands/oxe/security.md +2 -2
- package/commands/oxe/session.md +2 -2
- package/commands/oxe/ship.md +2 -2
- package/commands/oxe/skill.md +2 -2
- package/commands/oxe/spec.md +2 -2
- package/commands/oxe/ui-review.md +2 -2
- package/commands/oxe/ui-spec.md +2 -2
- package/commands/oxe/update.md +2 -2
- package/commands/oxe/validate-gaps.md +2 -2
- package/commands/oxe/verify.md +5 -2
- package/commands/oxe/workstream.md +2 -2
- package/lib/runtime/delivery/branch-manager.d.ts +1 -0
- package/lib/runtime/delivery/branch-manager.js +7 -0
- package/lib/runtime/delivery/ci-checks.js +34 -1
- package/lib/runtime/delivery/delivery-records.d.ts +34 -0
- package/lib/runtime/delivery/delivery-records.js +48 -0
- package/lib/runtime/delivery/index.d.ts +1 -0
- package/lib/runtime/delivery/index.js +1 -0
- package/lib/runtime/delivery/promotion-pipeline.d.ts +26 -2
- package/lib/runtime/delivery/promotion-pipeline.js +111 -14
- package/lib/runtime/gate/gate-manager.d.ts +41 -0
- package/lib/runtime/gate/gate-manager.js +108 -1
- package/lib/runtime/index.d.ts +2 -2
- package/lib/runtime/index.js +3 -1
- package/lib/runtime/models/gate-decision.d.ts +4 -1
- package/lib/runtime/models/workspace.d.ts +3 -0
- package/lib/runtime/plugins/capability-adapter.d.ts +12 -0
- package/lib/runtime/plugins/capability-adapter.js +204 -0
- package/lib/runtime/plugins/capability-matrix.d.ts +5 -0
- package/lib/runtime/plugins/capability-matrix.js +48 -17
- package/lib/runtime/plugins/index.d.ts +1 -0
- package/lib/runtime/plugins/index.js +1 -0
- package/lib/runtime/plugins/plugin-abi.d.ts +2 -0
- package/lib/runtime/plugins/plugin-manifest.d.ts +1 -1
- package/lib/runtime/plugins/plugin-manifest.js +6 -2
- package/lib/runtime/plugins/plugin-registry.d.ts +46 -0
- package/lib/runtime/plugins/plugin-registry.js +79 -2
- package/lib/runtime/policy/policy-engine.d.ts +19 -0
- package/lib/runtime/policy/policy-engine.js +76 -4
- package/lib/runtime/projection/projection-engine.d.ts +9 -1
- package/lib/runtime/projection/projection-engine.js +73 -3
- package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +43 -1
- package/lib/runtime/scheduler/multi-agent-coordinator.js +151 -39
- package/lib/runtime/scheduler/run-journal.d.ts +1 -1
- package/lib/runtime/scheduler/scheduler.d.ts +19 -1
- package/lib/runtime/scheduler/scheduler.js +258 -13
- package/lib/runtime/verification/verification-compiler.d.ts +43 -0
- package/lib/runtime/verification/verification-compiler.js +137 -0
- package/lib/runtime/verification/verification-manifest.d.ts +9 -0
- package/lib/runtime/verification/verification-manifest.js +56 -6
- package/lib/runtime/workspace/strategies/ephemeral-container.d.ts +1 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.js +4 -0
- package/lib/runtime/workspace/strategies/git-worktree.d.ts +1 -0
- package/lib/runtime/workspace/strategies/git-worktree.js +2 -0
- package/lib/runtime/workspace/strategies/inplace.d.ts +1 -0
- package/lib/runtime/workspace/strategies/inplace.js +2 -0
- package/lib/runtime/workspace/workspace-manager.d.ts +2 -1
- package/lib/sdk/README.md +9 -9
- package/lib/sdk/index.cjs +33 -24
- package/lib/sdk/index.d.ts +149 -14
- package/oxe/templates/ACTIVE-RUN.template.json +32 -32
- package/oxe/templates/CAPABILITIES.template.md +7 -7
- package/oxe/templates/CAPABILITY.template.md +45 -45
- package/oxe/templates/CHECKPOINTS.template.md +7 -7
- package/oxe/templates/EXECUTION-RUNTIME.template.md +68 -68
- package/oxe/templates/HYPOTHESES.template.md +33 -33
- package/oxe/templates/LESSONS-METRICS.template.json +13 -13
- package/oxe/templates/NOTES.template.md +16 -16
- package/oxe/templates/PLAN-REVIEW.template.md +31 -31
- package/oxe/templates/SESSION.template.md +34 -34
- package/oxe/templates/SKILL.template.md +26 -26
- package/oxe/templates/STATE.md +55 -55
- package/oxe/templates/WORKFLOW_AUTHORING.md +18 -18
- package/oxe/workflows/ask.md +96 -96
- package/oxe/workflows/capabilities.md +25 -25
- package/oxe/workflows/dashboard.md +33 -33
- package/oxe/workflows/discuss.md +12 -12
- package/oxe/workflows/execute.md +14 -0
- package/oxe/workflows/help.md +352 -352
- package/oxe/workflows/next.md +22 -22
- package/oxe/workflows/oxe.md +6 -6
- package/oxe/workflows/plan-agent.md +9 -9
- package/oxe/workflows/quick.md +10 -10
- package/oxe/workflows/references/reasoning-discovery.md +28 -28
- package/oxe/workflows/references/reasoning-execution.md +29 -29
- package/oxe/workflows/references/reasoning-planning.md +32 -32
- package/oxe/workflows/references/reasoning-review.md +29 -29
- package/oxe/workflows/references/reasoning-status.md +24 -24
- package/oxe/workflows/references/robustness-elevation.md +295 -295
- package/oxe/workflows/references/workflow-runtime-contracts.json +952 -930
- package/oxe/workflows/route.md +16 -16
- package/oxe/workflows/session.md +213 -213
- package/oxe/workflows/ship.md +142 -142
- package/oxe/workflows/skill.md +44 -44
- package/oxe/workflows/ui-review.md +36 -36
- package/oxe/workflows/verify-audit.md +73 -73
- package/oxe/workflows/verify.md +10 -0
- package/package.json +92 -92
- package/packages/runtime/package.json +17 -17
- package/packages/runtime/src/audit/audit-trail.ts +243 -243
- package/packages/runtime/src/audit/index.ts +2 -2
- package/packages/runtime/src/audit/policy-pack.ts +62 -62
- package/packages/runtime/src/compiler/graph-compiler.ts +245 -245
- package/packages/runtime/src/compiler/index.ts +1 -1
- package/packages/runtime/src/context/context-pack-builder.ts +259 -259
- package/packages/runtime/src/context/context-pack-store.ts +197 -197
- package/packages/runtime/src/context/context-profiles.ts +60 -60
- package/packages/runtime/src/context/index.ts +3 -3
- package/packages/runtime/src/decision/decision-engine.ts +174 -174
- package/packages/runtime/src/decision/decision-memo.ts +211 -211
- package/packages/runtime/src/decision/index.ts +2 -2
- package/packages/runtime/src/delivery/branch-manager.ts +91 -84
- package/packages/runtime/src/delivery/ci-checks.ts +285 -252
- package/packages/runtime/src/delivery/delivery-records.ts +75 -0
- package/packages/runtime/src/delivery/index.ts +5 -4
- package/packages/runtime/src/delivery/pr-manager.ts +112 -112
- package/packages/runtime/src/delivery/promotion-pipeline.ts +334 -180
- package/packages/runtime/src/events/bus.ts +92 -92
- package/packages/runtime/src/events/catalog.ts +29 -29
- package/packages/runtime/src/events/envelope.ts +14 -14
- package/packages/runtime/src/events/index.ts +3 -3
- package/packages/runtime/src/evidence/evidence-store.ts +130 -130
- package/packages/runtime/src/evidence/index.ts +1 -1
- package/packages/runtime/src/gate/gate-manager.ts +289 -137
- package/packages/runtime/src/gate/index.ts +1 -1
- package/packages/runtime/src/index.ts +41 -37
- package/packages/runtime/src/models/attempt.ts +19 -19
- package/packages/runtime/src/models/evidence.ts +21 -21
- package/packages/runtime/src/models/gate-decision.ts +25 -21
- package/packages/runtime/src/models/index.ts +8 -8
- package/packages/runtime/src/models/run.ts +24 -24
- package/packages/runtime/src/models/session.ts +11 -11
- package/packages/runtime/src/models/verification-result.ts +10 -10
- package/packages/runtime/src/models/work-item.ts +25 -25
- package/packages/runtime/src/models/workspace.ts +31 -28
- package/packages/runtime/src/plugins/capability-adapter.ts +206 -0
- package/packages/runtime/src/plugins/capability-matrix.ts +126 -83
- package/packages/runtime/src/plugins/index.ts +5 -4
- package/packages/runtime/src/plugins/plugin-abi.ts +97 -95
- package/packages/runtime/src/plugins/plugin-manifest.ts +118 -113
- package/packages/runtime/src/plugins/plugin-registry.ts +232 -124
- package/packages/runtime/src/policy/index.ts +1 -1
- package/packages/runtime/src/policy/policy-engine.ts +330 -244
- package/packages/runtime/src/projection/index.ts +1 -1
- package/packages/runtime/src/projection/projection-engine.ts +328 -249
- package/packages/runtime/src/reducers/debug-reducer.ts +36 -36
- package/packages/runtime/src/reducers/index.ts +2 -2
- package/packages/runtime/src/reducers/run-state-reducer.ts +269 -269
- package/packages/runtime/src/scheduler/agent-registry.ts +132 -132
- package/packages/runtime/src/scheduler/agent-roles.ts +109 -109
- package/packages/runtime/src/scheduler/index.ts +4 -4
- package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +521 -333
- package/packages/runtime/src/scheduler/run-journal.ts +62 -62
- package/packages/runtime/src/scheduler/scheduler.ts +722 -441
- package/packages/runtime/src/verification/index.ts +2 -2
- package/packages/runtime/src/verification/verification-compiler.ts +436 -225
- package/packages/runtime/src/verification/verification-manifest.ts +252 -192
- package/packages/runtime/src/workspace/index.ts +5 -5
- package/packages/runtime/src/workspace/strategies/ephemeral-container.ts +126 -121
- package/packages/runtime/src/workspace/strategies/git-worktree.ts +79 -77
- package/packages/runtime/src/workspace/strategies/inplace.ts +38 -35
- package/packages/runtime/src/workspace/workspace-manager.ts +16 -15
- package/packages/runtime/tsconfig.json +17 -17
- package/vscode-extension/.vscodeignore +7 -7
- package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
- package/vscode-extension/package.json +185 -185
- package/vscode-extension/src/extension.js +310 -310
- package/vscode-extension/src/shared/contextLoader.js +137 -137
- package/vscode-extension/src/shared/contractBuilder.js +159 -159
- package/vscode-extension/src/shared/stateReader.js +101 -101
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Scheduler = void 0;
|
|
4
4
|
const bus_1 = require("../events/bus");
|
|
5
|
+
const policy_engine_1 = require("../policy/policy-engine");
|
|
6
|
+
const audit_trail_1 = require("../audit/audit-trail");
|
|
5
7
|
const run_journal_1 = require("./run-journal");
|
|
6
8
|
class Scheduler {
|
|
7
9
|
constructor() {
|
|
@@ -23,6 +25,10 @@ class Scheduler {
|
|
|
23
25
|
this.journal = (0, run_journal_1.createJournal)(ctx.runId);
|
|
24
26
|
(0, run_journal_1.saveJournal)(ctx.projectRoot, ctx.runId, this.journal);
|
|
25
27
|
this.emit(ctx, { type: 'RunStarted', payload: { run_id: ctx.runId } });
|
|
28
|
+
ctx.auditTrail?.record('run_started', ctx.policyActor ?? 'runtime', {
|
|
29
|
+
runId: ctx.runId,
|
|
30
|
+
detail: { session_id: ctx.sessionId ?? null },
|
|
31
|
+
});
|
|
26
32
|
for (const wave of graph.waves) {
|
|
27
33
|
if (this.cancelled)
|
|
28
34
|
break;
|
|
@@ -35,7 +41,11 @@ class Scheduler {
|
|
|
35
41
|
this.journal.blocked_work_items = blocked.slice();
|
|
36
42
|
this.journal.partial_result = { run_id: ctx.runId, completed, failed, blocked };
|
|
37
43
|
(0, run_journal_1.saveJournal)(ctx.projectRoot, ctx.runId, this.journal);
|
|
38
|
-
|
|
44
|
+
ctx.auditTrail?.record('run_paused', ctx.policyActor ?? 'runtime', {
|
|
45
|
+
runId: ctx.runId,
|
|
46
|
+
detail: { completed, failed, blocked },
|
|
47
|
+
});
|
|
48
|
+
return { run_id: ctx.runId, status: 'paused', completed, failed, blocked, pending_gates: this.journal.pending_gates.slice() };
|
|
39
49
|
}
|
|
40
50
|
const waveFailed = await this.runWave(wave.node_ids, graph, ctx, status, completed, failed, blocked);
|
|
41
51
|
// Sync journal after each wave
|
|
@@ -62,17 +72,36 @@ class Scheduler {
|
|
|
62
72
|
? 'cancelled'
|
|
63
73
|
: failed.length > 0
|
|
64
74
|
? 'failed'
|
|
65
|
-
:
|
|
75
|
+
: blocked.length > 0
|
|
76
|
+
? 'blocked'
|
|
77
|
+
: 'completed';
|
|
66
78
|
this.emit(ctx, {
|
|
67
79
|
type: 'RunCompleted',
|
|
68
80
|
payload: { run_id: ctx.runId, status: finalStatus },
|
|
69
81
|
});
|
|
70
|
-
|
|
82
|
+
ctx.auditTrail?.record('run_completed', ctx.policyActor ?? 'runtime', {
|
|
83
|
+
runId: ctx.runId,
|
|
84
|
+
detail: {
|
|
85
|
+
status: finalStatus,
|
|
86
|
+
completed: completed.length,
|
|
87
|
+
failed: failed.length,
|
|
88
|
+
blocked: blocked.length,
|
|
89
|
+
pending_gates: this.journal.pending_gates.slice(),
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
this.journal.scheduler_state = this.cancelled ? 'cancelled' : finalStatus === 'blocked' ? 'blocked' : 'completed';
|
|
71
93
|
this.journal.completed_work_items = completed.slice();
|
|
72
94
|
this.journal.failed_work_items = failed.slice();
|
|
73
95
|
this.journal.blocked_work_items = blocked.slice();
|
|
74
96
|
(0, run_journal_1.saveJournal)(ctx.projectRoot, ctx.runId, this.journal);
|
|
75
|
-
return {
|
|
97
|
+
return {
|
|
98
|
+
run_id: ctx.runId,
|
|
99
|
+
status: finalStatus,
|
|
100
|
+
completed,
|
|
101
|
+
failed,
|
|
102
|
+
blocked,
|
|
103
|
+
pending_gates: this.journal.pending_gates.slice(),
|
|
104
|
+
};
|
|
76
105
|
}
|
|
77
106
|
/**
|
|
78
107
|
* Recover a previously paused run by loading its journal and re-running
|
|
@@ -117,7 +146,11 @@ class Scheduler {
|
|
|
117
146
|
this.journal.blocked_work_items = blocked.slice();
|
|
118
147
|
this.journal.partial_result = { run_id: ctx.runId, completed, failed, blocked };
|
|
119
148
|
(0, run_journal_1.saveJournal)(ctx.projectRoot, ctx.runId, this.journal);
|
|
120
|
-
|
|
149
|
+
ctx.auditTrail?.record('run_paused', ctx.policyActor ?? 'runtime', {
|
|
150
|
+
runId: ctx.runId,
|
|
151
|
+
detail: { recovered: true, completed, failed, blocked },
|
|
152
|
+
});
|
|
153
|
+
return { run_id: ctx.runId, status: 'paused', completed, failed, blocked, pending_gates: this.journal.pending_gates.slice() };
|
|
121
154
|
}
|
|
122
155
|
// Skip waves fully completed
|
|
123
156
|
const allDone = wave.node_ids.every((id) => restoredCompleted.has(id) || restoredFailed.has(id) || restoredBlocked.has(id));
|
|
@@ -146,18 +179,37 @@ class Scheduler {
|
|
|
146
179
|
? 'cancelled'
|
|
147
180
|
: failed.length > 0
|
|
148
181
|
? 'failed'
|
|
149
|
-
:
|
|
182
|
+
: blocked.length > 0
|
|
183
|
+
? 'blocked'
|
|
184
|
+
: 'completed';
|
|
150
185
|
this.emit(ctx, {
|
|
151
186
|
type: 'RunCompleted',
|
|
152
187
|
payload: { run_id: ctx.runId, status: finalStatus, recovered: true },
|
|
153
188
|
});
|
|
154
|
-
|
|
189
|
+
ctx.auditTrail?.record('run_recovered', ctx.policyActor ?? 'runtime', {
|
|
190
|
+
runId: ctx.runId,
|
|
191
|
+
detail: {
|
|
192
|
+
status: finalStatus,
|
|
193
|
+
completed: completed.length,
|
|
194
|
+
failed: failed.length,
|
|
195
|
+
blocked: blocked.length,
|
|
196
|
+
pending_gates: this.journal.pending_gates.slice(),
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
this.journal.scheduler_state = this.cancelled ? 'cancelled' : finalStatus === 'blocked' ? 'blocked' : 'completed';
|
|
155
200
|
this.journal.completed_work_items = completed.slice();
|
|
156
201
|
this.journal.failed_work_items = failed.slice();
|
|
157
202
|
this.journal.blocked_work_items = blocked.slice();
|
|
158
203
|
(0, run_journal_1.saveJournal)(ctx.projectRoot, ctx.runId, this.journal);
|
|
159
204
|
(0, run_journal_1.deleteJournal)(ctx.projectRoot, ctx.runId);
|
|
160
|
-
return {
|
|
205
|
+
return {
|
|
206
|
+
run_id: ctx.runId,
|
|
207
|
+
status: finalStatus,
|
|
208
|
+
completed,
|
|
209
|
+
failed,
|
|
210
|
+
blocked,
|
|
211
|
+
pending_gates: this.journal.pending_gates.slice(),
|
|
212
|
+
};
|
|
161
213
|
}
|
|
162
214
|
async runWave(nodeIds, graph, ctx, status, completed, failed, blocked) {
|
|
163
215
|
const eligible = [];
|
|
@@ -189,16 +241,16 @@ class Scheduler {
|
|
|
189
241
|
});
|
|
190
242
|
const mutations = eligible.filter((id) => !readOnly.includes(id));
|
|
191
243
|
if (readOnly.length > 0) {
|
|
192
|
-
await Promise.all(readOnly.map((id) => this.runNode(id, graph, ctx, status, completed, failed)));
|
|
244
|
+
await Promise.all(readOnly.map((id) => this.runNode(id, graph, ctx, status, completed, failed, blocked)));
|
|
193
245
|
}
|
|
194
246
|
for (const id of mutations) {
|
|
195
247
|
if (this.cancelled)
|
|
196
248
|
break;
|
|
197
|
-
await this.runNode(id, graph, ctx, status, completed, failed);
|
|
249
|
+
await this.runNode(id, graph, ctx, status, completed, failed, blocked);
|
|
198
250
|
}
|
|
199
251
|
return failed.length > 0;
|
|
200
252
|
}
|
|
201
|
-
async runNode(nodeId, graph, ctx, status, completed, failed) {
|
|
253
|
+
async runNode(nodeId, graph, ctx, status, completed, failed, blocked) {
|
|
202
254
|
const node = graph.nodes.get(nodeId);
|
|
203
255
|
status.set(nodeId, 'running');
|
|
204
256
|
this.emit(ctx, {
|
|
@@ -209,6 +261,11 @@ class Scheduler {
|
|
|
209
261
|
let lease = null;
|
|
210
262
|
let lastResult = null;
|
|
211
263
|
const maxAttempts = node.policy.max_retries + 1;
|
|
264
|
+
const quotaBlocked = this.consumeQuotaForNode(ctx, node);
|
|
265
|
+
if (quotaBlocked) {
|
|
266
|
+
this.blockNode(nodeId, ctx, status, blocked, 'quota_exceeded', quotaBlocked);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
212
269
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
213
270
|
const attemptId = `${nodeId}-a${attempt}`;
|
|
214
271
|
this.emit(ctx, {
|
|
@@ -218,20 +275,50 @@ class Scheduler {
|
|
|
218
275
|
payload: { attempt_number: attempt },
|
|
219
276
|
});
|
|
220
277
|
try {
|
|
278
|
+
const policyDecision = this.evaluatePolicyForNode(node, ctx);
|
|
279
|
+
if (policyDecision && !policyDecision.allowed) {
|
|
280
|
+
this.emit(ctx, {
|
|
281
|
+
type: 'PolicyEvaluated',
|
|
282
|
+
work_item_id: nodeId,
|
|
283
|
+
attempt_id: attemptId,
|
|
284
|
+
payload: { ...policyDecision },
|
|
285
|
+
});
|
|
286
|
+
ctx.auditTrail?.record('policy_denied', ctx.policyActor ?? 'runtime', {
|
|
287
|
+
runId: ctx.runId,
|
|
288
|
+
workItemId: nodeId,
|
|
289
|
+
detail: { reason: policyDecision.reason, rule_id: policyDecision.rule_id },
|
|
290
|
+
});
|
|
291
|
+
this.blockNode(nodeId, ctx, status, blocked, 'policy_denied', policyDecision.reason);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (policyDecision) {
|
|
295
|
+
this.emit(ctx, {
|
|
296
|
+
type: 'PolicyEvaluated',
|
|
297
|
+
work_item_id: nodeId,
|
|
298
|
+
attempt_id: attemptId,
|
|
299
|
+
payload: { ...policyDecision },
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (policyDecision?.gate_required || node.policy.requires_human_approval) {
|
|
303
|
+
const gateId = await this.requestGateForNode(node, ctx, policyDecision);
|
|
304
|
+
this.blockNode(nodeId, ctx, status, blocked, 'pending_gate', gateId);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
221
307
|
const wsReq = {
|
|
222
308
|
work_item_id: nodeId,
|
|
223
309
|
attempt_number: attempt,
|
|
224
310
|
strategy: node.workspace_strategy,
|
|
225
311
|
mutation_scope: node.mutation_scope,
|
|
226
312
|
};
|
|
227
|
-
|
|
313
|
+
const workspaceManager = ctx.pluginRegistry?.workspaceProviderFor(node.workspace_strategy) ?? ctx.workspaceManager;
|
|
314
|
+
lease = await workspaceManager.allocate(wsReq);
|
|
228
315
|
this.emit(ctx, {
|
|
229
316
|
type: 'WorkspaceAllocated',
|
|
230
317
|
work_item_id: nodeId,
|
|
231
318
|
attempt_id: attemptId,
|
|
232
319
|
payload: { workspace_id: lease.workspace_id, strategy: lease.strategy },
|
|
233
320
|
});
|
|
234
|
-
lastResult = await
|
|
321
|
+
lastResult = await this.executeNode(node, lease, ctx, attempt, attemptId);
|
|
235
322
|
if (lastResult.success) {
|
|
236
323
|
this.emit(ctx, {
|
|
237
324
|
type: 'WorkItemCompleted',
|
|
@@ -246,6 +333,11 @@ class Scheduler {
|
|
|
246
333
|
if (lastResult.failure_class === 'policy')
|
|
247
334
|
break;
|
|
248
335
|
if (attempt < maxAttempts) {
|
|
336
|
+
const retryBlocked = this.consumeRetryQuota(ctx);
|
|
337
|
+
if (retryBlocked) {
|
|
338
|
+
this.blockNode(nodeId, ctx, status, blocked, 'quota_exceeded', retryBlocked);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
249
341
|
this.emit(ctx, {
|
|
250
342
|
type: 'RetryScheduled',
|
|
251
343
|
work_item_id: nodeId,
|
|
@@ -313,6 +405,136 @@ class Scheduler {
|
|
|
313
405
|
static loadJournal(projectRoot, runId) {
|
|
314
406
|
return (0, run_journal_1.loadJournal)(projectRoot, runId);
|
|
315
407
|
}
|
|
408
|
+
async executeNode(node, lease, ctx, attempt, attemptId) {
|
|
409
|
+
const primaryAction = pickPrimaryAction(node, ctx.pluginRegistry);
|
|
410
|
+
const provider = primaryAction ? ctx.pluginRegistry?.toolProviderFor(primaryAction.type) : null;
|
|
411
|
+
if (!provider || !primaryAction) {
|
|
412
|
+
return ctx.executor.execute(node, lease, ctx.runId, attempt);
|
|
413
|
+
}
|
|
414
|
+
ctx.auditTrail?.record('plugin_invoked', ctx.policyActor ?? 'runtime', {
|
|
415
|
+
runId: ctx.runId,
|
|
416
|
+
workItemId: node.id,
|
|
417
|
+
resource: provider.name,
|
|
418
|
+
detail: { action_type: primaryAction.type, attempt_id: attemptId },
|
|
419
|
+
});
|
|
420
|
+
this.emit(ctx, {
|
|
421
|
+
type: 'ToolInvoked',
|
|
422
|
+
work_item_id: node.id,
|
|
423
|
+
attempt_id: attemptId,
|
|
424
|
+
payload: { provider: provider.name, action_type: primaryAction.type },
|
|
425
|
+
});
|
|
426
|
+
const result = await provider.invoke({
|
|
427
|
+
action_type: primaryAction.type,
|
|
428
|
+
work_item_id: node.id,
|
|
429
|
+
run_id: ctx.runId,
|
|
430
|
+
attempt_id: attemptId,
|
|
431
|
+
params: {
|
|
432
|
+
command: primaryAction.command ?? null,
|
|
433
|
+
targets: primaryAction.targets ?? [],
|
|
434
|
+
},
|
|
435
|
+
workspace_root: lease.root_path,
|
|
436
|
+
});
|
|
437
|
+
this.emit(ctx, {
|
|
438
|
+
type: result.success ? 'ToolCompleted' : 'ToolFailed',
|
|
439
|
+
work_item_id: node.id,
|
|
440
|
+
attempt_id: attemptId,
|
|
441
|
+
payload: {
|
|
442
|
+
provider: provider.name,
|
|
443
|
+
action_type: primaryAction.type,
|
|
444
|
+
evidence_paths: result.evidence_paths,
|
|
445
|
+
side_effects_applied: result.side_effects_applied,
|
|
446
|
+
error: result.error ?? null,
|
|
447
|
+
},
|
|
448
|
+
});
|
|
449
|
+
return {
|
|
450
|
+
success: result.success,
|
|
451
|
+
failure_class: result.success ? null : provider.kind === 'external_operation' ? 'policy' : 'env',
|
|
452
|
+
evidence: result.evidence_paths,
|
|
453
|
+
output: result.output,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
evaluatePolicyForNode(node, ctx) {
|
|
457
|
+
if (!ctx.policyEngine)
|
|
458
|
+
return null;
|
|
459
|
+
const primaryAction = pickPrimaryAction(node, ctx.pluginRegistry);
|
|
460
|
+
const decisionContext = {
|
|
461
|
+
tool: primaryAction?.type ?? 'custom',
|
|
462
|
+
kind: node.workspace_strategy,
|
|
463
|
+
mutation_scope: node.mutation_scope,
|
|
464
|
+
affected_paths: node.mutation_scope,
|
|
465
|
+
side_effect_class: inferSideEffectClass(node),
|
|
466
|
+
mutation_count: node.mutation_scope.length,
|
|
467
|
+
node_policy: {
|
|
468
|
+
max_retries: node.policy.max_retries,
|
|
469
|
+
},
|
|
470
|
+
};
|
|
471
|
+
const evaluated = ctx.policyEngine.evaluate(decisionContext);
|
|
472
|
+
const persisted = {
|
|
473
|
+
...evaluated,
|
|
474
|
+
run_id: ctx.runId,
|
|
475
|
+
work_item_id: node.id,
|
|
476
|
+
action: primaryAction?.type ?? 'custom',
|
|
477
|
+
actor: ctx.policyActor ?? 'runtime',
|
|
478
|
+
override: false,
|
|
479
|
+
rationale: null,
|
|
480
|
+
context: decisionContext,
|
|
481
|
+
};
|
|
482
|
+
(0, policy_engine_1.savePolicyDecision)(ctx.projectRoot, persisted);
|
|
483
|
+
return persisted;
|
|
484
|
+
}
|
|
485
|
+
async requestGateForNode(node, ctx, decision) {
|
|
486
|
+
if (!ctx.gateManager)
|
|
487
|
+
return 'gate-missing-manager';
|
|
488
|
+
const scope = inferGateScope(node);
|
|
489
|
+
const primaryAction = pickPrimaryAction(node, ctx.pluginRegistry);
|
|
490
|
+
const gate = await ctx.gateManager.request(scope, {
|
|
491
|
+
run_id: ctx.runId,
|
|
492
|
+
work_item_id: node.id,
|
|
493
|
+
action: primaryAction?.type ?? 'custom',
|
|
494
|
+
description: `Gate required before executing ${node.id}`,
|
|
495
|
+
evidence_refs: [],
|
|
496
|
+
risks: [decision?.reason ?? 'human approval required'],
|
|
497
|
+
rationale: decision?.reason ?? 'node policy requires approval',
|
|
498
|
+
policy_decision_id: decision?.decision_id ?? null,
|
|
499
|
+
});
|
|
500
|
+
if (this.journal && !this.journal.pending_gates.includes(gate.gate_id)) {
|
|
501
|
+
this.journal.pending_gates.push(gate.gate_id);
|
|
502
|
+
}
|
|
503
|
+
ctx.auditTrail?.record('gate_requested', ctx.policyActor ?? 'runtime', {
|
|
504
|
+
runId: ctx.runId,
|
|
505
|
+
workItemId: node.id,
|
|
506
|
+
detail: { gate_id: gate.gate_id, scope: gate.scope, action: gate.action },
|
|
507
|
+
});
|
|
508
|
+
return gate.gate_id;
|
|
509
|
+
}
|
|
510
|
+
blockNode(nodeId, ctx, status, blocked, reason, detail = null) {
|
|
511
|
+
this.emit(ctx, {
|
|
512
|
+
type: 'WorkItemBlocked',
|
|
513
|
+
work_item_id: nodeId,
|
|
514
|
+
payload: { reason, detail },
|
|
515
|
+
});
|
|
516
|
+
status.set(nodeId, 'blocked');
|
|
517
|
+
if (!blocked.includes(nodeId))
|
|
518
|
+
blocked.push(nodeId);
|
|
519
|
+
}
|
|
520
|
+
consumeQuotaForNode(ctx, node) {
|
|
521
|
+
if (!ctx.quota)
|
|
522
|
+
return null;
|
|
523
|
+
let quota = (0, audit_trail_1.consumeQuota)(ctx.quota, 'work_items', 1);
|
|
524
|
+
if (node.mutation_scope.length > 0) {
|
|
525
|
+
quota = (0, audit_trail_1.consumeQuota)(quota, 'mutations', 1);
|
|
526
|
+
}
|
|
527
|
+
const violation = (0, audit_trail_1.checkQuota)(quota);
|
|
528
|
+
ctx.quota = quota;
|
|
529
|
+
return violation ? `${violation.quota_type}:${violation.consumed}/${violation.limit}` : null;
|
|
530
|
+
}
|
|
531
|
+
consumeRetryQuota(ctx) {
|
|
532
|
+
if (!ctx.quota)
|
|
533
|
+
return null;
|
|
534
|
+
ctx.quota = (0, audit_trail_1.consumeQuota)(ctx.quota, 'retries', 1);
|
|
535
|
+
const violation = (0, audit_trail_1.checkQuota)(ctx.quota);
|
|
536
|
+
return violation ? `${violation.quota_type}:${violation.consumed}/${violation.limit}` : null;
|
|
537
|
+
}
|
|
316
538
|
emit(ctx, input) {
|
|
317
539
|
const event = (0, bus_1.appendEvent)(ctx.projectRoot, ctx.sessionId, {
|
|
318
540
|
run_id: ctx.runId,
|
|
@@ -322,3 +544,26 @@ class Scheduler {
|
|
|
322
544
|
}
|
|
323
545
|
}
|
|
324
546
|
exports.Scheduler = Scheduler;
|
|
547
|
+
function inferSideEffectClass(node) {
|
|
548
|
+
if (node.mutation_scope.length > 0)
|
|
549
|
+
return 'write_fs';
|
|
550
|
+
if (node.actions.some((action) => action.type === 'run_tests' || action.type === 'run_lint'))
|
|
551
|
+
return 'spawn_process';
|
|
552
|
+
return 'read_fs';
|
|
553
|
+
}
|
|
554
|
+
function pickPrimaryAction(node, pluginRegistry) {
|
|
555
|
+
const candidateActions = node.actions.filter((action) => action.type !== 'collect_evidence');
|
|
556
|
+
const preferredMutation = candidateActions.find((action) => action.type === 'generate_patch')
|
|
557
|
+
|| candidateActions.find((action) => action.type === 'run_tests')
|
|
558
|
+
|| candidateActions[0];
|
|
559
|
+
if (!pluginRegistry)
|
|
560
|
+
return preferredMutation;
|
|
561
|
+
return candidateActions.find((action) => pluginRegistry.toolProviderFor(action.type)) || preferredMutation;
|
|
562
|
+
}
|
|
563
|
+
function inferGateScope(node) {
|
|
564
|
+
if (node.mutation_scope.length > 0)
|
|
565
|
+
return 'critical_mutation';
|
|
566
|
+
if (node.actions.some((action) => action.type === 'collect_evidence'))
|
|
567
|
+
return 'security';
|
|
568
|
+
return 'plan_approval';
|
|
569
|
+
}
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { EvidenceType } from '../models/evidence';
|
|
2
2
|
import type { VerificationStatus } from '../models/verification-result';
|
|
3
|
+
import type { VerificationResult } from '../models/verification-result';
|
|
4
|
+
import type { EvidenceStore } from '../evidence/evidence-store';
|
|
5
|
+
import type { PluginRegistry } from '../plugins/plugin-registry';
|
|
6
|
+
import { type EvidenceCoverageSummary, type ResidualRiskLedger, type VerificationManifest } from './verification-manifest';
|
|
3
7
|
export type CheckType = 'unit' | 'integration' | 'contract' | 'smoke' | 'policy' | 'security' | 'ux_snapshot' | 'performance_baseline' | 'custom';
|
|
4
8
|
export interface AcceptanceCheck {
|
|
5
9
|
id: string;
|
|
@@ -24,6 +28,26 @@ export interface CheckResult {
|
|
|
24
28
|
exit_code: number | null;
|
|
25
29
|
duration_ms: number;
|
|
26
30
|
error: string | null;
|
|
31
|
+
evidence_refs?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface ExecutedVerificationSuite {
|
|
34
|
+
results: CheckResult[];
|
|
35
|
+
verification_results: VerificationResult[];
|
|
36
|
+
evidence_refs: Map<string, string[]>;
|
|
37
|
+
manifest: VerificationManifest;
|
|
38
|
+
risk_ledger: ResidualRiskLedger;
|
|
39
|
+
evidence_coverage: EvidenceCoverageSummary;
|
|
40
|
+
}
|
|
41
|
+
export interface VerifyRunResult {
|
|
42
|
+
status: 'passed' | 'failed' | 'partial';
|
|
43
|
+
suite: AcceptanceCheckSuite;
|
|
44
|
+
executed: ExecutedVerificationSuite | null;
|
|
45
|
+
gaps: string[];
|
|
46
|
+
verification_results: VerificationResult[];
|
|
47
|
+
check_results: CheckResult[];
|
|
48
|
+
manifest: VerificationManifest | null;
|
|
49
|
+
risk_ledger: ResidualRiskLedger | null;
|
|
50
|
+
evidence_coverage: EvidenceCoverageSummary | null;
|
|
27
51
|
}
|
|
28
52
|
interface Criterion {
|
|
29
53
|
id: string;
|
|
@@ -45,6 +69,14 @@ interface ParsedPlanLike {
|
|
|
45
69
|
export declare function compile(spec: ParsedSpecLike, plan: ParsedPlanLike): AcceptanceCheckSuite;
|
|
46
70
|
export declare function runCheck(check: AcceptanceCheck, cwd: string, timeoutMs?: number): Promise<CheckResult>;
|
|
47
71
|
export declare function runSuite(suite: AcceptanceCheckSuite, cwd: string, timeoutMs?: number): Promise<CheckResult[]>;
|
|
72
|
+
export declare function executeSuite(suite: AcceptanceCheckSuite, cwd: string, options: {
|
|
73
|
+
timeoutMs?: number;
|
|
74
|
+
runId: string;
|
|
75
|
+
workItemId: string;
|
|
76
|
+
attemptNumber?: number;
|
|
77
|
+
evidenceStore?: EvidenceStore;
|
|
78
|
+
pluginRegistry?: PluginRegistry;
|
|
79
|
+
}): Promise<ExecutedVerificationSuite>;
|
|
48
80
|
export declare function summarizeSuite(results: CheckResult[]): {
|
|
49
81
|
total: number;
|
|
50
82
|
pass: number;
|
|
@@ -53,4 +85,15 @@ export declare function summarizeSuite(results: CheckResult[]): {
|
|
|
53
85
|
error: number;
|
|
54
86
|
allPassed: boolean;
|
|
55
87
|
};
|
|
88
|
+
export declare function verifyRun(input: {
|
|
89
|
+
projectRoot: string;
|
|
90
|
+
runId: string;
|
|
91
|
+
workItemId: string;
|
|
92
|
+
cwd: string;
|
|
93
|
+
suite: AcceptanceCheckSuite;
|
|
94
|
+
pluginRegistry?: PluginRegistry;
|
|
95
|
+
evidenceStore?: EvidenceStore;
|
|
96
|
+
attemptNumber?: number;
|
|
97
|
+
timeoutMs?: number;
|
|
98
|
+
}): Promise<VerifyRunResult>;
|
|
56
99
|
export {};
|
|
@@ -6,9 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.compile = compile;
|
|
7
7
|
exports.runCheck = runCheck;
|
|
8
8
|
exports.runSuite = runSuite;
|
|
9
|
+
exports.executeSuite = executeSuite;
|
|
9
10
|
exports.summarizeSuite = summarizeSuite;
|
|
11
|
+
exports.verifyRun = verifyRun;
|
|
10
12
|
const crypto_1 = __importDefault(require("crypto"));
|
|
11
13
|
const child_process_1 = require("child_process");
|
|
14
|
+
const verification_manifest_1 = require("./verification-manifest");
|
|
12
15
|
function inferCheckType(howToVerify) {
|
|
13
16
|
const v = howToVerify.toLowerCase();
|
|
14
17
|
if (v.includes('npm test') || v.includes('jest') || v.includes('vitest') || v.includes('node --test'))
|
|
@@ -132,12 +135,125 @@ async function runSuite(suite, cwd, timeoutMs = 60000) {
|
|
|
132
135
|
}
|
|
133
136
|
return results;
|
|
134
137
|
}
|
|
138
|
+
async function executeSuite(suite, cwd, options) {
|
|
139
|
+
const results = [];
|
|
140
|
+
const verificationResults = [];
|
|
141
|
+
const evidenceRefs = new Map();
|
|
142
|
+
const timeoutMs = options.timeoutMs ?? 60000;
|
|
143
|
+
const attemptNumber = options.attemptNumber ?? 1;
|
|
144
|
+
for (const check of suite.checks) {
|
|
145
|
+
const provider = options.pluginRegistry?.verifierProviderFor(check.type);
|
|
146
|
+
let result;
|
|
147
|
+
let verificationResult;
|
|
148
|
+
if (provider) {
|
|
149
|
+
const providerResult = await provider.execute({
|
|
150
|
+
check_id: check.id,
|
|
151
|
+
check_type: check.type,
|
|
152
|
+
command: check.command,
|
|
153
|
+
work_item_id: options.workItemId,
|
|
154
|
+
workspace_root: cwd,
|
|
155
|
+
evidence_dir: '',
|
|
156
|
+
});
|
|
157
|
+
result = {
|
|
158
|
+
check_id: check.id,
|
|
159
|
+
acceptance_ref: check.acceptance_ref,
|
|
160
|
+
status: providerResult.status,
|
|
161
|
+
stdout: providerResult.summary ?? '',
|
|
162
|
+
stderr: '',
|
|
163
|
+
exit_code: providerResult.status === 'pass' ? 0 : 1,
|
|
164
|
+
duration_ms: 0,
|
|
165
|
+
error: providerResult.status === 'error' ? providerResult.summary ?? 'provider error' : null,
|
|
166
|
+
evidence_refs: providerResult.evidence_refs,
|
|
167
|
+
};
|
|
168
|
+
verificationResult = providerResult;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
result = await runCheck(check, cwd, timeoutMs);
|
|
172
|
+
const collectedEvidence = options.evidenceStore
|
|
173
|
+
? await collectCheckEvidence(options.evidenceStore, check, result, {
|
|
174
|
+
run_id: options.runId,
|
|
175
|
+
work_item_id: options.workItemId,
|
|
176
|
+
attempt_number: attemptNumber,
|
|
177
|
+
})
|
|
178
|
+
: [];
|
|
179
|
+
result.evidence_refs = collectedEvidence;
|
|
180
|
+
verificationResult = {
|
|
181
|
+
verification_id: `vr-${crypto_1.default.randomBytes(4).toString('hex')}`,
|
|
182
|
+
work_item_id: options.workItemId,
|
|
183
|
+
check_id: check.id,
|
|
184
|
+
status: result.status,
|
|
185
|
+
evidence_refs: collectedEvidence,
|
|
186
|
+
summary: result.error || result.stderr || result.stdout || null,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (result.evidence_refs && result.evidence_refs.length > 0) {
|
|
190
|
+
evidenceRefs.set(check.id, result.evidence_refs);
|
|
191
|
+
}
|
|
192
|
+
results.push(result);
|
|
193
|
+
verificationResults.push(verificationResult);
|
|
194
|
+
}
|
|
195
|
+
const manifest = (0, verification_manifest_1.buildManifest)(options.runId, results, {
|
|
196
|
+
workItemId: options.workItemId,
|
|
197
|
+
granularity: 'work_item',
|
|
198
|
+
evidenceRefs,
|
|
199
|
+
});
|
|
200
|
+
const riskLedger = (0, verification_manifest_1.buildRiskLedger)(options.runId, manifest);
|
|
201
|
+
const evidenceCoverage = (0, verification_manifest_1.summarizeEvidenceCoverage)(manifest);
|
|
202
|
+
return {
|
|
203
|
+
results,
|
|
204
|
+
verification_results: verificationResults,
|
|
205
|
+
evidence_refs: evidenceRefs,
|
|
206
|
+
manifest,
|
|
207
|
+
risk_ledger: riskLedger,
|
|
208
|
+
evidence_coverage: evidenceCoverage,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
135
211
|
function summarizeSuite(results) {
|
|
136
212
|
const counts = { total: results.length, pass: 0, fail: 0, skip: 0, error: 0 };
|
|
137
213
|
for (const r of results)
|
|
138
214
|
counts[r.status]++;
|
|
139
215
|
return { ...counts, allPassed: counts.fail === 0 && counts.error === 0 };
|
|
140
216
|
}
|
|
217
|
+
async function verifyRun(input) {
|
|
218
|
+
const gaps = [];
|
|
219
|
+
if (!input.suite || !Array.isArray(input.suite.checks) || input.suite.checks.length === 0) {
|
|
220
|
+
gaps.push('Nenhum check executável foi compilado a partir de SPEC/PLAN.');
|
|
221
|
+
return {
|
|
222
|
+
status: 'partial',
|
|
223
|
+
suite: input.suite,
|
|
224
|
+
executed: null,
|
|
225
|
+
gaps,
|
|
226
|
+
verification_results: [],
|
|
227
|
+
check_results: [],
|
|
228
|
+
manifest: null,
|
|
229
|
+
risk_ledger: null,
|
|
230
|
+
evidence_coverage: null,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
const executed = await executeSuite(input.suite, input.cwd, {
|
|
234
|
+
timeoutMs: input.timeoutMs,
|
|
235
|
+
runId: input.runId,
|
|
236
|
+
workItemId: input.workItemId,
|
|
237
|
+
attemptNumber: input.attemptNumber,
|
|
238
|
+
evidenceStore: input.evidenceStore,
|
|
239
|
+
pluginRegistry: input.pluginRegistry,
|
|
240
|
+
});
|
|
241
|
+
(0, verification_manifest_1.saveManifest)(input.projectRoot, input.runId, executed.manifest);
|
|
242
|
+
(0, verification_manifest_1.saveRiskLedger)(input.projectRoot, input.runId, executed.risk_ledger);
|
|
243
|
+
(0, verification_manifest_1.saveEvidenceCoverage)(input.projectRoot, input.runId, executed.evidence_coverage);
|
|
244
|
+
const summary = summarizeSuite(executed.results);
|
|
245
|
+
return {
|
|
246
|
+
status: summary.total === 0 ? 'partial' : summary.allPassed ? 'passed' : 'failed',
|
|
247
|
+
suite: input.suite,
|
|
248
|
+
executed,
|
|
249
|
+
gaps,
|
|
250
|
+
verification_results: executed.verification_results,
|
|
251
|
+
check_results: executed.results,
|
|
252
|
+
manifest: executed.manifest,
|
|
253
|
+
risk_ledger: executed.risk_ledger,
|
|
254
|
+
evidence_coverage: executed.evidence_coverage,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
141
257
|
function hashObject(obj) {
|
|
142
258
|
return crypto_1.default
|
|
143
259
|
.createHash('sha256')
|
|
@@ -145,3 +261,24 @@ function hashObject(obj) {
|
|
|
145
261
|
.digest('hex')
|
|
146
262
|
.slice(0, 12);
|
|
147
263
|
}
|
|
264
|
+
async function collectCheckEvidence(store, check, result, options) {
|
|
265
|
+
const refs = [];
|
|
266
|
+
if (result.stdout) {
|
|
267
|
+
const evidence = await store.collect('stdout', result.stdout, options);
|
|
268
|
+
refs.push(evidence.evidence_id);
|
|
269
|
+
}
|
|
270
|
+
if (result.stderr) {
|
|
271
|
+
const evidence = await store.collect('stderr', result.stderr, options);
|
|
272
|
+
refs.push(evidence.evidence_id);
|
|
273
|
+
}
|
|
274
|
+
const summaryEvidence = await store.collect(check.evidence_type_expected, JSON.stringify({
|
|
275
|
+
check_id: check.id,
|
|
276
|
+
type: check.type,
|
|
277
|
+
command: check.command,
|
|
278
|
+
status: result.status,
|
|
279
|
+
exit_code: result.exit_code,
|
|
280
|
+
duration_ms: result.duration_ms,
|
|
281
|
+
}, null, 2), options);
|
|
282
|
+
refs.push(summaryEvidence.evidence_id);
|
|
283
|
+
return refs;
|
|
284
|
+
}
|
|
@@ -43,6 +43,12 @@ export interface ResidualRiskLedger {
|
|
|
43
43
|
generated_at: string;
|
|
44
44
|
risks: ResidualRisk[];
|
|
45
45
|
}
|
|
46
|
+
export interface EvidenceCoverageSummary {
|
|
47
|
+
total_checks: number;
|
|
48
|
+
checks_with_evidence: number;
|
|
49
|
+
total_evidence_refs: number;
|
|
50
|
+
coverage_percent: number;
|
|
51
|
+
}
|
|
46
52
|
export declare function classifyFailure(result: CheckResult): FailureClass | null;
|
|
47
53
|
export declare function buildManifest(runId: string, results: CheckResult[], options?: {
|
|
48
54
|
workItemId?: string;
|
|
@@ -52,7 +58,10 @@ export declare function buildManifest(runId: string, results: CheckResult[], opt
|
|
|
52
58
|
evidenceRefs?: Map<string, string[]>;
|
|
53
59
|
}): VerificationManifest;
|
|
54
60
|
export declare function buildRiskLedger(runId: string, manifest: VerificationManifest): ResidualRiskLedger;
|
|
61
|
+
export declare function summarizeEvidenceCoverage(manifest: VerificationManifest): EvidenceCoverageSummary;
|
|
55
62
|
export declare function saveManifest(projectRoot: string, runId: string, manifest: VerificationManifest): void;
|
|
56
63
|
export declare function loadManifest(projectRoot: string, runId: string): VerificationManifest | null;
|
|
57
64
|
export declare function saveRiskLedger(projectRoot: string, runId: string, ledger: ResidualRiskLedger): void;
|
|
58
65
|
export declare function loadRiskLedger(projectRoot: string, runId: string): ResidualRiskLedger | null;
|
|
66
|
+
export declare function saveEvidenceCoverage(projectRoot: string, runId: string, coverage: EvidenceCoverageSummary): void;
|
|
67
|
+
export declare function loadEvidenceCoverage(projectRoot: string, runId: string): EvidenceCoverageSummary | null;
|