mirror of
https://github.com/morluto/rea.git
synced 2026-11-11 03:31:35 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11940ac24d |
No files matched your search
@@ -147,10 +147,15 @@ the measured build and selected source-location owners. A later unrelated genera
|
||||
desktop SQLite diagnostic change and rebuild are outside this snapshot; later
|
||||
whole-tree hashes do not replace the measured one.
|
||||
|
||||
The [portable driver](https://github.com/morluto/rea/blob/main/scripts/verify/analysis/source-location-delivery/task.mjs)
|
||||
has SHA-256 `b21ec9d5315682337eb55a4ad208e2145a7397d8d567cdb6653facd3f0bec90e`.
|
||||
The measured revision of the [portable driver](https://github.com/morluto/rea/blob/main/scripts/verify/analysis/source-location-delivery/task.mjs)
|
||||
had SHA-256 `b21ec9d5315682337eb55a4ad208e2145a7397d8d567cdb6653facd3f0bec90e`.
|
||||
The [observer](https://github.com/morluto/rea/blob/main/scripts/verify/analysis/budget-calibration-run.py)
|
||||
has SHA-256 `c18a06c44715c97ec9cbc76248dfbcd862d0e5ca3cd0c159d868bc7fa1fa9e9f`.
|
||||
The current driver additionally checks the MCP child's final exit and output
|
||||
closure, preserving both task and shutdown failures. Its shared process-owner
|
||||
sources are included in new aggregation hashes; the historical measurements
|
||||
above have not been rerun with this lifecycle correction.
|
||||
|
||||
Use the repository's built runtime and pinned Node. Acquisition refuses changed
|
||||
publisher bytes; the existing acquisition helper creates `artifacts.json` and
|
||||
analyst manifests under the selected artifact directory.
|
||||
|
||||
@@ -170,7 +170,7 @@ def main():
|
||||
medians = {name: {'runs': len(group), **{field: statistics.median(record[field] for record in group) for field in fields}} for name, group in groups.items()}
|
||||
assert all(len(group) == 3 for group in groups.values()) and len(groups) == 6
|
||||
recorded_runtime = json.loads((args.measurement_dir / 'runtime.json').read_text())
|
||||
paths = ['scripts/verify/analysis/source-location-delivery/task.mjs', 'scripts/verify/analysis/budget-calibration-run.py', 'scripts/rea.mjs', 'dist/cli.js', 'dist/mcp/main.js', 'src/application/WebSourceLocationService.ts', 'src/domain/analysisView/webSourceLocationView.ts', 'src/application/analysisView/AnalysisViewService.ts', 'src/contracts/webScriptToolContracts.ts', 'src/server/ToolResultDelivery.ts', 'src/server/toolResult.ts', 'src/domain/sourceMapLimits.ts', 'src/server/registerWebSourceLocationTool.ts', 'src/cli/webSourceLocationCommands.ts', 'scripts/verify/analysis/source-location-delivery/aggregate.py', 'package-lock.json', 'docs/verification/source-map-budgets-2026-11-09/artifacts.json']
|
||||
paths = ['scripts/verify/analysis/source-location-delivery/task.mjs', 'scripts/verify/analysis/budget-calibration-run.py', 'scripts/rea.mjs', 'dist/cli.js', 'dist/mcp/main.js', 'src/application/WebSourceLocationService.ts', 'src/domain/analysisView/webSourceLocationView.ts', 'src/application/analysisView/AnalysisViewService.ts', 'src/contracts/webScriptToolContracts.ts', 'src/server/ToolResultDelivery.ts', 'src/server/toolResult.ts', 'src/domain/sourceMapLimits.ts', 'src/server/registerWebSourceLocationTool.ts', 'src/cli/webSourceLocationCommands.ts', 'scripts/verify/analysis/source-location-delivery/aggregate.py', 'package-lock.json', 'docs/verification/source-map-budgets-2026-11-09/artifacts.json', 'scripts/lib/verifier-cleanup.mjs', 'scripts/lib/verifier-source-loader.mjs', 'src/process/ProviderProcess.ts']
|
||||
hashes = {path: sha256(repo / path) for path in paths}
|
||||
assert hashes[paths[0]] == recorded_runtime['driver_sha256']
|
||||
assert hashes[paths[1]] == recorded_runtime['observer_sha256']
|
||||
|
||||
@@ -3,6 +3,8 @@ import { readFile, writeFile } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import assert from "node:assert/strict";
|
||||
import { isAbsolute, join, relative, resolve, sep } from "node:path";
|
||||
import { withVerifierCleanup } from "../../../lib/verifier-cleanup.mjs";
|
||||
import { importVerifierSource } from "../../../lib/verifier-source-loader.mjs";
|
||||
|
||||
// Acquire artifactDir with docs/verification/source-map-budgets-2026-11-09/acquire.py.
|
||||
// This driver runs the public compiled stdio workflow; no target application is executed.
|
||||
@@ -99,6 +101,10 @@ assert.equal(bytes.length, source.bytes);
|
||||
assert.equal(createHash("sha256").update(bytes).digest("hex"), source.sha256);
|
||||
const artifact = JSON.parse(bytes.toString("utf8"));
|
||||
const manifestPath = localFile(source.generated_script.path + ".manifest.json");
|
||||
const { ProviderProcessSupervisor } = await importVerifierSource(
|
||||
new URL("../../../../src/process/ProviderProcess.ts", import.meta.url).href,
|
||||
import.meta.url,
|
||||
);
|
||||
const child = spawn(process.execPath, [join(root, "scripts/rea.mjs"), "mcp"], {
|
||||
cwd: root,
|
||||
env: {
|
||||
@@ -115,6 +121,14 @@ const child = spawn(process.execPath, [join(root, "scripts/rea.mjs"), "mcp"], {
|
||||
},
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
});
|
||||
const supervisor = new ProviderProcessSupervisor(
|
||||
{ process: child, ownsProcessLifetime: true },
|
||||
{
|
||||
captureStdout: false,
|
||||
// Protocol and bounded stderr receipts remain owned by this driver.
|
||||
maxDiagnosticBytes: 0,
|
||||
},
|
||||
);
|
||||
let buffer = "",
|
||||
sequence = 0,
|
||||
stderr = "";
|
||||
@@ -199,7 +213,7 @@ const contentOf = (r) => {
|
||||
assert(!r.isError, JSON.stringify(errorOf(r)));
|
||||
return r.structuredContent;
|
||||
};
|
||||
try {
|
||||
await withVerifierCleanup(async () => {
|
||||
await rpc("initialize", {
|
||||
protocolVersion: "2025-03-26",
|
||||
capabilities: {},
|
||||
@@ -410,17 +424,24 @@ try {
|
||||
{ flag: "wx" },
|
||||
);
|
||||
console.log(JSON.stringify(result));
|
||||
} finally {
|
||||
child.stdin.end();
|
||||
if (child.exitCode === null && child.signalCode === null)
|
||||
await new Promise((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
child.kill("SIGTERM");
|
||||
reject(Error("MCP close timeout"));
|
||||
}, 5000);
|
||||
child.once("exit", () => {
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [
|
||||
async () => {
|
||||
child.stdin.end();
|
||||
const exited = await supervisor.waitForExit(5000);
|
||||
const stopped = await supervisor.stop();
|
||||
if (stopped.status === "incomplete")
|
||||
throw Object.assign(
|
||||
new Error(`MCP child cleanup incomplete: ${stopped.reason}`, {
|
||||
cause: stopped,
|
||||
}),
|
||||
{ cleanupOwner: supervisor },
|
||||
);
|
||||
assert(exited, "MCP close timeout");
|
||||
assert(supervisor.observedOutputClose(), "MCP output did not close");
|
||||
const exit = supervisor.observedExit();
|
||||
assert(
|
||||
exit?.code === 0 && exit.signal === null,
|
||||
`MCP server exited (${String(exit?.code)}, ${String(exit?.signal)}): ${stderr}`,
|
||||
);
|
||||
},
|
||||
]);
|
||||
@@ -0,0 +1,92 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
import { expect } from "vitest";
|
||||
|
||||
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
||||
import { processTest } from "../../support/process/processFixture.js";
|
||||
|
||||
const hash = (text: string) => createHash("sha256").update(text).digest("hex");
|
||||
|
||||
for (const mode of ["clean", "nonzero", "primary-clean", "primary-hang"]) {
|
||||
processTest(
|
||||
`source-location driver preserves task and shutdown outcomes: ${mode}`,
|
||||
async ({ processes }) => {
|
||||
const root = await createTestTempDirectory("rea-source-location-close-");
|
||||
await mkdir(join(root, "scripts"));
|
||||
await copyFile(
|
||||
resolve("tests/fixtures/sourceLocationDeliveryChild.mjs"),
|
||||
join(root, "scripts/rea.mjs"),
|
||||
);
|
||||
const text = "x".repeat(800);
|
||||
const map = JSON.stringify({
|
||||
version: 3,
|
||||
sources: ["authored.js"],
|
||||
sourcesContent: [text],
|
||||
names: [],
|
||||
mappings: "AAAA",
|
||||
});
|
||||
const point = { line: 1, column: 0 };
|
||||
await writeFile(join(root, "fixture.js.map"), map);
|
||||
await writeFile(
|
||||
join(root, "artifacts.json"),
|
||||
JSON.stringify([
|
||||
{
|
||||
path: "fixture.js.map",
|
||||
url: "https://fixture.invalid/fixture.js.map",
|
||||
bytes: Buffer.byteLength(map),
|
||||
sha256: hash(map),
|
||||
point,
|
||||
generated_script: { path: "fixture.js" },
|
||||
expected_matches: [
|
||||
{
|
||||
source_index: 0,
|
||||
source: "authored.js",
|
||||
original_line: 1,
|
||||
original_column: 300,
|
||||
content_sha256: hash(text),
|
||||
},
|
||||
],
|
||||
},
|
||||
]),
|
||||
);
|
||||
const result = await processes.run(
|
||||
process.execPath,
|
||||
[
|
||||
resolve("scripts/verify/analysis/source-location-delivery/task.mjs"),
|
||||
root,
|
||||
JSON.stringify({
|
||||
artifactDir: root,
|
||||
select: "fixture.",
|
||||
detail: "complete",
|
||||
}),
|
||||
],
|
||||
{
|
||||
env: { ...process.env, SOURCE_LOCATION_FIXTURE_MODE: mode },
|
||||
timeoutMs: 20_000,
|
||||
},
|
||||
);
|
||||
expect(result.signal).toBeNull();
|
||||
expect(await readFile(join(root, "closed.txt"), "utf8")).toBe("EOF");
|
||||
if (mode === "clean") {
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(JSON.parse(result.stdout)).toMatchObject({
|
||||
evidence_id: "fixture-evidence",
|
||||
source_map_sha256: hash(map),
|
||||
matches: [{ content: { snippet: { length_utf16: 512 } } }],
|
||||
});
|
||||
return;
|
||||
}
|
||||
expect(result.exitCode).not.toBe(0);
|
||||
if (mode === "nonzero") expect(result.stderr).toContain("17");
|
||||
if (mode.startsWith("primary"))
|
||||
expect(result.stderr).toContain("controlled primary mapping refusal");
|
||||
if (mode.endsWith("hang")) {
|
||||
expect(result.stderr).toContain("MCP close timeout");
|
||||
expect(await readFile(join(root, "terminated.txt"), "utf8")).toBe(
|
||||
"TERM",
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { createInterface } from "node:readline";
|
||||
|
||||
// A protocol fixture for driver shutdown; no REA or target code is loaded.
|
||||
const root = process.cwd();
|
||||
const mode = process.env.SOURCE_LOCATION_FIXTURE_MODE;
|
||||
const source = JSON.parse(
|
||||
readFileSync(join(root, "artifacts.json"), "utf8"),
|
||||
)[0];
|
||||
const map = readFileSync(join(root, source.path), "utf8");
|
||||
const text = JSON.parse(map).sourcesContent[0];
|
||||
const input = createInterface({ input: process.stdin });
|
||||
const reply = (id, result) =>
|
||||
console.log(JSON.stringify({ jsonrpc: "2.0", id, result }));
|
||||
|
||||
// Bound the fixture even if a broken driver never closes its child.
|
||||
setTimeout(() => process.exit(91), 12_000).unref();
|
||||
input.on("line", (line) => {
|
||||
const request = JSON.parse(line);
|
||||
if (request.id === undefined) return;
|
||||
if (request.method === "initialize") return reply(request.id, {});
|
||||
if (request.method === "tools/list")
|
||||
return reply(request.id, {
|
||||
tools: [{ name: "trace_web_source_location" }],
|
||||
});
|
||||
if (request.method !== "tools/call")
|
||||
throw new Error(`Unexpected fixture request: ${request.method}`);
|
||||
reply(request.id, {
|
||||
content: [],
|
||||
structuredContent: {
|
||||
evidence_id: "fixture-evidence",
|
||||
raw_result: { source_map_text: map },
|
||||
normalized_result: {
|
||||
source_map: {
|
||||
sha256: mode.startsWith("primary")
|
||||
? "controlled primary mapping refusal"
|
||||
: source.sha256,
|
||||
},
|
||||
lookup: {
|
||||
requested: source.point,
|
||||
matched_generated_position: source.point,
|
||||
},
|
||||
matches: [
|
||||
{
|
||||
state: "mapped",
|
||||
source_index: 0,
|
||||
reported_source: "authored.js",
|
||||
original_position: { line: 1, column: 300, offset: 300 },
|
||||
content: {
|
||||
state: "embedded",
|
||||
text,
|
||||
utf8_sha256: source.expected_matches[0].content_sha256,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
input.on("close", () => {
|
||||
writeFileSync(join(root, "closed.txt"), "EOF");
|
||||
if (!mode.endsWith("hang")) process.exit(mode === "nonzero" ? 17 : 0);
|
||||
setInterval(() => {}, 1000);
|
||||
process.on("SIGTERM", () => {
|
||||
writeFileSync(join(root, "terminated.txt"), "TERM");
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user