Files
reverse-engineering-anything/scripts/lib/real-hopper-fixture.mjs
T
morlutoandCursor Agent 83f0a4d238 fix(ci)!: verify exact conformance fixture records (#9977)
* fix(ci)!: verify exact conformance fixture records

BREAKING CHANGE: Regenerate unversioned conformance manifests with npm run build:fixtures. Schema version 2 separates exact string markers from intentional fragments and rejects the ambiguous strings field.

* test(conformance): wait out a cold verifier instead of treating SIGTERM as rejection

The compiler-produced complete/REA_C_ENTRY run was killed by its 10s
execFile timeout on the loaded source-test runner, with empty stderr and
SIGTERM. The stricter record checks already passed locally and for the
other compiler-produced cases. Assert the process status and give that
cold run room inside the test budget.

* fix(ci): preserve carriage returns in nm symbol records

nm -j terminates each name with LF. A carriage return before that LF is
part of the symbol. Splitting on CR LF dropped it, so a renamed symbol
ending in CR matched the name without it.

* test(ci): supervise conformance verifier subprocesses

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-11-11 17:28:10 +08:00

110 lines
3.7 KiB
JavaScript

import { readFile, realpath } from "node:fs/promises";
import { dirname } from "node:path";
import {
bindConformanceFixtureArtifact,
resolveConformanceFixturePath,
parseConformanceFixtureManifest,
} from "./conformance-fixtures.mjs";
/** Bind the real-Hopper semantic verifier to source-owned manifest artifacts. */
export async function loadRealHopperFixtureTargets(manifestPath) {
const canonicalManifest = await realpath(manifestPath);
const manifest = parseConformanceFixtureManifest(
JSON.parse(await readFile(canonicalManifest, "utf8")),
);
const primary = fixtureEntry(manifest.fixtures, "c");
const secondary = fixtureEntry(manifest.fixtures, "version-v2");
const large = fixtureEntry(manifest.fixtures, "large");
const oracle = requireCOracle(primary.expectations?.hopperOracle);
const largeOracle = requireLargeOracle(large.expectations);
const root = dirname(canonicalManifest);
const [primaryArtifact, secondaryArtifact, largeArtifact] = await Promise.all(
[primary, secondary, large].map(async (fixture) =>
bindConformanceFixtureArtifact(
await resolveConformanceFixturePath(root, fixture.artifact),
fixture,
),
),
);
const objc = manifest.fixtures.find((fixture) => fixture?.name === "objc");
const unicode =
objc === undefined ? undefined : fixtureEntry(manifest.fixtures, "objc");
const unicodeArtifact =
unicode === undefined
? undefined
: await bindConformanceFixtureArtifact(
await resolveConformanceFixturePath(root, unicode.artifact),
unicode,
);
requireDistinctArtifacts([
primaryArtifact,
secondaryArtifact,
largeArtifact,
...(unicodeArtifact === undefined ? [] : [unicodeArtifact]),
]);
return {
manifestPath: canonicalManifest,
primary: primaryArtifact,
secondary: secondaryArtifact,
large: largeArtifact,
...(unicodeArtifact === undefined ? {} : { unicode: unicodeArtifact }),
oracle,
largeOracle,
};
}
function requireCOracle(oracle) {
if (
oracle === null ||
typeof oracle !== "object" ||
typeof oracle.mainProcedure !== "string" ||
typeof oracle.entryProcedure !== "string" ||
typeof oracle.branchProcedure !== "string" ||
typeof oracle.leafProcedure !== "string" ||
typeof oracle.entryString !== "string" ||
typeof oracle.leafString !== "string" ||
typeof oracle.globalName !== "string" ||
[
oracle.mainProcedure,
oracle.entryProcedure,
oracle.branchProcedure,
oracle.leafProcedure,
oracle.entryString,
oracle.leafString,
oracle.globalName,
].some((value) => value.length === 0)
)
throw new Error("C fixture omitted its Hopper semantic oracle");
return oracle;
}
function requireLargeOracle(largeOracle) {
if (
largeOracle === null ||
typeof largeOracle !== "object" ||
typeof largeOracle.symbolPrefix !== "string" ||
largeOracle.symbolPrefix.length === 0 ||
typeof largeOracle.stringPrefix !== "string" ||
largeOracle.stringPrefix.length === 0 ||
!Number.isInteger(largeOracle.symbolCount) ||
largeOracle.symbolCount !== largeOracle.stringCount ||
largeOracle.symbolCount <= 0
)
throw new Error("Large fixture omitted its complete-inventory oracle");
return largeOracle;
}
function requireDistinctArtifacts(artifacts) {
if (
new Set(artifacts.map(({ path }) => path)).size !== artifacts.length ||
new Set(artifacts.map(({ sha256 }) => sha256)).size !== artifacts.length
)
throw new Error("Hopper conformance fixtures must be distinct artifacts");
}
function fixtureEntry(fixtures, name) {
const matches = fixtures.filter((fixture) => fixture?.name === name);
if (matches.length !== 1) throw new Error(`Missing fixture ${name}`);
return matches[0];
}