@deftai/directive 0.61.2 → 0.63.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/dist/{branch-parity.d.ts → branch-fixtures.d.ts} +1 -3
- package/dist/{branch-parity.js → branch-fixtures.js} +3 -110
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +4 -1
- package/dist/framework-check-updates.d.ts +10 -0
- package/dist/framework-check-updates.js +68 -0
- package/dist/install-cli/coverage-map.js +3 -2
- package/dist/orchestration-cli/coverage-map.js +1 -1
- package/dist/{policy-parity.d.ts → policy-fixtures.d.ts} +1 -3
- package/dist/{policy-parity.js → policy-fixtures.js} +4 -100
- package/dist/{release-e2e-parity.d.ts → release-e2e-fixtures.d.ts} +1 -3
- package/dist/release-e2e-fixtures.js +38 -0
- package/dist/{story-ready-parity.d.ts → story-ready-fixtures.d.ts} +1 -3
- package/dist/{story-ready-parity.js → story-ready-fixtures.js} +4 -121
- package/dist/{triage-aux-a-parity.d.ts → triage-aux-a-fixtures.d.ts} +1 -3
- package/dist/{triage-aux-a-parity.js → triage-aux-a-fixtures.js} +3 -73
- package/dist/{triage-aux-b-parity.d.ts → triage-aux-b-fixtures.d.ts} +1 -3
- package/dist/triage-aux-b-fixtures.js +167 -0
- package/dist/{triage-bootstrap-parity.d.ts → triage-bootstrap-fixtures.d.ts} +1 -3
- package/dist/{triage-bootstrap-parity.js → triage-bootstrap-fixtures.js} +4 -91
- package/dist/{triage-classify-parity.d.ts → triage-classify-fixtures.d.ts} +1 -3
- package/dist/{triage-classify-parity.js → triage-classify-fixtures.js} +4 -94
- package/dist/{triage-queue-parity.d.ts → triage-queue-fixtures.d.ts} +1 -3
- package/dist/{triage-queue-parity.js → triage-queue-fixtures.js} +4 -86
- package/dist/{triage-scope-parity.d.ts → triage-scope-fixtures.d.ts} +1 -3
- package/dist/{triage-scope-parity.js → triage-scope-fixtures.js} +4 -91
- package/dist/umbrella-current-shape.d.ts +9 -0
- package/dist/umbrella-current-shape.js +56 -0
- package/dist/{vbrief-preflight-parity.d.ts → vbrief-preflight-fixtures.d.ts} +1 -3
- package/dist/vbrief-preflight-fixtures.js +79 -0
- package/dist/{wip-cap-parity.d.ts → wip-cap-fixtures.d.ts} +1 -3
- package/dist/{wip-cap-parity.js → wip-cap-fixtures.js} +4 -91
- package/package.json +4 -15
- package/dist/cache-parity.d.ts +0 -36
- package/dist/cache-parity.js +0 -165
- package/dist/codebase-parity.d.ts +0 -31
- package/dist/codebase-parity.js +0 -303
- package/dist/doc-cli-parity.d.ts +0 -29
- package/dist/doc-cli-parity.js +0 -159
- package/dist/doctor-parity.d.ts +0 -42
- package/dist/doctor-parity.js +0 -157
- package/dist/intake-parity.d.ts +0 -30
- package/dist/intake-parity.js +0 -203
- package/dist/lifecycle-packs-parity.d.ts +0 -30
- package/dist/lifecycle-packs-parity.js +0 -377
- package/dist/orchestration-parity.d.ts +0 -38
- package/dist/orchestration-parity.js +0 -364
- package/dist/parity.d.ts +0 -36
- package/dist/parity.js +0 -176
- package/dist/platform-parity.d.ts +0 -26
- package/dist/platform-parity.js +0 -309
- package/dist/pr-closing-keywords-parity.d.ts +0 -45
- package/dist/pr-closing-keywords-parity.js +0 -259
- package/dist/pr-merge-readiness-parity.d.ts +0 -44
- package/dist/pr-merge-readiness-parity.js +0 -296
- package/dist/pr-monitor-parity.d.ts +0 -44
- package/dist/pr-monitor-parity.js +0 -283
- package/dist/pr-protected-issues-parity.d.ts +0 -41
- package/dist/pr-protected-issues-parity.js +0 -220
- package/dist/pr-wait-mergeable-parity.d.ts +0 -45
- package/dist/pr-wait-mergeable-parity.js +0 -340
- package/dist/release-e2e-parity.js +0 -114
- package/dist/release-parity.d.ts +0 -40
- package/dist/release-parity.js +0 -226
- package/dist/release-publish-parity.d.ts +0 -36
- package/dist/release-publish-parity.js +0 -138
- package/dist/release-rollback-parity.d.ts +0 -37
- package/dist/release-rollback-parity.js +0 -161
- package/dist/render-parity.d.ts +0 -36
- package/dist/render-parity.js +0 -385
- package/dist/scm-parity.d.ts +0 -39
- package/dist/scm-parity.js +0 -181
- package/dist/scope-lifecycle-parity.d.ts +0 -35
- package/dist/scope-lifecycle-parity.js +0 -177
- package/dist/session-parity.d.ts +0 -39
- package/dist/session-parity.js +0 -262
- package/dist/slice-parity.d.ts +0 -36
- package/dist/slice-parity.js +0 -304
- package/dist/swarm-parity.d.ts +0 -28
- package/dist/swarm-parity.js +0 -327
- package/dist/triage-actions-parity.d.ts +0 -36
- package/dist/triage-actions-parity.js +0 -357
- package/dist/triage-aux-b-parity.js +0 -308
- package/dist/triage-summary-parity.d.ts +0 -50
- package/dist/triage-summary-parity.js +0 -306
- package/dist/validate-content-parity.d.ts +0 -33
- package/dist/validate-content-parity.js +0 -356
- package/dist/vbrief-activate-parity.d.ts +0 -39
- package/dist/vbrief-activate-parity.js +0 -216
- package/dist/vbrief-build-parity.d.ts +0 -28
- package/dist/vbrief-build-parity.js +0 -399
- package/dist/vbrief-preflight-parity.js +0 -163
- package/dist/vbrief-reconcile-parity.d.ts +0 -23
- package/dist/vbrief-reconcile-parity.js +0 -609
- package/dist/vbrief-validate-parity.d.ts +0 -27
- package/dist/vbrief-validate-parity.js +0 -122
- package/dist/vbrief-validation-parity.d.ts +0 -28
- package/dist/vbrief-validation-parity.js +0 -645
- package/dist/verify-env-parity.d.ts +0 -28
- package/dist/verify-env-parity.js +0 -272
- package/dist/verify-source-parity.d.ts +0 -26
- package/dist/verify-source-parity.js +0 -178
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Golden-output parity harness (#1783 s1): runs BOTH the Python oracles and the
|
|
4
|
-
* ported TS verify-env gates over shared fixtures (cache-off), asserting
|
|
5
|
-
* byte-identical stdout/stderr and exit codes.
|
|
6
|
-
*/
|
|
7
|
-
import { spawnSync } from "node:child_process";
|
|
8
|
-
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
9
|
-
import { tmpdir } from "node:os";
|
|
10
|
-
import { dirname, join, resolve } from "node:path";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { evaluate as evaluateHooks, formatScanResult, runToolchainCheck, scan, verifyRequiredTools, } from "@deftai/directive-core/verify-env";
|
|
13
|
-
function captureFromRun(exitCode, stdout, stderr) {
|
|
14
|
-
return { exitCode, stdout, stderr };
|
|
15
|
-
}
|
|
16
|
-
function loadModule(name, relPath) {
|
|
17
|
-
return `spec = importlib.util.spec_from_file_location(${JSON.stringify(name)}, root / ${JSON.stringify(relPath)})
|
|
18
|
-
mod = importlib.util.module_from_spec(spec)
|
|
19
|
-
sys.modules[${JSON.stringify(name)}] = mod
|
|
20
|
-
spec.loader.exec_module(mod)`;
|
|
21
|
-
}
|
|
22
|
-
function runPythonScript(deftRoot, script) {
|
|
23
|
-
const code = `import importlib.util, sys\nfrom pathlib import Path\nroot = Path(${JSON.stringify(deftRoot)})\n${script}`;
|
|
24
|
-
const result = spawnSync("uv", ["run", "python", "-c", code], {
|
|
25
|
-
cwd: deftRoot,
|
|
26
|
-
encoding: "utf8",
|
|
27
|
-
env: { ...process.env, DEFT_CACHE_DISABLE: "1", PYTHONUTF8: "1" },
|
|
28
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
29
|
-
});
|
|
30
|
-
return {
|
|
31
|
-
exitCode: result.status ?? 2,
|
|
32
|
-
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
33
|
-
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function probeWith(available) {
|
|
37
|
-
return (command) => (available.has(command) ? `/usr/bin/${command}` : null);
|
|
38
|
-
}
|
|
39
|
-
function makeNoTaskFixture(deftRoot) {
|
|
40
|
-
const root = mkdtempSync(join(tmpdir(), "deft-verify-env-notask-"));
|
|
41
|
-
mkdirSync(join(root, "scripts"), { recursive: true });
|
|
42
|
-
writeFileSync(join(root, "run"), "#!/usr/bin/env python3\n", "utf8");
|
|
43
|
-
writeFileSync(join(root, "scripts", "probe.py"), 'import subprocess\nimport shutil\nsubprocess.check_output(["task", "check"])\nshutil.which("task")\n', "utf8");
|
|
44
|
-
writeFileSync(join(root, "scripts", "verify_no_task_runtime.py"), readFileSync(join(deftRoot, "scripts", "verify_no_task_runtime.py"), "utf8"), "utf8");
|
|
45
|
-
return root;
|
|
46
|
-
}
|
|
47
|
-
export const PARITY_CASES = [
|
|
48
|
-
{
|
|
49
|
-
name: "verify-tools-clean-linux",
|
|
50
|
-
runPython(deftRoot) {
|
|
51
|
-
return runPythonScript(deftRoot, `${loadModule("verify_tools", "scripts/verify_tools.py")}
|
|
52
|
-
available = {"git","uv","python3","gh","apt-get"}
|
|
53
|
-
def probe(c):
|
|
54
|
-
return f"/usr/bin/{c}" if c in available else None
|
|
55
|
-
lines = []
|
|
56
|
-
result = mod.verify_required_tools(platform_id="linux", probe=probe, output_fn=lines.append)
|
|
57
|
-
for line in lines:
|
|
58
|
-
print(line)
|
|
59
|
-
sys.exit(result.exit_code)`);
|
|
60
|
-
},
|
|
61
|
-
runTs() {
|
|
62
|
-
const lines = [];
|
|
63
|
-
const result = verifyRequiredTools({
|
|
64
|
-
platformId: "linux",
|
|
65
|
-
probe: probeWith(new Set(["git", "uv", "python3", "gh", "apt-get"])),
|
|
66
|
-
outputFn: (line) => {
|
|
67
|
-
lines.push(line);
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
return captureFromRun(result.exitCode, `${lines.join("\n")}\n`, "");
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: "verify-tools-missing-task",
|
|
75
|
-
runPython(deftRoot) {
|
|
76
|
-
return runPythonScript(deftRoot, `${loadModule("verify_tools", "scripts/verify_tools.py")}
|
|
77
|
-
available = {"git","uv","python3","gh","apt-get"}
|
|
78
|
-
def probe(c):
|
|
79
|
-
return f"/usr/bin/{c}" if c in available else None
|
|
80
|
-
lines = []
|
|
81
|
-
result = mod.verify_required_tools(platform_id="linux", include_task=True, probe=probe, output_fn=lines.append)
|
|
82
|
-
for line in lines:
|
|
83
|
-
print(line)
|
|
84
|
-
sys.exit(result.exit_code)`);
|
|
85
|
-
},
|
|
86
|
-
runTs() {
|
|
87
|
-
const lines = [];
|
|
88
|
-
const result = verifyRequiredTools({
|
|
89
|
-
platformId: "linux",
|
|
90
|
-
includeTask: true,
|
|
91
|
-
probe: probeWith(new Set(["git", "uv", "python3", "gh", "apt-get"])),
|
|
92
|
-
outputFn: (line) => {
|
|
93
|
-
lines.push(line);
|
|
94
|
-
},
|
|
95
|
-
});
|
|
96
|
-
return captureFromRun(result.exitCode, `${lines.join("\n")}\n`, "");
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
name: "verify-tools-foundational-git-missing",
|
|
101
|
-
runPython(deftRoot) {
|
|
102
|
-
return runPythonScript(deftRoot, `${loadModule("verify_tools", "scripts/verify_tools.py")}
|
|
103
|
-
available = {"task","uv","python3","gh","apt-get"}
|
|
104
|
-
def probe(c):
|
|
105
|
-
return f"/usr/bin/{c}" if c in available else None
|
|
106
|
-
result = mod.verify_required_tools(platform_id="linux", probe=probe)
|
|
107
|
-
sys.exit(result.exit_code)`);
|
|
108
|
-
},
|
|
109
|
-
runTs() {
|
|
110
|
-
const result = verifyRequiredTools({
|
|
111
|
-
platformId: "linux",
|
|
112
|
-
probe: probeWith(new Set(["task", "uv", "python3", "gh", "apt-get"])),
|
|
113
|
-
});
|
|
114
|
-
return captureFromRun(result.exitCode, "", "");
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
name: "verify-hooks-clean-deft-root",
|
|
119
|
-
runPython(deftRoot) {
|
|
120
|
-
return runPythonScript(deftRoot, `${loadModule("verify_hooks_installed", "scripts/verify_hooks_installed.py")}
|
|
121
|
-
code, msg = mod.evaluate(root)
|
|
122
|
-
print(msg, file=sys.stdout if code == 0 else sys.stderr)
|
|
123
|
-
sys.exit(code)`);
|
|
124
|
-
},
|
|
125
|
-
runTs(deftRoot) {
|
|
126
|
-
const result = evaluateHooks(deftRoot);
|
|
127
|
-
if (result.stream === "stdout") {
|
|
128
|
-
return captureFromRun(result.code, `${result.message}\n`, "");
|
|
129
|
-
}
|
|
130
|
-
return captureFromRun(result.code, "", `${result.message}\n`);
|
|
131
|
-
},
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
name: "verify-hooks-unset",
|
|
135
|
-
runPython(deftRoot) {
|
|
136
|
-
const fixture = mkdtempSync(join(tmpdir(), "deft-verify-env-hooks-unset-"));
|
|
137
|
-
mkdirSync(fixture, { recursive: true });
|
|
138
|
-
const cap = runPythonScript(deftRoot, `${loadModule("verify_hooks_installed", "scripts/verify_hooks_installed.py")}
|
|
139
|
-
code, msg = mod.evaluate(Path(${JSON.stringify(fixture)}))
|
|
140
|
-
print(msg, file=sys.stdout if code == 0 else sys.stderr)
|
|
141
|
-
sys.exit(code)`);
|
|
142
|
-
rmSync(fixture, { recursive: true, force: true });
|
|
143
|
-
return cap;
|
|
144
|
-
},
|
|
145
|
-
runTs() {
|
|
146
|
-
const fixture = mkdtempSync(join(tmpdir(), "deft-verify-env-hooks-unset-ts-"));
|
|
147
|
-
const result = evaluateHooks(fixture, {
|
|
148
|
-
gitConfigReader: () => ({ hooksPath: null, error: null }),
|
|
149
|
-
});
|
|
150
|
-
rmSync(fixture, { recursive: true, force: true });
|
|
151
|
-
return captureFromRun(result.code, "", `${result.message}\n`);
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
name: "toolchain-empty-path",
|
|
156
|
-
runPython(deftRoot) {
|
|
157
|
-
return runPythonScript(deftRoot, `${loadModule("toolchain_check", "scripts/toolchain-check.py")}
|
|
158
|
-
from unittest.mock import patch
|
|
159
|
-
def fake_run(*args, **kwargs):
|
|
160
|
-
raise FileNotFoundError(args[0][0])
|
|
161
|
-
with patch("subprocess.run", fake_run):
|
|
162
|
-
sys.exit(mod.main())`);
|
|
163
|
-
},
|
|
164
|
-
runTs() {
|
|
165
|
-
const result = runToolchainCheck(() => ({ error: "not-found", message: "" }));
|
|
166
|
-
return captureFromRun(result.exitCode, `${result.lines.join("\n")}\n`, "");
|
|
167
|
-
},
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
name: "verify-no-task-runtime-clean-deft-root",
|
|
171
|
-
runPython(deftRoot) {
|
|
172
|
-
return runPythonScript(deftRoot, `${loadModule("verify_no_task_runtime", "scripts/verify_no_task_runtime.py")}
|
|
173
|
-
sys.exit(mod.main())`);
|
|
174
|
-
},
|
|
175
|
-
runTs(deftRoot) {
|
|
176
|
-
const findings = scan({ root: deftRoot });
|
|
177
|
-
const formatted = formatScanResult(findings);
|
|
178
|
-
return captureFromRun(formatted.exitCode, formatted.stdout, formatted.stderr);
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
name: "verify-no-task-runtime-findings",
|
|
183
|
-
runPython(deftRoot) {
|
|
184
|
-
const fixture = makeNoTaskFixture(deftRoot);
|
|
185
|
-
const cap = runPythonScript(deftRoot, `${loadModule("verify_no_task_runtime", "scripts/verify_no_task_runtime.py")}
|
|
186
|
-
fixture = Path(${JSON.stringify(fixture)})
|
|
187
|
-
mod.ROOT = fixture
|
|
188
|
-
mod._python_files = lambda: [fixture / "run", fixture / "scripts" / "probe.py"]
|
|
189
|
-
findings = mod.scan()
|
|
190
|
-
if not findings:
|
|
191
|
-
print("No runtime go-task subprocess dependencies found")
|
|
192
|
-
sys.exit(0)
|
|
193
|
-
print("Runtime go-task dependencies found:", file=sys.stderr)
|
|
194
|
-
for finding in findings:
|
|
195
|
-
rel = finding.path.relative_to(mod.ROOT)
|
|
196
|
-
print(f" {rel}:{finding.line}: {finding.message}", file=sys.stderr)
|
|
197
|
-
sys.exit(1)`);
|
|
198
|
-
rmSync(fixture, { recursive: true, force: true });
|
|
199
|
-
return cap;
|
|
200
|
-
},
|
|
201
|
-
runTs(deftRoot) {
|
|
202
|
-
const fixture = makeNoTaskFixture(deftRoot);
|
|
203
|
-
const findings = scan({
|
|
204
|
-
root: fixture,
|
|
205
|
-
pythonFiles: () => [join(fixture, "run"), join(fixture, "scripts", "probe.py")],
|
|
206
|
-
});
|
|
207
|
-
const formatted = formatScanResult(findings);
|
|
208
|
-
rmSync(fixture, { recursive: true, force: true });
|
|
209
|
-
return captureFromRun(formatted.exitCode, formatted.stdout, formatted.stderr);
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
];
|
|
213
|
-
function resolveDeftRoot() {
|
|
214
|
-
if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
|
|
215
|
-
return resolve(process.env.DEFT_ROOT);
|
|
216
|
-
}
|
|
217
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
218
|
-
}
|
|
219
|
-
export function diffCase(python, ts, name) {
|
|
220
|
-
return {
|
|
221
|
-
name,
|
|
222
|
-
exitMismatch: python.exitCode !== ts.exitCode,
|
|
223
|
-
stdoutMismatch: python.stdout !== ts.stdout,
|
|
224
|
-
stderrMismatch: python.stderr !== ts.stderr,
|
|
225
|
-
pythonExit: python.exitCode,
|
|
226
|
-
tsExit: ts.exitCode,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
export function runParity(deftRoot = resolveDeftRoot()) {
|
|
230
|
-
const diffs = [];
|
|
231
|
-
for (const testCase of PARITY_CASES) {
|
|
232
|
-
diffs.push(diffCase(testCase.runPython(deftRoot), testCase.runTs(deftRoot), testCase.name));
|
|
233
|
-
}
|
|
234
|
-
return {
|
|
235
|
-
ok: diffs.every((d) => !d.exitMismatch && !d.stdoutMismatch && !d.stderrMismatch),
|
|
236
|
-
diffs,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
export function renderReport(result) {
|
|
240
|
-
if (result.ok) {
|
|
241
|
-
return `verify-env parity: CLEAN -- Python and TS agree on ${PARITY_CASES.length} case(s).`;
|
|
242
|
-
}
|
|
243
|
-
const lines = ["verify-env parity: DIVERGENCE"];
|
|
244
|
-
for (const d of result.diffs) {
|
|
245
|
-
if (d.exitMismatch || d.stdoutMismatch || d.stderrMismatch) {
|
|
246
|
-
lines.push(` case: ${d.name}`);
|
|
247
|
-
if (d.exitMismatch)
|
|
248
|
-
lines.push(` exit: python=${d.pythonExit} ts=${d.tsExit}`);
|
|
249
|
-
if (d.stdoutMismatch)
|
|
250
|
-
lines.push(" stdout mismatch");
|
|
251
|
-
if (d.stderrMismatch)
|
|
252
|
-
lines.push(" stderr mismatch");
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
return lines.join("\n");
|
|
256
|
-
}
|
|
257
|
-
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
258
|
-
try {
|
|
259
|
-
const result = runParity();
|
|
260
|
-
if (result.ok) {
|
|
261
|
-
process.stdout.write(`${renderReport(result)}\n`);
|
|
262
|
-
process.exit(0);
|
|
263
|
-
}
|
|
264
|
-
process.stderr.write(`${renderReport(result)}\n`);
|
|
265
|
-
process.exit(1);
|
|
266
|
-
}
|
|
267
|
-
catch (err) {
|
|
268
|
-
process.stderr.write(`verify-env parity: harness error -- ${String(err)}\n`);
|
|
269
|
-
process.exit(2);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
//# sourceMappingURL=verify-env-parity.js.map
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
export interface GateCapture {
|
|
3
|
-
readonly name: string;
|
|
4
|
-
readonly exitCode: number;
|
|
5
|
-
readonly stdout: string;
|
|
6
|
-
readonly stderr: string;
|
|
7
|
-
}
|
|
8
|
-
export interface GateParity {
|
|
9
|
-
readonly name: string;
|
|
10
|
-
readonly exitMismatch: boolean;
|
|
11
|
-
readonly stdoutMismatch: boolean;
|
|
12
|
-
readonly stderrMismatch: boolean;
|
|
13
|
-
readonly pythonExit: number;
|
|
14
|
-
readonly tsExit: number;
|
|
15
|
-
}
|
|
16
|
-
export interface ParityResult {
|
|
17
|
-
readonly ok: boolean;
|
|
18
|
-
readonly gates: readonly GateParity[];
|
|
19
|
-
}
|
|
20
|
-
export declare function captureTsGate(name: string, deftRoot: string): GateCapture;
|
|
21
|
-
export declare function capturePythonGate(name: string, deftRoot: string): GateCapture;
|
|
22
|
-
export declare const PARITY_GATES: readonly ["verify_scm_boundary", "rule_ownership_lint", "code_structure_validate", "verify-stubs"];
|
|
23
|
-
export declare function diffGate(python: GateCapture, ts: GateCapture): GateParity;
|
|
24
|
-
export declare function runParity(deftRoot?: string): ParityResult;
|
|
25
|
-
export declare function renderReport(result: ParityResult): string;
|
|
26
|
-
//# sourceMappingURL=verify-source-parity.d.ts.map
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Golden-output parity harness (#1783 s2): runs BOTH the frozen Python source-tree
|
|
4
|
-
* scanner gates and the ported TS verify-source module over the repository tree,
|
|
5
|
-
* then diffs exit codes + byte-identical stdout/stderr (cache-off).
|
|
6
|
-
*
|
|
7
|
-
* Exit codes: 0 parity / 1 divergence / 2 harness setup error.
|
|
8
|
-
*/
|
|
9
|
-
import { spawnSync } from "node:child_process";
|
|
10
|
-
import { dirname, join, resolve } from "node:path";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { evaluateCodeStructure, evaluateRuleOwnership, evaluateScmBoundary, evaluateVerifyStubs, } from "@deftai/directive-core/verify-source";
|
|
13
|
-
function runCapture(cmd, args, cwd, env = {}) {
|
|
14
|
-
const result = spawnSync(cmd, args, {
|
|
15
|
-
cwd,
|
|
16
|
-
encoding: "utf8",
|
|
17
|
-
env: { ...process.env, ...env },
|
|
18
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
19
|
-
});
|
|
20
|
-
return {
|
|
21
|
-
status: result.status ?? 2,
|
|
22
|
-
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
23
|
-
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function resolveDeftRoot() {
|
|
27
|
-
if (process.env.DEFT_ROOT !== undefined && process.env.DEFT_ROOT.length > 0) {
|
|
28
|
-
return resolve(process.env.DEFT_ROOT);
|
|
29
|
-
}
|
|
30
|
-
return resolve(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
31
|
-
}
|
|
32
|
-
function normaliseHarnessNoise(text) {
|
|
33
|
-
return text
|
|
34
|
-
.split("\n")
|
|
35
|
-
.filter((line) => !line.startsWith("Using CPython") &&
|
|
36
|
-
!line.startsWith("Creating virtual environment") &&
|
|
37
|
-
!line.startsWith("Installed "))
|
|
38
|
-
.join("\n");
|
|
39
|
-
}
|
|
40
|
-
export function captureTsGate(name, deftRoot) {
|
|
41
|
-
if (name === "verify_scm_boundary") {
|
|
42
|
-
const result = evaluateScmBoundary(deftRoot);
|
|
43
|
-
return {
|
|
44
|
-
name,
|
|
45
|
-
exitCode: result.code,
|
|
46
|
-
stdout: result.stream === "stdout" ? `${result.message}\n` : "",
|
|
47
|
-
stderr: result.stream === "stderr" ? `${result.message}\n` : "",
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
if (name === "rule_ownership_lint") {
|
|
51
|
-
const result = evaluateRuleOwnership(deftRoot, { root: deftRoot });
|
|
52
|
-
return {
|
|
53
|
-
name,
|
|
54
|
-
exitCode: result.code,
|
|
55
|
-
stdout: result.stream === "stdout" ? `${result.message}\n` : "",
|
|
56
|
-
stderr: result.stream === "stderr" ? `${result.message}\n` : "",
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
if (name === "code_structure_validate") {
|
|
60
|
-
const result = evaluateCodeStructure(deftRoot);
|
|
61
|
-
return {
|
|
62
|
-
name,
|
|
63
|
-
exitCode: result.code,
|
|
64
|
-
stdout: result.stdout,
|
|
65
|
-
stderr: result.stderr,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
if (name === "verify-stubs") {
|
|
69
|
-
const result = evaluateVerifyStubs(deftRoot);
|
|
70
|
-
const msg = result.message.endsWith("\n") ? result.message : `${result.message}\n`;
|
|
71
|
-
return {
|
|
72
|
-
name,
|
|
73
|
-
exitCode: result.code,
|
|
74
|
-
stdout: msg,
|
|
75
|
-
stderr: "",
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
return { name, exitCode: 2, stdout: "", stderr: `unknown gate: ${name}\n` };
|
|
79
|
-
}
|
|
80
|
-
export function capturePythonGate(name, deftRoot) {
|
|
81
|
-
const env = { DEFT_CACHE_DISABLE: "1", PYTHONUTF8: "1" };
|
|
82
|
-
if (name === "verify_scm_boundary") {
|
|
83
|
-
const cap = runCapture("uv", [
|
|
84
|
-
"run",
|
|
85
|
-
"python",
|
|
86
|
-
join(deftRoot, "scripts", "verify_scm_boundary.py"),
|
|
87
|
-
"--project-root",
|
|
88
|
-
deftRoot,
|
|
89
|
-
], deftRoot, env);
|
|
90
|
-
return { name, exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
91
|
-
}
|
|
92
|
-
if (name === "rule_ownership_lint") {
|
|
93
|
-
const cap = runCapture("uv", ["run", "python", join(deftRoot, "scripts", "rule_ownership_lint.py"), "--root", deftRoot], deftRoot, env);
|
|
94
|
-
return { name, exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
95
|
-
}
|
|
96
|
-
if (name === "code_structure_validate") {
|
|
97
|
-
const cap = runCapture("uv", [
|
|
98
|
-
"run",
|
|
99
|
-
"python",
|
|
100
|
-
join(deftRoot, "scripts", "code_structure_validate.py"),
|
|
101
|
-
"--project-root",
|
|
102
|
-
deftRoot,
|
|
103
|
-
], deftRoot, env);
|
|
104
|
-
return { name, exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
105
|
-
}
|
|
106
|
-
if (name === "verify-stubs") {
|
|
107
|
-
const cap = runCapture("uv", ["run", "python", join(deftRoot, "scripts", "verify-stubs.py")], deftRoot, env);
|
|
108
|
-
return { name, exitCode: cap.status, stdout: cap.stdout, stderr: cap.stderr };
|
|
109
|
-
}
|
|
110
|
-
return { name, exitCode: 2, stdout: "", stderr: `unknown gate: ${name}\n` };
|
|
111
|
-
}
|
|
112
|
-
export const PARITY_GATES = [
|
|
113
|
-
"verify_scm_boundary",
|
|
114
|
-
"rule_ownership_lint",
|
|
115
|
-
"code_structure_validate",
|
|
116
|
-
"verify-stubs",
|
|
117
|
-
];
|
|
118
|
-
export function diffGate(python, ts) {
|
|
119
|
-
const pyOut = normaliseHarnessNoise(python.stdout);
|
|
120
|
-
const tsOut = normaliseHarnessNoise(ts.stdout);
|
|
121
|
-
const pyErr = normaliseHarnessNoise(python.stderr);
|
|
122
|
-
const tsErr = normaliseHarnessNoise(ts.stderr);
|
|
123
|
-
return {
|
|
124
|
-
name: python.name,
|
|
125
|
-
exitMismatch: python.exitCode !== ts.exitCode,
|
|
126
|
-
stdoutMismatch: pyOut !== tsOut,
|
|
127
|
-
stderrMismatch: pyErr !== tsErr,
|
|
128
|
-
pythonExit: python.exitCode,
|
|
129
|
-
tsExit: ts.exitCode,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
export function runParity(deftRoot = resolveDeftRoot()) {
|
|
133
|
-
const gates = [];
|
|
134
|
-
for (const name of PARITY_GATES) {
|
|
135
|
-
const python = capturePythonGate(name, deftRoot);
|
|
136
|
-
const ts = captureTsGate(name, deftRoot);
|
|
137
|
-
gates.push(diffGate(python, ts));
|
|
138
|
-
}
|
|
139
|
-
const ok = gates.every((g) => !g.exitMismatch && !g.stdoutMismatch && !g.stderrMismatch);
|
|
140
|
-
return { ok, gates };
|
|
141
|
-
}
|
|
142
|
-
export function renderReport(result) {
|
|
143
|
-
if (result.ok) {
|
|
144
|
-
return `verify-source parity: CLEAN -- Python and TS agree on ${PARITY_GATES.length} gate(s).`;
|
|
145
|
-
}
|
|
146
|
-
const lines = ["verify-source parity: DIVERGENCE"];
|
|
147
|
-
for (const g of result.gates) {
|
|
148
|
-
if (g.exitMismatch || g.stdoutMismatch || g.stderrMismatch) {
|
|
149
|
-
lines.push(` gate: ${g.name}`);
|
|
150
|
-
if (g.exitMismatch) {
|
|
151
|
-
lines.push(` exit: python=${g.pythonExit} ts=${g.tsExit}`);
|
|
152
|
-
}
|
|
153
|
-
if (g.stdoutMismatch) {
|
|
154
|
-
lines.push(" stdout mismatch");
|
|
155
|
-
}
|
|
156
|
-
if (g.stderrMismatch) {
|
|
157
|
-
lines.push(" stderr mismatch");
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return lines.join("\n");
|
|
162
|
-
}
|
|
163
|
-
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
164
|
-
try {
|
|
165
|
-
const result = runParity();
|
|
166
|
-
if (result.ok) {
|
|
167
|
-
process.stdout.write(`${renderReport(result)}\n`);
|
|
168
|
-
process.exit(0);
|
|
169
|
-
}
|
|
170
|
-
process.stderr.write(`${renderReport(result)}\n`);
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
catch (err) {
|
|
174
|
-
process.stderr.write(`verify-source parity: harness error -- ${String(err)}\n`);
|
|
175
|
-
process.exit(2);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
//# sourceMappingURL=verify-source-parity.js.map
|