stablyai/orca · error

resolved values differ for ${baseRef}:\n serial ${JSON.

Error message

resolved values differ for ${baseRef}:\n  serial     ${JSON.stringify(serial)}\n  concurrent ${JSON.stringify(concurrent)}

What it means

Thrown by the branch-compare-head benchmark as a correctness guard: for each baseRef it runs readSerial (the pre-fix serial chain) and readConcurrent (the production concurrent reader readBranchCompareHead) and JSON.stringifies both. A mismatch means the production concurrent path resolves a different compareRef/resolvedBaseRef/headOid/baseOid than the serial reference, i.e. the optimization changed semantics — a real bug, not a benchmark maintenance issue.

Source

Thrown at config/scripts/branch-compare-head-benchmark.mjs:175

console.log('getBranchCompare head-of-chain reads, per call. Lower is better.')
console.log(`iterations=${ITERATIONS} warmup=${WARMUP} rounds=${ROUNDS} (per-arm medians)`)
console.log(
  `${pad('base ref', 30)} ${pad('serial', 11)} ${pad('concurrent', 11)} ${pad('speedup', 9)}`
)

// A short remote label is the common case (Orca's base picker emits `origin/main`); the
// already-qualified ref skips the probe entirely, so only the concurrency half applies.
const upstream = await git(['rev-parse', '--abbrev-ref', 'HEAD@{upstream}']).catch(() => null)
const baseRefs = ['origin/main', 'refs/remotes/origin/main', 'main']
if (upstream && !baseRefs.includes(upstream)) {
  baseRefs.push(upstream)
}

for (const baseRef of baseRefs) {
  const serial = await readSerial(baseRef)
  const concurrent = await readConcurrent(baseRef)
  if (JSON.stringify(serial) !== JSON.stringify(concurrent)) {
    throw new Error(
      `resolved values differ for ${baseRef}:\n  serial     ${JSON.stringify(serial)}\n  concurrent ${JSON.stringify(concurrent)}`
    )
  }
  if (!serial.headOid) {
    throw new Error(`fixture resolved no HEAD oid for ${baseRef}`)
  }
  const { serialMs, concurrentMs } = await measure(baseRef)
  console.log(
    `${pad(baseRef, 30)} ${pad(`${serialMs.toFixed(1)} ms`, 11)} ${pad(`${concurrentMs.toFixed(1)} ms`, 11)} ${pad(`${(serialMs / concurrentMs).toFixed(2)}x`, 9)}`
  )
}

console.log(
  '\nThe already-qualified refs/... row skips the probe by design, so it only shows the\nconcurrency half. This times the native/WSL head-of-chain reads, not the whole compare;\nthe relay path has separate production-concurrency coverage.'
)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Inspect the printed JSON for both arms — the differing field (usually resolvedBaseRef or baseOid) identifies the bug location.
  2. Diff readBranchCompareHead in src/shared/git-branch-compare-head.ts against the serial reference in the benchmark and reconcile the resolution rule.
  3. For annotated-tag refs/remotes/* refs, confirm both arms dereference to the commit oid (^{commit}) consistently.
  4. Add a unit test in the production test suite capturing this baseRef so the divergence cannot recur silently.

Example fix

// before — concurrent arm reuses probe oid for refs/remotes/* (unsafe for annotated tags)
// -> 'resolved values differ for origin/main:\n  serial     {...}\n  concurrent {...}'

// after — only reuse probe oids for refs/heads/* (the optimization's invariant)
// if (candidate.startsWith('refs/heads/')) {
//   reusableProbedOidByRef.set(candidate, oid)
// }
Defensive patterns

Strategy: validation

Validate before calling

function assertArmsAgree(baseRef, serial, concurrent) {
  if (JSON.stringify(serial) !== JSON.stringify(concurrent)) {
    throw new Error(`Serial vs concurrent divergence on ${baseRef} — production readBranchCompareHead changed semantics.\n  serial     ${JSON.stringify(serial)}\n  concurrent ${JSON.stringify(concurrent)}`)
  }
}
// call after both arms resolve, before timing

Prevention

When it happens

Trigger: readBranchCompareHead in src/shared/git-branch-compare-head.ts was edited and now resolves refs differently; the probe-oid reuse optimization (reusableProbedOidByRef) returns the wrong oid for a refs/heads/* ref; the candidate-ordering in resolveBaseRef changed; an annotated-tag handling rule diverged between the two arms.

Common situations: A speed optimization to the head-of-chain reads changed which candidate wins; the serial path was updated but the concurrent path was not (or vice versa); remote-tracking refs that store annotated tags now resolve to a tag oid in one arm but a commit oid in the other.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/75bbc659f7052a54. Report an issue: GitHub.