chore: import upstream snapshot with attribution
CI / Deep Native Runtime Cases (1/6) (push) Has been skipped
CI / Native Preflight (push) Failing after 1s
CI / Native Runtime Cases (1/2) (push) Failing after 0s
CI / Native Runtime Cases (2/2) (push) Failing after 1s
CI / Native Metadata Reports (push) Failing after 0s
CI / Native Direct Backend Artifacts (push) Failing after 0s
CI / Native Sanitizer Smoke (push) Failing after 1s
CI / Command Contract Snapshots (push) Failing after 1s
CI / Deep Conformance Suite (push) Has been skipped
CI / Graph Build Perf (push) Failing after 1s
CI / Deep Native Preflight (push) Has been skipped
CI / Deep Native Runtime Cases (2/6) (push) Has been skipped
CI / Deep Native Runtime Cases (3/6) (push) Has been skipped
CI / Conformance Suite (push) Failing after 1s
CI / Workspace Checks (push) Failing after 0s
CI / Deep Native Runtime Cases (5/6) (push) Has been skipped
CI / Deep Native Runtime Cases (6/6) (push) Has been skipped
CI / Deep Native Runtime Cases (4/6) (push) Has been skipped
CI / Deep Graph Build Perf (push) Has been skipped

This commit is contained in:
wehub-resource-sync
2026-07-13 12:29:30 +08:00
commit e7738de6d2
1723 changed files with 216139 additions and 0 deletions
+128
View File
@@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$root"
native_shards="${ZERO_AGENT_NATIVE_TEST_SHARDS:-4}"
if ! [[ "$native_shards" =~ ^[0-9]+$ ]] || (( native_shards < 1 )); then
echo "ZERO_AGENT_NATIVE_TEST_SHARDS must be a positive integer" >&2
exit 1
fi
dry_run="${ZERO_AGENT_CHECK_DRY_RUN:-0}"
work_root="${ZERO_AGENT_CHECK_WORK_ROOT:-/tmp/zero-agent-checks-$$}"
log_dir="${ZERO_AGENT_CHECK_LOG_DIR:-$root/.zero/agent-checks}"
mkdir -p "$work_root" "$log_dir" "$root/.zero/toolchains"
cleanup() {
if [[ "${ZERO_AGENT_CHECK_KEEP_WORKDIR:-}" != "1" ]]; then
rm -rf "$work_root"
fi
}
trap cleanup EXIT
zig_platform() {
case "$(uname -s):$(uname -m)" in
Linux:x86_64) printf "linux-x64" ;;
Darwin:arm64 | Darwin:aarch64) printf "macos-aarch64" ;;
Darwin:x86_64) printf "macos-x86_64" ;;
*)
echo "unsupported host for pinned Zig installer: $(uname -s):$(uname -m)" >&2
exit 1
;;
esac
}
zig_dir="$root/.zero/toolchains/zig-0.14.1-$(zig_platform)"
if [[ "$dry_run" != "1" ]]; then
bash scripts/install-zig.sh >/dev/null
fi
export PATH="$zig_dir:$PATH"
prepare_job_dir() {
local name="$1"
local dir="$work_root/$name"
mkdir -p "$dir"
(
cd "$root"
tar \
--exclude='./.git' \
--exclude='./.zero' \
--exclude='./node_modules' \
--exclude='./docs/.next' \
--exclude='./docs/node_modules' \
-cf - .
) | (
cd "$dir"
tar -xf -
)
printf "%s" "$dir"
}
pids=()
names=()
logs=()
run_job() {
local name="$1"
shift
if [[ "$dry_run" == "1" ]]; then
echo "would start: $name: $*"
return
fi
local dir
dir="$(prepare_job_dir "$name")"
local log="$log_dir/$name.log"
names+=("$name")
logs+=("$log")
(
cd "$dir"
export PATH="$PATH"
pnpm install --frozen-lockfile --prefer-offline
"$@"
) >"$log" 2>&1 &
pids+=("$!")
echo "started: $name"
}
run_job conformance pnpm run conformance:local
for shard in $(seq 1 "$native_shards"); do
run_job "native-tests-${shard}-of-${native_shards}" env ZERO_NATIVE_TEST_SHARD="${shard}/${native_shards}" pnpm run native:test:local
done
run_job native-sanitizer-smoke pnpm run native:sanitize
run_job command-contract-snapshots pnpm run command-contracts:local
run_job workspace-checks bash scripts/workspace-checks.sh
if [[ "$dry_run" == "1" ]]; then
echo "agent checks plan ok"
exit 0
fi
failed=0
for i in "${!pids[@]}"; do
if wait "${pids[$i]}"; then
echo "ok: ${names[$i]}"
else
echo "failed: ${names[$i]}"
echo "log: ${logs[$i]}"
failed=1
fi
done
if (( failed != 0 )); then
echo
echo "failed job logs:"
for i in "${!pids[@]}"; do
if [[ -f "${logs[$i]}" ]]; then
echo "--- ${names[$i]} (${logs[$i]}) ---"
tail -n 80 "${logs[$i]}"
fi
done
exit 1
fi
echo "agent checks ok"
+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const outDir = ".zero/agent-repair-demo";
mkdirSync(outDir, { recursive: true });
const brokenSource = `pub fn main(world: World) -> Void raises {
let src: [4]u8 = [1, 2, 3, 4]
let dst: [4]u8 = [0, 0, 0, 0]
let copied: usize = std.mem.copy(dst, src)
if copied == 4 {
check world.out.write("copied\\n")
}
}
`;
const workFile = join(outDir, "main.0");
const workGraph = join(outDir, "main.graph");
writeFileSync(workFile, brokenSource);
function zeroJson(args, allowFailure = false) {
try {
return JSON.parse(execFileSync("bin/zero", args, { encoding: "utf8" }));
} catch (error) {
if (!allowFailure) throw error;
return JSON.parse(error.stdout.toString());
}
}
const importPlan = zeroJson(["import", "--json", "--format", "binary", "--out", workGraph, workFile], true);
assert.equal(importPlan.ok, false);
assert.equal(importPlan.diagnostics[0].code, "TYP009");
assert.equal(importPlan.diagnostics[0].repair.id, "make-binding-mutable");
const explain = zeroJson(["explain", "--json", "TYP009"]);
assert.equal(explain.code, "TYP009");
assert.equal(explain.repair.id, "make-binding-mutable");
const repair = importPlan.diagnostics[0].repair;
assert.equal(repair.id, "make-binding-mutable");
const fixedSource = brokenSource
.replace(" let dst: [4]u8", " var dst: [4]u8")
.replace(" let _copied: i32", " let _copied: usize");
writeFileSync(workFile, fixedSource);
const fixedImport = zeroJson(["import", "--json", "--format", "binary", "--out", workGraph, workFile]);
assert.equal(fixedImport.ok, true);
const fixed = zeroJson(["check", "--json", workGraph]);
assert.equal(fixed.ok, true);
assert.equal(fixed.diagnostics.length, 0);
const projectDir = join(outDir, "project");
rmSync(projectDir, { recursive: true, force: true });
execFileSync("bin/zero", ["new", "package", projectDir], { stdio: ["ignore", "ignore", "pipe"] });
function assertNoC(body) {
assert.equal(body.generatedCBytes ?? 0, 0);
assert.equal(body.cBridgeFallback ?? body.selfHostRouting?.cBridge?.required ?? false, false);
assert.notEqual(body.legacy, true);
}
const projectCheck = zeroJson(["check", "--json", projectDir]);
assert.equal(projectCheck.ok, true);
assertNoC(projectCheck);
const projectTest = zeroJson(["test", "--json", projectDir]);
assert.equal(projectTest.ok, true);
assert.equal(projectTest.testBackend, "direct-program-graph");
assertNoC(projectTest);
const projectMain = join(projectDir, "src", "main.0");
const projectMainSource = readFileSync(projectMain, "utf8");
writeFileSync(projectMain, projectMainSource.split('\n\ntest "package import works"')[0] + "\n");
const projectGraph = zeroJson(["inspect", "--json", projectDir]);
assert.equal(projectGraph.selfHostRouting.cBridge.required, false);
const projectDoc = zeroJson(["doc", "--json", projectDir]);
assertNoC(projectDoc);
const projectSize = zeroJson(["size", "--json", projectDir]);
assertNoC(projectSize);
const projectMem = zeroJson(["mem", "--json", projectDir]);
assertNoC(projectMem);
const releaseOut = join(outDir, "project-linux-release");
const projectRelease = zeroJson(["build", "--json", "--release", "tiny", "--target", "linux-musl-x64", projectDir, "--out", releaseOut]);
assert.equal(projectRelease.emit, "exe");
assert.equal(projectRelease.compiler, "zero-elf64");
assertNoC(projectRelease);
console.log("agent repair demo ok");
+82
View File
@@ -0,0 +1,82 @@
import nodeAssert from "node:assert/strict";
import { mkdirSync, writeFileSync } from "node:fs";
import { dirname } from "node:path";
const methods = ["deepEqual", "doesNotMatch", "equal", "match", "notEqual", "ok"];
function formatError(error) {
if (!(error instanceof Error)) return String(error);
return error.stack || error.message;
}
function formatFailure(failure, index) {
const header = `${index + 1}. ${failure.method}: ${failure.message}`;
return failure.stack ? `${header}\n${failure.stack}` : header;
}
export function createAggregateAssert(options = {}) {
const failFast = process.env.ZERO_VALIDATION_FAIL_FAST === "1" ||
process.env.ZERO_ASSERT_FAIL_FAST === "1" ||
options.failFast === true;
const failures = [];
function record(method, error) {
if (failFast) throw error;
failures.push({
method,
message: error instanceof Error ? error.message : String(error),
stack: error instanceof Error ? error.stack : "",
});
}
function aggregateAssert(value, message) {
try {
nodeAssert(value, message);
} catch (error) {
record("assert", error);
}
}
for (const method of methods) {
aggregateAssert[method] = (...args) => {
try {
nodeAssert[method](...args);
} catch (error) {
record(method, error);
}
};
}
aggregateAssert.fail = (...args) => {
try {
nodeAssert.fail(...args);
} catch (error) {
record("fail", error);
}
};
aggregateAssert.failures = failures;
return aggregateAssert;
}
export function finishAggregateAssert(assert, options = {}) {
const failures = assert?.failures ?? [];
if (failures.length === 0) return;
const suite = options.suite || "validation";
const reportPath = options.reportPath;
const summary = failures.map(formatFailure).join("\n\n");
const text = `${suite} collected ${failures.length} assertion failure(s):\n\n${summary}\n`;
if (reportPath) {
mkdirSync(dirname(reportPath), { recursive: true });
writeFileSync(reportPath, `${JSON.stringify({ suite, ok: false, failures }, null, 2)}\n`);
}
process.stderr.write(text);
process.exit(1);
}
export function describeFailure(error) {
return formatError(error);
}
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdir, mkdtemp, rm, stat, symlink, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const root = process.cwd();
const zero = "bin/zero";
const fixture = "examples/hello.graph";
const tempDir = await mkdtemp("/tmp/zero-artifact-finalization-");
const outDir = join(tempDir, "out");
const exe = join(outDir, "hello");
const dirOutput = join(outDir, "as-directory");
const symlinkTarget = join(outDir, "symlink-target");
const symlinkOutput = join(outDir, "as-symlink");
type CommandFailure = {
status: number | null;
stdout: string;
stderr: string;
};
async function runZero(args: string[]) {
return execFileAsync(zero, args, { cwd: root, timeout: 20000 });
}
async function expectZeroFailure(args: string[]): Promise<CommandFailure> {
try {
await runZero(args);
} catch (error) {
const failure = error as CommandFailure;
assert.notEqual(failure.status, 0);
return {
status: failure.status ?? null,
stdout: failure.stdout ?? "",
stderr: failure.stderr ?? "",
};
}
assert.fail(`expected zero ${args.join(" ")} to fail`);
}
function assertMentionsPathRejection(failure: CommandFailure) {
const text = `${failure.stdout}\n${failure.stderr}`;
assert.match(text, /regular|directory|symlink|artifact|output/i);
}
async function assertExecutable(path: string) {
const info = await stat(path);
assert.equal(info.isFile(), true);
assert.ok(info.size > 0, "executable output must be non-empty");
if (process.platform !== "win32") {
assert.notEqual(info.mode & 0o111, 0, "executable output must have an execute bit");
}
}
async function assertRunnable(path: string) {
const { stdout, stderr } = await execFileAsync(path, [], { timeout: 5000 });
assert.equal(stderr, "");
assert.equal(stdout.trim(), "hello from zero");
}
try {
await mkdir(outDir, { recursive: true });
await runZero(["build", "--out", exe, fixture]);
await assertExecutable(exe);
await assertRunnable(exe);
await mkdir(dirOutput);
const directoryFailure = await expectZeroFailure(["build", "--out", dirOutput, fixture]);
assertMentionsPathRejection(directoryFailure);
if (process.platform !== "win32") {
await writeFile(symlinkTarget, "not an executable\n");
await symlink(symlinkTarget, symlinkOutput);
const symlinkFailure = await expectZeroFailure(["build", "--out", symlinkOutput, fixture]);
assertMentionsPathRejection(symlinkFailure);
}
console.log("artifact finalization smoke ok");
} finally {
await rm(tempDir, { recursive: true, force: true });
}
+1115
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$root"
mode="${ZERO_BENCH_MODE:-local}"
if [[ " $* " == *" --mode local "* ]]; then
mode="local"
fi
if [[ "$mode" == "local" ]]; then
make -C native/zero-c >/dev/null
fi
if [[ " $* " == *" --mode "* ]]; then
scripts/bench.mts "$@"
else
scripts/bench.mts --mode "$mode" "$@"
fi
+54
View File
@@ -0,0 +1,54 @@
import { existsSync } from "node:fs";
import { readdir, rm } from "node:fs/promises";
import { execFile } from "node:child_process";
import path from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const cc = process.env.CC ?? "cc";
const out = `/tmp/zero-canonical-text-smoke-${process.pid}`;
async function fixtureArgs(root: string) {
const canonicalDir = path.join(root, "fixtures/canonical");
const rejectDir = path.join(root, "fixtures/reject");
const args: string[] = [];
if (existsSync(canonicalDir)) {
for (const name of (await readdir(canonicalDir)).filter((item) => item.endsWith(".canonical.0")).sort()) {
args.push("--accept", path.join(canonicalDir, name));
}
}
if (existsSync(rejectDir)) {
for (const name of (await readdir(rejectDir)).filter((item) => item.endsWith(".0")).sort()) {
args.push("--reject", path.join(rejectDir, name));
}
}
return args;
}
try {
const nativeSources = (await readdir("native/zero-c/src"))
.filter((name) => name.endsWith(".c") && name !== "main.c")
.sort()
.map((name) => path.join("native/zero-c/src", name));
await execFileAsync(cc, [
"-std=c11",
"-Wall",
"-Wextra",
"-Wpedantic",
"-I",
"native/zero-c/include",
"-I",
"native/zero-c/src",
...nativeSources,
"native/zero-c/tests/canonical_text_smoke.c",
"-o",
out,
]);
const args = process.env.ZERO_CANONICAL_TEXT_FIXTURES ? await fixtureArgs(process.env.ZERO_CANONICAL_TEXT_FIXTURES) : [];
const result = await execFileAsync(out, args, { maxBuffer: 1024 * 1024 * 8 });
if (!result.stdout.includes("canonical text smoke ok")) {
throw new Error(`unexpected canonical text smoke output: ${result.stdout}`);
}
} finally {
await rm(out, { force: true });
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const zeroBin = path.join(repoRoot, "bin/zero");
const stdRoot = path.join(repoRoot, "std");
const tmpRoot = path.join(os.tmpdir(), `zero-stdlib-binary-graphs-${process.pid}`);
function runZero(args: string[]) {
const result = spawnSync(zeroBin, args, {
cwd: repoRoot,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
if (result.status !== 0) {
const command = ["bin/zero", ...args].join(" ");
const output = `${result.stdout || ""}${result.stderr || ""}`.trim();
throw new Error(`${command} failed\n${output}`);
}
}
fs.mkdirSync(tmpRoot, { recursive: true });
const graphs = fs.readdirSync(stdRoot)
.filter((name) => name.endsWith(".graph"))
.sort((a, b) => a.localeCompare(b));
for (const name of graphs) {
const relative = `std/${name}`;
const tmp = path.join(tmpRoot, name);
runZero(["validate", "--format", "binary", "--out", tmp, relative]);
const magic = fs.readFileSync(tmp).subarray(0, 8).toString("latin1");
if (magic !== "ZRGBIN1\0") throw new Error(`${relative}: generated graph is not a binary graph store`);
fs.renameSync(tmp, path.join(repoRoot, relative));
}
fs.rmSync(tmpRoot, { recursive: true, force: true });
console.log(`converted ${graphs.length} std graph store(s) to binary`);
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const outPath = path.join(repoRoot, "native/zero-c/src/embedded_runtime_sources.inc");
const inputs = [
["zero_embedded_zero_runtime_h", "native/zero-c/include/zero_runtime.h"],
["zero_embedded_zero_runtime_c", "native/zero-c/runtime/zero_runtime.c"],
["zero_embedded_zero_http_curl_c", "native/zero-c/runtime/zero_http_curl.c"],
];
function chunkText(text) {
const chunks = [];
let current = "";
for (const line of text.match(/[^\n]*\n|[^\n]+$/g) || []) {
if (current && JSON.stringify(current + line).length > 3000) {
chunks.push(current);
current = "";
}
if (JSON.stringify(line).length <= 3000) {
current += line;
continue;
}
for (let index = 0; index < line.length; index += 1400) {
if (current) {
chunks.push(current);
current = "";
}
chunks.push(line.slice(index, index + 1400));
}
}
if (current) chunks.push(current);
return chunks;
}
const out = [];
out.push("/* Generated from Zero runtime sources. Run node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/embed-runtime-sources.mts to refresh. */");
out.push("#ifndef ZERO_EMBEDDED_RUNTIME_SOURCES_INC");
out.push("#define ZERO_EMBEDDED_RUNTIME_SOURCES_INC");
out.push("");
for (const [name, relativePath] of inputs) {
const text = fs.readFileSync(path.join(repoRoot, relativePath), "utf8");
out.push(`static const char *const ${name}[] = {`);
for (const chunk of chunkText(text)) {
out.push(` ${JSON.stringify(chunk)},`);
}
out.push(" NULL");
out.push("};");
out.push("");
}
out.push("#endif");
out.push("");
fs.writeFileSync(outPath, out.join("\n"));
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const outPath = path.join(repoRoot, "native/zero-c/src/embedded_skills.inc");
const inputs = [
"skills/zero/SKILL.md",
...fs.readdirSync(path.join(repoRoot, "skill-data"))
.filter((name) => name.endsWith(".md"))
.sort((a, b) => a.localeCompare(b))
.map((name) => `skill-data/${name}`),
];
type EmbeddedSkill = {
name: string;
description: string;
hidden: boolean;
relativePath: string;
text: string;
ident?: string;
};
function parseFrontmatter(text, relativePath): Omit<EmbeddedSkill, "relativePath" | "text" | "ident"> {
const match = text.trimStart().match(/^---\r?\n([\s\S]*?)\r?\n---/);
if (!match) throw new Error(`${relativePath}: missing skill frontmatter`);
const lines = match[1].split(/\r?\n/);
let name = null;
let description = "";
let hidden = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith("name:")) {
name = line.slice("name:".length).trim();
} else if (line.startsWith("description:")) {
const parts = [line.slice("description:".length).trim()];
while (i + 1 < lines.length && /^( |\t)/.test(lines[i + 1])) {
parts.push(lines[++i].trim());
}
description = parts.join(" ");
} else if (line.startsWith("hidden:")) {
hidden = ["true", "yes"].includes(line.slice("hidden:".length).trim());
}
}
if (!name) throw new Error(`${relativePath}: missing skill name`);
return { name, description, hidden };
}
function chunkText(text) {
const chunks = [];
let current = "";
for (const line of text.match(/[^\n]*\n|[^\n]+$/g) || []) {
if (current && JSON.stringify(current + line).length > 3000) {
chunks.push(current);
current = "";
}
if (JSON.stringify(line).length <= 3000) {
current += line;
continue;
}
for (let index = 0; index < line.length; index += 1400) {
if (current) {
chunks.push(current);
current = "";
}
chunks.push(line.slice(index, index + 1400));
}
}
if (current) chunks.push(current);
return chunks;
}
function cIdent(text) {
return text.replace(/[^A-Za-z0-9_]/g, "_");
}
const skills: EmbeddedSkill[] = inputs.map((relativePath) => {
const text = fs.readFileSync(path.join(repoRoot, relativePath), "utf8");
return { ...parseFrontmatter(text, relativePath), relativePath, text };
}).sort((a, b) => a.name.localeCompare(b.name));
const out = [];
out.push("/* Generated from Zero skill data. Run node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/embed-skill-data.mts to refresh. */");
out.push("#ifndef ZERO_EMBEDDED_SKILLS_INC");
out.push("#define ZERO_EMBEDDED_SKILLS_INC");
out.push("");
out.push("typedef struct {");
out.push(" const char *name;");
out.push(" const char *description;");
out.push(" bool hidden;");
out.push(" const char *const *content;");
out.push("} ZeroEmbeddedSkill;");
out.push("");
for (const skill of skills) {
const ident = `zero_embedded_skill_${cIdent(skill.name)}_chunks`;
skill.ident = ident;
out.push(`static const char *const ${ident}[] = {`);
for (const chunk of chunkText(skill.text)) {
out.push(` ${JSON.stringify(chunk)},`);
}
out.push(" NULL");
out.push("};");
out.push("");
}
out.push("static const ZeroEmbeddedSkill zero_embedded_skills[] = {");
for (const skill of skills) {
out.push(` {${JSON.stringify(skill.name)}, ${JSON.stringify(skill.description)}, ${skill.hidden ? "true" : "false"}, ${skill.ident}},`);
}
out.push("};");
out.push("static const size_t zero_embedded_skill_count = sizeof(zero_embedded_skills) / sizeof(zero_embedded_skills[0]);");
out.push("");
out.push("#endif");
out.push("");
fs.writeFileSync(outPath, out.join("\n"));
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const stdRoot = path.join(repoRoot, "std");
const outPath = path.join(repoRoot, "native/zero-c/src/embedded_stdlib_graph.inc");
const outDir = path.join(repoRoot, "native/zero-c/src/embedded_stdlib_graph");
function cIdent(text: string): string {
return text.replace(/[^A-Za-z0-9_]/g, "_");
}
function appendByteArray(out: string[], ident: string, bytes: Buffer) {
out.push(`static const unsigned char ${ident}[] = {`);
const rowWidth = 64;
for (let offset = 0; offset < bytes.length; offset += rowWidth) {
const row = [...bytes.subarray(offset, Math.min(offset + rowWidth, bytes.length))]
.map((byte) => `0x${byte.toString(16).padStart(2, "0")}`)
.join(", ");
out.push(` ${row},`);
}
out.push("};");
}
const fnvPrime = 1099511628211n;
const fnvMask = (1n << 64n) - 1n;
function fnvMul(hash: bigint): bigint {
return (hash * fnvPrime) & fnvMask;
}
function hashText(hash: bigint, text: string): bigint {
for (const byte of Buffer.from(text)) {
hash ^= BigInt(byte);
hash = fnvMul(hash);
}
hash ^= 0xffn;
return fnvMul(hash);
}
function hashBytes(hash: bigint, bytes: Buffer): bigint {
hash ^= BigInt(bytes.length);
hash = fnvMul(hash);
for (const byte of bytes) {
hash ^= BigInt(byte);
hash = fnvMul(hash);
}
return hash;
}
const inputs = fs.existsSync(stdRoot)
? fs.readdirSync(stdRoot)
.filter((name) => name.endsWith(".graph"))
.sort((a, b) => a.localeCompare(b))
.map((name) => `std/${name}`)
: [];
const out: string[] = [];
out.push("/* Generated from Zero standard-library binary ProgramGraphs. Run node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/embed-stdlib-graphs.mts to refresh. */");
out.push("#ifndef ZERO_EMBEDDED_STDLIB_GRAPH_INC");
out.push("#define ZERO_EMBEDDED_STDLIB_GRAPH_INC");
out.push("");
fs.rmSync(outDir, { recursive: true, force: true });
fs.mkdirSync(outDir, { recursive: true });
let fingerprint = hashText(1469598103934665603n, "zero-embedded-stdlib-graph-v1");
for (const relativePath of inputs) {
const ident = `zero_embedded_stdlib_graph_${cIdent(relativePath)}_bytes`;
const partName = `${cIdent(relativePath)}.inc`;
const part: string[] = [];
const bytes = fs.readFileSync(path.join(repoRoot, relativePath));
const moduleName = relativePath.slice(0, -".graph".length).replace("/", ".");
const modulePath = relativePath.slice(0, -".graph".length) + ".0";
fingerprint = hashText(fingerprint, moduleName);
fingerprint = hashText(fingerprint, modulePath);
fingerprint = hashBytes(fingerprint, bytes);
part.push(`/* Generated from ${relativePath}. */`);
appendByteArray(part, ident, bytes);
part.push("");
fs.writeFileSync(path.join(outDir, partName), part.join("\n"));
out.push(`#include "embedded_stdlib_graph/${partName}"`);
}
out.push("");
out.push(`#define ZERO_EMBEDDED_STDLIB_GRAPH_FINGERPRINT 0x${fingerprint.toString(16).padStart(16, "0")}ull`);
out.push("");
out.push("#endif");
out.push("");
fs.writeFileSync(outPath, out.join("\n"));
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { spawn, spawnSync } from "node:child_process";
import { existsSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
// Every example package with a committed zero.graph must pass `zero check`,
// build an executable for the canonical linux-musl-x64 target, and `zero run`
// cleanly. This closes the gap where a stale example keeps passing check while
// run-compilation fails. Host-backend gaps (for example fs programs on the
// Mach-O direct backend) are tolerated only after the linux build proves the
// package is not stale; hosts whose backend supports the package still run it.
const zeroBin = resolve("bin/zero");
const examplesDir = resolve("examples");
const buildTarget = "linux-musl-x64";
const runTimeoutMs = 120_000;
const buildTimeoutMs = 300_000;
type Expectation = {
exitCode?: number;
output?: string;
server?: { readyText: string };
};
const expectations: Record<string, Expectation> = {
"batch3-cli": { output: "batch3 cli ok" },
"direct-package-arrays": { exitCode: 13 },
"direct-package-call-order": { exitCode: 27 },
"memory-package": { output: "memory package ok" },
"ping-pong-api": { server: { readyText: "listening on " } },
"readall-cli": { output: "readall cli ok" },
"resource-cli": { output: "resource cli ok" },
"systems-package": { output: "systems package" },
"zero-hash": { output: "zero-hash ok" },
};
const packages = readdirSync(examplesDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory() && existsSync(join(examplesDir, entry.name, "zero.graph")))
.map((entry) => entry.name)
.sort();
if (packages.length === 0) {
console.error("examples gate found no example packages with committed zero.graph stores");
process.exit(1);
}
const staleExpectations = Object.keys(expectations).filter((name) => !packages.includes(name));
if (staleExpectations.length > 0) {
console.error(`examples gate expectations name missing packages: ${staleExpectations.join(", ")}`);
process.exit(1);
}
function runZero(args: string[], cwd: string, timeoutMs = runTimeoutMs) {
const result = spawnSync(zeroBin, args, {
cwd,
encoding: "utf8",
timeout: timeoutMs,
stdio: ["ignore", "pipe", "pipe"],
});
return {
code: result.status,
signal: result.signal,
stdout: result.stdout ?? "",
stderr: result.stderr ?? "",
error: result.error?.message ?? "",
timedOut: result.error !== undefined && "code" in result.error && result.error.code === "ETIMEDOUT",
timeoutMs,
};
}
function zeroFailure(action: string, result: ReturnType<typeof runZero>) {
const detail = result.stderr || result.stdout || result.error;
if (result.timedOut) {
return `${action} timed out after ${result.timeoutMs}ms${detail ? `\n${detail}` : ""}`;
}
return `${action} failed (exit ${result.code}${result.signal ? ` signal ${result.signal}` : ""})${detail ? `\n${detail}` : ""}`;
}
function isHostBackendGap(text: string) {
return text.includes("BLD004") && text.includes("executable buildability subset");
}
async function probeServer(packagePath: string, readyText: string, workDir: string) {
return await new Promise<{ ok: boolean; detail: string }>((settle) => {
const child = spawn(zeroBin, ["run", packagePath], { cwd: workDir, detached: true, stdio: ["ignore", "pipe", "pipe"] });
let output = "";
let done = false;
const finish = (ok: boolean, detail: string) => {
if (done) return;
done = true;
clearTimeout(timer);
if (child.pid !== undefined && child.exitCode === null) {
try {
process.kill(-child.pid, "SIGKILL");
} catch {
child.kill("SIGKILL");
}
}
settle({ ok, detail });
};
const timer = setTimeout(() => finish(false, `server never printed '${readyText}'\n${output}`), runTimeoutMs);
const onChunk = (chunk: Buffer) => {
output += chunk.toString();
if (output.includes(readyText)) finish(true, "server ready");
};
child.stdout.on("data", onChunk);
child.stderr.on("data", onChunk);
child.on("error", (error) => finish(false, error.message));
child.on("exit", (code, signal) => finish(false, `server exited before readiness: code ${code} signal ${signal}\n${output}`));
});
}
const failures: string[] = [];
const startedAt = Date.now();
for (const name of packages) {
const packagePath = join(examplesDir, name);
const expectation = expectations[name] ?? {};
const workDir = mkdtempSync(join(tmpdir(), `zero-examples-gate-${name}-`));
const steps: string[] = [];
let failure = "";
const check = runZero(["check", packagePath], workDir);
if (check.code === 0) {
steps.push("check");
} else {
failure = zeroFailure("zero check", check);
}
let linuxBuildOk = false;
if (!failure && !expectation.server) {
const build = runZero(["build", "--emit", "exe", "--target", buildTarget, packagePath, "--out", join(workDir, `${name}-${buildTarget}`)], workDir, buildTimeoutMs);
if (build.code === 0) {
linuxBuildOk = true;
steps.push(`build ${buildTarget}`);
} else {
failure = zeroFailure(`zero build --target ${buildTarget}`, build);
}
}
if (!failure && expectation.server) {
const probe = await probeServer(packagePath, expectation.server.readyText, workDir);
if (probe.ok) {
steps.push("run server-ready");
} else {
failure = `zero run server probe failed: ${probe.detail}`;
}
} else if (!failure) {
const expectedExit = expectation.exitCode ?? 0;
// Arguments after the input belong to the program (zero run [input] -- <args>),
// so --out must precede the package path or it lands in the program argv.
const run = runZero(["run", "--out", join(workDir, `${name}-exe`), packagePath], workDir);
const runText = `${run.stdout}${run.stderr}`;
if (run.code !== expectedExit && linuxBuildOk && isHostBackendGap(runText)) {
steps.push("run host-backend-gap");
} else if (run.code !== expectedExit) {
failure = `zero run exited ${run.code}${run.signal ? ` signal ${run.signal}` : ""}, expected ${expectedExit}\n${runText}`;
} else if (expectation.output && !run.stdout.includes(expectation.output)) {
failure = `zero run output missing '${expectation.output}'\n${runText}`;
} else {
steps.push("run");
}
}
// Retry the teardown: macOS indexing can briefly repopulate the temp tree
// while rm walks it, surfacing as ENOTEMPTY on an otherwise clean removal.
rmSync(workDir, { force: true, recursive: true, maxRetries: 5, retryDelay: 100 });
if (failure) {
failures.push(`${name}: ${failure.trimEnd()}`);
console.error(`examples gate FAIL: ${name}`);
} else {
console.log(`examples gate ok: ${name} (${steps.join(", ")})`);
}
}
if (failures.length > 0) {
console.error(`\nexamples gate failed for ${failures.length} package(s):\n`);
for (const failure of failures) console.error(`${failure}\n`);
process.exit(1);
}
console.log(`examples gate ok: ${packages.length} packages in ${((Date.now() - startedAt) / 1000).toFixed(1)}s`);
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const root = process.cwd();
const tempDir = await mkdtemp("/tmp/zero-fs-runtime-");
const src = join(tempDir, "fs-runtime-smoke.c");
const exe = join(tempDir, "fs-runtime-smoke");
const input = join(tempDir, "input.txt");
const large = join(tempDir, "large.bin");
const nestedDir = join(tempDir, "nested");
const missing = join(tempDir, "missing.txt");
const harness = String.raw`
#include "zero_runtime.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static ZeroByteView bytes(const char *text) {
return (ZeroByteView){(const unsigned char *)text, strlen(text)};
}
static ZeroMutByteView mut_bytes(unsigned char *ptr, size_t len) {
return (ZeroMutByteView){ptr, len};
}
static int fail(const char *name) {
fprintf(stderr, "fs runtime smoke failed: %s\n", name);
return 1;
}
static int expect_true(int ok, const char *name) {
return ok ? 0 : fail(name);
}
static int expect_none(ZeroMaybeUsize result, const char *name) {
return expect_true(result.has == 0 && result.value == 0, name);
}
static int expect_small_read(const char *path) {
unsigned char buffer[64];
memset(buffer, 0, sizeof(buffer));
ZeroMaybeUsize result = zero_fs_read_bytes(bytes(path), mut_bytes(buffer, sizeof(buffer)));
return expect_true(
result.has == 1 &&
result.value == 14 &&
memcmp(buffer, "hello runtime\n", 14) == 0 &&
buffer[14] == 0,
"read regular file"
);
}
static int expect_partial_read(const char *path) {
unsigned char buffer[5];
memset(buffer, 0, sizeof(buffer));
ZeroMaybeUsize result = zero_fs_read_bytes(bytes(path), mut_bytes(buffer, sizeof(buffer)));
return expect_true(
result.has == 1 &&
result.value == 14 &&
memcmp(buffer, "hello", sizeof(buffer)) == 0,
"read partial buffer reports total size"
);
}
static int expect_zero_len_read(const char *path) {
unsigned char buffer[1] = {0xaa};
ZeroMaybeUsize result = zero_fs_read_bytes(bytes(path), mut_bytes(buffer, 0));
return expect_true(result.has == 1 && result.value == 14 && buffer[0] == 0xaa, "read zero-length buffer reports total size");
}
static int expect_large_read(const char *path) {
const size_t len = 1048576u + 17u;
unsigned char *buffer = (unsigned char *)malloc(len);
if (!buffer) return fail("allocate large read buffer");
memset(buffer, 0, len);
ZeroMaybeUsize result = zero_fs_read_bytes(bytes(path), mut_bytes(buffer, len));
int ok = result.has == 1 && result.value == len;
for (size_t i = 0; ok && i < len; i++) {
ok = buffer[i] == 'z';
}
free(buffer);
return expect_true(ok, "read large file");
}
static int expect_rejected_inputs(const char *directory, const char *missing) {
unsigned char buffer[16];
memset(buffer, 0, sizeof(buffer));
int status = 0;
status |= expect_none(zero_fs_read_bytes(bytes(directory), mut_bytes(buffer, sizeof(buffer))), "reject directory");
status |= expect_none(zero_fs_read_bytes(bytes(missing), mut_bytes(buffer, sizeof(buffer))), "reject missing file");
status |= expect_none(zero_fs_read_bytes((ZeroByteView){NULL, 1}, mut_bytes(buffer, sizeof(buffer))), "reject null path");
status |= expect_none(zero_fs_read_bytes((ZeroByteView){(const unsigned char *)"", 0}, mut_bytes(buffer, sizeof(buffer))), "reject empty path");
status |= expect_none(zero_fs_read_bytes(bytes(missing), (ZeroMutByteView){NULL, sizeof(buffer)}), "reject null buffer");
status |= expect_none(zero_fs_read_bytes(bytes(missing), (ZeroMutByteView){NULL, 0}), "reject null zero-length buffer");
char long_path[4097];
memset(long_path, 'a', 4096);
long_path[4096] = '\0';
status |= expect_none(
zero_fs_read_bytes((ZeroByteView){(const unsigned char *)long_path, 4096}, mut_bytes(buffer, sizeof(buffer))),
"reject path at runtime limit"
);
return status;
}
int main(int argc, char **argv) {
if (argc != 5) return fail("expected input, large, directory, and missing paths");
int status = 0;
status |= expect_small_read(argv[1]);
status |= expect_partial_read(argv[1]);
status |= expect_zero_len_read(argv[1]);
status |= expect_large_read(argv[2]);
status |= expect_rejected_inputs(argv[3], argv[4]);
return status;
}
`;
try {
await mkdir(nestedDir);
await writeFile(input, "hello runtime\n");
await writeFile(large, Buffer.alloc(1048576 + 17, "z"));
await writeFile(src, harness);
await execFileAsync("cc", [
"-std=c11",
"-Wall",
"-Wextra",
"-Wpedantic",
"-Inative/zero-c/include",
"native/zero-c/runtime/zero_runtime.c",
src,
"-o",
exe,
], { cwd: root });
const { stdout, stderr } = await execFileAsync(exe, [input, large, nestedDir, missing], { timeout: 5000 });
assert.equal(stderr, "");
assert.equal(stdout, "");
console.log("fs runtime smoke ok");
} finally {
await rm(tempDir, { recursive: true, force: true });
}
+428
View File
@@ -0,0 +1,428 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { execFile } from "node:child_process";
import { mkdir, rm } from "node:fs/promises";
import { join } from "node:path";
import { performance } from "node:perf_hooks";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const zero = process.env.ZERO_BIN || "bin/zero";
const target = process.env.ZERO_GRAPH_BUILD_PERF_TARGET || "linux-musl-x64";
const outRoot = process.env.ZERO_GRAPH_BUILD_PERF_DIR || `/tmp/zero-graph-build-perf-${process.pid}`;
const maxBuffer = 128 * 1024 * 1024;
type Fixture = {
name: string;
input: string;
target?: string;
checkTarget?: string;
};
type CommandRun = {
ok: boolean;
command: string[];
wallMs: number;
body: any;
stderr: string;
};
type PerformanceBudget = {
name: string;
fixture: string;
pass: "cold" | "warm";
command: "build" | "check";
metric: string;
max: number;
unit: "ms" | "bytes";
};
const fixtures: Fixture[] = [
{ name: "hello-artifact", input: "examples/hello.graph" },
{ name: "stdlib-heavy-artifact", input: "conformance/native/pass/stdlib-target-neutral.graph" },
{ name: "crm-api-package", input: "examples/crm-api" },
];
const budgetMode = process.env.ZERO_GRAPH_BUILD_PERF_BUDGET || "warn";
function envNumber(name: string, fallback: number) {
const raw = process.env[name];
if (!raw) return fallback;
const parsed = Number(raw);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
const performanceBudgets: PerformanceBudget[] = [
{
name: "simple graph cold build",
fixture: "hello-artifact",
pass: "cold",
command: "build",
metric: "compilerElapsedMs",
max: envNumber("ZERO_GRAPH_BUILD_PERF_SIMPLE_COLD_MAX_MS", 5000),
unit: "ms",
},
{
name: "simple graph warm build",
fixture: "hello-artifact",
pass: "warm",
command: "build",
metric: "compilerElapsedMs",
max: envNumber("ZERO_GRAPH_BUILD_PERF_SIMPLE_WARM_MAX_MS", 3000),
unit: "ms",
},
{
name: "simple graph artifact size",
fixture: "hello-artifact",
pass: "warm",
command: "build",
metric: "artifactBytes",
max: envNumber("ZERO_GRAPH_BUILD_PERF_SIMPLE_ARTIFACT_MAX_BYTES", 8192),
unit: "bytes",
},
{
name: "simple graph lowered IR size",
fixture: "hello-artifact",
pass: "warm",
command: "build",
metric: "loweredIrBytes",
max: envNumber("ZERO_GRAPH_BUILD_PERF_SIMPLE_LOWERED_IR_MAX_BYTES", 16384),
unit: "bytes",
},
{
name: "stdlib-heavy cold build",
fixture: "stdlib-heavy-artifact",
pass: "cold",
command: "build",
metric: "compilerElapsedMs",
max: envNumber("ZERO_GRAPH_BUILD_PERF_STDLIB_HEAVY_COLD_MAX_MS", 120000),
unit: "ms",
},
{
name: "stdlib-heavy warm build",
fixture: "stdlib-heavy-artifact",
pass: "warm",
command: "build",
metric: "compilerElapsedMs",
max: envNumber("ZERO_GRAPH_BUILD_PERF_STDLIB_HEAVY_WARM_MAX_MS", 120000),
unit: "ms",
},
{
name: "stdlib-heavy warm graph load",
fixture: "stdlib-heavy-artifact",
pass: "warm",
command: "build",
metric: "timings.graphLoadMs",
max: envNumber("ZERO_GRAPH_BUILD_PERF_STDLIB_HEAVY_GRAPH_LOAD_MAX_MS", 30000),
unit: "ms",
},
{
name: "stdlib-heavy warm stdlib merge",
fixture: "stdlib-heavy-artifact",
pass: "warm",
command: "build",
metric: "timings.stdlibMergeMs",
max: envNumber("ZERO_GRAPH_BUILD_PERF_STDLIB_HEAVY_STDLIB_MERGE_MAX_MS", 70000),
unit: "ms",
},
{
name: "stdlib-heavy artifact size",
fixture: "stdlib-heavy-artifact",
pass: "warm",
command: "build",
metric: "artifactBytes",
max: envNumber("ZERO_GRAPH_BUILD_PERF_STDLIB_HEAVY_ARTIFACT_MAX_BYTES", 262144),
unit: "bytes",
},
{
name: "stdlib-heavy lowered IR size",
fixture: "stdlib-heavy-artifact",
pass: "warm",
command: "build",
metric: "loweredIrBytes",
max: envNumber("ZERO_GRAPH_BUILD_PERF_STDLIB_HEAVY_LOWERED_IR_MAX_BYTES", 4194304),
unit: "bytes",
},
];
function selectedFixtures() {
const raw = process.env.ZERO_GRAPH_BUILD_PERF_CASES;
if (!raw) return fixtures;
const wanted = new Set(raw.split(",").map((part) => part.trim()).filter(Boolean));
return fixtures.filter((fixture) => wanted.has(fixture.name) || wanted.has(fixture.input));
}
function phaseMs(body: any, name: string) {
const phase = Array.isArray(body?.compilerPhases)
? body.compilerPhases.find((item: any) => item?.name === name)
: null;
return typeof phase?.elapsedMs === "number" ? phase.elapsedMs : null;
}
function graphBuildTimings(body: any) {
const timings = body?.graphBuild?.timings || {};
return {
graphLoadMs: timings.graphLoadMs ?? null,
stdlibMergeMs: timings.stdlibMergeMs ?? null,
stdlibReferenceScanMs: timings.stdlibReferenceScanMs ?? null,
stdlibCleanupMs: timings.stdlibCleanupMs ?? null,
stdlibModuleLoadMs: timings.stdlibModuleLoadMs ?? null,
stdlibNodeMergeMs: timings.stdlibNodeMergeMs ?? null,
stdlibEdgeMergeMs: timings.stdlibEdgeMergeMs ?? null,
stdlibFinalizeMs: timings.stdlibFinalizeMs ?? null,
readinessCheckMs: timings.readinessCheckMs ?? null,
mirCacheLoadMs: timings.mirCacheLoadMs ?? null,
mirLowerMs: timings.mirLowerMs ?? null,
mirCacheWriteMs: timings.mirCacheWriteMs ?? null,
mirCacheReloadMs: timings.mirCacheReloadMs ?? null,
mirLoadOrLowerMs: timings.mirLoadOrLowerMs ?? null,
lowerPhaseMs: timings.lowerPhaseMs ?? phaseMs(body, "lower"),
codegenMs: timings.codegenMs ?? phaseMs(body, "codegen"),
objectMs: timings.objectMs ?? phaseMs(body, "object"),
linkMs: timings.linkMs ?? phaseMs(body, "link"),
};
}
function graphBuildStdlibMergeFacts(body: any) {
const merge = body?.graphBuild?.stdlibMerge || {};
return {
modulesMerged: merge.modulesMerged ?? null,
nodesMerged: merge.nodesMerged ?? null,
edgesMerged: merge.edgesMerged ?? null,
cacheHit: merge.cacheHit ?? null,
cacheStored: merge.cacheStored ?? null,
};
}
function graphCheckTimings(body: any) {
const timings = body?.graphCompiler?.timings || {};
const resolveMs = timings.resolveMs ?? phaseMs(body, "resolve");
const checkMs = timings.checkMs ?? phaseMs(body, "check");
const lowerMs = timings.lowerMs ?? phaseMs(body, "lower");
return {
graphLoadMs: timings.loadMs ?? null,
resolveMs: resolveMs ?? null,
checkMs: checkMs ?? null,
readinessCheckMs: typeof resolveMs === "number" && typeof checkMs === "number" ? resolveMs + checkMs : null,
readinessLowerMs: lowerMs ?? null,
cacheMs: timings.cacheMs ?? null,
};
}
function cacheFacts(body: any) {
const caches = Array.isArray(body?.compilerCaches) ? body.compilerCaches : [];
const mapped = caches.find((cache: any) => cache?.name === "mappedFinalMir") || body?.graphBuild?.mappedFinalMir || null;
return {
hits: caches.filter((cache: any) => cache?.hit === true).length,
misses: caches.filter((cache: any) => cache?.hit === false).length,
mappedFinalMir: mapped ? {
hit: mapped.hit ?? null,
written: mapped.written ?? null,
byteLength: mapped.byteLength ?? null,
memoryMapped: mapped.memoryMapped ?? null,
codegenImmediate: mapped.codegenImmediate ?? null,
programReconstructed: mapped.programReconstructed ?? null,
} : null,
};
}
function valueAtPath(value: any, path: string) {
return path.split(".").reduce((current, part) => current?.[part], value);
}
function evaluateBudgets(results: any[]) {
const mode = budgetMode === "fail" || budgetMode === "warn" || budgetMode === "off" ? budgetMode : "warn";
if (mode === "off") {
return { schemaVersion: 1, mode, status: "off", ok: true, overCount: 0, skippedCount: 0, items: [] };
}
const items = performanceBudgets.map((budget) => {
const fixture = results.find((item) => item.name === budget.fixture);
const run = fixture?.[budget.pass]?.[budget.command];
const actual = valueAtPath(run, budget.metric);
if (!fixture) {
return { ...budget, status: "skipped", actual: null, reason: "fixture not selected" };
}
if (typeof actual !== "number") {
return { ...budget, status: "skipped", actual: null, reason: "metric missing" };
}
const overBy = Number(Math.max(0, actual - budget.max).toFixed(3));
const unitSuffix = budget.unit === "ms" ? "Ms" : "Bytes";
return {
...budget,
status: actual <= budget.max ? "ok" : "over",
actual,
max: budget.max,
[`actual${unitSuffix}`]: actual,
[`max${unitSuffix}`]: budget.max,
[`overBy${unitSuffix}`]: overBy,
ratio: Number((actual / budget.max).toFixed(3)),
};
});
const overCount = items.filter((item) => item.status === "over").length;
const skippedCount = items.filter((item) => item.status === "skipped").length;
return {
schemaVersion: 1,
mode,
status: overCount === 0 ? "ok" : mode === "fail" ? "fail" : "warn",
ok: overCount === 0,
overCount,
skippedCount,
items,
};
}
function writeBudgetMessages(budget: any) {
if (!budget || budget.mode === "off") return;
for (const item of budget.items || []) {
if (item.status === "over") {
process.stderr.write(
`graph perf budget ${budget.status}: ${item.name} ${item.actual} ${item.unit} > ${item.max} ${item.unit} (${item.metric})\n`,
);
}
}
}
async function runJson(args: string[], env: Record<string, string | undefined>): Promise<CommandRun> {
const started = performance.now();
try {
const result = await execFileAsync(zero, args, {
env: { ...process.env, ...env },
maxBuffer,
});
const wallMs = Number((performance.now() - started).toFixed(3));
return { ok: true, command: [zero, ...args], wallMs, body: JSON.parse(result.stdout), stderr: result.stderr };
} catch (error: any) {
const wallMs = Number((performance.now() - started).toFixed(3));
let body: any = null;
try {
body = JSON.parse(error.stdout?.toString() ?? "");
} catch {
body = null;
}
return {
ok: false,
command: [zero, ...args],
wallMs,
body,
stderr: error.stderr?.toString() ?? error.message ?? "",
};
}
}
async function buildCompiler() {
if (process.env.ZERO_GRAPH_BUILD_PERF_SKIP_BUILD === "1") return null;
const started = performance.now();
await execFileAsync("make", ["-C", "native/zero-c"], { maxBuffer });
return Number((performance.now() - started).toFixed(3));
}
async function zeroVersion() {
const result = await runJson(["--version", "--json"], {});
if (!result.ok) throw new Error(`zero version failed: ${result.stderr}`);
return result.body;
}
function requireOk(run: CommandRun) {
if (run.ok && run.body?.ok !== false) return;
const diagnostic = run.body?.diagnostics?.[0];
const message = diagnostic ? `${diagnostic.code}: ${diagnostic.message}` : run.stderr || "command failed";
throw new Error(`${run.command.join(" ")} failed: ${message}`);
}
function normalizeBuild(run: CommandRun) {
requireOk(run);
return {
ok: true,
wallMs: run.wallMs,
compilerElapsedMs: run.body?.elapsedMs ?? null,
graphHash: run.body?.graph?.graphHash ?? null,
lowering: run.body?.graph?.lowering ?? null,
artifactBytes: run.body?.artifactBytes ?? null,
loweredIrBytes: run.body?.loweredIrBytes ?? null,
timings: graphBuildTimings(run.body),
stdlibMerge: graphBuildStdlibMergeFacts(run.body),
caches: cacheFacts(run.body),
};
}
function normalizeCheck(run: CommandRun) {
requireOk(run);
return {
ok: true,
wallMs: run.wallMs,
graphHash: run.body?.graph?.graphHash ?? run.body?.graphHash ?? null,
targetReady: run.body?.targetReadiness?.ok ?? null,
timings: graphCheckTimings(run.body),
caches: cacheFacts(run.body),
};
}
async function runFixture(fixture: Fixture) {
const fixtureTarget = fixture.target || target;
const checkTarget = fixture.checkTarget || process.env.ZERO_GRAPH_BUILD_PERF_CHECK_TARGET || "";
const fixtureRoot = join(outRoot, fixture.name);
const buildCache = join(fixtureRoot, "build-cache");
const checkCache = join(fixtureRoot, "check-cache");
await mkdir(fixtureRoot, { recursive: true });
async function runPass(pass: "cold" | "warm") {
const artifactPath = join(fixtureRoot, `${fixture.name}-${pass}.o`);
process.stderr.write(`graph perf ${fixture.name} ${pass} build\n`);
const build = await runJson(["build", "--json", "--emit", "obj", "--target", fixtureTarget, fixture.input, "--out", artifactPath], {
ZERO_CACHE_DIR: buildCache,
});
process.stderr.write(`graph perf ${fixture.name} ${pass} check\n`);
const checkArgs = ["check", "--json"];
if (checkTarget) checkArgs.push("--target", checkTarget);
checkArgs.push(fixture.input);
const check = await runJson(checkArgs, {
ZERO_CACHE_DIR: checkCache,
});
return {
build: normalizeBuild(build),
check: normalizeCheck(check),
};
}
return {
name: fixture.name,
input: fixture.input,
target: fixtureTarget,
checkTarget: checkTarget || "host-default",
cold: await runPass("cold"),
warm: await runPass("warm"),
};
}
async function main() {
await rm(outRoot, { recursive: true, force: true });
await mkdir(outRoot, { recursive: true });
const nativeBuildMs = await buildCompiler();
const version = await zeroVersion();
const cases = selectedFixtures();
if (cases.length === 0) throw new Error("ZERO_GRAPH_BUILD_PERF_CASES selected no fixtures");
const started = performance.now();
const results = [];
for (const fixture of cases) results.push(await runFixture(fixture));
const elapsedMs = Number((performance.now() - started).toFixed(3));
const budgets = evaluateBudgets(results);
const report = {
schemaVersion: 1,
kind: "zero-graph-build-perf",
generatedAt: new Date().toISOString(),
zero: version,
target,
outDir: outRoot,
nativeBuildMs,
elapsedMs,
budgets,
cases: results,
};
process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
writeBudgetMessages(budgets);
if (budgets.status === "fail") process.exit(1);
}
main().catch((error) => {
process.stderr.write(`${error instanceof Error ? error.stack || error.message : String(error)}\n`);
process.exit(1);
});
+105
View File
@@ -0,0 +1,105 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { readFileSync } from "node:fs";
const files = [
"tests/zero-cli.test.ts",
"scripts/snapshot-command-contracts.mts",
"scripts/program-graph-parity.mts",
"scripts/reliability-smoke.mts",
];
const compilerInputCommands = new Set(["check", "build", "run", "test", "size", "mem", "doc", "dev", "time", "fix"]);
const compilerInputValueFlags = new Set(["--backend", "--emit", "--filter", "--out", "--profile", "--release", "--target"]);
const abiInputSubcommands = new Set(["check", "dump"]);
function lineForOffset(text: string, offset: number) {
return text.slice(0, offset).split("\n").length;
}
function findArrayEnd(text: string, start: number) {
let depth = 0;
let quote = "";
let escaped = false;
for (let i = start; i < text.length; i++) {
const ch = text[i];
if (quote) {
if (escaped) {
escaped = false;
} else if (ch === "\\") {
escaped = true;
} else if (ch === quote) {
quote = "";
}
continue;
}
if (ch === "\"" || ch === "'" || ch === "`") {
quote = ch;
} else if (ch === "[") {
depth++;
} else if (ch === "]") {
depth--;
if (depth === 0) return i + 1;
}
}
return -1;
}
function stringLiterals(segment: string) {
const out: string[] = [];
const re = /"((?:\\.|[^"\\])*)"/g;
let match;
while ((match = re.exec(segment))) {
out.push(match[1].replace(/\\"/g, "\"").replace(/\\\\/g, "\\"));
}
return out;
}
function isCompilerInputCommand(strings: string[]) {
if (strings.length === 0) return false;
if (compilerInputCommands.has(strings[0])) return true;
return strings[0] === "abi" && abiInputSubcommands.has(strings[1]);
}
function projectionInputViolations(strings: string[]) {
const violations: string[] = [];
let skipNext = false;
for (const value of strings.slice(1)) {
if (value === "--") break;
if (skipNext) {
skipNext = false;
continue;
}
if (compilerInputValueFlags.has(value)) {
skipNext = true;
continue;
}
if (value.endsWith(".0")) violations.push(value);
}
return violations;
}
const failures: string[] = [];
for (const file of files) {
const text = readFileSync(file, "utf8");
for (let i = 0; i < text.length; i++) {
if (text[i] !== "[") continue;
const end = findArrayEnd(text, i);
if (end === -1) break;
const segment = text.slice(i, end);
const strings = stringLiterals(segment);
if (isCompilerInputCommand(strings)) {
for (const input of projectionInputViolations(strings)) {
failures.push(`${file}:${lineForOffset(text, i)}: compiler command ${strings[0]} uses projection input ${input}`);
}
}
i = end - 1;
}
}
if (failures.length > 0) {
console.error("direct .0 compiler inputs are not allowed in command contracts/tests:");
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}
console.log("graph input policy ok");
+976
View File
@@ -0,0 +1,976 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFile, spawn } from "node:child_process";
import { createServer as createHttpServer, request as createHttpRequest } from "node:http";
import { createServer as createHttpsServer } from "node:https";
import { connect as connectTcp, createServer as createTcpServer } from "node:net";
import { cp, mkdir, mkdtemp, readFile, readdir, rm, writeFile } from "node:fs/promises";
import { basename } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const zero = "bin/zero";
const outDir = ".zero/native-test";
const zeroRunTimeoutMs = 20000;
const target =
process.platform === "darwin" && process.arch === "arm64" ? "darwin-arm64" :
process.platform === "linux" && process.arch === "x64" ? "linux-x64" :
null;
type RawZeroListenerRequestOptions = {
end?: boolean;
timeoutMs?: number;
};
function zeroArray(count) {
return `0_u8; ${count}`;
}
async function canLinkCurl() {
const src = `/tmp/zero-http-curl-link-${process.pid}.c`;
const exe = `/tmp/zero-http-curl-link-${process.pid}`;
await writeFile(src, "#include <curl/curl.h>\nint main(void) { return curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK ? 0 : 1; }\n");
try {
await execFileAsync("cc", [src, "-lcurl", "-o", exe]);
return true;
} catch {
return false;
} finally {
await rm(src, { force: true });
await rm(exe, { force: true });
}
}
async function canRunOpenSsl() {
try {
await execFileAsync("openssl", ["version"]);
return true;
} catch {
return false;
}
}
async function assertProviderUnavailableRuntime() {
const src = `/tmp/zero-http-provider-unavailable-${process.pid}.c`;
const exe = `/tmp/zero-http-provider-unavailable-${process.pid}`;
await writeFile(src, `#include "zero_runtime.h"
int main(void) {
const unsigned char request[] = "GET http://127.0.0.1/\\n\\n";
unsigned char response[64] = {0};
uint64_t result = zero_http_fetch_result(
(ZeroByteView){request, sizeof(request) - 1},
(ZeroMutByteView){response, sizeof(response)},
10000000
);
return zero_http_result_ok(result) == 0 &&
zero_http_result_status(result) == 0 &&
zero_http_result_body_len(result) == 0 &&
zero_http_result_error(result) == ZERO_HTTP_PROVIDER_UNAVAILABLE &&
zero_http_response_len((ZeroByteView){response, sizeof(response)}) == 0 &&
zero_http_response_body_offset((ZeroByteView){response, sizeof(response)}) == ZERO_HTTP_RESPONSE_META_BYTES ? 0 : 1;
}
`);
try {
await execFileAsync("cc", [
"-DZERO_RUNTIME_NO_CURL",
"-Inative/zero-c/include",
"native/zero-c/runtime/zero_runtime.c",
"native/zero-c/runtime/zero_http_curl.c",
src,
"-o",
exe,
]);
await execFileAsync(exe, [], { timeout: 5000 });
} finally {
await rm(src, { force: true });
await rm(exe, { force: true });
}
}
async function createTlsFixture() {
const dir = await mkdtemp("/tmp/zero-http-tls-");
const caKey = `${dir}/ca.key`;
const caCert = `${dir}/ca.pem`;
const serverKey = `${dir}/server.key`;
const serverCsr = `${dir}/server.csr`;
const serverCert = `${dir}/server.pem`;
const serverConf = `${dir}/server.cnf`;
await writeFile(serverConf, `[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = localhost
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = 127.0.0.1
`);
try {
await execFileAsync("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-nodes", "-days", "1", "-keyout", caKey, "-out", caCert, "-subj", "/CN=Zero Test CA"]);
await execFileAsync("openssl", ["req", "-newkey", "rsa:2048", "-nodes", "-keyout", serverKey, "-out", serverCsr, "-subj", "/CN=localhost", "-config", serverConf]);
await execFileAsync("openssl", ["x509", "-req", "-in", serverCsr, "-CA", caCert, "-CAkey", caKey, "-CAcreateserial", "-out", serverCert, "-days", "1", "-sha256", "-extfile", serverConf, "-extensions", "v3_req"]);
return { dir, caCert, serverKey, serverCert };
} catch {
await rm(dir, { recursive: true, force: true });
return null;
}
}
function listen(server) {
return new Promise((resolve, reject) => {
server.once("error", reject);
server.listen(0, "127.0.0.1", () => {
server.off("error", reject);
resolve(server.address().port);
});
});
}
function listenOn(server, port) {
return new Promise<void>((resolve, reject) => {
const onError = (error) => {
server.off("listening", onListening);
reject(error);
};
const onListening = () => {
server.off("error", onError);
resolve();
};
server.once("error", onError);
server.once("listening", onListening);
server.listen(port, "127.0.0.1");
});
}
function close(server) {
return new Promise<void>((resolve, reject) => {
server.close((error) => error ? reject(error) : resolve());
});
}
function waitForZeroListener(child, timeoutMs = 30000) {
return new Promise<{ port: number; stdout: string; stderr: string }>((resolve, reject) => {
let stdout = "";
let stderr = "";
const maybeReady = () => {
const match = `${stdout}\n${stderr}`.match(/listening on http:\/\/127\.0\.0\.1:(\d+)/);
if (match) {
clearTimeout(timer);
resolve({ port: Number(match[1]), stdout, stderr });
}
};
const timer = setTimeout(() => {
reject(new Error(`timed out waiting for zero listener\nstdout:\n${stdout}\nstderr:\n${stderr}`));
}, timeoutMs);
child.stdout.on("data", (chunk) => {
stdout += chunk.toString("utf8");
maybeReady();
});
child.stderr.on("data", (chunk) => {
stderr += chunk.toString("utf8");
maybeReady();
});
child.once("exit", (code, signal) => {
clearTimeout(timer);
reject(new Error(`zero listener exited before ready: code=${code} signal=${signal}\nstdout:\n${stdout}\nstderr:\n${stderr}`));
});
});
}
function stopZeroListener(child) {
return new Promise<void>((resolve) => {
if (child.exitCode !== null || child.signalCode !== null) {
resolve();
return;
}
const killTimer = setTimeout(() => {
if (child.exitCode === null && child.signalCode === null) child.kill("SIGKILL");
}, 1000);
child.once("exit", () => {
clearTimeout(killTimer);
resolve();
});
child.kill("SIGTERM");
});
}
function requestZeroListener(port, method, path, body = "", headers = {}) {
const bodyBuffer = Buffer.from(body);
return new Promise<{ status: number; body: string }>((resolve, reject) => {
const timeout = setTimeout(() => {
request.destroy(new Error(`${method} ${path} timed out`));
}, 5000);
const request = createHttpRequest({
host: "127.0.0.1",
port,
path,
method,
headers: {
...headers,
...(bodyBuffer.length > 0 ? { "content-length": String(bodyBuffer.length) } : {}),
},
}, (response) => {
const chunks = [];
response.on("data", (chunk) => chunks.push(chunk));
response.on("end", () => {
clearTimeout(timeout);
resolve({
status: response.statusCode ?? 0,
body: Buffer.concat(chunks).toString("utf8"),
});
});
});
request.on("error", (error) => {
clearTimeout(timeout);
reject(new Error(`${method} ${path} failed: ${error.message}`));
});
if (bodyBuffer.length > 0) request.write(bodyBuffer);
request.end();
});
}
function rawZeroListenerRequest(port, payload, options: RawZeroListenerRequestOptions = {}) {
return new Promise<string>((resolve, reject) => {
const chunks = [];
let settled = false;
const socket = connectTcp({ host: "127.0.0.1", port }, () => {
if (options.end === false) socket.write(payload);
else socket.end(payload);
});
const timeout = setTimeout(() => {
finish(new Error("raw HTTP request timed out"));
}, options.timeoutMs ?? 5000);
function finish(error = null) {
if (settled) return;
settled = true;
clearTimeout(timeout);
socket.destroy();
if (error) {
reject(error);
return;
}
resolve(Buffer.concat(chunks).toString("utf8"));
}
socket.on("data", (chunk) => chunks.push(chunk));
socket.on("end", () => finish());
socket.on("close", () => {
if (!settled && chunks.length > 0) finish();
});
socket.on("error", finish);
});
}
async function assertExplicitPortConflict() {
const dir = await mkdtemp("/tmp/zero-http-listen-explicit-");
const packageDir = `${dir}/ping-pong-api`;
const patchPath = `${dir}/explicit-port.patch`;
try {
await cp("examples/ping-pong-api", packageDir, { recursive: true });
await writeFile(patchPath, `zero-program-graph-patch v1
replaceFunctionBody main
check std.http.listen(world, 3000_u16)
end
`);
await execFileAsync(zero, ["patch", packageDir, patchPath], { timeout: zeroRunTimeoutMs });
const result = await execFileAsync(zero, ["run", packageDir], { timeout: zeroRunTimeoutMs }).catch((error) => error);
assert.notEqual(result.code, 0);
assert.match(`${result.stdout ?? ""}\n${result.stderr ?? ""}`, /std\.http\.listen could not bind the requested port|Address already in use/);
} finally {
await rm(dir, { recursive: true, force: true });
}
}
async function runHttpListenExample() {
const tempDirsBefore = new Set((await readdir("/tmp")).filter((entry) => entry.startsWith("zero-listen-")));
let reserved3000 = null;
let port3000Occupied = false;
const devPortGuard = createTcpServer();
try {
await listenOn(devPortGuard, 3000);
reserved3000 = devPortGuard;
port3000Occupied = true;
} catch (error) {
try {
devPortGuard.close();
} catch {
// The guard may never have started if another local service owns 3000.
}
if (error && error.code === "EADDRINUSE") {
port3000Occupied = true;
} else {
throw error;
}
}
const child = spawn(zero, ["run", "examples/ping-pong-api"], {
stdio: ["ignore", "pipe", "pipe"],
});
try {
const { port } = await waitForZeroListener(child);
if (port3000Occupied) {
assert.notEqual(port, 3000);
}
assert.deepEqual(await requestZeroListener(port, "GET", "/ping"), {
status: 200,
body: "{\"message\":\"pong\"}",
});
assert.deepEqual(await requestZeroListener(port, "GET", "/health"), {
status: 200,
body: "{\"ok\":true}",
});
assert.deepEqual(await requestZeroListener(port, "GET", "/missing"), {
status: 404,
body: "{\"error\":\"not_found\"}",
});
assert.deepEqual(await requestZeroListener(port, "POST", "/echo", "{\"ping\":1}", { "content-type": "application/json" }), {
status: 201,
body: "{\"ping\":1}",
});
assert.deepEqual(await requestZeroListener(port, "POST", "/echo", "not-json"), {
status: 400,
body: "{\"error\":\"bad_request\"}",
});
const badRequest = await rawZeroListenerRequest(port, "POST /echo\r\ncontent-length: nope\r\n\r\nx");
assert.match(badRequest, /^HTTP\/1\.1 400 Bad Request/);
assert.match(badRequest, /\r\nconnection: close\r\n/i);
assert.match(badRequest, /\{"error":"bad_request"\}/);
const tooLarge = await rawZeroListenerRequest(port, "POST /echo\r\ncontent-length: 999999\r\n\r\n");
assert.match(tooLarge, /^HTTP\/1\.1 413 Payload Too Large/);
assert.match(tooLarge, /\{"error":"payload_too_large"\}/);
const incomplete = await rawZeroListenerRequest(port, "POST /echo\r\ncontent-length: 4\r\n\r\nx", { end: false, timeoutMs: 8000 });
assert.match(incomplete, /^HTTP\/1\.1 408 Request Timeout/);
assert.match(incomplete, /\{"error":"request_timeout"\}/);
if (port3000Occupied) await assertExplicitPortConflict();
} finally {
await stopZeroListener(child);
if (reserved3000) await close(reserved3000);
const tempDirsAfter = (await readdir("/tmp")).filter((entry) => entry.startsWith("zero-listen-"));
for (const entry of tempDirsAfter) {
assert(tempDirsBefore.has(entry), `std.http.listen leaked temporary directory /tmp/${entry}`);
}
}
}
async function runExitCode(path, env = {}) {
try {
await execFileAsync(path, [], { timeout: 5000, env: { ...process.env, ...env } });
return 0;
} catch (error) {
if (typeof error.code === "number") return error.code;
throw error;
}
}
async function importGraphInput(sourcePath) {
const graphPath = `/tmp/zero-http-runtime-${process.pid}-${basename(sourcePath, ".0")}.graph`;
const projectionSidecar = `${sourcePath.slice(0, -2)}.graph`;
await rm(projectionSidecar, { force: true });
await rm(graphPath, { force: true });
await execFileAsync(zero, ["import", "--format", "text", "--out", graphPath, sourcePath]);
return graphPath;
}
function assertRuntimeReport(report, targetName) {
assert.equal(report.generatedCBytes, 0);
assert.equal(report.objectBackend?.linking?.targetLibraries, "zero-runtime,curl");
assert.equal(report.objectBackend?.linking?.externalToolchain, "cc");
assert.equal(report.objectBackend?.httpRuntime?.status, "supported");
assert.equal(report.objectBackend?.httpRuntime?.provider, "curl");
assert.equal(report.objectBackend?.httpRuntime?.tlsVerification, true);
assert.equal(report.objectBackend?.httpRuntime?.customCa?.env, "ZERO_HTTP_TEST_CA_BUNDLE");
assert(report.objectBackend?.linkerPlan?.staticLibraries?.includes("zero_runtime.o"));
assert(report.objectBackend?.linkerPlan?.staticLibraries?.includes("zero_http_curl.o"));
assert(report.objectBackend?.linkerPlan?.systemLibraries?.includes("curl"));
assert.equal(report.objectBackend?.directFacts?.runtimeHelperCount, 2);
if (targetName === "darwin-arm64") {
assert.equal(report.objectBackend?.objectEmission?.path, "direct-macho64-object");
} else {
assert.equal(report.objectBackend?.objectEmission?.path, "direct-elf64-object");
}
}
async function buildAndRun(name, source, expectedCode, env = {}) {
const src = `/tmp/zero-http-runtime-${process.pid}-${name}.0`;
const exe = `${outDir}/${name}`;
const jsonPath = `${exe}.json`;
await writeFile(src, source);
const input = await importGraphInput(src);
const build = await execFileAsync(zero, ["build", "--json", "--emit", "exe", "--target", target, input, "--out", exe], { maxBuffer: 1024 * 1024 });
await writeFile(jsonPath, build.stdout);
assertRuntimeReport(JSON.parse(build.stdout), target);
const code = await runExitCode(exe, env);
assert.equal(code, expectedCode);
}
async function runHttpJsonExample(baseUrl) {
const exe = `${outDir}/std-http-json-example`;
const run = await execFileAsync(zero, ["run", "--out", exe, "examples/std-http-json.graph", "--", `GET ${baseUrl}/ok\n\n`], { timeout: zeroRunTimeoutMs });
assert.equal(run.stdout, "http json ok\n");
}
async function runHttpRequestExample(baseUrl) {
const exe = `${outDir}/std-http-request-example`;
const request = `POST ${baseUrl}/echo\ncontent-type: application/json\nx-zero-test: yes\n\n{"ping":1}`;
const run = await execFileAsync(zero, ["run", "--out", exe, "examples/std-http-request.graph", "--", request], { timeout: zeroRunTimeoutMs });
assert.equal(run.stdout, "http request ok\n");
}
async function runHttpHeadersExample(baseUrl) {
const exe = `${outDir}/std-http-headers-example`;
const run = await execFileAsync(zero, ["run", "--out", exe, "examples/std-http-headers.graph", "--", `GET ${baseUrl}/headers\n\n`, "connection"], { timeout: zeroRunTimeoutMs });
assert.equal(run.stdout, "http header found\n");
}
async function runJsonApiClientExample(baseUrl) {
const exe = `${outDir}/json-api-client-example`;
const run = await execFileAsync(zero, ["run", "--out", exe, "examples/json-api-client.graph", "--", `${baseUrl}/client`], { timeout: zeroRunTimeoutMs });
assert.equal(run.stdout, "json api client ok\n");
}
async function runJsonApiRouterExample() {
const exe = `${outDir}/json-api-router-example`;
const request = "POST /users?tenant=demo\ncontent-type: application/json\n\n{\"id\":7}";
const run = await execFileAsync(zero, ["run", "--out", exe, "examples/json-api-router.graph", "--", request], { timeout: zeroRunTimeoutMs });
assert.equal(run.stdout, "json api router ok\n");
const corsExe = `${outDir}/json-api-router-cors-example`;
const preflight = "OPTIONS /users\naccess-control-request-method: POST\n\n";
const cors = await execFileAsync(zero, ["run", "--out", corsExe, "examples/json-api-router.graph", "--", preflight], { timeout: zeroRunTimeoutMs });
assert.equal(cors.stdout, "json api router ok\n");
}
function okSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [512]u8 = [${zeroArray(512)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET ${baseUrl}/ok\\n\\n"), response, std.time.ms(1000))
let body_offset: usize = std.http.responseBodyOffset(response)
let body_len: usize = std.http.resultBodyLen(result)
if std.http.resultOk(result) == false {
return 99
}
if std.http.resultStatus(result) != 200 {
return 99
}
if body_len != 8 {
return 99
}
if std.http.resultError(result) != std.http.errorNone() {
return 99
}
if std.http.responseLen(response) < body_len {
return 99
}
if response[body_offset] != 123_u8 {
return 99
}
if response[body_offset + 1] != 34_u8 {
return 99
}
if response[body_offset + 2] != 111_u8 {
return 99
}
if response[body_offset + 3] != 107_u8 {
return 99
}
if response[body_offset + 4] != 34_u8 {
return 99
}
if response[body_offset + 5] != 58_u8 {
return 99
}
if response[body_offset + 6] != 49_u8 {
return 99
}
if response[body_offset + 7] != 125_u8 {
return 99
}
return 8
}
`;
}
function fetchRequestSource(baseUrl, method, path, body, expectedStatus, expectedBodyLen, expectedCode) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
let request: Span<u8> = std.mem.span("${method} ${baseUrl}${path}\\ncontent-type: application/json\\nx-zero-test: yes\\n\\n${body}")
var response: [512]u8 = [${zeroArray(512)}]
let result: HttpResult = std.http.fetch(client, request, response, std.time.ms(1000))
let body_offset: usize = std.http.responseBodyOffset(response)
if std.http.resultOk(result) == false {
return 99
}
if std.http.resultStatus(result) != ${expectedStatus} {
return 99
}
if std.http.resultBodyLen(result) != ${expectedBodyLen} {
return 99
}
if std.http.resultError(result) != std.http.errorNone() {
return 99
}
if response[body_offset] != 123_u8 {
return 99
}
if response[body_offset + 2] == 0_u8 {
return 99
}
return ${expectedCode}
}
`;
}
function resultFailureSource(baseUrl, path, responseSize, timeoutMs, expectedStatus, expectedLen, expectedError, expectedCode) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [${responseSize}]u8 = [${zeroArray(responseSize)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET ${baseUrl}${path}\\n\\n"), response, std.time.ms(${timeoutMs}))
if std.http.resultOk(result) != false {
return 99
}
if std.http.resultStatus(result) != ${expectedStatus} {
return 99
}
if std.http.resultBodyLen(result) != ${expectedLen} {
return 99
}
if std.http.resultError(result) != ${expectedError} {
return 99
}
return ${expectedCode}
}
`;
}
function headersSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [512]u8 = [${zeroArray(512)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET ${baseUrl}/ok\\n\\n"), response, std.time.ms(1000))
let reply: HttpHeaderValue = std.http.headerValue(response, std.mem.span("x-zero-reply"))
let reply_bytes: Maybe<Span<u8>> = std.http.headerBytes(response, reply)
if std.http.resultOk(result) == false {
return 99
}
if std.http.resultStatus(result) != 200 {
return 99
}
if std.http.responseHeadersLen(response) <= 16 {
return 99
}
if std.http.resultError(result) != std.http.errorNone() {
return 99
}
if std.http.headerFound(reply) == false {
return 99
}
if std.http.headerLen(reply) != 3 {
return 99
}
if !reply_bytes.has {
return 99
}
if reply_bytes.value[0] != 121_u8 {
return 99
}
if response[24] != 72_u8 {
return 99
}
if response[25] != 84_u8 {
return 99
}
if response[26] != 84_u8 {
return 99
}
if response[27] != 80_u8 {
return 99
}
return 44
}
`;
}
function interimHeadersSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [512]u8 = [${zeroArray(512)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET ${baseUrl}/interim\\n\\n"), response, std.time.ms(1000))
let reply: HttpHeaderValue = std.http.headerValue(response, std.mem.span("x-zero-reply"))
let reply_offset: usize = std.http.headerOffset(reply)
let body_offset: usize = std.http.responseBodyOffset(response)
if std.http.resultOk(result) == false {
return 99
}
if std.http.resultStatus(result) != 200 {
return 99
}
if std.http.resultBodyLen(result) != 8 {
return 99
}
if std.http.resultError(result) != std.http.errorNone() {
return 99
}
if std.http.headerFound(reply) == false {
return 99
}
if std.http.headerLen(reply) != 5 {
return 99
}
if response[reply_offset] != 102_u8 {
return 99
}
if response[33] != 50_u8 {
return 99
}
if response[34] != 48_u8 {
return 99
}
if response[35] != 48_u8 {
return 99
}
if response[body_offset] != 123_u8 {
return 99
}
return 46
}
`;
}
function headSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
let request: Span<u8> = std.mem.span("HEAD ${baseUrl}/ok\\nx-zero-test: yes\\n\\n")
var response: [512]u8 = [${zeroArray(512)}]
let result: HttpResult = std.http.fetch(client, request, response, std.time.ms(1000))
let reply: HttpHeaderValue = std.http.headerValue(response, std.mem.span("x-zero-reply"))
if std.http.resultOk(result) == false {
return 99
}
if std.http.resultStatus(result) != 200 {
return 99
}
if std.http.resultBodyLen(result) != 0 {
return 99
}
if std.http.responseHeadersLen(response) <= 16 {
return 99
}
if std.http.resultError(result) != std.http.errorNone() {
return 99
}
if std.http.headerFound(reply) == false {
return 99
}
if std.http.headerLen(reply) != 3 {
return 99
}
return 45
}
`;
}
function jsonResultSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [512]u8 = [${zeroArray(512)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET ${baseUrl}/ok\\n\\n"), response, std.time.ms(1000))
let bytes: Maybe<Span<u8>> = std.http.responseBody(response, result)
var arena_buf: [16]u8 = [${zeroArray(16)}]
var arena: FixedBufAlloc = std.mem.fixedBufAlloc(arena_buf)
var parsed: Maybe<JsonDoc> = null
if bytes.has {
parsed = std.json.parseBytes(arena, bytes.value)
}
if std.http.resultOk(result) == false {
return 99
}
if std.http.resultStatus(result) != 200 {
return 99
}
if !bytes.has {
return 99
}
if std.mem.len(bytes.value) != 8 {
return 99
}
if parsed.has == false {
return 99
}
if std.json.validateBytes(bytes.value) == false {
return 99
}
if std.json.streamTokensBytes(bytes.value) != 3 {
return 99
}
return 37
}
`;
}
function invalidUrlSource() {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [64]u8 = [${zeroArray(64)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET http://\\n\\n"), response, std.time.ms(1000))
if std.http.resultOk(result) != false {
return 99
}
if std.http.resultStatus(result) != 0 {
return 99
}
if std.http.resultBodyLen(result) != 0 {
return 99
}
if std.http.resultError(result) != std.http.errorInvalidUrl() {
return 99
}
return 36
}
`;
}
function shorthandRejectedSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [64]u8 = [${zeroArray(64)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("${baseUrl}/ok"), response, std.time.ms(1000))
if std.http.resultOk(result) != false {
return 99
}
if std.http.resultStatus(result) != 0 {
return 99
}
if std.http.resultBodyLen(result) != 0 {
return 99
}
if std.http.resultError(result) != std.http.errorInvalidRequest() {
return 99
}
return 48
}
`;
}
function unterminatedEnvelopeSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [64]u8 = [${zeroArray(64)}]
let result: HttpResult = std.http.fetch(client, std.mem.span("GET ${baseUrl}/ok"), response, std.time.ms(1000))
if std.http.resultOk(result) != false {
return 99
}
if std.http.resultStatus(result) != 0 {
return 99
}
if std.http.resultBodyLen(result) != 0 {
return 99
}
if std.http.resultError(result) != std.http.errorInvalidRequest() {
return 99
}
return 49
}
`;
}
function invalidRequestSource(baseUrl) {
return `export c fn main() -> i32 {
let net: Net = std.net.host()
let client: HttpClient = std.http.client(net)
var response: [128]u8 = [${zeroArray(128)}]
let request: Span<u8> = std.mem.span("POST ${baseUrl}/echo\\nbad-header\\n\\n")
let result: HttpResult = std.http.fetch(client, request, response, std.time.ms(1000))
if std.http.resultOk(result) != false {
return 99
}
if std.http.resultStatus(result) != 0 {
return 99
}
if std.http.resultBodyLen(result) != 0 {
return 99
}
if std.http.resultError(result) != std.http.errorInvalidRequest() {
return 99
}
return 43
}
`;
}
if (!target) {
process.stdout.write("http runtime smoke skipped: unsupported host target\n");
process.exit(0);
}
if (!(await canLinkCurl())) {
process.stdout.write("http runtime smoke skipped: cc cannot link libcurl\n");
process.exit(0);
}
await mkdir(outDir, { recursive: true });
await assertProviderUnavailableRuntime();
await runHttpListenExample();
function handleRequest(request, response) {
if (request.url === "/headers") {
response.sendDate = false;
response.writeHead(204, { "connection": "close" });
response.end();
} else if (request.url === "/ok") {
response.writeHead(200, { "content-type": "application/json", "x-zero-reply": "yes" });
response.end("{\"ok\":1}");
} else if (request.url === "/echo") {
const chunks = [];
request.on("data", (chunk) => chunks.push(chunk));
request.on("end", () => {
const body = Buffer.concat(chunks).toString("utf8");
if (request.method === "POST" &&
request.headers["x-zero-test"] === "yes" &&
request.headers["content-type"] === "application/json" &&
body === "{\"ping\":1}") {
response.writeHead(201, { "content-type": "application/json", "x-zero-reply": "yes" });
response.end("{\"echo\":1}");
} else {
response.writeHead(400, { "content-type": "text/plain" });
response.end("bad request");
}
});
} else if (request.url === "/client") {
const chunks = [];
request.on("data", (chunk) => chunks.push(chunk));
request.on("end", () => {
const body = Buffer.concat(chunks).toString("utf8");
if (request.method === "POST" &&
request.headers["content-type"] === "application/json" &&
body === "{\"ping\":1}") {
response.writeHead(201, { "content-type": "application/json", "x-zero-reply": "yes" });
response.end("{\"echo\":1}");
} else {
response.writeHead(400, { "content-type": "text/plain" });
response.end("bad request");
}
});
} else if (request.url === "/replace") {
const chunks = [];
request.on("data", (chunk) => chunks.push(chunk));
request.on("end", () => {
const body = Buffer.concat(chunks).toString("utf8");
if (request.method === "PUT" &&
request.headers["x-zero-test"] === "yes" &&
request.headers["content-type"] === "application/json" &&
body === "{\"value\":2}") {
response.writeHead(202, { "content-type": "application/json", "x-zero-reply": "yes" });
response.end("{\"put\":1}");
} else {
response.writeHead(400, { "content-type": "text/plain" });
response.end("bad request");
}
});
} else if (request.url === "/missing") {
response.writeHead(404, { "content-type": "text/plain" });
response.end("missing");
} else if (request.url === "/large") {
response.writeHead(200, { "content-type": "text/plain" });
response.end("0123456789abcdef0123456789abcdef");
} else if (request.url === "/slow") {
setTimeout(() => {
response.writeHead(200, { "content-type": "text/plain" });
response.end("slow");
}, 250);
} else {
response.writeHead(500, { "content-type": "text/plain" });
response.end("unexpected");
}
}
function createInterimHeaderServer() {
return createTcpServer((socket) => {
socket.once("data", () => {
socket.end([
"HTTP/1.1 103 Early Hints\r\n",
"Link: </zero.css>; rel=preload; as=style\r\n",
"\r\n",
"HTTP/1.1 200 OK\r\n",
"Content-Type: application/json\r\n",
"X-Zero-Reply: final\r\n",
"Connection: close\r\n",
"Content-Length: 8\r\n",
"\r\n",
"{\"ok\":1}",
].join(""));
});
socket.on("error", () => {});
});
}
const server = createHttpServer(handleRequest);
const port = await listen(server);
const baseUrl = `http://127.0.0.1:${port}`;
const interimServer = createInterimHeaderServer();
const interimPort = await listen(interimServer);
const interimBaseUrl = `http://127.0.0.1:${interimPort}`;
try {
await buildAndRun("http-runtime-ok", okSource(baseUrl), 8);
await buildAndRun("http-runtime-404", resultFailureSource(baseUrl, "/missing", 512, 1000, 404, 7, "std.http.errorNone()", 32), 32);
await buildAndRun("http-runtime-overflow", resultFailureSource(baseUrl, "/large", 32, 1000, 200, 0, "std.http.errorTooLarge()", 33), 33);
await buildAndRun("http-runtime-timeout", resultFailureSource(baseUrl, "/slow", 512, 25, 0, 0, "std.http.errorTimeout()", 34), 34);
await buildAndRun("http-runtime-post", fetchRequestSource(baseUrl, "POST", "/echo", "{\\\"ping\\\":1}", 201, 10, 42), 42);
await buildAndRun("http-runtime-put", fetchRequestSource(baseUrl, "PUT", "/replace", "{\\\"value\\\":2}", 202, 9, 47), 47);
await buildAndRun("http-runtime-headers", headersSource(baseUrl), 44);
await buildAndRun("http-runtime-interim-headers", interimHeadersSource(interimBaseUrl), 46);
await buildAndRun("http-runtime-head", headSource(baseUrl), 45);
await buildAndRun("http-runtime-result-json", jsonResultSource(baseUrl), 37);
await runHttpJsonExample(baseUrl);
await runHttpRequestExample(baseUrl);
await runHttpHeadersExample(baseUrl);
await runJsonApiClientExample(baseUrl);
await runJsonApiRouterExample();
await buildAndRun("http-runtime-shorthand-rejected", shorthandRejectedSource(baseUrl), 48);
await buildAndRun("http-runtime-unterminated-envelope", unterminatedEnvelopeSource(baseUrl), 49);
await buildAndRun("http-runtime-invalid-url", invalidUrlSource(), 36);
await buildAndRun("http-runtime-invalid-request", invalidRequestSource(baseUrl), 43);
} finally {
await close(server);
await close(interimServer);
}
if (await canRunOpenSsl()) {
const tls = await createTlsFixture();
if (tls) {
const httpsServer = createHttpsServer({
key: await readFile(tls.serverKey),
cert: await readFile(tls.serverCert),
}, handleRequest);
const httpsPort = await listen(httpsServer);
const httpsBaseUrl = `https://127.0.0.1:${httpsPort}`;
try {
await buildAndRun("http-runtime-https-ok", okSource(httpsBaseUrl), 8, { ZERO_HTTP_TEST_CA_BUNDLE: tls.caCert });
await buildAndRun("http-runtime-https-untrusted", resultFailureSource(httpsBaseUrl, "/ok", 512, 1000, 0, 0, "std.http.errorTls()", 35), 35);
} finally {
await close(httpsServer);
await rm(tls.dir, { recursive: true, force: true });
}
} else {
process.stdout.write("https runtime smoke skipped: openssl fixture generation failed\n");
}
} else {
process.stdout.write("https runtime smoke skipped: openssl unavailable\n");
}
const okReport = JSON.parse(await readFile(`${outDir}/http-runtime-ok.json`, "utf8"));
assertRuntimeReport(okReport, target);
process.stdout.write(`http runtime smoke ok (${target})\n`);
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -euo pipefail
version="${ZERO_ZIG_VERSION:-0.14.1}"
release_tag="${ZERO_ZIG_RELEASE_TAG:-toolchain-zig-${version}}"
mirror_base="${ZERO_ZIG_MIRROR_BASE:-https://github.com/vercel-labs/zerolang/releases/download/${release_tag}}"
cache_root="${ZERO_ZIG_CACHE_DIR:-${PWD}/.zero/toolchains}"
host_os="$(uname -s)"
host_arch="$(uname -m)"
case "${host_os}:${host_arch}" in
Linux:x86_64)
platform="x86_64-linux"
archive_name="zig-x86_64-linux-${version}.tar.xz"
archive_sha="24aeeec8af16c381934a6cd7d95c807a8cb2cf7df9fa40d359aa884195c4716c"
;;
Darwin:arm64 | Darwin:aarch64)
platform="aarch64-macos"
archive_name="zig-aarch64-macos-${version}.tar.xz"
archive_sha="39f3dc5e79c22088ce878edc821dedb4ca5a1cd9f5ef915e9b3cc3053e8faefa"
;;
Darwin:x86_64)
platform="x86_64-macos"
archive_name="zig-x86_64-macos-${version}.tar.xz"
archive_sha="b0f8bdfb9035783db58dd6c19d7dea89892acc3814421853e5752fe4573e5f43"
;;
*)
echo "unsupported Zig host for pinned installer: ${host_os}:${host_arch}" >&2
exit 1
;;
esac
install_dir="${ZERO_ZIG_INSTALL_DIR:-${cache_root}/zig-${version}-${platform}}"
archive_path="${cache_root}/${archive_name}"
archive_url="${mirror_base}/${archive_name}"
check_sha256() {
expected="$1"
path="$2"
if command -v sha256sum >/dev/null 2>&1; then
printf '%s %s\n' "$expected" "$path" | sha256sum -c -
else
printf '%s %s\n' "$expected" "$path" | shasum -a 256 -c -
fi
}
if [ -x "${install_dir}/zig" ] && [ "$("${install_dir}/zig" version)" = "$version" ]; then
echo "Zig ${version} already installed at ${install_dir}"
else
mkdir -p "$cache_root"
if [ ! -f "$archive_path" ] || ! check_sha256 "$archive_sha" "$archive_path" >/dev/null 2>&1; then
echo "Downloading ${archive_name} from repo mirror"
curl -fsSL --retry 3 --retry-delay 2 --output "$archive_path" "$archive_url"
fi
check_sha256 "$archive_sha" "$archive_path"
tmp_dir="${install_dir}.tmp.$$"
rm -rf "$tmp_dir"
mkdir -p "$tmp_dir"
tar -xf "$archive_path" -C "$tmp_dir" --strip-components=1
rm -rf "$install_dir"
mv "$tmp_dir" "$install_dir"
fi
if [ "$("${install_dir}/zig" version)" != "$version" ]; then
echo "installed Zig version does not match ${version}: $("${install_dir}/zig" version)" >&2
exit 1
fi
if [ -n "${GITHUB_PATH:-}" ]; then
printf '%s\n' "$install_dir" >> "$GITHUB_PATH"
fi
echo "Zig ${version} installed at ${install_dir}"
+158
View File
@@ -0,0 +1,158 @@
export function jsonByteTokenCount(bytes) {
if (!bytes || bytes.length === 0) return -1n;
const scanner = { bytes, pos: 0, tokens: 0 };
const len = () => scanner.bytes.length;
const skipWs = () => {
while (scanner.pos < len()) {
const ch = scanner.bytes[scanner.pos];
if (ch !== 0x20 && ch !== 0x0a && ch !== 0x0d && ch !== 0x09) return;
scanner.pos += 1;
}
};
const parseString = () => {
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== 0x22) return false;
scanner.pos += 1;
while (scanner.pos < len()) {
const ch = scanner.bytes[scanner.pos++];
if (ch === 0x22) return true;
if (ch < 0x20) return false;
if (ch !== 0x5c) continue;
if (scanner.pos >= len()) return false;
const esc = scanner.bytes[scanner.pos++];
if (esc === 0x22 || esc === 0x5c || esc === 0x2f || esc === 0x62 || esc === 0x66 || esc === 0x6e || esc === 0x72 || esc === 0x74) continue;
if (esc !== 0x75 || scanner.pos + 4 > len()) return false;
for (let i = 0; i < 4; i++) {
const hex = scanner.bytes[scanner.pos++];
const ok = (hex >= 0x30 && hex <= 0x39) || (hex >= 0x61 && hex <= 0x66) || (hex >= 0x41 && hex <= 0x46);
if (!ok) return false;
}
}
return false;
};
const matchLiteral = (literal) => {
const start = scanner.pos;
for (let i = 0; i < literal.length; i++) {
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== literal.charCodeAt(i)) {
scanner.pos = start;
return false;
}
scanner.pos += 1;
}
return true;
};
const parseNumber = () => {
const start = scanner.pos;
if (scanner.pos < len() && scanner.bytes[scanner.pos] === 0x2d) scanner.pos += 1;
if (scanner.pos >= len()) {
scanner.pos = start;
return false;
}
if (scanner.bytes[scanner.pos] === 0x30) {
scanner.pos += 1;
} else if (scanner.bytes[scanner.pos] >= 0x31 && scanner.bytes[scanner.pos] <= 0x39) {
while (scanner.pos < len() && scanner.bytes[scanner.pos] >= 0x30 && scanner.bytes[scanner.pos] <= 0x39) scanner.pos += 1;
} else {
scanner.pos = start;
return false;
}
if (scanner.pos < len() && scanner.bytes[scanner.pos] === 0x2e) {
scanner.pos += 1;
const digits = scanner.pos;
while (scanner.pos < len() && scanner.bytes[scanner.pos] >= 0x30 && scanner.bytes[scanner.pos] <= 0x39) scanner.pos += 1;
if (scanner.pos === digits) {
scanner.pos = start;
return false;
}
}
if (scanner.pos < len() && (scanner.bytes[scanner.pos] === 0x65 || scanner.bytes[scanner.pos] === 0x45)) {
scanner.pos += 1;
if (scanner.pos < len() && (scanner.bytes[scanner.pos] === 0x2b || scanner.bytes[scanner.pos] === 0x2d)) scanner.pos += 1;
const digits = scanner.pos;
while (scanner.pos < len() && scanner.bytes[scanner.pos] >= 0x30 && scanner.bytes[scanner.pos] <= 0x39) scanner.pos += 1;
if (scanner.pos === digits) {
scanner.pos = start;
return false;
}
}
return true;
};
const parseValue = (depth) => {
if (depth > 64) return false;
skipWs();
if (scanner.pos >= len()) return false;
const ch = scanner.bytes[scanner.pos];
if (ch === 0x7b) return parseObject(depth);
if (ch === 0x5b) return parseArray(depth);
if (ch === 0x22) {
scanner.tokens += 1;
return parseString();
}
if (ch === 0x74) {
scanner.tokens += 1;
return matchLiteral("true");
}
if (ch === 0x66) {
scanner.tokens += 1;
return matchLiteral("false");
}
if (ch === 0x6e) {
scanner.tokens += 1;
return matchLiteral("null");
}
if (ch === 0x2d || (ch >= 0x30 && ch <= 0x39)) {
scanner.tokens += 1;
return parseNumber();
}
return false;
};
const parseArray = (depth) => {
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== 0x5b) return false;
scanner.tokens += 1;
scanner.pos += 1;
skipWs();
if (scanner.pos < len() && scanner.bytes[scanner.pos] === 0x5d) {
scanner.pos += 1;
return true;
}
for (;;) {
if (!parseValue(depth + 1)) return false;
skipWs();
if (scanner.pos < len() && scanner.bytes[scanner.pos] === 0x5d) {
scanner.pos += 1;
return true;
}
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== 0x2c) return false;
scanner.pos += 1;
skipWs();
}
};
const parseObject = (depth) => {
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== 0x7b) return false;
scanner.tokens += 1;
scanner.pos += 1;
skipWs();
if (scanner.pos < len() && scanner.bytes[scanner.pos] === 0x7d) {
scanner.pos += 1;
return true;
}
for (;;) {
if (!parseString()) return false;
scanner.tokens += 1;
skipWs();
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== 0x3a) return false;
scanner.pos += 1;
if (!parseValue(depth + 1)) return false;
skipWs();
if (scanner.pos < len() && scanner.bytes[scanner.pos] === 0x7d) {
scanner.pos += 1;
return true;
}
if (scanner.pos >= len() || scanner.bytes[scanner.pos] !== 0x2c) return false;
scanner.pos += 1;
skipWs();
}
};
if (!parseValue(0)) return -1n;
skipWs();
return scanner.pos === len() ? BigInt(scanner.tokens) : -1n;
}
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdirSync, statSync } from "node:fs";
import { join } from "node:path";
const zero = "bin/zero";
const outDir = ".zero/llvm-profile";
const addInput = "examples/add.graph";
mkdirSync(outDir, { recursive: true });
function runJson(args: string[], options: { allowFailure?: boolean } = {}) {
try {
const stdout = execFileSync(zero, args, { encoding: "utf8" });
return { code: 0, body: JSON.parse(stdout) };
} catch (error: any) {
if (!options.allowFailure) throw error;
return {
code: error.status ?? error.code ?? 1,
body: JSON.parse(error.stdout?.toString() ?? "{}"),
};
}
}
function llvmOptimizationLevel(profile: string) {
if (profile === "debug" || profile === "dev") return "-O0";
if (profile === "fast" || profile === "release-fast") return "-O2";
if (profile === "audit") return "-O1";
return "-Oz";
}
function buildRow(id: string, backend: string, profile: string, emit: string, out: string, allowFailure = false) {
const args = ["build", "--json", "--backend", backend, "--profile", profile, "--emit", emit, addInput, "--out", out];
const result = runJson(args, { allowFailure });
if (result.code !== 0) {
return {
id,
backendFamily: backend,
profile,
emit,
status: "blocked",
diagnostic: result.body.diagnostics?.[0]?.code ?? "unknown",
backendBlocker: result.body.diagnostics?.[0]?.backendBlocker ?? null,
};
}
assert.equal(result.body.generatedCBytes, 0);
assert.equal(result.body.cBridgeFallback ?? false, false);
assert.equal(result.body.artifactBytes, statSync(result.body.artifactPath).size);
return {
id,
backendFamily: backend,
profile,
emit,
status: "measured",
elapsedMs: result.body.elapsedMs,
artifactBytes: result.body.artifactBytes,
optimizationLevel: backend === "llvm" && emit === "exe"
? llvmOptimizationLevel(profile)
: result.body.profileSemantics?.codegenOptimization ?? null,
target: result.body.target,
};
}
const size = runJson(["size", "--json", "--backend", "llvm", addInput]).body;
assert.equal(size.targetSupport.backendFamily, "llvm");
assert.equal(size.backendProfile.backendFamily, "llvm");
assert.equal(size.backendProfile.fallbackPolicy, "none");
assert.equal(size.backendProfile.targetTriple, size.targetSupport.llvmTargetTriple);
assert.equal(size.backendProfile.optimizationLevel, "-Oz");
assert.equal(size.objectBackend.backendFamily, "llvm");
assert.equal(size.backendComparison.rows.length, 4);
const check = runJson(["check", "--json", "--backend", "llvm", addInput]).body;
const llvmHostReady = check.targetReadiness.ok === true;
const rows = [
buildRow("direct-debug", "direct", "debug", "exe", join(outDir, "add-direct-debug")),
buildRow("direct-small", "direct", "small", "exe", join(outDir, "add-direct-small")),
buildRow("llvm-ir-no-opt", "llvm", "debug", "llvm-ir", join(outDir, "add-debug.ll")),
buildRow("llvm-ir-optimized-profile", "llvm", "small", "llvm-ir", join(outDir, "add-small.ll")),
];
if (llvmHostReady) {
rows.push(buildRow("llvm-native-no-opt", "llvm", "debug", "exe", join(outDir, "add-llvm-debug")));
rows.push(buildRow("llvm-native-optimized", "llvm", "small", "exe", join(outDir, "add-llvm-small")));
} else {
rows.push(buildRow("llvm-native-no-opt", "llvm", "debug", "exe", join(outDir, "add-llvm-debug"), true));
rows.push(buildRow("llvm-native-optimized", "llvm", "small", "exe", join(outDir, "add-llvm-small"), true));
}
assert(rows.some((row) => row.id === "direct-debug" && row.status === "measured"));
assert(rows.some((row) => row.id === "direct-small" && row.status === "measured"));
assert(rows.some((row) => row.id === "llvm-ir-no-opt" && row.status === "measured"));
assert(rows.some((row) => row.id === "llvm-ir-optimized-profile" && row.status === "measured"));
if (llvmHostReady) {
assert(rows.some((row) => row.id === "llvm-native-no-opt" && row.status === "measured"));
assert(rows.some((row) => row.id === "llvm-native-optimized" && row.status === "measured"));
}
console.log(JSON.stringify({
schemaVersion: 1,
kind: "zero-llvm-profile-smoke",
graphInput: addInput,
llvmHostReady,
rows,
}, null, 2));
+31
View File
@@ -0,0 +1,31 @@
import { execFile } from "node:child_process";
import { rm } from "node:fs/promises";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const cc = process.env.CC ?? "cc";
const out = `/tmp/zero-mir-verifier-smoke-${process.pid}`;
try {
await execFileAsync(cc, [
"-std=c11",
"-Wall",
"-Wextra",
"-Wpedantic",
"-I",
"native/zero-c/include",
"-I",
"native/zero-c/src",
"native/zero-c/src/mir_verify.c",
"native/zero-c/tests/mir_verify_smoke.c",
"-o",
out,
]);
const result = await execFileAsync(out);
if (!result.stdout.includes("mir verifier smoke ok")) {
throw new Error(`unexpected MIR verifier smoke output: ${result.stdout}`);
}
} finally {
await rm(out, { force: true });
}
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -euo pipefail
version="${ZERO_ZIG_VERSION:-0.14.1}"
release_tag="${ZERO_ZIG_RELEASE_TAG:-toolchain-zig-${version}}"
upstream_base="${ZERO_ZIG_UPSTREAM_BASE:-https://ziglang.org/download/${version}}"
work_dir="${ZERO_ZIG_MIRROR_WORK_DIR:-/tmp/zero-zig-mirror-${version}}"
assets=(
"zig-x86_64-linux-${version}.tar.xz:24aeeec8af16c381934a6cd7d95c807a8cb2cf7df9fa40d359aa884195c4716c"
"zig-aarch64-macos-${version}.tar.xz:39f3dc5e79c22088ce878edc821dedb4ca5a1cd9f5ef915e9b3cc3053e8faefa"
"zig-x86_64-macos-${version}.tar.xz:b0f8bdfb9035783db58dd6c19d7dea89892acc3814421853e5752fe4573e5f43"
)
check_sha256() {
expected="$1"
path="$2"
if command -v sha256sum >/dev/null 2>&1; then
printf '%s %s\n' "$expected" "$path" | sha256sum -c -
else
printf '%s %s\n' "$expected" "$path" | shasum -a 256 -c -
fi
}
if ! command -v gh >/dev/null 2>&1; then
echo "gh is required to upload mirrored Zig assets" >&2
exit 1
fi
rm -rf "$work_dir"
mkdir -p "$work_dir"
: > "${work_dir}/CHECKSUMS.txt"
for asset in "${assets[@]}"; do
name="${asset%%:*}"
sha="${asset##*:}"
path="${work_dir}/${name}"
echo "Downloading ${name}"
curl -fsSL --retry 3 --retry-delay 2 --output "$path" "${upstream_base}/${name}"
check_sha256 "$sha" "$path"
printf '%s %s\n' "$sha" "$name" >> "${work_dir}/CHECKSUMS.txt"
done
if ! gh release view "$release_tag" >/dev/null 2>&1; then
gh release create "$release_tag" \
--title "Zig ${version} mirror" \
--notes "Repo-owned mirror of pinned Zig ${version} archives used by CI and release workflows." \
--latest=false
fi
for asset in "${assets[@]}"; do
name="${asset%%:*}"
gh release upload "$release_tag" "${work_dir}/${name}" --clobber
done
gh release upload "$release_tag" "${work_dir}/CHECKSUMS.txt" --clobber
echo "Mirrored Zig ${version} assets to GitHub release ${release_tag}"
+100
View File
@@ -0,0 +1,100 @@
import { readFile } from "node:fs/promises";
const headerPath = "native/zero-c/include/zero.h";
const contractsHeaderPath = "native/zero-c/include/zero_contracts.h";
const accessEffectPattern = /\bZ_(?:IN|OUT|INOUT|SINK)\b/;
const returnOwnershipPattern = /\bZ_RET_(?:OWNED|BORROWED)\b/;
const returnOptionalPattern = /\bZ_RET_OPTIONAL\b/;
const contractMacros = ["Z_IN", "Z_OUT", "Z_INOUT", "Z_SINK", "Z_OPTIONAL", "Z_RET_OWNED", "Z_RET_BORROWED", "Z_RET_OPTIONAL"];
type Violation = {
kind: string;
line?: number;
declaration?: string;
parameter?: string;
macro?: string;
};
function stripLineComment(line: string): string {
const index = line.indexOf("//");
return index >= 0 ? line.slice(0, index) : line;
}
function pointerParameters(declaration: string): string[] {
const open = declaration.indexOf("(");
const close = declaration.lastIndexOf(")");
if (open < 0 || close < open) return [];
const params = declaration.slice(open + 1, close).trim();
if (params === "" || params === "void") return [];
return params
.split(",")
.map((param) => param.trim())
.filter((param) => param !== "..." && param.includes("*"));
}
function pointerReturn(declaration: string): string | null {
const beforeParams = declaration.slice(0, declaration.indexOf("(")).trim();
if (!beforeParams.includes("*")) return null;
return beforeParams.replace(/\s+z_[A-Za-z0-9_]+$/, "").trim();
}
function exportedDeclarations(header: string): { line: number; declaration: string }[] {
return header
.split("\n")
.map((line, index) => ({ line: index + 1, declaration: stripLineComment(line).trim() }))
.filter(({ declaration }) => /\bz_[A-Za-z0-9_]+\s*\([^;]*\);$/.test(declaration));
}
function contractViolations(header: string, contractsHeader: string): Violation[] {
const violations: Violation[] = [];
for (const macro of contractMacros) {
if (!new RegExp(`#define\\s+${macro}\\b`).test(contractsHeader)) {
violations.push({ kind: "missing-contract-macro", macro });
}
}
for (const { line, declaration } of exportedDeclarations(header)) {
const returned = pointerReturn(declaration);
if (returned) {
if (!returnOwnershipPattern.test(returned)) {
violations.push({ kind: "missing-pointer-return-ownership", line, declaration, parameter: returned });
}
if (returnOptionalPattern.test(returned) && !returnOwnershipPattern.test(returned)) {
violations.push({ kind: "optional-return-without-ownership", line, declaration, parameter: returned });
}
}
for (const parameter of pointerParameters(declaration)) {
if (!accessEffectPattern.test(parameter)) {
violations.push({ kind: "missing-pointer-access-effect", line, declaration, parameter });
}
if (/\bZ_OPTIONAL\b/.test(parameter) && !accessEffectPattern.test(parameter)) {
violations.push({ kind: "optional-without-access-effect", line, declaration, parameter });
}
}
}
return violations;
}
const header = await readFile(headerPath, "utf8");
const contractsHeader = await readFile(contractsHeaderPath, "utf8");
const declarations = exportedDeclarations(header);
const pointerParamCount = declarations.reduce((count, { declaration }) => count + pointerParameters(declaration).length, 0);
const pointerReturnCount = declarations.reduce((count, { declaration }) => count + (pointerReturn(declaration) ? 1 : 0), 0);
const violations = contractViolations(header, contractsHeader);
const result = {
schema: 1,
ok: violations.length === 0,
header: headerPath,
declarations: declarations.length,
pointerParameters: pointerParamCount,
pointerReturns: pointerReturnCount,
contractMacros,
violations,
};
if (violations.length > 0) {
console.error(JSON.stringify(result, null, 2));
process.exitCode = 1;
} else {
console.log(JSON.stringify(result, null, 2));
}
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { execFileSync } from "node:child_process";
import { mkdirSync } from "node:fs";
const targetByHost = {
"darwin:arm64": "darwin-arm64",
"darwin:x64": "darwin-x64",
"linux:arm64": "linux-musl-arm64",
"linux:x64": "linux-musl-x64",
"win32:arm64": "win32-arm64.exe",
"win32:x64": "win32-x64.exe",
};
function run(command, args, options = {}) {
execFileSync(command, args, { stdio: "inherit", ...options });
}
const target = targetByHost[`${process.platform}:${process.arch}`];
if (!target) {
console.error(`native smoke does not know a runnable target for ${process.platform}/${process.arch}`);
process.exit(1);
}
const out = ".zero/out/add-native";
const exe = target.startsWith("win32-") ? `${out}.exe` : out;
mkdirSync(".zero/out", { recursive: true });
run("make", ["-C", "native/zero-c"]);
run("bin/zero", ["check", "examples/hello.graph"]);
run("bin/zero", ["build", "--emit", "exe", "--target", target, "examples/add.graph", "--out", out]);
run(exe, []);
+320
View File
@@ -0,0 +1,320 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { spawnSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const root = process.cwd();
const outDir = join(root, ".zero", "native-test-sandbox");
mkdirSync(outDir, { recursive: true });
loadDotEnvFiles([".env", ".env.local"]);
const args = process.argv.slice(2);
if (args.includes("--help") || args.includes("-h")) {
console.log(`Run native test commands inside Vercel Sandbox.
Usage:
pnpm run native:test:sandbox
node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/native-test-sandbox.mts -- pnpm run conformance
Environment:
ZERO_NATIVE_TEST_SANDBOX_SNAPSHOT_ID Reuse a prepared native-test snapshot
ZERO_BENCH_SANDBOX_SNAPSHOT_ID Fallback reusable snapshot id from benchmark setup
ZERO_NATIVE_TEST_SANDBOX_REFRESH=1 Ignore the snapshot id and rebuild
ZERO_NATIVE_TEST_SANDBOX_PROJECT_DIR Remote project directory
ZERO_NATIVE_TEST_SANDBOX_RUNTIME Vercel Sandbox runtime, defaults to node24
ZERO_NATIVE_TEST_SANDBOX_TIMEOUT_MS Sandbox timeout, defaults to 600000
ZERO_NATIVE_TEST_SANDBOX_VCPUS Sandbox vCPU count, defaults to 16
ZERO_SANDBOX_COMMAND Command to run when no -- command is passed
The runner uploads a source archive that excludes generated build output and never copies native test binaries back to the local machine.`);
process.exit(0);
}
function shellQuote(value) {
if (/^[A-Za-z0-9_/:=.,@%+-]+$/.test(value)) return value;
return `'${value.replace(/'/g, "'\\''")}'`;
}
function sandboxCommand() {
const separator = args.indexOf("--");
if (separator !== -1 && separator + 1 < args.length) {
return args.slice(separator + 1).map(shellQuote).join(" ");
}
return process.env.ZERO_SANDBOX_COMMAND?.trim() || "bash scripts/test-native.sh";
}
function loadDotEnvFiles(paths) {
for (const path of paths) {
const fullPath = join(root, path);
if (!existsSync(fullPath)) continue;
const lines = readFileSync(fullPath, "utf8").split(/\r?\n/);
for (const line of lines) {
const trimmed = line.trim();
if (trimmed === "" || trimmed.startsWith("#")) continue;
const match = /^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/.exec(trimmed);
if (!match || process.env[match[1]] !== undefined) continue;
process.env[match[1]] = parseDotEnvValue(match[2]);
}
}
}
function parseDotEnvValue(value) {
const trimmed = value.trim();
const quote = trimmed[0];
if ((quote === "\"" || quote === "'") && trimmed.endsWith(quote)) {
const inner = trimmed.slice(1, -1);
return quote === "\"" ? inner.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, "\t").replace(/\\"/g, "\"").replace(/\\\\/g, "\\") : inner;
}
const commentStart = trimmed.search(/\s#/);
return commentStart === -1 ? trimmed : trimmed.slice(0, commentStart).trimEnd();
}
function parsePositiveInt(value, fallback) {
const parsed = Number.parseInt(value ?? "", 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
function parseOptionalNonNegativeInt(value) {
if (value === undefined || value === "") return undefined;
const parsed = Number.parseInt(value, 10);
if (!Number.isFinite(parsed) || parsed < 0) throw new Error(`expected a non-negative integer, got ${value}`);
return parsed;
}
function sandboxProjectDir() {
return process.env.ZERO_NATIVE_TEST_SANDBOX_PROJECT_DIR ||
process.env.ZERO_BENCH_SANDBOX_PROJECT_DIR ||
"/vercel/sandbox/zero-lang";
}
function sandboxRuntime() {
return process.env.ZERO_NATIVE_TEST_SANDBOX_RUNTIME ||
process.env.ZERO_BENCH_SANDBOX_RUNTIME ||
"node24";
}
function sandboxTimeout() {
return parsePositiveInt(
process.env.ZERO_NATIVE_TEST_SANDBOX_TIMEOUT_MS ?? process.env.ZERO_BENCH_SANDBOX_TIMEOUT_MS,
10 * 60 * 1000,
);
}
function sandboxVcpus() {
return parsePositiveInt(
process.env.ZERO_NATIVE_TEST_SANDBOX_VCPUS ?? process.env.ZERO_BENCH_SANDBOX_VCPUS,
16,
);
}
function snapshotFromEnv() {
const refresh = (process.env.ZERO_NATIVE_TEST_SANDBOX_REFRESH ?? "").toLowerCase();
if (["1", "true", "yes"].includes(refresh)) return null;
const snapshotId = process.env.ZERO_NATIVE_TEST_SANDBOX_SNAPSHOT_ID?.trim() ||
process.env.ZERO_BENCH_SANDBOX_SNAPSHOT_ID?.trim();
if (!snapshotId) return null;
return {
snapshotId,
projectDir: sandboxProjectDir(),
timeout: sandboxTimeout(),
vcpus: sandboxVcpus(),
reused: true,
};
}
function ensureVercelAuthEnv() {
if (process.env.VERCEL_OIDC_TOKEN?.trim()) return;
throw new Error(
"native:test:sandbox requires VERCEL_OIDC_TOKEN. Put it in .env or .env.local, matching the benchmark sandbox runner, or export it before running.",
);
}
function writeSnapshotEnv(snapshot) {
const snapshotPath = join(outDir, "snapshot.env");
const lines = [
`ZERO_NATIVE_TEST_SANDBOX_SNAPSHOT_ID=${snapshot.snapshotId}`,
`ZERO_NATIVE_TEST_SANDBOX_PROJECT_DIR=${snapshot.projectDir}`,
"",
];
writeFileSync(snapshotPath, lines.join("\n"));
process.stderr.write(`Created Vercel Sandbox native-test snapshot: ${snapshot.snapshotId}\n`);
process.stderr.write(`Saved reusable snapshot env to ${snapshotPath}\n`);
process.stderr.write("Add ZERO_NATIVE_TEST_SANDBOX_SNAPSHOT_ID to .env to reuse it, or set ZERO_NATIVE_TEST_SANDBOX_REFRESH=1 to rebuild it.\n");
}
function createSourceArchive() {
const archivePath = join(outDir, "source.tar.gz");
rmSync(archivePath, { force: true });
const excludes = [
".git",
".cursor",
".env",
".env.*",
".vercel",
".zero",
".next",
"dist",
"coverage",
"node_modules",
"docs/.next",
"docs/out",
"extensions/*/node_modules",
"docs/node_modules",
];
const excludeArgs = excludes.flatMap((exclude) => [`--exclude=${exclude}`, `--exclude=./${exclude}`]);
const metadataArgs = process.platform === "darwin" ? ["--no-xattrs"] : [];
const result = spawnSync("tar", [...metadataArgs, ...excludeArgs, "-czf", archivePath, "."], {
cwd: root,
encoding: "utf8",
env: { ...process.env, COPYFILE_DISABLE: "1" },
});
if (result.status !== 0) throw new Error(`failed to create native-test source archive\n${result.stderr.trim()}`);
return archivePath;
}
async function runSandboxCommand(sandbox, params, label) {
const result = await sandbox.runCommand(params);
let stdout = "";
let stderr = "";
for await (const log of result.logs()) {
if (log.stream === "stdout") {
stdout += log.data;
process.stdout.write(log.data);
} else {
stderr += log.data;
process.stderr.write(log.data);
}
}
if (result.exitCode !== 0) {
throw new Error(`${label} failed with exit code ${result.exitCode}`);
}
return { stdout, stderr };
}
function describeError(error) {
if (!(error instanceof Error)) return String(error);
const parts = [error.message];
if ("json" in error && error.json) parts.push(JSON.stringify(error.json));
if ("text" in error && error.text) parts.push(String(error.text));
return parts.filter(Boolean).join("\n");
}
async function createPreparedSnapshot(Sandbox) {
const runtime = sandboxRuntime();
const timeout = sandboxTimeout();
const vcpus = sandboxVcpus();
const snapshotExpiration = parseOptionalNonNegativeInt(process.env.ZERO_NATIVE_TEST_SANDBOX_SNAPSHOT_EXPIRATION_MS);
const archivePath = createSourceArchive();
const sandbox = await Sandbox.create({ runtime, timeout, resources: { vcpus } });
const projectDir = sandboxProjectDir();
try {
await sandbox.writeFiles([{ path: "/tmp/zero-lang-source.tar.gz", content: readFileSync(archivePath) }]);
await runSandboxCommand(
sandbox,
{
cmd: "bash",
args: [
"-lc",
[
"set -euo pipefail",
"as_root() { if command -v sudo >/dev/null 2>&1; then sudo \"$@\"; else \"$@\"; fi; }",
"install_build_tools() {",
" if command -v make >/dev/null 2>&1 && { command -v cc >/dev/null 2>&1 || command -v gcc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1; }; then return; fi",
" if command -v apt-get >/dev/null 2>&1; then",
" as_root apt-get update",
" as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential ca-certificates git gzip make tar",
" elif command -v apk >/dev/null 2>&1; then",
" as_root apk add --no-cache build-base ca-certificates git gzip make tar",
" elif command -v dnf >/dev/null 2>&1; then",
" as_root dnf install -y ca-certificates gcc git glibc-devel gzip make tar",
" elif command -v yum >/dev/null 2>&1; then",
" as_root yum install -y ca-certificates gcc git glibc-devel gzip make tar",
" else",
" echo 'no supported package manager found to install make and a C compiler' >&2",
" exit 127",
" fi",
"}",
"install_build_tools",
"command -v make >/dev/null 2>&1",
"command -v cc >/dev/null 2>&1 || command -v gcc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1",
`rm -rf ${projectDir}`,
`mkdir -p ${projectDir}`,
`tar -xzf /tmp/zero-lang-source.tar.gz -C ${projectDir}`,
`cd ${projectDir}`,
"corepack enable",
"corepack prepare pnpm@11.1.3 --activate",
"pnpm install --frozen-lockfile",
"make -C native/zero-c",
"node --version",
].join("\n"),
],
},
"native-test sandbox setup",
);
const snapshot = await sandbox.snapshot(snapshotExpiration === undefined ? undefined : { expiration: snapshotExpiration });
const preparedSnapshot = { snapshotId: snapshot.snapshotId, projectDir, timeout, vcpus, reused: false };
writeSnapshotEnv(preparedSnapshot);
return preparedSnapshot;
} catch (error) {
await sandbox.stop({ blocking: true }).catch(() => {});
throw error;
}
}
async function runSandboxTask(Sandbox, snapshot, command) {
const archivePath = createSourceArchive();
const sandbox = await Sandbox.create({
source: { type: "snapshot", snapshotId: snapshot.snapshotId },
timeout: snapshot.timeout,
resources: { vcpus: snapshot.vcpus },
});
try {
await sandbox.writeFiles([{ path: "/tmp/zero-lang-source-current.tar.gz", content: readFileSync(archivePath) }]);
await runSandboxCommand(
sandbox,
{
cmd: "bash",
args: [
"-lc",
[
"set -euxo pipefail",
`cd ${snapshot.projectDir}`,
"find . -mindepth 1 -maxdepth 1 ! -name node_modules -exec rm -rf {} +",
`tar -xzf /tmp/zero-lang-source-current.tar.gz -C ${snapshot.projectDir}`,
"corepack enable",
"corepack prepare pnpm@11.1.3 --activate",
"pnpm install --frozen-lockfile",
"make -C native/zero-c",
command,
].join("\n"),
],
cwd: snapshot.projectDir,
env: { ZERO_NATIVE_TEST_SANDBOX: "1" },
},
`${command} in Vercel Sandbox`,
);
} finally {
await sandbox.stop({ blocking: true }).catch(() => {});
}
}
async function main() {
ensureVercelAuthEnv();
const { Sandbox } = await import("@vercel/sandbox").catch((error) => {
throw new Error(`native:test:sandbox requires @vercel/sandbox. Run pnpm install first.\n${error.message}`);
});
const reusableSnapshot = snapshotFromEnv();
const snapshot = reusableSnapshot ?? (await createPreparedSnapshot(Sandbox));
const reuseText = snapshot.reused ? "reused" : "fresh";
const command = sandboxCommand();
process.stderr.write(`Running ${command} in Vercel Sandbox using ${reuseText} snapshot ${snapshot.snapshotId}...\n`);
await runSandboxTask(Sandbox, snapshot, command);
process.stderr.write(`sandbox command ok: ${command}\n`);
}
main().catch((error) => {
console.error(describeError(error));
process.exit(1);
});
File diff suppressed because it is too large Load Diff
+350
View File
@@ -0,0 +1,350 @@
import { execFile } from "node:child_process";
import assert from "node:assert/strict";
import { existsSync } from "node:fs";
import { lstat, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const cc = process.env.CC ?? "cc";
const out = `/tmp/zero-program-graph-smoke-${process.pid}`;
try {
await execFileAsync(cc, [
"-std=c11",
"-Wall",
"-Wextra",
"-Wpedantic",
"-I",
"native/zero-c/include",
"-I",
"native/zero-c/src",
"native/zero-c/src/program_graph.c",
"native/zero-c/src/program_graph_adjacency.c",
"native/zero-c/src/program_graph_clone.c",
"native/zero-c/src/program_graph_identity.c",
"native/zero-c/src/program_graph_import.c",
"native/zero-c/src/program_graph_lower.c",
"native/zero-c/src/program_graph_node_id.c",
"native/zero-c/src/program_graph_order.c",
"native/zero-c/src/program_graph_format.c",
"native/zero-c/src/program_graph_handle.c",
"native/zero-c/src/program_graph_compare.c",
"native/zero-c/src/program_graph_projection_path.c",
"native/zero-c/src/program_graph_projection_fast.c",
"native/zero-c/src/program_graph_reconcile.c",
"native/zero-c/src/program_graph_reconcile_apply.c",
"native/zero-c/src/program_graph_resolve.c",
"native/zero-c/src/program_graph_semantics.c",
"native/zero-c/src/program_graph_source_map.c",
"native/zero-c/src/program_graph_store.c",
"native/zero-c/src/program_graph_store_binary.c",
"native/zero-c/src/program_graph_store_prune.c",
"native/zero-c/src/program_graph_store_tables.c",
"native/zero-c/src/program_graph_std_deps.c",
"native/zero-c/src/program_graph_std_merge.c",
"native/zero-c/src/program_graph_std_prune.c",
"native/zero-c/src/program_graph_string_map.c",
"native/zero-c/src/program_graph_validate.c",
"native/zero-c/src/program_graph_view.c",
"native/zero-c/src/c_import.c",
"native/zero-c/src/canonical_text.c",
"native/zero-c/src/canonical_text_format.c",
"native/zero-c/src/canonical_text_program.c",
"native/zero-c/src/canonical_text_write.c",
"native/zero-c/src/fs_read.c",
"native/zero-c/src/std_sig.c",
"native/zero-c/src/std_source.c",
"native/zero-c/src/ast.c",
"native/zero-c/tests/program_graph_smoke_stubs.c",
"native/zero-c/tests/program_graph_smoke.c",
"-o",
out,
]);
const result = await execFileAsync(out);
if (!result.stdout.includes("program graph smoke ok")) {
throw new Error(`unexpected ProgramGraph smoke output: ${result.stdout}`);
}
} finally {
await rm(out, { force: true });
}
const zero = process.env.ZERO_BIN || (existsSync(".zero/bin/zero") ? ".zero/bin/zero" : "bin/zero");
const checkedInBinaryRoot = "examples/binary-graph-store";
const checkedInBinaryCrmRoot = "examples/crm-api";
const binaryRoot = `/tmp/zero-program-graph-binary-store-${process.pid}`;
async function zeroRun(args: string[]) {
return execFileAsync(zero, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024 });
}
async function zeroRunMaybe(args: string[]) {
try {
const result = await zeroRun(args);
return { code: 0, stdout: result.stdout, stderr: result.stderr };
} catch (error: any) {
return {
code: error.code ?? error.status ?? 1,
stdout: error.stdout ?? "",
stderr: error.stderr ?? "",
};
}
}
async function findCheckedInGraphStores(root: string, stores: string[] = []) {
if (!existsSync(root)) return stores;
for (const entry of await readdir(root, { withFileTypes: true })) {
const path = `${root}/${entry.name}`;
if (entry.isDirectory()) {
if (entry.name === ".zero" || entry.name === "node_modules") continue;
await findCheckedInGraphStores(path, stores);
} else if (entry.isFile() && entry.name === "zero.graph") {
stores.push(path);
} else if (entry.isSymbolicLink()) {
const stat = await lstat(path);
if (stat.isFile() && entry.name === "zero.graph") stores.push(path);
}
}
return stores;
}
async function findCheckedInFiles(root: string, suffix: string, files: string[] = []) {
if (!existsSync(root)) return files;
for (const entry of await readdir(root, { withFileTypes: true })) {
const path = `${root}/${entry.name}`;
if (entry.isDirectory()) {
if (entry.name === ".zero" || entry.name === "node_modules") continue;
await findCheckedInFiles(path, suffix, files);
} else if (entry.isFile() && entry.name.endsWith(suffix)) {
files.push(path);
} else if (entry.isSymbolicLink()) {
const stat = await lstat(path);
if (stat.isFile() && entry.name.endsWith(suffix)) files.push(path);
}
}
return files;
}
async function findAtomicWriteTempFiles(root: string, files: string[] = []) {
if (!existsSync(root)) return files;
for (const entry of await readdir(root, { withFileTypes: true })) {
const path = `${root}/${entry.name}`;
if (entry.name.includes(".zero-tmp-")) {
files.push(path);
continue;
}
if (entry.isDirectory()) {
await findAtomicWriteTempFiles(path, files);
}
}
return files;
}
async function assertNoAtomicWriteTempFiles(root: string) {
assert.deepEqual(await findAtomicWriteTempFiles(root), [], `${root}: atomic graph writes must clean up temporary files`);
}
function projectionHasGraphAuthority(path: string) {
if (existsSync(path.replace(/\.0$/, ".graph"))) return true;
for (let current = dirname(path); current !== "." && current !== "/"; current = dirname(current)) {
if (existsSync(join(current, "zero.graph"))) return true;
}
return false;
}
function assertBinaryGraphStore(path: string, bytes: Buffer) {
assert.equal(bytes.subarray(0, 8).toString("binary"), "ZRGBIN1\0", `${path} should be a binary repository graph store`);
}
const BINARY_NODE_COUNT_OFFSET = 40;
const BINARY_EDGE_COUNT_OFFSET = 48;
const BINARY_STRING_BYTES_OFFSET = 64;
const BINARY_MODULE_IDENTITY_REF_OFFSET = 72;
function corruptBinaryStoreModuleIdentity(bytes: Buffer) {
const copy = Buffer.from(bytes);
const stringBytes = Number(copy.readBigUInt64LE(BINARY_STRING_BYTES_OFFSET));
const moduleIdentityOffset = Number(copy.readBigUInt64LE(BINARY_MODULE_IDENTITY_REF_OFFSET));
const moduleIdentityLen = Number(copy.readBigUInt64LE(BINARY_MODULE_IDENTITY_REF_OFFSET + 8));
assert(stringBytes <= copy.length, "binary store fixture has invalid string table size");
assert(moduleIdentityLen > 2, "binary store fixture module identity is too short to corrupt");
const stringsOffset = copy.length - stringBytes;
assert(moduleIdentityOffset + 1 < stringBytes, "binary store fixture module identity offset is out of range");
copy[stringsOffset + moduleIdentityOffset + 1] = 0;
return copy;
}
function corruptBinaryStoreNodeCount(bytes: Buffer) {
const copy = Buffer.from(bytes);
copy.writeBigUInt64LE(1_000_001n, BINARY_NODE_COUNT_OFFSET);
return copy;
}
function corruptBinaryStoreEdgeCount(bytes: Buffer) {
const copy = Buffer.from(bytes);
copy.writeBigUInt64LE(4_000_001n, BINARY_EDGE_COUNT_OFFSET);
return copy;
}
async function assertInvalidBinaryStoreRejected(root: string, bytes: Buffer, label: string) {
await rm(root, { recursive: true, force: true });
await mkdir(root, { recursive: true });
await writeFile(
`${root}/zero.toml`,
'[package]\nname = "corrupt-binary-store"\nversion = "0.1.0"\n\n[targets.cli]\nkind = "exe"\nmain = "main.0"\n',
);
await writeFile(`${root}/main.0`, "pub fn main() -> i32 { return 0 }\n");
await writeFile(`${root}/zero.graph`, bytes);
const status = await zeroRunMaybe(["status", "--json", root]);
assert.notEqual(status.code, 0, `${label}: corrupt binary store status should fail`);
const body = JSON.parse(status.stdout);
assert.equal(body.repositoryGraph.storePresent, true);
assert.equal(body.repositoryGraph.storeValid, false);
assert.equal(body.repositoryGraph.projectionState, "store-invalid");
assert.equal(body.diagnostics[0].code, "RGP003");
assert.match(body.diagnostics[0].message, /repository graph store is invalid|invalid repository graph store|invalid binary repository graph store/);
}
const checkedInStores = [
...(await findCheckedInGraphStores("examples")),
...(await findCheckedInGraphStores("conformance")),
...(await findCheckedInGraphStores("benchmarks")),
].sort();
assert(checkedInStores.length > 0, "expected checked-in repository graph stores");
for (const store of checkedInStores) {
assertBinaryGraphStore(store, await readFile(store));
}
const checkedInGraphArtifacts = [
...(await findCheckedInFiles("examples", ".graph")),
...(await findCheckedInFiles("conformance", ".graph")),
...(await findCheckedInFiles("benchmarks", ".graph")),
...(await findCheckedInFiles("std", ".graph")),
].sort();
assert(checkedInGraphArtifacts.length > 0, "expected checked-in graph artifacts");
for (const graph of checkedInGraphArtifacts) {
assertBinaryGraphStore(graph, await readFile(graph));
}
const checkedInProjections = [
...(await findCheckedInFiles("examples", ".0")),
...(await findCheckedInFiles("conformance", ".0")),
...(await findCheckedInFiles("benchmarks", ".0")),
...(await findCheckedInFiles("std", ".0")),
].sort();
assert(checkedInProjections.length > 0, "expected checked-in source projections");
for (const projection of checkedInProjections) {
assert.equal(projectionHasGraphAuthority(projection), true, `${projection} must have a graph authority`);
}
for (const store of checkedInStores) {
const root = dirname(store);
const status = JSON.parse((await zeroRun(["status", "--json", root])).stdout);
assert.equal(status.store.encoding, "binary", `${root}: checked-in repository graph store must be binary`);
assert.equal(status.repositoryGraph.projectionValidity, "clean", `${root}: checked-in source projections must be clean`);
assert.equal((await zeroRun(["verify-projection", root])).stdout, "repository graph verify-projection ok\n", `${root}: verify-projection`);
}
const checkedInBinaryStore = await readFile(`${checkedInBinaryRoot}/zero.graph`);
assertBinaryGraphStore(`${checkedInBinaryRoot}/zero.graph`, checkedInBinaryStore);
const checkedInBinaryStatus = JSON.parse((await zeroRun(["status", "--json", checkedInBinaryRoot])).stdout);
assert.equal(checkedInBinaryStatus.store.encoding, "binary");
assert.equal(checkedInBinaryStatus.repositoryGraph.projectionValidity, "clean");
assert.equal((await zeroRun(["check", checkedInBinaryRoot])).stdout, "ok\n");
assert.equal((await zeroRun(["test", checkedInBinaryRoot])).stdout, "1 test(s) ok\n");
assert.equal((await zeroRun(["run", checkedInBinaryRoot])).stdout, "binary graph store example\n");
assert.equal((await zeroRun(["verify-projection", checkedInBinaryRoot])).stdout, "repository graph verify-projection ok\n");
const checkedInBinaryCrmStore = await readFile(`${checkedInBinaryCrmRoot}/zero.graph`);
assertBinaryGraphStore(`${checkedInBinaryCrmRoot}/zero.graph`, checkedInBinaryCrmStore);
const checkedInBinaryCrmStatus = JSON.parse((await zeroRun(["status", "--json", checkedInBinaryCrmRoot])).stdout);
assert.equal(checkedInBinaryCrmStatus.store.encoding, "binary");
assert.equal(checkedInBinaryCrmStatus.repositoryGraph.projectionValidity, "clean");
assert.equal((await zeroRun(["check", checkedInBinaryCrmRoot])).stdout, "ok\n");
assert.equal((await zeroRun(["verify-projection", checkedInBinaryCrmRoot])).stdout, "repository graph verify-projection ok\n");
await rm(binaryRoot, { recursive: true, force: true });
await mkdir(binaryRoot, { recursive: true });
await zeroRun(["init", binaryRoot]);
await assertNoAtomicWriteTempFiles(binaryRoot);
let binaryStore = await readFile(`${binaryRoot}/zero.graph`);
assert.equal(binaryStore.subarray(0, 8).toString("binary"), "ZRGBIN1\0");
await zeroRun(["patch", binaryRoot, "--op", "addMain", "--op", 'addCheckWrite fn="main" text="hello binary\\n"']);
await assertNoAtomicWriteTempFiles(binaryRoot);
binaryStore = await readFile(`${binaryRoot}/zero.graph`);
assert.equal(binaryStore.subarray(0, 8).toString("binary"), "ZRGBIN1\0");
await assertInvalidBinaryStoreRejected(
`/tmp/zero-program-graph-binary-corrupt-nul-${process.pid}`,
corruptBinaryStoreModuleIdentity(binaryStore),
"embedded nul",
);
await assertInvalidBinaryStoreRejected(
`/tmp/zero-program-graph-binary-corrupt-count-${process.pid}`,
corruptBinaryStoreNodeCount(binaryStore),
"node count",
);
await assertInvalidBinaryStoreRejected(
`/tmp/zero-program-graph-binary-corrupt-edge-count-${process.pid}`,
corruptBinaryStoreEdgeCount(binaryStore),
"edge count",
);
const binaryStatus = JSON.parse((await zeroRun(["status", "--json", binaryRoot])).stdout);
assert.equal(binaryStatus.store.encoding, "binary");
assert.equal(binaryStatus.storage.encoding, "single-file-binary");
assert.equal(binaryStatus.storage.defaultEncoding, "binary");
assert.equal(binaryStatus.storage.binaryAvailable, true);
assert.equal((await zeroRun(["check", binaryRoot])).stdout, "ok\n");
assert.equal((await zeroRun(["run", binaryRoot])).stdout, "hello binary\n");
const cleanRunStore = await readFile(`${binaryRoot}/zero.graph`);
await writeFile(`${binaryRoot}/zero.graph`, corruptBinaryStoreNodeCount(cleanRunStore));
const corruptCachedRun = await zeroRunMaybe(["run", binaryRoot]);
assert.notEqual(corruptCachedRun.code, 0, "corrupt binary store run should fail before using the linked executable cache");
assert.notEqual(corruptCachedRun.stdout, "hello binary\n", "corrupt binary store run must not execute the cached program");
assert.match(
`${corruptCachedRun.stdout}\n${corruptCachedRun.stderr}`,
/repository graph store is invalid|invalid repository graph store|invalid binary repository graph store/,
);
await writeFile(`${binaryRoot}/zero.graph`, cleanRunStore);
assert.match((await zeroRun(["export", binaryRoot])).stdout, /repository graph export ok/);
await assertNoAtomicWriteTempFiles(binaryRoot);
assert.equal((await zeroRun(["verify-projection", binaryRoot])).stdout, "repository graph verify-projection ok\n");
const textRoot = `/tmp/zero-program-graph-binary-convert-${process.pid}`;
await rm(textRoot, { recursive: true, force: true });
await mkdir(textRoot, { recursive: true });
await zeroRun(["init", "--format", "text", textRoot]);
await zeroRun(["patch", textRoot, "--op", "addMain", "--op", 'addCheckWrite fn="main" text="convert me\\n"']);
await assertNoAtomicWriteTempFiles(textRoot);
assert.match((await readFile(`${textRoot}/zero.graph`, "utf8")).slice(0, 64), /^zero-repository-graph v1/);
await zeroRun(["export", textRoot]);
await zeroRun(["import", "--format", "binary", textRoot]);
await assertNoAtomicWriteTempFiles(textRoot);
const convertedStore = await readFile(`${textRoot}/zero.graph`);
assert.equal(convertedStore.subarray(0, 8).toString("binary"), "ZRGBIN1\0");
assert.equal((await zeroRun(["run", textRoot])).stdout, "convert me\n");
assert.equal((await zeroRun(["verify-projection", textRoot])).stdout, "repository graph verify-projection ok\n");
const projectionDefaultRoot = `/tmp/zero-program-graph-projection-default-${process.pid}`;
await rm(projectionDefaultRoot, { recursive: true, force: true });
await mkdir(projectionDefaultRoot, { recursive: true });
await writeFile(
`${projectionDefaultRoot}/main.0`,
'pub fn main(world: World) -> Void raises {\n check world.out.write("projection default\\n")\n}\n',
);
await writeFile(
`${projectionDefaultRoot}/zero.toml`,
'[package]\nname = "projection-default"\nversion = "0.1.0"\n\n[targets.cli]\nkind = "exe"\nmain = "main.0"\n',
);
await zeroRun(["import", projectionDefaultRoot]);
await assertNoAtomicWriteTempFiles(projectionDefaultRoot);
const projectionDefaultStore = await readFile(`${projectionDefaultRoot}/zero.graph`);
assert.equal(projectionDefaultStore.subarray(0, 8).toString("binary"), "ZRGBIN1\0");
assert.equal((await zeroRun(["run", projectionDefaultRoot])).stdout, "projection default\n");
const invalidFormat = await zeroRun(["import", "--format", "pickle", textRoot]).catch((error) => error);
assert.notEqual(invalidFormat.code ?? invalidFormat.status, 0);
assert.match(invalidFormat.stderr, /repository graph store format is not supported/);
+664
View File
@@ -0,0 +1,664 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { existsSync, readFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(scriptDir, "..");
const checkerPath = path.join(repoRoot, "native/zero-c/src/checker.c");
const callResolvePath = path.join(repoRoot, "native/zero-c/src/call_resolve.h");
const stdSigPath = path.join(repoRoot, "native/zero-c/src/std_sig.h");
const matrixPath = path.join(repoRoot, "conformance/provenance-surface.json");
const conformancePath = path.join(repoRoot, "conformance/run.mjs");
const checker = readFileSync(checkerPath, "utf8");
const callResolve = readFileSync(callResolvePath, "utf8");
const stdSig = readFileSync(stdSigPath, "utf8");
const surfaceSpec = JSON.parse(readFileSync(matrixPath, "utf8"));
const conformance = readFileSync(conformancePath, "utf8");
const failures = [];
function fail(message) {
failures.push(message);
}
function assertIncludes(label, text, needle) {
if (!text.includes(needle)) fail(`${label}: missing ${needle}`);
}
function assertNotIncludes(label, text, needle) {
if (text.includes(needle)) fail(`${label}: unexpected ${needle}`);
}
function assertBefore(label, text, first, second) {
const firstIndex = text.indexOf(first);
const secondIndex = text.indexOf(second);
if (firstIndex < 0) fail(`${label}: missing ${first}`);
if (secondIndex < 0) fail(`${label}: missing ${second}`);
if (firstIndex >= 0 && secondIndex >= 0 && firstIndex > secondIndex) fail(`${label}: ${first} must appear before ${second}`);
}
function assertMatches(label, text, pattern) {
if (!pattern.test(text)) fail(`${label}: missing ${pattern}`);
}
function assertFixtureCoverage(label, fixture) {
const fullPath = path.join(repoRoot, fixture);
if (!existsSync(fullPath)) {
fail(`${label}: fixture '${fixture}' does not exist`);
return;
}
const basename = path.basename(fixture);
if (!conformance.includes(fixture) && !conformance.includes(basename)) {
fail(`${label}: fixture '${fixture}' is not run by conformance/run.mjs`);
}
}
function sliceBetween(text, start, end) {
const startIndex = text.indexOf(start);
if (startIndex < 0) return "";
const endIndex = text.indexOf(end, startIndex + start.length);
if (endIndex < 0) return text.slice(startIndex);
return text.slice(startIndex, endIndex);
}
function checkerFunctionNames(source) {
const names = new Set();
for (const line of source.split("\n")) {
if (line.trim().endsWith(";")) continue;
const match = line.match(/^static\b[^{;]*?\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/);
if (match) names.add(match[1]);
}
return names;
}
function currentFunctionByLine(source) {
const current = [];
let name = "<top-level>";
const lines = source.split("\n");
for (const line of lines) {
if (!line.trim().endsWith(";")) {
const match = line.match(/^static\b[^{;]*?\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/);
if (match) name = match[1];
}
current.push(name);
}
return current;
}
function surfaceFixturePaths(fixtures) {
if (Array.isArray(fixtures)) return fixtures;
if (!fixtures || typeof fixtures !== "object") return [];
const paths = [];
for (const group of ["fail", "pass", "other"]) {
if (fixtures[group] === undefined) continue;
if (!Array.isArray(fixtures[group])) {
fail(`provenance surface spec: fixtures.${group} must be an array`);
continue;
}
paths.push(...fixtures[group]);
}
return paths;
}
function parseSurfaceRows(spec) {
const rows = [];
if (!spec || typeof spec !== "object") {
fail("provenance surface spec: expected JSON object");
return rows;
}
if (spec.schemaVersion !== 1) fail("provenance surface spec: schemaVersion must be 1");
if (spec.kind !== "zero-provenance-surface-matrix") fail("provenance surface spec: unexpected kind");
if (!Array.isArray(spec.surfaces)) {
fail("provenance surface spec: surfaces must be an array");
return rows;
}
const seen = new Set();
for (let index = 0; index < spec.surfaces.length; index++) {
const row = spec.surfaces[index];
if (!row || typeof row !== "object") {
fail(`provenance surface spec: surface ${index + 1} must be an object`);
continue;
}
if (!row.surface || typeof row.surface !== "string") fail(`provenance surface spec: surface ${index + 1} has no name`);
if (!row.action || typeof row.action !== "string") fail(`provenance surface spec: '${row.surface ?? index + 1}' has no action`);
if (!Array.isArray(row.owners)) fail(`provenance surface spec: '${row.surface ?? index + 1}' owners must be an array`);
if (row.surface && seen.has(row.surface)) fail(`provenance surface spec: duplicate surface '${row.surface}'`);
if (row.surface) seen.add(row.surface);
rows.push({
surface: row.surface,
action: row.action,
owners: Array.isArray(row.owners) ? row.owners : [],
fixtures: surfaceFixturePaths(row.fixtures),
});
}
return rows;
}
const functionNames = checkerFunctionNames(checker);
const rows = parseSurfaceRows(surfaceSpec);
const rowsBySurface = new Map(rows.map((row) => [row.surface, row]));
const requiredSurfaces = [
"Identifier reads",
"Field reads",
"Index reads",
"Direct borrows",
"Mutable borrows",
"Shape literals",
"Array literals",
"Maybe<T> values",
"Choice payloads",
"check unwraps",
"rescue values",
"Primitive casts",
"Plain calls",
"Generic calls",
"Shape namespace calls",
"Receiver calls",
"Static interface calls",
"Incomplete summaries",
"Let bindings",
"Assignments",
"Field assignments",
"Index assignments",
"Returns",
"If joins",
"Match joins",
"Loop-carried values",
"Short-circuit expressions",
"Early returns",
"Mutref aliases",
];
for (const surface of requiredSurfaces) {
if (!rowsBySurface.has(surface)) fail(`provenance matrix: missing surface row '${surface}'`);
}
for (const row of rows) {
if (row.owners.length === 0) fail(`provenance matrix: '${row.surface}' has no checker owner`);
for (const owner of row.owners) {
if (!functionNames.has(owner)) fail(`provenance matrix: owner '${owner}' for '${row.surface}' is not a checker function`);
}
for (const fixture of row.fixtures) {
assertFixtureCoverage(`provenance matrix '${row.surface}'`, fixture);
}
}
const positivePrecisionClasses = [
["direct same-origin mutable reassignment", "conformance/native/pass/borrow-aggregate-reassignment-same-origin.0"],
["alias same-origin mutable reassignment", "conformance/native/pass/mutref-alias-assignment-same-origin.0"],
["field overwrite clears old origin", "conformance/native/pass/shape-field-reference-reassignment-clears-origin.0"],
["disjoint field assignment", "conformance/native/pass/borrow-field-independent-assignment.0"],
["caller-owned return ref", "conformance/native/pass/borrow-return-param-ref.0"],
["caller-owned field return ref", "conformance/native/pass/borrow-return-param-field-subpath.0"],
["plain mutref stores caller-owned ref", "conformance/native/pass/function-mutref-reference-store.0"],
["generic mutref stores caller-owned ref", "conformance/native/pass/generic-mutref-reference-store.0"],
["receiver stores caller-owned ref", "conformance/native/pass/receiver-method-reference-store.0"],
["static interface stores caller-owned ref", "conformance/native/pass/static-interface-mutref-reference-store.0"],
["static interface returns caller-owned ref", "conformance/native/pass/static-interface-return-reference-origin.0"],
["choice payload returns caller-owned ref", "conformance/native/pass/choice-payload-reference-return.0"],
["choice match payload preserves caller-owned ref", "conformance/native/pass/choice-match-payload-reference-origin.0"],
["choice match payload returns caller-owned ref", "conformance/native/pass/choice-match-payload-return-origin.0"],
["branches merge same origin", "conformance/native/pass/borrow-branch-reassignment.0"],
["branches overwrite away unsafe origin", "conformance/native/pass/branch-overwrite-away-reference-origin.0"],
["indexed assignment clears overwritten origin", "conformance/native/pass/index-reference-assignment-clears-origin.0"],
];
for (const [label, fixture] of positivePrecisionClasses) {
assertFixtureCoverage(`positive provenance class '${label}'`, fixture);
}
const canonicalPlaceClasses = [
["direct field write", "conformance/native/pass/function-mutref-reference-store.0"],
["mutref alias field write", "conformance/native/pass/mutref-alias-assignment-clears-old-origin.0"],
["receiver self field write", "conformance/native/pass/receiver-method-reference-store.0"],
["generic mutref write", "conformance/native/pass/generic-mutref-reference-store.0"],
["constrained interface mutref write", "conformance/native/pass/static-interface-mutref-reference-store.0"],
["precise indexed write clears target", "conformance/native/pass/index-reference-assignment-clears-origin.0"],
];
for (const [label, fixture] of canonicalPlaceClasses) {
if (existsSync(path.join(repoRoot, fixture))) assertFixtureCoverage(`canonical place class '${label}'`, fixture);
}
const requiredFunctions = [
"expr_value_provenance",
"expr_reference_provenance",
"resolve_provenance_call",
"call_result_value_provenance",
"function_provenance_summary",
"function_return_value_provenance",
"function_storage_effect_summary",
"choice_constructor_value_provenance",
"register_match_payload_binding_provenance",
"apply_checked_call_storage_effects",
"check_call_expr_expected",
"check_named_function_call_expected",
"check_stdlib_table_arg_range_expected",
"check_receiver_shape_call_expected",
"fallible_callee_in_context",
"resolve_stdlib_fallible_call",
"stdlib_call_error_sets_covered",
"function_error_sets_include_stdlib_resolution",
"find_shape_owning_method",
"finish_shape_method_provenance_call",
"resolve_shape_namespace_provenance_call",
"resolve_concrete_constrained_shape_provenance_call",
"resolve_named_provenance_call",
"resolve_constrained_interface_provenance_call",
"resolve_receiver_shape_provenance_call",
"bind_type_args_to_bindings",
"checked_call_type_args",
"generic_bindings_from_type_args",
"checked_call_bindings_from_recorded_type_args",
"shape_method_bindings_from_recorded_type_args",
"interface_method_bindings_from_recorded_type_args",
"generic_call_bindings_from_checked_call",
"call_resolution_record_bindings",
"call_resolution_record_param_facts",
"call_resolution_param_type_text",
"resolved_call_param_type_text",
"apply_provenance_storage_effect",
"stdlib_install_item_write_provenance",
"collect_effect_target_places",
"collect_assignment_target_places",
"expr_static_index_segment",
"origin_path_is_definitely_within",
"update_borrow_assignment",
"assignment_provenance_snapshot_clear",
"provenance_scope_snapshot_restore_union",
];
for (const name of requiredFunctions) {
if (!functionNames.has(name)) fail(`checker provenance foundation: missing function '${name}'`);
}
for (const kind of [
"Z_CALL_FUNCTION",
"Z_CALL_STDLIB",
"Z_CALL_SHAPE_NAMESPACE",
"Z_CALL_RECEIVER",
"Z_CALL_CONSTRAINED_INTERFACE",
"Z_CALL_CONCRETE_CONSTRAINED_SHAPE",
"Z_CALL_CHOICE_CONSTRUCTOR",
]) {
assertIncludes("shared call resolver", callResolve, kind);
assertIncludes("checker provenance call resolver", checker, kind);
}
for (const needle of [
"ZCallArgument",
"ZCallBinding",
"ZCallError",
"z_call_resolution_add_arg",
"z_call_resolution_expected_arg_count",
"z_call_resolution_param_type",
"z_call_resolution_add_binding",
"z_call_resolution_binding_type",
"z_call_resolution_add_error",
"z_call_resolution_error_set_text",
]) {
assertIncludes("shared call argument facts", callResolve, needle);
}
assertIncludes("shared stdlib error facts", stdSig, "Z_STD_HELPER_MAX_ERRORS");
assertIncludes("shared stdlib error facts", stdSig, "error_names");
assertIncludes("shared stdlib error facts", stdSig, "z_std_helper_error_name");
assertIncludes("shared stdlib error facts", stdSig, "z_std_helper_error_set_text");
assertIncludes("shared stdlib helper classification", stdSig, "ZStdHelperKind");
assertIncludes("shared stdlib helper classification", stdSig, "z_std_helper_kind");
assertNotIncludes("shared stdlib fallibility facts", checker, "is_builtin_fallible_call");
assertNotIncludes("shared stdlib fallibility facts", checker, "builtin_fallible_return_type");
const callResultBody = sliceBetween(checker, "static bool call_result_value_provenance", "static bool expr_reference_provenance");
assertIncludes("call result provenance", callResultBody, "resolve_provenance_call");
assertIncludes("call result provenance", callResultBody, "function_return_value_provenance");
assertIncludes("call result provenance", callResultBody, "instantiate_call_provenance_entry");
assertIncludes("call result provenance", callResultBody, "resolved_call_param_type_text");
const shapeMethodProvenanceBody = sliceBetween(checker, "static bool finish_shape_method_provenance_call", "static bool resolve_shape_namespace_provenance_call");
assertIncludes("shape method provenance facts", shapeMethodProvenanceBody, "shape_method_bindings_from_recorded_type_args");
assertIncludes("shape method provenance facts", shapeMethodProvenanceBody, "build_shape_method_bindings");
assertIncludes("shape method provenance facts", shapeMethodProvenanceBody, "provenance_context_substitute_bindings");
assertIncludes("shape method provenance facts", shapeMethodProvenanceBody, "call_resolution_record_bindings");
assertIncludes("shape method provenance facts", shapeMethodProvenanceBody, "call_resolution_record_param_facts");
assertBefore("shape method provenance binding source order", shapeMethodProvenanceBody, "shape_method_bindings_from_recorded_type_args", "build_shape_method_bindings");
const shapeNamespaceProvenanceBody = sliceBetween(checker, "static bool resolve_shape_namespace_provenance_call", "static bool resolve_concrete_constrained_shape_provenance_call");
assertIncludes("shape namespace provenance resolver", shapeNamespaceProvenanceBody, "resolve_shape_namespace_call");
assertIncludes("shape namespace provenance resolver", shapeNamespaceProvenanceBody, "finish_shape_method_provenance_call");
const concreteConstrainedShapeProvenanceBody = sliceBetween(checker, "static bool resolve_concrete_constrained_shape_provenance_call", "static bool resolve_named_provenance_call");
assertIncludes("concrete constrained-shape provenance resolver", concreteConstrainedShapeProvenanceBody, "resolve_concrete_constrained_shape_call");
assertIncludes("concrete constrained-shape provenance resolver", concreteConstrainedShapeProvenanceBody, "finish_shape_method_provenance_call");
const namedProvenanceBody = sliceBetween(checker, "static bool resolve_named_provenance_call", "static bool resolve_constrained_interface_provenance_call");
assertIncludes("named provenance resolver", namedProvenanceBody, "resolve_named_function_call");
assertIncludes("named provenance resolver", namedProvenanceBody, "generic_call_bindings_from_checked_call");
assertIncludes("named provenance resolver", namedProvenanceBody, "provenance_context_substitute_bindings");
assertIncludes("named provenance resolver", namedProvenanceBody, "call_resolution_record_bindings");
assertIncludes("named provenance resolver", namedProvenanceBody, "call_resolution_record_param_facts");
const checkedCallTypeArgsBody = sliceBetween(checker, "static const TypeArgVec *checked_call_type_args", "static bool generic_bindings_from_type_args");
assertIncludes("checked call type args", checkedCallTypeArgsBody, "checked_type_args");
const checkedCallBindingsBody = sliceBetween(
checker,
"static bool checked_call_bindings_from_recorded_type_args(CheckContext *ctx, const Program *program, const Function *callee, const Expr *call, GenericBinding **out_bindings, size_t *out_len, bool *out_recorded) {",
"static bool generic_call_bindings_from_checked_call"
);
assertIncludes("checked call bindings", checkedCallBindingsBody, "checked_call_type_args");
assertIncludes("checked call bindings", checkedCallBindingsBody, "generic_bindings_from_type_args");
const genericCallBindingsBody = sliceBetween(
checker,
"static bool generic_call_bindings_from_checked_call(CheckContext *ctx, const Program *program, const Function *callee, const Expr *call, Scope *scope, const char *return_type, GenericBinding **out_bindings, size_t *out_len) {",
"static char *call_param_type_text"
);
assertIncludes("generic call bindings", genericCallBindingsBody, "checked_call_bindings_from_recorded_type_args");
assertIncludes("generic call bindings", genericCallBindingsBody, "call_type_args(call)");
assertBefore("generic call binding source order", genericCallBindingsBody, "checked_call_bindings_from_recorded_type_args", "call_type_args(call)");
const constrainedInterfaceProvenanceBody = sliceBetween(checker, "static bool resolve_constrained_interface_provenance_call", "static bool resolve_receiver_shape_provenance_call");
assertIncludes("constrained interface provenance resolver", constrainedInterfaceProvenanceBody, "resolve_constrained_interface_call");
assertIncludes("constrained interface provenance resolver", constrainedInterfaceProvenanceBody, "interface_method_bindings_from_recorded_type_args");
assertIncludes("constrained interface provenance resolver", constrainedInterfaceProvenanceBody, "build_constrained_interface_method_bindings");
assertIncludes("constrained interface provenance resolver", constrainedInterfaceProvenanceBody, "call_resolution_record_bindings");
assertIncludes("constrained interface provenance resolver", constrainedInterfaceProvenanceBody, "call_resolution_record_param_facts");
assertBefore("constrained interface provenance binding source order", constrainedInterfaceProvenanceBody, "interface_method_bindings_from_recorded_type_args", "build_constrained_interface_method_bindings");
const receiverProvenanceBody = sliceBetween(checker, "static bool resolve_receiver_shape_provenance_call", "static bool resolve_provenance_call");
assertIncludes("receiver provenance resolver", receiverProvenanceBody, "resolve_receiver_shape_call");
assertIncludes("receiver provenance resolver", receiverProvenanceBody, "shape_method_bindings_from_recorded_type_args");
assertIncludes("receiver provenance resolver", receiverProvenanceBody, "build_receiver_shape_method_bindings");
assertIncludes("receiver provenance resolver", receiverProvenanceBody, "call_resolution_record_bindings");
assertIncludes("receiver provenance resolver", receiverProvenanceBody, "call_resolution_record_param_facts");
assertBefore("receiver provenance binding source order", receiverProvenanceBody, "shape_method_bindings_from_recorded_type_args", "build_receiver_shape_method_bindings");
const provenanceCallBody = sliceBetween(checker, "static bool resolve_provenance_call", "static bool function_return_value_provenance");
assertIncludes("provenance call dispatcher", provenanceCallBody, "resolve_named_provenance_call");
assertIncludes("provenance call dispatcher", provenanceCallBody, "resolve_shape_namespace_provenance_call");
assertIncludes("provenance call dispatcher", provenanceCallBody, "resolve_concrete_constrained_shape_provenance_call");
assertIncludes("provenance call dispatcher", provenanceCallBody, "resolve_constrained_interface_provenance_call");
assertIncludes("provenance call dispatcher", provenanceCallBody, "resolve_receiver_shape_provenance_call");
assertBefore("provenance call resolver order", provenanceCallBody, "resolve_concrete_constrained_shape_provenance_call", "resolve_constrained_interface_provenance_call");
const callResolutionFactsResolverBody = sliceBetween(checker, "static bool call_facts_resolve_call", "static void call_facts_collect_expr");
assertIncludes("call-resolution graph facts", callResolutionFactsResolverBody, "resolve_stdlib_call");
assertIncludes("call-resolution graph facts", callResolutionFactsResolverBody, "resolve_choice_constructor_call");
assertIncludes("call-resolution graph facts", callResolutionFactsResolverBody, "resolve_provenance_call");
assertIncludes("call-resolution graph facts", callResolutionFactsResolverBody, "ResolvedProvenanceCall");
const callResolutionFactsJsonBody = sliceBetween(checker, "void z_append_call_resolution_facts_json", "static bool function_return_value_provenance");
assertIncludes("call-resolution graph facts", callResolutionFactsJsonBody, "Z_CALL_FUNCTION");
assertIncludes("call-resolution graph facts", callResolutionFactsJsonBody, "Z_CALL_CHOICE_CONSTRUCTOR");
assertIncludes("call-resolution graph facts", callResolutionFactsJsonBody, "call_facts_collect_function");
assertIncludes("call-resolution graph fixture", conformance, "conformance/check/pass/call-resolution-inspection.0");
assertIncludes("call-resolution graph fixture", conformance, "callResolution");
const exprCallResolverBody = sliceBetween(checker, "static bool resolve_expr_call_for_type", "static const char *expr_call_return_type");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_named_function_call");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_shape_namespace_call");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_concrete_constrained_shape_call");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_constrained_interface_call");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_receiver_shape_call");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_choice_constructor_call");
assertIncludes("expr call return resolver", exprCallResolverBody, "resolve_stdlib_call");
const exprCallReturnBody = sliceBetween(checker, "static const char *expr_call_return_type", "static const char *expr_type");
assertIncludes("expr call return facts", exprCallReturnBody, "resolve_expr_call_for_type");
assertIncludes("expr call return facts", exprCallReturnBody, "resolution.return_type");
assertIncludes("expr call return facts", exprCallReturnBody, "Z_CALL_FUNCTION");
assertIncludes("expr call return facts", exprCallReturnBody, "Z_CALL_SHAPE_NAMESPACE");
assertIncludes("expr call return facts", exprCallReturnBody, "Z_CALL_CONSTRAINED_INTERFACE");
assertIncludes("expr call return facts", exprCallReturnBody, "Z_CALL_RECEIVER");
assertIncludes("expr call return facts", exprCallReturnBody, "generic_call_bindings_from_checked_call");
assertIncludes("expr call return facts", exprCallReturnBody, "shape_method_bindings_from_recorded_type_args");
assertIncludes("expr call return facts", exprCallReturnBody, "interface_method_bindings_from_recorded_type_args");
assertNotIncludes("expr call return facts", exprCallReturnBody, "build_generic_bindings");
assertBefore("expr call return shape binding source order", exprCallReturnBody, "shape_method_bindings_from_recorded_type_args", "build_shape_method_bindings");
assertBefore("expr call return interface binding source order", exprCallReturnBody, "interface_method_bindings_from_recorded_type_args", "build_constrained_interface_method_bindings");
assertBefore("expr call return receiver binding source order", exprCallReturnBody, "shape_method_bindings_from_recorded_type_args", "build_receiver_shape_method_bindings");
const exprTypeCallBody = sliceBetween(
checker,
"static const char *expr_type(CheckContext *ctx, const Program *program, const Expr *expr, Scope *scope) {",
"case EXPR_INDEX:"
);
assertIncludes("expr_type call return dispatch", exprTypeCallBody, "expr_call_return_type");
assertNotIncludes("expr_type call return dispatch", exprTypeCallBody, "resolve_named_function_call");
assertNotIncludes("expr_type call return dispatch", exprTypeCallBody, "resolve_shape_namespace_call");
assertNotIncludes("expr_type call return dispatch", exprTypeCallBody, "resolve_stdlib_call");
const namedCallBody = sliceBetween(checker, "static bool build_named_call_bindings_expected", "static bool check_stdlib_table_arg_range_expected");
assertIncludes("named call checking argument facts", namedCallBody, "resolve_named_function_call");
assertIncludes("named call checking argument facts", namedCallBody, "build_named_call_bindings_expected");
assertIncludes("named call checking argument facts", namedCallBody, "check_named_call_args_expected");
assertIncludes("named call checking argument facts", namedCallBody, "check_call_resolution_args_expected");
assertIncludes("named call checking argument facts", namedCallBody, "check_named_call_fallibility_expected");
assertIncludes("named call checking argument facts", namedCallBody, "prepare_named_call_return_and_storage_expected");
assertIncludes("named call checking argument facts", namedCallBody, "finish_named_call_return_expected");
assertIncludes("named call checking argument facts", namedCallBody, "z_call_resolution_expected_arg_count");
assertIncludes("named call checking argument facts", namedCallBody, "call_resolution_record_param_facts");
assertIncludes("named call checking argument facts", namedCallBody, "call_resolution_param_type_text");
assertIncludes("named call checking storage effects", namedCallBody, "apply_checked_call_storage_effects");
const stdlibTableCallBody = sliceBetween(checker, "static bool check_stdlib_table_arg_range_expected", "static bool check_stdlib_allocator_arg");
assertIncludes("stdlib table call checking argument facts", stdlibTableCallBody, "z_call_resolution_add_arg");
assertIncludes("stdlib table call checking argument facts", stdlibTableCallBody, "call_resolution_param_type_text");
assertIncludes("stdlib table call checking argument facts", stdlibTableCallBody, "z_call_resolution_param_type");
assertNotIncludes("stdlib table call checking argument facts", stdlibTableCallBody, "std_call_arg_type");
const stdlibTableDispatchBody = sliceBetween(checker, "static bool check_stdlib_table_call_expected", "static bool check_stdlib_known_call_expected");
assertIncludes("stdlib table call checking argument facts", stdlibTableDispatchBody, "check_stdlib_table_arg_range_expected");
const stdlibKnownCallBody = sliceBetween(checker, "static bool check_stdlib_known_call_expected", "static bool check_stdlib_call_expected");
assertIncludes("stdlib known call checking argument facts", stdlibKnownCallBody, "ZCallResolution *resolution");
assertIncludes("stdlib known call helper classification", stdlibKnownCallBody, "z_std_helper_kind");
assertIncludes("stdlib known call helper classification", stdlibKnownCallBody, "switch (kind)");
assertIncludes("stdlib known call checking argument facts", stdlibKnownCallBody, "check_stdlib_mem_get_call_expected");
assertIncludes("stdlib known call checking argument facts", stdlibKnownCallBody, "check_stdlib_table_call_expected");
assertNotIncludes("stdlib known call helper classification", stdlibKnownCallBody, "strcmp(");
const choiceCallBody = sliceBetween(checker, "static bool check_choice_constructor_call_expected", "static bool check_shape_namespace_call_expected");
assertIncludes("choice call checking argument facts", choiceCallBody, "resolve_choice_constructor_call");
assertIncludes("choice call checking argument facts", choiceCallBody, "z_call_resolution_add_arg(&choice_resolution");
assertIncludes("choice call checking argument facts", choiceCallBody, "call_resolution_param_type_text(&choice_resolution");
assertIncludes("choice call checking argument facts", choiceCallBody, "z_call_resolution_expected_arg_count");
assertBefore("choice call resolution order", choiceCallBody, "resolve_choice_constructor_call", "find_choice(program");
const shapeNamespaceCallBody = sliceBetween(checker, "static bool check_shape_namespace_call_expected", "static bool receiver_member_call_should_resolve");
assertIncludes("shape namespace call checking argument facts", shapeNamespaceCallBody, "call_resolution_record_param_facts");
assertIncludes("shape namespace call checking argument facts", shapeNamespaceCallBody, "check_call_resolution_args_expected");
assertIncludes("shape namespace call checking argument facts", shapeNamespaceCallBody, "z_call_resolution_expected_arg_count");
assertIncludes("shape namespace call checking argument facts", shapeNamespaceCallBody, "set_expr_checked_type_args");
assertIncludes("shape namespace call checking storage effects", shapeNamespaceCallBody, "apply_checked_call_storage_effects");
const receiverCallBody = sliceBetween(checker, "static bool check_receiver_method_receiver_access", "static bool check_constrained_interface_call_expected");
assertIncludes("receiver call checking argument facts", receiverCallBody, "resolve_receiver_shape_call");
assertIncludes("receiver call checking argument facts", receiverCallBody, "call_resolution_record_param_facts");
assertIncludes("receiver call checking argument facts", receiverCallBody, "check_call_resolution_args_expected");
assertIncludes("receiver call checking argument facts", receiverCallBody, "z_call_resolution_expected_arg_count");
assertIncludes("receiver call checking argument facts", receiverCallBody, "set_expr_checked_type_args");
assertIncludes("receiver call checking storage effects", receiverCallBody, "apply_checked_call_storage_effects");
const constrainedInterfaceCallBody = sliceBetween(checker, "static bool check_constrained_interface_call_expected", "static bool check_world_stream_write_call_expected");
assertIncludes("constrained interface call checking argument facts", constrainedInterfaceCallBody, "call_resolution_record_param_facts");
assertIncludes("constrained interface call checking argument facts", constrainedInterfaceCallBody, "check_call_resolution_args_expected");
assertIncludes("constrained interface call checking argument facts", constrainedInterfaceCallBody, "z_call_resolution_expected_arg_count");
assertIncludes("constrained interface call checking argument facts", constrainedInterfaceCallBody, "set_expr_checked_type_args");
assertIncludes("constrained interface call checking storage effects", constrainedInterfaceCallBody, "apply_checked_call_storage_effects");
const callExprBody = sliceBetween(checker, "static bool check_call_expr_expected", "static bool check_expr_expected");
assertIncludes("call expression checking dispatch", callExprBody, "check_choice_constructor_call_expected");
assertIncludes("call expression checking dispatch", callExprBody, "check_shape_namespace_call_expected");
assertIncludes("call expression checking dispatch", callExprBody, "check_receiver_shape_call_expected");
assertIncludes("call expression checking dispatch", callExprBody, "check_constrained_interface_call_expected");
assertIncludes("call expression checking dispatch", callExprBody, "check_named_function_call_expected");
assertIncludes("call expression checking dispatch", callExprBody, "check_stdlib_call_expected");
assertBefore("stdlib call resolution before fallback argument checks", callExprBody, "check_stdlib_call_expected", "for (size_t i = 0; i < expr->args.len; i++)");
const stdlibCallBody = sliceBetween(checker, "static bool check_stdlib_call_expected", "static bool check_choice_constructor_call_expected");
assertIncludes("stdlib call checking dispatch", stdlibCallBody, "resolve_stdlib_call");
assertIncludes("stdlib call checking dispatch", stdlibCallBody, "check_stdlib_known_call_expected");
assertIncludes("stdlib call checking fallibility", stdlibCallBody, "check_stdlib_call_fallibility_expected");
assertIncludes("stdlib call checking dispatch", stdlibCallBody, "z_call_resolution_free");
assertIncludes("stdlib call checking dispatch", stdlibCallBody, "z_call_resolution_expected_arg_count");
assertNotIncludes("stdlib call checking dispatch", stdlibCallBody, "std_call_arg_count");
const stdlibResolverBody = sliceBetween(checker, "static bool resolve_stdlib_callee", "static bool resolve_choice_constructor_call");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "z_std_helper_find");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "z_call_resolution_set_return_type(out, helper->return_type)");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "helper->arg_types");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "z_call_resolution_add_arg");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "z_std_helper_error_name");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "z_call_resolution_add_error");
assertIncludes("stdlib call resolver facts", stdlibResolverBody, "resolve_stdlib_fallible_call");
assertNotIncludes("stdlib call resolver facts", stdlibResolverBody, "std_call_arg_count");
const callFunctionContextBody = sliceBetween(checker, "static const Function *resolve_call_function_in_context", "static bool expr_call_has_error_flow");
assertIncludes("fallible call function context resolver", callFunctionContextBody, "resolve_named_function_call");
assertIncludes("fallible call function context resolver", callFunctionContextBody, "resolve_shape_namespace_call");
assertIncludes("fallible call function context resolver", callFunctionContextBody, "resolve_concrete_constrained_shape_call");
assertIncludes("fallible call function context resolver", callFunctionContextBody, "resolve_constrained_interface_call");
assertIncludes("fallible call function context resolver", callFunctionContextBody, "resolve_receiver_shape_call");
assertNotIncludes("fallible call function context resolver", callFunctionContextBody, "find_shape_method_decl");
const memberCallSkipBody = sliceBetween(checker, "static bool member_call_skips_callee_expr_check", "static bool check_call_callee");
assertIncludes("member callee precheck", memberCallSkipBody, "member_root_ident_is");
assertNotIncludes("member callee precheck", memberCallSkipBody, "member_name_buf");
const functionErrorFlowBody = sliceBetween(
checker,
"static bool function_has_error_flow_inner(CheckContext *ctx, const Program *program, const Function *fun, size_t depth) {",
"static bool function_has_error_flow(CheckContext"
);
assertIncludes("fallible function body context", functionErrorFlowBody, "find_shape_owning_method");
assertIncludes("fallible function body context", functionErrorFlowBody, "fun_ctx.shape");
const uncheckedFallibleCallBody = sliceBetween(checker, "static bool check_unchecked_fallible_call_expected", "static bool check_call_expr_expected");
assertIncludes("unchecked fallible call resolver", uncheckedFallibleCallBody, "fallible_callee_in_context");
assertNotIncludes("unchecked fallible call resolver", uncheckedFallibleCallBody, "resolve_stdlib_fallible_call");
assertNotIncludes("unchecked fallible call resolver", uncheckedFallibleCallBody, "fallible_callee(ctx");
const callCalleeBody = sliceBetween(checker, "static bool check_call_callee", "static bool build_named_call_bindings_expected");
assertIncludes("call callee precheck", callCalleeBody, "member_call_skips_callee_expr_check");
assertNotIncludes("call callee precheck", callCalleeBody, "resolve_shape_namespace_call");
assertNotIncludes("call callee precheck", callCalleeBody, "resolve_constrained_interface_call");
assertNotIncludes("call callee precheck", callCalleeBody, "resolve_stdlib_call");
const receiverShouldResolveBody = sliceBetween(checker, "static bool receiver_member_call_should_resolve", "static bool check_receiver_method_receiver_access");
assertIncludes("receiver resolution gate", receiverShouldResolveBody, "member_root_ident_is");
assertIncludes("receiver resolution gate", receiverShouldResolveBody, "resolve_stdlib_call");
assertNotIncludes("receiver resolution gate", receiverShouldResolveBody, "member_name_buf");
const checkCallBody = sliceBetween(
checker,
"static bool check_expr_expected(CheckContext *ctx, const Program *program, const Expr *expr, Scope *scope, ZDiag *diag, const char *expected) {",
"case EXPR_CAST:"
);
assertIncludes("call checking dispatch", checkCallBody, "check_call_expr_expected");
const checkedCallBody = sliceBetween(checker, "static bool apply_checked_call_storage_effects", "static bool apply_resolved_call_storage_effects");
assertIncludes("checked call storage effects", checkedCallBody, "resolve_provenance_call");
assertIncludes("checked call storage effects", checkedCallBody, "apply_provenance_call_storage_effects");
const stdMemGetProvenanceBody = sliceBetween(checker, "static bool std_mem_get_value_provenance", "static bool value_provenance_add_actual_place");
assertIncludes("std.mem.get provenance resolver", stdMemGetProvenanceBody, "resolve_stdlib_call");
assertIncludes("std.mem.get provenance resolver", stdMemGetProvenanceBody, "z_std_helper_kind");
assertIncludes("std.mem.get provenance resolver", stdMemGetProvenanceBody, "z_call_resolution_add_arg");
assertNotIncludes("std.mem.get provenance resolver", stdMemGetProvenanceBody, "member_name_buf");
assertNotIncludes("std.mem.get provenance resolver", stdMemGetProvenanceBody, "strcmp(");
const summaryBody = sliceBetween(checker, "static bool function_provenance_summary", "static bool function_return_value_provenance");
assertIncludes("function provenance summary", summaryBody, "collect_return_value_provenance_from_stmt_vec");
assertIncludes("function provenance summary", summaryBody, "body_complete");
assertIncludes("function provenance summary", summaryBody, "seed_param_storage_value_provenance");
assertIncludes("function provenance summary", summaryBody, "provenance_storage_effect_vec_add");
assertIncludes("function provenance summary", summaryBody, "return summary->return_complete && summary->effect_complete");
assertIncludes("choice type provenance", checker, "const Choice *choice = find_choice(program, type)");
assertIncludes("choice constructor provenance", checker, "choice_constructor_value_provenance(ctx, program, expr, scope, origins)");
const choiceConstructorBody = sliceBetween(checker, "static bool choice_constructor_value_provenance", "static void register_match_payload_binding_provenance");
assertIncludes("choice constructor provenance", choiceConstructorBody, "resolve_choice_constructor_call");
assertIncludes("choice constructor provenance", choiceConstructorBody, "z_call_resolution_add_arg");
assertIncludes("choice match payload provenance", checker, "register_match_payload_binding_provenance(ctx, program, stmt->expr, scope, &arm_scope, arm->payload_name, arm->case_name)");
const storageSummaryBody = sliceBetween(checker, "static bool function_storage_effect_summary", "static bool apply_provenance_storage_effect");
assertIncludes("storage-effect summary", storageSummaryBody, "function_provenance_summary");
const returnSummaryBody = sliceBetween(checker, "static bool function_return_value_provenance", "static const Expr *call_actual_for_param");
assertIncludes("return summary", returnSummaryBody, "function_provenance_summary");
const expressionEffectBody = sliceBetween(checker, "static bool apply_expr_call_storage_effects", "static bool check_assignment_not_borrowed");
assertIncludes("expression storage effects", expressionEffectBody, "if (expr->kind == EXPR_CALL) return apply_resolved_call_storage_effects");
assertIncludes("expression storage effects", expressionEffectBody, "provenance_scope_snapshot_restore_optional_branch");
assertIncludes("array literal provenance", checker, "value_provenance_add_all_with_prefix(origins, &item_origins, element_path)");
assertIncludes("assignment path clearing", checker, "origin_path_is_definitely_within(entry->value_path, path)");
const checkExprExpectedBody = sliceBetween(
checker,
"static bool check_expr_expected(CheckContext *ctx, const Program *program, const Expr *expr, Scope *scope, ZDiag *diag, const char *expected) {",
"static bool check_expr(CheckContext *ctx, const Program *program, const Expr *expr, Scope *scope, ZDiag *diag) {"
);
const callCase = sliceBetween(checkExprExpectedBody, "case EXPR_CALL:", "case EXPR_CAST:");
assertIncludes("call checking dispatcher", callCase, "check_call_expr_expected");
const callCaseStorageApplications = (callCase.match(/apply_checked_call_storage_effects\(ctx, program, expr, scope, diag\)/g) ?? []).length;
const namedCallStorageApplications = (namedCallBody.match(/apply_checked_call_storage_effects\(ctx, program, expr, scope, diag\)/g) ?? []).length;
const shapeNamespaceCallStorageApplications = (shapeNamespaceCallBody.match(/apply_checked_call_storage_effects\(ctx, program, expr, scope, diag\)/g) ?? []).length;
const receiverCallStorageApplications = (receiverCallBody.match(/apply_checked_call_storage_effects\(ctx, program, expr, scope, diag\)/g) ?? []).length;
const constrainedInterfaceCallStorageApplications = (constrainedInterfaceCallBody.match(/apply_checked_call_storage_effects\(ctx, program, expr, scope, diag\)/g) ?? []).length;
const totalCallStorageApplications =
callCaseStorageApplications +
namedCallStorageApplications +
shapeNamespaceCallStorageApplications +
receiverCallStorageApplications +
constrainedInterfaceCallStorageApplications;
if (totalCallStorageApplications < 4) {
fail(`EXPR_CALL provenance: expected storage-effect application for all user call forms, found ${totalCallStorageApplications}`);
}
const lines = checker.split("\n");
const currentFunction = currentFunctionByLine(checker);
const mutationAllowlist = new Map([
["scope_set_value_provenance(", new Set(["scope_set_value_provenance", "register_borrow_binding", "seed_param_storage_value_provenance", "register_match_payload_binding_provenance"])],
["scope_set_value_provenance_path_in_scope(", new Set(["scope_set_value_provenance_path_in_scope", "update_borrow_assignment", "assignment_provenance_snapshot_clear", "assignment_provenance_snapshot_restore", "apply_provenance_storage_effect", "stdlib_install_item_write_provenance"])],
["scope_borrow_counts_for_place(", new Set(["scope_borrow_counts_for_place", "check_borrow_conflict_at", "check_read_not_mutably_borrowed", "check_assignment_not_borrowed"])],
]);
for (let index = 0; index < lines.length; index++) {
const line = lines[index];
if (line.trimStart().startsWith("static ")) continue;
for (const [needle, allowed] of mutationAllowlist) {
if (!line.includes(needle)) continue;
const owner = currentFunction[index];
if (!allowed.has(owner)) {
fail(`checker provenance bypass: '${needle}' at ${checkerPath}:${index + 1} is in '${owner}', not ${[...allowed].join(", ")}`);
}
}
}
assertMatches(
"callee-local storage rejection",
checker,
/cannot store a reference to a callee-local binding through a mutable parameter/
);
assertMatches(
"incomplete mutref summary rejection",
checker,
/cannot verify provenance effects for mutable parameter call/
);
assertMatches(
"shorter-lived storage rejection",
checker,
/cannot assign a reference to a shorter-lived binding/
);
if (failures.length > 0) {
console.error("provenance guardrails failed:");
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}
console.log(`provenance guardrails ok (${rows.length} surfaces)`);
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const outDir = join("/tmp", `zero-reliability-smoke-${process.pid}`);
const zero = "bin/zero";
const rows = [];
await mkdir(outDir, { recursive: true });
async function run(args, { allowFailure = false } = {}) {
try {
const result = await execFileAsync(zero, args);
return { code: 0, stdout: result.stdout, stderr: result.stderr };
} catch (error) {
if (!allowFailure) throw error;
return {
code: error.code ?? error.status ?? 1,
stdout: error.stdout?.toString() ?? "",
stderr: error.stderr?.toString() ?? "",
};
}
}
async function json(args, options = {}) {
const result = await run(args, options);
return { ...result, body: JSON.parse(result.stdout) };
}
function record(id, kind, ok, facts = {}) {
rows.push({ id, kind, ok, ...facts });
assert.equal(ok, true, `${id} failed`);
}
const packageTests = await json(["test", "--json", "conformance/packages/test-app"]);
record("package-test-golden", "golden", packageTests.body.ok === true && packageTests.body.stdout === "3 test(s) ok\n", {
selectedTests: packageTests.body.selectedTests,
expectedFailures: packageTests.body.expectedFailures,
snapshotKey: packageTests.body.fixtures?.snapshotKey,
});
const filteredTests = await json(["test", "--json", "--filter", "helper", "conformance/packages/test-app"]);
record("package-test-filter", "golden", filteredTests.body.selectedTests === 2 && filteredTests.body.discoveredTests === 3, {
stdout: filteredTests.body.stdout,
});
const expectedFail = await json(["test", "--json", "conformance/native/pass/test-expected-fail.graph"]);
record("expected-fail-contract", "golden", expectedFail.body.expectedFailures === 1 && expectedFail.body.failedTests === 0, {
status: expectedFail.body.results?.[0]?.status,
});
const validFuzz = join(outDir, "valid-fuzz.0");
await writeFile(validFuzz, `fn add(a: i32, b: i32) -> i32 {
return a + b
}
test "fuzz valid arithmetic" {
expect (add(21, 21) == 42)
}
`);
const validTokens = await json(["tokens", "--json", validFuzz]);
const validParse = await json(["parse", "--json", validFuzz]);
const validGraph = join(outDir, "valid-fuzz.graph");
await json(["import", "--json", "--format", "binary", "--out", validGraph, validFuzz]);
const validCheck = await json(["check", "--json", validGraph]);
record("parser-checker-fuzz-valid", "fuzz", validTokens.body.tokens.length > 0 && validParse.body.root.kind === "module" && validCheck.body.ok === true, {
tokenCount: validTokens.body.tokens.length,
});
const invalidFuzz = join(outDir, "invalid-fuzz.0");
await writeFile(invalidFuzz, "pub fn main(world: World -> Void {\n");
const invalidGraph = join(outDir, "invalid-fuzz.graph");
const invalidImport = await json(["import", "--json", "--format", "binary", "--out", invalidGraph, invalidFuzz], { allowFailure: true });
record("parser-checker-fuzz-invalid", "fuzz", invalidImport.code !== 0 && invalidImport.body.diagnostics?.length > 0, {
diagnostic: invalidImport.body.diagnostics?.[0]?.code,
});
const fmtFixture = await run(["fmt", "conformance/native/pass/test-blocks.0"]);
const fmtExpected = await readFile("conformance/native/pass/test-blocks.0", "utf8");
record("formatter-snapshot", "snapshot", fmtFixture.stdout === fmtExpected, {
bytes: fmtFixture.stdout.length,
});
const stdlibJson = await json(["size", "--json", "conformance/native/pass/std-codec-json-url.graph"]);
record("stdlib-parser-golden", "golden", stdlibJson.body.usedStdlibHelpers?.some((helper) => helper.name === "std.json.field") && stdlibJson.body.compilerCaches?.some((cache) => cache.sourceKind === "program-graph"), {
helperCount: stdlibJson.body.usedStdlibHelpers?.length ?? 0,
});
const stdlibEdgesGraph = "conformance/native/pass/std-codec-json-url.graph";
const stdlibEdgesRun = await run(["run", stdlibEdgesGraph]);
record("stdlib-codec-json-http-edges", "golden", stdlibEdgesRun.code === 0 && stdlibEdgesRun.stdout === "std codec json url ok\n", {
fixture: stdlibEdgesGraph,
});
const crasher = join(outDir, "crasher-repro-unclosed-string.0");
await writeFile(crasher, "pub fn main() -> Void {\n let value: String = \"unterminated\n}\n");
const crasherGraph = join(outDir, "crasher-repro-unclosed-string.graph");
const crasherImport = await json(["import", "--json", "--format", "binary", "--out", crasherGraph, crasher], { allowFailure: true });
record("minimized-crasher-repro", "crasher", crasherImport.code !== 0 && crasherImport.body.diagnostics?.length > 0, {
diagnostic: crasherImport.body.diagnostics?.[0]?.code,
});
const report = {
schemaVersion: 1,
ok: rows.every((row) => row.ok),
rows,
conventions: {
fuzzCorpus: [validGraph, invalidFuzz, "conformance/format/functions-blocks.0", "examples/std-data-formats.graph"],
goldenOutputs: ["zero test --json conformance/packages/test-app", "zero fmt conformance/native/pass/test-blocks.0"],
crasherRepros: [crasher],
sanitizerGate: "pnpm run native:sanitize",
},
};
await writeFile(join(outDir, "report.json"), `${JSON.stringify(report, null, 2)}\n`);
console.log("reliability smoke ok");
@@ -0,0 +1,85 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { performance } from "node:perf_hooks";
import { resolve } from "node:path";
const root = "conformance/program-graph";
const storePath = `${root}/zero.graph`;
const target = "linux-musl-x64";
const zeroBin = resolve("bin/zero");
const execMaxBuffer = 16 * 1024 * 1024;
const budgets = {
statusMs: 2000,
verifyProjectionMs: 3000,
importMs: 5000,
exportMs: 5000,
};
function run(args: string[]) {
const start = performance.now();
const stdout = execFileSync(zeroBin, args, {
encoding: "utf8",
maxBuffer: execMaxBuffer,
stdio: ["ignore", "pipe", "pipe"],
});
return { stdout, elapsedMs: performance.now() - start };
}
function runJson(args: string[]) {
const result = run(args);
return { ...result, body: JSON.parse(result.stdout) };
}
function assertBudget(name: string, elapsedMs: number, maxMs: number) {
assert(
elapsedMs <= maxMs,
`${name} exceeded repository graph fixture budget: ${elapsedMs.toFixed(1)}ms > ${maxMs}ms`,
);
}
const sourceBefore = readFileSync(`${root}/hello.0`, "utf8");
const storeBefore = readFileSync(storePath);
const status = runJson(["status", "--json", "--target", target, root]);
assert.equal(status.body.ok, true);
assert.equal(status.body.repositoryGraph.storePresent, true);
assert.equal(status.body.repositoryGraph.storeValid, true);
assert.equal(status.body.repositoryGraph.projectionState, "clean");
assert.equal(status.body.repositoryGraph.compilerInput, "repository-graph");
assertBudget("status", status.elapsedMs, budgets.statusMs);
const check = runJson(["check", "--json", "--target", target, root]);
assert.equal(check.body.ok, true);
assert.equal(check.body.sourceFile, storePath);
assert.equal(check.body.graph.artifact, storePath);
assert.equal(check.body.graph.canonicalSource, false);
assert.equal(check.body.graph.moduleIdentity, "package:program-graph-fixture@0.1.0");
const verify = runJson(["verify-projection", "--json", "--target", target, root]);
assert.equal(verify.body.ok, true);
assert.equal(verify.body.writes, false);
assert.equal(verify.body.repositoryGraph.projectionState, "clean");
assertBudget("verify-projection", verify.elapsedMs, budgets.verifyProjectionMs);
const fromSource = runJson(["import", "--json", "--target", target, root]);
assert.equal(fromSource.body.ok, true);
assert.equal(fromSource.body.repositoryGraph.projectionState, "clean");
assert.deepEqual(fromSource.body.changedPaths, [storePath]);
assert.equal(readFileSync(`${root}/hello.0`, "utf8"), sourceBefore);
assert.equal(Buffer.compare(readFileSync(storePath), storeBefore), 0);
assertBudget("import", fromSource.elapsedMs, budgets.importMs);
const fromGraph = runJson(["export", "--json", "--target", target, root]);
assert.equal(fromGraph.body.ok, true);
assert.equal(fromGraph.body.repositoryGraph.projectionState, "clean");
assert.deepEqual(fromGraph.body.changedPaths, []);
assert.equal(readFileSync(`${root}/hello.0`, "utf8"), sourceBefore);
assert.equal(Buffer.compare(readFileSync(storePath), storeBefore), 0);
assertBudget("export", fromGraph.elapsedMs, budgets.exportMs);
console.log(
`repository graph fixture ok (status ${status.elapsedMs.toFixed(1)}ms, verify ${verify.elapsedMs.toFixed(1)}ms, import ${fromSource.elapsedMs.toFixed(1)}ms, export ${fromGraph.elapsedMs.toFixed(1)}ms)`,
);
+91
View File
@@ -0,0 +1,91 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFileSync } from "node:child_process";
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { join, resolve } from "node:path";
const root = join("/tmp", `zero-repository-graph-scale-${process.pid}`);
const source = join(root, "main.0");
const store = join(root, "zero.graph");
const zero = resolve("bin/zero");
const maxMs = Number(process.env.ZERO_REPOSITORY_GRAPH_SCALE_MAX_MS ?? "15000");
function json(args: string[], allowFailure = false) {
try {
const stdout = execFileSync(zero, args, { encoding: "utf8", maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "pipe"] });
return { code: 0, body: JSON.parse(stdout) };
} catch (error) {
if (!allowFailure) throw error;
return { code: error.status ?? 1, body: JSON.parse(error.stdout?.toString() ?? "{}") };
}
}
function elapsed<T>(fn: () => T) {
const started = Date.now();
const value = fn();
return { value, ms: Date.now() - started };
}
rmSync(root, { recursive: true, force: true });
mkdirSync(root, { recursive: true });
const functions: string[] = [];
for (let i = 0; i < 96; i++) {
functions.push(`fn value_${i}() -> i32 {\n return ${i}\n}\n`);
}
writeFileSync(
source,
`${functions.join("\n")}\npub fn main(world: World) -> Void raises {\n check world.out.write("repository graph scale ok\\n")\n}\n`,
);
const imported = elapsed(() => json(["import", "--format", "text", "--json", source]));
assert.equal(imported.value.code, 0);
assert.equal(imported.value.body.repositoryGraph.projectionState, "clean");
assert(imported.ms < maxMs, `repository graph import took ${imported.ms}ms`);
const status = elapsed(() => json(["status", "--json", source]));
assert.equal(status.value.body.repositoryGraph.storeValid, true);
assert.equal(status.value.body.storage.encoding, "single-file-text");
assert.equal(status.value.body.storage.interface, "ProgramGraphStore");
assert.equal(status.value.body.repositoryGraph.semanticValidity, "shape-valid");
assert.equal(status.value.body.repositoryGraph.projectionValidity, "clean");
assert.equal(status.value.body.compilerStore.shape, "compiler-oriented-tables");
assert.equal(status.value.body.compilerStore.sourceFreeInspection, true);
assert.equal(status.value.body.compilerStore.sourceProjectionRequiredForSemanticFacts, false);
assert.equal(status.value.body.compilerStore.tables.schema, 1);
assert.equal(status.value.body.compilerStore.tables.node, status.value.body.scale.nodes);
assert.equal(status.value.body.compilerStore.tables.edge, status.value.body.scale.edges);
assert.deepEqual(status.value.body.compilerStore.hashInputs.graphHashExcludes, ["sourcePath", "line", "column", "projectionText"]);
assert(status.value.body.scale.nodes >= 300, `expected a large graph, got ${status.value.body.scale.nodes} nodes`);
assert(status.value.body.scale.edges >= 200, `expected many graph edges, got ${status.value.body.scale.edges}`);
assert(status.ms < maxMs, `repository graph status took ${status.ms}ms`);
const verify = elapsed(() => json(["verify-projection", "--json", source]));
assert.equal(verify.value.code, 0);
assert.equal(verify.value.body.ok, true);
assert(verify.ms < maxMs, `repository graph verify-projection took ${verify.ms}ms`);
const originalStore = readFileSync(store, "utf8");
assert.match(originalStore, /^compilerStore schemaVersion:1 shape:"compiler-oriented-tables"/m);
assert.match(originalStore, /^compilerTables schema:1 package:/m);
assert.match(originalStore, /^compilerHashInputs graphHashExcludes:"source-path,line,column,projection-text"/m);
rmSync(source, { force: true });
const sourceFreeStatus = elapsed(() => json(["status", "--json", root]));
assert.equal(sourceFreeStatus.value.body.repositoryGraph.storeValid, true);
assert.equal(sourceFreeStatus.value.body.repositoryGraph.semanticValidity, "shape-valid");
assert.equal(sourceFreeStatus.value.body.repositoryGraph.projectionValidity, "missing");
assert.equal(sourceFreeStatus.value.body.compilerStore.sourceFreeInspection, true);
assert.equal(sourceFreeStatus.value.body.compilerStore.semanticValidity.ok, true);
assert.equal(sourceFreeStatus.value.body.compilerStore.projectionValidity.state, "missing");
assert.equal(sourceFreeStatus.value.body.compilerStore.tables.node, status.value.body.scale.nodes);
assert(sourceFreeStatus.ms < maxMs, `repository graph source-free status took ${sourceFreeStatus.ms}ms`);
writeFileSync(store, originalStore.replace("zero-repository-graph v1", "zero-repository-graph v2"));
const futureSchema = json(["status", "--json", root], true);
assert.notEqual(futureSchema.code, 0);
assert.equal(futureSchema.body.diagnostics[0].code, "RGP003");
assert.match(futureSchema.body.diagnostics[0].actual, /invalid repository graph store|valid zero.graph/);
writeFileSync(store, originalStore);
console.log(`repository graph scale ok (${status.value.body.scale.nodes} nodes, ${status.value.body.scale.edges} edges)`);
@@ -0,0 +1,143 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { execFileSync } from "node:child_process";
import { existsSync, lstatSync, readFileSync, readdirSync } from "node:fs";
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
const skippedDirs = new Set([
".git",
".next",
".turbo",
".zero",
"dist",
"node_modules",
"target",
"zig-cache",
"zig-out",
]);
function usage() {
console.error("usage: repository-graph-verify-projection [--root <path>] [--target <target>]");
}
let root = process.cwd();
let target = "";
for (let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i];
if (arg === "--root") {
const value = process.argv[++i];
if (!value) {
usage();
process.exit(2);
}
root = value;
} else if (arg === "--target") {
const value = process.argv[++i];
if (!value) {
usage();
process.exit(2);
}
target = value;
} else if (arg === "--help" || arg === "-h") {
usage();
process.exit(0);
} else {
usage();
process.exit(2);
}
}
const repoRoot = process.cwd();
const nativeZeroBin = resolve(repoRoot, ".zero/bin/zero");
const zeroBin = process.env.ZERO_BIN
? resolve(repoRoot, process.env.ZERO_BIN)
: existsSync(nativeZeroBin) ? nativeZeroBin : resolve(repoRoot, "bin/zero");
const absoluteRoot = resolve(root);
if (!existsSync(zeroBin)) {
console.error("repository graph verify-projection requires a built Zero compiler from the repository root");
process.exit(1);
}
if (!existsSync(absoluteRoot)) {
console.error(`repository graph verify-projection root does not exist: ${absoluteRoot}`);
process.exit(1);
}
function findStores(path: string, stores: string[]) {
const stat = lstatSync(path);
if (stat.isSymbolicLink()) return;
if (stat.isFile()) {
if (path.endsWith("/zero.graph") || path === "zero.graph") stores.push(path);
return;
}
if (!stat.isDirectory()) return;
for (const entry of readdirSync(path, { withFileTypes: true })) {
if (entry.isDirectory() && skippedDirs.has(entry.name)) continue;
const child = join(path, entry.name);
if (entry.isSymbolicLink()) continue;
if (entry.isFile() && entry.name === "zero.graph") stores.push(child);
else if (entry.isDirectory()) findStores(child, stores);
}
}
const stores: string[] = [];
findStores(absoluteRoot, stores);
stores.sort();
if (stores.length === 0) {
console.log("repository graph verify-projection ok (0 stores)");
process.exit(0);
}
let failures = 0;
for (const store of stores) {
const input = sourceInputForStore(store);
const display = relative(repoRoot, input) || ".";
console.log(`repository graph verify-projection: ${display}`);
const args = ["verify-projection"];
if (target) args.push("--target", target);
args.push(input);
try {
execFileSync(zeroBin, args, { stdio: "inherit" });
} catch {
failures++;
const targetArgs = target ? ` --target ${target}` : "";
console.error(`repository graph verify-projection failed: bin/zero verify-projection${targetArgs} ${display}`);
}
}
if (failures > 0) {
console.error(`repository graph verify-projection failed (${failures}/${stores.length} stores)`);
process.exit(1);
}
console.log(`repository graph verify-projection ok (${stores.length} ${stores.length === 1 ? "store" : "stores"})`);
function sourceInputForStore(store: string) {
const root = dirname(store);
if (existsSync(join(root, "zero.toml")) || existsSync(join(root, "zero.json"))) return root;
const text = readFileSync(store, "utf8");
const projections = text.matchAll(/^projection path:"((?:\\.|[^"])*)" text:/gm);
for (const projection of projections) {
const source = sourceInputForProjection(root, projection[1]);
if (source) return source;
}
return root;
}
function sourceInputForProjection(root: string, projection: string) {
let path = "";
try {
path = JSON.parse(`"${projection}"`);
} catch {
return "";
}
if (!path) return "";
const source = resolve(root, path);
const local = relative(root, source);
if (!local || local === ".." || local.startsWith(`..${sep}`) || isAbsolute(local)) return "";
if (dirname(source) !== root) return "";
return existsSync(source) ? source : "";
}
+182
View File
@@ -0,0 +1,182 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { spawnSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
type RosettaCase = {
id: string;
slug: string;
source: string;
expectedStdout: string;
expectedStderr: string;
};
type RosettaManifest = {
schemaVersion: number;
corpus: string;
taskCount: number;
target: string;
cases: RosettaCase[];
};
const manifestPath = "benchmarks/rosetta/manifest.json";
const hostTarget = process.platform === "darwin" && process.arch === "arm64" ? "darwin-arm64" : "linux-musl-x64";
const target = readFlag("--target") ?? process.env.ZERO_ROSETTA_TARGET ?? hostTarget;
const outDir = join(".zero/rosetta", target);
const runOutputs = canRunTarget(target);
function readFlag(name: string) {
const index = process.argv.indexOf(name);
if (index === -1) return null;
const value = process.argv[index + 1];
if (!value || value.startsWith("--")) fail(`${name} requires a value`);
return value;
}
function canRunTarget(targetName: string) {
return (targetName === "linux-musl-x64" && process.platform === "linux" && process.arch === "x64") ||
(targetName === "darwin-arm64" && process.platform === "darwin" && process.arch === "arm64") ||
(targetName === "darwin-x64" && process.platform === "darwin" && (process.arch === "x64" || spawnSync("arch", ["-x86_64", "/usr/bin/true"]).status === 0));
}
function expectedObjectEmissionPaths(targetName: string) {
if (targetName === "linux-musl-x64") return new Set(["direct-elf64-exe", "direct-elf64-object"]);
if (targetName === "darwin-arm64") return new Set(["direct-macho64-exe", "direct-macho64-object"]);
if (targetName === "darwin-x64") return new Set(["direct-macho-x64-exe", "direct-macho-x64-object"]);
fail(`unsupported Rosetta target: ${targetName}`);
}
function fail(message: string): never {
console.error(message);
process.exit(1);
}
function commandFailure(command: string, args: string[], result: ReturnType<typeof spawnSync>) {
let diagnostic = "";
if (typeof result.stdout === "string" && result.stdout.length > 0) {
try {
diagnostic = JSON.parse(result.stdout).diagnostics?.[0]?.message ?? result.stdout;
} catch {
diagnostic = result.stdout;
}
}
if (!diagnostic && typeof result.stderr === "string") diagnostic = result.stderr;
return {
command: [command, ...args].join(" "),
status: result.status,
signal: result.signal,
diagnostic: diagnostic.trim(),
error: result.error?.message,
};
}
function readManifest(): RosettaManifest {
if (!existsSync(manifestPath)) fail(`missing Rosetta manifest: ${manifestPath}`);
const manifest = JSON.parse(readFileSync(manifestPath, "utf8")) as RosettaManifest;
if (manifest.schemaVersion !== 1) fail(`unsupported Rosetta manifest schema: ${manifest.schemaVersion}`);
if (manifest.corpus !== "zero-rosetta") fail(`unexpected Rosetta corpus: ${manifest.corpus}`);
if (typeof manifest.target !== "string" || manifest.target.length === 0) fail("Rosetta manifest target must be a string");
if (!Array.isArray(manifest.cases)) fail("Rosetta manifest cases must be an array");
if (manifest.taskCount !== manifest.cases.length) fail(`Rosetta manifest taskCount ${manifest.taskCount} does not match ${manifest.cases.length} cases`);
return manifest;
}
function validateCases(cases: RosettaCase[]) {
const slugs = new Set<string>();
const ids = new Set<string>();
const bad = [];
for (const entry of cases) {
if (ids.has(entry.id)) bad.push(`${entry.id}: duplicate id`);
ids.add(entry.id);
if (slugs.has(entry.slug)) bad.push(`${entry.id}: duplicate slug ${entry.slug}`);
slugs.add(entry.slug);
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(entry.slug)) bad.push(`${entry.id}: slug is not param-case`);
if (entry.source !== `benchmarks/rosetta/${entry.slug}.0`) bad.push(`${entry.id}: source must be benchmarks/rosetta/${entry.slug}.0`);
if (dirname(entry.source) !== "benchmarks/rosetta") bad.push(`${entry.id}: source must be a flat .0 file`);
if (!existsSync(entry.source)) bad.push(`${entry.id}: missing source ${entry.source}`);
if (!existsSync(graphInputForSource(entry.source))) bad.push(`${entry.id}: missing graph sidecar ${graphInputForSource(entry.source)}`);
if (typeof entry.expectedStdout !== "string") bad.push(`${entry.id}: expectedStdout must be a string`);
if (typeof entry.expectedStderr !== "string") bad.push(`${entry.id}: expectedStderr must be a string`);
}
if (bad.length > 0) fail(`Rosetta manifest validation failed:\n${bad.slice(0, 40).join("\n")}`);
}
function graphInputForSource(source: string) {
return source.endsWith(".0") ? `${source.slice(0, -2)}.graph` : source;
}
function buildCase(entry: RosettaCase) {
const out = join(outDir, entry.slug);
const input = graphInputForSource(entry.source);
const args = ["build", "--json", "--emit", "exe", "--target", target, input, "--out", out];
const result = spawnSync("bin/zero", args, { encoding: "utf8", maxBuffer: 20_000_000 });
if (result.status !== 0) return { ok: false, out, failure: commandFailure("bin/zero", args, result) };
const body = JSON.parse(result.stdout);
if (body.generatedCBytes !== 0) {
return { ok: false, out, failure: { diagnostic: `expected generatedCBytes=0, got ${body.generatedCBytes}` } };
}
const emissionPath = body.objectBackend?.objectEmission?.path ?? "<missing>";
const expectedPaths = expectedObjectEmissionPaths(target);
if (!expectedPaths.has(emissionPath)) {
return { ok: false, out, failure: { diagnostic: `expected one of ${[...expectedPaths].join(", ")}, got ${emissionPath}` } };
}
return { ok: true, out };
}
function runCase(entry: RosettaCase, out: string) {
const result = spawnSync(out, [], { encoding: "utf8", timeout: 5000, maxBuffer: 10_000_000 });
const ok = result.status === 0 &&
result.signal === null &&
result.stdout === entry.expectedStdout &&
result.stderr === entry.expectedStderr;
if (ok) return null;
return {
id: entry.id,
slug: entry.slug,
status: result.status,
signal: result.signal,
stdout: result.stdout,
stderr: result.stderr,
expectedStdout: entry.expectedStdout,
expectedStderr: entry.expectedStderr,
error: result.error?.message,
};
}
const manifest = readManifest();
validateCases(manifest.cases);
mkdirSync(outDir, { recursive: true });
const buildFailures = [];
const runFailures = [];
let built = 0;
let passed = 0;
for (const entry of manifest.cases) {
const build = buildCase(entry);
if (!build.ok) {
buildFailures.push({ id: entry.id, slug: entry.slug, source: entry.source, ...build.failure });
continue;
}
built++;
if (!runOutputs) continue;
const runFailure = runCase(entry, build.out);
if (runFailure) runFailures.push(runFailure);
else passed++;
}
const summary = {
schemaVersion: 1,
corpus: manifest.corpus,
target,
total: manifest.cases.length,
built,
buildFailures: buildFailures.length,
runChecked: runOutputs,
passed,
runFailures: runFailures.length,
failures: [...buildFailures, ...runFailures].slice(0, 20),
};
console.log(JSON.stringify(summary, null, 2));
if (buildFailures.length > 0 || runFailures.length > 0) process.exit(1);
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env node
import { spawnSync } from "node:child_process";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const node = process.execPath;
run(node, [
resolve(repoRoot, "evals", "node_modules", "typescript", "bin", "tsc"),
"-p",
resolve(repoRoot, "evals", "tsconfig.json"),
]);
run(node, [
resolve(repoRoot, "evals", "dist", "run.js"),
...process.argv.slice(2),
]);
function run(command, args) {
const result = spawnSync(command, args, {
cwd: repoRoot,
env: process.env,
stdio: "inherit",
});
if (result.error) {
console.error(result.error.message);
process.exit(1);
}
if (result.signal) {
console.error(`${command} terminated by ${result.signal}`);
process.exit(1);
}
if (result.status !== 0) {
process.exit(result.status ?? 1);
}
}
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$root"
out=".zero/sanitizer/zero"
mkdir -p "$(dirname "$out")"
make -C native/zero-c \
OUT="$root/$out" \
CFLAGS="-std=c11 -Wall -Wextra -Wpedantic -g -O1 -fsanitize=address,undefined"
"$out" --version >/dev/null
"$out" check examples/hello.graph >/dev/null
"$out" build --json --target linux-musl-x64 examples/hello.graph --out .zero/sanitizer/hello-linux >/dev/null
"$out" check conformance/native/pass/stdlib-target-neutral.graph >/dev/null
"$out" run conformance/native/pass/stdlib-target-neutral.graph >/dev/null
"$out" inspect --json examples/memory-package >/dev/null
"$out" size --json examples/memory-package >/dev/null
"$out" size --json examples/std-str.graph >/dev/null
"$out" mem --json examples/hello.graph >/dev/null
# Regression: dependency manifest read errors must keep an owned diagnostic
# path after the transient manifest path buffer is freed.
if [ "$(id -u)" != "0" ]; then
dep_root="$(mktemp -d)"
cp -R conformance/packages/dep-app "$dep_root/dep-app"
cp -R conformance/packages/dep-lib "$dep_root/dep-lib"
rm -rf "$dep_root/dep-app/.zero" "$dep_root/dep-lib/.zero"
chmod 000 "$dep_root/dep-lib/zero.toml"
dep_out="$("$out" check --json "$dep_root/dep-app" 2>&1 || true)"
chmod 644 "$dep_root/dep-lib/zero.toml"
rm -rf "$dep_root"
case "$dep_out" in
*AddressSanitizer*|*runtime\ error:*)
echo "sanitizer error in dependency manifest read-error diagnostic path" >&2
printf '%s\n' "$dep_out" >&2
exit 1
;;
esac
printf '%s' "$dep_out" | grep -q "\"path\": \"$dep_root/dep-lib/zero.toml\"" || {
echo "dependency manifest read-error diagnostic did not report the dependency manifest path" >&2
printf '%s\n' "$dep_out" >&2
exit 1
}
fi
File diff suppressed because it is too large Load Diff
+700
View File
@@ -0,0 +1,700 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { existsSync } from "node:fs";
import { readdir, readFile } from "node:fs/promises";
import { join } from "node:path";
type StdHelper = {
name: string;
module: string;
returnType: string;
argCount: number;
argTypes: Array<string | null>;
errorNames: string[];
capability: string;
targetSupport: string;
allocationBehavior: string;
emitsRuntimeHelper: boolean;
kind: string;
};
type StdSourceModule = {
module: string;
path: string;
graphPath: string;
};
type StdSourceCall = {
publicName: string;
targetName: string;
module: string;
};
type StdSkillSignature = {
returnType: string;
argTypes: string[];
errorNames: string[];
};
type AllocationCategory =
| "borrowed-view"
| "caller-storage"
| "explicit-allocator"
| "host-resource"
| "no-allocation"
| "owned-resource";
type ReturnViewCategory =
| "borrowed-view"
| "caller-storage-view"
| "explicit-allocator-view"
| "static-view";
type ResourceLifetimeCategory =
| "borrowed-resource"
| "owned-resource"
| "resource-capability"
| "resource-value";
type StreamingBehaviorCategory =
| "bounded-input"
| "buffer-copy"
| "chunked-read"
| "line-scan"
| "stream-scan";
const knownCapabilities = new Set([
"alloc",
"args",
"codec",
"env",
"fs",
"memory",
"net",
"none",
"parse",
"path",
"proc",
"rand",
"time",
]);
const hostOnlyCapabilities = new Set(["args", "env", "fs", "proc"]);
const runtimeCapabilities = new Set(["memory", "net"]);
const targetSupportValues = new Set(["target-neutral", "host", "host-runtime"]);
const errorNamePattern = /^[A-Z][A-Za-z0-9]*$/;
const helperKindPattern = /^Z_STD_HELPER_KIND_[A-Z_]+$/;
const helperNamePattern = /^std\.[a-z][A-Za-z0-9]*\.[A-Za-z][A-Za-z0-9]*$/;
const moduleNamePattern = /^std\.[a-z][A-Za-z0-9]*$/;
const vagueAllocationBehaviors = new Set(["directory traversal"]);
const knownResourceTypes = new Set([
"BufferedReader",
"BufferedWriter",
"ByteBuf",
"File",
"FixedBufAlloc",
"FixedReader",
"FixedWriter",
"RandSource",
"Vec",
]);
const countedResourceTypes = new Set([
"Address",
"Alloc",
"BufferedReader",
"BufferedWriter",
"ByteBuf",
"File",
"FixedBufAlloc",
"FixedReader",
"FixedWriter",
"Fs",
"GeneralAlloc",
"HttpClient",
"HttpError",
"HttpHeaderValue",
"HttpMethod",
"HttpResult",
"HttpServer",
"JsonDoc",
"Net",
"NullAlloc",
"PageAlloc",
"ProcChild",
"ProcStatus",
"RandSource",
"Vec",
]);
const publicModuleDocsDir = "docs/articles/modules";
const skillPath = "skill-data/stdlib.md";
const stdSigPath = "native/zero-c/src/std_sig.c";
const stdSourcePath = "native/zero-c/src/std_source.c";
const embeddedStdlibGraphPath = "native/zero-c/src/embedded_stdlib_graph.inc";
const embeddedStdlibGraphDir = "native/zero-c/src/embedded_stdlib_graph";
const fixtureRoots = ["examples", "conformance", "benchmarks/rosetta"];
const generatedFixtureFiles = ["conformance/run.mjs"];
function cBlock(text: string, marker: string): string {
const start = text.indexOf(marker);
if (start < 0) return "";
const open = text.indexOf("{", start);
if (open < 0) return "";
let depth = 0;
for (let index = open; index < text.length; index++) {
const ch = text[index];
if (ch === "{") depth++;
else if (ch === "}") {
depth--;
if (depth === 0) return text.slice(open + 1, index);
}
}
return "";
}
function parseCStringArray(raw: string): Array<string | null> {
const values: Array<string | null> = [];
const tokenPattern = /"((?:\\.|[^"\\])*)"|NULL/g;
for (const match of raw.matchAll(tokenPattern)) {
values.push(match[0] === "NULL" ? null : match[1].replace(/\\"/g, "\"").replace(/\\\\/g, "\\"));
}
return values;
}
function duplicateValues(values: string[]): string[] {
const seen = new Set<string>();
const duplicates = new Set<string>();
for (const value of values) {
if (seen.has(value)) duplicates.add(value);
seen.add(value);
}
return [...duplicates].sort((a, b) => a.localeCompare(b));
}
function cIdent(text: string): string {
return text.replace(/[^A-Za-z0-9_]/g, "_");
}
function parseEmbeddedStdlibGraphBytes(text: string, graphPath: string): Buffer | null {
const ident = `zero_embedded_stdlib_graph_${cIdent(graphPath)}_bytes`;
const block = cBlock(text, `static const unsigned char ${ident}[] =`);
if (block.length === 0) return null;
const bytes = [...block.matchAll(/0x([0-9a-fA-F]{2})/g)].map((match) => Number.parseInt(match[1], 16));
return Buffer.from(bytes);
}
function parseEmbeddedStdlibGraphPart(text: string, graphPath: string): string | null {
const partName = `${cIdent(graphPath)}.inc`;
const pattern = new RegExp(`#include\\s+"embedded_stdlib_graph/${partName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"`);
return pattern.test(text) ? join(embeddedStdlibGraphDir, partName) : null;
}
async function readEmbeddedStdlibGraphBytes(text: string | null, graphPath: string): Promise<Buffer | null> {
if (text !== null) {
const embeddedGraph = parseEmbeddedStdlibGraphBytes(text, graphPath);
if (embeddedGraph !== null) return embeddedGraph;
const partPath = parseEmbeddedStdlibGraphPart(text, graphPath);
if (partPath !== null && existsSync(partPath)) {
const partText = await readFile(partPath, "utf8");
return parseEmbeddedStdlibGraphBytes(partText, graphPath);
}
}
return existsSync(graphPath) ? readFile(graphPath) : null;
}
function parseStdHelpers(text: string): StdHelper[] {
const block = cBlock(text, "const ZStdHelperInfo z_std_helpers[] =");
const helpers: StdHelper[] = [];
const rowPattern = /\{\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*(-?\d+)\s*,\s*\{([^}]*)\}\s*,\s*\{([^}]*)\}\s*,\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*(true|false)\s*,\s*(Z_STD_HELPER_KIND_[A-Z_]+)\s*\}/g;
for (const match of block.matchAll(rowPattern)) {
const name = match[1];
const parts = name.split(".");
helpers.push({
name,
module: `${parts[0]}.${parts[1]}`,
returnType: match[2],
argCount: Number(match[3]),
argTypes: parseCStringArray(match[4]),
errorNames: parseCStringArray(match[5]).filter((value): value is string => value !== null),
capability: match[6],
targetSupport: match[7],
allocationBehavior: match[8],
emitsRuntimeHelper: match[9] === "true",
kind: match[10],
});
}
return helpers.sort((a, b) => a.name.localeCompare(b.name));
}
function parseSkillSignatures(text: string): Map<string, StdSkillSignature> {
const start = text.indexOf("## Function Signatures");
if (start < 0) return new Map();
const end = text.indexOf("## Maybe Pattern", start);
const catalog = text.slice(start, end < 0 ? undefined : end);
const signatures = new Map<string, StdSkillSignature>();
const modulePattern = /### (std\.[A-Za-z0-9]+)\s+```text\n([\s\S]*?)\n```/g;
for (const moduleMatch of catalog.matchAll(modulePattern)) {
const module = moduleMatch[1];
for (const rawLine of moduleMatch[2].split(/\r?\n/)) {
const line = rawLine.trim();
if (line.length === 0) continue;
const signatureMatch = line.match(/^([A-Za-z][A-Za-z0-9]*)\((.*)\) -> (.+)$/);
if (!signatureMatch) continue;
const argText = signatureMatch[2].trim();
const argTypes = argText.length === 0
? []
: splitTopLevelCommaList(argText).map((arg) => {
const colon = arg.indexOf(":");
return (colon >= 0 ? arg.slice(colon + 1) : arg).trim();
});
const returnAndErrors = signatureMatch[3].trim();
const errorMatch = returnAndErrors.match(/\s+raises\s+\[([^\]]*)\]\s*$/);
const errorNames = errorMatch
? errorMatch[1].split(/\s*,\s*/).map((name) => name.trim()).filter((name) => name.length > 0)
: [];
const returnType = returnAndErrors.replace(/\s+raises\s+\[[^\]]*\]\s*$/, "").trim();
signatures.set(`${module}.${signatureMatch[1]}`, { returnType, argTypes, errorNames });
}
}
return signatures;
}
function splitTopLevelCommaList(text: string): string[] {
const parts: string[] = [];
let depth = 0;
let start = 0;
for (let index = 0; index < text.length; index++) {
const ch = text[index];
if (ch === "<" || ch === "(" || ch === "[") {
depth++;
} else if (ch === ">" || ch === ")" || ch === "]") {
if (depth > 0) depth--;
} else if (ch === "," && depth === 0) {
const part = text.slice(start, index).trim();
if (part.length > 0) parts.push(part);
start = index + 1;
}
}
const tail = text.slice(start).trim();
if (tail.length > 0) parts.push(tail);
return parts;
}
function parseStdSourceModules(text: string): StdSourceModule[] {
const block = cBlock(text, "static const ZStdSourceModule std_source_modules[] =");
return [...block.matchAll(/\{\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*zero_embedded_stdlib_graph_[A-Za-z0-9_]+_bytes\s*,\s*sizeof\s*\(\s*zero_embedded_stdlib_graph_[A-Za-z0-9_]+_bytes\s*\)\s*\}/g)]
.map((match) => ({ module: match[1], path: match[2], graphPath: match[2].replace(/\.0$/, ".graph") }))
.sort((a, b) => a.module.localeCompare(b.module));
}
function parseStdSourceCalls(text: string): StdSourceCall[] {
const block = cBlock(text, "static const ZStdSourceCall std_source_calls[] =");
return [...block.matchAll(/\{\s*"([^"]+)"\s*,\s*"([^"]+)"\s*,\s*"([^"]+)"\s*\}/g)]
.map((match) => ({ publicName: match[1], targetName: match[2], module: match[3] }))
.sort((a, b) => a.publicName.localeCompare(b.publicName));
}
async function readOptional(path: string): Promise<string | null> {
if (!existsSync(path)) return null;
return readFile(path, "utf8");
}
async function sourceFilesUnder(root: string): Promise<string[]> {
if (!existsSync(root)) return [];
const entries = await readdir(root, { withFileTypes: true });
const groups = await Promise.all(entries.map(async (entry) => {
const path = join(root, entry.name);
if (entry.isDirectory()) return sourceFilesUnder(path);
if (entry.isFile() && entry.name.endsWith(".0")) return [path];
return [];
}));
return groups.flat();
}
function pushIf(condition: boolean, failures: string[], message: string) {
if (condition) failures.push(message);
}
function incrementCount(map: Map<string, number>, key: string) {
map.set(key, (map.get(key) ?? 0) + 1);
}
function sortedObjectFromCounts(counts: Map<string, number>): Record<string, number> {
return Object.fromEntries([...counts.entries()].sort((a, b) => a[0].localeCompare(b[0])));
}
function allocationCategory(helper: StdHelper): AllocationCategory | null {
const behavior = helper.allocationBehavior.toLowerCase();
if (
behavior.includes("no allocation") ||
behavior.includes("never allocates") ||
behavior.includes("bounds-checked") ||
behavior.includes("checks ") ||
behavior.includes("counts ") ||
behavior.includes("decodes a bounded") ||
behavior.includes("deterministic test source") ||
behavior.includes("inspects ") ||
behavior.includes("little-endian byte read") ||
behavior.includes("little-endian byte write primitive") ||
behavior.includes("matches ") ||
behavior.includes("reads body start offset") ||
behavior.includes("reads header-value") ||
behavior.includes("reads http status metadata") ||
behavior.includes("reads response") ||
behavior.includes("reads transport error metadata") ||
behavior.includes("returns structured validation status") ||
behavior.includes("structured validation status code") ||
behavior.includes("streaming token count") ||
behavior.includes("typed decode boundary metadata")
) return "no-allocation";
if (
behavior.includes("caller") ||
behavior.includes("buffer") ||
behavior.includes("storage") ||
behavior.includes("writes ") ||
behavior.includes("fills ") ||
behavior.includes("sorts ")
) return "caller-storage";
if (
behavior.includes("borrows") ||
behavior.includes("borrowed") ||
behavior.includes("raw query parameter") ||
behavior.includes("raw top-level") ||
behavior.includes("field value slice")
) return "borrowed-view";
if (behavior.includes("owned") || behavior.includes("handle") || behavior.includes("closes ")) return "owned-resource";
if (behavior.includes("alloc") || behavior.includes("allocator") || behavior.includes("arena")) return "explicit-allocator";
if (
behavior.includes("directory") ||
behavior.includes("entropy") ||
behavior.includes("file") ||
behavior.includes("http listener") ||
behavior.includes("network") ||
behavior.includes("process") ||
behavior.includes("tls boundary")
) return "host-resource";
return null;
}
function resourceWrapperUses(type: string): Array<{ wrapper: string; typeName: string }> {
return [...type.matchAll(/\b(owned|mutref|ref)<([A-Za-z][A-Za-z0-9]*)>/g)]
.map((match) => ({ wrapper: match[1], typeName: match[2] }));
}
function resourceTypeUses(type: string): string[] {
const wrappers = resourceWrapperUses(type).map((use) => use.typeName);
const exact = type.match(/^[A-Za-z][A-Za-z0-9]*$/) && countedResourceTypes.has(type) ? [type] : [];
return [...wrappers, ...exact];
}
function unwrapMaybe(type: string): string {
const match = type.match(/^Maybe<(.+)>$/);
return match ? match[1] : type;
}
function returnsBorrowedViewType(type: string): boolean {
const unwrapped = unwrapMaybe(type);
return unwrapped === "String" || unwrapped.includes("Span<");
}
function hasMutableSpanArg(helper: StdHelper): boolean {
return helper.argTypes.some((type) => type?.startsWith("MutSpan<"));
}
function describesStaticView(behavior: string): boolean {
return behavior.includes("boundary metadata") ||
behavior.includes("status text") ||
behavior.includes("tls boundary") ||
behavior.includes("borrows static") ||
(behavior.includes("static") && !behavior.includes("borrows/static"));
}
function returnViewCategory(helper: StdHelper, category: AllocationCategory | null): ReturnViewCategory | null {
if (!returnsBorrowedViewType(helper.returnType)) return null;
const behavior = helper.allocationBehavior.toLowerCase();
if (describesStaticView(behavior)) return "static-view";
if (behavior.includes("borrows")) return "borrowed-view";
if (helper.returnType.includes("MutSpan<") && category === "explicit-allocator") return "explicit-allocator-view";
if (category === "caller-storage" && hasMutableSpanArg(helper)) return "caller-storage-view";
if (category === "explicit-allocator") return "explicit-allocator-view";
if (category === "borrowed-view") return "borrowed-view";
return null;
}
function resourceLifetimeCategories(helper: StdHelper): ResourceLifetimeCategory[] {
const categories = new Set<ResourceLifetimeCategory>();
if (helper.returnType.includes("owned<")) categories.add("owned-resource");
if (helperTypes(helper).some((type) => resourceWrapperUses(type).some((use) => use.wrapper === "ref" || use.wrapper === "mutref"))) {
categories.add("borrowed-resource");
}
const unwrappedReturn = unwrapMaybe(helper.returnType);
if (countedResourceTypes.has(unwrappedReturn) && !helper.returnType.includes("<")) categories.add("resource-value");
if (helper.argTypes.some((type) => type !== null && countedResourceTypes.has(type))) categories.add("resource-capability");
return [...categories].sort((a, b) => a.localeCompare(b));
}
function streamingBehaviorCategory(helper: StdHelper): StreamingBehaviorCategory | null {
const behavior = helper.allocationBehavior.toLowerCase();
if (helper.name.endsWith("streamTokens") || helper.name.endsWith("streamTokensBytes") || helper.name.endsWith("readUntilDelimiter") || helper.name.endsWith("readUntilDelimiterStart") || behavior.includes("streaming")) return "stream-scan";
if (helper.name.endsWith("readBytesAt") || behavior.includes("chunked")) return "chunked-read";
if (helper.name.includes("Within") || behavior.includes("within size limit")) return "bounded-input";
if (helper.name.endsWith("nextLine") || helper.name.endsWith("nextLineStart") || helper.name.endsWith("readLine") || helper.name.endsWith("readLineStart") || helper.name.endsWith("countLines")) return "line-scan";
if (helper.name.endsWith(".copy") || helper.name.endsWith("copyN") || helper.name.endsWith("copyBuffer") || behavior.includes("copies through caller buffer")) return "buffer-copy";
return null;
}
function capabilityTargetKey(helper: StdHelper): string {
return `${helper.targetSupport}:${helper.capability}`;
}
function helperTypes(helper: StdHelper): string[] {
return [
helper.returnType,
...helper.argTypes.filter((type): type is string => type !== null),
];
}
const [stdSig, stdSource, embeddedStdlibGraph, skill] = await Promise.all([
readFile(stdSigPath, "utf8"),
readFile(stdSourcePath, "utf8"),
readOptional(embeddedStdlibGraphPath),
readFile(skillPath, "utf8"),
]);
const stdEntries = await readdir("std", { withFileTypes: true });
const stdProjectionFiles = stdEntries
.filter((entry) => entry.isFile() && entry.name.endsWith(".0"))
.map((entry) => `std/${entry.name}`)
.sort((a, b) => a.localeCompare(b));
const stdGraphFiles = stdEntries
.filter((entry) => entry.isFile() && entry.name.endsWith(".graph"))
.map((entry) => `std/${entry.name}`)
.sort((a, b) => a.localeCompare(b));
const helpers = parseStdHelpers(stdSig);
const skillSignatures = parseSkillSignatures(skill);
const modules = [...new Set(helpers.map((helper) => helper.module))].sort((a, b) => a.localeCompare(b));
const sourceModules = parseStdSourceModules(stdSource);
const sourceCalls = parseStdSourceCalls(stdSource);
const fixtureFiles = [
...(await Promise.all(fixtureRoots.map((root) => sourceFilesUnder(root)))).flat(),
...generatedFixtureFiles.filter((path) => existsSync(path)),
]
.sort((a, b) => a.localeCompare(b));
const fixtureTexts = await Promise.all(fixtureFiles.map(async (path) => ({
path,
text: await readFile(path, "utf8"),
})));
const helpersByName = new Map(helpers.map((helper) => [helper.name, helper]));
const sourceModulesByName = new Map(sourceModules.map((module) => [module.module, module]));
const sourceModulePaths = new Set(sourceModules.map((module) => module.path));
const sourceModuleGraphPaths = new Set(sourceModules.map((module) => module.graphPath));
const sourceCallsByPublicName = new Map(sourceCalls.map((call) => [call.publicName, call]));
const graphImplementedHelperModules = new Set(sourceCalls.map((call) => call.module));
const partiallyGraphBackedModules = new Set(["std.args", "std.cli", "std.codec", "std.crypto", "std.env", "std.fmt", "std.fs", "std.http", "std.io", "std.json", "std.math", "std.mem", "std.net", "std.parse", "std.path", "std.proc", "std.rand", "std.search", "std.str", "std.term", "std.time", "std.toml"]);
const docsEntries = await readdir(publicModuleDocsDir, { withFileTypes: true });
const publicModuleDocs = new Set(
docsEntries
.filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
.map((entry) => `std.${entry.name.replace(/\.md$/, "")}`),
);
const docsByModule = new Map<string, string>();
await Promise.all(modules.map(async (module) => {
const path = `${publicModuleDocsDir}/${module.slice("std.".length)}.md`;
const content = await readOptional(path);
if (content !== null) docsByModule.set(module, content);
}));
const failures: string[] = [];
const allocationCategoryCounts = new Map<string, number>();
const capabilityCounts = new Map<string, number>();
const capabilityTargetCounts = new Map<string, number>();
const namedErrorCounts = new Map<string, number>();
const resourceTypeCounts = new Map<string, number>();
const resourceLifetimeCounts = new Map<string, number>();
const returnViewCounts = new Map<string, number>();
const targetSupportCounts = new Map<string, number>();
const streamingBehaviorCounts = new Map<string, number>();
pushIf(stdSource.includes("embedded_stdlib.inc"), failures, "std_source.c must not include embedded stdlib source chunks");
pushIf(/zero_embedded_stdlib_[A-Za-z0-9_]+_chunks/.test(stdSource), failures, "std_source.c must not reference embedded stdlib source chunks");
pushIf(/z_std_source_module_copy_source/.test(stdSource), failures, "std_source.c must not expose source-copy stdlib bridges");
pushIf(helpers.length === 0, failures, "no stdlib helpers were parsed from std_sig.c");
for (const duplicate of duplicateValues(helpers.map((helper) => helper.name))) {
failures.push(`duplicate stdlib helper contract: ${duplicate}`);
}
for (const helper of helpers) {
pushIf(!helperNamePattern.test(helper.name), failures, `${helper.name}: helper name must be std.<module>.<name>`);
pushIf(!moduleNamePattern.test(helper.module), failures, `${helper.name}: helper module must be std.<module>`);
pushIf(helper.returnType.length === 0, failures, `${helper.name}: return type is empty`);
pushIf(helper.argCount < 0 || helper.argCount > 5, failures, `${helper.name}: arg count ${helper.argCount} exceeds contract bounds`);
pushIf(helper.argTypes.length > 5, failures, `${helper.name}: arg type list exceeds contract bounds`);
for (let index = 0; index < helper.argCount; index++) {
pushIf(helper.argTypes[index] === null || helper.argTypes[index] === undefined, failures, `${helper.name}: arg ${index + 1} is missing from std_sig.c`);
}
pushIf(helper.errorNames.length > 4, failures, `${helper.name}: error list exceeds contract bounds`);
for (const duplicate of duplicateValues(helper.errorNames)) {
failures.push(`${helper.name}: duplicate named error '${duplicate}'`);
}
for (const errorName of helper.errorNames) {
pushIf(!errorNamePattern.test(errorName), failures, `${helper.name}: invalid named error '${errorName}'`);
incrementCount(namedErrorCounts, errorName);
}
pushIf(helper.name.endsWith("OrRaise") && helper.errorNames.length === 0, failures, `${helper.name}: OrRaise helper must declare named errors`);
pushIf(helper.errorNames.length > 0 && helper.returnType.startsWith("Maybe<"), failures, `${helper.name}: named-error helpers must not also use Maybe return failure`);
pushIf(!targetSupportValues.has(helper.targetSupport), failures, `${helper.name}: unknown target support '${helper.targetSupport}'`);
if (targetSupportValues.has(helper.targetSupport)) incrementCount(targetSupportCounts, helper.targetSupport);
pushIf(helper.capability.length === 0, failures, `${helper.name}: capability is empty`);
pushIf(helper.capability.length > 0 && !knownCapabilities.has(helper.capability), failures, `${helper.name}: unknown capability '${helper.capability}'`);
if (helper.capability.length > 0 && knownCapabilities.has(helper.capability)) incrementCount(capabilityCounts, helper.capability);
if (targetSupportValues.has(helper.targetSupport) && helper.capability.length > 0 && knownCapabilities.has(helper.capability)) {
incrementCount(capabilityTargetCounts, capabilityTargetKey(helper));
}
pushIf(helper.allocationBehavior.length === 0, failures, `${helper.name}: allocation behavior is empty`);
pushIf(vagueAllocationBehaviors.has(helper.allocationBehavior), failures, `${helper.name}: allocation behavior '${helper.allocationBehavior}' is too vague`);
const category = allocationCategory(helper);
pushIf(category === null, failures, `${helper.name}: allocation behavior '${helper.allocationBehavior}' does not fit a known ownership category`);
if (category !== null) incrementCount(allocationCategoryCounts, category);
pushIf(hostOnlyCapabilities.has(helper.capability) && helper.targetSupport !== "host", failures, `${helper.name}: capability '${helper.capability}' must use host target support`);
pushIf(helper.targetSupport === "host" && helper.capability === "none", failures, `${helper.name}: host helper must declare its host capability`);
pushIf(helper.targetSupport === "host-runtime" && !runtimeCapabilities.has(helper.capability), failures, `${helper.name}: host-runtime helper must use a runtime-facing capability`);
pushIf(helper.targetSupport === "target-neutral" && category === "host-resource", failures, `${helper.name}: target-neutral helper must not depend on host resources`);
const viewCategory = returnViewCategory(helper, category);
pushIf(returnsBorrowedViewType(helper.returnType) && viewCategory === null, failures, `${helper.name}: return type ${helper.returnType} needs explicit return-view lifetime metadata`);
if (viewCategory !== null) incrementCount(returnViewCounts, viewCategory);
for (const lifetimeCategory of resourceLifetimeCategories(helper)) {
incrementCount(resourceLifetimeCounts, lifetimeCategory);
}
const streamingCategory = streamingBehaviorCategory(helper);
if (streamingCategory !== null) incrementCount(streamingBehaviorCounts, streamingCategory);
pushIf(helper.name.includes("Within") && streamingCategory !== "bounded-input", failures, `${helper.name}: bounded helper must declare bounded-input streaming behavior`);
pushIf(helper.name.endsWith("readBytesAt") && streamingCategory !== "chunked-read", failures, `${helper.name}: offset read helper must declare chunked-read behavior`);
pushIf(helper.name.endsWith("streamTokens") && streamingCategory !== "stream-scan", failures, `${helper.name}: stream helper must declare stream-scan behavior`);
for (const type of helperTypes(helper)) {
for (const use of resourceWrapperUses(type)) {
pushIf(!knownResourceTypes.has(use.typeName), failures, `${helper.name}: ${use.wrapper}<${use.typeName}> uses an unknown resource type`);
}
for (const typeName of resourceTypeUses(type)) incrementCount(resourceTypeCounts, typeName);
}
if (helper.returnType.includes("owned<")) {
pushIf(category !== "owned-resource" && category !== "explicit-allocator", failures, `${helper.name}: owned return must declare owned-resource or explicit-allocator allocation behavior`);
}
pushIf(!helperKindPattern.test(helper.kind), failures, `${helper.name}: helper kind '${helper.kind}' is not a std helper kind`);
}
for (const module of modules) {
const docsPath = `${publicModuleDocsDir}/${module.slice("std.".length)}.md`;
pushIf(!publicModuleDocs.has(module), failures, `${module}: missing public module docs at ${docsPath}`);
pushIf(!skill.includes(module), failures, `${module}: skill-data/stdlib.md does not mention module`);
}
for (const helper of helpers) {
const signature = skillSignatures.get(helper.name);
pushIf(!signature, failures, `${helper.name}: skill-data/stdlib.md is missing a Function Signatures row`);
if (signature) {
pushIf(signature.returnType !== helper.returnType, failures, `${helper.name}: skill return type ${signature.returnType} does not match std_sig.c ${helper.returnType}`);
pushIf(signature.argTypes.length !== helper.argCount, failures, `${helper.name}: skill arg count ${signature.argTypes.length} does not match std_sig.c ${helper.argCount}`);
pushIf(signature.errorNames.join(",") !== helper.errorNames.join(","), failures, `${helper.name}: skill named errors [${signature.errorNames.join(", ")}] do not match std_sig.c [${helper.errorNames.join(", ")}]`);
for (let index = 0; index < helper.argCount && index < signature.argTypes.length; index++) {
const expected = helper.argTypes[index];
if (expected !== null && expected !== undefined) {
pushIf(signature.argTypes[index] !== expected, failures, `${helper.name}: skill arg ${index + 1} type ${signature.argTypes[index]} does not match std_sig.c ${expected}`);
}
}
}
const docs = docsByModule.get(helper.module);
if (docs) {
pushIf(!docs.includes(helper.name), failures, `${helper.name}: public module docs do not mention helper`);
}
pushIf(!fixtureTexts.some((fixture) => fixture.text.includes(helper.name)), failures, `${helper.name}: no example, conformance fixture, or Rosetta task exercises helper`);
}
for (const name of [...skillSignatures.keys()].sort((a, b) => a.localeCompare(b))) {
pushIf(!helpersByName.has(name), failures, `${name}: skill-data/stdlib.md Function Signatures row has no std_sig.c helper`);
}
for (const projectionPath of stdProjectionFiles) {
const graphPath = projectionPath.replace(/\.0$/, ".graph");
pushIf(!stdGraphFiles.includes(graphPath), failures, `${projectionPath}: missing sibling graph store ${graphPath}`);
pushIf(!sourceModulePaths.has(projectionPath), failures, `${projectionPath}: std projection is not registered as an embedded graph-backed module`);
}
for (const graphPath of stdGraphFiles) {
const projectionPath = graphPath.replace(/\.graph$/, ".0");
pushIf(!stdProjectionFiles.includes(projectionPath), failures, `${graphPath}: graph store has no sibling projection ${projectionPath}`);
pushIf(!sourceModuleGraphPaths.has(graphPath), failures, `${graphPath}: std graph store is not registered for embedding`);
}
for (const sourceModule of sourceModules) {
pushIf(!moduleNamePattern.test(sourceModule.module), failures, `${sourceModule.module}: invalid graph-backed std module name`);
pushIf(!existsSync(sourceModule.path), failures, `${sourceModule.module}: missing std projection ${sourceModule.path}`);
pushIf(!modules.includes(sourceModule.module), failures, `${sourceModule.module}: graph-backed module has no public helpers`);
const embeddedGraph = await readEmbeddedStdlibGraphBytes(embeddedStdlibGraph, sourceModule.graphPath);
const graph = existsSync(sourceModule.graphPath) ? await readFile(sourceModule.graphPath) : null;
pushIf(!existsSync(sourceModule.graphPath), failures, `${sourceModule.module}: missing graph-backed std module ${sourceModule.graphPath}`);
pushIf(embeddedGraph === null, failures, `${sourceModule.module}: embedded stdlib graph is missing for ${sourceModule.graphPath}`);
pushIf(graph !== null && graph.subarray(0, 8).toString("latin1") !== "ZRGBIN1\0", failures, `${sourceModule.module}: std graph store must be binary ${sourceModule.graphPath}`);
pushIf(graph !== null && embeddedGraph !== null && Buffer.compare(embeddedGraph, graph) !== 0, failures, `${sourceModule.module}: embedded stdlib graph is stale for ${sourceModule.graphPath}`);
}
for (const duplicate of duplicateValues(sourceCalls.map((call) => call.publicName))) {
failures.push(`duplicate graph-backed public helper mapping: ${duplicate}`);
}
for (const duplicate of duplicateValues(sourceCalls.map((call) => call.targetName))) {
failures.push(`duplicate graph-backed target helper mapping: ${duplicate}`);
}
for (const call of sourceCalls) {
const helper = helpersByName.get(call.publicName);
const sourceModule = sourceModulesByName.get(call.module);
pushIf(!helper, failures, `${call.publicName}: graph-backed mapping has no std_sig contract`);
pushIf(!sourceModule, failures, `${call.publicName}: graph-backed mapping references unknown module ${call.module}`);
pushIf(helper !== undefined && helper.module !== call.module, failures, `${call.publicName}: graph-backed mapping module ${call.module} does not match helper module ${helper?.module}`);
pushIf(helper !== undefined && !helper.emitsRuntimeHelper, failures, `${call.publicName}: graph-backed helper must emit runtime helper code`);
if (sourceModule && existsSync(sourceModule.path)) {
const source = await readFile(sourceModule.path, "utf8");
const targetPattern = new RegExp(`\\bfn\\s+${call.targetName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:<[^>]+>)?\\s*\\(`);
pushIf(!targetPattern.test(source), failures, `${call.publicName}: target function ${call.targetName} is missing from ${sourceModule.path}`);
}
}
for (const sourceModule of sourceModules) {
if (!graphImplementedHelperModules.has(sourceModule.module)) continue;
if (partiallyGraphBackedModules.has(sourceModule.module)) continue;
for (const helper of helpers.filter((candidate) => candidate.module === sourceModule.module)) {
pushIf(!sourceCallsByPublicName.has(helper.name), failures, `${helper.name}: graph-backed module helper is missing embedded std graph mapping`);
}
}
const graphStorageComplete = stdProjectionFiles.length === sourceModules.length &&
stdGraphFiles.length === sourceModules.length &&
stdProjectionFiles.every((projectionPath) => sourceModulePaths.has(projectionPath)) &&
stdGraphFiles.every((graphPath) => sourceModuleGraphPaths.has(graphPath));
const summary = {
schema: 1,
helperCount: helpers.length,
moduleCount: modules.length,
modules,
stdProjectionModuleCount: stdProjectionFiles.length,
embeddedStdModuleCount: sourceModules.length,
graphStoredModuleCount: sourceModules.length,
graphStorageComplete,
graphImplementedHelperModuleCount: graphImplementedHelperModules.size,
graphBackedHelperCount: sourceCalls.length,
nativeOrTableHelperCount: helpers.length - sourceCalls.length,
allocationCategoryCounts: sortedObjectFromCounts(allocationCategoryCounts),
capabilityCounts: sortedObjectFromCounts(capabilityCounts),
capabilityTargetCounts: sortedObjectFromCounts(capabilityTargetCounts),
namedErrorCounts: sortedObjectFromCounts(namedErrorCounts),
returnViewCounts: sortedObjectFromCounts(returnViewCounts),
resourceLifetimeCounts: sortedObjectFromCounts(resourceLifetimeCounts),
resourceTypeCounts: sortedObjectFromCounts(resourceTypeCounts),
streamingBehaviorCounts: sortedObjectFromCounts(streamingBehaviorCounts),
targetSupportCounts: sortedObjectFromCounts(targetSupportCounts),
fixtureFileCount: fixtureFiles.length,
ok: failures.length === 0,
failures,
};
if (process.argv.includes("--json")) {
console.log(JSON.stringify(summary, null, 2));
} else if (failures.length === 0) {
console.log(`stdlib contracts ok (${summary.helperCount} helpers, ${summary.graphStoredModuleCount}/${summary.stdProjectionModuleCount} std modules graph-stored, ${summary.graphBackedHelperCount} graph-backed helper mappings)`);
} else {
console.error(`stdlib contracts failed (${failures.length} issue${failures.length === 1 ? "" : "s"})`);
for (const failure of failures.slice(0, 40)) console.error(`- ${failure}`);
if (failures.length > 40) console.error(`- ... ${failures.length - 40} more`);
}
if (failures.length > 0) process.exitCode = 1;
+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { mkdir, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const zero = "bin/zero";
const outDir = ".zero/stdlib-target-matrix";
const fixtures = [
"conformance/native/pass/stdlib-target-neutral.graph",
"conformance/native/pass/direct-checksum-helpers.graph",
];
const artifactBudgetBytes = 120_000;
const targets = [
"darwin-arm64",
"darwin-x64",
"linux-arm64",
"linux-musl-arm64",
"linux-musl-x64",
"linux-x64",
"win32-arm64.exe",
"win32-x64.exe",
];
const representativeStdlibTargets = [
"darwin-arm64",
"linux-musl-x64",
"win32-x64.exe",
];
const matrixScope = process.env.ZERO_STDLIB_TARGET_MATRIX_SCOPE === "fast" ? "fast" : "deep";
type MatrixRow = {
fixture: string;
target: string;
ok: boolean;
artifactPath: string;
artifactBytes: number;
generatedCBytes: number;
directObjectEmitter?: string;
diagnostic?: string;
};
function parsePositiveInt(value: string | undefined, fallback: number) {
const parsed = Number.parseInt(value ?? "", 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
async function mapLimit<T, R>(items: T[], limit: number, callback: (item: T, index: number) => Promise<R>) {
const results = new Array<R>(items.length);
let next = 0;
const workerCount = Math.min(Math.max(1, limit), Math.max(1, items.length));
async function worker() {
for (;;) {
const index = next++;
if (index >= items.length) return;
results[index] = await callback(items[index], index);
}
}
await Promise.all(Array.from({ length: workerCount }, () => worker()));
return results;
}
await mkdir(outDir, { recursive: true });
async function json(args: string[]) {
try {
const result = await execFileAsync(zero, args, { maxBuffer: 1024 * 1024 * 4 });
return { code: 0, stdout: result.stdout, stderr: result.stderr, body: JSON.parse(result.stdout) };
} catch (error) {
const stdout = error.stdout?.toString() ?? "";
let body = null;
try {
body = JSON.parse(stdout);
} catch {
body = null;
}
return {
code: error.code ?? error.status ?? 1,
stdout,
stderr: error.stderr?.toString() ?? "",
body,
};
}
}
const rows: MatrixRow[] = [];
const deepMatrix = fixtures.flatMap((fixture) => {
const fixtureTargets = fixture.includes("stdlib-target-neutral")
? representativeStdlibTargets
: targets;
return fixtureTargets.map((target) => ({ fixture, target }));
});
const fastMatrix = [
{ fixture: "conformance/native/pass/stdlib-target-neutral.graph", target: "linux-musl-x64" },
{ fixture: "conformance/native/pass/stdlib-target-neutral.graph", target: "win32-x64.exe" },
{ fixture: "conformance/native/pass/direct-checksum-helpers.graph", target: "linux-musl-x64" },
{ fixture: "conformance/native/pass/direct-checksum-helpers.graph", target: "darwin-arm64" },
{ fixture: "conformance/native/pass/direct-checksum-helpers.graph", target: "win32-x64.exe" },
];
const matrix = matrixScope === "fast" ? fastMatrix : deepMatrix;
const jobs = parsePositiveInt(process.env.ZERO_STDLIB_TARGET_MATRIX_JOBS, 4);
rows.push(...await mapLimit(matrix, jobs, async ({ fixture, target }) => {
const startedAt = Date.now();
const ext = target.includes("win32") ? ".obj" : ".o";
const stem = fixture.split("/").pop()?.replace(/\.(?:0|graph)$/, "") ?? "fixture";
const artifactPath = join(outDir, `${stem}-${target}${ext}`);
const result = await json(["build", "--json", "--emit", "obj", "--target", target, fixture, "--out", artifactPath]);
const durationMs = Date.now() - startedAt;
const diagnostic = result.body?.diagnostics?.[0];
const row: MatrixRow = {
fixture,
target,
ok: result.code === 0 && result.body?.ok !== false,
artifactPath,
artifactBytes: result.body?.artifactBytes ?? 0,
generatedCBytes: result.body?.generatedCBytes ?? -1,
directObjectEmitter: result.body?.releaseTargetContract?.directObjectEmitter,
diagnostic: diagnostic ? `${diagnostic.code}: ${diagnostic.message}` : undefined,
};
console.error(`stdlib target matrix ${row.ok ? "ok" : "failed"}: ${fixture} ${target} (${durationMs}ms)`);
assert.equal(row.ok, true, `${fixture} ${target} failed: ${row.diagnostic ?? result.stderr}`);
assert.equal(row.generatedCBytes, 0, `${fixture} ${target} used generated C fallback`);
assert.ok(row.artifactBytes > 0, `${fixture} ${target} did not produce an object artifact`);
assert.ok(row.artifactBytes <= artifactBudgetBytes, `${fixture} ${target} object artifact exceeded ${artifactBudgetBytes} bytes`);
return row;
}));
for (const fixture of [...new Set(matrix.map((row) => row.fixture))]) {
const hostRun = await execFileAsync(zero, ["run", fixture]);
assert.equal(hostRun.stdout, "", `${fixture} should run silently`);
}
const report = {
schemaVersion: 1,
ok: rows.every((row) => row.ok),
scope: matrixScope,
fixtures,
artifactBudgetBytes,
representativeStdlibTargets,
targets: rows,
};
await writeFile(join(outDir, "report.json"), `${JSON.stringify(report, null, 2)}\n`);
console.log("stdlib target matrix ok");
+1287
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"noImplicitAny": false,
"strictNullChecks": false,
"useUnknownInCatchVariables": false,
"types": ["node"],
"noEmit": true,
"skipLibCheck": true,
"allowImportingTsExtensions": true,
"erasableSyntaxOnly": true,
"verbatimModuleSyntax": true
},
"include": ["*.mts"]
}
+556
View File
@@ -0,0 +1,556 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { execFileSync } from "node:child_process";
import { rmSync, writeFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(scriptDir, "..");
const tmpBase = path.join("/tmp", `zero-type-core-smoke-${process.pid}`);
const sourcePath = `${tmpBase}.c`;
const exePath = process.platform === "win32" ? `${tmpBase}.exe` : tmpBase;
const source = String.raw`
#include "type_core.h"
#include "unify.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void expect(int ok, const char *message) {
if (ok) return;
fprintf(stderr, "%s\n", message);
exit(1);
}
static ZTypeId parse_or_die(ZTypeArena *arena, const char *text) {
ZTypeId type = Z_TYPE_ID_INVALID;
ZTypeParseError error = {0};
if (!z_type_parse(arena, text, &type, &error)) {
fprintf(stderr, "failed to parse '%s': %s at %zu\n", text, error.message, error.offset);
exit(1);
}
return type;
}
static ZTypeId parse_with_binders_or_die(ZTypeArena *arena, const char *text, const ZTypeBinderScope *scope) {
ZTypeId type = Z_TYPE_ID_INVALID;
ZTypeParseError error = {0};
if (!z_type_parse_with_binders(arena, text, scope, &type, &error)) {
fprintf(stderr, "failed to parse '%s' with binders: %s at %zu\n", text, error.message, error.offset);
exit(1);
}
return type;
}
static void expect_roundtrip(const char *source, const char *expected) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId type = parse_or_die(&arena, source);
char *formatted = z_type_format(&arena, type);
expect(formatted && strcmp(formatted, expected) == 0, "type format mismatch");
free(formatted);
z_type_arena_free(&arena);
}
static void expect_static_roundtrip(const char *source, const char *expected, ZStaticValueKind kind) {
ZStaticValue value = {0};
ZTypeParseError error = {0};
if (!z_static_value_parse(source, &value, &error)) {
fprintf(stderr, "failed to parse static value '%s': %s at %zu\n", source, error.message, error.offset);
exit(1);
}
expect(value.kind == kind, "static value kind mismatch");
char *formatted = z_static_value_format(&value);
expect(formatted && strcmp(formatted, expected) == 0, "static value format mismatch");
free(formatted);
z_static_value_free(&value);
}
static void expect_invalid_type(const char *source) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId type = Z_TYPE_ID_INVALID;
ZTypeParseError error = {0};
int ok = z_type_parse(&arena, source, &type, &error);
expect(!ok && type == Z_TYPE_ID_INVALID && error.message[0] != 0, "invalid type parsed successfully");
expect(arena.len == 0, "failed type parse mutated arena");
z_type_arena_free(&arena);
}
static void expect_invalid_type_offset(const char *source, size_t offset) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId type = Z_TYPE_ID_INVALID;
ZTypeParseError error = {0};
int ok = z_type_parse(&arena, source, &type, &error);
expect(!ok && type == Z_TYPE_ID_INVALID && error.message[0] != 0, "invalid type parsed successfully");
expect(error.offset == offset, "invalid type reported wrong offset");
expect(arena.len == 0, "failed type parse mutated arena");
z_type_arena_free(&arena);
}
static void expect_invalid_static(const char *source) {
ZStaticValue value = {0};
ZTypeParseError error = {0};
int ok = z_static_value_parse(source, &value, &error);
expect(!ok && error.message[0] != 0, "invalid static value parsed successfully");
z_static_value_free(&value);
}
static void expect_equal_and_hash(const char *left_text, const char *right_text) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId left = parse_or_die(&arena, left_text);
ZTypeId right = parse_or_die(&arena, right_text);
expect(z_type_equal(&arena, left, right), "equal types did not compare equal");
expect(z_type_hash(&arena, left) == z_type_hash(&arena, right), "equal types produced different hashes");
z_type_arena_free(&arena);
}
static void expect_not_equal(const char *left_text, const char *right_text) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId left = parse_or_die(&arena, left_text);
ZTypeId right = parse_or_die(&arena, right_text);
expect(!z_type_equal(&arena, left, right), "different types compared equal");
z_type_arena_free(&arena);
}
static void expect_failed_parse_rewinds(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId base = parse_or_die(&arena, "i32");
size_t before = arena.len;
ZTypeId bad = Z_TYPE_ID_INVALID;
ZTypeParseError error = {0};
expect(!z_type_parse(&arena, "Span<", &bad, &error), "bad type parsed successfully");
expect(arena.len == before, "failed parse did not rewind arena");
char *formatted = z_type_format(&arena, base);
expect(formatted && strcmp(formatted, "i32") == 0, "rewind corrupted prior type");
free(formatted);
z_type_arena_free(&arena);
}
static void expect_speculative_arg_rewinds(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeId gate = parse_or_die(&arena, "Gate<Mode.tiny>");
expect(arena.len == 1, "static enum arg left speculative type nodes");
char *formatted = z_type_format(&arena, gate);
expect(formatted && strcmp(formatted, "Gate<Mode.tiny>") == 0, "static enum arg formatted incorrectly");
free(formatted);
z_type_arena_free(&arena);
}
static void expect_binder_identity(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl left_decl[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 1},
{.name = "N", .kind = Z_TYPE_BINDER_STATIC, .id = 2, .static_type = "usize"},
};
ZTypeBinderDecl right_decl[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 3},
{.name = "N", .kind = Z_TYPE_BINDER_STATIC, .id = 4, .static_type = "usize"},
};
ZTypeBinderScope left_scope = {.items = left_decl, .len = 2};
ZTypeBinderScope right_scope = {.items = right_decl, .len = 2};
ZTypeId left = parse_with_binders_or_die(&arena, "FixedVec<T,N>", &left_scope);
ZTypeId right = parse_with_binders_or_die(&arena, "FixedVec<T,N>", &right_scope);
expect(!z_type_equal(&arena, left, right), "binder identity collapsed to names");
char *formatted = z_type_format(&arena, left);
expect(formatted && strcmp(formatted, "FixedVec<T,N>") == 0, "binder formatting changed public type text");
free(formatted);
z_type_arena_free(&arena);
}
static void expect_unify_and_substitute(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 10},
{.name = "N", .kind = Z_TYPE_BINDER_STATIC, .id = 11, .static_type = "usize"},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "FixedVec<T,N>", &scope);
ZTypeId actual = parse_or_die(&arena, "FixedVec<u8,0x4>");
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, pattern, actual, &trace), "binder pattern did not unify with concrete type");
const ZUnifyBinding *type_binding = z_unify_trace_lookup(&trace, 10, Z_UNIFY_BINDING_TYPE);
const ZUnifyBinding *static_binding = z_unify_trace_lookup(&trace, 11, Z_UNIFY_BINDING_STATIC);
expect(type_binding && static_binding && trace.len == 2, "unification trace missed binder facts");
char *bound_type = z_type_format(&arena, type_binding->type);
expect(bound_type && strcmp(bound_type, "u8") == 0, "type binder bound to wrong type");
free(bound_type);
expect(static_binding->static_value.kind == Z_STATIC_VALUE_NUMBER && static_binding->static_value.number == 4, "static binder bound to wrong value");
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(z_type_substitute(&arena, pattern, &trace, &substituted), "substitution failed");
expect(z_type_equal(&arena, substituted, actual), "substitution result differs from concrete type");
expect(z_type_occurs(&arena, pattern, 10), "occurs check did not find type binder");
expect(z_type_occurs(&arena, pattern, 11), "occurs check did not find static binder");
expect(!z_type_occurs(&arena, actual, 10), "occurs check found binder in concrete type");
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_occurs_check_rejects_recursive_binding(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 20},
};
ZTypeBinderScope scope = {.items = decls, .len = 1};
ZTypeId pattern = parse_with_binders_or_die(&arena, "T", &scope);
ZTypeId recursive = parse_with_binders_or_die(&arena, "Maybe<T>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(!z_type_unify(&arena, pattern, recursive, &trace), "recursive type binding passed occurs check");
expect(strstr(trace.message, "occurs") != NULL, "occurs check failure did not leave a trace message");
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_occurs_check_follows_trace_bindings(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 30},
{.name = "U", .kind = Z_TYPE_BINDER_TYPE, .id = 31},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<T,U>", &scope);
ZTypeId recursive = parse_with_binders_or_die(&arena, "Pair<U,Maybe<T>>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(!z_type_unify(&arena, pattern, recursive, &trace), "transitive recursive type binding passed occurs check");
expect(strstr(trace.message, "occurs") != NULL, "transitive occurs check failure did not leave a trace message");
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_binder_alias_swap_unifies(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 40},
{.name = "U", .kind = Z_TYPE_BINDER_TYPE, .id = 41},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<T,U>", &scope);
ZTypeId actual = parse_with_binders_or_die(&arena, "Pair<U,T>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, pattern, actual, &trace), "plain binder alias swap did not unify");
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(z_type_substitute(&arena, pattern, &trace, &substituted), "alias substitution failed");
char *formatted = z_type_format(&arena, substituted);
expect(formatted && strcmp(formatted, "Pair<U,U>") == 0, "alias substitution did not use canonical binder");
free(formatted);
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_chained_type_substitution(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 50},
{.name = "U", .kind = Z_TYPE_BINDER_TYPE, .id = 51},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<T,T>", &scope);
ZTypeId actual = parse_with_binders_or_die(&arena, "Pair<U,i32>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, pattern, actual, &trace), "chained type binder pattern did not unify");
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(z_type_substitute(&arena, pattern, &trace, &substituted), "chained type substitution failed");
char *formatted = z_type_format(&arena, substituted);
expect(formatted && strcmp(formatted, "Pair<i32,i32>") == 0, "chained type substitution left an unresolved binder");
free(formatted);
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_concrete_first_type_substitution(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 52},
{.name = "U", .kind = Z_TYPE_BINDER_TYPE, .id = 53},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<Box<T>,Box<T>>", &scope);
ZTypeId actual = parse_with_binders_or_die(&arena, "Pair<Box<i32>,Box<U>>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, pattern, actual, &trace), "concrete-first type binder pattern did not unify");
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(z_type_substitute(&arena, actual, &trace, &substituted), "concrete-first actual substitution failed");
char *formatted = z_type_format(&arena, substituted);
expect(formatted && strcmp(formatted, "Pair<Box<i32>,Box<i32>>") == 0, "concrete-first type substitution left an unresolved binder");
free(formatted);
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_chained_static_substitution(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "N", .kind = Z_TYPE_BINDER_STATIC, .id = 60, .static_type = "usize"},
{.name = "M", .kind = Z_TYPE_BINDER_STATIC, .id = 61, .static_type = "usize"},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<FixedVec<u8,N>,FixedVec<u8,N>>", &scope);
ZTypeId actual = parse_with_binders_or_die(&arena, "Pair<FixedVec<u8,M>,FixedVec<u8,4>>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, pattern, actual, &trace), "chained static binder pattern did not unify");
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(z_type_substitute(&arena, pattern, &trace, &substituted), "chained static substitution failed");
char *formatted = z_type_format(&arena, substituted);
expect(formatted && strcmp(formatted, "Pair<FixedVec<u8,4>,FixedVec<u8,4>>") == 0, "chained static substitution left an unresolved binder");
free(formatted);
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_concrete_first_static_substitution(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "N", .kind = Z_TYPE_BINDER_STATIC, .id = 62, .static_type = "usize"},
{.name = "M", .kind = Z_TYPE_BINDER_STATIC, .id = 63, .static_type = "usize"},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<FixedVec<u8,N>,FixedVec<u8,N>>", &scope);
ZTypeId actual = parse_with_binders_or_die(&arena, "Pair<FixedVec<u8,4>,FixedVec<u8,M>>", &scope);
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, pattern, actual, &trace), "concrete-first static binder pattern did not unify");
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(z_type_substitute(&arena, actual, &trace, &substituted), "concrete-first static substitution failed");
char *formatted = z_type_format(&arena, substituted);
expect(formatted && strcmp(formatted, "Pair<FixedVec<u8,4>,FixedVec<u8,4>>") == 0, "concrete-first static substitution left an unresolved binder");
free(formatted);
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static bool mixed_arg_kind(const void *context, const char *type_name, size_t arg_index, ZTypeArgKind *out_kind) {
(void)context;
if (!type_name || strcmp(type_name, "Mixed") != 0 || arg_index > 1 || !out_kind) return false;
*out_kind = arg_index == 0 ? Z_TYPE_ARG_TYPE : Z_TYPE_ARG_STATIC;
return true;
}
static void expect_slot_aware_ambiguous_arg_parse(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "Foo", .kind = Z_TYPE_BINDER_STATIC, .id = 63, .static_type = "usize"},
};
ZTypeBinderScope scope = {.items = decls, .len = 1, .arg_kind = mixed_arg_kind};
ZTypeId mixed = parse_with_binders_or_die(&arena, "Mixed<Foo,Foo>", &scope);
expect(z_type_kind(&arena, mixed) == Z_TYPE_NODE_APPLY, "slot-aware parse did not create an applied type");
const ZTypeArg *type_arg = z_type_apply_arg(&arena, mixed, 0);
const ZTypeArg *static_arg = z_type_apply_arg(&arena, mixed, 1);
expect(type_arg && type_arg->kind == Z_TYPE_ARG_TYPE, "ambiguous type slot parsed as static value");
expect(z_type_kind(&arena, type_arg->as.type) == Z_TYPE_NODE_NAME, "ambiguous type slot did not parse as a concrete type");
expect(static_arg && static_arg->kind == Z_TYPE_ARG_STATIC, "ambiguous static slot parsed as a type");
expect(static_arg->as.static_value.kind == Z_STATIC_VALUE_BINDER && static_arg->as.static_value.binder == 63, "ambiguous static slot did not use the static binder");
z_type_arena_free(&arena);
}
static void expect_static_binder_types_are_checked(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "N", .kind = Z_TYPE_BINDER_STATIC, .id = 64, .static_type = "usize"},
{.name = "Flag", .kind = Z_TYPE_BINDER_STATIC, .id = 65, .static_type = "Bool"},
{.name = "ModeValue", .kind = Z_TYPE_BINDER_STATIC, .id = 66, .static_type = "Mode"},
};
ZTypeBinderScope scope = {.items = decls, .len = 3};
ZTypeId integer_pattern = parse_with_binders_or_die(&arena, "FixedVec<u8,N>", &scope);
ZTypeId bool_actual = parse_or_die(&arena, "FixedVec<u8,true>");
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(!z_type_unify(&arena, integer_pattern, bool_actual, &trace), "static integer binder accepted a Bool value");
expect(strstr(trace.message, "static value") != NULL, "static type failure did not leave a trace message");
ZTypeId alias_pattern = parse_with_binders_or_die(&arena, "Pair<N,N>", &scope);
ZTypeId alias_actual = parse_with_binders_or_die(&arena, "Pair<Flag,N>", &scope);
expect(!z_type_unify(&arena, alias_pattern, alias_actual, &trace), "static binders with different declared types unified");
ZTypeId enum_pattern = parse_with_binders_or_die(&arena, "Gate<ModeValue>", &scope);
ZTypeId enum_actual = parse_or_die(&arena, "Gate<Mode.tiny>");
expect(z_type_unify(&arena, enum_pattern, enum_actual, &trace), "enum-like static binder rejected matching symbol value");
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_failed_unify_rolls_back_trace(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 70},
{.name = "U", .kind = Z_TYPE_BINDER_TYPE, .id = 71},
};
ZTypeBinderScope scope = {.items = decls, .len = 2};
ZTypeId pattern = parse_with_binders_or_die(&arena, "Pair<T,T>", &scope);
ZTypeId bad = parse_or_die(&arena, "Pair<i32,String>");
ZTypeId prior_pattern = parse_with_binders_or_die(&arena, "U", &scope);
ZTypeId prior_actual = parse_or_die(&arena, "u8");
ZUnifyTrace trace;
z_unify_trace_init(&trace);
expect(z_type_unify(&arena, prior_pattern, prior_actual, &trace), "prior trace binding did not unify");
expect(trace.len == 1, "prior trace binding was not committed");
expect(!z_type_unify(&arena, pattern, bad, &trace), "conflicting type binder pattern unified successfully");
expect(trace.len == 1, "failed unification did not roll back to the prior trace length");
const ZUnifyBinding *prior_binding = z_unify_trace_lookup(&trace, 71, Z_UNIFY_BINDING_TYPE);
expect(prior_binding != NULL, "failed unification dropped a prior trace binding");
expect(trace.message[0] != 0, "failed unification did not preserve a diagnostic message");
ZTypeId good = parse_or_die(&arena, "Pair<u8,u8>");
expect(z_type_unify(&arena, pattern, good, &trace), "trace was poisoned after failed unification rollback");
expect(trace.message[0] == 0, "successful retry left a stale unification failure message");
expect(trace.len == 2, "successful retry did not commit expected binding count");
const ZUnifyBinding *type_binding = z_unify_trace_lookup(&trace, 70, Z_UNIFY_BINDING_TYPE);
expect(type_binding != NULL, "successful retry did not bind T");
char *bound_type = z_type_format(&arena, type_binding->type);
expect(bound_type && strcmp(bound_type, "u8") == 0, "successful retry bound T to the wrong type");
free(bound_type);
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
static void expect_failed_substitute_rolls_back_arena(void) {
ZTypeArena arena;
z_type_arena_init(&arena);
ZTypeBinderDecl decls[] = {
{.name = "T", .kind = Z_TYPE_BINDER_TYPE, .id = 80},
};
ZTypeBinderScope scope = {.items = decls, .len = 1};
ZTypeId source = parse_with_binders_or_die(&arena, "Tuple<i32,T,u8>", &scope);
ZTypeId recursive = parse_with_binders_or_die(&arena, "T", &scope);
size_t before = arena.len;
ZUnifyTrace trace;
z_unify_trace_init(&trace);
trace.items = calloc(1, sizeof(ZUnifyBinding));
expect(trace.items != NULL, "failed to allocate regression trace");
trace.len = 1;
trace.cap = 1;
trace.items[0] = (ZUnifyBinding){.binder = 80, .kind = Z_UNIFY_BINDING_TYPE, .type = recursive};
ZTypeId substituted = Z_TYPE_ID_INVALID;
expect(!z_type_substitute(&arena, source, &trace, &substituted), "recursive substitution unexpectedly succeeded");
expect(substituted == Z_TYPE_ID_INVALID, "failed substitution returned a type id");
expect(arena.len == before, "failed substitution did not roll back arena");
z_unify_trace_free(&trace);
z_type_arena_free(&arena);
}
int main(void) {
expect_roundtrip("i32", "i32");
expect_roundtrip("const i32", "const i32");
expect_roundtrip("[4]u8", "[4]u8");
expect_roundtrip("[0x10]u8", "[16]u8");
expect_roundtrip("[cap]u8", "[cap]u8");
expect_roundtrip("Span<u8>", "Span<u8>");
expect_roundtrip("MutSpan<Span<u8>>", "MutSpan<Span<u8>>");
expect_roundtrip("Maybe<owned<ByteBuf>>", "Maybe<owned<ByteBuf>>");
expect_roundtrip("Box<trueThing<u8>>", "Box<trueThing<u8>>");
expect_roundtrip("ref<FixedVec<u8, 4>>", "ref<FixedVec<u8,4>>");
expect_roundtrip("mutref<MutSpan<u8>>", "mutref<MutSpan<u8>>");
expect_roundtrip("FixedVec<T,N>", "FixedVec<T,N>");
expect_roundtrip("FixedVec<u8, 4_usize>", "FixedVec<u8,4>");
expect_roundtrip("Gate<true, Mode.tiny>", "Gate<true,Mode.tiny>");
expect_roundtrip("const [4]Maybe<ref<Point>>", "const [4]Maybe<ref<Point>>");
expect_static_roundtrip("42", "42", Z_STATIC_VALUE_NUMBER);
expect_static_roundtrip("4_096", "4096", Z_STATIC_VALUE_NUMBER);
expect_static_roundtrip("0b1010", "10", Z_STATIC_VALUE_NUMBER);
expect_static_roundtrip("true", "true", Z_STATIC_VALUE_BOOL);
expect_static_roundtrip("Mode.tiny", "Mode.tiny", Z_STATIC_VALUE_SYMBOL);
expect_equal_and_hash("FixedVec<u8,4>", "FixedVec<u8,0x4>");
expect_equal_and_hash("Maybe<Span<u8>>", "Maybe<Span<u8>>");
expect_not_equal("FixedVec<u8,4>", "FixedVec<u8,5>");
expect_not_equal("Span<u8>", "MutSpan<u8>");
expect_failed_parse_rewinds();
expect_speculative_arg_rewinds();
expect_binder_identity();
expect_unify_and_substitute();
expect_occurs_check_rejects_recursive_binding();
expect_occurs_check_follows_trace_bindings();
expect_binder_alias_swap_unifies();
expect_chained_type_substitution();
expect_chained_static_substitution();
expect_concrete_first_type_substitution();
expect_concrete_first_static_substitution();
expect_slot_aware_ambiguous_arg_parse();
expect_static_binder_types_are_checked();
expect_failed_unify_rolls_back_trace();
expect_failed_substitute_rolls_back_arena();
expect_invalid_type("");
expect_invalid_type("Span<");
expect_invalid_type("[4");
expect_invalid_type("Maybe<>");
expect_invalid_type("Span<u8,,i32>");
expect_invalid_type("[]u8");
expect_invalid_type("const");
expect_invalid_type("FixedVec<u8,>");
expect_invalid_type("[4_]u8");
expect_invalid_type("[4__5]u8");
expect_invalid_type("[0x_1]u8");
expect_invalid_type("FixedVec<u8,4_nope>");
expect_invalid_type_offset("FixedVec<u8,4_>", 12);
expect_invalid_type_offset("[4_]u8", 1);
expect_invalid_static("");
expect_invalid_static("Mode.");
expect_invalid_static("0x");
expect_invalid_static("4_");
expect_invalid_static("4__5");
expect_invalid_static("0x_1");
expect_invalid_static("4_nope");
printf("type core smoke ok\n");
return 0;
}
`;
try {
writeFileSync(sourcePath, source);
execFileSync(
"cc",
[
"-std=c11",
"-Wall",
"-Wextra",
"-Wpedantic",
"-I",
path.join(repoRoot, "native/zero-c/src"),
sourcePath,
path.join(repoRoot, "native/zero-c/src/type_core.c"),
path.join(repoRoot, "native/zero-c/src/unify.c"),
"-o",
exePath,
],
{ stdio: "inherit" },
);
execFileSync(exePath, [], { stdio: "inherit" });
} finally {
rmSync(sourcePath, { force: true });
rmSync(exePath, { force: true });
}
+272
View File
@@ -0,0 +1,272 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import { spawn } from "node:child_process";
import { mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";
const nodeArgs = ["--experimental-strip-types", "--disable-warning=ExperimentalWarning"];
const reportDir = ".zero/validation";
type Phase = {
name: string;
command: string;
args: string[];
setup?: boolean;
};
type Suite = {
setup: Phase[];
phases: Phase[];
defaultJobs?: number;
};
type PhaseResult = {
name: string;
command: string;
ok: boolean;
code: number | null;
signal: NodeJS.Signals | null;
durationMs: number;
stdout: string;
stderr: string;
};
const suites: Record<string, Suite> = {
conformance: {
setup: [
{ name: "native-build", command: "make", args: ["-C", "native/zero-c"], setup: true },
],
phases: [
{ name: "graph-input-policy", command: process.execPath, args: [...nodeArgs, "scripts/graph-input-policy.mts"] },
{ name: "native-contracts", command: process.execPath, args: [...nodeArgs, "scripts/native-contracts.mts"] },
{ name: "provenance-guardrails", command: process.execPath, args: [...nodeArgs, "scripts/provenance-guardrails.mts"] },
{ name: "type-core-smoke", command: process.execPath, args: [...nodeArgs, "scripts/type-core-smoke.mts"] },
{ name: "mir-verifier-smoke", command: process.execPath, args: [...nodeArgs, "scripts/mir-verifier-smoke.mts"] },
{ name: "program-graph-smoke", command: process.execPath, args: [...nodeArgs, "scripts/program-graph-smoke.mts"] },
{ name: "program-graph-parity", command: process.execPath, args: [...nodeArgs, "scripts/program-graph-parity.mts"] },
{ name: "canonical-text-smoke", command: process.execPath, args: [...nodeArgs, "scripts/canonical-text-smoke.mts"] },
{ name: "examples-gate", command: process.execPath, args: [...nodeArgs, "scripts/examples-gate.mts"] },
{ name: "conformance-run", command: process.execPath, args: ["conformance/run.mjs"] },
],
},
"command-contracts": {
setup: [
{ name: "native-build", command: "make", args: ["-C", "native/zero-c"], setup: true },
],
phases: [
{ name: "graph-input-policy", command: process.execPath, args: [...nodeArgs, "scripts/graph-input-policy.mts"] },
{ name: "snapshot-command-contracts", command: process.execPath, args: [...nodeArgs, "scripts/snapshot-command-contracts.mts"] },
],
},
};
function usage() {
const suiteNames = Object.keys(suites).join("|");
console.log(`Run validation phases with aggregate failure reporting.
Usage:
node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/validation-suite.mts <${suiteNames}> [options]
Options:
--list List phases and exit.
--phases <a,b> Run only the named comma-separated phases after setup.
--shard <index/count> Run only this 1-based phase shard after setup.
--jobs <count> Run selected phases concurrently. Defaults to 1.
--fail-fast Stop after the first failing phase.
Environment:
ZERO_VALIDATION_PHASES Default phase allowlist, for example a,b,c.
ZERO_VALIDATION_SHARD Default shard, for example 1/4.
ZERO_VALIDATION_JOBS Default jobs count.
ZERO_VALIDATION_FAIL_FAST=1 Stop after the first failing phase.`);
}
const rawArgs = process.argv.slice(2);
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
usage();
process.exit(0);
}
const suiteName = rawArgs.find((arg) => !arg.startsWith("--"));
if (!suiteName || !suites[suiteName]) {
usage();
process.exit(2);
}
function optionValue(name: string) {
const index = rawArgs.indexOf(name);
return index === -1 ? undefined : rawArgs[index + 1];
}
function parsePositiveInt(value: string | undefined, fallback: number) {
const parsed = Number.parseInt(value ?? "", 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
function parseShard(value: string | undefined) {
const text = value || process.env.ZERO_VALIDATION_SHARD || "";
if (!text) return null;
const match = /^([1-9][0-9]*)\/([1-9][0-9]*)$/.exec(text);
if (!match) throw new Error(`invalid shard ${text}; expected index/count, for example 1/4`);
const index = Number.parseInt(match[1], 10);
const count = Number.parseInt(match[2], 10);
if (index > count) throw new Error(`invalid shard ${text}; index must be <= count`);
return { index, count, text };
}
function parsePhaseFilter(value: string | undefined, suite: Suite) {
const text = value || process.env.ZERO_VALIDATION_PHASES || "";
if (!text.trim()) return null;
const wanted = new Set(text.split(",").map((part) => part.trim()).filter(Boolean));
const known = new Set(suite.phases.map((phase) => phase.name));
const unknown = [...wanted].filter((name) => !known.has(name));
if (unknown.length > 0) {
throw new Error(`unknown validation phase(s): ${unknown.join(", ")}`);
}
return wanted;
}
const suite = suites[suiteName];
const listOnly = rawArgs.includes("--list");
const phaseFilter = parsePhaseFilter(optionValue("--phases"), suite);
const shard = parseShard(optionValue("--shard"));
const jobs = parsePositiveInt(optionValue("--jobs") ?? process.env.ZERO_VALIDATION_JOBS, suite.defaultJobs ?? 1);
const failFast = rawArgs.includes("--fail-fast") || process.env.ZERO_VALIDATION_FAIL_FAST === "1";
const filteredPhases = phaseFilter
? suite.phases.filter((phase) => phaseFilter.has(phase.name))
: suite.phases;
const selectedPhases = shard
? filteredPhases.filter((_, index) => index % shard.count === shard.index - 1)
: filteredPhases;
if (listOnly) {
for (const phase of suite.setup) console.log(`${phase.name} setup`);
for (const [index, phase] of suite.phases.entries()) {
const selected = selectedPhases.includes(phase)
? "selected"
: phaseFilter && !phaseFilter.has(phase.name) ? "filtered" : "skipped";
console.log(`${index + 1}. ${phase.name} ${selected}`);
}
process.exit(0);
}
function runPhase(phase: Phase): Promise<PhaseResult> {
const startedAt = Date.now();
process.stderr.write(`validation phase start: ${phase.name}\n`);
return new Promise((resolve) => {
const child = spawn(phase.command, phase.args, {
cwd: process.cwd(),
env: process.env,
stdio: ["ignore", "pipe", "pipe"],
});
let stdout = "";
let stderr = "";
child.stdout.on("data", (chunk) => {
const text = chunk.toString();
stdout += text;
process.stdout.write(text);
});
child.stderr.on("data", (chunk) => {
const text = chunk.toString();
stderr += text;
process.stderr.write(text);
});
child.on("error", (error) => {
stderr += `${error.message}\n`;
});
child.on("close", (code, signal) => {
const durationMs = Date.now() - startedAt;
const ok = code === 0 && signal === null;
process.stderr.write(`validation phase ${ok ? "ok" : "failed"}: ${phase.name} (${durationMs}ms)\n`);
resolve({
name: phase.name,
command: [phase.command, ...phase.args].join(" "),
ok,
code,
signal,
durationMs,
stdout,
stderr,
});
});
});
}
async function runSequential(phases: Phase[]) {
const results: PhaseResult[] = [];
for (const phase of phases) {
const result = await runPhase(phase);
results.push(result);
if (!result.ok && failFast) break;
}
return results;
}
async function runConcurrent(phases: Phase[]) {
const results: PhaseResult[] = [];
let next = 0;
let stop = false;
const workerCount = Math.min(jobs, Math.max(1, phases.length));
async function worker() {
for (;;) {
if (stop) return;
const index = next++;
if (index >= phases.length) return;
const result = await runPhase(phases[index]);
results[index] = result;
if (!result.ok && failFast) stop = true;
}
}
await Promise.all(Array.from({ length: workerCount }, () => worker()));
return results.filter(Boolean);
}
function printFailures(results: any[]) {
const failures = results.filter((result) => !result.ok);
if (failures.length === 0) return;
process.stderr.write(`\n${suiteName} collected ${failures.length} failing phase(s):\n`);
for (const [index, failure] of failures.entries()) {
process.stderr.write(`\n${index + 1}. ${failure.name}\n`);
process.stderr.write(` command: ${failure.command}\n`);
process.stderr.write(` exit: ${failure.code ?? "signal"}${failure.signal ? ` signal ${failure.signal}` : ""}\n`);
const detail = (failure.stderr || failure.stdout || "").trim().split("\n").slice(-40).join("\n");
if (detail) process.stderr.write(`${detail}\n`);
}
}
async function main() {
mkdirSync(reportDir, { recursive: true });
const startedAt = Date.now();
const setupResults = await runSequential(suite.setup);
const setupFailed = setupResults.some((result) => !result.ok);
const phaseResults = setupFailed && failFast
? []
: jobs > 1 ? await runConcurrent(selectedPhases) : await runSequential(selectedPhases);
const results = [...setupResults, ...phaseResults];
const ok = results.every((result) => result.ok);
const report = {
suite: suiteName,
ok,
phases: phaseFilter ? [...phaseFilter] : null,
shard: shard?.text ?? null,
jobs,
failFast,
durationMs: Date.now() - startedAt,
results,
};
const reportPath = join(reportDir, `${suiteName}${shard ? `-shard-${shard.index}-of-${shard.count}` : ""}.json`);
writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}\n`);
printFailures(results);
if (!ok) {
process.stderr.write(`\nvalidation suite failed: ${suiteName}\nreport: ${reportPath}\n`);
process.exit(1);
}
process.stderr.write(`validation suite ok: ${suiteName}\nreport: ${reportPath}\n`);
}
main().catch((error) => {
console.error(error instanceof Error ? error.stack || error.message : String(error));
process.exit(1);
});
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$root"
make -C native/zero-c
embedded_skills_before="/tmp/zero-embedded-skills-$$.inc"
cp native/zero-c/src/embedded_skills.inc "$embedded_skills_before"
node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/embed-skill-data.mts
if ! cmp -s "$embedded_skills_before" native/zero-c/src/embedded_skills.inc; then
diff -u "$embedded_skills_before" native/zero-c/src/embedded_skills.inc
rm -f "$embedded_skills_before"
exit 1
fi
rm -f "$embedded_skills_before"
pnpm run check
pnpm run repository-graph:check
pnpm run rosetta:local
pnpm run stdlib:contracts
pnpm run test:zero
pnpm run extension:test
if [[ -n "${VERCEL_OIDC_TOKEN:-}" ]]; then
ZERO_BENCH_RUNS=1 pnpm run bench:budgets
else
ZERO_BENCH_RUNS=1 ZERO_BENCH_BUDGET=warn pnpm run bench:local
fi
bin/zero check --target linux-musl-x64 examples/memory-package
bin/zero build --emit obj --target linux-musl-x64 examples/direct-obj-add.graph --out .zero/out/direct-obj-add-linux-musl.o
bin/zero build --target linux-musl-x64 examples/hello.graph --out .zero/out/hello-linux-musl
bin/zero build --target win32-x64.exe examples/hello.graph --out .zero/out/hello-win32
mkdir -p .zero/ci-release
node --experimental-strip-types --disable-warning=ExperimentalWarning scripts/embed-skill-data.mts
build_hash="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
ZIG_GLOBAL_CACHE_DIR=.zero/zig-global-cache ZIG_LOCAL_CACHE_DIR=.zero/zig-local-cache zig cc -target x86_64-linux-musl -std=c11 -D_POSIX_C_SOURCE=200809L -DZERO_BUILD_HASH="\"$build_hash\"" -Os -Inative/zero-c/include native/zero-c/src/*.c -o .zero/ci-release/zero-linux-musl-x64
test -s .zero/ci-release/zero-linux-musl-x64
if [[ "$(uname -s):$(uname -m)" == "Linux:x86_64" ]]; then
./.zero/ci-release/zero-linux-musl-x64 --version
./.zero/ci-release/zero-linux-musl-x64 skills list --json
fi
+563
View File
@@ -0,0 +1,563 @@
#!/usr/bin/env -S node --experimental-strip-types --disable-warning=ExperimentalWarning
import assert from "node:assert/strict";
import { execFile } from "node:child_process";
import { readFile, writeFile, mkdir } from "node:fs/promises";
import { fileURLToPath, pathToFileURL } from "node:url";
import { dirname, join } from "node:path";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
const zero = "bin/zero";
const documents = new Map();
const symbols = new Map();
const documentFacts = new Map();
function uriToPath(uri) {
return uri && uri.startsWith("file://") ? fileURLToPath(uri) : uri;
}
function pathToUri(path) {
return pathToFileURL(path).href;
}
function graphSidecarPath(path) {
return path.endsWith(".0") ? `${path.slice(0, -2)}.graph` : null;
}
function diagnosticsFromBody(body) {
return (body?.diagnostics ?? []).map((diag) => ({
range: {
start: { line: Math.max(0, diag.line - 1), character: Math.max(0, diag.column - 1) },
end: { line: Math.max(0, diag.line - 1), character: Math.max(0, diag.column) },
},
severity: 1,
code: diag.code,
source: "zero",
message: diag.message,
data: { repair: diag.repair, fixSafety: diag.fixSafety },
}));
}
async function importProjectionSidecar(path) {
const sidecar = graphSidecarPath(path);
if (!sidecar) return null;
const result = await execFileAsync(zero, ["import", "--json", "--format", "binary", "--out", sidecar, path]).catch((error) => error);
if (!result.stdout) return null;
try {
return JSON.parse(result.stdout);
} catch {
return null;
}
}
function positionAt(text, offset) {
const prefix = text.slice(0, offset);
const lines = prefix.split("\n");
return { line: lines.length - 1, character: lines[lines.length - 1].length };
}
function offsetAt(text, position) {
const lines = text.split("\n");
let offset = 0;
for (let i = 0; i < Math.min(position.line, lines.length); i++) offset += lines[i].length + 1;
return offset + Math.min(position.character, lines[position.line]?.length ?? 0);
}
function wordAt(text, position) {
const offset = offsetAt(text, position);
let start = offset;
let end = offset;
while (start > 0 && /[A-Za-z0-9_]/.test(text[start - 1])) start--;
while (end < text.length && /[A-Za-z0-9_]/.test(text[end])) end++;
return text.slice(start, end);
}
function rangeForLine(line, start, end) {
return {
start: { line, character: start },
end: { line, character: end },
};
}
function symbolKind(kind) {
return {
function: 12,
shape: 23,
enum: 10,
choice: 23,
interface: 11,
const: 14,
alias: 5,
"type-alias": 5,
type: 5,
}[kind] ?? 13;
}
function analyzeText(uri, text) {
const found = [];
const lines = text.split("\n");
const declaration = /^\s*(?:pub\s+)?(?:(export\s+c)\s+)?(?:(extern|packed)\s+)?(fn|type|enum|choice|interface|const|alias)\s+([A-Za-z_][A-Za-z0-9_]*)/;
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
const match = lines[lineIndex].match(declaration);
if (!match) continue;
const kind = match[3] === "fn" ? "function" : match[3];
const name = match[4];
const start = lines[lineIndex].indexOf(name);
found.push({
name,
kind,
detail: lines[lineIndex].trim(),
uri,
range: rangeForLine(lineIndex, start, start + name.length),
selectionRange: rangeForLine(lineIndex, start, start + name.length),
});
}
symbols.set(uri, found);
return found;
}
function simpleDiagnostics(uri, text) {
const diagnostics = [];
let balance = 0;
for (let i = 0; i < text.length; i++) {
if (text[i] === "{") balance++;
if (text[i] === "}") balance--;
if (balance < 0) {
diagnostics.push({
range: { start: positionAt(text, i), end: positionAt(text, i + 1) },
severity: 1,
code: "PAR100",
source: "zero",
message: "unmatched closing brace",
});
balance = 0;
}
}
if (balance > 0) {
diagnostics.push({
range: { start: positionAt(text, text.length), end: positionAt(text, text.length) },
severity: 1,
code: "PAR100",
source: "zero",
message: "missing closing brace",
});
}
return diagnostics;
}
async function compilerDiagnostics(uri, text) {
const path = uriToPath(uri);
try {
await writeFile(path, text);
const sidecar = graphSidecarPath(path);
const imported = await importProjectionSidecar(path);
if (imported && imported.ok === false) return diagnosticsFromBody(imported);
const input = sidecar && imported ? sidecar : path;
const result = await execFileAsync(zero, ["check", "--json", input]).catch((error) => error);
if (!result.stdout) return simpleDiagnostics(uri, text);
const body = JSON.parse(result.stdout);
return diagnosticsFromBody(body);
} catch {
return simpleDiagnostics(uri, text);
}
}
async function compilerFacts(path) {
const sidecar = graphSidecarPath(path);
const imported = await importProjectionSidecar(path);
const input = sidecar && imported ? sidecar : path;
const [graphResult, sizeResult, memResult, docResult] = await Promise.all([
execFileAsync(zero, ["inspect", "--json", input]).catch((error) => error),
execFileAsync(zero, ["size", "--json", input]).catch((error) => error),
execFileAsync(zero, ["mem", "--json", input]).catch((error) => error),
execFileAsync(zero, ["doc", "--json", input]).catch((error) => error),
]);
const parseBody = (result) => {
if (!result.stdout) return null;
try {
return JSON.parse(result.stdout);
} catch {
return null;
}
};
const graph = parseBody(graphResult);
const size = parseBody(sizeResult);
const mem = parseBody(memResult);
const doc = parseBody(docResult);
return {
schemaVersion: 1,
sourceFile: graph?.sourceFile ?? size?.sourceFile ?? mem?.sourceFile ?? path,
generatedCBytes: Math.max(graph?.generatedCBytes ?? 0, size?.generatedCBytes ?? 0, mem?.generatedCBytes ?? 0, doc?.generatedCBytes ?? 0),
cBridgeFallback: Boolean(
graph?.selfHostRouting?.cBridge?.required ??
size?.selfHostRouting?.cBridge?.required ??
mem?.cBridgeFallback ??
doc?.cBridgeFallback ??
false
),
targetCapabilityFacts: graph?.targetSupport ?? size?.targetSupport ?? null,
directBackendStatus: {
graph: graph?.selfHostRouting ?? null,
objectBackend: size?.objectBackend ?? mem?.objectBackend ?? null,
},
generatedBindingPreviews: (graph?.cImports ?? []).map((item) => ({
header: item.header,
alias: item.alias,
functions: item.typedModel?.functions?.map((fn) => fn.name) ?? [],
constants: item.typedModel?.constants?.map((constant) => constant.name) ?? [],
structs: item.typedModel?.structs?.map((shape) => shape.name) ?? [],
})),
runtimeHelperCosts: {
usedStdlibHelpers: size?.usedStdlibHelpers ?? [],
runtimeShims: size?.runtimeShims ?? [],
compilerRuntimeHelpers: size?.compilerRuntimeHelpers ?? [],
},
memoryBudget: {
sections: mem?.sections ?? [],
stackBytes: mem?.stackBytes ?? null,
heapBytes: mem?.heapBytes ?? null,
staticBytes: mem?.staticBytes ?? null,
},
docs: {
publicSymbols: doc?.symbols ?? [],
requiresCapabilities: doc?.requiresCapabilities ?? [],
},
};
}
function completionItems() {
const keywordItems = [
"pub",
"fn",
"type",
"enum",
"choice",
"interface",
"alias",
"const",
"let",
"var",
"return",
"if",
"else",
"while",
"for",
"match",
"check",
"rescue",
"raise",
"raises",
"use",
"extern",
"packed",
"static",
"meta",
"test",
"break",
"continue",
"defer",
].map((label) => ({ label, kind: 14 }));
const symbolItems = [...symbols.values()].flat().map((symbol) => ({ label: symbol.name, kind: symbolKind(symbol.kind), detail: symbol.detail }));
return [...keywordItems, ...symbolItems];
}
function findSymbol(name) {
for (const list of symbols.values()) {
const found = list.find((symbol) => symbol.name === name);
if (found) return found;
}
return null;
}
function hover(params) {
const doc = documents.get(params.textDocument.uri);
const name = doc ? wordAt(doc.text, params.position) : "";
const symbol = findSymbol(name);
if (!symbol) return null;
const facts = documentFacts.get(params.textDocument.uri);
const directStatus = facts?.directBackendStatus?.objectBackend?.targetFacts?.directStatus ?? facts?.targetCapabilityFacts?.requiredCapabilitySupport?.status ?? "unknown";
const target = facts?.targetCapabilityFacts?.target ?? "host";
const capabilities = (facts?.docs?.requiresCapabilities ?? []).map((item) => item.name ?? item).filter(Boolean).join(", ") || "none";
const bindingPreview = (facts?.generatedBindingPreviews ?? [])
.map((item) => `${item.alias ?? item.header}: ${(item.functions ?? []).slice(0, 3).join(", ") || "typed header"}`)
.join("; ") || "none";
return {
contents: {
kind: "markdown",
value: `\`${symbol.detail}\`\n\nkind: ${symbol.kind}\n\ntarget: ${target}\n\ncapabilities: ${capabilities}\n\ndirect backend: ${directStatus}\n\ngenerated binding previews: ${bindingPreview}\n\ngeneratedCBytes: ${facts?.generatedCBytes ?? 0}`,
},
range: symbol.selectionRange,
};
}
function documentSymbols(params) {
const uri = params.textDocument.uri;
return (symbols.get(uri) ?? []).map((symbol) => ({
name: symbol.name,
kind: symbolKind(symbol.kind),
detail: symbol.detail,
range: symbol.range,
selectionRange: symbol.selectionRange,
}));
}
function signatureHelp(params) {
const doc = documents.get(params.textDocument.uri);
if (!doc) return { signatures: [], activeSignature: 0, activeParameter: 0 };
const offset = offsetAt(doc.text, params.position);
const before = doc.text.slice(0, offset);
const call = before.match(/([A-Za-z_][A-Za-z0-9_]*)\([^()]*$/);
const symbol = call ? findSymbol(call[1]) : null;
return {
signatures: symbol ? [{ label: symbol.detail, parameters: [] }] : [],
activeSignature: 0,
activeParameter: 0,
};
}
function definition(params) {
const doc = documents.get(params.textDocument.uri);
const name = doc ? wordAt(doc.text, params.position) : "";
const symbol = findSymbol(name);
return symbol ? { uri: symbol.uri, range: symbol.selectionRange } : null;
}
function references(params) {
const doc = documents.get(params.textDocument.uri);
if (!doc) return [];
const name = wordAt(doc.text, params.position);
const locations = [];
const pattern = new RegExp(`\\b${name}\\b`, "g");
let match = null;
while ((match = pattern.exec(doc.text)) !== null) {
const start = positionAt(doc.text, match.index);
locations.push({ uri: params.textDocument.uri, range: { start, end: { line: start.line, character: start.character + name.length } } });
}
return locations;
}
function rename(params) {
const refs = references(params);
return {
changes: {
[params.textDocument.uri]: refs.map((location) => ({ range: location.range, newText: params.newName })),
},
};
}
async function codeActions(params) {
const path = uriToPath(params.textDocument.uri);
const diagnosticActions = (params.context?.diagnostics ?? [])
.filter((diagnostic) => diagnostic.data?.repair?.id)
.map((diagnostic) => ({
title: diagnostic.data.repair.summary ?? `Repair ${diagnostic.code}`,
kind: "quickfix",
diagnostics: [diagnostic],
data: {
id: diagnostic.data.repair.id,
diagnosticCode: diagnostic.code,
safety: diagnostic.data.fixSafety ?? "requires-human-review",
patches: [],
},
}));
const result = await execFileAsync(zero, ["fix", "--patch", "--json", path]).catch((error) => error);
if (!result.stdout) return diagnosticActions;
const body = JSON.parse(result.stdout);
const patchActions = (body.fixes ?? []).map((fix) => ({
title: fix.summary,
kind: "quickfix",
diagnostics: params.context?.diagnostics ?? [],
data: {
id: fix.id,
diagnosticCode: fix.diagnosticCode,
safety: fix.safety,
patches: body.patches ?? [],
},
}));
return [...diagnosticActions, ...patchActions];
}
async function didOpen(params, send) {
const { uri, text } = params.textDocument;
documents.set(uri, { text, version: params.textDocument.version ?? 0 });
analyzeText(uri, text);
const diagnostics = await compilerDiagnostics(uri, text);
send("textDocument/publishDiagnostics", { uri, diagnostics });
const facts = await compilerFacts(uriToPath(uri));
documentFacts.set(uri, facts);
send("zero/editorMetadata", { uri, facts });
}
async function didChange(params, send) {
const uri = params.textDocument.uri;
const text = params.contentChanges.at(-1)?.text ?? documents.get(uri)?.text ?? "";
documents.set(uri, { text, version: params.textDocument.version ?? 0 });
analyzeText(uri, text);
const diagnostics = await compilerDiagnostics(uri, text);
send("textDocument/publishDiagnostics", { uri, diagnostics });
const facts = await compilerFacts(uriToPath(uri));
documentFacts.set(uri, facts);
send("zero/editorMetadata", { uri, facts });
}
function workspaceSymbols(query) {
return [...symbols.values()].flat()
.filter((symbol) => !query || symbol.name.toLowerCase().includes(query.toLowerCase()))
.map((symbol) => ({ name: symbol.name, kind: symbolKind(symbol.kind), location: { uri: symbol.uri, range: symbol.selectionRange } }));
}
async function handle(method, params, send) {
if (method === "initialize") {
return {
capabilities: {
textDocumentSync: 2,
workspaceSymbolProvider: true,
completionProvider: { triggerCharacters: ["."] },
hoverProvider: true,
signatureHelpProvider: { triggerCharacters: ["("] },
definitionProvider: true,
documentSymbolProvider: true,
referencesProvider: true,
renameProvider: true,
codeActionProvider: true,
},
};
}
if (method === "textDocument/didOpen") return didOpen(params, send);
if (method === "textDocument/didChange") return didChange(params, send);
if (method === "workspace/symbol") return workspaceSymbols(params.query ?? "");
if (method === "textDocument/completion") return completionItems();
if (method === "textDocument/hover") return hover(params);
if (method === "textDocument/signatureHelp") return signatureHelp(params);
if (method === "textDocument/definition") return definition(params);
if (method === "textDocument/documentSymbol") return documentSymbols(params);
if (method === "textDocument/references") return references(params);
if (method === "textDocument/rename") return rename(params);
if (method === "textDocument/codeAction") return codeActions(params);
return null;
}
function sendMessage(message) {
const json = JSON.stringify(message);
process.stdout.write(`Content-Length: ${Buffer.byteLength(json, "utf8")}\r\n\r\n${json}`);
}
function startServer() {
let buffer = Buffer.alloc(0);
const send = (method, params) => sendMessage({ jsonrpc: "2.0", method, params });
process.stdin.on("data", async (chunk) => {
const data = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
buffer = Buffer.concat([buffer, data]);
while (true) {
const headerEnd = buffer.indexOf("\r\n\r\n");
if (headerEnd < 0) return;
const header = buffer.slice(0, headerEnd).toString("utf8");
const match = header.match(/Content-Length: (\d+)/i);
if (!match) return;
const length = Number(match[1]);
const bodyStart = headerEnd + 4;
if (buffer.length < bodyStart + length) return;
const body = buffer.slice(bodyStart, bodyStart + length).toString("utf8");
buffer = buffer.slice(bodyStart + length);
const message = JSON.parse(body);
if (message.method === "exit") process.exit(0);
const result = await handle(message.method, message.params ?? {}, send);
if (Object.hasOwn(message, "id")) sendMessage({ jsonrpc: "2.0", id: message.id, result });
}
});
}
async function selfTest() {
const dir = ".zero/lsp";
await mkdir(dir, { recursive: true });
const path = join(dir, "sample.0");
const uri = pathToUri(path);
const text = "pub fn add(a: i32, b: i32) -> i32 {\n return a + b\n}\n\npub fn main(world: World) -> Void raises {\n check world.out.write(\"ok\\n\")\n}\n";
await writeFile(path, text);
const notifications = [];
await didOpen({ textDocument: { uri, text, version: 1 } }, (method, params) => notifications.push({ method, params }));
const metadata = notifications.find((item) => item.method === "zero/editorMetadata")?.params?.facts;
assert.equal(metadata.generatedCBytes, 0);
assert.equal(metadata.cBridgeFallback, false);
assert(metadata.targetCapabilityFacts);
assert(metadata.runtimeHelperCosts.usedStdlibHelpers.length >= 0);
assert(Array.isArray(metadata.memoryBudget.sections));
assert(metadata.directBackendStatus.objectBackend);
assert(Array.isArray(metadata.generatedBindingPreviews));
assert(symbols.get(uri).some((symbol) => symbol.name === "add"));
assert(notifications.some((item) => item.method === "textDocument/publishDiagnostics"));
assert(workspaceSymbols("add").some((symbol) => symbol.name === "add"));
const completions = completionItems();
assert(completions.some((item) => item.label === "add"));
assert(completions.some((item) => item.label === "fn"));
assert(completions.some((item) => item.label === "return"));
assert(!completions.some((item) => item.label === "fun"));
assert(completions.some((item) => item.label === "raises"));
const hoverText = hover({ textDocument: { uri }, position: { line: 0, character: 9 } }).contents.value;
assert(hoverText.includes("add"));
assert(hoverText.includes("capabilities:"));
assert(hoverText.includes("generated binding previews:"));
assert(hoverText.includes("generatedCBytes: 0"));
assert(documentSymbols({ textDocument: { uri } }).some((symbol) => symbol.name === "add"));
assert(signatureHelp({ textDocument: { uri }, position: { line: 4, character: 20 } }).signatures.length >= 0);
assert(definition({ textDocument: { uri }, position: { line: 0, character: 9 } }).uri === uri);
assert(references({ textDocument: { uri }, position: { line: 0, character: 9 } }).length >= 1);
assert(rename({ textDocument: { uri }, position: { line: 0, character: 9 }, newName: "sum" }).changes[uri].length >= 1);
const mutableFixPath = join(dir, "mutable-fix.0");
const mutableFixUri = pathToUri(mutableFixPath);
const mutableFixText = "pub fn main() -> Void {\n let dst: [2]u8 = [0_u8; 2]\n let src: [2]u8 = [1_u8; 2]\n std.mem.copy(dst, src)\n}\n";
await writeFile(mutableFixPath, mutableFixText);
const mutableNotifications = [];
await didOpen({ textDocument: { uri: mutableFixUri, text: mutableFixText, version: 1 } }, (method, params) => mutableNotifications.push({ method, params }));
const mutableDiagnostics = mutableNotifications.find((item) => item.method === "textDocument/publishDiagnostics")?.params?.diagnostics ?? [];
const actions = await codeActions({ textDocument: { uri: mutableFixUri }, context: { diagnostics: mutableDiagnostics } });
assert(actions.some((action) => action.data.id === "make-binding-mutable"));
const targetActions = await codeActions({
textDocument: { uri },
context: {
diagnostics: [{
code: "TAR002",
message: "target does not provide hosted filesystem capability",
data: { repair: { id: "choose-target-with-required-capability", summary: "Build for a target with the required capability or move the code behind a target-specific entry point." }, fixSafety: "requires-human-review" },
}],
},
});
assert(targetActions.some((action) => action.data.id === "choose-target-with-required-capability"));
const typeAnnotationActions = await codeActions({
textDocument: { uri },
context: {
diagnostics: [{
code: "PUB001",
message: "public declaration requires explicit type metadata",
data: { repair: { id: "add-public-api-type", summary: "Add an explicit public type annotation so graph and docs metadata stay stable." }, fixSafety: "behavior-preserving" },
}],
},
});
assert(typeAnnotationActions.some((action) => action.data.id === "add-public-api-type"));
const errorSetActions = await codeActions({
textDocument: { uri },
context: {
diagnostics: [
{
code: "ERR002",
message: "caller error set is missing a callee error",
data: { repair: { id: "add-missing-error-name", summary: "Add the missing error name to the caller `raises [...]` set." }, fixSafety: "api-changing" },
},
{
code: "ERR003",
message: "fallible call requires check or rescue",
data: { repair: { id: "check-or-rescue-fallible-call", summary: "Wrap the fallible call with check or handle it locally with rescue." }, fixSafety: "api-changing" },
},
],
},
});
assert(errorSetActions.some((action) => action.data.id === "add-missing-error-name"));
assert(errorSetActions.some((action) => action.data.id === "check-or-rescue-fallible-call"));
console.log("zls self-test ok");
}
if (process.argv.includes("--self-test")) {
await selfTest();
} else {
startServer();
}