Skip to content

fix: [no-ticket] harbor - ops integrity (exhaust-budget instruction lever, fail-closed ledger restore)#36

Merged
varunursekar merged 11 commits into
harbor-8-honest-signalsfrom
harbor-9-ops
Jul 17, 2026
Merged

fix: [no-ticket] harbor - ops integrity (exhaust-budget instruction lever, fail-closed ledger restore)#36
varunursekar merged 11 commits into
harbor-8-honest-signalsfrom
harbor-9-ops

Conversation

@shehabyasser-scale

@shehabyasser-scale shehabyasser-scale commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #35 (harbor-8-honest-signals). Closes out the pre-paper hardening series (#34 access tiers, #35 honest signals, #36 ops).

Changes

1. instruct_exhaust_budget build-config lever (build/config.py, compiler.py, instruction.md.j2, mirrored into serve.json like instruct_multifidelity). The compiled instruction's "unspent budget is wasted: re-measure your champion or try one more variant" bullet was unconditional; it is now a flag, default on (current behavior byte-for-byte in spirit; the bullet splits from the "scores are noisy" fact, which stays unconditional). Off makes stopping-early the agent's own choice. This is the ablation arm for the persistence experiments: with the exhortation always baked in, there is no way to measure what it contributes to optimizer persistence vs what the optimizer does on its own.

2. Ledger restore fails closed (serve.py). _load_or_build_ledger restored the configured (full) budgets whenever the persisted ledger.json existed but could not be parsed. The persisted ledger exists precisely so a sidecar restart cannot refill spent budget; falling back to full on a parse failure refunds the agent everything already spent, so any crash that corrupts the flush mints budget. Now: a missing file is still a fresh boot (configured budgets), but an unreadable file restores every metered split with zero remaining, preserves the unreadable original as ledger.corrupt for the operator, and logs at error level with the recovery instruction (delete ledger.json deliberately to boot fresh). Admin and finalize paths are unaffected; only agent metering closes.

Tests

  • Instruction lever: default renders the bullet; instruct_exhaust_budget=False omits it while keeping "Scores are noisy".
  • Ledger: missing file boots configured; unparseable file restores zero-remaining and preserves ledger.corrupt byte-for-byte; structurally-malformed JSON entries (KeyError path) also fail closed.
  • 48 passed, 1 skipped (pre-existing) on the affected files.

🤖 Generated with Claude Code

Greptile Summary

This PR closes out the pre-paper hardening series with two focused integrity fixes and several supporting signal improvements.

  • Ledger fail-closed: _load_or_build_ledger now treats an unreadable-but-present ledger.json as fully spent (zeroes all metered budgets) rather than refunding configured budgets, closing the crash-to-budget-refund path. Missing files still boot fresh. The corrupt file is copied to ledger.corrupt as forensic evidence.
  • instruct_exhaust_budget flag: Splits the "Unspent budget is wasted" instruction bullet from the unconditional "Scores are noisy" fact; defaults on (current behavior) and enables an ablation arm that removes the persistence exhortation to measure the optimizer's own stopping behaviour.
  • Supporting changes: per-target executor-model override for transfer probes, infra dead-attempt classification and bounded within-eval retry (off by default, adversarial-candidate warning documented), freebie-baseline race-condition fix (claim before await, refund on BaseException), volume-reuse ordinal resumption, score_semean_score_se rename, and k_anonymity_floor default corrected from 1 → 5.

Confidence Score: 5/5

Safe to merge; all changes harden existing invariants rather than relaxing them.

The ledger fail-closed logic is correct and well-tested (missing, unparseable, and malformed-entry paths all covered). The infra-retry feature is disabled by default with documented adversarial-candidate risks. The freebie race-condition fix correctly uses the claim-before-await / refund-on-exception pattern. The only notable nit is that the error log in _load_or_build_ledger claims the corrupt file is preserved before the copy is attempted, so a disk-full failure would leave an incorrect log trace — but this does not affect the core zeroing logic.

No files require special attention; serve.py has the minor log-ordering nit but the fail-closed behaviour itself is correct.

Important Files Changed

Filename Overview
vero/src/vero/harbor/serve.py Ledger fail-closed logic is correct; log message claims corrupt-file preservation before copy is attempted, which can mislead operators if the copy fails.
vero/src/vero/harbor/server.py Race-condition fix for free baseline (claim before await, refund on BaseException) and volume-reuse ordinal scan are both correct.
vero/src/vero/harbor/runner.py Dead-attempt classification, infra retry (OFF by default, sibling dirs, audit marker), and feedback for no-rewards error samples all look well-guarded.
vero/src/vero/harbor/build/config.py New instruct_exhaust_budget flag and TargetSpec.model field; validation for infra_retry config is thorough.
vero/src/vero/harbor/verifier.py Transfer-target model override, cause string in floored rewards, and dominant-error clustering are all correct; _dominant_sample_errors defensively catches exceptions.
vero/src/vero/evaluation/engine.py model_copy avoids mutating shared run_constraints; per-eval override correctly isolated to the call scope.
vero/src/vero/harbor/config.py infra_retry_rounds and infra_retry_delay_s added with appropriate guards; security implications documented clearly in comments.
vero/tests/test_harbor_serve.py TestLedgerFailClosed covers missing file, unparseable JSON, and malformed entries; all three fail-closed paths are tested.
vero/tests/test_harbor_runner.py TestInfraResilience is comprehensive: infra labeling, forged-suffix neutralization, key-budget alarm, retry default-off, sibling dir isolation, audit markers, multi-round backoff, partial recovery.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[sidecar startup: _load_or_build_ledger] --> B{ledger.json exists?}
    B -- No --> C[Fresh boot: configured budgets\nremaining = total]
    B -- Yes --> D[Parse JSON]
    D -- Success --> E[Restore persisted remaining_* values\nReturn BudgetLedger]
    D -- Fail\njson.JSONDecodeError / KeyError / OSError --> F[logger.error: failing CLOSED]
    F --> G[shutil.copyfile to ledger.corrupt]
    G --> H[Zero out all metered remaining budgets]
    H --> I[Return BudgetLedger - all splits exhausted]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[sidecar startup: _load_or_build_ledger] --> B{ledger.json exists?}
    B -- No --> C[Fresh boot: configured budgets\nremaining = total]
    B -- Yes --> D[Parse JSON]
    D -- Success --> E[Restore persisted remaining_* values\nReturn BudgetLedger]
    D -- Fail\njson.JSONDecodeError / KeyError / OSError --> F[logger.error: failing CLOSED]
    F --> G[shutil.copyfile to ledger.corrupt]
    G --> H[Zero out all metered remaining budgets]
    H --> I[Return BudgetLedger - all splits exhausted]
Loading

Reviews (3): Last reviewed commit: "Merge pull request #37 from scaleapi/har..." | Re-trigger Greptile

shehabyasser-scale and others added 4 commits July 9, 2026 02:36
…fails closed on corrupt restore)

Two operational fixes:

1. instruct_exhaust_budget (default True): the instruction's "unspent
   budget is wasted" persistence bullet becomes a build-config lever,
   like instruct_multifidelity. On preserves current behavior; off makes
   stopping-early the agent's own choice, which is the ablation arm for
   measuring what the exhortation itself contributes to optimizer
   persistence. The "scores are noisy" fact stays unconditional.

2. _load_or_build_ledger fails CLOSED on a persisted ledger that exists
   but cannot be parsed: metered budgets restore with zero remaining,
   and the unreadable file is preserved as ledger.corrupt for the
   operator. The old fallback restored the CONFIGURED budgets, which
   refunded the agent everything already spent, so any crash that
   corrupted the flush minted budget. A missing file is still a fresh
   boot; admin and finalize are unaffected either way.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two Greptile P2s on #30, fixed at the stack tip:

- An empty transcript file no longer surfaces as "" feedback: empty
  candidates are skipped (an empty pane falls through to the
  trajectory), and if everything is empty the search moves to the next
  failed attempt rather than short-circuiting on "".

- The no-verifier-rewards error branch (agent died before scoring) now
  attaches the failure transcript like any failed sample: a candidate
  edit that crashes the agent lands exactly here, and the transcript is
  the only way the optimizer can see the crash it caused.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… floor default, ordinal resume, SE naming)

- Free-baseline flag is claimed BEFORE the eval await and refunded on
  failure: setting it only after success reopened a window where two
  concurrent baseline evals both resolved free (asyncio interleaves at
  await points). Claim-then-refund keeps both properties: concurrent
  callers see the claim, and a failed eval does not burn the freebie.

- build_status defaults k_anonymity_floor to 5, matching the sidecar's
  enforcement default: a caller that forgets to pass the floor must not
  advertise a laxer one than gets enforced.

- _route_results resumes the eval ordinal past surviving __eN dirs on a
  reused volume: a restarted sidecar started back at e1 and silently
  wiped the prior session's evidence, the exact erasure the versioned
  dirs exist to prevent.

- score_se renamed to mean_score_se and documented: it is the SE of the
  zero-filled mean_score over n_samples, not of the n_scored subset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e crash vs infra outage)

Measured live in the transfer matrix: three champions scored 0/72 on an
off-model executor because their optimizers hardcoded temperature=0,
which that provider rejects. The harness handled it safely (rewards
floored, finalize shipped) but the durable record could not say WHY, and
"why" decides opposite actions: a deterministic candidate crash is a
real, reportable portability failure; an infra outage means invalidate
and re-run. Two changes:

- Collation's no-verifier-rewards error string now names the dead
  attempts' exception types ("attempts died: UnsupportedParamsError
  x6"). The error string is the one field that flows to the DB, the
  per-sample files, and the verifier.

- _admin_eval_score returns (score, failure_cause); a floored target's
  target_errors entry carries the dominant per-sample causes (frequency
  summary, top 3). Diagnostics are fail-safe: any surprise result shape
  degrades to a fixed string, never fails finalize.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
shehabyasser-scale and others added 7 commits July 9, 2026 15:25
…ask crashes cluster

Greptile follow-up on #37: _dominant_sample_errors keyed on the raw error
string, which embeds the task name, so identical exceptions across a
multi-task slice landed in 1x singletons instead of one dominant cause.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… finalize

Home-model evals cannot see model-specific couplings the optimizer bakes
in. Measured live in the wave-1 transfer matrix: three of five champions
independently hardcoded temperature=0 (a variance trick on their home
model, gpt-4.1-mini) and scored 0/72 on claude-opus-4-8, which rejects
it, while looking healthy on every eval the optimization loop ever ran.
The portability failure was invisible until a separate, manual,
after-the-fact probe.

VerificationTarget gains `model`: a target with an executor override
scores the selected commit under a model it was NOT optimized on, in the
same finalize battery as its home-model reward. The baseline is scored
under the same override so the comparison stays like-for-like. Plumbing:
build.yaml TargetSpec -> compiler -> serve.json _TargetCfg ->
VerificationTarget -> engine.evaluate_admin(model=...) -> task_params
["harbor_model_override"] -> HarborRunner -m flag. The override rides
task_params, so Mode A ignores it and the runner needs no new state; the
shared run_constraints are copied, never mutated.

Test fakes of evaluate_admin widened to accept the new kwarg (a strict
signature turned the new call into a retried TypeError, flooring
rewards, which is itself a nice demonstration of the floor's fail-safe).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…utage retry, key-budget alarm

Three infra failure modes measured live in the E5 matrix runs, fixed at
the measurement layer:

- Dead attempts are classified infra vs candidate (conservative
  exception-type allowlist + the litellm key-budget message signature).
  Labels flow into dead_exception_types, error strings, and a new
  n_dead_infra metric. Classification never moves a score: every dead
  attempt still zero-fills, or faking infra would excuse failures.
  Exception type names are candidate-authored, so brackets are
  neutralized before labeling (a class named 'XError[infra]' cannot
  walk in pre-suffixed).

- An OPT-IN, bounded, backoff-spaced within-eval retry re-measures
  samples whose every attempt died of a transient infra cause (the
  65-second DNS blip that killed 44/72 attempts of one eval). Off by
  default: against an adversarial optimizer the qualifying predicate is
  a re-roll lever, since a stochastic candidate that raises allowlisted
  exceptions on failing attempts converts all-bad rounds into fresh
  draws. Retry rounds run in fresh sibling jobs dirs (nesting would
  pool dead attempts into later resumed means) and recovered samples
  carry an infra_retry audit marker naming the discarded attempts.

- An ERROR-level alarm names key-budget exhaustion (a spent key fails
  every later call identically; two matrix cells of budget-exceeded
  zeros were nearly booked as a portability finding), with hedged
  wording since the signature reads candidate-process exceptions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d audit history

- HarborConfig rejects infra_retry_delay_s <= 0 when retries are enabled
  (a zero delay silently nullified the backoff) and negative
  infra_retry_rounds.
- The infra_retry audit marker now lists EVERY discarded round in order
  (discarded_rounds), not just the one immediately before recovery;
  recovered_round names when the sample finally measured.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat: [no-ticket] harbor - infra resilience (dead-attempt classification, opt-in outage retry, key-budget alarm)
feat: [no-ticket] harbor - transfer targets (per-target executor-model override at finalize)
fix: [no-ticket] harbor - floored rewards name their cause (candidate crash vs infra outage)
@varunursekar
varunursekar merged commit b29e3ac into harbor-8-honest-signals Jul 17, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants