Ctrl K
ComunidadGuías…

packages/code-indexer/bench/judge-packet.mjs

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env node
// Gauntlet tooling (P1a): build a stratified sample of CALLS edges (proportional
// by lang x confidence tier) with enough source context for an LLM judge to
// verdict them without opening the repo itself. Complements ts-oracle.mjs, which
// only covers TS/JS - this packet is the ground-truth path for Python, Rust, and
// any TS/JS call the LanguageService oracle couldn't resolve.
//
// Each sampled edge gets id = "<head> -> <tail>" - a stable, human-readable key
// that verdicts.json (filled in later by the judge) reuses to join back onto
// edges.jsonl, so no separate packet.json lookup is needed downstream.
//
// Usage: node bench/judge-packet.mjs <repoPath> <edges.jsonl> --sample 60 [--seed 42] --out packet.json
import fs from 'node:fs';
import path from 'node:path';

const HEAD_CAP_LINES = 80;
const TAIL_CAP_LINES = 25;

function parseArgs(argv) {
  const args = { repoPath: null, edgesPath: null, sample: 60, seed: 42, out: 'packet.json' };
  const positional = [];
  for (let i = 0; i < argv.length; i++) {
    const a = argv[i];
    if (a === '--sample') args.sample = Number(argv[++i]);
    else if (a === '--seed') args.seed = Number(argv[++i]);
    else if (a === '--out') args.out = argv[++i];
    else if (a === '--help' || a === '-h') args.help = true;
    else positional.push(a);
  }
  [args.repoPath, args.edgesPath] = positional;
  return args;
}

function usage() {
  console.error('usage: node bench/judge-packet.mjs <repoPath> <edges.jsonl> --sample 60 [--seed 42] --out packet.json');
}

function readJsonl(p) {
  return fs.readFileSync(p, 'utf8').split('\n').filter((l) => l.trim()).map((l) => JSON.parse(l));
}

// mulberry32 - tiny seeded PRNG, deterministic across runs/platforms for a given seed.
function mulberry32(seed) {
  let a = seed >>> 0;
  return function rng() {
    a |= 0; a = (a + 0x6d2b79f5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

function shuffle(arr, rng) {
  const a = arr.slice();
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(rng() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

const tierOf = (confidence) => {
  if (confidence === 1) return '1.0';
  if (confidence === 0.6) return '0.6';
  if (confidence === 0.4) return '0.4';
  return String(confidence);
};

// Proportional allocation across strata with a floor of `min(5, strataSize)` per
// non-empty stratum, then trim/top-up the largest strata to land on the exact
// total sample size.
function allocate(strata, total) {
  const keys = [...strata.keys()];
  const grand = keys.reduce((s, k) => s + strata.get(k).length, 0);
  const alloc = new Map();
  for (const k of keys) {
    const size = strata.get(k).length;
    const floor = Math.min(5, size);
    const proportional = Math.round((total * size) / grand);
    alloc.set(k, Math.max(floor, Math.min(size, proportional)));
  }
  let sum = [...alloc.values()].reduce((a, b) => a + b, 0);
  const bySize = keys.slice().sort((a, b) => strata.get(b).length - strata.get(a).length);
  // Trim excess from the largest strata first, never below the 5-floor.
  for (let i = 0; sum > total && i < bySize.length * 4; i++) {
    const k = bySize[i % bySize.length];
    const floor = Math.min(5, strata.get(k).length);
    if (alloc.get(k) > floor) { alloc.set(k, alloc.get(k) - 1); sum--; }
  }
  // Top up remaining budget into strata that still have room.
  for (let i = 0; sum < total && i < bySize.length * 4; i++) {
    const k = bySize[i % bySize.length];
    if (alloc.get(k) < strata.get(k).length) { alloc.set(k, alloc.get(k) + 1); sum++; }
  }
  return alloc;
}

function readLinesCapped(repoPath, relFile, start, end, cap) {
  if (!relFile || start == null || end == null) return { lines: null, code: null };
  const abs = path.join(repoPath, relFile);
  if (!fs.existsSync(abs)) return { lines: [start, end], code: null };
  const all = fs.readFileSync(abs, 'utf8').split('\n');
  const from = Math.max(0, start - 1);
  const to = Math.min(all.length, end, from + cap);
  const code = all.slice(from, to).join('\n');
  const truncated = to < Math.min(all.length, end);
  return { lines: [start, from + (to - from)], code: truncated ? `${code}\n... (truncated at ${cap} lines)` : code };
}

async function main() {
  const args = parseArgs(process.argv.slice(2));
  if (args.help || !args.repoPath || !args.edgesPath) { usage(); process.exit(args.help ? 0 : 1); }
  const repoPath = path.resolve(args.repoPath);
  if (!fs.existsSync(repoPath)) { console.error(`repoPath does not exist: ${repoPath}`); process.exit(1); }
  if (!fs.existsSync(args.edgesPath)) { console.error(`edges file does not exist: ${args.edgesPath}`); process.exit(1); }

  const edges = readJsonl(args.edgesPath).filter((e) => (e.type ?? 'CALLS') === 'CALLS');
  if (!edges.length) { console.error('judge-packet: no CALLS edges found in input'); process.exit(1); }

  const strata = new Map(); // "lang|tier" -> edges[]
  for (const e of edges) {
    const key = `${e.lang}|${tierOf(e.confidence)}`;
    if (!strata.has(key)) strata.set(key, []);
    strata.get(key).push(e);
  }

  const sampleSize = Math.min(args.sample, edges.length);
  const alloc = allocate(strata, sampleSize);
  const rng = mulberry32(args.seed);

  const sampled = [];
  for (const [key, list] of strata) {
    const n = alloc.get(key) ?? 0;
    const picked = shuffle(list, rng).slice(0, n);
    sampled.push(...picked);
  }

  const packetEdges = sampled.map((e) => {
    const head = readLinesCapped(repoPath, e.headFile, e.headLineStart, e.headLineEnd, HEAD_CAP_LINES);
    // "first 25 lines" of the tail symbol - cap the tail's own end to start+24 before reading.
    const tailEnd = e.tailLineEnd != null && e.tailLineStart != null
      ? Math.min(e.tailLineEnd, e.tailLineStart + TAIL_CAP_LINES - 1)
      : e.tailLineEnd;
    const tail = readLinesCapped(repoPath, e.tailFile, e.tailLineStart, tailEnd, TAIL_CAP_LINES);
    return {
      id: `${e.head} -> ${e.tail}`,
      head: e.head,
      tail: e.tail,
      confidence: e.confidence,
      lang: e.lang,
      headFile: e.headFile,
      headLines: head.lines,
      headCode: head.code,
      tailFile: e.tailFile,
      tailLines: tail.lines,
      tailCode: tail.code,
    };
  });

  const packet = { repo: repoPath, edges: packetEdges };
  fs.writeFileSync(path.resolve(args.out), JSON.stringify(packet, null, 2));

  console.error(`judge-packet: ${edges.length} CALLS edges across ${strata.size} strata (lang x tier), sampled ${packetEdges.length} -> ${args.out}`);
  const summary = {};
  for (const [key, n] of alloc) summary[key] = `${n}/${strata.get(key).length}`;
  console.error(`allocation (sampled/available): ${JSON.stringify(summary)}`);
}

main().catch((e) => { console.error(e.stack || e.message || e); process.exit(1); });