@substrate-ai/sdlc 0.20.3 → 0.20.5
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/dist/run-model/index.d.ts +2 -2
- package/dist/run-model/index.d.ts.map +1 -1
- package/dist/run-model/index.js +2 -1
- package/dist/run-model/index.js.map +1 -1
- package/dist/run-model/per-story-state.d.ts +16 -2
- package/dist/run-model/per-story-state.d.ts.map +1 -1
- package/dist/run-model/schemas.d.ts +16 -2
- package/dist/run-model/schemas.d.ts.map +1 -1
- package/dist/run-model/verification-result.d.ts +53 -3
- package/dist/run-model/verification-result.d.ts.map +1 -1
- package/dist/run-model/verification-result.js +28 -0
- package/dist/run-model/verification-result.js.map +1 -1
- package/dist/verification/checks/acceptance-criteria-evidence-check.d.ts.map +1 -1
- package/dist/verification/checks/acceptance-criteria-evidence-check.js +65 -8
- package/dist/verification/checks/acceptance-criteria-evidence-check.js.map +1 -1
- package/dist/verification/checks/build-check.d.ts.map +1 -1
- package/dist/verification/checks/build-check.js +64 -8
- package/dist/verification/checks/build-check.js.map +1 -1
- package/dist/verification/checks/index.d.ts +4 -1
- package/dist/verification/checks/index.d.ts.map +1 -1
- package/dist/verification/checks/index.js +3 -1
- package/dist/verification/checks/index.js.map +1 -1
- package/dist/verification/checks/phantom-review-check.d.ts.map +1 -1
- package/dist/verification/checks/phantom-review-check.js +21 -2
- package/dist/verification/checks/phantom-review-check.js.map +1 -1
- package/dist/verification/checks/runtime-probe-check.d.ts +43 -0
- package/dist/verification/checks/runtime-probe-check.d.ts.map +1 -0
- package/dist/verification/checks/runtime-probe-check.js +152 -0
- package/dist/verification/checks/runtime-probe-check.js.map +1 -0
- package/dist/verification/checks/trivial-output-check.d.ts.map +1 -1
- package/dist/verification/checks/trivial-output-check.js +21 -3
- package/dist/verification/checks/trivial-output-check.js.map +1 -1
- package/dist/verification/findings.d.ts +61 -0
- package/dist/verification/findings.d.ts.map +1 -0
- package/dist/verification/findings.js +39 -0
- package/dist/verification/findings.js.map +1 -0
- package/dist/verification/index.d.ts +6 -1
- package/dist/verification/index.d.ts.map +1 -1
- package/dist/verification/index.js +4 -0
- package/dist/verification/index.js.map +1 -1
- package/dist/verification/probes/executor.d.ts +39 -0
- package/dist/verification/probes/executor.d.ts.map +1 -0
- package/dist/verification/probes/executor.js +109 -0
- package/dist/verification/probes/executor.js.map +1 -0
- package/dist/verification/probes/index.d.ts +14 -0
- package/dist/verification/probes/index.d.ts.map +1 -0
- package/dist/verification/probes/index.js +12 -0
- package/dist/verification/probes/index.js.map +1 -0
- package/dist/verification/probes/parser.d.ts +26 -0
- package/dist/verification/probes/parser.d.ts.map +1 -0
- package/dist/verification/probes/parser.js +134 -0
- package/dist/verification/probes/parser.js.map +1 -0
- package/dist/verification/probes/types.d.ts +122 -0
- package/dist/verification/probes/types.d.ts.map +1 -0
- package/dist/verification/probes/types.js +68 -0
- package/dist/verification/probes/types.js.map +1 -0
- package/dist/verification/types.d.ts +10 -1
- package/dist/verification/types.d.ts.map +1 -1
- package/dist/verification/verification-pipeline.d.ts +3 -1
- package/dist/verification/verification-pipeline.d.ts.map +1 -1
- package/dist/verification/verification-pipeline.js +20 -2
- package/dist/verification/verification-pipeline.js.map +1 -1
- package/package.json +6 -3
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host-sandbox probe executor — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* Runs one runtime probe directly on the operator machine via a detached
|
|
5
|
+
* shell process, with stream-separated capture and a hard timeout that
|
|
6
|
+
* terminates the entire process group. Same safety posture as BuildCheck —
|
|
7
|
+
* specifically the detached-process-group + SIGKILL-on-timeout pattern —
|
|
8
|
+
* so probe execution cannot orphan long-running descendants.
|
|
9
|
+
*
|
|
10
|
+
* Twin-sandbox execution is **deferred to Phase 3** (Digital Twin
|
|
11
|
+
* integration). RuntimeProbeCheck handles the `sandbox: twin` case itself
|
|
12
|
+
* without routing through this module.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn } from 'node:child_process';
|
|
15
|
+
import { DEFAULT_PROBE_TIMEOUT_MS, PROBE_TAIL_BYTES, } from './types.js';
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Helpers
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/** Return the last N bytes of a UTF-8 string (sliced by length for simplicity). */
|
|
20
|
+
function tail(text, bytes = PROBE_TAIL_BYTES) {
|
|
21
|
+
return text.length <= bytes ? text : text.slice(text.length - bytes);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Execute one probe on the host and return a structured ProbeResult.
|
|
25
|
+
*
|
|
26
|
+
* Behavior notes:
|
|
27
|
+
* - The shell used is `/bin/sh -c '<probe.command>'` inside a detached
|
|
28
|
+
* process group (so the entire tree is killed on timeout).
|
|
29
|
+
* - stdout and stderr are captured independently; each is returned
|
|
30
|
+
* tailed to PROBE_TAIL_BYTES (≤ 4 KiB) so published tarballs of the
|
|
31
|
+
* run manifest stay small.
|
|
32
|
+
* - Timeout defaults to `probe.timeout_ms ?? DEFAULT_PROBE_TIMEOUT_MS`
|
|
33
|
+
* (60 s). When the timeout fires, the process group is SIGKILL'd and
|
|
34
|
+
* the returned result has `outcome: 'timeout'`, `exitCode` undefined.
|
|
35
|
+
* - Never throws. Spawn errors (e.g. exec format error) are returned as
|
|
36
|
+
* `outcome: 'fail'` with exitCode -1 and the error message captured on
|
|
37
|
+
* stderrTail, so the caller can emit a deterministic finding.
|
|
38
|
+
*/
|
|
39
|
+
export function executeProbeOnHost(probe, options = {}) {
|
|
40
|
+
const timeoutMs = probe.timeout_ms ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
41
|
+
const cwd = options.cwd ?? process.cwd();
|
|
42
|
+
const env = options.env ?? process.env;
|
|
43
|
+
const start = Date.now();
|
|
44
|
+
return new Promise((resolve) => {
|
|
45
|
+
let stdout = '';
|
|
46
|
+
let stderr = '';
|
|
47
|
+
let settled = false;
|
|
48
|
+
const child = spawn(probe.command, [], {
|
|
49
|
+
cwd,
|
|
50
|
+
env,
|
|
51
|
+
detached: true,
|
|
52
|
+
shell: true,
|
|
53
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
54
|
+
});
|
|
55
|
+
const finalize = (result) => {
|
|
56
|
+
if (settled)
|
|
57
|
+
return;
|
|
58
|
+
settled = true;
|
|
59
|
+
resolve(result);
|
|
60
|
+
};
|
|
61
|
+
child.on('error', (err) => {
|
|
62
|
+
// spawn error (ENOENT, EACCES, EMFILE, etc.) — never reach 'close'.
|
|
63
|
+
finalize({
|
|
64
|
+
outcome: 'fail',
|
|
65
|
+
command: probe.command,
|
|
66
|
+
exitCode: -1,
|
|
67
|
+
stdoutTail: tail(stdout),
|
|
68
|
+
stderrTail: tail(stderr + (stderr.length > 0 && !stderr.endsWith('\n') ? '\n' : '') + `spawn error: ${err.message}\n`),
|
|
69
|
+
durationMs: Date.now() - start,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
child.stdout?.on('data', (chunk) => {
|
|
73
|
+
stdout += chunk.toString();
|
|
74
|
+
});
|
|
75
|
+
child.stderr?.on('data', (chunk) => {
|
|
76
|
+
stderr += chunk.toString();
|
|
77
|
+
});
|
|
78
|
+
const timeoutHandle = setTimeout(() => {
|
|
79
|
+
try {
|
|
80
|
+
if (child.pid !== undefined) {
|
|
81
|
+
process.kill(-child.pid, 'SIGKILL');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Process already exited between timeout fire and kill call.
|
|
86
|
+
}
|
|
87
|
+
finalize({
|
|
88
|
+
outcome: 'timeout',
|
|
89
|
+
command: probe.command,
|
|
90
|
+
stdoutTail: tail(stdout),
|
|
91
|
+
stderrTail: tail(stderr),
|
|
92
|
+
durationMs: Date.now() - start,
|
|
93
|
+
});
|
|
94
|
+
}, timeoutMs);
|
|
95
|
+
child.on('close', (code) => {
|
|
96
|
+
clearTimeout(timeoutHandle);
|
|
97
|
+
const duration = Date.now() - start;
|
|
98
|
+
finalize({
|
|
99
|
+
outcome: code === 0 ? 'pass' : 'fail',
|
|
100
|
+
command: probe.command,
|
|
101
|
+
...(code !== null ? { exitCode: code } : {}),
|
|
102
|
+
stdoutTail: tail(stdout),
|
|
103
|
+
stderrTail: tail(stderr),
|
|
104
|
+
durationMs: duration,
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/verification/probes/executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime probe public surface — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the parser, executor, and supporting types. The actual
|
|
5
|
+
* VerificationCheck implementation lives in ../checks/runtime-probe-check.ts
|
|
6
|
+
* to keep the existing `checks/` directory as the canonical location for
|
|
7
|
+
* all VerificationCheck subclasses.
|
|
8
|
+
*/
|
|
9
|
+
export { DEFAULT_PROBE_TIMEOUT_MS, PROBE_TAIL_BYTES, RuntimeProbeListSchema, RuntimeProbeSandboxSchema, RuntimeProbeSchema, } from './types.js';
|
|
10
|
+
export type { ProbeResult, RuntimeProbe, RuntimeProbeParseResult, RuntimeProbeSandbox, } from './types.js';
|
|
11
|
+
export { parseRuntimeProbes } from './parser.js';
|
|
12
|
+
export { executeProbeOnHost } from './executor.js';
|
|
13
|
+
export type { HostExecuteOptions } from './executor.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/verification/probes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime probe public surface — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the parser, executor, and supporting types. The actual
|
|
5
|
+
* VerificationCheck implementation lives in ../checks/runtime-probe-check.ts
|
|
6
|
+
* to keep the existing `checks/` directory as the canonical location for
|
|
7
|
+
* all VerificationCheck subclasses.
|
|
8
|
+
*/
|
|
9
|
+
export { DEFAULT_PROBE_TIMEOUT_MS, PROBE_TAIL_BYTES, RuntimeProbeListSchema, RuntimeProbeSandboxSchema, RuntimeProbeSchema, } from './types.js';
|
|
10
|
+
export { parseRuntimeProbes } from './parser.js';
|
|
11
|
+
export { executeProbeOnHost } from './executor.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/verification/probes/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,sBAAsB,EACtB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,YAAY,CAAA;AAQnB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAEhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime probe parser — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* Locates the `## Runtime Probes` section in a story's markdown content and
|
|
5
|
+
* extracts any probe declarations contained in a `yaml` code fence inside
|
|
6
|
+
* it. Never throws: every failure mode is returned as a RuntimeProbeParseResult
|
|
7
|
+
* variant so the VerificationCheck can emit a structured finding rather than
|
|
8
|
+
* crash the verification pipeline.
|
|
9
|
+
*/
|
|
10
|
+
import { type RuntimeProbeParseResult } from './types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Parse the `## Runtime Probes` section of a story's markdown content.
|
|
13
|
+
*
|
|
14
|
+
* Outcomes:
|
|
15
|
+
* - section missing → { kind: 'absent' }
|
|
16
|
+
* - section present, no yaml fence → { kind: 'invalid' }
|
|
17
|
+
* - section present, yaml fence malformed → { kind: 'invalid' }
|
|
18
|
+
* - section present, yaml root is not a list → { kind: 'invalid' }
|
|
19
|
+
* - section present, entry fails RuntimeProbeSchema → { kind: 'invalid' }
|
|
20
|
+
* - section present, yaml valid, all entries valid → { kind: 'parsed' }
|
|
21
|
+
*
|
|
22
|
+
* Duplicate names within a single story are surfaced as `invalid` so that
|
|
23
|
+
* finding messages can unambiguously reference a probe by name.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseRuntimeProbes(storyContent: string): RuntimeProbeParseResult;
|
|
26
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/verification/probes/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,YAAY,CAAA;AAmEnB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAsDhF"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime probe parser — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* Locates the `## Runtime Probes` section in a story's markdown content and
|
|
5
|
+
* extracts any probe declarations contained in a `yaml` code fence inside
|
|
6
|
+
* it. Never throws: every failure mode is returned as a RuntimeProbeParseResult
|
|
7
|
+
* variant so the VerificationCheck can emit a structured finding rather than
|
|
8
|
+
* crash the verification pipeline.
|
|
9
|
+
*/
|
|
10
|
+
import { load as yamlLoad, YAMLException } from 'js-yaml';
|
|
11
|
+
import { RuntimeProbeListSchema, } from './types.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Section extraction
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
const SECTION_HEADING = /^##\s+Runtime\s+Probes\s*$/i;
|
|
16
|
+
/**
|
|
17
|
+
* Return the raw text of the story's `## Runtime Probes` section (excluding
|
|
18
|
+
* the heading line itself), or `undefined` if the section is not present.
|
|
19
|
+
*
|
|
20
|
+
* The section ends at the next `##` heading or end-of-file. Sub-headings
|
|
21
|
+
* (`###`, `####`) remain part of the section body.
|
|
22
|
+
*/
|
|
23
|
+
function extractRuntimeProbesSection(storyContent) {
|
|
24
|
+
const lines = storyContent.split(/\r?\n/);
|
|
25
|
+
const start = lines.findIndex((line) => SECTION_HEADING.test(line.trim()));
|
|
26
|
+
if (start === -1)
|
|
27
|
+
return undefined;
|
|
28
|
+
let end = lines.length;
|
|
29
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
30
|
+
if (/^##\s+\S/.test(lines[i] ?? '')) {
|
|
31
|
+
end = i;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return lines.slice(start + 1, end).join('\n');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Extract the body of the first ```yaml (or ```yml) fenced block in the
|
|
39
|
+
* given section text. Returns `undefined` if no yaml fence is present.
|
|
40
|
+
*
|
|
41
|
+
* The opening fence is recognized case-insensitively and may carry an
|
|
42
|
+
* arbitrary trailing info string (e.g. ```yaml title=...). The closing
|
|
43
|
+
* fence is any line whose first non-whitespace run is exactly three
|
|
44
|
+
* backticks.
|
|
45
|
+
*/
|
|
46
|
+
function extractYamlFence(section) {
|
|
47
|
+
const lines = section.split(/\r?\n/);
|
|
48
|
+
let inside = false;
|
|
49
|
+
let collected;
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
if (!inside) {
|
|
52
|
+
if (/^\s*```\s*(yaml|yml)\b/i.test(line)) {
|
|
53
|
+
inside = true;
|
|
54
|
+
collected = [];
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// inside a yaml fence
|
|
59
|
+
if (/^\s*```\s*$/.test(line)) {
|
|
60
|
+
return (collected ?? []).join('\n');
|
|
61
|
+
}
|
|
62
|
+
collected?.push(line);
|
|
63
|
+
}
|
|
64
|
+
// Unterminated fence → treat as missing; the caller surfaces this as an
|
|
65
|
+
// `invalid` parse result with a clear message.
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// parseRuntimeProbes — public entry point
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/**
|
|
72
|
+
* Parse the `## Runtime Probes` section of a story's markdown content.
|
|
73
|
+
*
|
|
74
|
+
* Outcomes:
|
|
75
|
+
* - section missing → { kind: 'absent' }
|
|
76
|
+
* - section present, no yaml fence → { kind: 'invalid' }
|
|
77
|
+
* - section present, yaml fence malformed → { kind: 'invalid' }
|
|
78
|
+
* - section present, yaml root is not a list → { kind: 'invalid' }
|
|
79
|
+
* - section present, entry fails RuntimeProbeSchema → { kind: 'invalid' }
|
|
80
|
+
* - section present, yaml valid, all entries valid → { kind: 'parsed' }
|
|
81
|
+
*
|
|
82
|
+
* Duplicate names within a single story are surfaced as `invalid` so that
|
|
83
|
+
* finding messages can unambiguously reference a probe by name.
|
|
84
|
+
*/
|
|
85
|
+
export function parseRuntimeProbes(storyContent) {
|
|
86
|
+
const section = extractRuntimeProbesSection(storyContent);
|
|
87
|
+
if (section === undefined) {
|
|
88
|
+
return { kind: 'absent' };
|
|
89
|
+
}
|
|
90
|
+
const yamlBody = extractYamlFence(section);
|
|
91
|
+
if (yamlBody === undefined) {
|
|
92
|
+
return {
|
|
93
|
+
kind: 'invalid',
|
|
94
|
+
error: '## Runtime Probes section is present but contains no terminated ```yaml fenced block',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
let parsed;
|
|
98
|
+
try {
|
|
99
|
+
parsed = yamlLoad(yamlBody) ?? [];
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
const detail = err instanceof YAMLException ? err.message : String(err);
|
|
103
|
+
return { kind: 'invalid', error: `YAML parse error: ${detail}` };
|
|
104
|
+
}
|
|
105
|
+
if (!Array.isArray(parsed)) {
|
|
106
|
+
return {
|
|
107
|
+
kind: 'invalid',
|
|
108
|
+
error: `probe block root must be a YAML list; got ${typeof parsed}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const validation = RuntimeProbeListSchema.safeParse(parsed);
|
|
112
|
+
if (!validation.success) {
|
|
113
|
+
const first = validation.error.issues[0];
|
|
114
|
+
const path = first?.path.join('.') ?? '';
|
|
115
|
+
const message = first?.message ?? 'schema validation failed';
|
|
116
|
+
return {
|
|
117
|
+
kind: 'invalid',
|
|
118
|
+
error: `probe list is malformed at ${path || '<root>'}: ${message}`,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const probes = validation.data;
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
for (const probe of probes) {
|
|
124
|
+
if (seen.has(probe.name)) {
|
|
125
|
+
return {
|
|
126
|
+
kind: 'invalid',
|
|
127
|
+
error: `duplicate probe name: ${probe.name}`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
seen.add(probe.name);
|
|
131
|
+
}
|
|
132
|
+
return { kind: 'parsed', probes };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../../src/verification/probes/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime probe types — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* A "runtime probe" is an author-declared executable command that the
|
|
5
|
+
* verification pipeline runs against a real or ephemeral target environment
|
|
6
|
+
* to answer the question "does the artifact this story produced actually
|
|
7
|
+
* work?". Runtime probes exist specifically to catch the class of bugs that
|
|
8
|
+
* static shape-gates (phantom-review, trivial-output, ac-evidence, build)
|
|
9
|
+
* cannot — runtime misconfiguration, wrong image paths, systemd semantics,
|
|
10
|
+
* credential issues, and so on.
|
|
11
|
+
*
|
|
12
|
+
* This file defines the data shape; parsing lives in ./parser.ts, execution
|
|
13
|
+
* lives in ./executor.ts, and the VerificationCheck implementation lives in
|
|
14
|
+
* ../checks/runtime-probe-check.ts.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
/**
|
|
18
|
+
* Execution sandbox for a runtime probe.
|
|
19
|
+
*
|
|
20
|
+
* - `host`: probe runs directly on the operator's machine. Explicit opt-in.
|
|
21
|
+
* Cheapest; most dangerous. Authors choosing `host` acknowledge the probe
|
|
22
|
+
* may touch host state (ports, systemd units, filesystem) and take
|
|
23
|
+
* responsibility for cleanup.
|
|
24
|
+
* - `twin`: probe runs inside an ephemeral sandbox brokered by the Digital
|
|
25
|
+
* Twin subsystem (Epic 47). Twin integration is **deferred to Phase 3** —
|
|
26
|
+
* probes with `sandbox: twin` currently emit a `probe-deferred` warn
|
|
27
|
+
* finding rather than executing. Authors can declare twin-scoped probes
|
|
28
|
+
* today and they will execute transparently once Phase 3 lands.
|
|
29
|
+
*/
|
|
30
|
+
export declare const RuntimeProbeSandboxSchema: z.ZodEnum<{
|
|
31
|
+
host: "host";
|
|
32
|
+
twin: "twin";
|
|
33
|
+
}>;
|
|
34
|
+
export type RuntimeProbeSandbox = z.infer<typeof RuntimeProbeSandboxSchema>;
|
|
35
|
+
/**
|
|
36
|
+
* Default per-probe timeout in milliseconds. Matches the existing
|
|
37
|
+
* BuildCheck ceiling (60 s) — deliberate, so probe timeouts are bounded
|
|
38
|
+
* by the same policy the pipeline already uses for long-running checks.
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_PROBE_TIMEOUT_MS = 60000;
|
|
41
|
+
/** Hard upper bound on per-probe stdout/stderr retention (≤ 4 KiB — the
|
|
42
|
+
* same convention as VerificationFinding.{stdoutTail,stderrTail}). */
|
|
43
|
+
export declare const PROBE_TAIL_BYTES: number;
|
|
44
|
+
/**
|
|
45
|
+
* Zod schema for one runtime probe declared in a story's
|
|
46
|
+
* `## Runtime Probes` section.
|
|
47
|
+
*
|
|
48
|
+
* Required fields (`name`, `sandbox`, `command`) force authors to make
|
|
49
|
+
* intent explicit — no silent defaults that could mask a miswritten probe.
|
|
50
|
+
* Optional fields cover operational knobs with sensible fallbacks.
|
|
51
|
+
*/
|
|
52
|
+
export declare const RuntimeProbeSchema: z.ZodObject<{
|
|
53
|
+
name: z.ZodString;
|
|
54
|
+
sandbox: z.ZodEnum<{
|
|
55
|
+
host: "host";
|
|
56
|
+
twin: "twin";
|
|
57
|
+
}>;
|
|
58
|
+
command: z.ZodString;
|
|
59
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
60
|
+
description: z.ZodOptional<z.ZodString>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
export type RuntimeProbe = z.infer<typeof RuntimeProbeSchema>;
|
|
63
|
+
/** Zod schema for the full list (wrapping the per-probe schema). */
|
|
64
|
+
export declare const RuntimeProbeListSchema: z.ZodArray<z.ZodObject<{
|
|
65
|
+
name: z.ZodString;
|
|
66
|
+
sandbox: z.ZodEnum<{
|
|
67
|
+
host: "host";
|
|
68
|
+
twin: "twin";
|
|
69
|
+
}>;
|
|
70
|
+
command: z.ZodString;
|
|
71
|
+
timeout_ms: z.ZodOptional<z.ZodNumber>;
|
|
72
|
+
description: z.ZodOptional<z.ZodString>;
|
|
73
|
+
}, z.core.$strip>>;
|
|
74
|
+
/**
|
|
75
|
+
* Result of parsing the `## Runtime Probes` section from story markdown.
|
|
76
|
+
*
|
|
77
|
+
* Parsing never throws — instead it returns one of three variants so the
|
|
78
|
+
* VerificationCheck can distinguish and emit appropriate findings:
|
|
79
|
+
*
|
|
80
|
+
* - `absent`: section missing entirely. Treat as "no probes declared" →
|
|
81
|
+
* check emits pass with skip note. Backward compat for every
|
|
82
|
+
* story authored before Phase 2.
|
|
83
|
+
* - `parsed`: section present, YAML valid, all entries match
|
|
84
|
+
* RuntimeProbeSchema. `probes` is the parsed array (may be
|
|
85
|
+
* empty if the YAML list was intentionally `[]`).
|
|
86
|
+
* - `invalid`: section present but YAML is malformed, the root value is
|
|
87
|
+
* not a list, or at least one entry fails schema validation.
|
|
88
|
+
* The check surfaces `invalid` as a fail finding with the
|
|
89
|
+
* original parse error so authors see the exact problem.
|
|
90
|
+
*/
|
|
91
|
+
export type RuntimeProbeParseResult = {
|
|
92
|
+
kind: 'absent';
|
|
93
|
+
} | {
|
|
94
|
+
kind: 'parsed';
|
|
95
|
+
probes: RuntimeProbe[];
|
|
96
|
+
} | {
|
|
97
|
+
kind: 'invalid';
|
|
98
|
+
error: string;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Outcome of one probe execution.
|
|
102
|
+
*
|
|
103
|
+
* Mirrors the optional `{command, exitCode, stdoutTail, stderrTail,
|
|
104
|
+
* durationMs}` surface on VerificationFinding so the RuntimeProbeCheck can
|
|
105
|
+
* lift ProbeResult fields into a finding with minimal translation.
|
|
106
|
+
*
|
|
107
|
+
* `outcome` disambiguates the three terminal states the check cares about:
|
|
108
|
+
*
|
|
109
|
+
* - `pass`: command exited 0 within its timeout.
|
|
110
|
+
* - `fail`: command exited non-zero within its timeout.
|
|
111
|
+
* - `timeout`: probe exceeded its timeout and was killed. `exitCode` is
|
|
112
|
+
* undefined (the process never reported one).
|
|
113
|
+
*/
|
|
114
|
+
export interface ProbeResult {
|
|
115
|
+
outcome: 'pass' | 'fail' | 'timeout';
|
|
116
|
+
command: string;
|
|
117
|
+
exitCode?: number;
|
|
118
|
+
stdoutTail: string;
|
|
119
|
+
stderrTail: string;
|
|
120
|
+
durationMs: number;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/verification/probes/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB;;;EAA2B,CAAA;AACjE,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAM3E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,QAAS,CAAA;AAE9C;uEACuE;AACvE,eAAO,MAAM,gBAAgB,QAAW,CAAA;AAExC;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;iBAW7B,CAAA;AAEF,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAE7D,oEAAoE;AACpE,eAAO,MAAM,sBAAsB;;;;;;;;;kBAA8B,CAAA;AAMjE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAMtC;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;IACpC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime probe types — Epic 55 / Phase 2.
|
|
3
|
+
*
|
|
4
|
+
* A "runtime probe" is an author-declared executable command that the
|
|
5
|
+
* verification pipeline runs against a real or ephemeral target environment
|
|
6
|
+
* to answer the question "does the artifact this story produced actually
|
|
7
|
+
* work?". Runtime probes exist specifically to catch the class of bugs that
|
|
8
|
+
* static shape-gates (phantom-review, trivial-output, ac-evidence, build)
|
|
9
|
+
* cannot — runtime misconfiguration, wrong image paths, systemd semantics,
|
|
10
|
+
* credential issues, and so on.
|
|
11
|
+
*
|
|
12
|
+
* This file defines the data shape; parsing lives in ./parser.ts, execution
|
|
13
|
+
* lives in ./executor.ts, and the VerificationCheck implementation lives in
|
|
14
|
+
* ../checks/runtime-probe-check.ts.
|
|
15
|
+
*/
|
|
16
|
+
import { z } from 'zod';
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Sandbox — where the probe runs
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
/**
|
|
21
|
+
* Execution sandbox for a runtime probe.
|
|
22
|
+
*
|
|
23
|
+
* - `host`: probe runs directly on the operator's machine. Explicit opt-in.
|
|
24
|
+
* Cheapest; most dangerous. Authors choosing `host` acknowledge the probe
|
|
25
|
+
* may touch host state (ports, systemd units, filesystem) and take
|
|
26
|
+
* responsibility for cleanup.
|
|
27
|
+
* - `twin`: probe runs inside an ephemeral sandbox brokered by the Digital
|
|
28
|
+
* Twin subsystem (Epic 47). Twin integration is **deferred to Phase 3** —
|
|
29
|
+
* probes with `sandbox: twin` currently emit a `probe-deferred` warn
|
|
30
|
+
* finding rather than executing. Authors can declare twin-scoped probes
|
|
31
|
+
* today and they will execute transparently once Phase 3 lands.
|
|
32
|
+
*/
|
|
33
|
+
export const RuntimeProbeSandboxSchema = z.enum(['host', 'twin']);
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// RuntimeProbe — one author-declared probe
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Default per-probe timeout in milliseconds. Matches the existing
|
|
39
|
+
* BuildCheck ceiling (60 s) — deliberate, so probe timeouts are bounded
|
|
40
|
+
* by the same policy the pipeline already uses for long-running checks.
|
|
41
|
+
*/
|
|
42
|
+
export const DEFAULT_PROBE_TIMEOUT_MS = 60_000;
|
|
43
|
+
/** Hard upper bound on per-probe stdout/stderr retention (≤ 4 KiB — the
|
|
44
|
+
* same convention as VerificationFinding.{stdoutTail,stderrTail}). */
|
|
45
|
+
export const PROBE_TAIL_BYTES = 4 * 1024;
|
|
46
|
+
/**
|
|
47
|
+
* Zod schema for one runtime probe declared in a story's
|
|
48
|
+
* `## Runtime Probes` section.
|
|
49
|
+
*
|
|
50
|
+
* Required fields (`name`, `sandbox`, `command`) force authors to make
|
|
51
|
+
* intent explicit — no silent defaults that could mask a miswritten probe.
|
|
52
|
+
* Optional fields cover operational knobs with sensible fallbacks.
|
|
53
|
+
*/
|
|
54
|
+
export const RuntimeProbeSchema = z.object({
|
|
55
|
+
/** Stable, unique-within-story identifier used in finding messages and logs. */
|
|
56
|
+
name: z.string().min(1, 'probe name is required'),
|
|
57
|
+
/** Where the probe runs. See RuntimeProbeSandboxSchema. */
|
|
58
|
+
sandbox: RuntimeProbeSandboxSchema,
|
|
59
|
+
/** Shell command line(s). Passed to a detached `sh -c` wrapper on host execution. */
|
|
60
|
+
command: z.string().min(1, 'probe command is required'),
|
|
61
|
+
/** Optional per-probe timeout in ms. Defaults to DEFAULT_PROBE_TIMEOUT_MS. */
|
|
62
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
63
|
+
/** Optional human-readable description. Surfaced in finding messages. */
|
|
64
|
+
description: z.string().optional(),
|
|
65
|
+
});
|
|
66
|
+
/** Zod schema for the full list (wrapping the per-probe schema). */
|
|
67
|
+
export const RuntimeProbeListSchema = z.array(RuntimeProbeSchema);
|
|
68
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/verification/probes/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,8EAA8E;AAC9E,iCAAiC;AACjC,8EAA8E;AAE9E;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAGjE,8EAA8E;AAC9E,2CAA2C;AAC3C,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAA;AAE9C;uEACuE;AACvE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,CAAA;AAExC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,gFAAgF;IAChF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,wBAAwB,CAAC;IACjD,2DAA2D;IAC3D,OAAO,EAAE,yBAAyB;IAClC,qFAAqF;IACrF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,2BAA2B,CAAC;IACvD,8EAA8E;IAC9E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAClD,yEAAyE;IACzE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAA;AAIF,oEAAoE;AACpE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAA"}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* Package placement: packages/sdlc/src/verification/ — SDLC-specific fields
|
|
9
9
|
* (storyKey, commitSha, priorStoryFiles) make these types inappropriate for @substrate-ai/core.
|
|
10
10
|
*/
|
|
11
|
+
import type { VerificationFinding } from './findings.js';
|
|
12
|
+
export type { VerificationFinding, VerificationFindingSeverity } from './findings.js';
|
|
11
13
|
/**
|
|
12
14
|
* Slim projection of code-review dispatch signals needed by PhantomReviewCheck.
|
|
13
15
|
*
|
|
@@ -102,12 +104,19 @@ export interface VerificationContext {
|
|
|
102
104
|
/**
|
|
103
105
|
* Result returned by a single VerificationCheck.run() invocation.
|
|
104
106
|
*
|
|
105
|
-
*
|
|
107
|
+
* `details` is a human-readable rendering, preserved for any consumer that
|
|
108
|
+
* already reads it. `findings` (story 55-1) is the structured per-issue
|
|
109
|
+
* surface — downstream consumers (retry prompts, run manifest, post-run
|
|
110
|
+
* analysis) should prefer it. Checks that emit findings should derive
|
|
111
|
+
* `details` via `renderFindings(findings)` so the two stay in sync.
|
|
106
112
|
*/
|
|
107
113
|
export interface VerificationResult {
|
|
108
114
|
status: 'pass' | 'warn' | 'fail';
|
|
109
115
|
details: string;
|
|
110
116
|
duration_ms: number;
|
|
117
|
+
/** Structured per-issue payload. Optional for backward compatibility with
|
|
118
|
+
* checks and consumers that pre-date story 55-1. */
|
|
119
|
+
findings?: VerificationFinding[];
|
|
111
120
|
}
|
|
112
121
|
/**
|
|
113
122
|
* Per-check result included in a VerificationSummary.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/verification/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/verification/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAGxD,YAAY,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAA;AAMrF;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,6GAA6G;IAC7G,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,uEAAuE;IACvE,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAA;IACtC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;CACjC;AAMD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAA;IAClB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAA;IACjB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,aAAa,CAAA;IAC5B;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,eAAe,CAAA;IAChC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAMD;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB;wDACoD;IACpD,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAA;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE,SAAS,EAAE,MAAM,CAAA;CAClB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,uBAAuB,EAAE,CAAA;IACjC,gDAAgD;IAChD,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IAChC,WAAW,EAAE,MAAM,CAAA;CACpB;AAMD;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAA;IACZ,mFAAmF;IACnF,IAAI,EAAE,GAAG,GAAG,GAAG,CAAA;IACf;;;OAGG;IACH,GAAG,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CAC/D"}
|
|
@@ -52,11 +52,13 @@ export declare class VerificationPipeline {
|
|
|
52
52
|
/**
|
|
53
53
|
* Create a VerificationPipeline pre-loaded with the canonical check set.
|
|
54
54
|
*
|
|
55
|
-
* Canonical Tier A check order
|
|
55
|
+
* Canonical Tier A check order:
|
|
56
56
|
* 1. PhantomReviewCheck — story 51-2 (runs first: unreviewed stories skipped)
|
|
57
57
|
* 2. TrivialOutputCheck — story 51-3
|
|
58
58
|
* 3. AcceptanceCriteriaEvidenceCheck
|
|
59
59
|
* 4. BuildCheck — story 51-4
|
|
60
|
+
* 5. RuntimeProbeCheck — Epic 55 Phase 2: runtime behavior gate; runs last
|
|
61
|
+
* in Tier A because probes may depend on built artifacts
|
|
60
62
|
*
|
|
61
63
|
* @param bus Typed event bus for verification events.
|
|
62
64
|
* @param config Optional config (used to forward threshold to TrivialOutputCheck).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verification-pipeline.d.ts","sourceRoot":"","sources":["../../src/verification/verification-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EAEnB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAA;
|
|
1
|
+
{"version":3,"file":"verification-pipeline.d.ts","sourceRoot":"","sources":["../../src/verification/verification-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAC9C,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EAEnB,mBAAmB,EACpB,MAAM,YAAY,CAAA;AAGnB,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAA;AA4BhF;;;;;;GAMG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD;;;OAGG;gBACS,GAAG,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,GAAE,iBAAiB,EAAO;IAO5E;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI;IAIxC;;;;;;;;;;OAUG;IACG,GAAG,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,GAAE,GAAG,GAAG,GAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAqE7F;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iCAAiC,CAC/C,GAAG,EAAE,aAAa,CAAC,UAAU,CAAC,EAC9B,MAAM,CAAC,EAAE,wBAAwB,GAChC,oBAAoB,CAStB"}
|