@smartergpt/lexrunner 1.5.2 → 2.0.0

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.
@@ -13,6 +13,9 @@ import {
13
13
  canonicalJSONStringify
14
14
  } from "./chunk-UHFMFO54.js";
15
15
  import {
16
+ AXErrorException,
17
+ configInvalidError,
18
+ planValidationError,
16
19
  securitySarifParseError,
17
20
  securityScanFailedError
18
21
  } from "./chunk-26SCN2LJ.js";
@@ -243,7 +246,7 @@ function emitDeprecationNotice(oldVar, newVar) {
243
246
  }
244
247
  deprecationNotices.add(key);
245
248
  console.warn(
246
- `\u26A0\uFE0F Environment variable ${oldVar} is deprecated. Use ${newVar} instead. Support for ${oldVar} will be removed in v2.0.0.`
249
+ `\u26A0\uFE0F Environment variable ${oldVar} is deprecated. Use ${newVar} instead. Support for ${oldVar} will be removed in v3.0.0.`
247
250
  );
248
251
  }
249
252
 
@@ -1869,11 +1872,12 @@ function createGitOperations(workingDir) {
1869
1872
 
1870
1873
  // src/gates.ts
1871
1874
  import { spawn as spawn2 } from "child_process";
1875
+ import { createHash as createHash2 } from "crypto";
1872
1876
  import path9 from "path";
1873
1877
  import fs9 from "fs";
1874
1878
 
1875
1879
  // src/security/scanning.ts
1876
- import { AXErrorException } from "@smartergpt/lex/errors";
1880
+ import { AXErrorException as AXErrorException2 } from "@smartergpt/lex/errors";
1877
1881
  var DEFAULT_SECURITY_POLICY = {
1878
1882
  blockCritical: true,
1879
1883
  blockHigh: true,
@@ -1904,7 +1908,7 @@ var NpmAuditScanner = class {
1904
1908
  originalError: error instanceof Error ? error.message : String(error)
1905
1909
  }
1906
1910
  );
1907
- throw new AXErrorException(
1911
+ throw new AXErrorException2(
1908
1912
  axError.code,
1909
1913
  axError.message,
1910
1914
  axError.nextActions,
@@ -1970,7 +1974,7 @@ var NpmAuditScanner = class {
1970
1974
  };
1971
1975
 
1972
1976
  // src/security/sarif.ts
1973
- import { AXErrorException as AXErrorException2 } from "@smartergpt/lex/errors";
1977
+ import { AXErrorException as AXErrorException3 } from "@smartergpt/lex/errors";
1974
1978
  function mapSarifLevel(level, securitySeverity) {
1975
1979
  if (securitySeverity) {
1976
1980
  const normalized2 = securitySeverity.toLowerCase();
@@ -1994,7 +1998,7 @@ function parseSarif(sarifContent) {
1994
1998
  `Invalid SARIF JSON: ${error instanceof Error ? error.message : String(error)}`,
1995
1999
  { parseError: error instanceof Error ? error.message : String(error) }
1996
2000
  );
1997
- throw new AXErrorException2(axError.code, axError.message, axError.nextActions, axError.context);
2001
+ throw new AXErrorException3(axError.code, axError.message, axError.nextActions, axError.context);
1998
2002
  }
1999
2003
  if (!sarif.runs || sarif.runs.length === 0) {
2000
2004
  return createEmptyResult("sarif");
@@ -3216,8 +3220,768 @@ import {
3216
3220
  writeFileSync as writeFileSync5
3217
3221
  } from "fs";
3218
3222
  import { basename as basename2, delimiter, dirname, extname, isAbsolute as isAbsolute2, join as join9, resolve as resolve5 } from "path";
3219
- var GATE_EXECUTION_RECEIPT_SCHEMA_VERSION = "lexrunner-gate-execution-receipt/v1";
3223
+ import { z as z8 } from "zod";
3224
+
3225
+ // src/schema.ts
3226
+ import { z as z6 } from "zod";
3227
+
3228
+ // src/tiers/schema.ts
3229
+ import { z as z5 } from "zod";
3230
+ var CapabilityTier = z5.enum(["senior", "mid", "junior"]);
3231
+ var TierAssignment = z5.object({
3232
+ /** Suggested tier based on heuristics */
3233
+ suggested: CapabilityTier,
3234
+ /** Actual tier used during execution (may differ due to override) */
3235
+ actual: CapabilityTier.optional(),
3236
+ /** Whether the task was escalated to a higher tier */
3237
+ escalated: z5.boolean().default(false),
3238
+ /** Reason for escalation if applicable */
3239
+ escalationReason: z5.string().optional(),
3240
+ /** Whether actual tier differs from suggested tier */
3241
+ mismatch: z5.boolean().optional()
3242
+ });
3243
+ var TierOverride = z5.object({
3244
+ /** Item name to override */
3245
+ itemName: z5.string(),
3246
+ /** Tier to assign */
3247
+ tier: CapabilityTier
3248
+ });
3249
+ function parseTierOverride(overrideStr) {
3250
+ const parts = overrideStr.split("=");
3251
+ if (parts.length !== 2) {
3252
+ return null;
3253
+ }
3254
+ const [itemName, tierStr] = parts;
3255
+ const tierResult = CapabilityTier.safeParse(tierStr.toLowerCase());
3256
+ if (!tierResult.success || !itemName) {
3257
+ return null;
3258
+ }
3259
+ return {
3260
+ itemName: itemName.trim(),
3261
+ tier: tierResult.data
3262
+ };
3263
+ }
3264
+ function parseTierOverrides(overrides) {
3265
+ const overrideList = typeof overrides === "string" ? overrides.split(",") : overrides;
3266
+ const result = [];
3267
+ for (const override of overrideList) {
3268
+ const parsed = parseTierOverride(override.trim());
3269
+ if (parsed) {
3270
+ result.push(parsed);
3271
+ }
3272
+ }
3273
+ return result;
3274
+ }
3275
+
3276
+ // src/schema.ts
3277
+ var GateStatus = z6.enum(["pass", "fail", "blocked", "skipped", "retrying"]);
3278
+ var NodeStatus = z6.enum(["pass", "fail", "blocked", "skipped", "retrying"]);
3279
+ var GateResult = z6.object({
3280
+ gate: z6.string(),
3281
+ status: GateStatus,
3282
+ exitCode: z6.number().optional(),
3283
+ duration: z6.number().optional(),
3284
+ // milliseconds
3285
+ timeoutMs: z6.number().int().positive().optional(),
3286
+ // effective timeout used for this gate
3287
+ stdout: z6.string().optional(),
3288
+ stderr: z6.string().optional(),
3289
+ failureKind: z6.enum(["nonzero_exit", "spawn_error", "timeout", "evidence_error"]).optional(),
3290
+ timeoutCleanup: z6.object({
3291
+ method: z6.enum(["process-group", "taskkill", "direct-child"]),
3292
+ forceKilled: z6.boolean(),
3293
+ descendantsReaped: z6.boolean()
3294
+ }).optional(),
3295
+ artifacts: z6.array(z6.string()).optional(),
3296
+ attempts: z6.number().default(1),
3297
+ lastAttempt: z6.string().optional()
3298
+ // ISO timestamp
3299
+ });
3300
+ var NodeResult = z6.object({
3301
+ name: z6.string(),
3302
+ status: NodeStatus,
3303
+ gates: z6.array(GateResult).default([]),
3304
+ blockedBy: z6.array(z6.string()).optional(),
3305
+ // names of nodes that blocked this one
3306
+ eligibleForMerge: z6.boolean().default(false)
3307
+ });
3308
+ var SchemaVersion = z6.string().regex(/^1\.\d+\.\d+$/, "Schema version must be 1.x.y format");
3309
+ function validateSchemaVersion(version) {
3310
+ const parsed = SchemaVersion.safeParse(version);
3311
+ if (!parsed.success) {
3312
+ const axError = configInvalidError(
3313
+ `Unsupported schema version: ${version}. This runner only supports schema version 1.x.y`,
3314
+ { version, expected: "1.x.y" }
3315
+ );
3316
+ throw new AXErrorException(axError.code, axError.message, axError.nextActions, axError.context);
3317
+ }
3318
+ const [major] = version.split(".").map(Number);
3319
+ if (major !== 1) {
3320
+ const axError = configInvalidError(
3321
+ `Incompatible schema major version: ${major}. This runner only supports major version 1.`,
3322
+ { version, major, expectedMajor: 1 }
3323
+ );
3324
+ throw new AXErrorException(axError.code, axError.message, axError.nextActions, axError.context);
3325
+ }
3326
+ }
3327
+ var RetryConfig = z6.object({
3328
+ maxAttempts: z6.number().int().min(1).default(1),
3329
+ backoffSeconds: z6.number().min(0).default(0)
3330
+ });
3331
+ var AdminOverride = z6.object({
3332
+ allowedUsers: z6.array(z6.string()).optional(),
3333
+ requireReason: z6.boolean().default(false)
3334
+ });
3335
+ var MergeRule = z6.object({
3336
+ type: z6.enum(["strict-required"]).default("strict-required")
3337
+ // Future: could add "best-effort", "admin-override-allowed", etc.
3338
+ });
3339
+ var PerformanceConfig = z6.object({
3340
+ maxMemoryMB: z6.number().int().min(128).optional(),
3341
+ // Memory limit in MB
3342
+ batchSize: z6.number().int().min(1).default(50),
3343
+ // Batch size for large plans
3344
+ cacheTTLSeconds: z6.number().int().min(0).default(3600),
3345
+ // Cache TTL in seconds
3346
+ enableCaching: z6.boolean().default(true),
3347
+ // Enable operation caching
3348
+ throttleOnMemory: z6.boolean().default(true),
3349
+ // Throttle workers when memory high
3350
+ memoryThresholdPercent: z6.number().min(0).max(100).default(80)
3351
+ // Memory threshold %
3352
+ }).default(() => ({
3353
+ batchSize: 50,
3354
+ cacheTTLSeconds: 3600,
3355
+ enableCaching: true,
3356
+ throttleOnMemory: true,
3357
+ memoryThresholdPercent: 80
3358
+ }));
3359
+ var VulnPolicy = z6.object({
3360
+ blockCritical: z6.boolean().default(true),
3361
+ blockHigh: z6.boolean().default(true),
3362
+ maxMedium: z6.number().int().min(0).default(5),
3363
+ maxLow: z6.number().int().min(0).default(10)
3364
+ }).default(() => ({
3365
+ blockCritical: true,
3366
+ blockHigh: true,
3367
+ maxMedium: 5,
3368
+ maxLow: 10
3369
+ }));
3370
+ var Policy = z6.object({
3371
+ requiredGates: z6.array(z6.string()).default([]),
3372
+ optionalGates: z6.array(z6.string()).default([]),
3373
+ maxWorkers: z6.number().int().min(1).default(1),
3374
+ retries: z6.record(z6.string(), RetryConfig).default(() => ({})),
3375
+ overrides: z6.object({
3376
+ adminGreen: AdminOverride.optional()
3377
+ }).default(() => ({})),
3378
+ blockOn: z6.array(z6.string()).default([]),
3379
+ mergeRule: MergeRule.default({ type: "strict-required" }),
3380
+ performance: PerformanceConfig.optional(),
3381
+ // Performance tuning options
3382
+ security: VulnPolicy.optional()
3383
+ // Security/vulnerability thresholds for vuln gate
3384
+ });
3385
+ var ContainerMount = z6.object({
3386
+ source: z6.string(),
3387
+ target: z6.string(),
3388
+ type: z6.enum(["bind", "volume"]).default("bind")
3389
+ });
3390
+ var ContainerSpec = z6.object({
3391
+ image: z6.string(),
3392
+ entrypoint: z6.array(z6.string()).optional(),
3393
+ mounts: z6.array(ContainerMount).optional()
3394
+ });
3395
+ var Gate = z6.object({
3396
+ name: z6.string(),
3397
+ run: z6.string(),
3398
+ cwd: z6.string().optional(),
3399
+ env: z6.record(z6.string(), z6.string()).default(() => ({})),
3400
+ // Runtime configuration
3401
+ runtime: z6.enum(["local", "container", "ci-service"]).default("local"),
3402
+ // Container spec (only used when runtime is "container")
3403
+ container: ContainerSpec.optional(),
3404
+ // Expected artifact paths (for output collection)
3405
+ artifacts: z6.array(z6.string()).default([]),
3406
+ // Optional input data for gates that require structured inputs (validated against gate-specific schemas)
3407
+ input: z6.record(z6.string(), z6.unknown()).optional(),
3408
+ // Exact per-gate timeout. Overrides the operation default after hostility adjustment.
3409
+ timeoutMs: z6.number().int().positive().max(24 * 60 * 60 * 1e3).optional()
3410
+ }).strict();
3411
+ var PlanItem = z6.object({
3412
+ name: z6.string(),
3413
+ deps: z6.string().array().default([]),
3414
+ // Dependency references by item name
3415
+ gates: z6.array(Gate).default([]),
3416
+ // Tier routing for governance (optional - added during plan generation or execution)
3417
+ tier: TierAssignment.optional()
3418
+ }).strict();
3419
+ var Plan = z6.object({
3420
+ schemaVersion: SchemaVersion,
3421
+ target: z6.string().default("main"),
3422
+ policy: Policy.optional(),
3423
+ items: z6.array(PlanItem).default([])
3424
+ }).strict().superRefine((plan, context) => {
3425
+ const itemNames = /* @__PURE__ */ new Set();
3426
+ let duplicateItemNameFound = false;
3427
+ const duplicateGateNameItemIndexes = [];
3428
+ for (const [itemIndex, item] of plan.items.entries()) {
3429
+ if (itemNames.has(item.name)) {
3430
+ duplicateItemNameFound = true;
3431
+ }
3432
+ itemNames.add(item.name);
3433
+ const gateNames = /* @__PURE__ */ new Set();
3434
+ let duplicateGateNameFound = false;
3435
+ for (const gate of item.gates) {
3436
+ if (gateNames.has(gate.name)) {
3437
+ duplicateGateNameFound = true;
3438
+ }
3439
+ gateNames.add(gate.name);
3440
+ }
3441
+ if (duplicateGateNameFound) duplicateGateNameItemIndexes.push(itemIndex);
3442
+ }
3443
+ if (duplicateItemNameFound) {
3444
+ context.addIssue({
3445
+ code: "custom",
3446
+ path: ["items"],
3447
+ message: "Plan item names must be unique",
3448
+ params: { validationCode: "DUPLICATE_NAMES" }
3449
+ });
3450
+ }
3451
+ for (const itemIndex of duplicateGateNameItemIndexes) {
3452
+ context.addIssue({
3453
+ code: "custom",
3454
+ path: ["items", itemIndex, "gates"],
3455
+ message: "Gate names must be unique within an item",
3456
+ params: { validationCode: "DUPLICATE_GATE_NAMES" }
3457
+ });
3458
+ }
3459
+ });
3460
+ var MAX_SCHEMA_VALIDATION_ERRORS = 50;
3461
+ var MAX_SCHEMA_VALIDATION_PATH_BYTES = 256;
3462
+ var MAX_SCHEMA_VALIDATION_MESSAGE_BYTES = 512;
3463
+ var MAX_SCHEMA_VALIDATION_ACTION_BYTES = 512;
3464
+ var SchemaValidationError = class extends AXErrorException {
3465
+ constructor(issues) {
3466
+ const errorCount = issues.length;
3467
+ const errors = issues.slice(0, MAX_SCHEMA_VALIDATION_ERRORS).map(normalizeValidationIssue);
3468
+ const errorsTruncated = errorCount > errors.length;
3469
+ const errorStrings = errors.map((e) => `${e.path}: ${e.message}`);
3470
+ const axError = planValidationError({
3471
+ errors: errorStrings,
3472
+ errorCount,
3473
+ errorsTruncated
3474
+ // planPath is omitted as it's not available in this context
3475
+ });
3476
+ super(axError.code, axError.message, axError.nextActions, axError.context);
3477
+ this.name = "SchemaValidationError";
3478
+ this.issues = issues;
3479
+ this.errors = errors;
3480
+ this.errorCount = errorCount;
3481
+ this.errorsTruncated = errorsTruncated;
3482
+ }
3483
+ /**
3484
+ * Get legacy machine-readable error format for backward compatibility
3485
+ */
3486
+ toLegacyJSON() {
3487
+ return {
3488
+ valid: false,
3489
+ errors: this.errors
3490
+ };
3491
+ }
3492
+ };
3493
+ function formatPlanValidationFailure(error) {
3494
+ const nextActions = error.axError.nextActions.filter((action) => !action.startsWith("Errors:")).slice(0, 10).map((action) => boundDiagnostic(action, MAX_SCHEMA_VALIDATION_ACTION_BYTES));
3495
+ return {
3496
+ contract: "bounded-ax-v1",
3497
+ valid: false,
3498
+ code: error.axError.code,
3499
+ message: boundDiagnostic(error.message, MAX_SCHEMA_VALIDATION_MESSAGE_BYTES),
3500
+ errorCount: error.errorCount,
3501
+ errors: error.errors,
3502
+ errorsTruncated: error.errorsTruncated,
3503
+ nextActions: nextActions.length > 0 ? nextActions : ["Review each validation path and update the plan"],
3504
+ context: {
3505
+ errorCount: error.errorCount,
3506
+ errorsTruncated: error.errorsTruncated
3507
+ }
3508
+ };
3509
+ }
3510
+ function asPlanValidationFailure(error) {
3511
+ if (error instanceof SchemaValidationError) return formatPlanValidationFailure(error);
3512
+ if (!(error instanceof AXErrorException) || error.axError.code !== "CONFIG_INVALID") {
3513
+ return void 0;
3514
+ }
3515
+ const message = boundDiagnostic(error.message, MAX_SCHEMA_VALIDATION_MESSAGE_BYTES);
3516
+ return {
3517
+ contract: "bounded-ax-v1",
3518
+ valid: false,
3519
+ code: error.axError.code,
3520
+ message,
3521
+ errorCount: 1,
3522
+ errors: [{ path: "root", message, code: error.axError.code }],
3523
+ errorsTruncated: false,
3524
+ nextActions: error.axError.nextActions.slice(0, 10).map((action) => boundDiagnostic(action, MAX_SCHEMA_VALIDATION_ACTION_BYTES)),
3525
+ context: {
3526
+ errorCount: 1,
3527
+ errorsTruncated: false
3528
+ }
3529
+ };
3530
+ }
3531
+ function formatPlanValidationFailureText(failure) {
3532
+ const lines = [failure.message];
3533
+ for (const error of failure.errors) {
3534
+ lines.push(` - ${error.path} [${error.code}]: ${error.message}`);
3535
+ }
3536
+ if (failure.errorsTruncated) {
3537
+ lines.push(
3538
+ ` - \u2026 ${failure.errorCount - failure.errors.length} additional validation error(s) omitted`
3539
+ );
3540
+ }
3541
+ return lines.join("\n");
3542
+ }
3543
+ function normalizeValidationIssue(issue) {
3544
+ const path11 = normalizeValidationPath(issue.path);
3545
+ const stableCustomIssue = safeCustomValidationIssue(issue);
3546
+ return {
3547
+ path: boundDiagnostic(path11, MAX_SCHEMA_VALIDATION_PATH_BYTES),
3548
+ message: boundDiagnostic(
3549
+ stableCustomIssue?.message ?? safeValidationMessage(issue.code),
3550
+ MAX_SCHEMA_VALIDATION_MESSAGE_BYTES
3551
+ ),
3552
+ code: stableCustomIssue?.code ?? issue.code
3553
+ };
3554
+ }
3555
+ function safeCustomValidationIssue(issue) {
3556
+ if (issue.code !== "custom") return void 0;
3557
+ switch (issue.params?.validationCode) {
3558
+ case "DUPLICATE_NAMES":
3559
+ return { code: "DUPLICATE_NAMES", message: "Plan item names must be unique" };
3560
+ case "DUPLICATE_GATE_NAMES":
3561
+ return {
3562
+ code: "DUPLICATE_GATE_NAMES",
3563
+ message: "Gate names must be unique within an item"
3564
+ };
3565
+ default:
3566
+ return void 0;
3567
+ }
3568
+ }
3569
+ function normalizeValidationPath(segments) {
3570
+ if (segments.length === 0) return "root";
3571
+ return segments.map((segment, index) => {
3572
+ const previous = segments[index - 1];
3573
+ if (previous === "retries" || previous === "env" || previous === "input") {
3574
+ return "<key>";
3575
+ }
3576
+ return String(segment);
3577
+ }).join(".");
3578
+ }
3579
+ function safeValidationMessage(code) {
3580
+ switch (code) {
3581
+ case "invalid_type":
3582
+ return "Value has an invalid type";
3583
+ case "invalid_value":
3584
+ return "Value is not an allowed option";
3585
+ case "too_big":
3586
+ return "Value exceeds the allowed maximum";
3587
+ case "too_small":
3588
+ return "Value is below the allowed minimum";
3589
+ case "invalid_format":
3590
+ return "Value does not match the required format";
3591
+ case "not_multiple_of":
3592
+ return "Value is not an allowed multiple";
3593
+ case "unrecognized_keys":
3594
+ return "Object contains one or more unrecognized keys";
3595
+ case "invalid_union":
3596
+ return "Value does not match any allowed shape";
3597
+ case "invalid_key":
3598
+ return "Object contains an invalid key";
3599
+ case "invalid_element":
3600
+ return "Collection contains an invalid element";
3601
+ case "custom":
3602
+ return "Value failed schema validation";
3603
+ default:
3604
+ return "Value does not satisfy schema requirements";
3605
+ }
3606
+ }
3607
+ function boundDiagnostic(value, maxBytes) {
3608
+ const singleLine = value.replace(
3609
+ /[\u0000-\u001f\u007f]/g,
3610
+ (character) => JSON.stringify(character).slice(1, -1)
3611
+ );
3612
+ const encoded = Buffer.from(singleLine, "utf8");
3613
+ if (encoded.length <= maxBytes) return singleLine;
3614
+ const suffix = "\u2026 [truncated]";
3615
+ const suffixBytes = Buffer.byteLength(suffix, "utf8");
3616
+ let end = Math.max(0, maxBytes - suffixBytes);
3617
+ while (end > 0 && (encoded[end] & 192) === 128) end -= 1;
3618
+ return `${encoded.subarray(0, end).toString("utf8")}${suffix}`;
3619
+ }
3620
+ function validatePlan(planData) {
3621
+ const result = Plan.safeParse(planData);
3622
+ if (!result.success) {
3623
+ throw new SchemaValidationError(result.error.issues);
3624
+ }
3625
+ validateSchemaVersion(result.data.schemaVersion);
3626
+ return result.data;
3627
+ }
3628
+ function loadPlan(planContent) {
3629
+ try {
3630
+ const planData = JSON.parse(planContent);
3631
+ return validatePlan(planData);
3632
+ } catch (error) {
3633
+ if (error instanceof SyntaxError) {
3634
+ const axError = configInvalidError("Invalid JSON: plan content could not be parsed", {
3635
+ parseError: "MALFORMED_JSON"
3636
+ });
3637
+ throw new AXErrorException(
3638
+ axError.code,
3639
+ axError.message,
3640
+ axError.nextActions,
3641
+ axError.context
3642
+ );
3643
+ }
3644
+ throw error;
3645
+ }
3646
+ }
3647
+
3648
+ // src/schemas/task-contract.ts
3649
+ import { createHash } from "crypto";
3650
+ import { z as z7 } from "zod";
3651
+ var TASK_CONTRACT_VERSION = "1.0.0";
3652
+ function computeCanonicalHash(obj) {
3653
+ const canonical = JSON.stringify(obj, sortedReplacer);
3654
+ return computeCanonicalHashFromCompactJSON(canonical);
3655
+ }
3656
+ function computeCanonicalHashFromCompactJSON(canonical) {
3657
+ const hash = createHash("sha256").update(canonical, "utf8").digest("hex");
3658
+ return `sha256:${hash}`;
3659
+ }
3660
+ function sortedReplacer(_key, value) {
3661
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3662
+ return Object.keys(value).sort().reduce(
3663
+ (sorted, key) => {
3664
+ sorted[key] = value[key];
3665
+ return sorted;
3666
+ },
3667
+ {}
3668
+ );
3669
+ }
3670
+ return value;
3671
+ }
3672
+ var DeterminismLevel = z7.enum(["D1", "D2", "D3"]);
3673
+ var ConfidenceLevel2 = z7.enum(["high", "medium", "low"]);
3674
+ var SourceOfTruthKind = z7.enum(["symbol", "file", "registry"]);
3675
+ var AssumptionType = z7.enum(["scope", "codebase", "env", "intent", "dependency", "test"]);
3676
+ var RepoRelativePath = z7.string().refine((p) => !p.startsWith("/"), {
3677
+ message: "Path must be repo-relative (no leading slash)"
3678
+ }).refine((p) => !p.includes(":\\") && !p.includes(":/"), {
3679
+ message: "Path must not be absolute (no drive letters)"
3680
+ }).refine((p) => !p.startsWith(".."), {
3681
+ message: "Path must not escape repo root"
3682
+ });
3683
+ var GlobPattern = z7.string().min(1);
3684
+ var SHA256Hash = z7.string().regex(/^sha256:[a-f0-9]{64}$/, "Must be sha256:<64-hex-chars>");
3685
+ var SHA256HashOrPlaceholder = z7.string().refine((h) => h.startsWith("sha256:"), {
3686
+ message: "Must start with sha256:"
3687
+ });
3688
+ var RepoProvenance = z7.object({
3689
+ /** Repository identifier (owner/name) */
3690
+ id: z7.string().regex(/^[^/]+\/[^/]+$/, "Must be owner/repo format"),
3691
+ /** Absolute path to repo root (engine-local, for resolution) */
3692
+ root: z7.string(),
3693
+ /** Pinned commit SHA */
3694
+ commit_sha: z7.string().min(7)
3695
+ });
3696
+ var ScopeBoundary = z7.object({
3697
+ /** Globs for files agent can read */
3698
+ read_globs: z7.array(GlobPattern),
3699
+ /** Globs for files agent can modify */
3700
+ write_globs: z7.array(GlobPattern),
3701
+ /** Globs for files explicitly denied (always applied) */
3702
+ deny_globs: z7.array(GlobPattern),
3703
+ /** Whether cross-repo operations are permitted */
3704
+ cross_repo_allowed: z7.boolean()
3705
+ });
3706
+ var FailureEvidence = z7.object({
3707
+ /** Short error description */
3708
+ message: z7.string(),
3709
+ /** Repo-relative path to failed file */
3710
+ file_rel: RepoRelativePath,
3711
+ /** Line number if available */
3712
+ line: z7.number().int().positive().optional(),
3713
+ /** Actual test runner output snippet */
3714
+ runner_output_snip: z7.string(),
3715
+ /** Code context around failure */
3716
+ excerpt: z7.string().optional()
3717
+ });
3718
+ var HintEdit = z7.object({
3719
+ find: z7.string(),
3720
+ replace: z7.string()
3721
+ });
3722
+ var Target = z7.object({
3723
+ /** Repo-relative file path */
3724
+ path_rel: RepoRelativePath,
3725
+ /** Anchored code context (±N lines) */
3726
+ hunk: z7.string(),
3727
+ /** SHA256 of hunk for drift detection */
3728
+ hunk_sha256: SHA256HashOrPlaceholder,
3729
+ /** Optional find/replace suggestion */
3730
+ hint_edit: HintEdit.optional()
3731
+ });
3732
+ var IntroducingChange = z7.object({
3733
+ commit_sha: z7.string().min(7),
3734
+ diff_hunk: z7.string()
3735
+ });
3736
+ var SourceOfTruth = z7.object({
3737
+ /** Kind of source */
3738
+ kind: SourceOfTruthKind,
3739
+ /** Repo-relative path */
3740
+ path_rel: RepoRelativePath,
3741
+ /** Repository ID (defaults to snapshot repo if omitted) */
3742
+ repo_id: z7.string().optional(),
3743
+ /** Commit SHA (defaults to snapshot commit if omitted) */
3744
+ commit_sha: z7.string().optional(),
3745
+ /** Canonical excerpt */
3746
+ excerpt: z7.string(),
3747
+ /** Lexmap module ID if applicable */
3748
+ lexmap_module_id: z7.string().optional(),
3749
+ /** Change that introduced this */
3750
+ introducing_change: IntroducingChange.optional()
3751
+ });
3752
+ var VerificationExpectations = z7.object({
3753
+ /** Command to run */
3754
+ cmd: z7.string(),
3755
+ /** Expected results */
3756
+ expect: z7.object({
3757
+ /** Expected exit code (usually 0) */
3758
+ exit_code: z7.number().int(),
3759
+ /** Strings that must appear in output */
3760
+ must_include: z7.array(z7.string()).optional(),
3761
+ /** Strings that must not appear */
3762
+ must_not_include: z7.array(z7.string()).optional()
3763
+ })
3764
+ });
3765
+ var Budget = z7.object({
3766
+ /** Token budget hint in bytes */
3767
+ max_bytes: z7.number().int().positive().optional(),
3768
+ /** Fields that were truncated (empty if none) */
3769
+ truncated_fields: z7.array(z7.string())
3770
+ });
3771
+ var TaskSnapshot_v1 = z7.object({
3772
+ // Schema version
3773
+ schema_version: z7.literal(TASK_CONTRACT_VERSION),
3774
+ // Identity
3775
+ task_id: z7.string().min(1),
3776
+ procedure: z7.string().min(1),
3777
+ determinism: DeterminismLevel,
3778
+ snapshot_hash: SHA256HashOrPlaceholder,
3779
+ // Provenance (MUST)
3780
+ repo: RepoProvenance,
3781
+ // Scope boundary (MUST)
3782
+ scope: ScopeBoundary,
3783
+ // Failure evidence (MUST)
3784
+ failure: FailureEvidence,
3785
+ // Invariants (SHOULD) - anti-brittleness constraints
3786
+ invariants: z7.array(z7.string()).optional(),
3787
+ // Targets (MUST, array)
3788
+ targets: z7.array(Target).min(1),
3789
+ // Source of truth (SHOULD)
3790
+ source_of_truth: SourceOfTruth.optional(),
3791
+ // Verification expectations (MUST)
3792
+ verification: VerificationExpectations,
3793
+ // Budget/truncation (MUST)
3794
+ budget: Budget,
3795
+ // Output contract
3796
+ receipt_schema_id: z7.string()
3797
+ });
3798
+ var StructuredAssumption = z7.object({
3799
+ /** Type of assumption */
3800
+ type: AssumptionType,
3801
+ /** Assumption text */
3802
+ text: z7.string(),
3803
+ /** Whether it was validated */
3804
+ validated: z7.boolean().optional(),
3805
+ /** Evidence supporting validation */
3806
+ evidence: z7.string().optional()
3807
+ });
3808
+ var AgentClaims = z7.object({
3809
+ /** Whether the task succeeded */
3810
+ success: z7.boolean(),
3811
+ /** Unified diff patch */
3812
+ patch: z7.string().optional(),
3813
+ /** Files touched (repo-relative) */
3814
+ files_touched: z7.array(RepoRelativePath),
3815
+ /** Rationale for the fix */
3816
+ rationale: z7.string(),
3817
+ /** Confidence level */
3818
+ confidence: ConfidenceLevel2,
3819
+ /** Which invariants were respected */
3820
+ invariants_respected: z7.array(z7.string()).optional(),
3821
+ /** Structured assumptions made */
3822
+ assumptions_made: z7.array(StructuredAssumption)
3823
+ });
3824
+ var SearchActivity = z7.object({
3825
+ /** Search query */
3826
+ query: z7.string(),
3827
+ /** Search method used */
3828
+ method: z7.string().optional(),
3829
+ /** Roots searched (repo-relative) */
3830
+ roots: z7.array(z7.string()),
3831
+ /** Number of results found */
3832
+ results_count: z7.number().int().nonnegative().optional(),
3833
+ /** Time taken in milliseconds */
3834
+ time_ms: z7.number().nonnegative().optional()
3835
+ });
3836
+ var TokenUsage = z7.object({
3837
+ input: z7.number().int().nonnegative(),
3838
+ output: z7.number().int().nonnegative(),
3839
+ total: z7.number().int().nonnegative()
3840
+ });
3841
+ var CostTracking = z7.object({
3842
+ /** Token usage breakdown */
3843
+ token_usage: TokenUsage.optional(),
3844
+ /** Number of tool calls made */
3845
+ tool_calls_count: z7.number().int().nonnegative().optional(),
3846
+ /** Elapsed time in milliseconds */
3847
+ elapsed_ms: z7.number().nonnegative().optional()
3848
+ });
3849
+ var AgentVerification = z7.object({
3850
+ /** Whether verification command was run */
3851
+ cmd_ran: z7.boolean(),
3852
+ /** Exit code if run */
3853
+ exit_code: z7.number().int().optional(),
3854
+ /** Output snippet */
3855
+ output_snip: z7.string().optional()
3856
+ });
3857
+ var TaskReceipt_v1 = z7.object({
3858
+ // Schema version
3859
+ schema_version: z7.literal(TASK_CONTRACT_VERSION),
3860
+ // Identity (echo from snapshot)
3861
+ task_id: z7.string().min(1),
3862
+ snapshot_hash: SHA256HashOrPlaceholder,
3863
+ // Claims (what agent says it did)
3864
+ claims: AgentClaims,
3865
+ // Search activity (if agent searched)
3866
+ search_activity: z7.array(SearchActivity),
3867
+ // Cost tracking
3868
+ cost: CostTracking,
3869
+ // Agent's verification attempt (still a claim)
3870
+ agent_verification: AgentVerification.optional(),
3871
+ // Blockers (if not successful)
3872
+ blockers: z7.array(z7.string())
3873
+ });
3874
+ var DetectedFailure = z7.object({
3875
+ type: z7.string(),
3876
+ message: z7.string(),
3877
+ file: z7.string().optional(),
3878
+ line: z7.number().int().positive().optional()
3879
+ });
3880
+ var EngineVerification_v1 = z7.object({
3881
+ // Identity
3882
+ task_id: z7.string().min(1),
3883
+ timestamp: z7.string().datetime(),
3884
+ // Hash binding (audit trail)
3885
+ snapshot_hash: SHA256HashOrPlaceholder,
3886
+ receipt_hash: SHA256HashOrPlaceholder,
3887
+ // Verification result
3888
+ verified: z7.boolean(),
3889
+ // What engine ran
3890
+ cmd_ran: z7.string(),
3891
+ exit_code: z7.number().int(),
3892
+ stdout_snip: z7.string(),
3893
+ stderr_snip: z7.string(),
3894
+ // Patch verification
3895
+ patch_hash: SHA256HashOrPlaceholder.optional(),
3896
+ patch_applied: z7.boolean(),
3897
+ // Comparison with agent claim
3898
+ agent_claimed: z7.boolean(),
3899
+ trust_gap: z7.boolean(),
3900
+ // Failures detected
3901
+ failures: z7.array(DetectedFailure)
3902
+ });
3903
+
3904
+ // src/gates/execution-receipt.ts
3905
+ var GATE_EXECUTION_RECEIPT_SCHEMA_VERSION = "lexrunner-gate-execution-receipt/v2";
3220
3906
  var MAX_GATE_RECEIPT_OUTPUT_BYTES = 64 * 1024;
3907
+ var FileIdentitySchema = z8.object({
3908
+ path: z8.string(),
3909
+ realPath: z8.string(),
3910
+ bytes: z8.number().int().nonnegative(),
3911
+ mtimeMs: z8.number().nonnegative(),
3912
+ sha256: z8.string().regex(/^sha256:[a-f0-9]{64}$/u)
3913
+ }).strict();
3914
+ var OutputEvidenceSchema = z8.object({
3915
+ bytes: z8.number().int().nonnegative(),
3916
+ sha256: z8.string().regex(/^sha256:[a-f0-9]{64}$/u),
3917
+ truncated: z8.boolean(),
3918
+ content: z8.string().max(MAX_GATE_RECEIPT_OUTPUT_BYTES)
3919
+ }).strict();
3920
+ var ArtifactIdentitySchema = z8.object({
3921
+ declaredPath: z8.string(),
3922
+ resolvedPath: z8.string(),
3923
+ status: z8.enum(["collected", "missing", "stale", "unsupported", "collection_error"]),
3924
+ before: FileIdentitySchema.nullable(),
3925
+ source: FileIdentitySchema.nullable(),
3926
+ retainedPath: z8.string().optional(),
3927
+ retained: FileIdentitySchema.optional(),
3928
+ error: z8.string().optional()
3929
+ }).strict();
3930
+ var LocalGateExecutionReceiptSchema = z8.object({
3931
+ schemaVersion: z8.literal(GATE_EXECUTION_RECEIPT_SCHEMA_VERSION),
3932
+ attempt: z8.number().int().positive(),
3933
+ binding: z8.object({
3934
+ item: z8.string().min(1).nullable(),
3935
+ declaredGateDigest: z8.string().regex(/^sha256:[a-f0-9]{64}$/u),
3936
+ candidateDigest: z8.string().regex(/^sha256:[a-f0-9]{64}$/u).nullable(),
3937
+ timeoutMs: z8.number().int().positive()
3938
+ }).strict(),
3939
+ declaredGate: z8.object({
3940
+ name: z8.string(),
3941
+ run: z8.string(),
3942
+ cwd: z8.string().nullable(),
3943
+ runtime: z8.enum(["local", "container", "ci-service"]),
3944
+ artifacts: z8.array(z8.string())
3945
+ }).strict(),
3946
+ execution: z8.object({
3947
+ cwd: z8.string(),
3948
+ startedAt: z8.string(),
3949
+ finishedAt: z8.string(),
3950
+ durationMs: z8.number().nonnegative(),
3951
+ shell: z8.object({
3952
+ command: z8.enum(["bash", "pwsh"]),
3953
+ executable: FileIdentitySchema.nullable(),
3954
+ argv: z8.array(z8.string()),
3955
+ identityAfter: FileIdentitySchema.nullable(),
3956
+ unchanged: z8.boolean(),
3957
+ spawned: z8.boolean()
3958
+ }).strict()
3959
+ }).strict(),
3960
+ outcome: z8.object({
3961
+ status: z8.enum(["pass", "fail", "blocked", "skipped", "retrying"]),
3962
+ exitCode: z8.number().int().nullable(),
3963
+ failureKind: z8.enum(["nonzero_exit", "spawn_error", "timeout", "evidence_error"]).nullable(),
3964
+ timeoutCleanup: z8.object({
3965
+ method: z8.enum(["process-group", "taskkill", "direct-child"]),
3966
+ forceKilled: z8.boolean(),
3967
+ descendantsReaped: z8.boolean()
3968
+ }).strict().nullable(),
3969
+ evidenceComplete: z8.boolean()
3970
+ }).strict(),
3971
+ output: z8.object({ stdout: OutputEvidenceSchema, stderr: OutputEvidenceSchema }).strict(),
3972
+ artifacts: z8.array(ArtifactIdentitySchema)
3973
+ }).strict();
3974
+ function parseLocalGateExecutionReceipt(value) {
3975
+ return LocalGateExecutionReceiptSchema.parse(value);
3976
+ }
3977
+ function gateExecutionBinding(gate, item, timeoutMs, candidateDigest) {
3978
+ return {
3979
+ item: item ?? null,
3980
+ declaredGateDigest: computeCanonicalHash(Gate.parse(gate)),
3981
+ candidateDigest: candidateDigest ?? null,
3982
+ timeoutMs
3983
+ };
3984
+ }
3221
3985
  function resolveSpawnExecutable(command, environment, workingDirectory, platform2 = process.platform) {
3222
3986
  if (isAbsolute2(command) || /[\\/]/u.test(command)) {
3223
3987
  return requireExecutable(resolve5(workingDirectory, command));
@@ -3365,7 +4129,17 @@ function resolveLocalGateShell(command, platform2 = process.platform) {
3365
4129
  arguments: ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", command]
3366
4130
  } : { command: "bash", arguments: ["-c", command] };
3367
4131
  }
3368
- async function executeGate(gate, policy, artifactDir, timeoutMs = 3e4, itemName, skipValidation = false, repoRoot, turnCostTracker, suppressStdout = false) {
4132
+ function sanitizedGateEnvironment(declared) {
4133
+ const environment = { ...process.env };
4134
+ for (const key of Object.keys(environment)) {
4135
+ if (key.toUpperCase().startsWith("GIT_")) delete environment[key];
4136
+ }
4137
+ return { ...environment, ...declared };
4138
+ }
4139
+ function artifactIdentitySegment(identity) {
4140
+ return `identity-${createHash2("sha256").update(identity, "utf8").digest("hex").slice(0, 32)}`;
4141
+ }
4142
+ async function executeGate(gate, policy, artifactDir, timeoutMs = 3e4, itemName, skipValidation = false, repoRoot, turnCostTracker, suppressStdout = false, candidateDigest) {
3369
4143
  if (!skipValidation && gate.input) {
3370
4144
  try {
3371
4145
  validateGateInput(gate.name, gate.input);
@@ -3397,7 +4171,15 @@ async function executeGate(gate, policy, artifactDir, timeoutMs = 3e4, itemName,
3397
4171
  }
3398
4172
  await new Promise((resolve6) => setTimeout(resolve6, delayMs));
3399
4173
  }
3400
- const result = await executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoot);
4174
+ const result = await executeGateAttempt(
4175
+ gate,
4176
+ artifactDir,
4177
+ attempt,
4178
+ timeoutMs,
4179
+ repoRoot,
4180
+ itemName,
4181
+ candidateDigest
4182
+ );
3401
4183
  lastResult = result;
3402
4184
  totalDuration += result.duration || 0;
3403
4185
  if (turnCostTracker && result.duration) {
@@ -3499,14 +4281,17 @@ async function writeFlakeReport(itemName, gateName, attempts, totalDuration, art
3499
4281
  if (!fs9.existsSync(flakeReportDir)) {
3500
4282
  fs9.mkdirSync(flakeReportDir, { recursive: true });
3501
4283
  }
3502
- const reportPath = path9.join(flakeReportDir, `${itemName}-${gateName}.json`);
4284
+ const reportPath = path9.join(
4285
+ flakeReportDir,
4286
+ `${artifactIdentitySegment(itemName)}-${artifactIdentitySegment(gateName)}.json`
4287
+ );
3503
4288
  const reportContent = canonicalJSONStringify(flakeReport);
3504
4289
  fs9.writeFileSync(reportPath, reportContent, "utf-8");
3505
4290
  if (!suppressStdout) {
3506
4291
  console.log(`\u{1F4CA} Flake report written: ${reportPath}`);
3507
4292
  }
3508
4293
  }
3509
- async function executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoot) {
4294
+ async function executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoot, itemName, candidateDigest) {
3510
4295
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
3511
4296
  const startTime = Date.now();
3512
4297
  switch (gate.runtime) {
@@ -3518,7 +4303,8 @@ async function executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoo
3518
4303
  startedAt,
3519
4304
  startTime,
3520
4305
  timeoutMs,
3521
- repoRoot
4306
+ repoRoot,
4307
+ itemName
3522
4308
  );
3523
4309
  case "ci-service":
3524
4310
  return executeCiServiceGate(gate, artifactDir, attempt, startedAt, startTime);
@@ -3531,14 +4317,16 @@ async function executeGateAttempt(gate, artifactDir, attempt, timeoutMs, repoRoo
3531
4317
  startedAt,
3532
4318
  startTime,
3533
4319
  timeoutMs,
3534
- repoRoot
4320
+ repoRoot,
4321
+ itemName,
4322
+ candidateDigest
3535
4323
  );
3536
4324
  }
3537
4325
  }
3538
- async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot) {
4326
+ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot, itemName, candidateDigest) {
3539
4327
  const workingDirectory = path9.resolve(gate.cwd || repoRoot || process.cwd());
3540
- const gateArtifactDirectory = path9.join(artifactDir, gate.name);
3541
- const environment = { ...process.env, ...gate.env };
4328
+ const gateArtifactDirectory = path9.join(artifactDir, artifactIdentitySegment(gate.name));
4329
+ const environment = sanitizedGateEnvironment(gate.env);
3542
4330
  const shell = resolveLocalGateShell(gate.run);
3543
4331
  const artifactBaselines = captureDeclaredArtifactBaselines(
3544
4332
  gate.artifacts ?? [],
@@ -3582,7 +4370,10 @@ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime
3582
4370
  artifacts: [],
3583
4371
  attempts: attempt,
3584
4372
  lastAttempt: startedAt
3585
- }
4373
+ },
4374
+ itemName,
4375
+ timeoutMs,
4376
+ candidateDigest
3586
4377
  });
3587
4378
  }
3588
4379
  try {
@@ -3616,7 +4407,10 @@ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime
3616
4407
  artifacts: [],
3617
4408
  attempts: attempt,
3618
4409
  lastAttempt: startedAt
3619
- }
4410
+ },
4411
+ itemName,
4412
+ timeoutMs,
4413
+ candidateDigest
3620
4414
  });
3621
4415
  }
3622
4416
  return new Promise((resolve6) => {
@@ -3680,7 +4474,10 @@ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime
3680
4474
  artifacts: [],
3681
4475
  attempts: attempt,
3682
4476
  lastAttempt: startedAt
3683
- }
4477
+ },
4478
+ itemName,
4479
+ timeoutMs,
4480
+ candidateDigest
3684
4481
  })
3685
4482
  );
3686
4483
  });
@@ -3719,7 +4516,10 @@ async function executeLocalGate(gate, artifactDir, attempt, startedAt, startTime
3719
4516
  artifacts: [],
3720
4517
  attempts: attempt,
3721
4518
  lastAttempt: startedAt
3722
- }
4519
+ },
4520
+ itemName,
4521
+ timeoutMs,
4522
+ candidateDigest
3723
4523
  })
3724
4524
  );
3725
4525
  });
@@ -3746,6 +4546,12 @@ function finalizeLocalGateAttempt(input) {
3746
4546
  const receiptPath = writeLocalGateExecutionReceipt(input.gateArtifactDirectory, {
3747
4547
  schemaVersion: GATE_EXECUTION_RECEIPT_SCHEMA_VERSION,
3748
4548
  attempt: input.attempt,
4549
+ binding: gateExecutionBinding(
4550
+ input.gate,
4551
+ input.itemName,
4552
+ input.timeoutMs,
4553
+ input.candidateDigest
4554
+ ),
3749
4555
  declaredGate: {
3750
4556
  name: input.gate.name,
3751
4557
  run: input.gate.run,
@@ -3783,11 +4589,21 @@ function finalizeLocalGateAttempt(input) {
3783
4589
  result.artifacts = [...collected.paths, receiptPath];
3784
4590
  return result;
3785
4591
  }
3786
- async function executeContainerGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot) {
3787
- console.warn(
3788
- `\u26A0\uFE0F Container runtime for gate '${gate.name}' not yet implemented, falling back to local execution`
3789
- );
3790
- return executeLocalGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot);
4592
+ async function executeContainerGate(gate, artifactDir, attempt, startedAt, startTime, timeoutMs, repoRoot, itemName) {
4593
+ console.warn(`\u26A0\uFE0F Container runtime for gate '${gate.name}' is not implemented; failing closed`);
4594
+ return {
4595
+ gate: gate.name,
4596
+ status: "fail",
4597
+ exitCode: 1,
4598
+ duration: Date.now() - startTime,
4599
+ stdout: "",
4600
+ stderr: "GATE_RUNTIME_UNAVAILABLE: container execution is not implemented",
4601
+ failureKind: "evidence_error",
4602
+ artifacts: [],
4603
+ attempts: attempt,
4604
+ lastAttempt: startedAt,
4605
+ timeoutMs
4606
+ };
3791
4607
  }
3792
4608
  async function executeCiServiceGate(gate, artifactDir, attempt, startedAt, startTime) {
3793
4609
  console.warn(
@@ -3952,7 +4768,7 @@ async function executeItemGates(item, policy, executionState, artifactDir, timeo
3952
4768
  return [];
3953
4769
  }
3954
4770
  const results = [];
3955
- const itemArtifactDir = path9.join(artifactDir, item.name);
4771
+ const itemArtifactDir = path9.join(artifactDir, artifactIdentitySegment(item.name));
3956
4772
  if (!fs9.existsSync(itemArtifactDir)) {
3957
4773
  fs9.mkdirSync(itemArtifactDir, { recursive: true });
3958
4774
  }
@@ -4003,13 +4819,15 @@ async function executeItemGates(item, policy, executionState, artifactDir, timeo
4003
4819
  gate,
4004
4820
  policy,
4005
4821
  itemArtifactDir,
4006
- timeoutMs,
4822
+ gate.timeoutMs ?? timeoutMs,
4007
4823
  item.name,
4008
4824
  skipValidation,
4009
4825
  repoRoot,
4010
4826
  options?.turnCostTracker,
4011
- options?.suppressStdout
4827
+ options?.suppressStdout,
4828
+ options?.candidateDigest
4012
4829
  );
4830
+ result.timeoutMs = gate.timeoutMs ?? timeoutMs;
4013
4831
  results.push(result);
4014
4832
  executionState.updateGateResult(item.name, result);
4015
4833
  if (result.status === "fail" && options?.runId) {
@@ -5885,6 +6703,14 @@ var AutopilotLevel4 = class extends AutopilotLevel3 {
5885
6703
  };
5886
6704
 
5887
6705
  export {
6706
+ parseTierOverrides,
6707
+ Policy,
6708
+ Plan,
6709
+ SchemaValidationError,
6710
+ formatPlanValidationFailure,
6711
+ asPlanValidationFailure,
6712
+ formatPlanValidationFailureText,
6713
+ loadPlan,
5888
6714
  getRunsDir,
5889
6715
  getRunDir,
5890
6716
  writeRunState,
@@ -5901,6 +6727,14 @@ export {
5901
6727
  listCounterExamples,
5902
6728
  loadCounterExample,
5903
6729
  exportCounterExamples,
6730
+ computeCanonicalHash,
6731
+ computeCanonicalHashFromCompactJSON,
6732
+ RepoRelativePath,
6733
+ SHA256Hash,
6734
+ GATE_EXECUTION_RECEIPT_SCHEMA_VERSION,
6735
+ parseLocalGateExecutionReceipt,
6736
+ resolveSpawnExecutable,
6737
+ fileIdentity,
5904
6738
  executeGate,
5905
6739
  executeGatesWithPolicy,
5906
6740
  getEnvWithAlias,