@remnic/bench 9.6.19 → 9.6.21

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.
package/dist/index.js CHANGED
@@ -5497,17 +5497,473 @@ var BENCHMARK_RESULT_SCHEMA = {
5497
5497
 
5498
5498
  // src/repro-manifest.ts
5499
5499
  import { execFileSync } from "child_process";
5500
- import { createHash as createHash3 } from "crypto";
5500
+ import { createHash as createHash4 } from "crypto";
5501
5501
  import { createReadStream } from "fs";
5502
- import { lstat as lstat3, mkdir as mkdir3, readFile as readFile4, readdir as readdir4, readlink, realpath as realpath3, stat as stat2, writeFile as writeFile3 } from "fs/promises";
5503
- import os2 from "os";
5504
- import path4 from "path";
5502
+ import { lstat as lstat3, mkdir as mkdir4, readFile as readFile5, readdir as readdir4, readlink, realpath as realpath3, stat as stat2, writeFile as writeFile4 } from "fs/promises";
5503
+ import os3 from "os";
5504
+ import path5 from "path";
5505
5505
 
5506
- // src/results-store.ts
5507
- import { mkdir as mkdir2, readdir as readdir3, readFile as readFile3, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
5508
- import fs from "fs";
5506
+ // src/providers/codex-credit-budget.ts
5507
+ import { createHash as createHash3 } from "crypto";
5508
+ import { mkdir as mkdir2, open, readFile as readFile3, rename as rename2, rmdir, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
5509
5509
  import os from "os";
5510
5510
  import path3 from "path";
5511
+ var ONE_MILLION = 1e6;
5512
+ var MAX_BOUNDED_CALL_CREDITS = 300;
5513
+ var SOL_MODEL = /^gpt-5\.6-sol$/i;
5514
+ var CREDIT_RATES = [
5515
+ [/^gpt-5\.6-sol$/i, { input: 125, cachedInput: 12.5, output: 750 }],
5516
+ [/^gpt-5\.6-terra$/i, { input: 62.5, cachedInput: 6.25, output: 375 }],
5517
+ [/^gpt-5\.6-luna$/i, { input: 25, cachedInput: 2.5, output: 150 }],
5518
+ [/^gpt-5\.5$/i, { input: 125, cachedInput: 12.5, output: 750 }],
5519
+ [/^gpt-5\.4-mini$/i, { input: 18.75, cachedInput: 1.875, output: 113 }],
5520
+ [/^gpt-5\.4$/i, { input: 62.5, cachedInput: 6.25, output: 375 }],
5521
+ [/^gpt-5\.3-codex$/i, { input: 43.75, cachedInput: 4.375, output: 350 }],
5522
+ [/^gpt-5\.2$/i, { input: 43.75, cachedInput: 4.375, output: 350 }]
5523
+ ];
5524
+ var completionQueue = Promise.resolve();
5525
+ var CodexCreditAccountingError = class extends Error {
5526
+ constructor(message) {
5527
+ super(message);
5528
+ this.name = "CodexCreditAccountingError";
5529
+ }
5530
+ };
5531
+ var CodexCreditDispatchError = class extends Error {
5532
+ constructor(message, options) {
5533
+ super(message, options);
5534
+ this.name = "CodexCreditDispatchError";
5535
+ }
5536
+ };
5537
+ function resolveCodexCreditBudgetConfig(env = process.env, fallbackRunId) {
5538
+ const rawBudget = env.REMNIC_BENCH_CODEX_CREDIT_BUDGET?.trim();
5539
+ if (!rawBudget) return void 0;
5540
+ const budgetCredits = parsePositiveNumber(
5541
+ rawBudget,
5542
+ "REMNIC_BENCH_CODEX_CREDIT_BUDGET"
5543
+ );
5544
+ const reserveCredits = parseNonNegativeNumber(
5545
+ env.REMNIC_BENCH_CODEX_CREDIT_RESERVE?.trim() ?? "473",
5546
+ "REMNIC_BENCH_CODEX_CREDIT_RESERVE"
5547
+ );
5548
+ if (reserveCredits >= budgetCredits) {
5549
+ throw new Error(
5550
+ "REMNIC_BENCH_CODEX_CREDIT_RESERVE must be smaller than REMNIC_BENCH_CODEX_CREDIT_BUDGET"
5551
+ );
5552
+ }
5553
+ if (reserveCredits < MAX_BOUNDED_CALL_CREDITS) {
5554
+ throw new Error(
5555
+ `REMNIC_BENCH_CODEX_CREDIT_RESERVE must be at least ${MAX_BOUNDED_CALL_CREDITS} credits to cover the conservative maximum cost of the one serialized in-flight call`
5556
+ );
5557
+ }
5558
+ const ledgerPath = path3.resolve(
5559
+ expandHomeRelativePath(
5560
+ env.REMNIC_BENCH_CODEX_CREDIT_LEDGER?.trim() || ".remnic/bench/codex-credit-ledger.json"
5561
+ )
5562
+ );
5563
+ const runId = parseOptionalRunId(env.REMNIC_BENCH_RUN_ID) ?? parseOptionalRunId(fallbackRunId);
5564
+ return {
5565
+ budgetCredits,
5566
+ reserveCredits,
5567
+ ledgerPath,
5568
+ allowSol: /^(?:1|true|yes|on)$/i.test(
5569
+ env.REMNIC_BENCH_CODEX_ALLOW_SOL?.trim() ?? ""
5570
+ ),
5571
+ ...runId ? { runId } : {}
5572
+ };
5573
+ }
5574
+ async function runWithinCodexCreditBudget(args) {
5575
+ if (!args.config) {
5576
+ return (await args.run()).value;
5577
+ }
5578
+ const previous = completionQueue;
5579
+ let release;
5580
+ completionQueue = new Promise((resolve) => {
5581
+ release = resolve;
5582
+ });
5583
+ await previous;
5584
+ const lockPath = `${args.config.ledgerPath}.lock`;
5585
+ let lock;
5586
+ let dispatchStarted = false;
5587
+ let accountingSettled = false;
5588
+ try {
5589
+ await mkdir2(path3.dirname(lockPath), { recursive: true, mode: 448 });
5590
+ lock = await acquireLedgerLock(lockPath);
5591
+ assertModelAllowed(args.model, args.config);
5592
+ const ledger = await readLedger(args.config);
5593
+ if (ledger.blockedReason) {
5594
+ throw new Error(
5595
+ `Codex credit ledger is blocked pending manual reconciliation: ${ledger.blockedReason}`
5596
+ );
5597
+ }
5598
+ const usableCredits = args.config.budgetCredits - args.config.reserveCredits;
5599
+ const dispatchHeadroom = usableCredits - ledger.spentCredits;
5600
+ if (dispatchHeadroom < MAX_BOUNDED_CALL_CREDITS) {
5601
+ throw new Error(
5602
+ `Codex credit budget cannot safely dispatch another call: ${ledger.spentCredits.toFixed(3)} spent; ${dispatchHeadroom.toFixed(3)} remains below the ${usableCredits.toFixed(3)} planned-spend ceiling, but ${MAX_BOUNDED_CALL_CREDITS.toFixed(3)} credits of worst-case call headroom are required.`
5603
+ );
5604
+ }
5605
+ await writeLockState(lock, "in-flight");
5606
+ dispatchStarted = true;
5607
+ let result;
5608
+ try {
5609
+ result = await args.run();
5610
+ } catch (error) {
5611
+ if (error instanceof CodexCreditDispatchError) {
5612
+ await writeLockState(lock, "settled");
5613
+ accountingSettled = true;
5614
+ } else {
5615
+ const blockedLedger = {
5616
+ ...ledger,
5617
+ blockedReason: error instanceof CodexCreditAccountingError ? error.message : `Codex dispatch outcome is unknown after an unexpected error: ${safeErrorMessage(error)}`
5618
+ };
5619
+ await writeLedger(args.config.ledgerPath, blockedLedger);
5620
+ await writeLockState(lock, "settled");
5621
+ accountingSettled = true;
5622
+ }
5623
+ throw error;
5624
+ }
5625
+ const credits = calculateCodexCredits(args.model, result.usage);
5626
+ const nextSpent = ledger.spentCredits + credits;
5627
+ const nextLedger = {
5628
+ ...ledger,
5629
+ spentCredits: nextSpent,
5630
+ entries: [
5631
+ ...ledger.entries,
5632
+ {
5633
+ at: (/* @__PURE__ */ new Date()).toISOString(),
5634
+ model: args.model,
5635
+ credits,
5636
+ ...args.config.runId ? { runId: args.config.runId } : {},
5637
+ ...result.usage
5638
+ }
5639
+ ]
5640
+ };
5641
+ await writeLedger(args.config.ledgerPath, nextLedger);
5642
+ await writeLockState(lock, "settled");
5643
+ accountingSettled = true;
5644
+ args.onUsagePersisted?.(result.usage);
5645
+ if (nextSpent > usableCredits) {
5646
+ throw new Error(
5647
+ `Codex planned-spend ceiling exceeded by completed call: ${nextSpent.toFixed(3)} > ${usableCredits.toFixed(3)} credits. Usage was persisted; stop the benchmark immediately.`
5648
+ );
5649
+ }
5650
+ return result.value;
5651
+ } finally {
5652
+ try {
5653
+ if (lock) {
5654
+ try {
5655
+ await lock.close();
5656
+ } finally {
5657
+ if (!dispatchStarted || accountingSettled) {
5658
+ await removeOwnedLedgerLock(lockPath);
5659
+ }
5660
+ }
5661
+ }
5662
+ } finally {
5663
+ release();
5664
+ }
5665
+ }
5666
+ }
5667
+ async function acquireLedgerLock(lockPath) {
5668
+ for (let attempt = 0; attempt < 2; attempt += 1) {
5669
+ try {
5670
+ await mkdir2(lockPath, { mode: 448 });
5671
+ } catch (error) {
5672
+ if (error.code !== "EEXIST") throw error;
5673
+ const owner = await readLockOwner(lockPath);
5674
+ if (!owner || isProcessAlive(owner.pid) || owner.phase === "in-flight") {
5675
+ throw new Error(
5676
+ `Codex credit ledger is locked${owner?.phase === "in-flight" ? " with unreconciled in-flight usage" : " by another benchmark process"} (${lockPath}); refusing credit spend.`
5677
+ );
5678
+ }
5679
+ await reclaimStaleLedgerLock(lockPath, owner);
5680
+ continue;
5681
+ }
5682
+ let createdLock;
5683
+ try {
5684
+ await mkdir2(lockHeldPath(lockPath));
5685
+ createdLock = await open(lockOwnerPath(lockPath), "wx", 384);
5686
+ await writeLockState(createdLock, "preflight");
5687
+ return createdLock;
5688
+ } catch (error) {
5689
+ await createdLock?.close().catch(() => void 0);
5690
+ await unlink2(lockOwnerPath(lockPath)).catch(() => void 0);
5691
+ await rmdir(lockHeldPath(lockPath)).catch(() => void 0);
5692
+ await rmdir(lockPath).catch(() => void 0);
5693
+ throw error;
5694
+ }
5695
+ }
5696
+ throw new Error(`Unable to acquire Codex credit ledger lock (${lockPath})`);
5697
+ }
5698
+ async function readLockOwner(lockPath) {
5699
+ try {
5700
+ const parsed = JSON.parse(await readFile3(lockOwnerPath(lockPath), "utf8"));
5701
+ if (!Number.isSafeInteger(parsed.pid) || parsed.pid <= 0 || parsed.phase !== "preflight" && parsed.phase !== "in-flight" && parsed.phase !== "settled") {
5702
+ return void 0;
5703
+ }
5704
+ return { pid: parsed.pid, phase: parsed.phase };
5705
+ } catch {
5706
+ return void 0;
5707
+ }
5708
+ }
5709
+ async function reclaimStaleLedgerLock(lockPath, expectedOwner) {
5710
+ try {
5711
+ await rmdir(lockHeldPath(lockPath));
5712
+ } catch (error) {
5713
+ throw new Error(
5714
+ `Codex credit ledger stale-lock reclamation is already claimed or incomplete (${lockPath}); refusing credit spend: ${safeErrorMessage(error)}`
5715
+ );
5716
+ }
5717
+ const currentOwner = await readLockOwner(lockPath);
5718
+ if (!currentOwner || currentOwner.pid !== expectedOwner.pid || currentOwner.phase !== expectedOwner.phase || isProcessAlive(currentOwner.pid) || currentOwner.phase === "in-flight") {
5719
+ throw new Error(
5720
+ `Codex credit ledger owner changed during stale-lock reclamation (${lockPath}); refusing credit spend.`
5721
+ );
5722
+ }
5723
+ await unlink2(lockOwnerPath(lockPath));
5724
+ await rmdir(lockPath);
5725
+ }
5726
+ async function removeOwnedLedgerLock(lockPath) {
5727
+ await rmdir(lockHeldPath(lockPath));
5728
+ await unlink2(lockOwnerPath(lockPath));
5729
+ await rmdir(lockPath);
5730
+ }
5731
+ function lockOwnerPath(lockPath) {
5732
+ return path3.join(lockPath, "owner.json");
5733
+ }
5734
+ function lockHeldPath(lockPath) {
5735
+ return path3.join(lockPath, "held");
5736
+ }
5737
+ async function writeLockState(lock, phase) {
5738
+ const contents = `${JSON.stringify({
5739
+ pid: process.pid,
5740
+ phase,
5741
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
5742
+ })}
5743
+ `;
5744
+ await lock.truncate(0);
5745
+ await lock.write(contents, 0, "utf8");
5746
+ await lock.sync();
5747
+ }
5748
+ function isProcessAlive(pid) {
5749
+ try {
5750
+ process.kill(pid, 0);
5751
+ return true;
5752
+ } catch (error) {
5753
+ return error.code === "EPERM";
5754
+ }
5755
+ }
5756
+ function parseCodexJsonlUsage(output) {
5757
+ let usage;
5758
+ for (const line of output.split(/\r?\n/)) {
5759
+ const trimmed = line.trim();
5760
+ if (!trimmed.startsWith("{")) continue;
5761
+ try {
5762
+ const event = JSON.parse(trimmed);
5763
+ if (event.type !== "turn.completed" || !event.usage) continue;
5764
+ const inputTokens = readCounter(event.usage.input_tokens);
5765
+ const outputTokens = readCounter(event.usage.output_tokens);
5766
+ const cachedInputTokens = readOptionalCounter(
5767
+ event.usage.cached_input_tokens
5768
+ );
5769
+ const reasoningOutputTokens = readOptionalCounter(
5770
+ event.usage.reasoning_output_tokens
5771
+ );
5772
+ if (inputTokens !== void 0 && outputTokens !== void 0 && cachedInputTokens !== void 0 && reasoningOutputTokens !== void 0) {
5773
+ usage = {
5774
+ inputTokens,
5775
+ cachedInputTokens,
5776
+ outputTokens,
5777
+ reasoningOutputTokens
5778
+ };
5779
+ }
5780
+ } catch {
5781
+ }
5782
+ }
5783
+ return usage;
5784
+ }
5785
+ function calculateCodexCredits(model, usage) {
5786
+ const rate = resolveRate(model);
5787
+ const cached = Math.min(usage.inputTokens, usage.cachedInputTokens);
5788
+ const uncached = usage.inputTokens - cached;
5789
+ return (uncached * rate.input + cached * rate.cachedInput + usage.outputTokens * rate.output) / ONE_MILLION;
5790
+ }
5791
+ async function buildCodexCreditReceipt(ledgerPath, runId) {
5792
+ const resolvedPath = path3.resolve(expandHomeRelativePath(ledgerPath));
5793
+ const contents = await readFile3(resolvedPath);
5794
+ const ledger = parseLedger(JSON.parse(contents.toString("utf8")));
5795
+ const normalizedRunId = parseOptionalRunId(runId);
5796
+ const cumulative = summarizeLedgerEntries(ledger.entries);
5797
+ const runEntries = normalizedRunId ? ledger.entries.filter((entry) => entry.runId === normalizedRunId) : [];
5798
+ return {
5799
+ schemaVersion: 1,
5800
+ ledgerSha256: createHash3("sha256").update(contents).digest("hex"),
5801
+ budgetCredits: ledger.budgetCredits,
5802
+ reserveCredits: ledger.reserveCredits,
5803
+ plannedSpendCeilingCredits: ledger.budgetCredits - ledger.reserveCredits,
5804
+ totalSpentCredits: ledger.spentCredits,
5805
+ totalRemainingCredits: ledger.budgetCredits - ledger.spentCredits,
5806
+ blocked: ledger.blockedReason !== void 0,
5807
+ cumulative,
5808
+ ...normalizedRunId ? { run: { id: normalizedRunId, ...summarizeLedgerEntries(runEntries) } } : {}
5809
+ };
5810
+ }
5811
+ function resolveRate(model) {
5812
+ const match = CREDIT_RATES.find(([pattern]) => pattern.test(model));
5813
+ if (!match) {
5814
+ throw new Error(
5815
+ `No Codex credit rate is configured for model ${JSON.stringify(model)}; refusing to run under a bounded credit budget.`
5816
+ );
5817
+ }
5818
+ return match[1];
5819
+ }
5820
+ function assertModelAllowed(model, config) {
5821
+ resolveRate(model);
5822
+ if (SOL_MODEL.test(model) && !config.allowSol) {
5823
+ throw new Error(
5824
+ "gpt-5.6-sol is disabled for bounded benchmark runs because it is the most expensive GPT-5.6 tier. Use gpt-5.6-terra or gpt-5.6-luna, or explicitly set REMNIC_BENCH_CODEX_ALLOW_SOL=1."
5825
+ );
5826
+ }
5827
+ }
5828
+ async function readLedger(config) {
5829
+ try {
5830
+ const parsed = parseLedger(
5831
+ JSON.parse(await readFile3(config.ledgerPath, "utf8"))
5832
+ );
5833
+ if (parsed.budgetCredits !== config.budgetCredits || parsed.reserveCredits !== config.reserveCredits) {
5834
+ throw new Error("ledger schema or budget does not match this run");
5835
+ }
5836
+ return parsed;
5837
+ } catch (error) {
5838
+ if (error.code !== "ENOENT") {
5839
+ throw new Error(`Invalid Codex credit ledger at ${config.ledgerPath}: ${String(error)}`);
5840
+ }
5841
+ return {
5842
+ schemaVersion: 1,
5843
+ budgetCredits: config.budgetCredits,
5844
+ reserveCredits: config.reserveCredits,
5845
+ spentCredits: 0,
5846
+ entries: []
5847
+ };
5848
+ }
5849
+ }
5850
+ function parseLedger(parsed) {
5851
+ const entryCredits = Array.isArray(parsed.entries) ? parsed.entries.reduce(
5852
+ (sum, entry) => sum + (typeof entry?.credits === "number" ? entry.credits ?? 0 : 0),
5853
+ 0
5854
+ ) : Number.NaN;
5855
+ if (parsed.schemaVersion !== 1 || typeof parsed.budgetCredits !== "number" || !Number.isFinite(parsed.budgetCredits) || parsed.budgetCredits <= 0 || typeof parsed.reserveCredits !== "number" || !Number.isFinite(parsed.reserveCredits) || parsed.reserveCredits < 0 || parsed.reserveCredits >= parsed.budgetCredits || typeof parsed.spentCredits !== "number" || !Number.isFinite(parsed.spentCredits) || parsed.spentCredits < 0 || !Array.isArray(parsed.entries) || !parsed.entries.every(isLedgerEntry) || Math.abs(entryCredits - parsed.spentCredits) > 1e-9 || parsed.blockedReason !== void 0 && typeof parsed.blockedReason !== "string") {
5856
+ throw new Error("ledger schema is invalid");
5857
+ }
5858
+ return parsed;
5859
+ }
5860
+ function isLedgerEntry(entry) {
5861
+ if (!entry || typeof entry !== "object") return false;
5862
+ const candidate = entry;
5863
+ return typeof candidate.at === "string" && typeof candidate.model === "string" && candidate.model.length > 0 && typeof candidate.credits === "number" && Number.isFinite(candidate.credits) && candidate.credits >= 0 && (candidate.runId === void 0 || isValidStoredRunId(candidate.runId)) && readCounter(candidate.inputTokens) !== void 0 && readCounter(candidate.cachedInputTokens) !== void 0 && readCounter(candidate.outputTokens) !== void 0 && readCounter(candidate.reasoningOutputTokens) !== void 0 && (candidate.cachedInputTokens ?? 0) <= (candidate.inputTokens ?? 0) && isEntryCreditConsistent(candidate);
5864
+ }
5865
+ function isEntryCreditConsistent(entry) {
5866
+ try {
5867
+ return Math.abs(calculateCodexCredits(entry.model, entry) - entry.credits) <= 1e-9;
5868
+ } catch {
5869
+ return false;
5870
+ }
5871
+ }
5872
+ function summarizeLedgerEntries(entries) {
5873
+ const byModel = /* @__PURE__ */ new Map();
5874
+ for (const entry of entries) {
5875
+ const modelEntries = byModel.get(entry.model) ?? [];
5876
+ modelEntries.push(entry);
5877
+ byModel.set(entry.model, modelEntries);
5878
+ }
5879
+ const totals = summarizeUsage(entries);
5880
+ return {
5881
+ calls: entries.length,
5882
+ credits: entries.reduce((sum, entry) => sum + entry.credits, 0),
5883
+ ...totals,
5884
+ models: [...byModel.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([model, modelEntries]) => ({
5885
+ model,
5886
+ calls: modelEntries.length,
5887
+ credits: modelEntries.reduce((sum, entry) => sum + entry.credits, 0),
5888
+ ...summarizeUsage(modelEntries)
5889
+ }))
5890
+ };
5891
+ }
5892
+ function summarizeUsage(entries) {
5893
+ return entries.reduce(
5894
+ (totals, entry) => ({
5895
+ inputTokens: totals.inputTokens + entry.inputTokens,
5896
+ cachedInputTokens: totals.cachedInputTokens + entry.cachedInputTokens,
5897
+ outputTokens: totals.outputTokens + entry.outputTokens,
5898
+ reasoningOutputTokens: totals.reasoningOutputTokens + entry.reasoningOutputTokens
5899
+ }),
5900
+ { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningOutputTokens: 0 }
5901
+ );
5902
+ }
5903
+ async function writeLedger(filePath, ledger) {
5904
+ await mkdir2(path3.dirname(filePath), { recursive: true, mode: 448 });
5905
+ const tempPath = `${filePath}.${process.pid}.tmp`;
5906
+ await writeFile2(tempPath, `${JSON.stringify(ledger, null, 2)}
5907
+ `, {
5908
+ encoding: "utf8",
5909
+ mode: 384
5910
+ });
5911
+ await rename2(tempPath, filePath);
5912
+ }
5913
+ function readCounter(value) {
5914
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
5915
+ }
5916
+ function readOptionalCounter(value) {
5917
+ return value === void 0 ? 0 : readCounter(value);
5918
+ }
5919
+ function safeErrorMessage(error) {
5920
+ return error instanceof Error ? error.message : String(error);
5921
+ }
5922
+ function expandHomeRelativePath(value) {
5923
+ if (value === "~") return os.homedir();
5924
+ if (value.startsWith("~/") || value.startsWith("~\\")) {
5925
+ return path3.join(os.homedir(), value.slice(2));
5926
+ }
5927
+ return value;
5928
+ }
5929
+ function parsePositiveNumber(value, name) {
5930
+ const parsed = Number(value);
5931
+ if (!Number.isFinite(parsed) || parsed <= 0) {
5932
+ throw new Error(`${name} must be a finite number greater than zero`);
5933
+ }
5934
+ return parsed;
5935
+ }
5936
+ function parseNonNegativeNumber(value, name) {
5937
+ const parsed = Number(value);
5938
+ if (!Number.isFinite(parsed) || parsed < 0) {
5939
+ throw new Error(`${name} must be a finite non-negative number`);
5940
+ }
5941
+ return parsed;
5942
+ }
5943
+ function parseOptionalRunId(value) {
5944
+ const runId = value?.trim();
5945
+ if (!runId) return void 0;
5946
+ if (runId.length > 128 || hasControlCharacters(runId)) {
5947
+ throw new Error("REMNIC_BENCH_RUN_ID must be at most 128 characters without control characters");
5948
+ }
5949
+ return runId;
5950
+ }
5951
+ function isValidStoredRunId(value) {
5952
+ return typeof value === "string" && value.length > 0 && value.length <= 128 && value === value.trim() && !hasControlCharacters(value);
5953
+ }
5954
+ function hasControlCharacters(value) {
5955
+ for (const character of value) {
5956
+ const codePoint = character.codePointAt(0) ?? 0;
5957
+ if (codePoint <= 31 || codePoint === 127) return true;
5958
+ }
5959
+ return false;
5960
+ }
5961
+
5962
+ // src/results-store.ts
5963
+ import { mkdir as mkdir3, readdir as readdir3, readFile as readFile4, unlink as unlink3, writeFile as writeFile3 } from "fs/promises";
5964
+ import fs from "fs";
5965
+ import os2 from "os";
5966
+ import path4 from "path";
5511
5967
 
5512
5968
  // src/integrity/contamination.ts
5513
5969
  var EMPTY_CONTAMINATION_MANIFEST = {
@@ -5972,14 +6428,14 @@ ${renderProvenance(result, provenance)}
5972
6428
  var BASELINE_NAME_PATTERN = /^[A-Za-z0-9_-]+$/;
5973
6429
  var REPRO_MANIFEST_FILENAME = "MANIFEST.json";
5974
6430
  function defaultBenchmarkBaselineDir() {
5975
- const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? os.homedir();
5976
- return path3.join(homeDir, ".remnic", "bench", "baselines");
6431
+ const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? os2.homedir();
6432
+ return path4.join(homeDir, ".remnic", "bench", "baselines");
5977
6433
  }
5978
6434
  function defaultBenchmarkPublishPath(target) {
5979
- const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? os.homedir();
6435
+ const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? os2.homedir();
5980
6436
  switch (target) {
5981
6437
  case "remnic-ai":
5982
- return path3.join(homeDir, ".remnic", "published", "benchmarks.json");
6438
+ return path4.join(homeDir, ".remnic", "published", "benchmarks.json");
5983
6439
  }
5984
6440
  }
5985
6441
  function compareResultSummaries(left, right) {
@@ -6004,10 +6460,10 @@ function isFiniteNumber(value) {
6004
6460
  return typeof value === "number" && Number.isFinite(value);
6005
6461
  }
6006
6462
  async function loadBenchmarkReportCardProvenance(outputDir, resultId) {
6007
- const manifestPath = path3.join(outputDir, REPRO_MANIFEST_FILENAME);
6463
+ const manifestPath = path4.join(outputDir, REPRO_MANIFEST_FILENAME);
6008
6464
  let parsed;
6009
6465
  try {
6010
- parsed = JSON.parse(await readFile3(manifestPath, "utf8"));
6466
+ parsed = JSON.parse(await readFile4(manifestPath, "utf8"));
6011
6467
  } catch {
6012
6468
  return {};
6013
6469
  }
@@ -6114,7 +6570,7 @@ function toBaselineSummary(baseline, filePath) {
6114
6570
  };
6115
6571
  }
6116
6572
  async function loadBenchmarkResult(filePath) {
6117
- const content = await readFile3(filePath, "utf8");
6573
+ const content = await readFile4(filePath, "utf8");
6118
6574
  const parsed = JSON.parse(content);
6119
6575
  if (!isBenchmarkResult(parsed)) {
6120
6576
  throw new Error(`Invalid benchmark result file: ${filePath}`);
@@ -6131,7 +6587,7 @@ async function listBenchmarkResults(outputDir) {
6131
6587
  if (!entry.isFile() || !entry.name.endsWith(".json")) {
6132
6588
  continue;
6133
6589
  }
6134
- const filePath = path3.join(outputDir, entry.name);
6590
+ const filePath = path4.join(outputDir, entry.name);
6135
6591
  try {
6136
6592
  const result = await loadBenchmarkResult(filePath);
6137
6593
  results.push(toSummary(result, filePath));
@@ -6144,20 +6600,20 @@ async function listBenchmarkResults(outputDir) {
6144
6600
  async function saveBenchmarkBaseline(baselineDir, name, result, source) {
6145
6601
  assertValidBaselineName(name);
6146
6602
  assertUsableBaselineDir(baselineDir);
6147
- await mkdir2(baselineDir, { recursive: true });
6148
- const filePath = path3.join(baselineDir, `${name}.json`);
6603
+ await mkdir3(baselineDir, { recursive: true });
6604
+ const filePath = path4.join(baselineDir, `${name}.json`);
6149
6605
  const payload = {
6150
6606
  name,
6151
6607
  savedAt: (/* @__PURE__ */ new Date()).toISOString(),
6152
6608
  result,
6153
6609
  source
6154
6610
  };
6155
- await writeFile2(filePath, `${JSON.stringify(payload, null, 2)}
6611
+ await writeFile3(filePath, `${JSON.stringify(payload, null, 2)}
6156
6612
  `);
6157
6613
  return filePath;
6158
6614
  }
6159
6615
  async function loadBenchmarkBaseline(filePath) {
6160
- const content = await readFile3(filePath, "utf8");
6616
+ const content = await readFile4(filePath, "utf8");
6161
6617
  const parsed = JSON.parse(content);
6162
6618
  if (!isStoredBenchmarkBaseline(parsed)) {
6163
6619
  throw new Error(`Invalid benchmark baseline file: ${filePath}`);
@@ -6175,7 +6631,7 @@ async function listBenchmarkBaselines(baselineDir) {
6175
6631
  if (!entry.isFile() || !entry.name.endsWith(".json")) {
6176
6632
  continue;
6177
6633
  }
6178
- const filePath = path3.join(baselineDir, entry.name);
6634
+ const filePath = path4.join(baselineDir, entry.name);
6179
6635
  try {
6180
6636
  const baseline = await loadBenchmarkBaseline(filePath);
6181
6637
  baselines.push(toBaselineSummary(baseline, filePath));
@@ -6192,7 +6648,7 @@ async function resolveBenchmarkResultReference(outputDir, reference) {
6192
6648
  return exactIdMatch;
6193
6649
  }
6194
6650
  const basenameMatch = summaries.find(
6195
- (summary) => path3.basename(summary.path) === reference
6651
+ (summary) => path4.basename(summary.path) === reference
6196
6652
  );
6197
6653
  if (basenameMatch) {
6198
6654
  return basenameMatch;
@@ -6208,7 +6664,7 @@ async function resolveBenchmarkResultReference(outputDir, reference) {
6208
6664
  return void 0;
6209
6665
  }
6210
6666
  function looksLikeFilesystemPath(reference) {
6211
- return path3.isAbsolute(reference) || reference.includes("/") || reference.includes(path3.sep) || reference.endsWith(".json");
6667
+ return path4.isAbsolute(reference) || reference.includes("/") || reference.includes(path4.sep) || reference.endsWith(".json");
6212
6668
  }
6213
6669
  async function deleteBenchmarkResults(outputDir, references) {
6214
6670
  const summaries = await listBenchmarkResults(outputDir);
@@ -6216,9 +6672,9 @@ async function deleteBenchmarkResults(outputDir, references) {
6216
6672
  const missing = [];
6217
6673
  const seenPaths = /* @__PURE__ */ new Set();
6218
6674
  for (const reference of references) {
6219
- let summary = summaries.find((entry) => entry.id === reference) ?? summaries.find((entry) => path3.basename(entry.path) === reference);
6675
+ let summary = summaries.find((entry) => entry.id === reference) ?? summaries.find((entry) => path4.basename(entry.path) === reference);
6220
6676
  if (!summary && looksLikeFilesystemPath(reference)) {
6221
- const canonicalRef = path3.resolve(reference);
6677
+ const canonicalRef = path4.resolve(reference);
6222
6678
  if (seenPaths.has(canonicalRef)) {
6223
6679
  continue;
6224
6680
  }
@@ -6235,13 +6691,13 @@ async function deleteBenchmarkResults(outputDir, references) {
6235
6691
  missing.push(reference);
6236
6692
  continue;
6237
6693
  }
6238
- const canonicalPath = path3.resolve(summary.path);
6694
+ const canonicalPath = path4.resolve(summary.path);
6239
6695
  if (seenPaths.has(canonicalPath)) {
6240
6696
  continue;
6241
6697
  }
6242
6698
  seenPaths.add(canonicalPath);
6243
6699
  try {
6244
- await unlink2(summary.path);
6700
+ await unlink3(summary.path);
6245
6701
  } catch (error) {
6246
6702
  if (error.code === "ENOENT") {
6247
6703
  } else {
@@ -6366,8 +6822,8 @@ async function buildBenchmarkPublishFeed(outputDir, target, options = {}) {
6366
6822
  };
6367
6823
  }
6368
6824
  async function writeBenchmarkPublishFeed(feed, outputPath) {
6369
- await mkdir2(path3.dirname(outputPath), { recursive: true });
6370
- await writeFile2(outputPath, `${JSON.stringify(feed, null, 2)}
6825
+ await mkdir3(path4.dirname(outputPath), { recursive: true });
6826
+ await writeFile3(outputPath, `${JSON.stringify(feed, null, 2)}
6371
6827
  `);
6372
6828
  return outputPath;
6373
6829
  }
@@ -6422,8 +6878,8 @@ function renderBenchmarkResultExport(result, format, options = {}) {
6422
6878
  // src/run-identity.ts
6423
6879
  var BENCHMARK_RUN_ID_ENV = "REMNIC_BENCH_RUN_ID";
6424
6880
  var generatedBenchmarkRunId;
6425
- function resolveBenchmarkRunId() {
6426
- const explicit = process.env[BENCHMARK_RUN_ID_ENV]?.trim();
6881
+ function resolveBenchmarkRunId(env = process.env) {
6882
+ const explicit = env[BENCHMARK_RUN_ID_ENV]?.trim();
6427
6883
  if (explicit) {
6428
6884
  return explicit;
6429
6885
  }
@@ -6627,14 +7083,22 @@ var BENCH_OPTION_BOUNDARY_FLAGS = /* @__PURE__ */ new Set([
6627
7083
  ]);
6628
7084
  var SECRET_KEY_PATTERN = /(^|[-_])(?:api[-_]?key|secret[-_]?access[-_]?key|secret[-_]?key|client[-_]?secret(?:[-_]?key)?|app[-_]?secret(?:[-_]?key)?|provider[-_]?secret(?:[-_]?key)?|access[-_]?key|private[-_]?key|secret|password|authorization|credential|access[-_]?token|auth[-_]?token|refresh[-_]?token|id[-_]?token|token)$/i;
6629
7085
  var REDACTED_ARG_VALUE = "[redacted]";
7086
+ var CODEX_CREDIT_REPRO_ENV_KEYS = [
7087
+ "REMNIC_BENCH_CODEX_ALLOW_SOL",
7088
+ "REMNIC_BENCH_CODEX_CREDIT_BUDGET",
7089
+ "REMNIC_BENCH_CODEX_CREDIT_LEDGER",
7090
+ "REMNIC_BENCH_CODEX_CREDIT_RESERVE",
7091
+ "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_MODE",
7092
+ "REMNIC_BENCH_RUN_ID"
7093
+ ];
6630
7094
  function sha256String(value) {
6631
- return createHash3("sha256").update(value).digest("hex");
7095
+ return createHash4("sha256").update(value).digest("hex");
6632
7096
  }
6633
7097
  function sha256Buffer(value) {
6634
- return createHash3("sha256").update(value).digest("hex");
7098
+ return createHash4("sha256").update(value).digest("hex");
6635
7099
  }
6636
7100
  async function sha256File(filePath) {
6637
- const hash = createHash3("sha256");
7101
+ const hash = createHash4("sha256");
6638
7102
  await new Promise((resolve, reject) => {
6639
7103
  const stream = createReadStream(filePath);
6640
7104
  stream.on("data", (chunk) => hash.update(chunk));
@@ -7137,7 +7601,10 @@ function isAsciiAlnum2(char) {
7137
7601
  return isUppercaseAscii(char) || isLowercaseAscii(char) || char >= "0" && char <= "9";
7138
7602
  }
7139
7603
  function sanitizeEnvKeys(env, explicitKeys) {
7140
- const sourceKeys = explicitKeys ?? Object.keys(env ?? {});
7604
+ const sourceKeys = [
7605
+ ...explicitKeys ?? Object.keys(env ?? {}),
7606
+ ...CODEX_CREDIT_REPRO_ENV_KEYS.filter((key) => env?.[key] !== void 0)
7607
+ ];
7141
7608
  return [...new Set(sourceKeys)].filter((key) => typeof key === "string" && key.length > 0).sort((left, right) => left.localeCompare(right));
7142
7609
  }
7143
7610
  function gitOutput(args, cwd) {
@@ -7191,7 +7658,8 @@ function buildArtifactHashIdentity(manifest) {
7191
7658
  ...manifest.qmd ? { qmd: manifest.qmd } : {},
7192
7659
  configFiles: manifest.configFiles,
7193
7660
  datasets: manifest.datasets,
7194
- results: manifest.results
7661
+ results: manifest.results,
7662
+ ...manifest.codexCredit ? { codexCredit: manifest.codexCredit } : {}
7195
7663
  };
7196
7664
  }
7197
7665
  async function scanDatasetFiles(root) {
@@ -7200,18 +7668,18 @@ async function scanDatasetFiles(root) {
7200
7668
  const entries = await readdir4(directory, { withFileTypes: true });
7201
7669
  entries.sort((left, right) => left.name.localeCompare(right.name));
7202
7670
  for (const entry of entries) {
7203
- const entryPath = path4.join(directory, entry.name);
7671
+ const entryPath = path5.join(directory, entry.name);
7204
7672
  const entryStat = await lstat3(entryPath);
7205
- const relativePath = path4.relative(root, entryPath).split(path4.sep).join("/");
7673
+ const relativePath = path5.relative(root, entryPath).split(path5.sep).join("/");
7206
7674
  if (entryStat.isSymbolicLink()) {
7207
7675
  const target = await readlink(entryPath);
7208
- const resolvedTarget = path4.resolve(directory, target);
7676
+ const resolvedTarget = path5.resolve(directory, target);
7209
7677
  const realTarget = await realpath3(resolvedTarget);
7210
- const targetRelativePath = path4.relative(root, realTarget);
7211
- if (targetRelativePath.length === 0 || targetRelativePath === ".." || targetRelativePath.startsWith(`..${path4.sep}`) || path4.isAbsolute(targetRelativePath)) {
7678
+ const targetRelativePath = path5.relative(root, realTarget);
7679
+ if (targetRelativePath.length === 0 || targetRelativePath === ".." || targetRelativePath.startsWith(`..${path5.sep}`) || path5.isAbsolute(targetRelativePath)) {
7212
7680
  throw new Error(`dataset symlink target must be inside ${root}: ${entryPath}`);
7213
7681
  }
7214
- const manifestTarget = path4.isAbsolute(target) ? targetRelativePath.split(path4.sep).join("/") : target;
7682
+ const manifestTarget = path5.isAbsolute(target) ? targetRelativePath.split(path5.sep).join("/") : target;
7215
7683
  files.push({
7216
7684
  path: relativePath,
7217
7685
  kind: "symlink",
@@ -7239,9 +7707,9 @@ async function scanDatasetFiles(root) {
7239
7707
  return files.sort((left, right) => left.path.localeCompare(right.path));
7240
7708
  }
7241
7709
  async function lstatPathWithoutSymlinkComponents(targetPath) {
7242
- const parsed = path4.parse(targetPath);
7243
- const relativePath = path4.relative(parsed.root, targetPath);
7244
- const parts = relativePath.length > 0 ? relativePath.split(path4.sep) : [];
7710
+ const parsed = path5.parse(targetPath);
7711
+ const relativePath = path5.relative(parsed.root, targetPath);
7712
+ const parts = relativePath.length > 0 ? relativePath.split(path5.sep) : [];
7245
7713
  let currentPath = parsed.root;
7246
7714
  let currentStat;
7247
7715
  try {
@@ -7249,7 +7717,7 @@ async function lstatPathWithoutSymlinkComponents(targetPath) {
7249
7717
  currentStat = await lstat3(currentPath);
7250
7718
  }
7251
7719
  for (const part of parts) {
7252
- currentPath = path4.join(currentPath, part);
7720
+ currentPath = path5.join(currentPath, part);
7253
7721
  currentStat = await lstat3(currentPath);
7254
7722
  if (currentStat.isSymbolicLink()) {
7255
7723
  return void 0;
@@ -7270,7 +7738,7 @@ async function buildDatasetManifest(benchmark, datasetDir) {
7270
7738
  files: []
7271
7739
  };
7272
7740
  }
7273
- const datasetRoot = path4.resolve(datasetDir);
7741
+ const datasetRoot = path5.resolve(datasetDir);
7274
7742
  const datasetStat = await lstatPathWithoutSymlinkComponents(datasetRoot);
7275
7743
  if (!datasetStat) {
7276
7744
  return {
@@ -7312,7 +7780,7 @@ async function buildResultManifest(resultsDir, resultPath, result) {
7312
7780
  await assertRegularFileWithoutSymlinkComponents(resultPath, "result path");
7313
7781
  const fileStats = await stat2(resultPath);
7314
7782
  return {
7315
- path: path4.relative(resultsDir, resultPath).split(path4.sep).join("/"),
7783
+ path: path5.relative(resultsDir, resultPath).split(path5.sep).join("/"),
7316
7784
  sha256: await sha256File(resultPath),
7317
7785
  sizeBytes: fileStats.size,
7318
7786
  resultId: result.meta.id,
@@ -7334,7 +7802,7 @@ async function resolveResultPaths(resultsDir, explicitPaths) {
7334
7802
  if (explicitPaths !== void 0) {
7335
7803
  const resolvedPaths = await Promise.all(
7336
7804
  explicitPaths.map(async (entry) => {
7337
- const resultPath = path4.resolve(entry);
7805
+ const resultPath = path5.resolve(entry);
7338
7806
  assertPathInsideRoot(resultsDir, resultPath, "result path");
7339
7807
  await assertRegularFileWithoutSymlinkComponents(resultPath, "result path");
7340
7808
  return resultPath;
@@ -7343,20 +7811,20 @@ async function resolveResultPaths(resultsDir, explicitPaths) {
7343
7811
  return [...new Set(resolvedPaths)].sort((left, right) => left.localeCompare(right));
7344
7812
  }
7345
7813
  const summaries = await listBenchmarkResults(resultsDir);
7346
- return summaries.map((summary) => path4.resolve(summary.path));
7814
+ return summaries.map((summary) => path5.resolve(summary.path));
7347
7815
  }
7348
7816
  function assertPathInsideRoot(root, targetPath, label) {
7349
- const resolvedRoot = path4.resolve(root);
7350
- const resolvedTargetPath = path4.resolve(targetPath);
7351
- const relativePath = path4.relative(resolvedRoot, resolvedTargetPath);
7352
- if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${path4.sep}`) || path4.isAbsolute(relativePath)) {
7817
+ const resolvedRoot = path5.resolve(root);
7818
+ const resolvedTargetPath = path5.resolve(targetPath);
7819
+ const relativePath = path5.relative(resolvedRoot, resolvedTargetPath);
7820
+ if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${path5.sep}`) || path5.isAbsolute(relativePath)) {
7353
7821
  throw new Error(`${label} must be inside ${resolvedRoot}: ${resolvedTargetPath}`);
7354
7822
  }
7355
7823
  }
7356
7824
  async function assertRegularFileWithoutSymlinkComponents(targetPath, label) {
7357
- const targetStat = await lstatPathWithoutSymlinkComponents(path4.resolve(targetPath));
7825
+ const targetStat = await lstatPathWithoutSymlinkComponents(path5.resolve(targetPath));
7358
7826
  if (!targetStat?.isFile()) {
7359
- throw new Error(`${label} must be a regular file without symlink components: ${path4.resolve(targetPath)}`);
7827
+ throw new Error(`${label} must be a regular file without symlink components: ${path5.resolve(targetPath)}`);
7360
7828
  }
7361
7829
  }
7362
7830
  function isKnownNonSecretOptionFlag(arg) {
@@ -7402,7 +7870,7 @@ async function buildConfigFileEntries(configFiles = []) {
7402
7870
  entries.push({ label: configFile.label, path: configFile.path, missing: true });
7403
7871
  continue;
7404
7872
  }
7405
- const content = await readFile4(configFile.path);
7873
+ const content = await readFile5(configFile.path);
7406
7874
  const sanitizedConfig = sanitizeConfigFileContent(content);
7407
7875
  entries.push({
7408
7876
  label: configFile.label,
@@ -7469,7 +7937,7 @@ function resolvePackageManager(cwd) {
7469
7937
  }
7470
7938
  }
7471
7939
  async function buildBenchmarkReproManifest(resultsDir, options = {}) {
7472
- const resolvedResultsDir = path4.resolve(resultsDir);
7940
+ const resolvedResultsDir = path5.resolve(resultsDir);
7473
7941
  const cwd = options.command?.cwd ?? process.cwd();
7474
7942
  const resultPaths = await resolveResultPaths(resolvedResultsDir, options.resultPaths);
7475
7943
  const loadedResults = await Promise.all(resultPaths.map((resultPath) => loadBenchmarkResult(resultPath)));
@@ -7487,11 +7955,23 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
7487
7955
  );
7488
7956
  const qmdCollections = collectQmdCollections(options.qmd?.collections, loadedResults);
7489
7957
  const pnpmVersion = resolvePackageManager(cwd);
7958
+ const commandEnv = options.command?.env ?? process.env;
7959
+ const runId = options.runId ?? resolveBenchmarkRunId(commandEnv);
7960
+ const resolvedCreditConfig = resolveCodexCreditBudgetConfig(commandEnv, runId);
7961
+ const creditConfig = resolvedCreditConfig ? { ...resolvedCreditConfig, runId } : void 0;
7962
+ let codexCredit;
7963
+ if (creditConfig) {
7964
+ try {
7965
+ codexCredit = await buildCodexCreditReceipt(creditConfig.ledgerPath, creditConfig.runId);
7966
+ } catch (error) {
7967
+ if (error.code !== "ENOENT") throw error;
7968
+ }
7969
+ }
7490
7970
  const manifestWithoutHash = {
7491
7971
  schemaVersion: BENCHMARK_REPRO_MANIFEST_SCHEMA_VERSION,
7492
7972
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
7493
7973
  run: {
7494
- id: options.runId ?? resolveBenchmarkRunId(),
7974
+ id: runId,
7495
7975
  ...options.mode ? { mode: options.mode } : {},
7496
7976
  selectedBenchmarks,
7497
7977
  runtimeProfiles: options.runtimeProfiles ?? [],
@@ -7503,13 +7983,13 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
7503
7983
  command: {
7504
7984
  cwd,
7505
7985
  argv: sanitizeArgv(options.command?.argv ?? process.argv.slice(2)),
7506
- envKeys: sanitizeEnvKeys(options.command?.env, options.command?.envKeys)
7986
+ envKeys: sanitizeEnvKeys(commandEnv, options.command?.envKeys)
7507
7987
  },
7508
7988
  environment: {
7509
7989
  platform: process.platform,
7510
7990
  arch: process.arch,
7511
7991
  nodeVersion: process.version,
7512
- hostname: os2.hostname(),
7992
+ hostname: os3.hostname(),
7513
7993
  ...pnpmVersion ? { packageManager: `pnpm@${pnpmVersion}` } : {}
7514
7994
  },
7515
7995
  ...options.qmd || qmdCollections.length > 0 ? {
@@ -7521,7 +8001,8 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
7521
8001
  } : {},
7522
8002
  configFiles: await buildConfigFileEntries(options.configFiles),
7523
8003
  datasets,
7524
- results: resultEntries.sort((left, right) => left.path.localeCompare(right.path))
8004
+ results: resultEntries.sort((left, right) => left.path.localeCompare(right.path)),
8005
+ ...codexCredit ? { codexCredit } : {}
7525
8006
  };
7526
8007
  return {
7527
8008
  ...manifestWithoutHash,
@@ -7529,18 +8010,18 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
7529
8010
  };
7530
8011
  }
7531
8012
  async function writeBenchmarkReproManifest(resultsDir, options = {}) {
7532
- await mkdir3(resultsDir, { recursive: true });
8013
+ await mkdir4(resultsDir, { recursive: true });
7533
8014
  const manifest = await buildBenchmarkReproManifest(resultsDir, options);
7534
- const manifestPath = path4.join(resultsDir, BENCHMARK_REPRO_MANIFEST_FILENAME);
7535
- await writeFile3(manifestPath, `${JSON.stringify(manifest, null, 2)}
8015
+ const manifestPath = path5.join(resultsDir, BENCHMARK_REPRO_MANIFEST_FILENAME);
8016
+ await writeFile4(manifestPath, `${JSON.stringify(manifest, null, 2)}
7536
8017
  `);
7537
8018
  return manifestPath;
7538
8019
  }
7539
8020
 
7540
8021
  // src/published-artifact.ts
7541
- import { createHash as createHash4 } from "crypto";
7542
- import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
7543
- import path5 from "path";
8022
+ import { createHash as createHash5 } from "crypto";
8023
+ import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
8024
+ import path6 from "path";
7544
8025
  var BENCHMARK_ARTIFACT_SCHEMA_VERSION = 1;
7545
8026
  var PUBLISHED_BENCHMARK_ARTIFACT_IDS = Object.freeze([
7546
8027
  "ama-bench",
@@ -7681,25 +8162,25 @@ function serializeBenchmarkArtifact(artifact) {
7681
8162
  `;
7682
8163
  }
7683
8164
  function hashBenchmarkArtifact(artifact) {
7684
- return createHash4("sha256").update(serializeBenchmarkArtifact(artifact)).digest("hex");
8165
+ return createHash5("sha256").update(serializeBenchmarkArtifact(artifact)).digest("hex");
7685
8166
  }
7686
8167
  async function writeBenchmarkArtifact(artifact, outputDir) {
7687
- await mkdir4(outputDir, { recursive: true });
8168
+ await mkdir5(outputDir, { recursive: true });
7688
8169
  const filename = buildBenchmarkArtifactFilename(artifact);
7689
8170
  const body = serializeBenchmarkArtifact(artifact);
7690
- const resolvedDir = path5.resolve(outputDir);
7691
- const abs = path5.resolve(resolvedDir, filename);
7692
- const relative = path5.relative(resolvedDir, abs);
7693
- if (relative.length === 0 || relative.startsWith("..") || path5.isAbsolute(relative) || relative.includes(path5.sep)) {
8171
+ const resolvedDir = path6.resolve(outputDir);
8172
+ const abs = path6.resolve(resolvedDir, filename);
8173
+ const relative = path6.relative(resolvedDir, abs);
8174
+ if (relative.length === 0 || relative.startsWith("..") || path6.isAbsolute(relative) || relative.includes(path6.sep)) {
7694
8175
  throw new Error(
7695
8176
  `writeBenchmarkArtifact: refusing to write outside outputDir (filename="${filename}", resolved="${abs}").`
7696
8177
  );
7697
8178
  }
7698
- await writeFile4(abs, body);
8179
+ await writeFile5(abs, body);
7699
8180
  return {
7700
8181
  path: abs,
7701
8182
  filename,
7702
- sha256: createHash4("sha256").update(body).digest("hex"),
8183
+ sha256: createHash5("sha256").update(body).digest("hex"),
7703
8184
  bytes: Buffer.byteLength(body, "utf8")
7704
8185
  };
7705
8186
  }
@@ -7804,11 +8285,11 @@ function parseBenchmarkArtifact(raw) {
7804
8285
  return parsed;
7805
8286
  }
7806
8287
  async function loadBenchmarkArtifact(filePath) {
7807
- const raw = await readFile5(filePath, "utf8");
8288
+ const raw = await readFile6(filePath, "utf8");
7808
8289
  const artifact = parseBenchmarkArtifact(raw);
7809
8290
  return {
7810
8291
  artifact,
7811
- sha256: createHash4("sha256").update(raw).digest("hex"),
8292
+ sha256: createHash5("sha256").update(raw).digest("hex"),
7812
8293
  bytes: Buffer.byteLength(raw, "utf8")
7813
8294
  };
7814
8295
  }
@@ -8211,8 +8692,8 @@ function createAnthropicProvider(config) {
8211
8692
  // src/providers/claude-cli.ts
8212
8693
  import { spawn } from "child_process";
8213
8694
  import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
8214
- import os3 from "os";
8215
- import path6 from "path";
8695
+ import os4 from "os";
8696
+ import path7 from "path";
8216
8697
  var CLAUDE_CLI_STDIO_LIMIT = 64e3;
8217
8698
  var CLAUDE_CLI_PARENT_SIGNALS = ["SIGHUP", "SIGINT", "SIGTERM"];
8218
8699
  var CLAUDE_CLI_FORCED_PARENT_EXIT_MS = 1e3;
@@ -8365,7 +8846,7 @@ var ClaudeCliProvider = class {
8365
8846
  let transientAttempt = 1;
8366
8847
  let usageLimitAttempt = 1;
8367
8848
  while (true) {
8368
- const tempDir = await mkdtemp2(path6.join(os3.tmpdir(), "remnic-claude-cli-"));
8849
+ const tempDir = await mkdtemp2(path7.join(os4.tmpdir(), "remnic-claude-cli-"));
8369
8850
  try {
8370
8851
  const request = this.buildRunRequest(prompt, opts, tempDir);
8371
8852
  const result = await this.runClaudeCli(request);
@@ -8577,14 +9058,14 @@ function resolveClaudeCliExecutable(config) {
8577
9058
  if (trimmed.length === 0) {
8578
9059
  throw new Error(`${CLAUDE_CLI_EXECUTABLE_ENV} / claude-cli executable must not be empty`);
8579
9060
  }
8580
- return expandHomeRelativePath(trimmed);
9061
+ return expandHomeRelativePath2(trimmed);
8581
9062
  }
8582
- function expandHomeRelativePath(value) {
9063
+ function expandHomeRelativePath2(value) {
8583
9064
  if (value === "~") {
8584
- return os3.homedir();
9065
+ return os4.homedir();
8585
9066
  }
8586
9067
  if (value.startsWith("~/") || value.startsWith("~\\")) {
8587
- return path6.join(os3.homedir(), value.slice(2));
9068
+ return path7.join(os4.homedir(), value.slice(2));
8588
9069
  }
8589
9070
  return value;
8590
9071
  }
@@ -8971,12 +9452,203 @@ function createClaudeCliProvider(config, deps) {
8971
9452
 
8972
9453
  // src/providers/codex-cli.ts
8973
9454
  import { spawn as spawn2 } from "child_process";
8974
- import { createHash as createHash5, randomUUID } from "crypto";
8975
- import { mkdir as mkdir5, mkdtemp as mkdtemp3, readFile as readFile6, rm as rm3, writeFile as writeFile5 } from "fs/promises";
8976
- import os4 from "os";
8977
- import path7 from "path";
9455
+ import { createHash as createHash6, randomUUID } from "crypto";
9456
+ import { mkdir as mkdir6, mkdtemp as mkdtemp3, readFile as readFile7, rm as rm3, writeFile as writeFile6 } from "fs/promises";
9457
+ import os5 from "os";
9458
+ import path8 from "path";
9459
+
9460
+ // src/judges/memcorrect-rubrics.ts
9461
+ var OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION = "openai-responses-bench-v1";
9462
+ var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION = "memcorrect-correction-acceptance-v1";
9463
+ var MEMCORRECT_STALE_HARM_RUBRIC_VERSION = "memcorrect-stale-memory-harm-v1";
9464
+ var GENERAL_ANSWER_JUDGE_RUBRIC = [
9465
+ "Grade the predicted benchmark answer against the reference answer.",
9466
+ "A score of 1 means fully correct, 0 means fully incorrect, and values between 0 and 1 mean partially correct.",
9467
+ "Do not reward unsupported claims. Ignore harmless wording and formatting differences."
9468
+ ].join(" ");
9469
+ var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC = [
9470
+ "Decide whether the memory system accepted the user's correction.",
9471
+ "Pass only when the corrected fact is reflected and the retired fact is not asserted as current.",
9472
+ "A quotation or correction-history record that clearly marks the retired fact as obsolete is not stale recall.",
9473
+ "Use a score of 1 for accepted, 0 for not accepted, and a fractional score only when the evidence is genuinely ambiguous."
9474
+ ].join(" ");
9475
+ var MEMCORRECT_STALE_HARM_RUBRIC = [
9476
+ "Decide whether the memory system avoided stale-memory harm after a correction.",
9477
+ "Pass only when the answer does not present the retired fact as current and does not act on it.",
9478
+ "Correction provenance may mention the retired fact only when it is explicitly identified as obsolete.",
9479
+ "Use a score of 1 when no stale harm is present, 0 when stale information affected the answer, and a fractional score only for genuinely ambiguous evidence."
9480
+ ].join(" ");
9481
+
9482
+ // src/providers/structured-judge.ts
9483
+ var VERDICT_JSON_SCHEMA = {
9484
+ type: "object",
9485
+ additionalProperties: false,
9486
+ required: ["score", "decision", "reason"],
9487
+ properties: {
9488
+ score: { type: "number", minimum: 0, maximum: 1 },
9489
+ decision: { type: "string", enum: ["pass", "partial", "fail"] },
9490
+ reason: { type: "string" }
9491
+ }
9492
+ };
9493
+ var ASSISTANT_RUBRIC_JSON_SCHEMA = {
9494
+ type: "object",
9495
+ additionalProperties: false,
9496
+ required: ["identity_accuracy", "stance_coherence", "novelty", "calibration", "notes"],
9497
+ properties: {
9498
+ identity_accuracy: { type: "number", minimum: 0, maximum: 5 },
9499
+ stance_coherence: { type: "number", minimum: 0, maximum: 5 },
9500
+ novelty: { type: "number", minimum: 0, maximum: 5 },
9501
+ calibration: { type: "number", minimum: 0, maximum: 5 },
9502
+ notes: { type: "string" }
9503
+ }
9504
+ };
9505
+ var StructuredJudgeError = class extends Error {
9506
+ code;
9507
+ retryable;
9508
+ httpStatus;
9509
+ telemetry;
9510
+ constructor(failure) {
9511
+ super(failure.error.message);
9512
+ this.name = "StructuredJudgeError";
9513
+ this.code = failure.error.code;
9514
+ this.retryable = failure.error.retryable;
9515
+ this.httpStatus = failure.error.httpStatus;
9516
+ this.telemetry = failure.telemetry;
9517
+ }
9518
+ };
9519
+ function isStructuredJudgeProvider(provider) {
9520
+ const candidate = provider;
9521
+ return typeof candidate.judge === "function" && typeof candidate.evaluateAssistantRubric === "function";
9522
+ }
9523
+ function createStructuredBenchJudge(provider, rubricVersion = OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION) {
9524
+ const scoreWithMetrics = async (question, predicted, expected, control) => unwrapJudgeResult(
9525
+ provider,
9526
+ await provider.judge({
9527
+ rubric: GENERAL_ANSWER_JUDGE_RUBRIC,
9528
+ rubricVersion,
9529
+ input: [`QUESTION: ${question}`, `REFERENCE_ANSWER: ${expected}`, `PREDICTED_ANSWER: ${predicted}`].join(
9530
+ "\n\n"
9531
+ ),
9532
+ signal: control?.signal
9533
+ })
9534
+ );
9535
+ const scoreBinaryPrompt = async (prompt, control) => {
9536
+ const result = await provider.judge({
9537
+ rubric: `${GENERAL_ANSWER_JUDGE_RUBRIC} This evaluator is binary: score must be exactly 0 or 1.`,
9538
+ rubricVersion,
9539
+ input: prompt,
9540
+ signal: control?.signal
9541
+ });
9542
+ if (result.ok && result.verdict.score !== 0 && result.verdict.score !== 1) {
9543
+ throwJudgeFailure(provider, {
9544
+ ok: false,
9545
+ error: {
9546
+ code: "malformed_verdict",
9547
+ message: "Structured judge returned a non-binary verdict for a binary rubric.",
9548
+ retryable: false
9549
+ },
9550
+ telemetry: { ...result.telemetry, errorCode: "malformed_verdict" }
9551
+ });
9552
+ }
9553
+ return unwrapJudgeResult(provider, result);
9554
+ };
9555
+ const judgeSpecialized = async (request, rubric, control) => {
9556
+ const result = await provider.judge({
9557
+ rubric: rubric === "correction" ? MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC : MEMCORRECT_STALE_HARM_RUBRIC,
9558
+ rubricVersion: rubric === "correction" ? MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION : MEMCORRECT_STALE_HARM_RUBRIC_VERSION,
9559
+ input: serializeMemCorrectJudgeRequest(request),
9560
+ signal: control?.signal
9561
+ });
9562
+ if (!result.ok) {
9563
+ throwJudgeFailure(provider, result);
9564
+ }
9565
+ const base = unwrapJudgeResult(provider, result);
9566
+ return {
9567
+ ...base,
9568
+ decision: result.verdict.decision,
9569
+ reason: result.verdict.reason,
9570
+ rubricVersion: result.telemetry.rubricVersion
9571
+ };
9572
+ };
9573
+ return {
9574
+ async score(question, predicted, expected, control) {
9575
+ return (await scoreWithMetrics(question, predicted, expected, control)).score;
9576
+ },
9577
+ scoreWithMetrics,
9578
+ scoreBinaryPrompt,
9579
+ judgeMemCorrectCorrectionAcceptance: (request, control) => judgeSpecialized(request, "correction", control),
9580
+ judgeMemCorrectStaleMemoryHarm: (request, control) => judgeSpecialized(request, "stale_harm", control)
9581
+ };
9582
+ }
9583
+ function parseStructuredJudgeVerdict(text) {
9584
+ let parsed;
9585
+ try {
9586
+ parsed = JSON.parse(text);
9587
+ } catch {
9588
+ return null;
9589
+ }
9590
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
9591
+ const candidate = parsed;
9592
+ if (Object.keys(candidate).sort().join(",") !== "decision,reason,score") return null;
9593
+ if (typeof candidate.score !== "number" || !Number.isFinite(candidate.score) || candidate.score < 0 || candidate.score > 1 || candidate.decision !== "pass" && candidate.decision !== "partial" && candidate.decision !== "fail" || typeof candidate.reason !== "string" || candidate.reason.trim().length === 0) {
9594
+ return null;
9595
+ }
9596
+ return {
9597
+ score: candidate.score,
9598
+ decision: candidate.decision,
9599
+ reason: candidate.reason.trim()
9600
+ };
9601
+ }
9602
+ function isValidAssistantRubric(text) {
9603
+ let parsed;
9604
+ try {
9605
+ parsed = JSON.parse(text);
9606
+ } catch {
9607
+ return false;
9608
+ }
9609
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
9610
+ const candidate = parsed;
9611
+ if (Object.keys(candidate).sort().join(",") !== "calibration,identity_accuracy,notes,novelty,stance_coherence") {
9612
+ return false;
9613
+ }
9614
+ return ["identity_accuracy", "stance_coherence", "novelty", "calibration"].every(
9615
+ (key) => typeof candidate[key] === "number" && Number.isFinite(candidate[key]) && candidate[key] >= 0 && candidate[key] <= 5
9616
+ ) && typeof candidate.notes === "string";
9617
+ }
9618
+ function serializeMemCorrectJudgeRequest(request) {
9619
+ return JSON.stringify({
9620
+ taskId: request.taskId,
9621
+ query: request.query,
9622
+ retiredContent: request.retiredContent,
9623
+ correctedContent: request.correctedContent,
9624
+ evidence: {
9625
+ postCorrectionRecall: request.postCorrectionRecall,
9626
+ postMaintenanceRecall: request.postMaintenanceRecall,
9627
+ postReingestRecall: request.postReingestRecall
9628
+ }
9629
+ });
9630
+ }
9631
+ function unwrapJudgeResult(provider, result) {
9632
+ if (!result.ok) {
9633
+ throwJudgeFailure(provider, result);
9634
+ }
9635
+ return {
9636
+ score: result.verdict.score,
9637
+ tokens: {
9638
+ input: result.telemetry.inputTokens,
9639
+ output: result.telemetry.outputTokens
9640
+ },
9641
+ latencyMs: result.telemetry.latencyMs,
9642
+ model: result.telemetry.model
9643
+ };
9644
+ }
9645
+ function throwJudgeFailure(provider, failure) {
9646
+ throw provider.createJudgeError?.(failure) ?? new StructuredJudgeError(failure);
9647
+ }
9648
+
9649
+ // src/providers/codex-cli.ts
8978
9650
  var DEFAULT_REASONING_EFFORT = "xhigh";
8979
- var DEFAULT_SERVICE_TIER = "fast";
9651
+ var DEFAULT_SERVICE_TIER = "default";
8980
9652
  var CODEX_CLI_STDIO_LIMIT = 64e3;
8981
9653
  var CODEX_CLI_PARENT_SIGNALS = [
8982
9654
  "SIGHUP",
@@ -8987,12 +9659,8 @@ var CODEX_CLI_FORCED_PARENT_EXIT_MS = 1e3;
8987
9659
  var CODEX_CLI_DIAGNOSTICS_DIR_ENV = "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_DIR";
8988
9660
  var CODEX_CLI_DIAGNOSTICS_MODE_ENV = "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_MODE";
8989
9661
  var CODEX_CLI_EXECUTABLE_ENV = "REMNIC_BENCH_CODEX_CLI_EXECUTABLE";
8990
- var CODEX_CLI_TRANSPORT_ENV = "REMNIC_BENCH_CODEX_CLI_TRANSPORT";
8991
9662
  var CODEX_CLI_VERSION_TIMEOUT_MS = 5e3;
8992
- var CODEX_CLI_HEALTH_CACHE_TTL_MS = 3e4;
8993
- var OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
8994
- var OPENAI_BASE_URL_ENV = "OPENAI_BASE_URL";
8995
- var OPENAI_RESPONSES_BASE_URL = "https://api.openai.com/v1";
9663
+ var CODEX_CLI_PRE_START_ABORT_MESSAGE = "Codex CLI aborted before start.";
8996
9664
  var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
8997
9665
  "ALL_PROXY",
8998
9666
  "APPDATA",
@@ -9010,9 +9678,6 @@ var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
9010
9678
  "NODE_EXTRA_CA_CERTS",
9011
9679
  "NO_PROXY",
9012
9680
  "NUMBER_OF_PROCESSORS",
9013
- OPENAI_BASE_URL_ENV,
9014
- "OPENAI_ORGANIZATION",
9015
- "OPENAI_PROJECT",
9016
9681
  "OS",
9017
9682
  "PATH",
9018
9683
  "PATHEXT",
@@ -9040,7 +9705,7 @@ var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
9040
9705
  ]);
9041
9706
  var activeCodexCliChildPids = /* @__PURE__ */ new Set();
9042
9707
  var codexCliParentCleanupInstalled = false;
9043
- var codexCliHealthCache = /* @__PURE__ */ new Map();
9708
+ var codexCliLoginStatusCache = /* @__PURE__ */ new Map();
9044
9709
  var CodexCliProvider = class {
9045
9710
  provider = "codex-cli";
9046
9711
  id;
@@ -9048,7 +9713,8 @@ var CodexCliProvider = class {
9048
9713
  config;
9049
9714
  runCodexCli;
9050
9715
  runCodexVersion;
9051
- shouldProbeCliHealth;
9716
+ runCodexLoginStatus;
9717
+ requiresExactUsage;
9052
9718
  usage = {
9053
9719
  inputTokens: 0,
9054
9720
  outputTokens: 0,
@@ -9058,23 +9724,31 @@ var CodexCliProvider = class {
9058
9724
  this.config = config;
9059
9725
  this.runCodexCli = deps.runCodexCli ?? runCodexCliCommand;
9060
9726
  this.runCodexVersion = deps.runCodexVersion ?? runCodexVersionCommand;
9061
- this.shouldProbeCliHealth = deps.runCodexCli === void 0;
9727
+ this.runCodexLoginStatus = deps.runCodexLoginStatus ?? runCodexLoginStatusCommand;
9728
+ this.requiresExactUsage = deps.runCodexCli === void 0;
9062
9729
  this.id = `codex-cli:${config.model}`;
9063
9730
  this.name = config.model;
9064
9731
  }
9065
9732
  async complete(prompt, opts = {}) {
9733
+ if (opts.signal?.aborted) {
9734
+ throw codexCliAbortError(opts.signal);
9735
+ }
9066
9736
  const startedAt = performance.now();
9067
- if (await this.shouldUseResponsesFallback()) {
9068
- return this.completeViaResponsesApi(prompt, opts, startedAt);
9737
+ const creditBudget = resolveCodexCreditBudgetConfig(
9738
+ process.env,
9739
+ resolveBenchmarkRunId()
9740
+ );
9741
+ if (creditBudget) {
9742
+ await this.assertChatGptCreditAuth();
9069
9743
  }
9070
9744
  const maxAttempts = normalizeCodexCliMaxAttempts(
9071
- this.config.retryOptions?.maxAttempts
9745
+ creditBudget ? 1 : this.config.retryOptions?.maxAttempts
9072
9746
  );
9073
9747
  let lastError;
9074
9748
  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
9075
- const tempDir = await mkdtemp3(path7.join(os4.tmpdir(), "remnic-codex-cli-"));
9076
- const workspacePath = path7.join(tempDir, "workspace");
9077
- const outputPath = path7.join(tempDir, "last-message.txt");
9749
+ const tempDir = await mkdtemp3(path8.join(os5.tmpdir(), "remnic-codex-cli-"));
9750
+ const workspacePath = path8.join(tempDir, "workspace");
9751
+ const outputPath = path8.join(tempDir, "last-message.txt");
9078
9752
  let diagnostics;
9079
9753
  let diagnosticsFinished = false;
9080
9754
  const finishDiagnostics = async (outcome) => {
@@ -9085,7 +9759,7 @@ var CodexCliProvider = class {
9085
9759
  await finishCodexCliDiagnostics(diagnostics, startedAt, outcome);
9086
9760
  };
9087
9761
  try {
9088
- await mkdir5(workspacePath, { recursive: true });
9762
+ await mkdir6(workspacePath, { recursive: true });
9089
9763
  const request = this.buildRunRequest(prompt, opts, workspacePath, outputPath);
9090
9764
  diagnostics = await startCodexCliDiagnostics({
9091
9765
  config: this.config,
@@ -9094,12 +9768,48 @@ var CodexCliProvider = class {
9094
9768
  serviceTier: DEFAULT_SERVICE_TIER,
9095
9769
  retry: { attempt, maxAttempts }
9096
9770
  });
9097
- const result = await this.runCodexCli(request);
9771
+ const result = creditBudget ? await runWithinCodexCreditBudget({
9772
+ config: creditBudget,
9773
+ model: this.config.model,
9774
+ onUsagePersisted: (usage) => {
9775
+ this.recordUsage(usage.inputTokens, usage.outputTokens);
9776
+ },
9777
+ run: async () => {
9778
+ if (opts.signal?.aborted) {
9779
+ throw codexCliPreStartAbortError(opts.signal);
9780
+ }
9781
+ let value;
9782
+ try {
9783
+ value = await this.runCodexCli(request);
9784
+ } catch (error) {
9785
+ if (error instanceof CodexCreditDispatchError || error instanceof CodexCreditAccountingError) {
9786
+ throw error;
9787
+ }
9788
+ throw new CodexCreditAccountingError(
9789
+ `Codex CLI failed after dispatch; account balance must be reconciled before resuming: ${safeErrorMessage2(error)}`
9790
+ );
9791
+ }
9792
+ const usage = parseCodexJsonlUsage(
9793
+ `${value.stdout}
9794
+ ${value.stderr}`
9795
+ );
9796
+ if (!usage) {
9797
+ throw new CodexCreditAccountingError(
9798
+ `Codex CLI exited ${value.status ?? "without a status"} without exact turn.completed usage; account balance must be reconciled before resuming.`
9799
+ );
9800
+ }
9801
+ return { value, usage };
9802
+ }
9803
+ }) : await this.runCodexCli(request);
9804
+ const exactUsage = parseCodexJsonlUsage(
9805
+ `${result.stdout}
9806
+ ${result.stderr}`
9807
+ );
9808
+ if (!creditBudget && exactUsage) {
9809
+ this.recordUsage(exactUsage.inputTokens, exactUsage.outputTokens);
9810
+ }
9098
9811
  if (result.status !== 0) {
9099
- const exitLabel = result.signal ? `signal ${result.signal}` : `exit ${result.status ?? "unknown"}`;
9100
- const error = new Error(
9101
- `Codex CLI completion failed (${exitLabel}): ${summarizeProcessOutput2(result.stderr, result.stdout)}`
9102
- );
9812
+ const error = codexCliResultError(result);
9103
9813
  if (attempt < maxAttempts && isRetryableCodexCliResult(result)) {
9104
9814
  lastError = error;
9105
9815
  await finishDiagnostics({
@@ -9126,12 +9836,14 @@ var CodexCliProvider = class {
9126
9836
  throw error;
9127
9837
  }
9128
9838
  await finishDiagnostics({ result });
9129
- const tokens = parseCodexTokenUsage(
9130
- `${result.stderr}
9131
- ${result.stdout}`,
9132
- text
9133
- );
9134
- this.recordUsage(tokens.input, tokens.output);
9839
+ const nativeUsage = exactUsage ?? (this.requiresExactUsage ? requireCodexJsonlUsage(result) : readCodexUsage(result, text));
9840
+ const tokens = {
9841
+ input: nativeUsage.inputTokens,
9842
+ output: nativeUsage.outputTokens
9843
+ };
9844
+ if (!creditBudget && !exactUsage) {
9845
+ this.recordUsage(tokens.input, tokens.output);
9846
+ }
9135
9847
  return {
9136
9848
  text,
9137
9849
  tokens,
@@ -9139,15 +9851,93 @@ ${result.stdout}`,
9139
9851
  model: this.config.model
9140
9852
  };
9141
9853
  } catch (error) {
9142
- lastError = error;
9143
- await finishDiagnostics({ error });
9144
- throw error;
9854
+ const surfacedError = unwrapCodexCliPreStartAbort(error);
9855
+ lastError = surfacedError;
9856
+ await finishDiagnostics({ error: surfacedError });
9857
+ throw surfacedError;
9145
9858
  } finally {
9146
9859
  await rm3(tempDir, { force: true, recursive: true });
9147
9860
  }
9148
9861
  }
9149
9862
  throw lastError instanceof Error ? lastError : new Error(String(lastError));
9150
9863
  }
9864
+ async judge(request) {
9865
+ const startedAt = performance.now();
9866
+ try {
9867
+ const completion = await this.complete(request.input, {
9868
+ systemPrompt: buildCodexStructuredJudgePrompt(request.rubric),
9869
+ temperature: 0,
9870
+ maxTokens: request.maxTokens ?? 256,
9871
+ signal: request.signal
9872
+ });
9873
+ const telemetry = {
9874
+ model: completion.model,
9875
+ rubricVersion: request.rubricVersion,
9876
+ inputTokens: completion.tokens.input,
9877
+ outputTokens: completion.tokens.output,
9878
+ latencyMs: completion.latencyMs
9879
+ };
9880
+ const verdict = parseStructuredJudgeVerdict(completion.text);
9881
+ if (!verdict) {
9882
+ return {
9883
+ ok: false,
9884
+ error: {
9885
+ code: "malformed_verdict",
9886
+ message: "Codex CLI returned a verdict that failed schema validation.",
9887
+ retryable: false
9888
+ },
9889
+ telemetry: { ...telemetry, errorCode: "malformed_verdict" }
9890
+ };
9891
+ }
9892
+ return { ok: true, verdict, telemetry };
9893
+ } catch (error) {
9894
+ const aborted = isCodexStructuredJudgeAbort(error, request.signal);
9895
+ const errorCode = aborted ? "aborted" : "transport_error";
9896
+ return {
9897
+ ok: false,
9898
+ error: {
9899
+ code: errorCode,
9900
+ message: aborted ? "Codex CLI judging was aborted by the caller." : `Codex CLI judging failed (${structuredJudgeErrorName(error)}).`,
9901
+ retryable: false
9902
+ },
9903
+ telemetry: {
9904
+ model: this.config.model,
9905
+ rubricVersion: request.rubricVersion,
9906
+ inputTokens: 0,
9907
+ outputTokens: 0,
9908
+ latencyMs: Math.round(performance.now() - startedAt),
9909
+ errorCode
9910
+ }
9911
+ };
9912
+ }
9913
+ }
9914
+ async evaluateAssistantRubric(request) {
9915
+ const rubricVersion = `sealed:${request.rubricId}`;
9916
+ const completion = await this.complete(request.user, {
9917
+ systemPrompt: buildCodexAssistantRubricPrompt(request.system),
9918
+ temperature: 0,
9919
+ maxTokens: 512
9920
+ });
9921
+ if (isValidAssistantRubric(completion.text)) {
9922
+ return completion.text;
9923
+ }
9924
+ throw new StructuredJudgeError({
9925
+ ok: false,
9926
+ error: {
9927
+ code: "malformed_verdict",
9928
+ message: "Codex CLI returned an invalid sealed assistant-rubric verdict.",
9929
+ retryable: false
9930
+ },
9931
+ telemetry: {
9932
+ model: completion.model,
9933
+ rubricVersion,
9934
+ inputTokens: completion.tokens.input,
9935
+ outputTokens: completion.tokens.output,
9936
+ latencyMs: completion.latencyMs,
9937
+ errorCode: "malformed_verdict"
9938
+ }
9939
+ });
9940
+ }
9151
9941
  async discover() {
9152
9942
  const version = await this.runCodexVersion(
9153
9943
  resolveCodexCliExecutable(this.config),
@@ -9177,6 +9967,26 @@ ${result.stdout}`,
9177
9967
  totalTokens: 0
9178
9968
  };
9179
9969
  }
9970
+ async assertChatGptCreditAuth() {
9971
+ const executable = resolveCodexCliExecutable(this.config);
9972
+ const env = buildIsolatedCodexEnv();
9973
+ const cacheKey = `${executable}\0${env.CODEX_HOME ?? env.HOME ?? ""}`;
9974
+ let check = codexCliLoginStatusCache.get(cacheKey);
9975
+ if (!check) {
9976
+ check = this.runCodexLoginStatus(executable, env).then((result) => {
9977
+ const output = `${result.stdout}
9978
+ ${result.stderr}`.trim();
9979
+ if (result.status !== 0 || !/logged in using chatgpt/i.test(output)) {
9980
+ throw new Error(
9981
+ `Bounded Codex credit runs require ChatGPT-backed Codex CLI authentication; \`codex login status\` reported: ${output || `exit ${result.status ?? "unknown"}`}`
9982
+ );
9983
+ }
9984
+ });
9985
+ codexCliLoginStatusCache.set(cacheKey, check);
9986
+ check.catch(() => codexCliLoginStatusCache.delete(cacheKey));
9987
+ }
9988
+ await check;
9989
+ }
9180
9990
  recordUsage(inputTokens, outputTokens) {
9181
9991
  this.usage = {
9182
9992
  inputTokens: this.usage.inputTokens + inputTokens,
@@ -9184,126 +9994,57 @@ ${result.stdout}`,
9184
9994
  totalTokens: this.usage.totalTokens + inputTokens + outputTokens
9185
9995
  };
9186
9996
  }
9187
- async shouldUseResponsesFallback() {
9188
- const transport = process.env[CODEX_CLI_TRANSPORT_ENV]?.trim().toLowerCase();
9189
- if (transport === "cli") {
9190
- return false;
9191
- }
9192
- if (transport === "responses") {
9193
- return true;
9194
- }
9195
- if (!this.shouldProbeCliHealth || this.resolveOpenAiApiKey().length === 0) {
9196
- return false;
9197
- }
9198
- return !await this.isCliHealthy();
9199
- }
9200
- async isCliHealthy() {
9201
- const executable = resolveCodexCliExecutable(this.config);
9202
- const env = buildIsolatedCodexEnv(this.config.apiKey);
9203
- if (this.runCodexVersion !== runCodexVersionCommand) {
9204
- return this.probeCliHealth(executable, env);
9205
- }
9206
- const cacheKey = `${executable}\0${env.PATH ?? ""}`;
9207
- const cached = codexCliHealthCache.get(cacheKey);
9208
- if (cached && Date.now() - cached.checkedAt < CODEX_CLI_HEALTH_CACHE_TTL_MS) {
9209
- return cached.promise;
9210
- }
9211
- if (cached) {
9212
- codexCliHealthCache.delete(cacheKey);
9213
- }
9214
- const promise = this.probeCliHealth(executable, env).then((healthy) => {
9215
- if (!healthy) {
9216
- codexCliHealthCache.delete(cacheKey);
9217
- }
9218
- return healthy;
9219
- });
9220
- codexCliHealthCache.set(cacheKey, { checkedAt: Date.now(), promise });
9221
- return promise;
9222
- }
9223
- async probeCliHealth(executable, env) {
9224
- try {
9225
- const version = await this.runCodexVersion(executable, env);
9226
- return version.status === 0;
9227
- } catch {
9228
- return false;
9229
- }
9230
- }
9231
- resolveOpenAiApiKey() {
9232
- return (this.config.apiKey ?? process.env[OPENAI_API_KEY_ENV] ?? "").trim();
9233
- }
9234
- async completeViaResponsesApi(prompt, opts, startedAt) {
9235
- const apiKey = this.resolveOpenAiApiKey();
9236
- if (apiKey.length === 0) {
9237
- throw new Error(
9238
- `Codex CLI fallback requires ${OPENAI_API_KEY_ENV} or codex-cli apiKey.`
9239
- );
9240
- }
9241
- const serviceTier = responsesApiServiceTier(DEFAULT_SERVICE_TIER);
9242
- const body = {
9243
- model: this.config.model,
9244
- instructions: buildResponsesInstructions(opts.systemPrompt),
9245
- input: prompt,
9246
- reasoning: {
9247
- effort: this.config.reasoningEffort ?? DEFAULT_REASONING_EFFORT
9248
- },
9249
- ...serviceTier ? { service_tier: serviceTier } : {},
9250
- max_output_tokens: Math.max(1, Math.floor(opts.maxTokens ?? 1024)),
9251
- store: false
9252
- };
9253
- const response = await retryFetch(
9254
- this.responsesApiUrl(),
9255
- {
9256
- method: "POST",
9257
- headers: {
9258
- "content-type": "application/json",
9259
- authorization: `Bearer ${apiKey}`
9260
- },
9261
- signal: opts.signal,
9262
- body: JSON.stringify(body)
9263
- },
9264
- this.config.retryOptions
9265
- );
9266
- if (!response.ok) {
9267
- throw new Error(
9268
- `Codex CLI Responses API fallback failed: ${response.status} ${response.statusText}${await readResponseErrorBody(response)}`
9269
- );
9270
- }
9271
- const payload = await response.json();
9272
- const text = extractResponsesOutputText(payload).trim();
9273
- if (text.length === 0) {
9274
- throw new Error("Codex CLI Responses API fallback returned no text.");
9275
- }
9276
- const inputTokens = payload.usage?.input_tokens ?? 0;
9277
- const outputTokens = payload.usage?.output_tokens ?? 0;
9278
- this.recordUsage(inputTokens, outputTokens);
9279
- return {
9280
- text,
9281
- tokens: { input: inputTokens, output: outputTokens },
9282
- latencyMs: Math.round(performance.now() - startedAt),
9283
- model: payload.model ?? this.config.model
9284
- };
9285
- }
9286
- responsesApiUrl() {
9287
- const baseUrl = (this.config.baseUrl ?? OPENAI_RESPONSES_BASE_URL).replace(
9288
- /\/$/,
9289
- ""
9290
- );
9291
- return baseUrl.endsWith("/v1") ? `${baseUrl}/responses` : `${baseUrl}/v1/responses`;
9292
- }
9293
9997
  buildRunRequest(prompt, opts, workspacePath, outputPath) {
9294
9998
  const reasoningEffort = this.config.reasoningEffort ?? DEFAULT_REASONING_EFFORT;
9295
9999
  const args = [
9296
10000
  "exec",
10001
+ "--strict-config",
9297
10002
  "--model",
9298
10003
  this.config.model,
9299
10004
  "--config",
9300
10005
  `model_reasoning_effort=${tomlString(reasoningEffort)}`,
9301
10006
  "--config",
9302
- `service_tier=${tomlString(DEFAULT_SERVICE_TIER)}`,
9303
- "--config",
9304
10007
  'approval_policy="never"',
10008
+ "--config",
10009
+ 'web_search="disabled"',
10010
+ "--disable",
10011
+ "hooks",
10012
+ "--disable",
10013
+ "shell_tool",
10014
+ "--disable",
10015
+ "unified_exec",
10016
+ "--disable",
10017
+ "apps",
10018
+ "--disable",
10019
+ "plugins",
10020
+ "--disable",
10021
+ "remote_plugin",
10022
+ "--disable",
10023
+ "multi_agent",
10024
+ "--disable",
10025
+ "browser_use",
10026
+ "--disable",
10027
+ "browser_use_external",
10028
+ "--disable",
10029
+ "browser_use_full_cdp_access",
10030
+ "--disable",
10031
+ "computer_use",
10032
+ "--disable",
10033
+ "image_generation",
10034
+ "--disable",
10035
+ "in_app_browser",
10036
+ "--disable",
10037
+ "goals",
10038
+ "--disable",
10039
+ "memories",
10040
+ "--disable",
10041
+ "chronicle",
9305
10042
  "--disable",
9306
- "codex_hooks",
10043
+ "tool_suggest",
10044
+ "--disable",
10045
+ "workspace_dependencies",
10046
+ "--disable",
10047
+ "shell_snapshot",
9307
10048
  "--ephemeral",
9308
10049
  "--ignore-user-config",
9309
10050
  "--ignore-rules",
@@ -9312,6 +10053,7 @@ ${result.stdout}`,
9312
10053
  "--cd",
9313
10054
  workspacePath,
9314
10055
  "--skip-git-repo-check",
10056
+ "--json",
9315
10057
  "--output-last-message",
9316
10058
  outputPath,
9317
10059
  "-"
@@ -9324,50 +10066,10 @@ ${result.stdout}`,
9324
10066
  workspacePath,
9325
10067
  timeoutMs: this.config.retryOptions?.timeoutMs,
9326
10068
  signal: opts.signal,
9327
- env: buildIsolatedCodexEnv(this.config.apiKey, this.config.baseUrl)
10069
+ env: buildIsolatedCodexEnv()
9328
10070
  };
9329
10071
  }
9330
10072
  };
9331
- function responsesApiServiceTier(serviceTier) {
9332
- if (serviceTier === "auto" || serviceTier === "default" || serviceTier === "flex" || serviceTier === "scale" || serviceTier === "priority") {
9333
- return serviceTier;
9334
- }
9335
- return void 0;
9336
- }
9337
- function buildResponsesInstructions(systemPrompt) {
9338
- return [
9339
- "You are acting as a benchmark LLM completion endpoint, not as a coding agent.",
9340
- "Use only the user input and the benchmark system instructions.",
9341
- "Do not inspect files, run commands, browse, use tools, or use persisted memory.",
9342
- "Return only the final answer text. If the request asks for JSON, return raw JSON only.",
9343
- ...systemPrompt?.trim() ? ["", systemPrompt.trim()] : []
9344
- ].join("\n");
9345
- }
9346
- async function readResponseErrorBody(response) {
9347
- try {
9348
- const body = await response.text();
9349
- return body.trim().length > 0 ? ` \u2014 ${body.slice(0, 1e3)}` : "";
9350
- } catch {
9351
- return "";
9352
- }
9353
- }
9354
- function extractResponsesOutputText(payload) {
9355
- if (typeof payload.output_text === "string" && payload.output_text.length > 0) {
9356
- return payload.output_text;
9357
- }
9358
- const parts = [];
9359
- for (const item of payload.output ?? []) {
9360
- if (typeof item.text === "string" && item.text.length > 0) {
9361
- parts.push(item.text);
9362
- }
9363
- for (const content of item.content ?? []) {
9364
- if (typeof content.text === "string" && content.text.length > 0 && (content.type === void 0 || content.type.endsWith("_text"))) {
9365
- parts.push(content.text);
9366
- }
9367
- }
9368
- }
9369
- return parts.join("\n");
9370
- }
9371
10073
  function runCodexVersionCommand(executable, env) {
9372
10074
  return new Promise((resolve, reject) => {
9373
10075
  const child = spawn2(executable, ["--version"], {
@@ -9425,6 +10127,58 @@ Codex CLI --version timed out after ${CODEX_CLI_VERSION_TIMEOUT_MS}ms.`
9425
10127
  });
9426
10128
  });
9427
10129
  }
10130
+ function runCodexLoginStatusCommand(executable, env) {
10131
+ return new Promise((resolve, reject) => {
10132
+ const child = spawn2(executable, ["login", "status"], {
10133
+ env,
10134
+ stdio: ["ignore", "pipe", "pipe"],
10135
+ detached: process.platform !== "win32",
10136
+ windowsHide: true
10137
+ });
10138
+ let stdout = "";
10139
+ let stderr = "";
10140
+ let killTimeout;
10141
+ const terminate = (signal) => {
10142
+ if (child.pid && process.platform !== "win32") {
10143
+ try {
10144
+ process.kill(-child.pid, signal);
10145
+ return;
10146
+ } catch {
10147
+ }
10148
+ }
10149
+ child.kill(signal);
10150
+ };
10151
+ const timeout = setTimeout(() => {
10152
+ stderr = appendBounded2(
10153
+ stderr,
10154
+ `
10155
+ Codex CLI login status timed out after ${CODEX_CLI_VERSION_TIMEOUT_MS}ms.`
10156
+ );
10157
+ terminate("SIGTERM");
10158
+ killTimeout = setTimeout(() => terminate("SIGKILL"), 1e3);
10159
+ killTimeout.unref();
10160
+ }, CODEX_CLI_VERSION_TIMEOUT_MS);
10161
+ timeout.unref();
10162
+ child.stdout?.setEncoding("utf8");
10163
+ child.stderr?.setEncoding("utf8");
10164
+ child.stdout?.on("data", (chunk) => {
10165
+ stdout = appendBounded2(stdout, chunk);
10166
+ });
10167
+ child.stderr?.on("data", (chunk) => {
10168
+ stderr = appendBounded2(stderr, chunk);
10169
+ });
10170
+ child.on("error", (error) => {
10171
+ clearTimeout(timeout);
10172
+ if (killTimeout) clearTimeout(killTimeout);
10173
+ reject(error);
10174
+ });
10175
+ child.on("close", (status) => {
10176
+ clearTimeout(timeout);
10177
+ if (killTimeout) clearTimeout(killTimeout);
10178
+ resolve({ status, stdout, stderr });
10179
+ });
10180
+ });
10181
+ }
9428
10182
  function resolveCodexCliExecutable(config) {
9429
10183
  const configured = config.executable ?? process.env[CODEX_CLI_EXECUTABLE_ENV];
9430
10184
  if (configured === void 0) {
@@ -9436,7 +10190,7 @@ function resolveCodexCliExecutable(config) {
9436
10190
  `${CODEX_CLI_EXECUTABLE_ENV} / codex-cli executable must not be empty`
9437
10191
  );
9438
10192
  }
9439
- return expandHomeRelativePath2(trimmed);
10193
+ return expandHomeRelativePath3(trimmed);
9440
10194
  }
9441
10195
  function buildCodexCompletionPrompt(userPrompt, systemPrompt) {
9442
10196
  const payload = {
@@ -9454,21 +10208,13 @@ function buildCodexCompletionPrompt(userPrompt, systemPrompt) {
9454
10208
  JSON.stringify(payload, null, 2)
9455
10209
  ].join("\n");
9456
10210
  }
9457
- function buildIsolatedCodexEnv(apiKey, baseUrl) {
10211
+ function buildIsolatedCodexEnv() {
9458
10212
  const env = {};
9459
10213
  for (const [key, value] of Object.entries(process.env)) {
9460
10214
  if (value !== void 0 && isAllowedCodexRuntimeEnvKey(key)) {
9461
10215
  env[key] = value;
9462
10216
  }
9463
10217
  }
9464
- const resolvedApiKey = (apiKey ?? process.env[OPENAI_API_KEY_ENV] ?? "").trim();
9465
- if (resolvedApiKey.length > 0) {
9466
- env[OPENAI_API_KEY_ENV] = resolvedApiKey;
9467
- }
9468
- const resolvedBaseUrl = (baseUrl ?? process.env[OPENAI_BASE_URL_ENV] ?? "").trim();
9469
- if (resolvedBaseUrl.length > 0) {
9470
- env[OPENAI_BASE_URL_ENV] = resolvedBaseUrl;
9471
- }
9472
10218
  return env;
9473
10219
  }
9474
10220
  function isAllowedCodexRuntimeEnvKey(key) {
@@ -9481,7 +10227,7 @@ async function startCodexCliDiagnostics(args) {
9481
10227
  return void 0;
9482
10228
  }
9483
10229
  try {
9484
- await mkdir5(diagnosticsDir, { recursive: true, mode: 448 });
10230
+ await mkdir6(diagnosticsDir, { recursive: true, mode: 448 });
9485
10231
  const id = `${Date.now()}-${process.pid}-${randomUUID()}`;
9486
10232
  const promptStats = inspectCodexCompletionPrompt(args.request.input);
9487
10233
  const mode = resolveCodexCliDiagnosticsMode(args.config);
@@ -9494,10 +10240,10 @@ async function startCodexCliDiagnostics(args) {
9494
10240
  model: args.config.model,
9495
10241
  reasoningEffort: args.reasoningEffort,
9496
10242
  serviceTier: args.serviceTier,
9497
- executable: path7.basename(args.request.executable),
10243
+ executable: path8.basename(args.request.executable),
9498
10244
  ...args.request.timeoutMs ? { timeoutMs: args.request.timeoutMs } : {},
9499
- workspaceBasename: path7.basename(args.request.workspacePath),
9500
- outputBasename: path7.basename(args.request.outputPath),
10245
+ workspaceBasename: path8.basename(args.request.workspacePath),
10246
+ outputBasename: path8.basename(args.request.outputPath),
9501
10247
  prompt: promptStats,
9502
10248
  command: {
9503
10249
  args: redactCodexCliArgs(args.request.args)
@@ -9505,7 +10251,7 @@ async function startCodexCliDiagnostics(args) {
9505
10251
  retry: args.retry,
9506
10252
  ...mode === "full" ? { fullPrompt: args.request.input } : {}
9507
10253
  };
9508
- const filePath = path7.join(diagnosticsDir, `${id}.json`);
10254
+ const filePath = path8.join(diagnosticsDir, `${id}.json`);
9509
10255
  await writeCodexCliDiagnosticRecord(filePath, record);
9510
10256
  return { path: filePath, record };
9511
10257
  } catch {
@@ -9548,7 +10294,7 @@ async function finishCodexCliDiagnostics(handle, startedAt, outcome) {
9548
10294
  }
9549
10295
  }
9550
10296
  async function writeCodexCliDiagnosticRecord(filePath, record) {
9551
- await writeFile5(filePath, `${JSON.stringify(record, null, 2)}
10297
+ await writeFile6(filePath, `${JSON.stringify(record, null, 2)}
9552
10298
  `, {
9553
10299
  encoding: "utf8",
9554
10300
  mode: 384
@@ -9557,14 +10303,14 @@ async function writeCodexCliDiagnosticRecord(filePath, record) {
9557
10303
  function resolveCodexCliDiagnosticsDir(config) {
9558
10304
  const dir = config.diagnosticsDir ?? process.env[CODEX_CLI_DIAGNOSTICS_DIR_ENV];
9559
10305
  const trimmed = typeof dir === "string" ? dir.trim() : "";
9560
- return trimmed.length > 0 ? path7.resolve(expandHomeRelativePath2(trimmed)) : void 0;
10306
+ return trimmed.length > 0 ? path8.resolve(expandHomeRelativePath3(trimmed)) : void 0;
9561
10307
  }
9562
- function expandHomeRelativePath2(value) {
10308
+ function expandHomeRelativePath3(value) {
9563
10309
  if (value === "~") {
9564
- return os4.homedir();
10310
+ return os5.homedir();
9565
10311
  }
9566
10312
  if (value.startsWith("~/") || value.startsWith("~\\")) {
9567
- return path7.join(os4.homedir(), value.slice(2));
10313
+ return path8.join(os5.homedir(), value.slice(2));
9568
10314
  }
9569
10315
  return value;
9570
10316
  }
@@ -9574,7 +10320,7 @@ function resolveCodexCliDiagnosticsMode(config) {
9574
10320
  }
9575
10321
  function inspectCodexCompletionPrompt(prompt) {
9576
10322
  const stats = {
9577
- sha256: createHash5("sha256").update(prompt).digest("hex"),
10323
+ sha256: createHash6("sha256").update(prompt).digest("hex"),
9578
10324
  chars: prompt.length,
9579
10325
  lines: prompt.length === 0 ? 0 : prompt.split("\n").length
9580
10326
  };
@@ -9614,13 +10360,7 @@ function redactCodexCliArgs(args) {
9614
10360
  function runCodexCliCommand(request) {
9615
10361
  return new Promise((resolve, reject) => {
9616
10362
  if (request.signal?.aborted) {
9617
- resolve({
9618
- status: 124,
9619
- signal: null,
9620
- stdout: "",
9621
- stderr: "Codex CLI aborted before start.",
9622
- outputText: ""
9623
- });
10363
+ reject(codexCliPreStartAbortError(request.signal));
9624
10364
  return;
9625
10365
  }
9626
10366
  const child = spawn2(request.executable, request.args, {
@@ -9704,7 +10444,15 @@ Codex CLI stdin error: ${error.code ?? error.message}`
9704
10444
  unregisterActiveCodexCliChild(child.pid);
9705
10445
  }
9706
10446
  request.signal?.removeEventListener("abort", onAbort);
9707
- reject(error);
10447
+ reject(
10448
+ child.pid ? new Error(
10449
+ `Codex CLI failed after its process started: ${safeErrorMessage2(error)}`,
10450
+ { cause: error }
10451
+ ) : new CodexCreditDispatchError(
10452
+ `Codex CLI could not start: ${safeErrorMessage2(error)}`,
10453
+ { cause: error }
10454
+ )
10455
+ );
9708
10456
  });
9709
10457
  child.on("close", async (status, signal) => {
9710
10458
  if (timeout) {
@@ -9740,10 +10488,17 @@ Codex CLI timed out after ${request.timeoutMs}ms.`
9740
10488
  return;
9741
10489
  }
9742
10490
  try {
9743
- const outputText = await readCodexOutput(request.outputPath, stdout);
10491
+ const outputText = await readCodexOutput(request.outputPath, status);
9744
10492
  resolve({ status, signal, stdout, stderr, outputText });
9745
10493
  } catch (error) {
9746
- reject(error);
10494
+ resolve({
10495
+ status,
10496
+ signal,
10497
+ stdout,
10498
+ stderr: appendBounded2(stderr, `
10499
+ ${safeErrorMessage2(error)}`),
10500
+ outputText: ""
10501
+ });
9747
10502
  }
9748
10503
  });
9749
10504
  try {
@@ -9817,13 +10572,21 @@ function signalExitCode2(signal) {
9817
10572
  return 1;
9818
10573
  }
9819
10574
  }
9820
- async function readCodexOutput(outputPath, stdout) {
10575
+ async function readCodexOutput(outputPath, status) {
9821
10576
  try {
9822
- return await readFile6(outputPath, "utf8");
9823
- } catch {
9824
- return stdout;
10577
+ return await readFile7(outputPath, "utf8");
10578
+ } catch (error) {
10579
+ if (status === 0) {
10580
+ throw new Error(
10581
+ `Codex CLI exited successfully but did not write --output-last-message: ${safeErrorMessage2(error)}`
10582
+ );
10583
+ }
10584
+ return "";
9825
10585
  }
9826
10586
  }
10587
+ function safeErrorMessage2(error) {
10588
+ return error instanceof Error ? error.message : String(error);
10589
+ }
9827
10590
  function appendBounded2(existing, next) {
9828
10591
  const combined = existing + next;
9829
10592
  if (combined.length <= CODEX_CLI_STDIO_LIMIT) {
@@ -9894,64 +10657,118 @@ function codexCliAbortError(signal) {
9894
10657
  }
9895
10658
  return new DOMException("The operation was aborted.", "AbortError");
9896
10659
  }
10660
+ function codexCliPreStartAbortError(signal) {
10661
+ return new CodexCreditDispatchError(CODEX_CLI_PRE_START_ABORT_MESSAGE, {
10662
+ cause: codexCliAbortError(signal)
10663
+ });
10664
+ }
10665
+ function unwrapCodexCliPreStartAbort(error) {
10666
+ return error instanceof CodexCreditDispatchError && error.message === CODEX_CLI_PRE_START_ABORT_MESSAGE && error.cause instanceof Error ? error.cause : error;
10667
+ }
9897
10668
  function summarizeProcessOutput2(stderr, stdout) {
9898
10669
  const summary = [stderr.trim(), stdout.trim()].filter((value) => value.length > 0).join("\n").trim();
9899
10670
  return summary.length > 0 ? summary.slice(-1e3) : "no process output";
9900
10671
  }
9901
- function parseCodexTokenUsage(stderr, outputText) {
9902
- const totalTokens = parseCodexTotalTokens(stderr);
9903
- if (totalTokens === void 0) {
9904
- return { input: 0, output: 0 };
10672
+ function requireCodexJsonlUsage(result) {
10673
+ const usage = parseCodexJsonlUsage(`${result.stdout}
10674
+ ${result.stderr}`);
10675
+ if (!usage) {
10676
+ throw new Error(
10677
+ `Codex CLI completion did not emit a valid turn.completed usage event: ${summarizeProcessOutput2(result.stderr, result.stdout)}`
10678
+ );
9905
10679
  }
9906
- const estimatedOutputTokens = Math.min(
9907
- totalTokens,
9908
- Math.max(1, Math.ceil(outputText.length / 4))
10680
+ return usage;
10681
+ }
10682
+ function readCodexUsage(result, outputText) {
10683
+ const exact = parseCodexJsonlUsage(`${result.stdout}
10684
+ ${result.stderr}`);
10685
+ if (exact) return exact;
10686
+ const legacy = parseCodexTokenUsage(
10687
+ `${result.stderr}
10688
+ ${result.stdout}`,
10689
+ outputText
9909
10690
  );
9910
10691
  return {
9911
- input: totalTokens - estimatedOutputTokens,
9912
- output: estimatedOutputTokens
10692
+ inputTokens: legacy.input,
10693
+ cachedInputTokens: 0,
10694
+ outputTokens: legacy.output,
10695
+ reasoningOutputTokens: 0
9913
10696
  };
9914
10697
  }
9915
- function parseCodexTotalTokens(stderr) {
9916
- const matches = [...stderr.matchAll(/\btokens used\s+([0-9][0-9,]*)\b/gi)];
10698
+ function parseCodexTokenUsage(output, outputText) {
10699
+ const matches = [...output.matchAll(/\btokens used\s+([0-9][0-9,]*)\b/gi)];
9917
10700
  const raw = matches.at(-1)?.[1];
9918
- if (!raw) {
9919
- return void 0;
10701
+ if (!raw) return { input: 0, output: 0 };
10702
+ const totalTokens = Number(raw.replace(/,/g, ""));
10703
+ if (!Number.isSafeInteger(totalTokens) || totalTokens < 0) {
10704
+ return { input: 0, output: 0 };
9920
10705
  }
9921
- const parsed = Number(raw.replace(/,/g, ""));
9922
- return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
10706
+ const outputTokens = Math.min(
10707
+ totalTokens,
10708
+ Math.max(1, Math.ceil(outputText.length / 4))
10709
+ );
10710
+ return { input: totalTokens - outputTokens, output: outputTokens };
10711
+ }
10712
+ function codexCliResultError(result) {
10713
+ const exitLabel = result.signal ? `signal ${result.signal}` : `exit ${result.status ?? "unknown"}`;
10714
+ return new Error(
10715
+ `Codex CLI completion failed (${exitLabel}): ${summarizeProcessOutput2(result.stderr, result.stdout)}`
10716
+ );
9923
10717
  }
9924
10718
  function tomlString(value) {
9925
10719
  return JSON.stringify(value);
9926
10720
  }
10721
+ function buildCodexStructuredJudgePrompt(rubric) {
10722
+ return [
10723
+ rubric,
10724
+ "Return raw JSON only, with exactly these keys:",
10725
+ '{"score":<number from 0 to 1>,"decision":"pass|partial|fail","reason":"non-empty concise reason"}',
10726
+ "Do not wrap the JSON in Markdown or add any other text."
10727
+ ].join("\n\n");
10728
+ }
10729
+ function buildCodexAssistantRubricPrompt(systemPrompt) {
10730
+ return [
10731
+ systemPrompt,
10732
+ "Return raw JSON only, with exactly these keys:",
10733
+ '{"identity_accuracy":<0-5>,"stance_coherence":<0-5>,"novelty":<0-5>,"calibration":<0-5>,"notes":"string"}',
10734
+ "Every numeric value must be finite and within the inclusive range 0 to 5.",
10735
+ "Do not wrap the JSON in Markdown or add any other text."
10736
+ ].join("\n\n");
10737
+ }
10738
+ function isCodexStructuredJudgeAbort(error, signal) {
10739
+ return signal?.aborted === true || error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
10740
+ }
10741
+ function structuredJudgeErrorName(error) {
10742
+ return error instanceof Error && error.name.trim().length > 0 ? error.name : "unknown error";
10743
+ }
9927
10744
  function createCodexCliProvider(config, deps) {
9928
10745
  return new CodexCliProvider(config, deps);
9929
10746
  }
9930
10747
 
9931
10748
  // src/reporter.ts
9932
10749
  import { execSync } from "child_process";
9933
- import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
9934
- import path10 from "path";
10750
+ import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
10751
+ import path11 from "path";
9935
10752
 
9936
10753
  // src/filename-safety.ts
9937
- import path8 from "path";
10754
+ import path9 from "path";
9938
10755
  function sanitizeFilenameSegment(value) {
9939
10756
  const sanitized = value.trim().replace(/[^a-zA-Z0-9._-]/g, "_");
9940
10757
  return sanitized.length > 0 ? sanitized : "unknown";
9941
10758
  }
9942
10759
  function resolveContainedPath(root, ...segments) {
9943
- const outputRoot = path8.resolve(root);
9944
- const filePath = path8.resolve(outputRoot, ...segments);
9945
- const relativePath = path8.relative(outputRoot, filePath);
9946
- if (relativePath === ".." || relativePath.startsWith(`..${path8.sep}`) || path8.isAbsolute(relativePath)) {
10760
+ const outputRoot = path9.resolve(root);
10761
+ const filePath = path9.resolve(outputRoot, ...segments);
10762
+ const relativePath = path9.relative(outputRoot, filePath);
10763
+ if (relativePath === ".." || relativePath.startsWith(`..${path9.sep}`) || path9.isAbsolute(relativePath)) {
9947
10764
  throw new Error(`Refusing to write benchmark artifact outside ${outputRoot}`);
9948
10765
  }
9949
10766
  return filePath;
9950
10767
  }
9951
10768
 
9952
10769
  // src/leaderboard-export.ts
9953
- import { mkdir as mkdir6, writeFile as writeFile6 } from "fs/promises";
9954
- import path9 from "path";
10770
+ import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
10771
+ import path10 from "path";
9955
10772
  async function writeLeaderboardArtifactsForResult(result, outputDir) {
9956
10773
  if (result.meta.benchmark === "ama-bench") {
9957
10774
  return writeAmaBenchLeaderboard(result, outputDir);
@@ -9966,12 +10783,12 @@ async function writeAmaBenchLeaderboard(result, outputDir) {
9966
10783
  if (rows.length === 0) {
9967
10784
  return [];
9968
10785
  }
9969
- const outputRoot = path9.resolve(outputDir);
10786
+ const outputRoot = path10.resolve(outputDir);
9970
10787
  const leaderboardDir = resolveContainedPath(outputRoot, "leaderboard");
9971
- await mkdir6(leaderboardDir, { recursive: true });
10788
+ await mkdir7(leaderboardDir, { recursive: true });
9972
10789
  const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
9973
10790
  const filePath = resolveContainedPath(leaderboardDir, `ama-bench-${timestamp}-answers.jsonl`);
9974
- await writeFile6(filePath, serializeJsonl(rows), "utf8");
10791
+ await writeFile7(filePath, serializeJsonl(rows), "utf8");
9975
10792
  return [
9976
10793
  {
9977
10794
  benchmark: "ama-bench",
@@ -9984,16 +10801,16 @@ async function writeAmaBenchLeaderboard(result, outputDir) {
9984
10801
  async function writeMemCorrectLeaderboard(result, outputDir) {
9985
10802
  const row = buildMemCorrectLeaderboardRow(result);
9986
10803
  if (!row) return [];
9987
- const outputRoot = path9.resolve(outputDir);
10804
+ const outputRoot = path10.resolve(outputDir);
9988
10805
  const leaderboardDir = resolveContainedPath(outputRoot, "leaderboard");
9989
- await mkdir6(leaderboardDir, { recursive: true });
10806
+ await mkdir7(leaderboardDir, { recursive: true });
9990
10807
  const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
9991
10808
  const safeAdapter = sanitizeFilenameSegment(row.adapter);
9992
10809
  const filePath = resolveContainedPath(
9993
10810
  leaderboardDir,
9994
10811
  `memcorrect-${safeAdapter}-${timestamp}.jsonl`
9995
10812
  );
9996
- await writeFile6(filePath, `${JSON.stringify(row)}
10813
+ await writeFile7(filePath, `${JSON.stringify(row)}
9997
10814
  `, "utf8");
9998
10815
  return [
9999
10816
  {
@@ -10352,8 +11169,8 @@ function replaceLoneSurrogates(value) {
10352
11169
  return out;
10353
11170
  }
10354
11171
  async function writeBenchmarkResult(result, outputDir) {
10355
- const outputRoot = path10.resolve(outputDir);
10356
- await mkdir7(outputRoot, { recursive: true });
11172
+ const outputRoot = path11.resolve(outputDir);
11173
+ await mkdir8(outputRoot, { recursive: true });
10357
11174
  const safeBenchmark = sanitizeFilenameSegment(result.meta.benchmark);
10358
11175
  const safeRemnicVersion = sanitizeFilenameSegment(result.meta.remnicVersion);
10359
11176
  const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
@@ -10381,14 +11198,14 @@ async function writeBenchmarkResult(result, outputDir) {
10381
11198
  }
10382
11199
  };
10383
11200
  const publicResult = sanitizeBenchmarkResultForJson(redactBenchmarkResultSecrets(resultWithArtifacts));
10384
- await writeFile7(filePath, `${JSON.stringify(publicResult, null, 2)}
11201
+ await writeFile8(filePath, `${JSON.stringify(publicResult, null, 2)}
10385
11202
  `);
10386
11203
  return filePath;
10387
11204
  }
10388
11205
  async function getRemnicVersion() {
10389
11206
  try {
10390
11207
  const packageJson = JSON.parse(
10391
- await readFile7(path10.resolve(import.meta.dirname, "../../../package.json"), "utf8")
11208
+ await readFile8(path11.resolve(import.meta.dirname, "../../../package.json"), "utf8")
10392
11209
  );
10393
11210
  return typeof packageJson.version === "string" ? packageJson.version : "unknown";
10394
11211
  } catch {
@@ -11641,52 +12458,8 @@ function asStringArray(value) {
11641
12458
  // src/responders.ts
11642
12459
  import { FallbackLlmClient } from "@remnic/core";
11643
12460
 
11644
- // src/judges/memcorrect-rubrics.ts
11645
- var OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION = "openai-responses-bench-v1";
11646
- var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION = "memcorrect-correction-acceptance-v1";
11647
- var MEMCORRECT_STALE_HARM_RUBRIC_VERSION = "memcorrect-stale-memory-harm-v1";
11648
- var GENERAL_ANSWER_JUDGE_RUBRIC = [
11649
- "Grade the predicted benchmark answer against the reference answer.",
11650
- "A score of 1 means fully correct, 0 means fully incorrect, and values between 0 and 1 mean partially correct.",
11651
- "Do not reward unsupported claims. Ignore harmless wording and formatting differences."
11652
- ].join(" ");
11653
- var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC = [
11654
- "Decide whether the memory system accepted the user's correction.",
11655
- "Pass only when the corrected fact is reflected and the retired fact is not asserted as current.",
11656
- "A quotation or correction-history record that clearly marks the retired fact as obsolete is not stale recall.",
11657
- "Use a score of 1 for accepted, 0 for not accepted, and a fractional score only when the evidence is genuinely ambiguous."
11658
- ].join(" ");
11659
- var MEMCORRECT_STALE_HARM_RUBRIC = [
11660
- "Decide whether the memory system avoided stale-memory harm after a correction.",
11661
- "Pass only when the answer does not present the retired fact as current and does not act on it.",
11662
- "Correction provenance may mention the retired fact only when it is explicitly identified as obsolete.",
11663
- "Use a score of 1 when no stale harm is present, 0 when stale information affected the answer, and a fractional score only for genuinely ambiguous evidence."
11664
- ].join(" ");
11665
-
11666
12461
  // src/providers/openai-responses.ts
11667
12462
  var DEFAULT_OPENAI_RESPONSES_JUDGE_MODEL = "gpt-5.6";
11668
- var VERDICT_JSON_SCHEMA = {
11669
- type: "object",
11670
- additionalProperties: false,
11671
- required: ["score", "decision", "reason"],
11672
- properties: {
11673
- score: { type: "number", minimum: 0, maximum: 1 },
11674
- decision: { type: "string", enum: ["pass", "partial", "fail"] },
11675
- reason: { type: "string" }
11676
- }
11677
- };
11678
- var ASSISTANT_RUBRIC_JSON_SCHEMA = {
11679
- type: "object",
11680
- additionalProperties: false,
11681
- required: ["identity_accuracy", "stance_coherence", "novelty", "calibration", "notes"],
11682
- properties: {
11683
- identity_accuracy: { type: "number", minimum: 0, maximum: 5 },
11684
- stance_coherence: { type: "number", minimum: 0, maximum: 5 },
11685
- novelty: { type: "number", minimum: 0, maximum: 5 },
11686
- calibration: { type: "number", minimum: 0, maximum: 5 },
11687
- notes: { type: "string" }
11688
- }
11689
- };
11690
12463
  var OpenAiResponsesJudgeError = class extends Error {
11691
12464
  code;
11692
12465
  retryable;
@@ -11825,7 +12598,7 @@ var OpenAiResponsesProvider = class {
11825
12598
  this.recordTelemetry(failure.telemetry);
11826
12599
  return failure;
11827
12600
  }
11828
- const verdict = parseVerdict(parsed.text);
12601
+ const verdict = parseStructuredJudgeVerdict(parsed.text);
11829
12602
  if (!verdict) {
11830
12603
  const failure = this.failure(
11831
12604
  "malformed_verdict",
@@ -11879,7 +12652,7 @@ var OpenAiResponsesProvider = class {
11879
12652
  this.recordTelemetry(parsed.telemetry);
11880
12653
  throw new OpenAiResponsesJudgeError(parsed);
11881
12654
  }
11882
- if (parsed.text === null || !parseAssistantRubric(parsed.text)) {
12655
+ if (parsed.text === null || !isValidAssistantRubric(parsed.text)) {
11883
12656
  const failure = this.failure(
11884
12657
  "malformed_verdict",
11885
12658
  "OpenAI Responses API returned an invalid sealed assistant-rubric verdict.",
@@ -11901,6 +12674,9 @@ var OpenAiResponsesProvider = class {
11901
12674
  getTelemetryEvents() {
11902
12675
  return this.telemetryEvents.map((event) => ({ ...event }));
11903
12676
  }
12677
+ createJudgeError(failure) {
12678
+ return new OpenAiResponsesJudgeError(failure);
12679
+ }
11904
12680
  async parseResponse(response, startedAt, rubricVersion) {
11905
12681
  let payload;
11906
12682
  try {
@@ -12052,61 +12828,10 @@ function createOpenAiResponsesProvider(config = {}) {
12052
12828
  return new OpenAiResponsesProvider(config);
12053
12829
  }
12054
12830
  function createOpenAiResponsesBenchJudge(config = {}, provider = createOpenAiResponsesProvider(config)) {
12055
- const scoreWithMetrics = async (question, predicted, expected, control) => {
12056
- const result = await provider.judge({
12057
- rubric: GENERAL_ANSWER_JUDGE_RUBRIC,
12058
- rubricVersion: config.rubricVersion ?? OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION,
12059
- input: [
12060
- `QUESTION: ${question}`,
12061
- `REFERENCE_ANSWER: ${expected}`,
12062
- `PREDICTED_ANSWER: ${predicted}`
12063
- ].join("\n\n"),
12064
- signal: control?.signal
12065
- });
12066
- if (!result.ok) throw new OpenAiResponsesJudgeError(result);
12067
- return toBenchJudgeResult(result);
12068
- };
12069
- const scoreBinaryPrompt = async (prompt, control) => {
12070
- const result = await provider.judge({
12071
- rubric: `${GENERAL_ANSWER_JUDGE_RUBRIC} This evaluator is binary: score must be exactly 0 or 1.`,
12072
- rubricVersion: config.rubricVersion ?? OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION,
12073
- input: prompt,
12074
- signal: control?.signal
12075
- });
12076
- if (!result.ok) throw new OpenAiResponsesJudgeError(result);
12077
- if (result.verdict.score !== 0 && result.verdict.score !== 1) {
12078
- const failure = {
12079
- ok: false,
12080
- error: {
12081
- code: "malformed_verdict",
12082
- message: "OpenAI Responses API returned a non-binary verdict for a binary rubric.",
12083
- retryable: false
12084
- },
12085
- telemetry: { ...result.telemetry, errorCode: "malformed_verdict" }
12086
- };
12087
- throw new OpenAiResponsesJudgeError(failure);
12088
- }
12089
- return toBenchJudgeResult(result);
12090
- };
12091
- const judgeSpecialized = async (request, rubric, control) => {
12092
- const result = rubric === "correction" ? await judgeMemCorrectCorrectionAcceptance(provider, serializeMemCorrectJudgeRequest(request), control?.signal) : await judgeMemCorrectStaleMemoryHarm(provider, serializeMemCorrectJudgeRequest(request), control?.signal);
12093
- if (!result.ok) throw new OpenAiResponsesJudgeError(result);
12094
- return {
12095
- ...toBenchJudgeResult(result),
12096
- decision: result.verdict.decision,
12097
- reason: result.verdict.reason,
12098
- rubricVersion: result.telemetry.rubricVersion
12099
- };
12100
- };
12101
- return {
12102
- async score(question, predicted, expected, control) {
12103
- return (await scoreWithMetrics(question, predicted, expected, control)).score;
12104
- },
12105
- scoreWithMetrics,
12106
- scoreBinaryPrompt,
12107
- judgeMemCorrectCorrectionAcceptance: (request, control) => judgeSpecialized(request, "correction", control),
12108
- judgeMemCorrectStaleMemoryHarm: (request, control) => judgeSpecialized(request, "stale_harm", control)
12109
- };
12831
+ return createStructuredBenchJudge(
12832
+ provider,
12833
+ config.rubricVersion ?? OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION
12834
+ );
12110
12835
  }
12111
12836
  async function judgeMemCorrectCorrectionAcceptance(provider, input, signal) {
12112
12837
  return provider.judge({
@@ -12124,17 +12849,6 @@ async function judgeMemCorrectStaleMemoryHarm(provider, input, signal) {
12124
12849
  signal
12125
12850
  });
12126
12851
  }
12127
- function toBenchJudgeResult(result) {
12128
- return {
12129
- score: result.verdict.score,
12130
- tokens: {
12131
- input: result.telemetry.inputTokens,
12132
- output: result.telemetry.outputTokens
12133
- },
12134
- latencyMs: result.telemetry.latencyMs,
12135
- model: result.telemetry.model
12136
- };
12137
- }
12138
12852
  function normalizeModel(model) {
12139
12853
  if (model === void 0) return DEFAULT_OPENAI_RESPONSES_JUDGE_MODEL;
12140
12854
  const trimmed = model.trim();
@@ -12143,54 +12857,6 @@ function normalizeModel(model) {
12143
12857
  }
12144
12858
  return trimmed;
12145
12859
  }
12146
- function parseVerdict(text) {
12147
- let parsed;
12148
- try {
12149
- parsed = JSON.parse(text);
12150
- } catch {
12151
- return null;
12152
- }
12153
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
12154
- const candidate = parsed;
12155
- const keys = Object.keys(candidate).sort();
12156
- if (keys.join(",") !== "decision,reason,score") return null;
12157
- if (typeof candidate.score !== "number" || !Number.isFinite(candidate.score) || candidate.score < 0 || candidate.score > 1 || candidate.decision !== "pass" && candidate.decision !== "partial" && candidate.decision !== "fail" || typeof candidate.reason !== "string" || candidate.reason.trim().length === 0) {
12158
- return null;
12159
- }
12160
- return {
12161
- score: candidate.score,
12162
- decision: candidate.decision,
12163
- reason: candidate.reason.trim()
12164
- };
12165
- }
12166
- function parseAssistantRubric(text) {
12167
- let parsed;
12168
- try {
12169
- parsed = JSON.parse(text);
12170
- } catch {
12171
- return false;
12172
- }
12173
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
12174
- const candidate = parsed;
12175
- const keys = Object.keys(candidate).sort();
12176
- if (keys.join(",") !== "calibration,identity_accuracy,notes,novelty,stance_coherence") return false;
12177
- return ["identity_accuracy", "stance_coherence", "novelty", "calibration"].every(
12178
- (key) => typeof candidate[key] === "number" && Number.isFinite(candidate[key]) && candidate[key] >= 0 && candidate[key] <= 5
12179
- ) && typeof candidate.notes === "string";
12180
- }
12181
- function serializeMemCorrectJudgeRequest(request) {
12182
- return JSON.stringify({
12183
- taskId: request.taskId,
12184
- query: request.query,
12185
- retiredContent: request.retiredContent,
12186
- correctedContent: request.correctedContent,
12187
- evidence: {
12188
- postCorrectionRecall: request.postCorrectionRecall,
12189
- postMaintenanceRecall: request.postMaintenanceRecall,
12190
- postReingestRecall: request.postReingestRecall
12191
- }
12192
- });
12193
- }
12194
12860
  function readOutputText(payload) {
12195
12861
  const text = (payload.output ?? []).flatMap((item) => item.type === "message" ? item.content ?? [] : []).filter((part) => part.type === "output_text").map((part) => part.text ?? "").join("").trim();
12196
12862
  return text.length > 0 ? text : null;
@@ -12715,10 +13381,11 @@ function createJudgeFromProvider(provider) {
12715
13381
  }
12716
13382
  function createProviderBackedJudge(config, providerInstance) {
12717
13383
  validateProviderConfig(config, "judge");
12718
- if (config.provider === "openai" && providerInstance === void 0) {
12719
- return createOpenAiResponsesBenchJudge({ ...config, provider: "openai" });
13384
+ const provider = providerInstance ?? createJudgeProvider(config);
13385
+ if (isStructuredJudgeProvider(provider)) {
13386
+ return createStructuredBenchJudge(provider, config.rubricVersion);
12720
13387
  }
12721
- return createJudgeFromProvider(providerInstance ?? createProvider(config));
13388
+ return createJudgeFromProvider(provider);
12722
13389
  }
12723
13390
  function createAmaBenchRecommendedJudgeFromProvider(provider) {
12724
13391
  async function scoreWithMetrics(question, predicted, expected, control) {
@@ -12771,15 +13438,16 @@ function createStructuredJudgeFromProvider(provider) {
12771
13438
  }
12772
13439
  function createProviderBackedStructuredJudge(config, providerInstance) {
12773
13440
  validateProviderConfig(config, "judge");
12774
- if (config.provider === "openai" && providerInstance === void 0) {
12775
- const provider = createOpenAiResponsesProvider({ ...config, provider: "openai" });
13441
+ const provider = providerInstance ?? createJudgeProvider(config);
13442
+ if (isStructuredJudgeProvider(provider)) {
12776
13443
  return {
12777
13444
  evaluate: (request) => provider.evaluateAssistantRubric(request)
12778
13445
  };
12779
13446
  }
12780
- return createStructuredJudgeFromProvider(
12781
- providerInstance ?? createProvider(config)
12782
- );
13447
+ return createStructuredJudgeFromProvider(provider);
13448
+ }
13449
+ function createJudgeProvider(config) {
13450
+ return config.provider === "openai" ? createOpenAiResponsesProvider({ ...config, provider: "openai" }) : createProvider(config);
12783
13451
  }
12784
13452
  function createGatewayResponder(options) {
12785
13453
  if (!options.gatewayConfig) {
@@ -13052,8 +13720,8 @@ function clampNormalizedScore(value) {
13052
13720
  }
13053
13721
 
13054
13722
  // src/runtime-profiles.ts
13055
- import path11 from "path";
13056
- import { readFile as readFile9 } from "fs/promises";
13723
+ import path12 from "path";
13724
+ import { readFile as readFile10 } from "fs/promises";
13057
13725
  import {
13058
13726
  resolvePluginEntry,
13059
13727
  setCodexCliFallbackRunnerForProcess
@@ -13401,7 +14069,7 @@ function buildPromptSpecificRequirements(prompt) {
13401
14069
  }
13402
14070
 
13403
14071
  // src/local-lab/manifest.ts
13404
- import { readFile as readFile8 } from "fs/promises";
14072
+ import { readFile as readFile9 } from "fs/promises";
13405
14073
  var LOCAL_LAB_PROVIDER_KINDS = [
13406
14074
  "openai-compatible",
13407
14075
  "ollama"
@@ -13438,7 +14106,7 @@ function parseLocalLabManifest(raw) {
13438
14106
  async function loadLocalLabManifest(filePath) {
13439
14107
  let text;
13440
14108
  try {
13441
- text = await readFile8(filePath, "utf8");
14109
+ text = await readFile9(filePath, "utf8");
13442
14110
  } catch (error) {
13443
14111
  const code = error?.code ?? "EUNKNOWN";
13444
14112
  throw new Error(`local-lab manifest at ${filePath} could not be read (${code})`);
@@ -14099,14 +14767,14 @@ async function loadOpenclawRuntimeConfig(filePath) {
14099
14767
  };
14100
14768
  }
14101
14769
  function deriveOpenclawRuntimeContext(configPath) {
14102
- const rootDir = path11.dirname(path11.resolve(configPath));
14770
+ const rootDir = path12.dirname(path12.resolve(configPath));
14103
14771
  return {
14104
- agentDir: path11.join(rootDir, "agents", "main", "agent"),
14105
- workspaceDir: path11.join(rootDir, "workspace")
14772
+ agentDir: path12.join(rootDir, "agents", "main", "agent"),
14773
+ workspaceDir: path12.join(rootDir, "workspace")
14106
14774
  };
14107
14775
  }
14108
14776
  async function loadJsonObject(filePath, label) {
14109
- const raw = await readFile9(filePath, "utf8");
14777
+ const raw = await readFile10(filePath, "utf8");
14110
14778
  let parsed;
14111
14779
  try {
14112
14780
  parsed = JSON.parse(raw);
@@ -14518,20 +15186,20 @@ async function resolveLocalLabRuntimeProfile(options) {
14518
15186
 
14519
15187
  // src/benchmark.ts
14520
15188
  import fs2 from "fs";
14521
- import path34 from "path";
14522
- import { createHash as createHash11 } from "crypto";
15189
+ import path35 from "path";
15190
+ import { createHash as createHash12 } from "crypto";
14523
15191
  import { expandTildePath as expandTildePath3 } from "@remnic/core";
14524
15192
 
14525
15193
  // src/judges/judge-cache.ts
14526
- import { createHash as createHash6, randomBytes as randomBytes2 } from "crypto";
15194
+ import { createHash as createHash7, randomBytes as randomBytes2 } from "crypto";
14527
15195
  import {
14528
- mkdir as mkdir8,
14529
- readFile as readFile10,
14530
- rename as rename2,
15196
+ mkdir as mkdir9,
15197
+ readFile as readFile11,
15198
+ rename as rename3,
14531
15199
  rm as rm4,
14532
- writeFile as writeFile8
15200
+ writeFile as writeFile9
14533
15201
  } from "fs/promises";
14534
- import path12 from "path";
15202
+ import path13 from "path";
14535
15203
  var JUDGE_CACHE_PROTOCOL_VERSION = "judge-protocol-v1";
14536
15204
  function stableStringify2(value) {
14537
15205
  if (Array.isArray(value)) {
@@ -14562,12 +15230,12 @@ var JudgeCache = class {
14562
15230
  inflight = /* @__PURE__ */ new Map();
14563
15231
  cachedDirExists = false;
14564
15232
  constructor(options) {
14565
- this.dir = path12.resolve(options.dir);
15233
+ this.dir = path13.resolve(options.dir);
14566
15234
  }
14567
15235
  /** Compute the sha256-hex key for a set of parts. Pure, sync, side-effect-free. */
14568
15236
  computeKey(parts) {
14569
- const fieldDigest = (value) => createHash6("sha256").update(value).digest();
14570
- return createHash6("sha256").update(fieldDigest(parts.benchmarkId)).update(fieldDigest(parts.datasetVersion)).update(fieldDigest(parts.questionId)).update(fieldDigest(parts.answerText)).update(fieldDigest(parts.judgePromptHash)).update(fieldDigest(parts.judgeModelId)).update(fieldDigest(parts.judgeParamsHash)).digest("hex");
15237
+ const fieldDigest = (value) => createHash7("sha256").update(value).digest();
15238
+ return createHash7("sha256").update(fieldDigest(parts.benchmarkId)).update(fieldDigest(parts.datasetVersion)).update(fieldDigest(parts.questionId)).update(fieldDigest(parts.answerText)).update(fieldDigest(parts.judgePromptHash)).update(fieldDigest(parts.judgeModelId)).update(fieldDigest(parts.judgeParamsHash)).digest("hex");
14571
15239
  }
14572
15240
  /**
14573
15241
  * Read a previously-stored verdict. Returns `undefined` on miss, corrupted
@@ -14587,7 +15255,7 @@ var JudgeCache = class {
14587
15255
  const filePath = this.entryPath(key);
14588
15256
  let raw;
14589
15257
  try {
14590
- raw = await readFile10(filePath, "utf8");
15258
+ raw = await readFile11(filePath, "utf8");
14591
15259
  } catch {
14592
15260
  return void 0;
14593
15261
  }
@@ -14633,25 +15301,25 @@ var JudgeCache = class {
14633
15301
  }
14634
15302
  async writeOne(key, envelope) {
14635
15303
  if (!this.cachedDirExists) {
14636
- await mkdir8(this.dir, { recursive: true });
15304
+ await mkdir9(this.dir, { recursive: true });
14637
15305
  this.cachedDirExists = true;
14638
15306
  }
14639
15307
  const filePath = this.entryPath(key);
14640
- const tempPath = path12.join(
15308
+ const tempPath = path13.join(
14641
15309
  this.dir,
14642
15310
  `.${key}.${randomBytes2(6).toString("hex")}.tmp`
14643
15311
  );
14644
- await writeFile8(tempPath, `${JSON.stringify(envelope)}
15312
+ await writeFile9(tempPath, `${JSON.stringify(envelope)}
14645
15313
  `, "utf8");
14646
15314
  try {
14647
- await rename2(tempPath, filePath);
15315
+ await rename3(tempPath, filePath);
14648
15316
  } catch (error) {
14649
15317
  await rm4(tempPath, { force: true }).catch(() => void 0);
14650
15318
  throw error;
14651
15319
  }
14652
15320
  }
14653
15321
  entryPath(key) {
14654
- return path12.join(this.dir, `${key}.json`);
15322
+ return path13.join(this.dir, `${key}.json`);
14655
15323
  }
14656
15324
  };
14657
15325
  function runJudgeWithCache(options) {
@@ -14762,7 +15430,7 @@ function runJudgeWithCache(options) {
14762
15430
  // Binary prompts are content-sensitive: two distinct prompts of
14763
15431
  // the same character length would collide on the previous
14764
15432
  // `binary:N` key, so key on a sha256 prefix of the prompt body.
14765
- questionId: `binary:${createHash6("sha256").update(prompt).digest("hex").slice(0, 16)}`,
15433
+ questionId: `binary:${createHash7("sha256").update(prompt).digest("hex").slice(0, 16)}`,
14766
15434
  answerText: prompt,
14767
15435
  judgePromptHash: keyExtras.judgePromptHash ?? "unknown-prompt",
14768
15436
  judgeModelId: keyExtras.judgeModelId ?? "unknown-judge",
@@ -14841,8 +15509,8 @@ function isBenchJudgeResult(value) {
14841
15509
 
14842
15510
  // src/benchmarks/published/ama-bench/runner.ts
14843
15511
  import { randomUUID as randomUUID2 } from "crypto";
14844
- import { readFile as readFile11 } from "fs/promises";
14845
- import path13 from "path";
15512
+ import { readFile as readFile12 } from "fs/promises";
15513
+ import path14 from "path";
14846
15514
 
14847
15515
  // src/benchmarks/published/ama-bench/fixture.ts
14848
15516
  var AMA_BENCH_SMOKE_FIXTURE = [
@@ -15417,10 +16085,10 @@ async function loadDataset(mode, datasetDir, limit) {
15417
16085
  return episodes;
15418
16086
  };
15419
16087
  if (datasetDir) {
15420
- const filePath = path13.join(datasetDir, "open_end_qa_set.jsonl");
16088
+ const filePath = path14.join(datasetDir, "open_end_qa_set.jsonl");
15421
16089
  let raw;
15422
16090
  try {
15423
- raw = await readFile11(filePath, "utf8");
16091
+ raw = await readFile12(filePath, "utf8");
15424
16092
  } catch (error) {
15425
16093
  throw new Error(
15426
16094
  `AMA-Bench dataset not found at ${filePath}: ${error instanceof Error ? error.message : String(error)}`
@@ -15712,8 +16380,8 @@ function isValidQaPairs(value) {
15712
16380
 
15713
16381
  // src/benchmarks/published/amemgym/runner.ts
15714
16382
  import { randomUUID as randomUUID3 } from "crypto";
15715
- import { readFile as readFile12 } from "fs/promises";
15716
- import path14 from "path";
16383
+ import { readFile as readFile13 } from "fs/promises";
16384
+ import path15 from "path";
15717
16385
 
15718
16386
  // src/benchmarks/published/amemgym/fixture.ts
15719
16387
  var AMEMGYM_SMOKE_FIXTURE = [
@@ -16242,7 +16910,7 @@ async function loadDataset2(mode, datasetDir, limit) {
16242
16910
  const datasetErrors = [];
16243
16911
  for (const filename of DATASET_FILENAMES) {
16244
16912
  try {
16245
- const raw = await readFile12(path14.join(datasetDir, filename), "utf8");
16913
+ const raw = await readFile13(path15.join(datasetDir, filename), "utf8");
16246
16914
  const parsed = parseDataset(raw, filename, normalizedLimit);
16247
16915
  return ensureDatasetProfiles(parsed);
16248
16916
  } catch (error) {
@@ -16416,8 +17084,8 @@ function normalizeRole(role) {
16416
17084
 
16417
17085
  // src/benchmarks/published/memory-arena/runner.ts
16418
17086
  import { randomUUID as randomUUID4 } from "crypto";
16419
- import { readFile as readFile13, readdir as readdir5, stat as stat3 } from "fs/promises";
16420
- import path15 from "path";
17087
+ import { readFile as readFile14, readdir as readdir5, stat as stat3 } from "fs/promises";
17088
+ import path16 from "path";
16421
17089
  import { expandTildePath as expandTildePath2 } from "@remnic/core";
16422
17090
 
16423
17091
  // src/benchmarks/published/memory-arena/fixture.ts
@@ -16744,7 +17412,7 @@ async function loadDataset3(mode, datasetDir, limit) {
16744
17412
  if (remainingLimit2 === 0) {
16745
17413
  break;
16746
17414
  }
16747
- const raw = await readFile13(path15.join(datasetDir, filename), "utf8");
17415
+ const raw = await readFile14(path16.join(datasetDir, filename), "utf8");
16748
17416
  const parsedTasks = [];
16749
17417
  raw.split("\n").forEach((line, lineIndex) => {
16750
17418
  if (line.trim().length === 0) {
@@ -17080,7 +17748,7 @@ async function loadMemoryArenaWebshopProductCatalog(datasetDir) {
17080
17748
  `MemoryArena WebShop product sidecar is ${sourceStat.size} bytes; provide a compact JSON/JSONL sidecar smaller than ${MEMORY_ARENA_WEBSHOP_PRODUCTS_MAX_BYTES} bytes instead of the full WebShop catalog.`
17081
17749
  );
17082
17750
  }
17083
- const raw = await readFile13(sourcePath, "utf8");
17751
+ const raw = await readFile14(sourcePath, "utf8");
17084
17752
  const records = parseMemoryArenaWebshopSidecarRecords(raw, sourcePath);
17085
17753
  const byAsin = /* @__PURE__ */ new Map();
17086
17754
  for (const record of records) {
@@ -17100,14 +17768,14 @@ async function loadMemoryArenaWebshopProductCatalog(datasetDir) {
17100
17768
  async function resolveMemoryArenaWebshopProductCatalogPath(datasetDir) {
17101
17769
  const configuredPath = process.env[MEMORY_ARENA_WEBSHOP_PRODUCTS_ENV]?.trim();
17102
17770
  if (configuredPath && configuredPath.length > 0) {
17103
- return path15.resolve(expandTildePath2(configuredPath));
17771
+ return path16.resolve(expandTildePath2(configuredPath));
17104
17772
  }
17105
17773
  if (datasetDir === void 0) {
17106
17774
  return void 0;
17107
17775
  }
17108
17776
  const candidatePaths = [
17109
17777
  ...MEMORY_ARENA_WEBSHOP_PRODUCT_SIDECAR_FILENAMES
17110
- ].map((filename) => path15.join(datasetDir, filename));
17778
+ ].map((filename) => path16.join(datasetDir, filename));
17111
17779
  for (const candidatePath of candidatePaths) {
17112
17780
  try {
17113
17781
  const candidateStat = await stat3(candidatePath);
@@ -18529,8 +19197,8 @@ function scoreSubtaskSuccess(scores) {
18529
19197
  import { collectTemporalLexicalCues } from "@remnic/core";
18530
19198
 
18531
19199
  // src/benchmarks/published/dataset-loader.ts
18532
- import { readFile as readFile14 } from "fs/promises";
18533
- import path16 from "path";
19200
+ import { readFile as readFile15 } from "fs/promises";
19201
+ import path17 from "path";
18534
19202
 
18535
19203
  // src/benchmarks/published/longmemeval/fixture.ts
18536
19204
  var LONG_MEM_EVAL_SMOKE_FIXTURE = [
@@ -18633,10 +19301,10 @@ async function loadDataset4(options) {
18633
19301
  const errors = [];
18634
19302
  if (options.datasetDir) {
18635
19303
  for (const filename of options.filenames) {
18636
- const abs = path16.join(options.datasetDir, filename);
19304
+ const abs = path17.join(options.datasetDir, filename);
18637
19305
  let raw;
18638
19306
  try {
18639
- raw = await readFile14(abs, "utf8");
19307
+ raw = await readFile15(abs, "utf8");
18640
19308
  } catch (error) {
18641
19309
  errors.push(
18642
19310
  `${filename}: ${error instanceof Error ? error.message : String(error)}`
@@ -20743,7 +21411,7 @@ function normalizeQaArray(value, location) {
20743
21411
  import { randomUUID as randomUUID6 } from "crypto";
20744
21412
  import { createReadStream as createReadStream2 } from "fs";
20745
21413
  import { readdir as readdir6 } from "fs/promises";
20746
- import path17 from "path";
21414
+ import path18 from "path";
20747
21415
  import { createInterface } from "readline/promises";
20748
21416
  import {
20749
21417
  asyncBufferFromFile,
@@ -21214,8 +21882,8 @@ async function listBeamDatasetFiles(datasetDir) {
21214
21882
  return directFiles;
21215
21883
  }
21216
21884
  try {
21217
- const nestedFilenames = await readdir6(path17.join(datasetDir, "data"));
21218
- return nestedFilenames.filter((filename) => isBeamDatasetFilename(filename)).map((filename) => path17.join("data", filename));
21885
+ const nestedFilenames = await readdir6(path18.join(datasetDir, "data"));
21886
+ return nestedFilenames.filter((filename) => isBeamDatasetFilename(filename)).map((filename) => path18.join("data", filename));
21219
21887
  } catch {
21220
21888
  return [];
21221
21889
  }
@@ -21242,7 +21910,7 @@ async function* iterateDatasetFiles(datasetDir, datasetFiles, limit) {
21242
21910
  let remainingLimit = limit;
21243
21911
  for (const filename of datasetFiles) {
21244
21912
  const scale = inferScaleFromFilename(filename);
21245
- const filePath = path17.join(datasetDir, filename);
21913
+ const filePath = path18.join(datasetDir, filename);
21246
21914
  const conversations = filename.endsWith(".jsonl") ? streamJsonlDataset(filePath, filename, remainingLimit) : filename.endsWith(".parquet") ? streamParquetDataset(filePath, filename, remainingLimit) : streamJsonDataset(filePath, filename, remainingLimit);
21247
21915
  for await (const conversation of conversations) {
21248
21916
  yield {
@@ -22253,9 +22921,9 @@ var StructuredLiteralParser = class {
22253
22921
  };
22254
22922
 
22255
22923
  // src/benchmarks/published/personamem/runner.ts
22256
- import { createHash as createHash7, randomUUID as randomUUID7 } from "crypto";
22257
- import { readFile as readFile15, realpath as realpath4 } from "fs/promises";
22258
- import path18 from "path";
22924
+ import { createHash as createHash8, randomUUID as randomUUID7 } from "crypto";
22925
+ import { readFile as readFile16, realpath as realpath4 } from "fs/promises";
22926
+ import path19 from "path";
22259
22927
 
22260
22928
  // src/benchmarks/published/personamem/fixture.ts
22261
22929
  var PERSONAMEM_SMOKE_FIXTURE = [
@@ -22531,10 +23199,10 @@ async function loadDataset8(mode, datasetDir, limit) {
22531
23199
  if (datasetDir) {
22532
23200
  const datasetErrors = [];
22533
23201
  for (const relativePath of DATASET_FILE_CANDIDATES) {
22534
- const datasetPath = path18.join(datasetDir, relativePath);
23202
+ const datasetPath = path19.join(datasetDir, relativePath);
22535
23203
  let raw;
22536
23204
  try {
22537
- raw = await readFile15(datasetPath, "utf8");
23205
+ raw = await readFile16(datasetPath, "utf8");
22538
23206
  } catch (error) {
22539
23207
  datasetErrors.push(
22540
23208
  `${relativePath}: ${error instanceof Error ? error.message : String(error)}`
@@ -22592,7 +23260,7 @@ async function hydrateSample(row, datasetRoot) {
22592
23260
  datasetRoot,
22593
23261
  row.chat_history_32k_link
22594
23262
  );
22595
- const chatHistoryRaw = await readFile15(chatHistoryPath, "utf8");
23263
+ const chatHistoryRaw = await readFile16(chatHistoryPath, "utf8");
22596
23264
  const chatHistory = parseChatHistory(
22597
23265
  chatHistoryRaw,
22598
23266
  row.chat_history_32k_link
@@ -22725,12 +23393,12 @@ function parseCsv(raw, limit) {
22725
23393
  return rows;
22726
23394
  }
22727
23395
  async function resolveDatasetFilePath(datasetRoot, relativePath) {
22728
- const rootPath = path18.resolve(datasetRoot);
23396
+ const rootPath = path19.resolve(datasetRoot);
22729
23397
  const rootRealPath = await realpath4(rootPath);
22730
- const candidatePath = path18.resolve(rootPath, relativePath);
23398
+ const candidatePath = path19.resolve(rootPath, relativePath);
22731
23399
  const candidateRealPath = await realpath4(candidatePath);
22732
- const relativeToRoot = path18.relative(rootRealPath, candidateRealPath);
22733
- if (relativeToRoot.startsWith("..") || path18.isAbsolute(relativeToRoot)) {
23400
+ const relativeToRoot = path19.relative(rootRealPath, candidateRealPath);
23401
+ if (relativeToRoot.startsWith("..") || path19.isAbsolute(relativeToRoot)) {
22734
23402
  throw new Error(
22735
23403
  `PersonaMem-v2 dataset file reference "${relativePath}" must stay within datasetDir.`
22736
23404
  );
@@ -22858,7 +23526,7 @@ function buildMcqPrompt(sample, seed) {
22858
23526
  function deterministicShuffle(values, seedMaterial) {
22859
23527
  return values.map((value, index) => ({
22860
23528
  value,
22861
- key: createHash7("sha256").update(`${seedMaterial}:${index}:${value}`).digest("hex"),
23529
+ key: createHash8("sha256").update(`${seedMaterial}:${index}:${value}`).digest("hex"),
22862
23530
  index
22863
23531
  })).sort((left, right) => {
22864
23532
  const byKey = left.key.localeCompare(right.key);
@@ -23058,8 +23726,8 @@ function applyLimit6(items, limit) {
23058
23726
 
23059
23727
  // src/benchmarks/published/membench/runner.ts
23060
23728
  import { randomUUID as randomUUID8 } from "crypto";
23061
- import { readFile as readFile16, readdir as readdir7 } from "fs/promises";
23062
- import path19 from "path";
23729
+ import { readFile as readFile17, readdir as readdir7 } from "fs/promises";
23730
+ import path20 from "path";
23063
23731
 
23064
23732
  // src/benchmarks/published/membench/fixture.ts
23065
23733
  var MEMBENCH_SMOKE_FIXTURE = [
@@ -23320,7 +23988,7 @@ async function loadDataset9(mode, datasetDir, limit) {
23320
23988
  let remainingLimit = normalizedLimit;
23321
23989
  for (const filename of filenames) {
23322
23990
  try {
23323
- const raw = await readFile16(path19.join(datasetDir, filename), "utf8");
23991
+ const raw = await readFile17(path20.join(datasetDir, filename), "utf8");
23324
23992
  const parsed = filename.endsWith(".jsonl") ? parseJsonlDataset(raw, filename) : parseJsonDataset(raw, filename);
23325
23993
  const limitedCases = remainingLimit === 0 ? [] : applyLimit7(parsed, remainingLimit);
23326
23994
  if (limitedCases.length > 0) {
@@ -24187,8 +24855,8 @@ function isPlainObject4(value) {
24187
24855
 
24188
24856
  // src/benchmarks/published/memoryagentbench/runner.ts
24189
24857
  import { randomUUID as randomUUID9 } from "crypto";
24190
- import { access, readFile as readFile17 } from "fs/promises";
24191
- import path20 from "path";
24858
+ import { access, readFile as readFile18 } from "fs/promises";
24859
+ import path21 from "path";
24192
24860
 
24193
24861
  // src/benchmarks/published/memoryagentbench/fixture.ts
24194
24862
  var MEMORY_AGENT_BENCH_SMOKE_FIXTURE = [
@@ -25210,7 +25878,7 @@ async function loadRecSysEntityMapping(datasetDir) {
25210
25878
  }
25211
25879
  let parsed;
25212
25880
  try {
25213
- parsed = JSON.parse(await readFile17(candidate, "utf8"));
25881
+ parsed = JSON.parse(await readFile18(candidate, "utf8"));
25214
25882
  } catch (error) {
25215
25883
  console.error(
25216
25884
  ` [WARN] MemoryAgentBench ReDial entity mapping ${candidate} is invalid JSON; trying the next candidate: ${error instanceof Error ? error.message : String(error)}`
@@ -25267,21 +25935,21 @@ function recsysEntityMappingCandidates(datasetDir) {
25267
25935
  if (!datasetDir) {
25268
25936
  return [];
25269
25937
  }
25270
- const absoluteDatasetDir = path20.resolve(datasetDir);
25938
+ const absoluteDatasetDir = path21.resolve(datasetDir);
25271
25939
  const roots = [
25272
25940
  absoluteDatasetDir,
25273
- path20.dirname(absoluteDatasetDir)
25941
+ path21.dirname(absoluteDatasetDir)
25274
25942
  ];
25275
25943
  const canonicalSuffixes = [
25276
- path20.join("processed_data", "Recsys_Redial", "entity2id.json"),
25277
- path20.join("Recsys_Redial", "entity2id.json")
25944
+ path21.join("processed_data", "Recsys_Redial", "entity2id.json"),
25945
+ path21.join("Recsys_Redial", "entity2id.json")
25278
25946
  ];
25279
25947
  const looseSuffixes = ["entity2id.json"];
25280
25948
  return [
25281
25949
  ...roots.flatMap(
25282
- (root) => canonicalSuffixes.map((suffix) => path20.join(root, suffix))
25950
+ (root) => canonicalSuffixes.map((suffix) => path21.join(root, suffix))
25283
25951
  ),
25284
- ...looseSuffixes.map((suffix) => path20.join(absoluteDatasetDir, suffix))
25952
+ ...looseSuffixes.map((suffix) => path21.join(absoluteDatasetDir, suffix))
25285
25953
  ];
25286
25954
  }
25287
25955
  async function fileExists(filePath) {
@@ -25318,7 +25986,7 @@ async function loadDataset10(mode, datasetDir, limit) {
25318
25986
  const datasetErrors = [];
25319
25987
  for (const filename of DATASET_BUNDLE_CANDIDATES) {
25320
25988
  const parsed = await tryReadDatasetFile(
25321
- path20.join(datasetDir, filename),
25989
+ path21.join(datasetDir, filename),
25322
25990
  filename,
25323
25991
  datasetErrors
25324
25992
  );
@@ -25335,7 +26003,7 @@ async function loadDataset10(mode, datasetDir, limit) {
25335
26003
  let splitData;
25336
26004
  for (const filename of splitConfig.candidates) {
25337
26005
  try {
25338
- splitData = await readDatasetFile(path20.join(datasetDir, filename), filename);
26006
+ splitData = await readDatasetFile(path21.join(datasetDir, filename), filename);
25339
26007
  break;
25340
26008
  } catch (error) {
25341
26009
  if (!isFileNotFoundError2(error)) {
@@ -25373,7 +26041,7 @@ async function loadDataset10(mode, datasetDir, limit) {
25373
26041
  return ensureDatasetItems(applyLimit8(MEMORY_AGENT_BENCH_SMOKE_FIXTURE, normalizedLimit));
25374
26042
  }
25375
26043
  async function readDatasetFile(filePath, filename) {
25376
- const raw = await readFile17(filePath, "utf8");
26044
+ const raw = await readFile18(filePath, "utf8");
25377
26045
  const parsed = filename.endsWith(".jsonl") ? parseJsonLines(raw, filename) : parseJsonArray(raw, filename);
25378
26046
  return parsed.map(
25379
26047
  (item, index) => parseMemoryAgentBenchItem(item, `${filename} item ${index + 1}`)
@@ -25983,8 +26651,8 @@ function loadCases(mode, limit) {
25983
26651
 
25984
26652
  // src/benchmarks/remnic/extraction-judge-calibration/runner.ts
25985
26653
  import { randomUUID as randomUUID11 } from "crypto";
25986
- import os5 from "os";
25987
- import path21 from "path";
26654
+ import os6 from "os";
26655
+ import path22 from "path";
25988
26656
  import {
25989
26657
  createVerdictCache,
25990
26658
  judgeFactDurability,
@@ -26094,8 +26762,8 @@ var extractionJudgeCalibrationDefinition = {
26094
26762
  async function runExtractionJudgeCalibrationBenchmark(options) {
26095
26763
  const cases = loadCases2(options.mode, options.limit);
26096
26764
  const config = parseConfig2({
26097
- memoryDir: path21.join(os5.tmpdir(), "remnic-bench-extraction-judge"),
26098
- workspaceDir: path21.join(os5.tmpdir(), "remnic-bench-extraction-judge-workspace"),
26765
+ memoryDir: path22.join(os6.tmpdir(), "remnic-bench-extraction-judge"),
26766
+ workspaceDir: path22.join(os6.tmpdir(), "remnic-bench-extraction-judge-workspace"),
26099
26767
  openaiApiKey: "bench-test-key",
26100
26768
  extractionJudgeEnabled: true,
26101
26769
  extractionJudgeBatchSize: 4,
@@ -26643,8 +27311,8 @@ function constantAggregate2(value) {
26643
27311
  }
26644
27312
 
26645
27313
  // src/benchmarks/remnic/entity-consolidation/runner.ts
26646
- import os6 from "os";
26647
- import path22 from "path";
27314
+ import os7 from "os";
27315
+ import path23 from "path";
26648
27316
  import { randomUUID as randomUUID13 } from "crypto";
26649
27317
  import { mkdtemp as mkdtemp4, rm as rm5 } from "fs/promises";
26650
27318
  import { StorageManager } from "@remnic/core";
@@ -26807,7 +27475,7 @@ function loadCases4(mode, limit) {
26807
27475
  return limited;
26808
27476
  }
26809
27477
  async function executeCase(sample) {
26810
- const tmpDir = await mkdtemp4(path22.join(os6.tmpdir(), "remnic-bench-entity-consolidation-"));
27478
+ const tmpDir = await mkdtemp4(path23.join(os7.tmpdir(), "remnic-bench-entity-consolidation-"));
26811
27479
  try {
26812
27480
  const storage = new StorageManager(tmpDir);
26813
27481
  await storage.ensureDirectories();
@@ -26986,9 +27654,9 @@ function parseNonNegativeInt(rawValue) {
26986
27654
 
26987
27655
  // src/benchmarks/remnic/page-versioning/runner.ts
26988
27656
  import { randomUUID as randomUUID14 } from "crypto";
26989
- import { mkdir as mkdir9, mkdtemp as mkdtemp5, readFile as readFile18, rm as rm6, writeFile as writeFile9 } from "fs/promises";
26990
- import os7 from "os";
26991
- import path23 from "path";
27657
+ import { mkdir as mkdir10, mkdtemp as mkdtemp5, readFile as readFile19, rm as rm6, writeFile as writeFile10 } from "fs/promises";
27658
+ import os8 from "os";
27659
+ import path24 from "path";
26992
27660
  import {
26993
27661
  createVersion,
26994
27662
  diffVersions,
@@ -27152,21 +27820,21 @@ function loadCases5(mode, limit) {
27152
27820
  return limited;
27153
27821
  }
27154
27822
  async function executeCase2(sample, dependencies) {
27155
- const tmpDir = await mkdtemp5(path23.join(os7.tmpdir(), "remnic-bench-page-versioning-"));
27823
+ const tmpDir = await mkdtemp5(path24.join(os8.tmpdir(), "remnic-bench-page-versioning-"));
27156
27824
  try {
27157
- const factsDir = path23.join(tmpDir, "facts");
27158
- const pagePath = path23.join(factsDir, `${sample.id}.md`);
27159
- await mkdir9(factsDir, { recursive: true });
27825
+ const factsDir = path24.join(tmpDir, "facts");
27826
+ const pagePath = path24.join(factsDir, `${sample.id}.md`);
27827
+ await mkdir10(factsDir, { recursive: true });
27160
27828
  const config = versioningConfig();
27161
27829
  switch (sample.scenario) {
27162
27830
  case "revert-flow": {
27163
- await writeFile9(pagePath, "original content", "utf-8");
27831
+ await writeFile10(pagePath, "original content", "utf-8");
27164
27832
  await dependencies.createVersion(pagePath, "original content", "write", config, void 0, void 0, tmpDir);
27165
- await writeFile9(pagePath, "modified content", "utf-8");
27833
+ await writeFile10(pagePath, "modified content", "utf-8");
27166
27834
  await dependencies.createVersion(pagePath, "modified content", "write", config, void 0, void 0, tmpDir);
27167
27835
  await dependencies.revertToVersion(pagePath, "1", config, void 0, tmpDir);
27168
27836
  const history = await dependencies.listVersions(pagePath, config, tmpDir);
27169
- const pageContent = await readFile18(pagePath, "utf-8");
27837
+ const pageContent = await readFile19(pagePath, "utf-8");
27170
27838
  const observed = await dependencies.getVersion(pagePath, "3", config, tmpDir);
27171
27839
  return {
27172
27840
  versionIds: history.versions.map((version) => version.versionId),
@@ -27179,11 +27847,11 @@ async function executeCase2(sample, dependencies) {
27179
27847
  const pruningConfig = versioningConfig({ maxVersionsPerPage: 2 });
27180
27848
  for (let index = 1; index <= 4; index += 1) {
27181
27849
  const content = `content v${index}`;
27182
- await writeFile9(pagePath, content, "utf-8");
27850
+ await writeFile10(pagePath, content, "utf-8");
27183
27851
  await dependencies.createVersion(pagePath, content, "write", pruningConfig, void 0, void 0, tmpDir);
27184
27852
  }
27185
27853
  const history = await dependencies.listVersions(pagePath, pruningConfig, tmpDir);
27186
- const pageContent = await readFile18(pagePath, "utf-8");
27854
+ const pageContent = await readFile19(pagePath, "utf-8");
27187
27855
  const prunedIds = [];
27188
27856
  for (const versionId of ["1", "2"]) {
27189
27857
  try {
@@ -27203,7 +27871,7 @@ async function executeCase2(sample, dependencies) {
27203
27871
  };
27204
27872
  }
27205
27873
  case "diff-output": {
27206
- await writeFile9(pagePath, "line 1\nline 2\nline 3", "utf-8");
27874
+ await writeFile10(pagePath, "line 1\nline 2\nline 3", "utf-8");
27207
27875
  await dependencies.createVersion(
27208
27876
  pagePath,
27209
27877
  "line 1\nline 2\nline 3",
@@ -27213,7 +27881,7 @@ async function executeCase2(sample, dependencies) {
27213
27881
  void 0,
27214
27882
  tmpDir
27215
27883
  );
27216
- await writeFile9(pagePath, "line 1\nline 2 changed\nline 3\nline 4", "utf-8");
27884
+ await writeFile10(pagePath, "line 1\nline 2 changed\nline 3\nline 4", "utf-8");
27217
27885
  await dependencies.createVersion(
27218
27886
  pagePath,
27219
27887
  "line 1\nline 2 changed\nline 3\nline 4",
@@ -27224,7 +27892,7 @@ async function executeCase2(sample, dependencies) {
27224
27892
  tmpDir
27225
27893
  );
27226
27894
  const history = await dependencies.listVersions(pagePath, config, tmpDir);
27227
- const pageContent = await readFile18(pagePath, "utf-8");
27895
+ const pageContent = await readFile19(pagePath, "utf-8");
27228
27896
  const diff = await dependencies.diffVersions(pagePath, "1", "2", config, tmpDir);
27229
27897
  const observedLines = normalizeDiffChangedLines(diff);
27230
27898
  return {
@@ -29510,8 +30178,8 @@ function loadCases9(mode, limit) {
29510
30178
  // src/benchmarks/remnic/procedural-recall/runner.ts
29511
30179
  import { randomUUID as randomUUID21 } from "crypto";
29512
30180
  import { mkdtemp as mkdtemp6, rm as rm7 } from "fs/promises";
29513
- import os8 from "os";
29514
- import path24 from "path";
30181
+ import os9 from "os";
30182
+ import path25 from "path";
29515
30183
  import {
29516
30184
  StorageManager as StorageManager2,
29517
30185
  parseConfig as parseConfig3,
@@ -29641,7 +30309,7 @@ async function runProceduralRecallBenchmark(options) {
29641
30309
  }
29642
30310
  for (const sample of e2eCases) {
29643
30311
  const startedAt = performance.now();
29644
- const dir = await mkdtemp6(path24.join(os8.tmpdir(), "remnic-bench-procedural-recall-"));
30312
+ const dir = await mkdtemp6(path25.join(os9.tmpdir(), "remnic-bench-procedural-recall-"));
29645
30313
  let section = null;
29646
30314
  try {
29647
30315
  const storage = new StorageManager2(dir);
@@ -29656,7 +30324,7 @@ ${body}`,
29656
30324
  );
29657
30325
  const config = parseConfig3({
29658
30326
  memoryDir: dir,
29659
- workspaceDir: path24.join(dir, "ws"),
30327
+ workspaceDir: path25.join(dir, "ws"),
29660
30328
  openaiApiKey: "bench-key",
29661
30329
  procedural: {
29662
30330
  enabled: sample.proceduralEnabled !== false,
@@ -29726,9 +30394,9 @@ ${body}`,
29726
30394
 
29727
30395
  // src/benchmarks/remnic/ingestion-entity-recall/runner.ts
29728
30396
  import { randomUUID as randomUUID22 } from "crypto";
29729
- import { mkdtemp as mkdtemp7, writeFile as writeFile10, rm as rm8, mkdir as mkdir10, realpath as realpath5 } from "fs/promises";
30397
+ import { mkdtemp as mkdtemp7, writeFile as writeFile11, rm as rm8, mkdir as mkdir11, realpath as realpath5 } from "fs/promises";
29730
30398
  import { tmpdir as tmpdir2 } from "os";
29731
- import path25 from "path";
30399
+ import path26 from "path";
29732
30400
 
29733
30401
  // src/ingestion-scorer.ts
29734
30402
  function normalize(value) {
@@ -30230,13 +30898,13 @@ async function runIngestionEntityRecallBenchmark(options) {
30230
30898
  throw new Error("ingestionAdapter is required for ingestion benchmarks");
30231
30899
  }
30232
30900
  const fixture = emailFixture.generate();
30233
- const fixtureDir = await mkdtemp7(path25.join(tmpdir2(), "bench-email-"));
30901
+ const fixtureDir = await mkdtemp7(path26.join(tmpdir2(), "bench-email-"));
30234
30902
  try {
30235
30903
  await options.ingestionAdapter.reset();
30236
30904
  for (const file of fixture.files) {
30237
- const filePath = path25.join(fixtureDir, file.relativePath);
30238
- await mkdir10(path25.dirname(filePath), { recursive: true });
30239
- await writeFile10(filePath, file.content, "utf8");
30905
+ const filePath = path26.join(fixtureDir, file.relativePath);
30906
+ await mkdir11(path26.dirname(filePath), { recursive: true });
30907
+ await writeFile11(filePath, file.content, "utf8");
30240
30908
  }
30241
30909
  const { result: ingestionLog, durationMs } = await timed(
30242
30910
  async () => options.ingestionAdapter.ingest(await realpath5(fixtureDir))
@@ -30363,9 +31031,9 @@ async function buildResult(options, tasks, totalLatencyMs) {
30363
31031
 
30364
31032
  // src/benchmarks/remnic/ingestion-schema-completeness/runner.ts
30365
31033
  import { randomUUID as randomUUID23 } from "crypto";
30366
- import { mkdtemp as mkdtemp8, writeFile as writeFile11, rm as rm9, mkdir as mkdir11, realpath as realpath6 } from "fs/promises";
31034
+ import { mkdtemp as mkdtemp8, writeFile as writeFile12, rm as rm9, mkdir as mkdir12, realpath as realpath6 } from "fs/promises";
30367
31035
  import { tmpdir as tmpdir3 } from "os";
30368
- import path26 from "path";
31036
+ import path27 from "path";
30369
31037
  var ingestionSchemaCompletenessDefinition = {
30370
31038
  id: "ingestion-schema-completeness",
30371
31039
  title: "Ingestion: Schema Completeness",
@@ -30384,13 +31052,13 @@ async function runIngestionSchemaCompletenessBenchmark(options) {
30384
31052
  throw new Error("ingestionAdapter is required for ingestion benchmarks");
30385
31053
  }
30386
31054
  const fixture = emailFixture.generate();
30387
- const fixtureDir = await mkdtemp8(path26.join(tmpdir3(), "bench-email-"));
31055
+ const fixtureDir = await mkdtemp8(path27.join(tmpdir3(), "bench-email-"));
30388
31056
  try {
30389
31057
  await options.ingestionAdapter.reset();
30390
31058
  for (const file of fixture.files) {
30391
- const filePath = path26.join(fixtureDir, file.relativePath);
30392
- await mkdir11(path26.dirname(filePath), { recursive: true });
30393
- await writeFile11(filePath, file.content, "utf8");
31059
+ const filePath = path27.join(fixtureDir, file.relativePath);
31060
+ await mkdir12(path27.dirname(filePath), { recursive: true });
31061
+ await writeFile12(filePath, file.content, "utf8");
30394
31062
  }
30395
31063
  const { result: ingestionLog, durationMs } = await timed(
30396
31064
  async () => options.ingestionAdapter.ingest(await realpath6(fixtureDir))
@@ -30536,9 +31204,9 @@ async function runIngestionSchemaCompletenessBenchmark(options) {
30536
31204
 
30537
31205
  // src/benchmarks/remnic/ingestion-backlink-f1/runner.ts
30538
31206
  import { randomUUID as randomUUID24 } from "crypto";
30539
- import { mkdtemp as mkdtemp9, writeFile as writeFile12, rm as rm10, mkdir as mkdir12, realpath as realpath7 } from "fs/promises";
31207
+ import { mkdtemp as mkdtemp9, writeFile as writeFile13, rm as rm10, mkdir as mkdir13, realpath as realpath7 } from "fs/promises";
30540
31208
  import { tmpdir as tmpdir4 } from "os";
30541
- import path27 from "path";
31209
+ import path28 from "path";
30542
31210
  var ingestionBacklinkF1Definition = {
30543
31211
  id: "ingestion-backlink-f1",
30544
31212
  title: "Ingestion: Backlink F1",
@@ -30557,13 +31225,13 @@ async function runIngestionBacklinkF1Benchmark(options) {
30557
31225
  throw new Error("ingestionAdapter is required for ingestion benchmarks");
30558
31226
  }
30559
31227
  const fixture = emailFixture.generate();
30560
- const fixtureDir = await mkdtemp9(path27.join(tmpdir4(), "bench-email-"));
31228
+ const fixtureDir = await mkdtemp9(path28.join(tmpdir4(), "bench-email-"));
30561
31229
  try {
30562
31230
  await options.ingestionAdapter.reset();
30563
31231
  for (const file of fixture.files) {
30564
- const filePath = path27.join(fixtureDir, file.relativePath);
30565
- await mkdir12(path27.dirname(filePath), { recursive: true });
30566
- await writeFile12(filePath, file.content, "utf8");
31232
+ const filePath = path28.join(fixtureDir, file.relativePath);
31233
+ await mkdir13(path28.dirname(filePath), { recursive: true });
31234
+ await writeFile13(filePath, file.content, "utf8");
30567
31235
  }
30568
31236
  const { result: ingestionLog, durationMs } = await timed(
30569
31237
  async () => options.ingestionAdapter.ingest(await realpath7(fixtureDir))
@@ -30637,9 +31305,9 @@ async function runIngestionBacklinkF1Benchmark(options) {
30637
31305
 
30638
31306
  // src/benchmarks/remnic/ingestion-setup-friction/runner.ts
30639
31307
  import { randomUUID as randomUUID25 } from "crypto";
30640
- import { mkdtemp as mkdtemp10, writeFile as writeFile13, rm as rm11, mkdir as mkdir13, realpath as realpath8 } from "fs/promises";
31308
+ import { mkdtemp as mkdtemp10, writeFile as writeFile14, rm as rm11, mkdir as mkdir14, realpath as realpath8 } from "fs/promises";
30641
31309
  import { tmpdir as tmpdir5 } from "os";
30642
- import path28 from "path";
31310
+ import path29 from "path";
30643
31311
  var INGESTION_SETUP_FRICTION_LOWER_IS_BETTER = /* @__PURE__ */ new Set(["setup_friction", "commands_count", "prompts_count", "errors_count"]);
30644
31312
  var ingestionSetupFrictionDefinition = {
30645
31313
  id: "ingestion-setup-friction",
@@ -30659,13 +31327,13 @@ async function runIngestionSetupFrictionBenchmark(options) {
30659
31327
  throw new Error("ingestionAdapter is required for ingestion benchmarks");
30660
31328
  }
30661
31329
  const fixture = emailFixture.generate();
30662
- const fixtureDir = await mkdtemp10(path28.join(tmpdir5(), "bench-friction-"));
31330
+ const fixtureDir = await mkdtemp10(path29.join(tmpdir5(), "bench-friction-"));
30663
31331
  try {
30664
31332
  await options.ingestionAdapter.reset();
30665
31333
  for (const file of fixture.files) {
30666
- const filePath = path28.join(fixtureDir, file.relativePath);
30667
- await mkdir13(path28.dirname(filePath), { recursive: true });
30668
- await writeFile13(filePath, file.content, "utf8");
31334
+ const filePath = path29.join(fixtureDir, file.relativePath);
31335
+ await mkdir14(path29.dirname(filePath), { recursive: true });
31336
+ await writeFile14(filePath, file.content, "utf8");
30669
31337
  }
30670
31338
  const { result: ingestionLog, durationMs } = await timed(
30671
31339
  async () => options.ingestionAdapter.ingest(await realpath8(fixtureDir))
@@ -30743,9 +31411,9 @@ async function runIngestionSetupFrictionBenchmark(options) {
30743
31411
 
30744
31412
  // src/benchmarks/remnic/ingestion-citation-accuracy/runner.ts
30745
31413
  import { randomUUID as randomUUID26 } from "crypto";
30746
- import { mkdtemp as mkdtemp11, writeFile as writeFile14, rm as rm12, mkdir as mkdir14, realpath as realpath9 } from "fs/promises";
31414
+ import { mkdtemp as mkdtemp11, writeFile as writeFile15, rm as rm12, mkdir as mkdir15, realpath as realpath9 } from "fs/promises";
30747
31415
  import { tmpdir as tmpdir6 } from "os";
30748
- import path29 from "path";
31416
+ import path30 from "path";
30749
31417
  var CITATION_SUPPORT_THRESHOLD = 0.72;
30750
31418
  var ingestionCitationAccuracyDefinition = {
30751
31419
  id: "ingestion-citation-accuracy",
@@ -30804,10 +31472,10 @@ function resolveCitedSources(sourceRefs, seeAlso, pageRef, sourceContentMap) {
30804
31472
  return "";
30805
31473
  }
30806
31474
  for (const ref of normalizedRefs) {
30807
- const refBase = path29.basename(ref).toLowerCase();
31475
+ const refBase = path30.basename(ref).toLowerCase();
30808
31476
  let matched = false;
30809
31477
  for (const [relativePath, content] of sourceContentMap) {
30810
- if (relativePath === ref || relativePath.endsWith(ref) || path29.basename(relativePath).toLowerCase() === refBase) {
31478
+ if (relativePath === ref || relativePath.endsWith(ref) || path30.basename(relativePath).toLowerCase() === refBase) {
30811
31479
  resolved.push(content);
30812
31480
  matched = true;
30813
31481
  break;
@@ -30823,9 +31491,9 @@ function resolveCitedSources(sourceRefs, seeAlso, pageRef, sourceContentMap) {
30823
31491
  if (normalizedRefs.length > 0) {
30824
31492
  return "";
30825
31493
  }
30826
- const pageBase = path29.basename(pageRef).toLowerCase();
31494
+ const pageBase = path30.basename(pageRef).toLowerCase();
30827
31495
  for (const [relativePath, content] of sourceContentMap) {
30828
- if (path29.basename(relativePath).toLowerCase() === pageBase) {
31496
+ if (path30.basename(relativePath).toLowerCase() === pageBase) {
30829
31497
  return content;
30830
31498
  }
30831
31499
  }
@@ -30836,13 +31504,13 @@ async function runIngestionCitationAccuracyBenchmark(options) {
30836
31504
  throw new Error("ingestionAdapter is required for ingestion benchmarks");
30837
31505
  }
30838
31506
  const fixture = emailFixture.generate();
30839
- const fixtureDir = await mkdtemp11(path29.join(tmpdir6(), "bench-citation-"));
31507
+ const fixtureDir = await mkdtemp11(path30.join(tmpdir6(), "bench-citation-"));
30840
31508
  try {
30841
31509
  await options.ingestionAdapter.reset();
30842
31510
  for (const file of fixture.files) {
30843
- const filePath = path29.join(fixtureDir, file.relativePath);
30844
- await mkdir14(path29.dirname(filePath), { recursive: true });
30845
- await writeFile14(filePath, file.content, "utf8");
31511
+ const filePath = path30.join(fixtureDir, file.relativePath);
31512
+ await mkdir15(path30.dirname(filePath), { recursive: true });
31513
+ await writeFile15(filePath, file.content, "utf8");
30846
31514
  }
30847
31515
  const benchmarkStart = performance.now();
30848
31516
  const { result: ingestionLog, durationMs: ingestionDurationMs } = await timed(
@@ -31227,7 +31895,7 @@ var ASSISTANT_MORNING_BRIEF_SMOKE_SCENARIOS = ASSISTANT_MORNING_BRIEF_SCENARIOS.
31227
31895
 
31228
31896
  // src/benchmarks/remnic/_assistant-common/runner.ts
31229
31897
  import { randomUUID as randomUUID27 } from "crypto";
31230
- import path31 from "path";
31898
+ import path32 from "path";
31231
31899
 
31232
31900
  // src/run-seeds.ts
31233
31901
  function buildBenchmarkRunSeeds(runCount, baseSeed) {
@@ -31317,9 +31985,9 @@ function pairedDeltaConfidenceInterval(candidateValues, baselineValues, options
31317
31985
  }
31318
31986
 
31319
31987
  // src/judges/sealed-rubric.ts
31320
- import { createHash as createHash8 } from "crypto";
31988
+ import { createHash as createHash9 } from "crypto";
31321
31989
  import { appendFileSync, mkdirSync } from "fs";
31322
- import path30 from "path";
31990
+ import path31 from "path";
31323
31991
 
31324
31992
  // src/judges/sealed-prompts/assistant-rubric-v1.ts
31325
31993
  var ASSISTANT_RUBRIC_V1 = `# Assistant rubric v1 (sealed)
@@ -31426,7 +32094,7 @@ function loadSealedRubric(id = DEFAULT_ASSISTANT_RUBRIC_ID, options = {}) {
31426
32094
  if (typeof prompt !== "string" || prompt.length === 0) {
31427
32095
  throw new Error(`sealed rubric not found in registry: ${id}`);
31428
32096
  }
31429
- const sha256 = createHash8("sha256").update(prompt, "utf8").digest("hex");
32097
+ const sha256 = createHash9("sha256").update(prompt, "utf8").digest("hex");
31430
32098
  const version = parseVersionFromId(id);
31431
32099
  return { id, version, prompt, sha256 };
31432
32100
  }
@@ -31599,7 +32267,7 @@ function createSpotCheckFileLogger(options) {
31599
32267
  return { log() {
31600
32268
  } };
31601
32269
  }
31602
- const logPath = path30.join(directory, `${runId}.jsonl`);
32270
+ const logPath = path31.join(directory, `${runId}.jsonl`);
31603
32271
  let written = 0;
31604
32272
  let warnedOnWriteFailure = false;
31605
32273
  const cap = typeof sampleSize === "number" && sampleSize > 0 ? sampleSize : 5;
@@ -31688,7 +32356,7 @@ async function runAssistantBenchmark(definition, scenarios, resolved, runnerOpti
31688
32356
  const runId = buildRunId(definition.id);
31689
32357
  const spotCheckLogger = createSpotCheckFileLogger({
31690
32358
  runId,
31691
- directory: runnerOptions.spotCheckDir ?? path31.join(process.cwd(), "benchmarks", "results", "spot-checks"),
32359
+ directory: runnerOptions.spotCheckDir ?? path32.join(process.cwd(), "benchmarks", "results", "spot-checks"),
31692
32360
  sampleRate: 0.35,
31693
32361
  sampleSize: 5
31694
32362
  });
@@ -32337,9 +33005,9 @@ async function runAssistantSynthesisBenchmark(options) {
32337
33005
 
32338
33006
  // src/benchmarks/remnic/buffer-surprise-trigger/runner.ts
32339
33007
  import { randomUUID as randomUUID28 } from "crypto";
32340
- import path32 from "path";
32341
- import os9 from "os";
32342
- import { mkdir as mkdir15, rm as rm13 } from "fs/promises";
33008
+ import path33 from "path";
33009
+ import os10 from "os";
33010
+ import { mkdir as mkdir16, rm as rm13 } from "fs/promises";
32343
33011
  import {
32344
33012
  SmartBuffer,
32345
33013
  computeSurprise,
@@ -32568,11 +33236,11 @@ function hasExplicitTopicPivotCue(text) {
32568
33236
  }
32569
33237
  async function runBufferSurpriseTriggerBenchmark(options) {
32570
33238
  const cases = loadCases10(options.mode, options.limit);
32571
- const tmpRoot = path32.join(
32572
- os9.tmpdir(),
33239
+ const tmpRoot = path33.join(
33240
+ os10.tmpdir(),
32573
33241
  `remnic-bench-buffer-surprise-${randomUUID28()}`
32574
33242
  );
32575
- await mkdir15(tmpRoot, { recursive: true });
33243
+ await mkdir16(tmpRoot, { recursive: true });
32576
33244
  const tasks = [];
32577
33245
  const startedAt = performance.now();
32578
33246
  try {
@@ -32637,12 +33305,12 @@ async function runBufferSurpriseTriggerBenchmark(options) {
32637
33305
  };
32638
33306
  }
32639
33307
  async function runSingleCase(caseDef, options) {
32640
- const memoryDir = path32.join(
33308
+ const memoryDir = path33.join(
32641
33309
  options.tmpRoot,
32642
33310
  `${caseDef.id}-${options.label}`
32643
33311
  );
32644
- const workspaceDir = path32.join(memoryDir, "workspace");
32645
- await mkdir15(workspaceDir, { recursive: true });
33312
+ const workspaceDir = path33.join(memoryDir, "workspace");
33313
+ await mkdir16(workspaceDir, { recursive: true });
32646
33314
  const config = parseConfig4({
32647
33315
  memoryDir,
32648
33316
  workspaceDir,
@@ -33629,7 +34297,7 @@ async function runRetentionAgedDatasetBenchmark(options) {
33629
34297
  import { randomUUID as randomUUID31 } from "crypto";
33630
34298
 
33631
34299
  // src/benchmarks/remnic/memcorrect/generator.ts
33632
- import { createHash as createHash9 } from "crypto";
34300
+ import { createHash as createHash10 } from "crypto";
33633
34301
 
33634
34302
  // src/benchmarks/remnic/memcorrect/token-pools.ts
33635
34303
  var PERSONAS = [
@@ -33953,7 +34621,7 @@ function corpusHash(corpus) {
33953
34621
  uptakeLatencyCap: corpus.options.uptakeLatencyCap,
33954
34622
  scenarios: corpus.scenarios
33955
34623
  });
33956
- return createHash9("sha256").update(canonical).digest("hex");
34624
+ return createHash10("sha256").update(canonical).digest("hex");
33957
34625
  }
33958
34626
 
33959
34627
  // src/benchmarks/remnic/memcorrect/schema.ts
@@ -34904,11 +35572,11 @@ async function runMemCorrectBenchmark(options) {
34904
35572
 
34905
35573
  // src/benchmarks/remnic/bounded-memory-contracts/runner.ts
34906
35574
  import { randomUUID as randomUUID32 } from "crypto";
34907
- import { mkdir as mkdir16, writeFile as writeFile15 } from "fs/promises";
34908
- import path33 from "path";
35575
+ import { mkdir as mkdir17, writeFile as writeFile16 } from "fs/promises";
35576
+ import path34 from "path";
34909
35577
 
34910
35578
  // src/benchmarks/remnic/bounded-memory-contracts/fixture.ts
34911
- import { createHash as createHash10 } from "crypto";
35579
+ import { createHash as createHash11 } from "crypto";
34912
35580
  var SCOPE_ACME = "project:acme";
34913
35581
  var SCOPE_BETA = "project:beta";
34914
35582
  var SCOPE_ALICE = "user:alice";
@@ -35391,7 +36059,7 @@ var BOUNDED_MEMORY_SMOKE_FIXTURE = [
35391
36059
  function fixtureHash(tasks) {
35392
36060
  const source = tasks ?? BOUNDED_MEMORY_FIXTURE;
35393
36061
  const payload = JSON.stringify(source);
35394
- return createHash10("sha256").update(payload, "utf8").digest("hex");
36062
+ return createHash11("sha256").update(payload, "utf8").digest("hex");
35395
36063
  }
35396
36064
 
35397
36065
  // src/benchmarks/remnic/bounded-memory-contracts/agent.ts
@@ -36137,24 +36805,24 @@ async function runBoundedMemoryContractsBenchmark(options) {
36137
36805
  };
36138
36806
  }
36139
36807
  async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks) {
36140
- const root = path33.resolve(outputDir);
36141
- await mkdir16(path33.join(root, "conditions"), { recursive: true });
36142
- await mkdir16(path33.join(root, "prompts"), { recursive: true });
36143
- await mkdir16(path33.join(root, "retrieval"), { recursive: true });
36144
- await mkdir16(path33.join(root, "scores"), { recursive: true });
36808
+ const root = path34.resolve(outputDir);
36809
+ await mkdir17(path34.join(root, "conditions"), { recursive: true });
36810
+ await mkdir17(path34.join(root, "prompts"), { recursive: true });
36811
+ await mkdir17(path34.join(root, "retrieval"), { recursive: true });
36812
+ await mkdir17(path34.join(root, "scores"), { recursive: true });
36145
36813
  const csvRows = [
36146
36814
  "task_id,condition,family,scope,task_success,should_ask_accuracy,relevant_memory_recall,stale_memory_harm_rate,wrong_scope_retrieval_rate,supersession_respected_rate,citation_coverage,memory_tokens_injected,retrieved_item_count,compression_ratio_vs_raw_transcript"
36147
36815
  ];
36148
36816
  for (const condition of BOUNDED_MEMORY_CONDITIONS) {
36149
36817
  const results = byCondition.get(condition);
36150
- const condDir = path33.join(root, "conditions", condition);
36151
- await mkdir16(condDir, { recursive: true });
36818
+ const condDir = path34.join(root, "conditions", condition);
36819
+ await mkdir17(condDir, { recursive: true });
36152
36820
  for (const { task, pack, decision } of results) {
36153
36821
  const scores = scoreTaskPair(task, pack, decision);
36154
36822
  const promptMd = renderPromptPack(task, condition, pack);
36155
- const promptPath = path33.join(root, "prompts", `${task.id}.${condition}.md`);
36156
- await mkdir16(path33.dirname(promptPath), { recursive: true });
36157
- await writeFile15(promptPath, promptMd, "utf8");
36823
+ const promptPath = path34.join(root, "prompts", `${task.id}.${condition}.md`);
36824
+ await mkdir17(path34.dirname(promptPath), { recursive: true });
36825
+ await writeFile16(promptPath, promptMd, "utf8");
36158
36826
  const retrievalJson = `${JSON.stringify(
36159
36827
  {
36160
36828
  taskId: task.id,
@@ -36177,8 +36845,8 @@ async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks
36177
36845
  2
36178
36846
  )}
36179
36847
  `;
36180
- const retrievalPath = path33.join(root, "retrieval", `${task.id}.${condition}.json`);
36181
- await writeFile15(retrievalPath, retrievalJson, "utf8");
36848
+ const retrievalPath = path34.join(root, "retrieval", `${task.id}.${condition}.json`);
36849
+ await writeFile16(retrievalPath, retrievalJson, "utf8");
36182
36850
  csvRows.push(
36183
36851
  [
36184
36852
  task.id,
@@ -36198,24 +36866,24 @@ async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks
36198
36866
  ].join(",")
36199
36867
  );
36200
36868
  }
36201
- await writeFile15(
36202
- path33.join(condDir, "summary.json"),
36869
+ await writeFile16(
36870
+ path34.join(condDir, "summary.json"),
36203
36871
  `${JSON.stringify(conditionAggregates[condition], null, 2)}
36204
36872
  `,
36205
36873
  "utf8"
36206
36874
  );
36207
36875
  }
36208
- await writeFile15(path33.join(root, "scores", "per-task.csv"), `${csvRows.join("\n")}
36876
+ await writeFile16(path34.join(root, "scores", "per-task.csv"), `${csvRows.join("\n")}
36209
36877
  `, "utf8");
36210
- await writeFile15(
36211
- path33.join(root, "scores", "aggregate.json"),
36878
+ await writeFile16(
36879
+ path34.join(root, "scores", "aggregate.json"),
36212
36880
  `${JSON.stringify(conditionAggregates, null, 2)}
36213
36881
  `,
36214
36882
  "utf8"
36215
36883
  );
36216
36884
  const report = renderReportMarkdown(tasks, conditionAggregates);
36217
- await writeFile15(path33.join(root, "report.md"), report, "utf8");
36218
- return path33.join(root, "report.md");
36885
+ await writeFile16(path34.join(root, "report.md"), report, "utf8");
36886
+ return path34.join(root, "report.md");
36219
36887
  }
36220
36888
  function renderPromptPack(task, condition, pack) {
36221
36889
  const lines = [];
@@ -36440,8 +37108,8 @@ function finalizeBenchmarkResultConfig(result, options) {
36440
37108
  }
36441
37109
 
36442
37110
  // src/benchmark.ts
36443
- var DEFAULT_BASELINE_PATH = path34.join(process.cwd(), "benchmarks", "baseline.json");
36444
- var DEFAULT_REPORT_PATH = path34.join(process.cwd(), "benchmarks", "report.json");
37111
+ var DEFAULT_BASELINE_PATH = path35.join(process.cwd(), "benchmarks", "baseline.json");
37112
+ var DEFAULT_REPORT_PATH = path35.join(process.cwd(), "benchmarks", "report.json");
36445
37113
  var BASELINE_VERSION = 1;
36446
37114
  var DEFAULT_TOLERANCE = 10;
36447
37115
  var DEFAULT_FULL_RUN_COUNT = 5;
@@ -36519,7 +37187,7 @@ async function runBenchmark(benchmarkId, options) {
36519
37187
  if (!willWrapPrimary && !willWrapCross) {
36520
37188
  return void 0;
36521
37189
  }
36522
- const cacheDir = options.judgeCacheDir ? path34.resolve(expandTildePath3(options.judgeCacheDir)) : options.outputDir ? path34.join(path34.resolve(expandTildePath3(options.outputDir)), "judge-cache") : void 0;
37190
+ const cacheDir = options.judgeCacheDir ? path35.resolve(expandTildePath3(options.judgeCacheDir)) : options.outputDir ? path35.join(path35.resolve(expandTildePath3(options.outputDir)), "judge-cache") : void 0;
36523
37191
  if (cacheDir === void 0) {
36524
37192
  return void 0;
36525
37193
  }
@@ -36651,13 +37319,13 @@ function wrapJudgeWithCache(args) {
36651
37319
  // differentiator is part of the prompt hash. Bumping
36652
37320
  // JUDGE_CACHE_PROTOCOL_VERSION invalidates verdicts when judge
36653
37321
  // prompt/parse semantics change (PR #1591, High).
36654
- judgePromptHash: createHash11("sha256").update(JUDGE_CACHE_PROTOCOL_VERSION).update("").update(args.amaBenchJudgeProtocol).update("").update(args.role).digest("hex"),
37322
+ judgePromptHash: createHash12("sha256").update(JUDGE_CACHE_PROTOCOL_VERSION).update("").update(args.amaBenchJudgeProtocol).update("").update(args.role).digest("hex"),
36655
37323
  judgeModelId: args.provider?.model !== void 0 && args.provider.model.length > 0 ? `${args.provider.model}${crossJudgeIdSuffix}` : `unknown-${args.role}-judge`,
36656
37324
  // Full judge configuration, deterministically serialized (sorted
36657
37325
  // keys) so provider/base-url/retry changes produce fresh cache
36658
37326
  // keys. `role` is included so primary and cross judges never
36659
37327
  // share a paramsHash.
36660
- judgeParamsHash: createHash11("sha256").update(
37328
+ judgeParamsHash: createHash12("sha256").update(
36661
37329
  stableStringify2({
36662
37330
  role: args.role,
36663
37331
  provider: args.provider
@@ -36718,7 +37386,7 @@ function loadBaseline(baselinePath) {
36718
37386
  return raw;
36719
37387
  }
36720
37388
  function saveBaseline(baselinePath, baseline) {
36721
- fs2.mkdirSync(path34.dirname(baselinePath), { recursive: true });
37389
+ fs2.mkdirSync(path35.dirname(baselinePath), { recursive: true });
36722
37390
  fs2.writeFileSync(baselinePath, `${JSON.stringify(baseline, null, 2)}
36723
37391
  `);
36724
37392
  }
@@ -36948,7 +37616,7 @@ function generateReport(results, reportPath) {
36948
37616
  totalDurationMs: results.reduce((sum, result) => sum + result.totalDurationMs, 0)
36949
37617
  };
36950
37618
  if (reportPath) {
36951
- fs2.mkdirSync(path34.dirname(reportPath), { recursive: true });
37619
+ fs2.mkdirSync(path35.dirname(reportPath), { recursive: true });
36952
37620
  fs2.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}
36953
37621
  `);
36954
37622
  }
@@ -37363,7 +38031,7 @@ function formatSignedScore(value) {
37363
38031
  }
37364
38032
 
37365
38033
  // src/integrity/sealed-qrels.ts
37366
- import { readFile as readFile19 } from "fs/promises";
38034
+ import { readFile as readFile20 } from "fs/promises";
37367
38035
  function isSealedQrelsArtifact(value) {
37368
38036
  if (!value || typeof value !== "object") {
37369
38037
  return false;
@@ -37433,7 +38101,7 @@ function parseSealedQrels(raw, options = {}) {
37433
38101
  };
37434
38102
  }
37435
38103
  async function loadSealedQrels(filePath, options = {}) {
37436
- const raw = await readFile19(filePath, "utf8");
38104
+ const raw = await readFile20(filePath, "utf8");
37437
38105
  return parseSealedQrels(raw, options);
37438
38106
  }
37439
38107
  function serializeSealedQrels(artifact) {
@@ -37553,7 +38221,7 @@ function selectFixtureVariant(variants, seed) {
37553
38221
  }
37554
38222
 
37555
38223
  // src/benchmarks/custom/loader.ts
37556
- import { readFile as readFile20 } from "fs/promises";
38224
+ import { readFile as readFile21 } from "fs/promises";
37557
38225
  import { parse as parseYaml } from "yaml";
37558
38226
  var CUSTOM_SCORING_VALUES = /* @__PURE__ */ new Set([
37559
38227
  "exact_match",
@@ -37573,7 +38241,7 @@ function parseCustomBenchmark(source) {
37573
38241
  async function loadCustomBenchmarkFile(filePath) {
37574
38242
  let source;
37575
38243
  try {
37576
- source = await readFile20(filePath, "utf8");
38244
+ source = await readFile21(filePath, "utf8");
37577
38245
  } catch (error) {
37578
38246
  throw new Error(
37579
38247
  `Failed to read custom benchmark file ${filePath}: ${formatError(error)}`
@@ -37681,7 +38349,7 @@ function formatError(error) {
37681
38349
 
37682
38350
  // src/benchmarks/custom/runner.ts
37683
38351
  import { randomUUID as randomUUID33 } from "crypto";
37684
- import path35 from "path";
38352
+ import path36 from "path";
37685
38353
  import { expandTildePath as expandTildePath4 } from "@remnic/core";
37686
38354
  async function runCustomBenchmarkFile(filePath, options) {
37687
38355
  const spec = await loadCustomBenchmarkFile(filePath);
@@ -37694,7 +38362,7 @@ async function runCustomBenchmarkFile(filePath, options) {
37694
38362
  let cacheRestore;
37695
38363
  let cacheCounters;
37696
38364
  if (spec.scoring === "llm_judge" && runOptions.system.judge !== void 0 && !runOptions.noJudgeCache && (runOptions.judgeProvider ?? null) !== null) {
37697
- const cacheDir = runOptions.judgeCacheDir ? path35.resolve(expandTildePath4(runOptions.judgeCacheDir)) : runOptions.outputDir ? path35.join(path35.resolve(expandTildePath4(runOptions.outputDir)), "judge-cache") : void 0;
38365
+ const cacheDir = runOptions.judgeCacheDir ? path36.resolve(expandTildePath4(runOptions.judgeCacheDir)) : runOptions.outputDir ? path36.join(path36.resolve(expandTildePath4(runOptions.outputDir)), "judge-cache") : void 0;
37698
38366
  if (cacheDir !== void 0) {
37699
38367
  const originalJudge = runOptions.system.judge;
37700
38368
  const wrapped = wrapJudgeWithCache({
@@ -37895,7 +38563,7 @@ async function scoreTask(scoring, options, question, actual, expected) {
37895
38563
  }
37896
38564
  }
37897
38565
  function createCustomBenchmarkDefinition(benchmark, filePath) {
37898
- const id = `custom:${slugify(path35.basename(filePath, path35.extname(filePath)) || benchmark.name)}`;
38566
+ const id = `custom:${slugify(path36.basename(filePath, path36.extname(filePath)) || benchmark.name)}`;
37899
38567
  return {
37900
38568
  id,
37901
38569
  title: benchmark.name,
@@ -38765,9 +39433,9 @@ var chatFixture = {
38765
39433
  };
38766
39434
 
38767
39435
  // src/judges/calibration-slice.ts
38768
- import { createHash as createHash12, randomBytes as randomBytes3 } from "crypto";
38769
- import { mkdir as mkdir17, readFile as readFile21, rename as rename3, unlink as unlink3, writeFile as writeFile16 } from "fs/promises";
38770
- import path36 from "path";
39436
+ import { createHash as createHash13, randomBytes as randomBytes3 } from "crypto";
39437
+ import { mkdir as mkdir18, readFile as readFile22, rename as rename4, unlink as unlink4, writeFile as writeFile17 } from "fs/promises";
39438
+ import path37 from "path";
38771
39439
 
38772
39440
  // src/judges/cohen-kappa.ts
38773
39441
  var DEFAULT_KAPPA_BOOTSTRAP_SAMPLES = 2e3;
@@ -38912,7 +39580,7 @@ function selectCalibrationSlice(questionIds, size = CALIBRATION_SLICE_SIZE) {
38912
39580
  unique.push(id);
38913
39581
  }
38914
39582
  }
38915
- return unique.map((id) => ({ id, digest: createHash12("sha256").update(id, "utf8").digest("hex") })).sort((a, b) => a.digest < b.digest ? -1 : a.digest > b.digest ? 1 : 0).slice(0, Math.min(size, unique.length)).map((entry) => entry.id);
39583
+ return unique.map((id) => ({ id, digest: createHash13("sha256").update(id, "utf8").digest("hex") })).sort((a, b) => a.digest < b.digest ? -1 : a.digest > b.digest ? 1 : 0).slice(0, Math.min(size, unique.length)).map((entry) => entry.id);
38916
39584
  }
38917
39585
  async function runJudgeCalibration(options) {
38918
39586
  const binScore = options.binScore ?? ((score) => binarizeJudgeScore(score));
@@ -38987,7 +39655,7 @@ function validatePinnedQuestionIds(ids, availableIds) {
38987
39655
  return [...ids];
38988
39656
  }
38989
39657
  function hashCalibrationAnswerSet(answers) {
38990
- return createHash12("sha256").update(JSON.stringify(answers.map((answer) => [
39658
+ return createHash13("sha256").update(JSON.stringify(answers.map((answer) => [
38991
39659
  answer.questionId,
38992
39660
  answer.question,
38993
39661
  answer.predicted,
@@ -38995,7 +39663,7 @@ function hashCalibrationAnswerSet(answers) {
38995
39663
  ]))).digest("hex");
38996
39664
  }
38997
39665
  async function writeJudgeCalibrationState(result, calibrationDir, identities, provenance) {
38998
- await mkdir17(calibrationDir, { recursive: true });
39666
+ await mkdir18(calibrationDir, { recursive: true });
38999
39667
  const state = {
39000
39668
  kappa: result.kappa,
39001
39669
  sampleSize: result.sampleSize,
@@ -39008,23 +39676,23 @@ async function writeJudgeCalibrationState(result, calibrationDir, identities, pr
39008
39676
  ...provenance ? provenance : {},
39009
39677
  ...identities ? identities : {}
39010
39678
  };
39011
- const filePath = path36.join(calibrationDir, `${sanitizeCalibrationSegment(result.benchmarkId)}.json`);
39679
+ const filePath = path37.join(calibrationDir, `${sanitizeCalibrationSegment(result.benchmarkId)}.json`);
39012
39680
  const tempPath = `${filePath}.${randomBytes3(6).toString("hex")}.tmp`;
39013
- await writeFile16(tempPath, `${JSON.stringify(state, null, 2)}
39681
+ await writeFile17(tempPath, `${JSON.stringify(state, null, 2)}
39014
39682
  `, "utf8");
39015
39683
  try {
39016
- await rename3(tempPath, filePath);
39684
+ await rename4(tempPath, filePath);
39017
39685
  } catch (error) {
39018
- await unlink3(tempPath).catch(() => void 0);
39686
+ await unlink4(tempPath).catch(() => void 0);
39019
39687
  throw error;
39020
39688
  }
39021
39689
  return filePath;
39022
39690
  }
39023
39691
  async function loadJudgeCalibrationState(benchmarkId, calibrationDir) {
39024
- const filePath = path36.join(calibrationDir, `${sanitizeCalibrationSegment(benchmarkId)}.json`);
39692
+ const filePath = path37.join(calibrationDir, `${sanitizeCalibrationSegment(benchmarkId)}.json`);
39025
39693
  let raw;
39026
39694
  try {
39027
- raw = await readFile21(filePath, "utf8");
39695
+ raw = await readFile22(filePath, "utf8");
39028
39696
  } catch {
39029
39697
  return void 0;
39030
39698
  }
@@ -39108,9 +39776,9 @@ function sanitizeCalibrationSegment(value) {
39108
39776
  }
39109
39777
 
39110
39778
  // src/benchmarks/remnic/procedural-recall/ablation.ts
39111
- import { mkdir as mkdir18, mkdtemp as mkdtemp12, rm as rm14, writeFile as writeFile17, readFile as readFile22 } from "fs/promises";
39112
- import os10 from "os";
39113
- import path37 from "path";
39779
+ import { mkdir as mkdir19, mkdtemp as mkdtemp12, rm as rm14, writeFile as writeFile18, readFile as readFile23 } from "fs/promises";
39780
+ import os11 from "os";
39781
+ import path38 from "path";
39114
39782
  import {
39115
39783
  StorageManager as StorageManager3,
39116
39784
  parseConfig as parseConfig5,
@@ -39141,7 +39809,7 @@ async function runSide(scenarios, proceduralEnabled) {
39141
39809
  const observed = [];
39142
39810
  for (const scenario of scenarios) {
39143
39811
  const dir = await mkdtemp12(
39144
- path37.join(os10.tmpdir(), "remnic-bench-proc-ablation-")
39812
+ path38.join(os11.tmpdir(), "remnic-bench-proc-ablation-")
39145
39813
  );
39146
39814
  try {
39147
39815
  const storage = new StorageManager3(dir);
@@ -39156,7 +39824,7 @@ ${body}`,
39156
39824
  );
39157
39825
  const config = parseConfig5({
39158
39826
  memoryDir: dir,
39159
- workspaceDir: path37.join(dir, "ws"),
39827
+ workspaceDir: path38.join(dir, "ws"),
39160
39828
  openaiApiKey: "bench-key",
39161
39829
  procedural: {
39162
39830
  enabled: proceduralEnabled,
@@ -39231,7 +39899,7 @@ async function runProceduralAblation(options) {
39231
39899
  };
39232
39900
  }
39233
39901
  async function loadAblationFixture(fixturePath) {
39234
- const raw = await readFile22(fixturePath, "utf8");
39902
+ const raw = await readFile23(fixturePath, "utf8");
39235
39903
  let parsed;
39236
39904
  try {
39237
39905
  parsed = JSON.parse(raw);
@@ -39327,9 +39995,9 @@ async function runProceduralAblationCli(args) {
39327
39995
  random: args.random,
39328
39996
  seed: args.seed
39329
39997
  });
39330
- const outDir = path37.dirname(path37.resolve(args.outPath));
39331
- await mkdir18(outDir, { recursive: true });
39332
- await writeFile17(args.outPath, JSON.stringify(artifact, null, 2) + "\n", "utf8");
39998
+ const outDir = path38.dirname(path38.resolve(args.outPath));
39999
+ await mkdir19(outDir, { recursive: true });
40000
+ await writeFile18(args.outPath, JSON.stringify(artifact, null, 2) + "\n", "utf8");
39333
40001
  return artifact;
39334
40002
  }
39335
40003
 
@@ -40443,7 +41111,7 @@ function createMitigatedTarget(config) {
40443
41111
  }
40444
41112
 
40445
41113
  // src/coding-graph/generator.ts
40446
- import { createHash as createHash13 } from "crypto";
41114
+ import { createHash as createHash14 } from "crypto";
40447
41115
  function createSeededRng3(seed) {
40448
41116
  let state = seed >>> 0;
40449
41117
  return function rng() {
@@ -40472,7 +41140,7 @@ var EDGE_TYPE_WEIGHTS = [
40472
41140
  var PROVENANCE_VALUES = ["heuristic", "heuristic", "heuristic", "trace"];
40473
41141
  var AVG_BYTES_PER_LINE = 40;
40474
41142
  function hashContent(input) {
40475
- return createHash13("sha256").update(input).digest("hex").slice(0, 16);
41143
+ return createHash14("sha256").update(input).digest("hex").slice(0, 16);
40476
41144
  }
40477
41145
  function generateSyntheticRepo(config) {
40478
41146
  const rng = createSeededRng3(config.seed);
@@ -40570,8 +41238,8 @@ import { performance as performance2 } from "perf_hooks";
40570
41238
  import { mkdtemp as mkdtemp13, rm as rm15 } from "fs/promises";
40571
41239
  import { statSync } from "fs";
40572
41240
  import { tmpdir as tmpdir7 } from "os";
40573
- import path38 from "path";
40574
- import os11 from "os";
41241
+ import path39 from "path";
41242
+ import os12 from "os";
40575
41243
  import {
40576
41244
  GraphStore
40577
41245
  } from "@remnic/coding-graph";
@@ -40597,14 +41265,14 @@ var CODING_GRAPH_BENCH_SCHEMA_VERSION = 2;
40597
41265
 
40598
41266
  // src/coding-graph/harness.ts
40599
41267
  function captureMachineFingerprint() {
40600
- const cpus = os11.cpus();
41268
+ const cpus = os12.cpus();
40601
41269
  return {
40602
41270
  arch: process.arch,
40603
41271
  platform: process.platform,
40604
41272
  nodeVersion: process.version,
40605
41273
  cpuModel: cpus.length > 0 ? cpus[0].model : null,
40606
41274
  cpuCores: cpus.length,
40607
- totalMemoryMb: Math.round(os11.totalmem() / (1024 * 1024))
41275
+ totalMemoryMb: Math.round(os12.totalmem() / (1024 * 1024))
40608
41276
  };
40609
41277
  }
40610
41278
  function percentile3(sorted, p) {
@@ -40667,15 +41335,15 @@ async function runCodingGraphBenchmark(config = {}) {
40667
41335
  const sampleRss = () => {
40668
41336
  peakRss = Math.max(peakRss, process.memoryUsage().rss);
40669
41337
  };
40670
- const dir = await mkdtemp13(path38.join(tmpdir7(), "coding-graph-bench-"));
40671
- const dbPath = path38.join(dir, "bench.sqlite");
41338
+ const dir = await mkdtemp13(path39.join(tmpdir7(), "coding-graph-bench-"));
41339
+ const dbPath = path39.join(dir, "bench.sqlite");
40672
41340
  try {
40673
41341
  const store = await GraphStore.open({ dbPath });
40674
41342
  try {
40675
41343
  const FULL_INDEX_SAMPLES = 3;
40676
41344
  const fullIndexSamples = [];
40677
41345
  for (let s = 0; s < FULL_INDEX_SAMPLES; s++) {
40678
- const sampleStore = s === 0 ? store : await GraphStore.open({ dbPath: path38.join(dir, `bench-warm-${s}.sqlite`) });
41346
+ const sampleStore = s === 0 ? store : await GraphStore.open({ dbPath: path39.join(dir, `bench-warm-${s}.sqlite`) });
40679
41347
  const fi = await timeAsync(() => sampleStore.upsertFileBatch(storeFiles));
40680
41348
  if (!fi.result.ok) {
40681
41349
  if (sampleStore !== store) await sampleStore.close();
@@ -41067,6 +41735,7 @@ export {
41067
41735
  SEALED_PROMPT_REGISTRY,
41068
41736
  SINGLE_FLAG_ABLATION_MATRIX,
41069
41737
  SYNTHETIC_MEMORIES,
41738
+ StructuredJudgeError,
41070
41739
  ZepMemCorrectAdapter,
41071
41740
  addContaminationEntry,
41072
41741
  aggregateTaskScores,
@@ -41140,6 +41809,7 @@ export {
41140
41809
  createResponderFromProvider,
41141
41810
  createSeededRng,
41142
41811
  createSpotCheckFileLogger,
41812
+ createStructuredBenchJudge,
41143
41813
  createStructuredJudgeFromProvider,
41144
41814
  createSyntheticEmailIngestionAdapter,
41145
41815
  createSyntheticTarget,
@@ -41177,6 +41847,7 @@ export {
41177
41847
  isContaminationManifest,
41178
41848
  isSealedQrelsArtifact,
41179
41849
  isSha256Hex,
41850
+ isStructuredJudgeProvider,
41180
41851
  judgeMemCorrectCorrectionAcceptance,
41181
41852
  judgeMemCorrectStaleMemoryHarm,
41182
41853
  linkMatches,