Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/dispatcher/src/grant-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ export const RUN_GRANTS: Readonly<Record<string, RunGrant>> = {
// capability, not from the container — so `cf-api` is deliberately absent.
"finops-audit": { profiles: ["public-repo-read"], rollout: "legacy" },
"contextful-measures": { profiles: ["public-repo-read", "rust-install"], rollout: "legacy" },
"contextful-protocol": { profiles: ["public-repo-read", "rust-install"], rollout: "legacy", facadeGaps: ["container-artifact"] },
// The parent uses Worker-side GitHub and child-run capabilities only.
"contextful-release": { profiles: [], rollout: "legacy" },
// Cells and the formula clone the public tree, build with Cargo, and upload
// container artifacts; the substrate facade does not serve that upload yet.
"contextful-release-cell": {
profiles: ["public-repo-read", "rust-install"], rollout: "legacy",
facadeGaps: ["container-artifact"],
},
"contextful-release-formula": {
profiles: ["public-repo-read", "rust-install"], rollout: "legacy",
facadeGaps: ["container-artifact"],
},

// --- deploy --------------------------------------------------------------
// `cf-api` is where `wrangler deploy` sends its bytes; `wrangler` itself
Expand Down
1 change: 1 addition & 0 deletions apps/dispatcher/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ describe("GET /health", () => {
"ci-triage-pr",
"contextful-gate",
"contextful-measures",
"contextful-protocol",
"contextful-release",
"contextful-release-cell",
"contextful-release-formula",
Expand Down
2 changes: 2 additions & 0 deletions apps/dispatcher/src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ciTriagePr,
contextfulGate,
contextfulMeasures,
contextfulProtocol,
demoReel,
deploySmoke,
emailOtpLogin,
Expand Down Expand Up @@ -78,6 +79,7 @@ const RUN_REGISTRY: Record<string, Run<unknown, unknown>> = {
[emailOtpLogin.name]: emailOtpLogin as Run<unknown, unknown>,
[finopsAudit.name]: finopsAudit as Run<unknown, unknown>,
[contextfulMeasures.name]: contextfulMeasures as Run<unknown, unknown>,
[contextfulProtocol.name]: contextfulProtocol as Run<unknown, unknown>,
[workerDeploy.name]: workerDeploy as Run<unknown, unknown>,
// Presentation stage for a captured demo: consumes a product-demo
// execution's demo-bundle/v1 and renders a deck (+ MP4 when the image
Expand Down
155 changes: 155 additions & 0 deletions runs/contextful-protocol.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { it } from "@effect/vitest";
import { spawnSync } from "node:child_process";
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { Effect, Exit } from "effect";
import { describe, expect } from "vitest";
import { makeCFRuntimeTest } from "@fractalboxdev/flare-dispatch-core/testing";
import { contextfulProtocol, protocolCommand } from "./contextful-protocol";

const sha = "a".repeat(40);
const input = { repo: "fractalboxdev/contextful", ref: "refs/heads/main", firedAt: 1791253020000 };

describe("contextful-protocol", () => {
it("restores the installed Lean environment in a fresh command process", () => {
const dir = mkdtempSync(join(tmpdir(), "protocol-command-"));
try {
const elanHome = join(dir, "elan");
mkdirSync(join(elanHome, "bin"), { recursive: true });
mkdirSync(join(dir, "formal"));
writeFileSync(join(dir, "formal/lean-toolchain"), "leanprover/lean4:v4.29.1\n");
writeFileSync(
join(elanHome, "bin/cargo"),
`#!${process.execPath}\nconsole.log(JSON.stringify({toolchain:process.env.ELAN_TOOLCHAIN,requireLean:process.env.CONTEXTFUL_REQUIRE_LEAN,path:process.env.PATH,args:process.argv.slice(2)}));\n`,
{ mode: 0o755 },
);
const result = spawnSync("sh", ["-c", protocolCommand("123")], {
cwd: dir,
env: {
...process.env,
ELAN_HOME: elanHome,
ELAN_TOOLCHAIN: "unrelated",
CONTEXTFUL_REQUIRE_LEAN: "0",
},
encoding: "utf8",
});
expect(result.status).toBe(0);
const observed = JSON.parse(result.stdout);
expect(observed.toolchain).toBe("leanprover/lean4:v4.29.1");
expect(observed.requireLean).toBe("1");
expect(observed.path.split(":")[0]).toBe(join(elanHome, "bin"));
expect(observed.args.slice(-6)).toEqual([
"formal",
"protocol-differential",
"--seed",
"123",
"--cases",
"256",
]);
} finally {
rmSync(dir, { recursive: true, force: true });
}
}, 30000);
it("routes the weekly schedule with one identity per tick", () => {
const schedule = contextfulProtocol.schedules?.[0];
expect(schedule?.cron).toBe("17 3 * * 0");
expect(schedule?.inputs({ cron: "17 3 * * 0", firedAt: input.firedAt })).toEqual(input);
expect(schedule?.idempotencyKey({ cron: "17 3 * * 0", firedAt: input.firedAt })).toBe(
`contextful-protocol:${input.firedAt}`,
);
});

it.effect("checks the pinned model before exploring a checkpointed fresh u64 seed", () => {
const { layer, handles } = makeCFRuntimeTest({
github: { branchHeads: { "fractalboxdev/contextful:main": sha } },
sandboxProgram: {
"gate --predecessors --stage toolchain": { exitCode: 0 },
randomBytes: { exitCode: 0, stdout: "18446744073709551615\n" },
"protocol-differential": { exitCode: 0 },
"formal check": { exitCode: 0 },
},
});
return Effect.gen(function* () {
const out = yield* contextfulProtocol.run(input);
expect(out.commit).toBe(sha);
expect(out.seed).toBe("18446744073709551615");
expect(handles.sandbox.clones).toEqual([{ repo: input.repo, sha }]);
const commands = handles.sandbox.execs.map((exec) => exec.command);
expect(commands[0]).toContain("gate --predecessors --stage toolchain");
expect(commands[1]).toContain("formal check");
expect(commands[3]).toBe(protocolCommand(out.seed));
expect(commands[3]).toContain('export PATH="${ELAN_HOME:-$HOME/.elan}/bin:$PATH"');
expect(commands[3]).toContain('export ELAN_TOOLCHAIN="$(cat formal/lean-toolchain)"');
expect(commands[3]).toContain("--no-default-features");
expect(commands[3]).toContain("--cases 256");
expect(handles.artifact.uploads).toHaveLength(3);
}).pipe(Effect.provide(layer));
});

it.effect(
"preserves the failing seed, log and reduced regressions before reporting drift",
() => {
const { layer, handles } = makeCFRuntimeTest({
github: { branchHeads: { "fractalboxdev/contextful:main": sha } },
sandboxProgram: {
"gate --predecessors --stage toolchain": { exitCode: 0 },
randomBytes: { exitCode: 0, stdout: "123\n" },
"protocol-differential": { exitCode: 3 },
"formal check": { exitCode: 0 },
},
sandboxFiles: {
"/workspace/contextful/formal/protocol/regressions.jsonl": '{"seed":123}\n',
},
});
return Effect.gen(function* () {
const out = yield* Effect.exit(contextfulProtocol.run(input));
expect(Exit.isFailure(out)).toBe(true);
expect(handles.artifact.uploads.map((upload) => upload.name)).toContain(
"protocol-regressions.jsonl",
);
expect(handles.sandbox.execs[3]?.command).toContain("--seed 123");
}).pipe(Effect.provide(layer));
},
);

it.effect("rejects a different repository before allocating a sandbox", () => {
const { layer, handles } = makeCFRuntimeTest({});
return Effect.gen(function* () {
const out = yield* Effect.exit(contextfulProtocol.run({ ...input, repo: "other/repo" }));
expect(Exit.isFailure(out)).toBe(true);
expect(handles.sandbox.clones).toHaveLength(0);
}).pipe(Effect.provide(layer));
});

it.effect("keeps malformed seed output out of the shell command", () => {
const { layer, handles } = makeCFRuntimeTest({
github: { branchHeads: { "fractalboxdev/contextful:main": sha } },
sandboxProgram: {
"gate --predecessors --stage toolchain": { exitCode: 0 },
randomBytes: { exitCode: 0, stdout: "123; touch injected\n" },
"formal check": { exitCode: 0 },
},
});
return Effect.gen(function* () {
const out = yield* Effect.exit(contextfulProtocol.run(input));
expect(Exit.isFailure(out)).toBe(true);
expect(handles.sandbox.execs).toHaveLength(3);
}).pipe(Effect.provide(layer));
});

it.effect("retains the toolchain failure log and starts no model check", () => {
const { layer, handles } = makeCFRuntimeTest({
github: { branchHeads: { "fractalboxdev/contextful:main": sha } },
sandboxProgram: { "gate --predecessors --stage toolchain": { exitCode: 7 } },
});
return Effect.gen(function* () {
const out = yield* Effect.exit(contextfulProtocol.run(input));
expect(Exit.isFailure(out)).toBe(true);
expect(handles.sandbox.execs).toHaveLength(1);
expect(handles.artifact.uploads.map((upload) => upload.name)).toEqual([
"protocol-toolchain.log",
]);
}).pipe(Effect.provide(layer));
});
});
175 changes: 175 additions & 0 deletions runs/contextful-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { Effect, Schema } from "effect";
import {
AcceptanceFailed,
artifact,
defineRun,
github,
sandbox,
StepFailed,
step,
} from "@fractalboxdev/flare-dispatch-core";
import { workspace } from "@fractalboxdev/flare-dispatch-core/primitives";

const REPO = "fractalboxdev/contextful";
const REF = "refs/heads/main";
const TOOLCHAIN_COMMAND =
"cargo run --locked -q -p contextful-ci -- gate --predecessors --stage toolchain";
const PINNED_ENVIRONMENT =
'export PATH="${ELAN_HOME:-$HOME/.elan}/bin:$PATH"; export ELAN_TOOLCHAIN="$(cat formal/lean-toolchain)"; export CONTEXTFUL_REQUIRE_LEAN=1; ';
const FORMAL_COMMAND = `${PINNED_ENVIRONMENT}cargo run --locked -q -p contextful-cli --no-default-features --bin contextful -- formal check`;
const SEED_COMMAND = `node -e 'console.log(require("node:crypto").randomBytes(8).readBigUInt64LE().toString())'`;
const REGRESSIONS = "formal/protocol/regressions.jsonl";
const COMMAND_TIMEOUT_SEC = 1800;
const Input = Schema.Struct({ repo: Schema.String, ref: Schema.String, firedAt: Schema.Number });
const Output = Schema.Struct({ commit: Schema.String, seed: Schema.String, logUrl: Schema.String });

/** The gate installs elan; the separate command restores its pinned executable environment. */
export const protocolCommand = (seed: string): string =>
`${PINNED_ENVIRONMENT}cargo run --locked -q -p contextful-cli --no-default-features --bin contextful -- formal protocol-differential --seed ${seed} --cases 256`;

export const contextfulProtocol = defineRun({
name: "contextful-protocol",
version: "1.0.0",
schedules: [
{
cron: "17 3 * * 0",
idempotencyKey: ({ firedAt }) => `contextful-protocol:${firedAt}`,
inputs: ({ firedAt }): typeof Input.Type => ({ repo: REPO, ref: REF, firedAt }),
},
],
inputs: Input,
outputs: Output,
limits: { maxDurationSec: 7200, admissionMaxQueueAgeSec: 21600 },
run: (input) =>
Effect.gen(function* () {
if (input.repo !== REPO || input.ref !== REF) {
return yield* Effect.fail(
new StepFailed({
step: "scope",
cause: "protocol exploration targets the Contextful default branch",
}),
);
}
const commit = yield* step("resolve-head", () =>
github.branchHead({ repo: REPO, branch: "main" }),
);
const ws = yield* step("checkout", () => workspace({ repo: REPO, sha: commit }));
const provisioned = yield* step(
"toolchain",
() =>
sandbox.exec({
container: ws.container,
cwd: ws.dir,
command: TOOLCHAIN_COMMAND,
timeoutSec: COMMAND_TIMEOUT_SEC,
}),
{ timeoutSec: COMMAND_TIMEOUT_SEC + 120, retries: 0 },
);
const toolchainLog = yield* step("toolchain-log", () =>
artifact.upload({
name: "protocol-toolchain.log",
path: provisioned.logPath,
signedUrlTTL: "30 days",
}),
);
if (provisioned.exitCode !== 0) {
return yield* Effect.fail(
new AcceptanceFailed({
exitCode: provisioned.exitCode,
summaryMd: `The pinned toolchain fails on ${commit}. [Log](${toolchainLog})`,
}),
);
}
const formal = yield* step(
"formal-gate",
() =>
sandbox.exec({
container: ws.container,
cwd: ws.dir,
command: FORMAL_COMMAND,
timeoutSec: COMMAND_TIMEOUT_SEC,
}),
{ timeoutSec: COMMAND_TIMEOUT_SEC + 120, retries: 0 },
);
const formalLog = yield* step("formal-log", () =>
artifact.upload({
name: "protocol-formal.log",
path: formal.logPath,
signedUrlTTL: "30 days",
}),
);
if (formal.exitCode !== 0) {
return yield* Effect.fail(
new AcceptanceFailed({
exitCode: formal.exitCode,
summaryMd: `The pinned formal gate fails on ${commit}. [Log](${formalLog})`,
}),
);
}
const generated = yield* step("fresh-seed", () =>
sandbox.exec({
container: ws.container,
cwd: ws.dir,
command: SEED_COMMAND,
timeoutSec: 60,
}),
);
const seed = generated.stdout.trim();
if (
generated.exitCode !== 0 ||
!/^(0|[1-9][0-9]{0,19})$/.test(seed) ||
BigInt(seed) > 18446744073709551615n
) {
return yield* Effect.fail(
new StepFailed({
step: "fresh-seed",
cause: "seed generation returns no unsigned 64-bit integer",
}),
);
}
const compared = yield* step(
"protocol-exploration",
() =>
sandbox.exec({
container: ws.container,
cwd: ws.dir,
command: protocolCommand(seed),
timeoutSec: COMMAND_TIMEOUT_SEC,
}),
{ timeoutSec: COMMAND_TIMEOUT_SEC + 120, retries: 0 },
);
const logUrl = yield* step("protocol-log", () =>
artifact.upload({
name: "protocol-exploration.log",
path: compared.logPath,
signedUrlTTL: "30 days",
}),
);
if (compared.exitCode !== 0) {
const saved = yield* step("saved-regressions", () =>
sandbox
.readFile({ container: ws.container, path: `${ws.dir}/${REGRESSIONS}` })
.pipe(Effect.catchTag("ReadFileFailed", () => Effect.succeed(undefined))),
);
const regressionsUrl =
saved === undefined
? undefined
: yield* step("regressions-artifact", () =>
artifact.upload({
name: "protocol-regressions.jsonl",
path: `${ws.dir}/${REGRESSIONS}`,
container: ws.container,
contentType: "application/x-ndjson",
signedUrlTTL: "30 days",
}),
);
return yield* Effect.fail(
new AcceptanceFailed({
exitCode: compared.exitCode,
summaryMd: `Protocol exploration fails on ${commit} with seed ${seed}. [Log](${logUrl})${regressionsUrl === undefined ? "" : ` [Regressions](${regressionsUrl})`}`,
}),
);
}
return { commit, seed, logUrl };
}),
});
1 change: 1 addition & 0 deletions runs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ export { contextfulGate } from "./contextful-gate";
export { emailOtpLogin } from "./email-otp-login";
export { finopsAudit } from "./finops-audit";
export { contextfulMeasures } from "./contextful-measures";
export { contextfulProtocol } from "./contextful-protocol";
export { demoReel } from "./demo-reel";
3 changes: 2 additions & 1 deletion runs/sandbox-image.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ describe("sandboxImage catalog", () => {
r.sandboxImage !== undefined &&
r.sandboxImage !== "lean" &&
r.sandboxImage !== "browser" &&
r.sandboxImage !== "agent",
r.sandboxImage !== "agent" &&
r.sandboxImage !== "release",
)
.map((r) => r.name);
expect(unknown).toEqual([]);
Expand Down
1 change: 1 addition & 0 deletions wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"0 6 * * *", // ci-triage-pr — daily
"0 7 * * 1", // finops-audit — Mondays
"17 2 * * *", // contextful-measures — daily
"17 3 * * 0", // contextful-protocol — weekly
],
},

Expand Down
Loading