@brainbase-labs/cli 0.23.0 → 0.25.0-eng1209.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1119 -74
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
36008
36008
  // package.json
36009
36009
  var package_default = {
36010
36010
  name: "@brainbase-labs/cli",
36011
- version: "0.23.0",
36011
+ version: "0.25.0-eng1209.1",
36012
36012
  description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
36013
36013
  type: "module",
36014
36014
  bin: {
@@ -78472,7 +78472,9 @@ import crypto6 from "node:crypto";
78472
78472
  import fs81 from "node:fs";
78473
78473
  import os16 from "node:os";
78474
78474
  import path88 from "node:path";
78475
+ import { Readable, Transform as Transform2 } from "node:stream";
78475
78476
  import { pipeline as pipeline2 } from "node:stream/promises";
78477
+ import { createGunzip, createInflateRaw } from "node:zlib";
78476
78478
  var SCHEMA_VERSION = "1";
78477
78479
  var SHA256_RE = /^[a-f0-9]{64}$/i;
78478
78480
  var ID_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
@@ -78480,6 +78482,16 @@ var ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
78480
78482
  var MAX_SPEC_BYTES = 20 * 1024 * 1024;
78481
78483
  var MAX_FINAL_OUTPUT_BYTES = 10 * 1024 * 1024;
78482
78484
  var MAX_TRAJECTORY_BYTES = 100 * 1024 * 1024;
78485
+ var MAX_REMOTE_INPUT_BYTES = 2 * 1024 * 1024 * 1024;
78486
+ var MAX_ARCHIVE_EXTRACTED_BYTES = 2 * 1024 * 1024 * 1024;
78487
+ var MAX_ARCHIVE_SCAN_BYTES = 2 * 1024 * 1024 * 1024;
78488
+ var MAX_SANDBOX_COMMANDS = 20;
78489
+ var MAX_CRITERIA_PER_EVALUATOR = 100;
78490
+ var MAX_CRITERIA_RESULT_BYTES = 1024 * 1024;
78491
+ var MAX_CRITERION_EXPLANATION_LENGTH = 16384;
78492
+ var MAX_CRITERION_EVIDENCE_IDS = 100;
78493
+ var MAX_CRITERION_EVIDENCE_ID_LENGTH = 256;
78494
+ var MAX_ALLOWED_EVIDENCE_IDS = 1e4;
78483
78495
  var RESERVED_WORKSPACE_PATHS = new Set([
78484
78496
  ".brainbase",
78485
78497
  ".git",
@@ -78507,21 +78519,62 @@ var NonSecretEnvironmentValueSchema = exports_external.object({
78507
78519
  sensitive: exports_external.literal(false)
78508
78520
  }).strict();
78509
78521
  var RootRelativePathSchema = exports_external.string().min(1).max(1024);
78522
+ var CandidateOutputPatternSchema = RootRelativePathSchema.refine((value) => {
78523
+ if (value.includes("\\") || /[\[\]{}]/.test(value))
78524
+ return false;
78525
+ try {
78526
+ return safeRelPath(value) === value;
78527
+ } catch {
78528
+ return false;
78529
+ }
78530
+ }, {
78531
+ message: "must be a normalized safe relative glob using only *, ?, and ** wildcards"
78532
+ });
78533
+ var ArchivePathSchema = RootRelativePathSchema.refine((value) => {
78534
+ try {
78535
+ return safeRelPath(value) === value;
78536
+ } catch {
78537
+ return false;
78538
+ }
78539
+ }, {
78540
+ message: "must be a normalized safe relative path"
78541
+ });
78510
78542
  var BudgetSchema = exports_external.object({
78511
78543
  timeout_ms: exports_external.number().int().min(100).max(3600000),
78512
78544
  max_output_bytes: exports_external.number().int().min(1024).max(100 * 1024 * 1024)
78513
78545
  }).strict();
78514
- var MaterialSchema = exports_external.object({
78546
+ var MaterialBaseSchema = {
78515
78547
  id: IdSchema,
78516
- kind: exports_external.enum(["file", "tar_gz"]),
78517
78548
  source: RootRelativePathSchema,
78549
+ download_url_env: EnvNameSchema.optional(),
78518
78550
  destination: RootRelativePathSchema,
78519
78551
  sha256: Sha256Schema,
78520
78552
  size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024),
78521
- mode: exports_external.number().int().min(0).max(511).optional(),
78553
+ mode: exports_external.number().int().min(0).max(511).optional()
78554
+ };
78555
+ var ExpandableMaterialSchema = {
78522
78556
  max_unpacked_bytes: exports_external.number().int().min(1).max(2 * 1024 * 1024 * 1024).optional(),
78523
78557
  max_file_count: exports_external.number().int().min(1).max(1e5).optional()
78524
- }).strict();
78558
+ };
78559
+ var MaterialSchema = exports_external.discriminatedUnion("kind", [
78560
+ exports_external.object({
78561
+ ...MaterialBaseSchema,
78562
+ ...ExpandableMaterialSchema,
78563
+ kind: exports_external.literal("file")
78564
+ }).strict(),
78565
+ exports_external.object({
78566
+ ...MaterialBaseSchema,
78567
+ ...ExpandableMaterialSchema,
78568
+ kind: exports_external.literal("tar_gz")
78569
+ }).strict(),
78570
+ exports_external.object({
78571
+ ...MaterialBaseSchema,
78572
+ kind: exports_external.literal("archive_file"),
78573
+ archive_path: ArchivePathSchema,
78574
+ file_sha256: Sha256Schema,
78575
+ file_size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
78576
+ }).strict()
78577
+ ]);
78525
78578
  var CommandSchema = exports_external.object({
78526
78579
  id: IdSchema,
78527
78580
  argv: exports_external.array(exports_external.string().min(1)).min(1).max(128),
@@ -78583,11 +78636,16 @@ var EvaluatorSchema = exports_external.discriminatedUnion("type", [
78583
78636
  ...EvaluatorBase,
78584
78637
  type: exports_external.literal("sandbox_command"),
78585
78638
  command: CommandSchema.omit({ id: true }),
78586
- root: exports_external.enum(["workspace", "tests"]).default("tests")
78639
+ root: exports_external.enum(["workspace", "tests"]).default("tests"),
78640
+ criterion_keys: exports_external.array(IdSchema).min(1).max(MAX_CRITERIA_PER_EVALUATOR).optional(),
78641
+ allowed_evidence_ids: exports_external.array(exports_external.string().min(1).max(MAX_CRITERION_EVIDENCE_ID_LENGTH)).max(MAX_ALLOWED_EVIDENCE_IDS).optional(),
78642
+ tests_path: ArchivePathSchema.optional(),
78643
+ workspace_mode: exports_external.enum(["read_only", "isolated_copy"]).default("read_only")
78587
78644
  }).strict()
78588
78645
  ]);
78589
78646
  var EvidenceFileSchema = exports_external.object({
78590
78647
  source: RootRelativePathSchema,
78648
+ download_url_env: EnvNameSchema.optional(),
78591
78649
  sha256: Sha256Schema,
78592
78650
  size_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
78593
78651
  }).strict();
@@ -78602,6 +78660,37 @@ var HydrateSpecSchema = BaseSpecSchema.extend({
78602
78660
  materials: exports_external.array(MaterialSchema).max(1e4).default([]),
78603
78661
  setup_commands: exports_external.array(CommandSchema).max(128).default([])
78604
78662
  }).strict();
78663
+ var CandidateOutputSchema = exports_external.object({
78664
+ id: IdSchema,
78665
+ pattern: CandidateOutputPatternSchema,
78666
+ kind: exports_external.enum(["file", "directory"]),
78667
+ required: exports_external.boolean(),
78668
+ min_matches: exports_external.number().int().min(0).max(1e5),
78669
+ max_matches: exports_external.number().int().min(1).max(1e5),
78670
+ max_total_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
78671
+ }).strict().superRefine((value, context) => {
78672
+ if (value.min_matches > value.max_matches) {
78673
+ context.addIssue({
78674
+ code: exports_external.ZodIssueCode.custom,
78675
+ path: ["min_matches"],
78676
+ message: "min_matches cannot exceed max_matches"
78677
+ });
78678
+ }
78679
+ if (value.required && value.min_matches === 0) {
78680
+ context.addIssue({
78681
+ code: exports_external.ZodIssueCode.custom,
78682
+ path: ["min_matches"],
78683
+ message: "required candidate outputs must require at least one match"
78684
+ });
78685
+ }
78686
+ if (!value.required && value.min_matches > 0) {
78687
+ context.addIssue({
78688
+ code: exports_external.ZodIssueCode.custom,
78689
+ path: ["min_matches"],
78690
+ message: "optional candidate outputs must allow zero matches"
78691
+ });
78692
+ }
78693
+ });
78605
78694
  var EvaluateSpecSchema = BaseSpecSchema.extend({
78606
78695
  phase: exports_external.literal("evaluate"),
78607
78696
  tests_root: AbsolutePathSchema,
@@ -78612,6 +78701,7 @@ var EvaluateSpecSchema = BaseSpecSchema.extend({
78612
78701
  references: exports_external.array(MaterialSchema).max(1e4).default([]),
78613
78702
  evaluators: exports_external.array(EvaluatorSchema).min(1).max(1000),
78614
78703
  candidate_artifacts: exports_external.array(RootRelativePathSchema).max(1000).default([]),
78704
+ candidate_outputs: exports_external.array(CandidateOutputSchema).max(1000).default([]),
78615
78705
  capture_workspace_archive: exports_external.boolean().default(false),
78616
78706
  workspace_limits: exports_external.object({
78617
78707
  max_file_count: exports_external.number().int().min(1).max(1e6).default(1e5),
@@ -78632,6 +78722,35 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78632
78722
  }
78633
78723
  }
78634
78724
  const declaredSecrets = new Set(value.secret_env);
78725
+ const remoteInputs = value.phase === "hydrate" ? value.materials : [
78726
+ value.evidence.final_output,
78727
+ value.evidence.trajectory,
78728
+ ...value.references
78729
+ ];
78730
+ const remoteUrlEnvNames = new Set(remoteInputs.flatMap((input) => input.download_url_env ? [input.download_url_env] : []));
78731
+ const uniqueRemoteInputs = new Map;
78732
+ for (const input of remoteInputs) {
78733
+ if (!input.download_url_env)
78734
+ continue;
78735
+ uniqueRemoteInputs.set([input.source, input.sha256, input.size_bytes].join("\x00"), input.size_bytes);
78736
+ }
78737
+ const remoteInputBytes = [...uniqueRemoteInputs.values()].reduce((total, size2) => total + size2, 0);
78738
+ if (remoteInputBytes > MAX_REMOTE_INPUT_BYTES) {
78739
+ context.addIssue({
78740
+ code: exports_external.ZodIssueCode.custom,
78741
+ path: [value.phase === "hydrate" ? "materials" : "references"],
78742
+ message: "remote inputs exceed the aggregate download byte limit"
78743
+ });
78744
+ }
78745
+ for (const name of remoteUrlEnvNames) {
78746
+ if (Object.hasOwn(value.environment, name)) {
78747
+ context.addIssue({
78748
+ code: exports_external.ZodIssueCode.custom,
78749
+ path: ["environment", name],
78750
+ message: "signed download URLs must be supplied through the process environment"
78751
+ });
78752
+ }
78753
+ }
78635
78754
  const commands = value.phase === "hydrate" ? value.setup_commands.map((command, index) => ({
78636
78755
  command,
78637
78756
  path: ["setup_commands", index, "secret_env"]
@@ -78641,6 +78760,13 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78641
78760
  }] : []);
78642
78761
  for (const { command, path: issuePath } of commands) {
78643
78762
  for (const name of command.secret_env) {
78763
+ if (remoteUrlEnvNames.has(name)) {
78764
+ context.addIssue({
78765
+ code: exports_external.ZodIssueCode.custom,
78766
+ path: issuePath,
78767
+ message: `signed download URL environment variables cannot be exposed to commands: ${name}`
78768
+ });
78769
+ }
78644
78770
  if (!declaredSecrets.has(name)) {
78645
78771
  context.addIssue({
78646
78772
  code: exports_external.ZodIssueCode.custom,
@@ -78655,7 +78781,8 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78655
78781
  { items: value.setup_commands, path: "setup_commands" }
78656
78782
  ] : [
78657
78783
  { items: value.references, path: "references" },
78658
- { items: value.evaluators, path: "evaluators" }
78784
+ { items: value.evaluators, path: "evaluators" },
78785
+ { items: value.candidate_outputs, path: "candidate_outputs" }
78659
78786
  ];
78660
78787
  for (const { items, path: issuePath } of uniqueLists) {
78661
78788
  const ids = items.map((item) => item.id);
@@ -78667,11 +78794,53 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
78667
78794
  });
78668
78795
  }
78669
78796
  }
78670
- if (value.phase === "evaluate" && value.evaluators.filter((evaluator) => evaluator.type === "sandbox_command").length > 1) {
78797
+ if (value.phase === "evaluate") {
78798
+ value.evaluators.forEach((evaluator, index) => {
78799
+ if (evaluator.type === "sandbox_command" && evaluator.criterion_keys && new Set(evaluator.criterion_keys).size !== evaluator.criterion_keys.length) {
78800
+ context.addIssue({
78801
+ code: exports_external.ZodIssueCode.custom,
78802
+ path: ["evaluators", index, "criterion_keys"],
78803
+ message: "criterion_keys must be unique"
78804
+ });
78805
+ }
78806
+ if (evaluator.type === "sandbox_command" && evaluator.criterion_keys && evaluator.allowed_evidence_ids === undefined) {
78807
+ context.addIssue({
78808
+ code: exports_external.ZodIssueCode.custom,
78809
+ path: ["evaluators", index, "allowed_evidence_ids"],
78810
+ message: "structured criteria require allowed_evidence_ids"
78811
+ });
78812
+ }
78813
+ if (evaluator.type === "sandbox_command" && evaluator.allowed_evidence_ids && new Set(evaluator.allowed_evidence_ids).size !== evaluator.allowed_evidence_ids.length) {
78814
+ context.addIssue({
78815
+ code: exports_external.ZodIssueCode.custom,
78816
+ path: ["evaluators", index, "allowed_evidence_ids"],
78817
+ message: "allowed_evidence_ids must be unique"
78818
+ });
78819
+ }
78820
+ });
78821
+ const candidateOutputBytes = value.candidate_outputs.reduce((total, output) => total + output.max_total_bytes, 0);
78822
+ if (candidateOutputBytes > value.workspace_limits.max_total_bytes) {
78823
+ context.addIssue({
78824
+ code: exports_external.ZodIssueCode.custom,
78825
+ path: ["candidate_outputs"],
78826
+ message: "candidate output byte limits exceed the workspace byte limit"
78827
+ });
78828
+ }
78829
+ }
78830
+ const materials = value.phase === "hydrate" ? value.materials : value.references;
78831
+ const archiveOutputBytes = materials.reduce((total, material) => total + (material.kind === "archive_file" ? material.file_size_bytes : 0), 0);
78832
+ if (archiveOutputBytes > MAX_ARCHIVE_EXTRACTED_BYTES) {
78833
+ context.addIssue({
78834
+ code: exports_external.ZodIssueCode.custom,
78835
+ path: [value.phase === "hydrate" ? "materials" : "references"],
78836
+ message: "archive-file materials exceed the aggregate extracted byte limit"
78837
+ });
78838
+ }
78839
+ if (value.phase === "evaluate" && value.evaluators.filter((evaluator) => evaluator.type === "sandbox_command").length > MAX_SANDBOX_COMMANDS) {
78671
78840
  context.addIssue({
78672
78841
  code: exports_external.ZodIssueCode.custom,
78673
78842
  path: ["evaluators"],
78674
- message: "schema version 1 supports at most one sandbox_command evaluator"
78843
+ message: `schema version 1 supports at most ${MAX_SANDBOX_COMMANDS} sandbox_command evaluators`
78675
78844
  });
78676
78845
  }
78677
78846
  });
@@ -78680,6 +78849,15 @@ var BENCHMARK_CAPABILITIES = {
78680
78849
  cli_version: VERSION,
78681
78850
  schema_versions: [SCHEMA_VERSION],
78682
78851
  phases: ["hydrate", "evaluate"],
78852
+ features: [
78853
+ "remote_input_references_v1",
78854
+ "archive_file_materials_v1",
78855
+ "structured_criterion_results_v1",
78856
+ "multiple_sandbox_commands_v1",
78857
+ "sandbox_command_workspace_modes_v1",
78858
+ "candidate_outputs_v1",
78859
+ "criterion_evidence_allowlist_v1"
78860
+ ],
78683
78861
  evaluator_types: [
78684
78862
  "output_assertion",
78685
78863
  "trajectory_assertion",
@@ -78689,7 +78867,8 @@ var BENCHMARK_CAPABILITIES = {
78689
78867
  limits: {
78690
78868
  max_secret_bindings: 100,
78691
78869
  max_evaluators: 1000,
78692
- max_sandbox_commands: 1
78870
+ max_sandbox_commands: MAX_SANDBOX_COMMANDS,
78871
+ max_criteria_per_evaluator: MAX_CRITERIA_PER_EVALUATOR
78693
78872
  }
78694
78873
  };
78695
78874
 
@@ -78703,6 +78882,11 @@ class BenchmarkPhaseError extends Error {
78703
78882
  this.name = "BenchmarkPhaseError";
78704
78883
  }
78705
78884
  }
78885
+ var ZIP_EOCD_SIGNATURE = 101010256;
78886
+ var ZIP_CENTRAL_SIGNATURE = 33639248;
78887
+ var ZIP_LOCAL_SIGNATURE = 67324752;
78888
+ var MAX_ZIP_EOCD_BYTES = 65535 + 22;
78889
+ var MAX_ARCHIVE_MEMBERS = 1e5;
78706
78890
  function nowIso() {
78707
78891
  return new Date().toISOString();
78708
78892
  }
@@ -78965,10 +79149,516 @@ async function verifyInput(stagingRoot, material) {
78965
79149
  if (actual !== material.sha256) {
78966
79150
  throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${material.source}`, { expected: material.sha256, actual });
78967
79151
  }
79152
+ return {
79153
+ source,
79154
+ sha256: actual,
79155
+ size: opened.stat.size,
79156
+ mode: opened.stat.mode & 511
79157
+ };
78968
79158
  } finally {
78969
79159
  fs81.closeSync(opened.fd);
78970
79160
  }
78971
- return source;
79161
+ }
79162
+ function inputCacheKey(input) {
79163
+ return [
79164
+ input.source,
79165
+ input.sha256,
79166
+ input.size_bytes
79167
+ ].join(":");
79168
+ }
79169
+ async function cachedVerifiedInput(stagingRoot, input, context) {
79170
+ const cacheKey = inputCacheKey(input);
79171
+ const cached2 = context.verifiedInputs.get(cacheKey);
79172
+ if (cached2)
79173
+ return cached2;
79174
+ const verified = await verifyInput(stagingRoot, input);
79175
+ context.verifiedInputs.set(cacheKey, verified);
79176
+ return verified;
79177
+ }
79178
+ function stagedInputRecord(stagingRoot, verified) {
79179
+ return {
79180
+ root: "staging",
79181
+ path: path88.relative(stagingRoot, verified.source).replace(/\\/g, "/"),
79182
+ sha256: verified.sha256,
79183
+ size: verified.size,
79184
+ mode: verified.mode,
79185
+ kind: "file"
79186
+ };
79187
+ }
79188
+ function remoteUrlEnvironmentNames(spec) {
79189
+ const inputs = spec.phase === "hydrate" ? spec.materials : [
79190
+ spec.evidence.final_output,
79191
+ spec.evidence.trajectory,
79192
+ ...spec.references
79193
+ ];
79194
+ return new Set(inputs.flatMap((input) => input.download_url_env ? [input.download_url_env] : []));
79195
+ }
79196
+ function removeRemoteHydrationInputs(spec) {
79197
+ const removedSources = new Set;
79198
+ for (const material of spec.materials) {
79199
+ if (!material.download_url_env || removedSources.has(material.source))
79200
+ continue;
79201
+ const relative = safeRelPath(material.source);
79202
+ const source = path88.resolve(spec.staging_root, relative);
79203
+ if (!isWithin(spec.staging_root, source)) {
79204
+ throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${material.source}`);
79205
+ }
79206
+ assertNoSymlinkTraversal(spec.staging_root, relative);
79207
+ try {
79208
+ fs81.rmSync(source, { force: true });
79209
+ } catch {
79210
+ throw new BenchmarkPhaseError("staging_cleanup_failed", `downloaded benchmark input could not be removed: ${material.source}`);
79211
+ }
79212
+ removedSources.add(material.source);
79213
+ }
79214
+ }
79215
+ async function downloadInputReference(stagingRoot, input, context) {
79216
+ const cacheKey = inputCacheKey(input);
79217
+ const cached2 = context.verifiedInputs.get(cacheKey);
79218
+ if (cached2)
79219
+ return cached2;
79220
+ const envName = input.download_url_env;
79221
+ if (!envName) {
79222
+ return await cachedVerifiedInput(stagingRoot, input, context);
79223
+ }
79224
+ const relative = safeRelPath(input.source);
79225
+ const destination = path88.resolve(stagingRoot, relative);
79226
+ if (!isWithin(stagingRoot, destination)) {
79227
+ throw new BenchmarkPhaseError("unsafe_path", `source escapes staging root: ${input.source}`);
79228
+ }
79229
+ assertNoSymlinkTraversal(stagingRoot, relative);
79230
+ try {
79231
+ fs81.lstatSync(destination);
79232
+ return await cachedVerifiedInput(stagingRoot, input, context);
79233
+ } catch (error2) {
79234
+ if (error2.code !== "ENOENT")
79235
+ throw error2;
79236
+ }
79237
+ const rawUrl = process.env[envName];
79238
+ if (!rawUrl) {
79239
+ throw new BenchmarkPhaseError("missing_environment", `required signed download URL environment variable is missing: ${envName}`);
79240
+ }
79241
+ let url2;
79242
+ try {
79243
+ url2 = new URL(rawUrl);
79244
+ } catch {
79245
+ throw new BenchmarkPhaseError("invalid_download_url", `signed download URL environment variable is invalid: ${envName}`);
79246
+ }
79247
+ if (url2.protocol !== "https:" || url2.username || url2.password) {
79248
+ throw new BenchmarkPhaseError("invalid_download_url", `signed download URL environment variable must contain an HTTPS URL without credentials: ${envName}`);
79249
+ }
79250
+ const remainingMs = context.deadline - Date.now();
79251
+ if (remainingMs <= 0) {
79252
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
79253
+ }
79254
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true, mode: 448 });
79255
+ assertNoSymlinkTraversal(stagingRoot, relative);
79256
+ assertWritableDestination(stagingRoot, relative);
79257
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.download`;
79258
+ const controller = new AbortController;
79259
+ const timer = setTimeout(() => controller.abort(), remainingMs);
79260
+ let descriptor;
79261
+ try {
79262
+ let response;
79263
+ try {
79264
+ response = await fetch(url2, {
79265
+ redirect: "error",
79266
+ signal: controller.signal
79267
+ });
79268
+ } catch {
79269
+ if (controller.signal.aborted || Date.now() >= context.deadline) {
79270
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
79271
+ }
79272
+ throw new BenchmarkPhaseError("download_failed", `signed input download failed for ${input.source}`);
79273
+ }
79274
+ if (response.redirected || response.status >= 300 && response.status < 400) {
79275
+ throw new BenchmarkPhaseError("download_redirect_rejected", `signed input download redirected for ${input.source}`);
79276
+ }
79277
+ if (!response.ok || !response.body) {
79278
+ throw new BenchmarkPhaseError("download_failed", `signed input download failed for ${input.source}`, { status: response.status });
79279
+ }
79280
+ const declaredLength = response.headers.get("content-length");
79281
+ if (declaredLength !== null && /^\d+$/.test(declaredLength) && Number(declaredLength) > input.size_bytes) {
79282
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${input.source}`, { expected: input.size_bytes, actual: Number(declaredLength) });
79283
+ }
79284
+ descriptor = fs81.openSync(temporary, "wx", 384);
79285
+ const reader = response.body.getReader();
79286
+ let actual;
79287
+ let size2 = 0;
79288
+ try {
79289
+ const hash = crypto6.createHash("sha256");
79290
+ while (true) {
79291
+ const { done, value } = await reader.read();
79292
+ if (done)
79293
+ break;
79294
+ assertBudget(context);
79295
+ size2 += value.byteLength;
79296
+ if (size2 > input.size_bytes) {
79297
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${input.source}`, { expected: input.size_bytes, actual: size2 });
79298
+ }
79299
+ hash.update(value);
79300
+ let offset = 0;
79301
+ while (offset < value.byteLength) {
79302
+ offset += fs81.writeSync(descriptor, value, offset, value.byteLength - offset);
79303
+ }
79304
+ }
79305
+ actual = hash.digest("hex");
79306
+ } finally {
79307
+ try {
79308
+ await reader.cancel();
79309
+ } catch {}
79310
+ }
79311
+ if (size2 !== input.size_bytes) {
79312
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for ${input.source}`, { expected: input.size_bytes, actual: size2 });
79313
+ }
79314
+ if (actual !== input.sha256) {
79315
+ throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for ${input.source}`, { expected: input.sha256, actual });
79316
+ }
79317
+ fs81.fsyncSync(descriptor);
79318
+ fs81.closeSync(descriptor);
79319
+ descriptor = undefined;
79320
+ assertNoSymlinkTraversal(stagingRoot, relative);
79321
+ if (fs81.existsSync(destination)) {
79322
+ return await cachedVerifiedInput(stagingRoot, input, context);
79323
+ }
79324
+ fs81.renameSync(temporary, destination);
79325
+ return await cachedVerifiedInput(stagingRoot, input, context);
79326
+ } catch (error2) {
79327
+ if (!(error2 instanceof BenchmarkPhaseError) && (controller.signal.aborted || Date.now() >= context.deadline)) {
79328
+ throw new BenchmarkPhaseError("phase_timeout", "phase budget expired");
79329
+ }
79330
+ if (error2 instanceof BenchmarkPhaseError)
79331
+ throw error2;
79332
+ throw new BenchmarkPhaseError("download_failed", `signed input download failed for ${input.source}`);
79333
+ } finally {
79334
+ clearTimeout(timer);
79335
+ controller.abort();
79336
+ if (descriptor !== undefined)
79337
+ fs81.closeSync(descriptor);
79338
+ fs81.rmSync(temporary, { force: true });
79339
+ }
79340
+ }
79341
+ function readExactly(descriptor, length, position) {
79342
+ const buffer = Buffer.alloc(length);
79343
+ let offset = 0;
79344
+ while (offset < length) {
79345
+ const count = fs81.readSync(descriptor, buffer, offset, length - offset, position + offset);
79346
+ if (count === 0) {
79347
+ throw new BenchmarkPhaseError("invalid_archive", "archive ended unexpectedly");
79348
+ }
79349
+ offset += count;
79350
+ }
79351
+ return buffer;
79352
+ }
79353
+ function decodeZipPath(value, utf8) {
79354
+ if (!utf8 && value.some((byte) => byte >= 128)) {
79355
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP members with non-UTF-8 names are unsupported");
79356
+ }
79357
+ try {
79358
+ return new TextDecoder("utf-8", { fatal: true }).decode(value);
79359
+ } catch {
79360
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP member name is not valid UTF-8");
79361
+ }
79362
+ }
79363
+ function findZipMembers(archivePath, requested, context) {
79364
+ const descriptor = fs81.openSync(archivePath, "r");
79365
+ try {
79366
+ assertBudget(context);
79367
+ const archiveSize = fs81.fstatSync(descriptor).size;
79368
+ const tailSize = Math.min(archiveSize, MAX_ZIP_EOCD_BYTES);
79369
+ const tailOffset = archiveSize - tailSize;
79370
+ const tail2 = readExactly(descriptor, tailSize, tailOffset);
79371
+ let eocdOffset = -1;
79372
+ for (let offset2 = tail2.length - 22;offset2 >= 0; offset2 -= 1) {
79373
+ assertBudget(context);
79374
+ if (tail2.readUInt32LE(offset2) === ZIP_EOCD_SIGNATURE) {
79375
+ const commentLength = tail2.readUInt16LE(offset2 + 20);
79376
+ if (offset2 + 22 + commentLength === tail2.length) {
79377
+ eocdOffset = offset2;
79378
+ break;
79379
+ }
79380
+ }
79381
+ }
79382
+ if (eocdOffset < 0) {
79383
+ throw new BenchmarkPhaseError("invalid_archive", "invalid ZIP archive");
79384
+ }
79385
+ const diskNumber = tail2.readUInt16LE(eocdOffset + 4);
79386
+ const directoryDisk = tail2.readUInt16LE(eocdOffset + 6);
79387
+ const diskEntries = tail2.readUInt16LE(eocdOffset + 8);
79388
+ const totalEntries = tail2.readUInt16LE(eocdOffset + 10);
79389
+ const directorySize = tail2.readUInt32LE(eocdOffset + 12);
79390
+ const directoryOffset = tail2.readUInt32LE(eocdOffset + 16);
79391
+ if (diskNumber !== 0 || directoryDisk !== 0 || diskEntries !== totalEntries) {
79392
+ throw new BenchmarkPhaseError("invalid_archive", "multi-disk ZIP archives are unsupported");
79393
+ }
79394
+ if (totalEntries === 65535 || directorySize === 4294967295 || directoryOffset === 4294967295) {
79395
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP64 archives are unsupported");
79396
+ }
79397
+ if (totalEntries > MAX_ARCHIVE_MEMBERS || directoryOffset + directorySize > tailOffset + eocdOffset) {
79398
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP central directory is invalid");
79399
+ }
79400
+ let offset = directoryOffset;
79401
+ const found = new Map;
79402
+ for (let index = 0;index < totalEntries; index += 1) {
79403
+ assertBudget(context);
79404
+ const header = readExactly(descriptor, 46, offset);
79405
+ if (header.readUInt32LE(0) !== ZIP_CENTRAL_SIGNATURE) {
79406
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP central directory is invalid");
79407
+ }
79408
+ const flags = header.readUInt16LE(8);
79409
+ const compressionMethod = header.readUInt16LE(10);
79410
+ const compressedSize = header.readUInt32LE(20);
79411
+ const uncompressedSize = header.readUInt32LE(24);
79412
+ const nameLength = header.readUInt16LE(28);
79413
+ const extraLength = header.readUInt16LE(30);
79414
+ const commentLength = header.readUInt16LE(32);
79415
+ const diskStart = header.readUInt16LE(34);
79416
+ const externalAttributes = header.readUInt32LE(38);
79417
+ const localHeaderOffset = header.readUInt32LE(42);
79418
+ const recordSize = 46 + nameLength + extraLength + commentLength;
79419
+ if (offset + recordSize > directoryOffset + directorySize || compressedSize === 4294967295 || uncompressedSize === 4294967295 || localHeaderOffset === 4294967295 || diskStart !== 0) {
79420
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP member metadata is invalid");
79421
+ }
79422
+ const name = decodeZipPath(readExactly(descriptor, nameLength, offset + 46), (flags & 2048) !== 0);
79423
+ const material = requested.get(name);
79424
+ if (material) {
79425
+ if (found.has(name)) {
79426
+ throw new BenchmarkPhaseError("invalid_archive", `archive member is duplicated: ${name}`);
79427
+ }
79428
+ const madeBy = header.readUInt16LE(4) >> 8;
79429
+ const unixMode = externalAttributes >>> 16;
79430
+ const fileType = unixMode & 61440;
79431
+ if (name.endsWith("/") || (externalAttributes & 16) !== 0 || madeBy === 3 && fileType !== 0 && fileType !== 32768) {
79432
+ throw new BenchmarkPhaseError("invalid_archive", `archive member must be a regular file: ${name}`);
79433
+ }
79434
+ if ((flags & 1) !== 0 || compressionMethod !== 0 && compressionMethod !== 8) {
79435
+ throw new BenchmarkPhaseError("invalid_archive", `archive member uses unsupported ZIP features: ${name}`);
79436
+ }
79437
+ if (uncompressedSize !== material.file_size_bytes) {
79438
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${name}`, { expected: material.file_size_bytes, actual: uncompressedSize });
79439
+ }
79440
+ const localHeader = readExactly(descriptor, 30, localHeaderOffset);
79441
+ if (localHeader.readUInt32LE(0) !== ZIP_LOCAL_SIGNATURE || localHeader.readUInt16LE(6) !== flags || localHeader.readUInt16LE(8) !== compressionMethod) {
79442
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP local header is invalid");
79443
+ }
79444
+ const localNameLength = localHeader.readUInt16LE(26);
79445
+ const localExtraLength = localHeader.readUInt16LE(28);
79446
+ const localName = decodeZipPath(readExactly(descriptor, localNameLength, localHeaderOffset + 30), (flags & 2048) !== 0);
79447
+ const dataOffset = localHeaderOffset + 30 + localNameLength + localExtraLength;
79448
+ if (localName !== name || dataOffset + compressedSize > directoryOffset) {
79449
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP member bounds are invalid");
79450
+ }
79451
+ found.set(name, {
79452
+ compressionMethod,
79453
+ compressedSize,
79454
+ dataOffset
79455
+ });
79456
+ }
79457
+ offset += recordSize;
79458
+ }
79459
+ if (offset !== directoryOffset + directorySize) {
79460
+ throw new BenchmarkPhaseError("invalid_archive", "ZIP central directory is invalid");
79461
+ }
79462
+ for (const memberPath of requested.keys()) {
79463
+ if (!found.has(memberPath)) {
79464
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${memberPath}`);
79465
+ }
79466
+ }
79467
+ return found;
79468
+ } finally {
79469
+ fs81.closeSync(descriptor);
79470
+ }
79471
+ }
79472
+ async function writeVerifiedArchiveMember(source, destination, material, context) {
79473
+ fs81.mkdirSync(path88.dirname(destination), { recursive: true, mode: 448 });
79474
+ const temporary = `${destination}.${process.pid}.${crypto6.randomBytes(6).toString("hex")}.tmp`;
79475
+ const descriptor = fs81.openSync(temporary, "wx", 384);
79476
+ const hash = crypto6.createHash("sha256");
79477
+ let size2 = 0;
79478
+ try {
79479
+ for await (const value of source) {
79480
+ assertBudget(context);
79481
+ const chunk2 = Buffer.isBuffer(value) ? value : Buffer.from(value);
79482
+ size2 += chunk2.length;
79483
+ if (size2 > material.file_size_bytes) {
79484
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${material.archive_path}`, { expected: material.file_size_bytes, actual: size2 });
79485
+ }
79486
+ hash.update(chunk2);
79487
+ let offset = 0;
79488
+ while (offset < chunk2.length) {
79489
+ offset += fs81.writeSync(descriptor, chunk2, offset, chunk2.length - offset);
79490
+ }
79491
+ }
79492
+ if (size2 !== material.file_size_bytes) {
79493
+ throw new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${material.archive_path}`, { expected: material.file_size_bytes, actual: size2 });
79494
+ }
79495
+ const actual = hash.digest("hex");
79496
+ if (actual !== material.file_sha256) {
79497
+ throw new BenchmarkPhaseError("digest_mismatch", `checksum mismatch for archive member ${material.archive_path}`, { expected: material.file_sha256, actual });
79498
+ }
79499
+ fs81.fsyncSync(descriptor);
79500
+ fs81.closeSync(descriptor);
79501
+ fs81.renameSync(temporary, destination);
79502
+ } catch (error2) {
79503
+ if (error2 instanceof BenchmarkPhaseError)
79504
+ throw error2;
79505
+ throw new BenchmarkPhaseError("invalid_archive", `archive member could not be extracted: ${material.archive_path}`);
79506
+ } finally {
79507
+ try {
79508
+ fs81.closeSync(descriptor);
79509
+ } catch {}
79510
+ fs81.rmSync(temporary, { force: true });
79511
+ }
79512
+ }
79513
+ function isZipArchive(archivePath) {
79514
+ const descriptor = fs81.openSync(archivePath, "r");
79515
+ try {
79516
+ const header = Buffer.alloc(4);
79517
+ return fs81.readSync(descriptor, header, 0, header.length, 0) === header.length && [
79518
+ ZIP_LOCAL_SIGNATURE,
79519
+ ZIP_EOCD_SIGNATURE,
79520
+ 134695760
79521
+ ].includes(header.readUInt32LE(0));
79522
+ } finally {
79523
+ fs81.closeSync(descriptor);
79524
+ }
79525
+ }
79526
+ function isGzipArchive(archivePath) {
79527
+ const descriptor = fs81.openSync(archivePath, "r");
79528
+ try {
79529
+ const header = Buffer.alloc(2);
79530
+ return fs81.readSync(descriptor, header, 0, header.length, 0) === header.length && header[0] === 31 && header[1] === 139;
79531
+ } finally {
79532
+ fs81.closeSync(descriptor);
79533
+ }
79534
+ }
79535
+ function archiveSourceCacheKey(material) {
79536
+ return [
79537
+ material.source,
79538
+ material.sha256,
79539
+ material.size_bytes,
79540
+ material.download_url_env ?? ""
79541
+ ].join("\x00");
79542
+ }
79543
+ function archiveMemberCacheKey(material) {
79544
+ return [
79545
+ archiveSourceCacheKey(material),
79546
+ material.archive_path,
79547
+ material.file_sha256,
79548
+ material.file_size_bytes
79549
+ ].join("\x00");
79550
+ }
79551
+ function archiveScanBudget(context) {
79552
+ let scanned = 0;
79553
+ return new Transform2({
79554
+ transform(chunk2, _encoding, callback) {
79555
+ try {
79556
+ assertBudget(context);
79557
+ scanned += chunk2.length;
79558
+ if (scanned > MAX_ARCHIVE_SCAN_BYTES) {
79559
+ throw new BenchmarkPhaseError("invalid_archive", "archive expands beyond the supported scan limit");
79560
+ }
79561
+ callback(null, chunk2);
79562
+ } catch (error2) {
79563
+ callback(error2);
79564
+ }
79565
+ }
79566
+ });
79567
+ }
79568
+ async function extractArchiveMembers(archivePath, outputRoot, materials, context) {
79569
+ const requested = new Map;
79570
+ for (const material of materials) {
79571
+ let memberPath;
79572
+ try {
79573
+ memberPath = safeRelPath(material.archive_path);
79574
+ } catch {
79575
+ throw new BenchmarkPhaseError("unsafe_path", "archive member path is unsafe");
79576
+ }
79577
+ const existing = requested.get(memberPath);
79578
+ if (existing && (existing.file_sha256 !== material.file_sha256 || existing.file_size_bytes !== material.file_size_bytes)) {
79579
+ throw new BenchmarkPhaseError("invalid_archive", `archive member has conflicting declarations: ${memberPath}`);
79580
+ }
79581
+ requested.set(memberPath, material);
79582
+ }
79583
+ const extracted = new Map;
79584
+ if (isZipArchive(archivePath)) {
79585
+ const indexed = findZipMembers(archivePath, requested, context);
79586
+ for (const [memberPath, material] of requested) {
79587
+ assertBudget(context);
79588
+ const destination = path88.resolve(outputRoot, memberPath);
79589
+ if (!isWithin(outputRoot, destination)) {
79590
+ throw new BenchmarkPhaseError("unsafe_path", `archive member escapes output root: ${memberPath}`);
79591
+ }
79592
+ const member = indexed.get(memberPath);
79593
+ const compressed = member.compressedSize === 0 ? Readable.from([]) : fs81.createReadStream(archivePath, {
79594
+ start: member.dataOffset,
79595
+ end: member.dataOffset + member.compressedSize - 1
79596
+ });
79597
+ const contents = member.compressionMethod === 8 ? compressed.pipe(createInflateRaw()) : compressed;
79598
+ await writeVerifiedArchiveMember(contents, destination, material, context);
79599
+ extracted.set(memberPath, destination);
79600
+ }
79601
+ return extracted;
79602
+ }
79603
+ const matches2 = new Map;
79604
+ let validationError;
79605
+ const unpack = co({
79606
+ cwd: outputRoot,
79607
+ strict: true,
79608
+ preserveOwner: false,
79609
+ filter: (entryPath, entryAny) => {
79610
+ assertBudget(context);
79611
+ const material = requested.get(entryPath);
79612
+ if (!material)
79613
+ return false;
79614
+ const count = (matches2.get(entryPath) ?? 0) + 1;
79615
+ matches2.set(entryPath, count);
79616
+ const entry = entryAny;
79617
+ if (count > 1) {
79618
+ validationError = new BenchmarkPhaseError("invalid_archive", `archive member is duplicated: ${entryPath}`);
79619
+ return false;
79620
+ }
79621
+ if (!["File", "OldFile", "ContiguousFile"].includes(entry.type)) {
79622
+ validationError = new BenchmarkPhaseError("invalid_archive", `archive member must be a regular file: ${entryPath}`);
79623
+ return false;
79624
+ }
79625
+ if (entry.size !== material.file_size_bytes) {
79626
+ validationError = new BenchmarkPhaseError("size_mismatch", `size mismatch for archive member ${entryPath}`, { expected: material.file_size_bytes, actual: entry.size });
79627
+ return false;
79628
+ }
79629
+ return true;
79630
+ }
79631
+ });
79632
+ const archive = fs81.createReadStream(archivePath);
79633
+ const scanBudget = archiveScanBudget(context);
79634
+ try {
79635
+ if (isGzipArchive(archivePath)) {
79636
+ await pipeline2(archive, createGunzip(), scanBudget, unpack);
79637
+ } else {
79638
+ await pipeline2(archive, scanBudget, unpack);
79639
+ }
79640
+ } catch (error2) {
79641
+ if (validationError)
79642
+ throw validationError;
79643
+ if (error2 instanceof BenchmarkPhaseError)
79644
+ throw error2;
79645
+ throw new BenchmarkPhaseError("invalid_archive", "archive members could not be extracted");
79646
+ }
79647
+ if (validationError)
79648
+ throw validationError;
79649
+ for (const [memberPath, material] of requested) {
79650
+ if (!matches2.has(memberPath)) {
79651
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${memberPath}`);
79652
+ }
79653
+ const verified = await verifyInput(outputRoot, {
79654
+ source: memberPath,
79655
+ sha256: material.file_sha256,
79656
+ size_bytes: material.file_size_bytes
79657
+ });
79658
+ assertBudget(context);
79659
+ extracted.set(memberPath, verified.source);
79660
+ }
79661
+ return extracted;
78972
79662
  }
78973
79663
  async function atomicCopy(source, destination, mode, sourceRoot) {
78974
79664
  fs81.mkdirSync(path88.dirname(destination), { recursive: true });
@@ -79017,21 +79707,31 @@ async function recordFile(root, filePath, rootName, kind = "file") {
79017
79707
  fs81.closeSync(opened.fd);
79018
79708
  }
79019
79709
  }
79020
- async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace) {
79021
- const source = await verifyInput(sourceRoot, material);
79710
+ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRootName, protectWorkspace, context) {
79711
+ const verifiedSource = material.kind === "archive_file" ? undefined : await cachedVerifiedInput(sourceRoot, material, context);
79712
+ const source = material.kind === "archive_file" ? context.preparedArchiveFiles.get(archiveMemberCacheKey(material)) : verifiedSource?.source;
79713
+ if (!source) {
79714
+ throw new BenchmarkPhaseError("invalid_archive", `archive member was not prepared: ${material.id}`);
79715
+ }
79022
79716
  const destinationRel = protectWorkspace ? workspaceRel(material.destination, material.kind === "tar_gz") : normalizedRootRelative(material.destination);
79023
79717
  if (!protectWorkspace && destinationRel.toLowerCase() === ".brainbase-benchmark-owner.json") {
79024
79718
  throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
79025
79719
  }
79026
- if (material.kind === "file") {
79720
+ if (material.kind === "file" || material.kind === "archive_file") {
79027
79721
  if (destinationRel === ".") {
79028
79722
  throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
79029
79723
  }
79030
79724
  assertWritableDestination(destinationRoot, destinationRel);
79031
79725
  const destination = path88.resolve(destinationRoot, destinationRel);
79032
- await atomicCopy(source, destination, material.mode, sourceRoot);
79726
+ if (material.kind === "file") {
79727
+ await atomicCopy(source, destination, material.mode ?? verifiedSource?.mode, sourceRoot);
79728
+ } else {
79729
+ await atomicCopy(source, destination, material.mode, path88.dirname(source));
79730
+ }
79033
79731
  const record3 = await recordFile(destinationRoot, destination, destinationRootName);
79034
- if (record3.sha256 !== material.sha256 || record3.size !== material.size_bytes) {
79732
+ const expectedSha256 = material.kind === "archive_file" ? material.file_sha256 : material.sha256;
79733
+ const expectedSize = material.kind === "archive_file" ? material.file_size_bytes : material.size_bytes;
79734
+ if (record3.sha256 !== expectedSha256 || record3.size !== expectedSize) {
79035
79735
  throw new BenchmarkPhaseError("evidence_tampered", `material changed while it was copied: ${material.source}`);
79036
79736
  }
79037
79737
  return [record3];
@@ -79072,17 +79772,39 @@ async function copyMaterial(material, sourceRoot, destinationRoot, destinationRo
79072
79772
  fs81.rmSync(temporary, { recursive: true, force: true });
79073
79773
  }
79074
79774
  }
79075
- async function preflightMaterial(material, sourceRoot, destinationRoot, protectWorkspace) {
79076
- const source = await verifyInput(sourceRoot, material);
79775
+ async function preflightMaterial(material, materials, sourceRoot, destinationRoot, protectWorkspace, context) {
79776
+ const source = (await cachedVerifiedInput(sourceRoot, material, context)).source;
79077
79777
  const destinationRel = protectWorkspace ? workspaceRel(material.destination, material.kind === "tar_gz") : normalizedRootRelative(material.destination);
79078
79778
  if (!protectWorkspace && destinationRel.toLowerCase() === ".brainbase-benchmark-owner.json") {
79079
79779
  throw new BenchmarkPhaseError("reserved_path", "benchmark input cannot replace the phase ownership marker");
79080
79780
  }
79081
- if (material.kind === "file") {
79781
+ if (material.kind === "file" || material.kind === "archive_file") {
79082
79782
  if (destinationRel === ".") {
79083
79783
  throw new BenchmarkPhaseError("unsafe_path", "file destination cannot be a directory root");
79084
79784
  }
79085
79785
  assertWritableDestination(destinationRoot, destinationRel);
79786
+ if (material.kind === "archive_file") {
79787
+ const cacheKey = archiveMemberCacheKey(material);
79788
+ let extracted = context.preparedArchiveFiles.get(cacheKey);
79789
+ if (!extracted) {
79790
+ const temporary2 = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-member-"));
79791
+ context.temporaryRoots.add(temporary2);
79792
+ const archiveKey = archiveSourceCacheKey(material);
79793
+ const related = materials.filter((candidate) => candidate.kind === "archive_file" && archiveSourceCacheKey(candidate) === archiveKey);
79794
+ const extractedMembers = await extractArchiveMembers(source, temporary2, related, context);
79795
+ for (const candidate of related) {
79796
+ const prepared = extractedMembers.get(safeRelPath(candidate.archive_path));
79797
+ if (!prepared) {
79798
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${candidate.archive_path}`);
79799
+ }
79800
+ context.preparedArchiveFiles.set(archiveMemberCacheKey(candidate), prepared);
79801
+ }
79802
+ extracted = context.preparedArchiveFiles.get(cacheKey);
79803
+ }
79804
+ if (!extracted) {
79805
+ throw new BenchmarkPhaseError("missing_input", `archive member does not exist: ${material.archive_path}`);
79806
+ }
79807
+ }
79086
79808
  return [destinationRel];
79087
79809
  }
79088
79810
  const temporary = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-preflight-"));
@@ -79150,14 +79872,18 @@ function prepareOwnedDirectory(root, role, spec) {
79150
79872
  }
79151
79873
  function buildEnvironment(spec, secretNames, additions = {}) {
79152
79874
  const env3 = {};
79875
+ const remoteUrlEnvNames = remoteUrlEnvironmentNames(spec);
79153
79876
  for (const name of BASE_ENV_NAMES) {
79154
- if (process.env[name] !== undefined)
79877
+ if (!remoteUrlEnvNames.has(name) && process.env[name] !== undefined) {
79155
79878
  env3[name] = process.env[name];
79879
+ }
79156
79880
  }
79157
79881
  for (const [name, declared] of Object.entries(spec.environment)) {
79158
79882
  env3[name] = declared.value;
79159
79883
  }
79160
79884
  for (const name of secretNames) {
79885
+ if (remoteUrlEnvNames.has(name))
79886
+ continue;
79161
79887
  const value = process.env[name];
79162
79888
  if (value === undefined) {
79163
79889
  throw new BenchmarkPhaseError("missing_environment", `required environment variable is missing: ${name}`);
@@ -79169,7 +79895,11 @@ function buildEnvironment(spec, secretNames, additions = {}) {
79169
79895
  }
79170
79896
  function redactCommandOutput(data, spec) {
79171
79897
  let value = data.toString("utf8");
79172
- for (const name of spec.secret_env) {
79898
+ const sensitiveNames = new Set([
79899
+ ...spec.secret_env,
79900
+ ...remoteUrlEnvironmentNames(spec)
79901
+ ]);
79902
+ for (const name of sensitiveNames) {
79173
79903
  const secret = process.env[name];
79174
79904
  if (secret)
79175
79905
  value = value.split(secret).join("[REDACTED]");
@@ -79339,16 +80069,19 @@ async function executeHydrate(spec, context) {
79339
80069
  const plannedDestinations = [];
79340
80070
  for (const material of spec.materials) {
79341
80071
  assertBudget(context);
79342
- plannedDestinations.push(...await preflightMaterial(material, spec.staging_root, spec.workspace_root, true));
79343
- const source = await verifyInput(spec.staging_root, material);
79344
- context.inputs.push(await recordFile(spec.staging_root, source, "staging"));
80072
+ const verified = await downloadInputReference(spec.staging_root, material, context);
80073
+ plannedDestinations.push(...await preflightMaterial(material, spec.materials, spec.staging_root, spec.workspace_root, true, context));
80074
+ const record3 = stagedInputRecord(spec.staging_root, verified);
80075
+ if (!context.inputs.some((input) => input.path === record3.path && input.sha256 === record3.sha256 && input.size === record3.size)) {
80076
+ context.inputs.push(record3);
80077
+ }
79345
80078
  }
79346
80079
  validateDestinationGraph(plannedDestinations);
79347
80080
  for (const material of spec.materials) {
79348
80081
  assertBudget(context);
79349
80082
  const started = Date.now();
79350
80083
  try {
79351
- const records = await copyMaterial(material, spec.staging_root, spec.workspace_root, "workspace", true);
80084
+ const records = await copyMaterial(material, spec.staging_root, spec.workspace_root, "workspace", true, context);
79352
80085
  outputs.push(...records);
79353
80086
  context.outputs.push(...records);
79354
80087
  context.steps.push({
@@ -79422,6 +80155,7 @@ async function executeHydrate(spec, context) {
79422
80155
  }
79423
80156
  outputs.splice(0, outputs.length, ...finalOutputs);
79424
80157
  context.outputs.splice(0, context.outputs.length, ...finalOutputs);
80158
+ removeRemoteHydrationInputs(spec);
79425
80159
  assertBudget(context);
79426
80160
  return outputs;
79427
80161
  }
@@ -79486,6 +80220,234 @@ async function workspaceManifest(spec, context) {
79486
80220
  }
79487
80221
  return records.sort((a3, b4) => a3.path.localeCompare(b4.path));
79488
80222
  }
80223
+ function candidateGlob(pattern) {
80224
+ let source = "^";
80225
+ for (let index = 0;index < pattern.length; index += 1) {
80226
+ const char = pattern[index];
80227
+ if (char === "*") {
80228
+ if (pattern[index + 1] === "*") {
80229
+ if (pattern[index + 2] === "/") {
80230
+ source += "(?:.*/)?";
80231
+ index += 2;
80232
+ } else {
80233
+ source += ".*";
80234
+ index += 1;
80235
+ }
80236
+ } else {
80237
+ source += "[^/]*";
80238
+ }
80239
+ continue;
80240
+ }
80241
+ if (char === "?") {
80242
+ source += "[^/]";
80243
+ continue;
80244
+ }
80245
+ source += char.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
80246
+ }
80247
+ return new RegExp(`${source}$`);
80248
+ }
80249
+ function manifestDirectories(manifest, context) {
80250
+ const directories = new Set;
80251
+ for (const entry of manifest) {
80252
+ assertBudget(context);
80253
+ let current = path88.posix.dirname(entry.path);
80254
+ while (current !== ".") {
80255
+ assertBudget(context);
80256
+ directories.add(current);
80257
+ current = path88.posix.dirname(current);
80258
+ }
80259
+ }
80260
+ return [...directories].sort();
80261
+ }
80262
+ function candidateOutputFiles(output, manifest, context) {
80263
+ const matcher = candidateGlob(output.pattern);
80264
+ if (output.kind === "file") {
80265
+ const matched = [];
80266
+ for (const entry of manifest) {
80267
+ assertBudget(context);
80268
+ if (!matcher.test(entry.path))
80269
+ continue;
80270
+ if (entry.kind === "symlink") {
80271
+ throw new BenchmarkPhaseError("unsafe_path", `candidate output ${output.id} matches a symlink`);
80272
+ }
80273
+ matched.push(entry);
80274
+ }
80275
+ return {
80276
+ matchedCount: matched.length,
80277
+ files: matched
80278
+ };
80279
+ }
80280
+ for (const entry of manifest) {
80281
+ assertBudget(context);
80282
+ if (entry.kind === "symlink" && matcher.test(entry.path)) {
80283
+ throw new BenchmarkPhaseError("unsafe_path", `candidate output ${output.id} matches a symlink`);
80284
+ }
80285
+ }
80286
+ const directories = [];
80287
+ for (const directory of manifestDirectories(manifest, context)) {
80288
+ assertBudget(context);
80289
+ if (matcher.test(directory))
80290
+ directories.push(directory);
80291
+ }
80292
+ const selected = new Map;
80293
+ for (const directory of directories) {
80294
+ assertBudget(context);
80295
+ const prefix = `${directory}/`;
80296
+ for (const entry of manifest) {
80297
+ assertBudget(context);
80298
+ if (!entry.path.startsWith(prefix))
80299
+ continue;
80300
+ if (entry.kind === "symlink") {
80301
+ throw new BenchmarkPhaseError("unsafe_path", `candidate output ${output.id} contains a symlink`);
80302
+ }
80303
+ selected.set(entry.path, entry);
80304
+ }
80305
+ }
80306
+ return {
80307
+ matchedCount: directories.length,
80308
+ files: [...selected.values()].sort((left, right) => left.path.localeCompare(right.path))
80309
+ };
80310
+ }
80311
+ async function copyCandidateOutput(output, manifest, spec, context) {
80312
+ const selected = candidateOutputFiles(output, manifest, context);
80313
+ if (!output.required && selected.matchedCount === 0)
80314
+ return [];
80315
+ const minimumMatches = output.required ? Math.max(1, output.min_matches) : output.min_matches;
80316
+ if (selected.matchedCount < minimumMatches || selected.matchedCount > output.max_matches) {
80317
+ throw new BenchmarkPhaseError("candidate_output_match_count", `candidate output ${output.id} matched ${selected.matchedCount} ${output.kind}s`, {
80318
+ actual: selected.matchedCount,
80319
+ min_matches: minimumMatches,
80320
+ max_matches: output.max_matches
80321
+ });
80322
+ }
80323
+ let totalBytes = 0;
80324
+ for (const file of selected.files) {
80325
+ assertBudget(context);
80326
+ totalBytes += file.size;
80327
+ }
80328
+ if (totalBytes > output.max_total_bytes) {
80329
+ throw new BenchmarkPhaseError("candidate_output_size_exceeded", `candidate output ${output.id} exceeds its byte limit`, { actual: totalBytes, max_total_bytes: output.max_total_bytes });
80330
+ }
80331
+ const copied = [];
80332
+ for (const frozenFile of selected.files) {
80333
+ assertBudget(context);
80334
+ const source = path88.resolve(spec.workspace_root, safeRelPath(frozenFile.path));
80335
+ const destination = path88.resolve(spec.logs_root, "candidate-artifacts", output.id, safeRelPath(frozenFile.path));
80336
+ if (fs81.existsSync(destination)) {
80337
+ throw new BenchmarkPhaseError("destination_conflict", `candidate output destination already exists: ${output.id}/${frozenFile.path}`);
80338
+ }
80339
+ await atomicCopy(source, destination, frozenFile.mode, spec.workspace_root);
80340
+ const record3 = await recordFile(spec.logs_root, destination, "logs");
80341
+ if (record3.sha256 !== frozenFile.sha256 || record3.size !== frozenFile.size || record3.mode !== frozenFile.mode) {
80342
+ throw new BenchmarkPhaseError("evidence_tampered", `candidate output changed after the workspace freeze: ${frozenFile.path}`);
80343
+ }
80344
+ copied.push(record3);
80345
+ }
80346
+ return copied;
80347
+ }
80348
+ async function copyFrozenWorkspace(manifest, spec, context) {
80349
+ for (const entry of manifest) {
80350
+ assertBudget(context);
80351
+ if (entry.kind === "symlink") {
80352
+ throw new BenchmarkPhaseError("unsupported_workspace_symlink", `sandbox evaluator workspace cannot safely reproduce symlink: ${entry.path}`);
80353
+ }
80354
+ }
80355
+ const destinationRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-workspace-"));
80356
+ fs81.chmodSync(destinationRoot, 448);
80357
+ context.temporaryRoots.add(destinationRoot);
80358
+ for (const frozenFile of manifest) {
80359
+ assertBudget(context);
80360
+ const source = path88.resolve(spec.workspace_root, safeRelPath(frozenFile.path));
80361
+ const destination = path88.resolve(destinationRoot, safeRelPath(frozenFile.path));
80362
+ await atomicCopy(source, destination, frozenFile.mode, spec.workspace_root);
80363
+ const copied = await recordFile(destinationRoot, destination, "workspace");
80364
+ if (copied.sha256 !== frozenFile.sha256 || copied.size !== frozenFile.size || copied.mode !== frozenFile.mode) {
80365
+ throw new BenchmarkPhaseError("evidence_tampered", `workspace changed after it was frozen: ${frozenFile.path}`);
80366
+ }
80367
+ }
80368
+ return destinationRoot;
80369
+ }
80370
+ function evaluatorTestsPath(evaluator, spec) {
80371
+ if (!evaluator.tests_path)
80372
+ return spec.tests_root;
80373
+ const relative = normalizedRootRelative(evaluator.tests_path);
80374
+ assertNoSymlinkTraversal(spec.tests_root, relative);
80375
+ const candidate = path88.resolve(spec.tests_root, relative);
80376
+ if (!isWithin(spec.tests_root, candidate) || !fs81.existsSync(candidate)) {
80377
+ throw new BenchmarkPhaseError("invalid_tests_path", `evaluator tests_path does not exist: ${evaluator.tests_path}`);
80378
+ }
80379
+ const stat = fs81.lstatSync(candidate);
80380
+ if (stat.isSymbolicLink() || !stat.isDirectory()) {
80381
+ throw new BenchmarkPhaseError("invalid_tests_path", `evaluator tests_path must be a directory: ${evaluator.tests_path}`);
80382
+ }
80383
+ return candidate;
80384
+ }
80385
+ var CriterionResultSchema = exports_external.object({
80386
+ criterion_key: IdSchema,
80387
+ outcome: exports_external.enum(["satisfied", "not_satisfied", "not_applicable"]),
80388
+ explanation: exports_external.string().min(1).max(MAX_CRITERION_EXPLANATION_LENGTH),
80389
+ evidence_ids: exports_external.array(exports_external.string().min(1).max(MAX_CRITERION_EVIDENCE_ID_LENGTH)).max(MAX_CRITERION_EVIDENCE_IDS)
80390
+ }).strict().superRefine((value, context) => {
80391
+ if (new Set(value.evidence_ids).size !== value.evidence_ids.length) {
80392
+ context.addIssue({
80393
+ code: exports_external.ZodIssueCode.custom,
80394
+ path: ["evidence_ids"],
80395
+ message: "evidence_ids must be unique"
80396
+ });
80397
+ }
80398
+ });
80399
+ var CriteriaResultFileSchema = exports_external.object({
80400
+ criteria: exports_external.array(CriterionResultSchema).max(MAX_CRITERIA_PER_EVALUATOR)
80401
+ }).strict();
80402
+ function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds) {
80403
+ let opened;
80404
+ try {
80405
+ opened = openRegularFileNoFollow(resultPath, "criterion result", path88.dirname(resultPath));
80406
+ } catch (error2) {
80407
+ if (error2.code === "ENOENT") {
80408
+ throw new BenchmarkPhaseError("missing_criterion_result", "sandbox evaluator did not write its criterion result");
80409
+ }
80410
+ throw error2;
80411
+ }
80412
+ try {
80413
+ if (opened.stat.size > MAX_CRITERIA_RESULT_BYTES) {
80414
+ throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result exceeds the 1 MiB limit");
80415
+ }
80416
+ let raw;
80417
+ try {
80418
+ raw = JSON.parse(readDescriptor(opened.fd).toString("utf8"));
80419
+ } catch {
80420
+ throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result is not valid JSON");
80421
+ }
80422
+ let parsed;
80423
+ try {
80424
+ parsed = CriteriaResultFileSchema.parse(raw);
80425
+ } catch (error2) {
80426
+ throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result does not match the required schema", error2 instanceof exports_external.ZodError ? error2.issues : undefined);
80427
+ }
80428
+ const byKey = new Map;
80429
+ for (const criterion of parsed.criteria) {
80430
+ if (byKey.has(criterion.criterion_key)) {
80431
+ throw new BenchmarkPhaseError("invalid_criterion_result", `criterion result is duplicated: ${criterion.criterion_key}`);
80432
+ }
80433
+ byKey.set(criterion.criterion_key, criterion);
80434
+ }
80435
+ const expected = new Set(criterionKeys);
80436
+ const extra = [...byKey.keys()].filter((key2) => !expected.has(key2));
80437
+ const missing = criterionKeys.filter((key2) => !byKey.has(key2));
80438
+ if (extra.length > 0 || missing.length > 0) {
80439
+ throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result keys do not match the evaluator plan", { missing, extra });
80440
+ }
80441
+ const allowedEvidence = new Set(allowedEvidenceIds);
80442
+ const unknownEvidenceIds = [...new Set(parsed.criteria.flatMap((criterion) => criterion.evidence_ids))].filter((evidenceId) => !allowedEvidence.has(evidenceId));
80443
+ if (unknownEvidenceIds.length > 0) {
80444
+ throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result cites evidence outside the evaluator plan", { unknown_evidence_ids: unknownEvidenceIds });
80445
+ }
80446
+ return criterionKeys.map((key2) => byKey.get(key2));
80447
+ } finally {
80448
+ fs81.closeSync(opened.fd);
80449
+ }
80450
+ }
79489
80451
  function trajectoryEvents(value) {
79490
80452
  if (Array.isArray(value))
79491
80453
  return value;
@@ -79504,7 +80466,7 @@ function eventType(event) {
79504
80466
  }
79505
80467
  return;
79506
80468
  }
79507
- async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvidence, context) {
80469
+ async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, frozenEvidence, context) {
79508
80470
  const started = Date.now();
79509
80471
  const base2 = {
79510
80472
  id: evaluator.id,
@@ -79516,11 +80478,11 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
79516
80478
  };
79517
80479
  if (evaluator.type === "output_assertion") {
79518
80480
  const assertion = evaluator.assertion;
79519
- let verdict2 = false;
80481
+ let verdict = false;
79520
80482
  if (assertion.operator === "exact")
79521
- verdict2 = finalOutput === assertion.expected;
80483
+ verdict = finalOutput === assertion.expected;
79522
80484
  if (assertion.operator === "contains")
79523
- verdict2 = finalOutput.includes(assertion.expected);
80485
+ verdict = finalOutput.includes(assertion.expected);
79524
80486
  if (assertion.operator === "regex") {
79525
80487
  const regexResult = await runCommand({
79526
80488
  id: `${evaluator.id}.regex`,
@@ -79546,17 +80508,17 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
79546
80508
  if (regexResult.exitCode === 2) {
79547
80509
  throw new BenchmarkPhaseError("invalid_evaluator", `invalid regex in evaluator: ${evaluator.id}`);
79548
80510
  }
79549
- verdict2 = regexResult.exitCode === 0;
80511
+ verdict = regexResult.exitCode === 0;
79550
80512
  }
79551
- return { ...base2, status: verdict2 ? "passed" : "failed", verdict: verdict2, duration_ms: Date.now() - started };
80513
+ return { ...base2, status: verdict ? "passed" : "failed", verdict, duration_ms: Date.now() - started };
79552
80514
  }
79553
80515
  if (evaluator.type === "trajectory_assertion") {
79554
80516
  const count = trajectory.filter((event) => eventType(event) === evaluator.event_type).length;
79555
- const verdict2 = count >= evaluator.min_count && (evaluator.max_count === undefined || count <= evaluator.max_count);
80517
+ const verdict = count >= evaluator.min_count && (evaluator.max_count === undefined || count <= evaluator.max_count);
79556
80518
  return {
79557
80519
  ...base2,
79558
- status: verdict2 ? "passed" : "failed",
79559
- verdict: verdict2,
80520
+ status: verdict ? "passed" : "failed",
80521
+ verdict,
79560
80522
  duration_ms: Date.now() - started,
79561
80523
  details: { count, min_count: evaluator.min_count, max_count: evaluator.max_count }
79562
80524
  };
@@ -79577,16 +80539,16 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
79577
80539
  throw new BenchmarkPhaseError("unsafe_path", `workspace assertion cannot target a symlink: ${relative}`);
79578
80540
  }
79579
80541
  const exists2 = stat !== null;
79580
- let verdict2 = false;
80542
+ let verdict = false;
79581
80543
  if (evaluator.assertion.operator === "exists")
79582
- verdict2 = exists2;
80544
+ verdict = exists2;
79583
80545
  if (evaluator.assertion.operator === "not_exists")
79584
- verdict2 = !exists2;
80546
+ verdict = !exists2;
79585
80547
  if (evaluator.assertion.operator === "sha256") {
79586
80548
  if (stat?.isFile()) {
79587
80549
  const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
79588
80550
  try {
79589
- verdict2 = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
80551
+ verdict = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
79590
80552
  } finally {
79591
80553
  fs81.closeSync(opened.fd);
79592
80554
  }
@@ -79596,37 +80558,82 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
79596
80558
  if (stat?.isFile()) {
79597
80559
  const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
79598
80560
  try {
79599
- verdict2 = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
80561
+ verdict = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
79600
80562
  } finally {
79601
80563
  fs81.closeSync(opened.fd);
79602
80564
  }
79603
80565
  }
79604
80566
  }
79605
- return { ...base2, status: verdict2 ? "passed" : "failed", verdict: verdict2, duration_ms: Date.now() - started };
80567
+ return { ...base2, status: verdict ? "passed" : "failed", verdict, duration_ms: Date.now() - started };
80568
+ }
80569
+ let isolatedWorkspace;
80570
+ let privateResultRoot;
80571
+ try {
80572
+ const evaluatorWorkspace = await copyFrozenWorkspace(manifest, spec, context);
80573
+ isolatedWorkspace = evaluatorWorkspace;
80574
+ const testsPath = evaluatorTestsPath(evaluator, spec);
80575
+ const commandRoot = evaluator.root === "workspace" ? evaluatorWorkspace : spec.tests_root;
80576
+ const command = { id: evaluator.id, ...evaluator.command };
80577
+ const environment = {
80578
+ BRAINBASE_BENCHMARK_WORKSPACE: evaluatorWorkspace,
80579
+ BRAINBASE_BENCHMARK_TESTS: testsPath,
80580
+ BRAINBASE_BENCHMARK_LOGS: spec.logs_root,
80581
+ BRAINBASE_BENCHMARK_FINAL_OUTPUT: frozenEvidence.finalOutputPath,
80582
+ BRAINBASE_BENCHMARK_TRAJECTORY: frozenEvidence.trajectoryPath
80583
+ };
80584
+ let criterionResultPath;
80585
+ if (evaluator.criterion_keys) {
80586
+ privateResultRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-criteria-"));
80587
+ fs81.chmodSync(privateResultRoot, 448);
80588
+ context.temporaryRoots.add(privateResultRoot);
80589
+ criterionResultPath = path88.join(privateResultRoot, "result.json");
80590
+ environment.BRAINBASE_BENCHMARK_CRITERIA_RESULT = criterionResultPath;
80591
+ }
80592
+ const result2 = await runCommand(command, commandRoot, spec, context, environment);
80593
+ const stdout = await writeLog(spec.logs_root, `${evaluator.id}.stdout.log`, result2.stdout, spec);
80594
+ const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
80595
+ let criterionResults;
80596
+ try {
80597
+ criterionResults = evaluator.criterion_keys && criterionResultPath ? readCriterionResults(criterionResultPath, evaluator.criterion_keys, evaluator.allowed_evidence_ids ?? []) : undefined;
80598
+ } catch (error2) {
80599
+ const normalized = stableError(error2);
80600
+ return {
80601
+ ...base2,
80602
+ status: "errored",
80603
+ verdict: null,
80604
+ duration_ms: result2.durationMs,
80605
+ details: {
80606
+ exit_code: result2.exitCode,
80607
+ error_code: normalized?.code ?? "invalid_criterion_result",
80608
+ error_message: normalized?.message ?? "criterion result validation failed"
80609
+ },
80610
+ stdout,
80611
+ stderr
80612
+ };
80613
+ }
80614
+ const verdict = result2.exitCode === 0;
80615
+ return {
80616
+ ...base2,
80617
+ status: verdict ? "passed" : "failed",
80618
+ verdict,
80619
+ duration_ms: result2.durationMs,
80620
+ details: { exit_code: result2.exitCode },
80621
+ stdout,
80622
+ stderr,
80623
+ ...criterionResults ? { criterion_results: criterionResults } : {}
80624
+ };
80625
+ } finally {
80626
+ for (const temporary of [privateResultRoot, isolatedWorkspace]) {
80627
+ if (!temporary)
80628
+ continue;
80629
+ fs81.rmSync(temporary, { recursive: true, force: true });
80630
+ context.temporaryRoots.delete(temporary);
80631
+ }
79606
80632
  }
79607
- const commandRoot = evaluator.root === "workspace" ? spec.workspace_root : spec.tests_root;
79608
- const command = { id: evaluator.id, ...evaluator.command };
79609
- const result2 = await runCommand(command, commandRoot, spec, context, {
79610
- BRAINBASE_BENCHMARK_WORKSPACE: spec.workspace_root,
79611
- BRAINBASE_BENCHMARK_TESTS: spec.tests_root,
79612
- BRAINBASE_BENCHMARK_LOGS: spec.logs_root,
79613
- BRAINBASE_BENCHMARK_FINAL_OUTPUT: frozenEvidence.finalOutputPath,
79614
- BRAINBASE_BENCHMARK_TRAJECTORY: frozenEvidence.trajectoryPath
79615
- });
79616
- const stdout = await writeLog(spec.logs_root, `${evaluator.id}.stdout.log`, result2.stdout, spec);
79617
- const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
79618
- const verdict = result2.exitCode === 0;
79619
- return {
79620
- ...base2,
79621
- status: verdict ? "passed" : "failed",
79622
- verdict,
79623
- duration_ms: result2.durationMs,
79624
- details: { exit_code: result2.exitCode },
79625
- stdout,
79626
- stderr
79627
- };
79628
80633
  }
79629
80634
  async function executeEvaluate(spec, context) {
80635
+ await downloadInputReference(spec.staging_root, spec.evidence.final_output, context);
80636
+ await downloadInputReference(spec.staging_root, spec.evidence.trajectory, context);
79630
80637
  const finalOutput = await readEvidence(spec.staging_root, spec.evidence.final_output);
79631
80638
  const trajectoryEvidence = await readEvidence(spec.staging_root, spec.evidence.trajectory);
79632
80639
  context.inputs.push(finalOutput.record, trajectoryEvidence.record);
@@ -79640,9 +80647,12 @@ async function executeEvaluate(spec, context) {
79640
80647
  const plannedReferences = [];
79641
80648
  for (const reference of spec.references) {
79642
80649
  assertBudget(context);
79643
- plannedReferences.push(...await preflightMaterial(reference, spec.staging_root, spec.tests_root, false));
79644
- const source = await verifyInput(spec.staging_root, reference);
79645
- context.inputs.push(await recordFile(spec.staging_root, source, "staging"));
80650
+ const verified = await downloadInputReference(spec.staging_root, reference, context);
80651
+ plannedReferences.push(...await preflightMaterial(reference, spec.references, spec.staging_root, spec.tests_root, false, context));
80652
+ const record3 = stagedInputRecord(spec.staging_root, verified);
80653
+ if (!context.inputs.some((input) => input.path === record3.path && input.sha256 === record3.sha256 && input.size === record3.size)) {
80654
+ context.inputs.push(record3);
80655
+ }
79646
80656
  }
79647
80657
  validateDestinationGraph(plannedReferences);
79648
80658
  assertBudget(context);
@@ -79691,6 +80701,11 @@ async function executeEvaluate(spec, context) {
79691
80701
  outputs.push(artifact);
79692
80702
  context.outputs.push(artifact);
79693
80703
  }
80704
+ for (const candidateOutput of spec.candidate_outputs) {
80705
+ const copied = await copyCandidateOutput(candidateOutput, manifest, spec, context);
80706
+ outputs.push(...copied);
80707
+ context.outputs.push(...copied);
80708
+ }
79694
80709
  if (spec.capture_workspace_archive) {
79695
80710
  const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
79696
80711
  const archive = path88.join(spec.logs_root, "candidate-workspace.tar.gz");
@@ -79707,7 +80722,7 @@ async function executeEvaluate(spec, context) {
79707
80722
  }
79708
80723
  await verifyRecordsUnchanged(manifest, spec);
79709
80724
  for (const reference of spec.references) {
79710
- const referenceOutputs = await copyMaterial(reference, spec.staging_root, spec.tests_root, "tests", false);
80725
+ const referenceOutputs = await copyMaterial(reference, spec.staging_root, spec.tests_root, "tests", false, context);
79711
80726
  outputs.push(...referenceOutputs);
79712
80727
  context.outputs.push(...referenceOutputs);
79713
80728
  }
@@ -79718,8 +80733,9 @@ async function executeEvaluate(spec, context) {
79718
80733
  for (const evaluator of executionOrder) {
79719
80734
  assertBudget(context);
79720
80735
  const started = Date.now();
80736
+ let requiredResultError;
79721
80737
  try {
79722
- const evaluated = await evaluateOne(evaluator, spec, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
80738
+ const evaluated = await evaluateOne(evaluator, spec, manifest, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
79723
80739
  assertBudget(context);
79724
80740
  evaluators.push(evaluated);
79725
80741
  context.evaluators.push(evaluated);
@@ -79731,6 +80747,11 @@ async function executeEvaluate(spec, context) {
79731
80747
  outputs.push(evaluated.stderr);
79732
80748
  context.outputs.push(evaluated.stderr);
79733
80749
  }
80750
+ if (evaluated.status === "errored" && evaluator.required) {
80751
+ const errorCode = typeof evaluated.details?.error_code === "string" ? evaluated.details.error_code : "evaluator_execution_failed";
80752
+ const errorMessage2 = typeof evaluated.details?.error_message === "string" ? evaluated.details.error_message : "required evaluator execution failed";
80753
+ requiredResultError = new BenchmarkPhaseError(errorCode, errorMessage2);
80754
+ }
79734
80755
  } catch (error2) {
79735
80756
  const normalized = stableError(error2);
79736
80757
  const errored = {
@@ -79754,6 +80775,8 @@ async function executeEvaluate(spec, context) {
79754
80775
  throw error2;
79755
80776
  assertBudget(context);
79756
80777
  }
80778
+ if (requiredResultError)
80779
+ throw requiredResultError;
79757
80780
  }
79758
80781
  await verifyRecordsUnchanged([...context.inputs, ...context.outputs.slice(0, frozenOutputCount)], spec);
79759
80782
  if (!verifyOwnedDirectory(spec.tests_root, "tests", spec) || !verifyOwnedDirectory(spec.logs_root, "logs", spec)) {
@@ -79857,19 +80880,26 @@ function prepareBenchmarkPhaseInvocation(specPathInput, resultPathInput, expecte
79857
80880
  spec_digest: digest,
79858
80881
  timeout_ms: spec.budget.timeout_ms
79859
80882
  };
80883
+ let cachedResult;
79860
80884
  if (fs81.existsSync(resultPath)) {
79861
80885
  try {
79862
80886
  const cached2 = JSON.parse(fs81.readFileSync(resultPath, "utf8"));
79863
80887
  if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
79864
- return {
79865
- ok: true,
79866
- invocation,
79867
- spec_bytes: bytes,
79868
- cached_result: cached2
79869
- };
80888
+ cachedResult = cached2;
79870
80889
  }
79871
80890
  } catch {}
79872
80891
  }
80892
+ if (cachedResult) {
80893
+ if (spec.phase === "hydrate") {
80894
+ removeRemoteHydrationInputs(spec);
80895
+ }
80896
+ return {
80897
+ ok: true,
80898
+ invocation,
80899
+ spec_bytes: bytes,
80900
+ cached_result: cachedResult
80901
+ };
80902
+ }
79873
80903
  return { ok: true, invocation, spec_bytes: bytes };
79874
80904
  } catch (error2) {
79875
80905
  return {
@@ -79966,14 +80996,21 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
79966
80996
  throw new BenchmarkPhaseError("invalid_result_path", `result path must be ${expectedResultPath}`);
79967
80997
  }
79968
80998
  resultPathValidated = true;
80999
+ let cachedResult;
79969
81000
  if (fs81.existsSync(resultPath)) {
79970
81001
  try {
79971
81002
  const cached2 = JSON.parse(fs81.readFileSync(resultPath, "utf8"));
79972
81003
  if (cached2.schema_version === SCHEMA_VERSION && cached2.phase === spec.phase && cached2.attempt_id === spec.attempt_id && cached2.phase_id === spec.phase_id && cached2.spec_digest === digest && cached2.status === "succeeded") {
79973
- return { exitCode: 0, result: cached2 };
81004
+ cachedResult = cached2;
79974
81005
  }
79975
81006
  } catch {}
79976
81007
  }
81008
+ if (cachedResult) {
81009
+ if (spec.phase === "hydrate") {
81010
+ removeRemoteHydrationInputs(spec);
81011
+ }
81012
+ return { exitCode: 0, result: cachedResult };
81013
+ }
79977
81014
  context = {
79978
81015
  deadline: started + spec.budget.timeout_ms,
79979
81016
  remainingOutputBytes: spec.budget.max_output_bytes,
@@ -79981,7 +81018,10 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
79981
81018
  evaluators: [],
79982
81019
  inputs: [],
79983
81020
  outputs: [],
79984
- logsOwned: false
81021
+ logsOwned: false,
81022
+ verifiedInputs: new Map,
81023
+ preparedArchiveFiles: new Map,
81024
+ temporaryRoots: new Set
79985
81025
  };
79986
81026
  if (spec.phase === "hydrate") {
79987
81027
  outputs = await executeHydrate(spec, context);
@@ -80001,6 +81041,11 @@ async function runBenchmarkPhase(specPathInput, resultPathInput, expectedPhase,
80001
81041
  evaluators = context.evaluators;
80002
81042
  }
80003
81043
  }
81044
+ if (context) {
81045
+ for (const temporary of context.temporaryRoots) {
81046
+ fs81.rmSync(temporary, { recursive: true, force: true });
81047
+ }
81048
+ }
80004
81049
  const result2 = {
80005
81050
  schema_version: SCHEMA_VERSION,
80006
81051
  cli_version: VERSION,