Skip to content

feat(harbor): feedback levers: failure transcripts, multi-fidelity screening, per-attempt detail#30

Merged
varunursekar merged 28 commits into
harbor-all-fixesfrom
harbor-3-feedback-levers
Jul 17, 2026
Merged

feat(harbor): feedback levers: failure transcripts, multi-fidelity screening, per-attempt detail#30
varunursekar merged 28 commits into
harbor-all-fixesfrom
harbor-3-feedback-levers

Conversation

@shehabyasser-scale

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

Copy link
Copy Markdown
Collaborator

Adds three opt-in feedback levers to Mode B, answering the question this stack kept circling: the optimizer only gets one score per paid eval, which is very thin signal. Each lever is a build.yaml switch, default off, byte-identical behavior when off.

  • feedback_transcripts (+ feedback_max_bytes, default 3000): every FAILED sample of an eval carries the tail of its rollout transcript in the per-sample feedback field. Rides the per-sample result files the sidecar writes ONLY for viewable splits, so it can never surface for non_viewable / no_access tiers.
  • instruct_multifidelity: the compiled instruction teaches subset-eval screening (triage rough ideas cheaply, confirm survivors on the full split). Renders only when a viewable split exists (see leak fix below).
  • expose_attempt_detail: per-sample attempts list with {reward, exception} per attempt, same viewable-only exposure.

The final commit closes what adversarial review found: a multi-fidelity hidden-split leak (1-sample subset evals could recover per-sample labels on non_viewable splits; the instruction is now gated to viewable splits), subset evals polluting the auto_best shortlist (ranking now prefers full-split evals), feedback_max_bytes <= 0 returning the whole transcript (now means "no feedback"), symlink/path-escape containment on transcript reads, typo-safe config keys (extra="forbid"), and attempt-ordering.

Live experimental evidence (2026-07-06). Three arms on the same substrate (the VeRO paper's minimal Pawn agent on gpt-4.1-mini, baseline 0.20, ceiling ~0.43), same optimizer (opus), same 10-eval budget, only the levers differ:

Arm Levers Hidden-split final Optimizer behavior
A multifidelity + attempt detail 0.139 prompt rewording only, flat
B transcripts only 0.194 rewrote agent CODE: file parsing, image support, fixed a binary-read crash it saw in the transcripts
C all three 0.167 code fixes too; subset screening diluted the budget

Transcripts changed the optimizer from prompt-tweaker (which never moves the score; see the campaign doc's 6-model flatness result) into code-fixer, which is where all measured gains come from. n=1 per arm; a replication and a 25-eval run are in flight.

Stacked on the harbor stack (base: harbor-all-fixes, the integration union of the open PRs; will re-target as the stack merges).

🤖 Generated with Claude Code

Greptile Summary

This PR adds three opt-in feedback levers to Mode B Harbor evaluations and closes several adversarially-identified integrity gaps: the free/admin authority conflation (no_access split bypass on the free baseline), the multi-fidelity hidden-split leak, subset evals polluting the auto_best shortlist, and missing path-containment on transcript reads.

  • Feedback levers (feedback_transcripts, expose_attempt_detail, instruct_multifidelity): each is a build.yaml toggle defaulting to off; existing behavior is byte-identical when all three are off, and transcript exposure is gated to viewable splits through the sidecar's existing tier routing.
  • Auth and integrity fixes: engine.evaluate() now distinguishes free (budget-only waiver) from admin (full bypass), closing the no_access escape; _best_from_db prefers full-split evals for shortlisting when any exist; auto_best_baseline_floor prevents shipping regressions; BuildConfig/ServeConfig are split into typed A/B variants with extra=\"forbid\" so a mistyped lever fails loudly at load time rather than silently disabling the feature.

Confidence Score: 5/5

Safe to merge. All three levers default to off, so existing deployments are byte-identical. The integrity fixes are defensive and fail-closed.

The feedback levers are cleanly isolated behind instance-variable flags. The security fixes are narrow, well-tested, and the existing tier routing provides the primary exposure gate independently of the new code. Test coverage for the new levers and verifier ranking changes is thorough.

vero/src/vero/harbor/runner.py — the _read_transcript_tail TOCTOU gap and duplicated feedback_max_bytes default are minor polish items.

Important Files Changed

Filename Overview
vero/src/vero/harbor/runner.py Added three feedback levers: _failure_feedback (transcript tail for failed samples), _attempt_detail (per-attempt reward/exception), and path-containment logic in _read_transcript_tail. Logic is well-guarded; two previously-flagged bugs are noted as fixed upstream.
vero/src/vero/harbor/verifier.py Added auto_best_baseline_floor (reverts to seed when no candidate beats baseline) and subset-eval shortlist filter (full-split evals preferred for ranking). Well-tested.
vero/src/vero/evaluation/engine.py Added free parameter to evaluate() to separate budget-waiver from admin access, and model parameter to evaluate_admin() for transfer-target overrides. Both changes are narrow and well-documented.
vero/src/vero/harbor/build/config.py Split BuildConfig into typed BuildConfigA/BuildConfigB with extra=forbid, preventing mistyped levers from silently no-oping. Backward-compatible.
vero/src/vero/harbor/build/compiler.py _serve_config updated for A/B split; multifidelity template context correctly gates on viewable split existence and EvalRequest field introspection.
vero/src/vero/harbor/serve.py ServeConfig split into ServeConfigA/ServeConfigB. HarborRunner instantiation now passes all three lever flags. Backward-compatible.
vero/src/vero/harbor/server.py Free-baseline handling now passes free=True instead of admin=True, closing the no_access bypass. Versioned eval dirs prevent result erasure on re-measurement.
vero/src/vero/workspace/git.py Added tree_hash() for git rev-parse ^{tree}; used by Verifier._tree_of() to pool re-committed identical trees in auto_best shortlisting.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Agent
    participant Sidecar as EvaluationSidecar
    participant Engine as EvaluationEngine
    participant Runner as HarborRunner
    participant Verifier

    Agent->>Sidecar: POST /eval (commit, split)
    Sidecar->>Sidecar: k-anonymity check (non_viewable subsets)
    Sidecar->>Sidecar: _transfer_commit()
    alt first eval of base_commit (free baseline)
        Sidecar->>Engine: "evaluate(req, free=True)"
        note over Engine: tier gate applies, budget skipped
    else normal agent eval
        Sidecar->>Engine: "evaluate(req, free=False)"
        Engine->>Engine: tier gate (no_access reject)
        Engine->>Engine: budget.reserve()
    end
    Engine->>Runner: produce_sample_results()
    Runner->>Runner: harbor run (nested)
    Runner->>Runner: _collate()
    opt "feedback_transcripts=True and score==0.0"
        Runner->>Runner: _failure_feedback() _read_transcript_tail()
        note over Runner: symlink check + path containment before read
    end
    opt "expose_attempt_detail=True"
        Runner->>Runner: _attempt_detail()
    end
    Sidecar->>Sidecar: _route_results() by split tier
    Sidecar-->>Agent: EvalSummary (aggregate only)

    Note over Verifier: At trial end (finalize)
    Verifier->>Verifier: _best_from_db(): prefer full-split evals
    Verifier->>Engine: evaluate_admin() x rescore_top_k
    opt auto_best_baseline_floor
        Verifier->>Engine: evaluate_admin() baseline
    end
    Verifier->>Engine: evaluate_admin() x targets
    Verifier-->>Agent: reward.json
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"}}}%%
sequenceDiagram
    participant Agent
    participant Sidecar as EvaluationSidecar
    participant Engine as EvaluationEngine
    participant Runner as HarborRunner
    participant Verifier

    Agent->>Sidecar: POST /eval (commit, split)
    Sidecar->>Sidecar: k-anonymity check (non_viewable subsets)
    Sidecar->>Sidecar: _transfer_commit()
    alt first eval of base_commit (free baseline)
        Sidecar->>Engine: "evaluate(req, free=True)"
        note over Engine: tier gate applies, budget skipped
    else normal agent eval
        Sidecar->>Engine: "evaluate(req, free=False)"
        Engine->>Engine: tier gate (no_access reject)
        Engine->>Engine: budget.reserve()
    end
    Engine->>Runner: produce_sample_results()
    Runner->>Runner: harbor run (nested)
    Runner->>Runner: _collate()
    opt "feedback_transcripts=True and score==0.0"
        Runner->>Runner: _failure_feedback() _read_transcript_tail()
        note over Runner: symlink check + path containment before read
    end
    opt "expose_attempt_detail=True"
        Runner->>Runner: _attempt_detail()
    end
    Sidecar->>Sidecar: _route_results() by split tier
    Sidecar-->>Agent: EvalSummary (aggregate only)

    Note over Verifier: At trial end (finalize)
    Verifier->>Verifier: _best_from_db(): prefer full-split evals
    Verifier->>Engine: evaluate_admin() x rescore_top_k
    opt auto_best_baseline_floor
        Verifier->>Engine: evaluate_admin() baseline
    end
    Verifier->>Engine: evaluate_admin() x targets
    Verifier-->>Agent: reward.json
Loading

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

shehabyasser-scale and others added 5 commits July 5, 2026 13:23
…ck_transcripts)

When enabled, collation attaches the last feedback_max_bytes bytes of a
failed sample's trial transcript (agent/terminus_2.pane, falling back to
agent/trajectory.json) to SampleResult.feedback: the first failed attempt
only, passed samples carry nothing, missing transcripts are omitted
silently. Exposure to the agent stays gated by the sidecar's tier routing
(per-sample files are written only for viewable splits), so nothing can
leak to non_viewable or no_access tiers. Plumbed build.yaml -> serve.json
-> ServeConfig -> HarborRunner, mirroring score_baseline.

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

When enabled, the compiled instruction gains a section teaching the
optimizer to triage rough ideas on subset evals (--num-samples /
--sample-ids) and spend full-split evals only on survivors, stating the
true economics: every eval debits one run-budget unit regardless of size,
while the sample budget is debited only for the samples actually run, and
subset aggregates are noisier. The section is gated on introspecting
EvalRequest for the subset-eval fields (the same merge-order-truthfulness
pattern as the free-baseline bullet), so it can never render against a
sidecar that lacks subset evals. Plumbed build.yaml -> serve.json ->
ServeConfig for contract parity; consumption is compile-time.

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

When enabled, each collated sample's output carries an attempts list, one
{reward, exception} entry per attempt in stable attempt order: reward is
None when the attempt died before the verifier scored it, exception is the
recorded exception class name (None for clean attempts). Collation now
loads the attempt groups under 'best' aggregation too when a lever needs
them, without touching best-mode scoring. Exposure rides the same
viewable-only per-sample files as transcript feedback, so nothing reaches
non_viewable or no_access tiers. Plumbed build.yaml -> serve.json ->
ServeConfig -> HarborRunner, mirroring score_baseline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tlist pollution, and feedback-cap edge cases

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

BuildConfig and ServeConfig become discriminated unions on `mode`: a shared
extra="forbid" base plus per-mode subclasses (BuildConfigA/B, ServeConfigA/B).
A Mode-A config that sets a Mode-B-only field (feedback_transcripts,
expose_attempt_detail, instruct_multifidelity, feedback_max_bytes, harbor,
partition, inner_task) or a Mode-B config that sets a Mode-A-only field
(sample_timeout, task, task_project, task_module, dataset) is now a load-time
ValidationError instead of a silently-ignored no-op.

A discriminated union is not a class, so the BuildConfig.from_file and
ServeConfig.from_file classmethods become module-level loaders
(load_build_config, load_serve_config) built on pydantic TypeAdapter, keeping
the relative-path resolution and defaulting mode to "A" when omitted. Call
sites in the CLI, compiler, and serve entrypoint updated; _serve_config and
build_components narrow by isinstance / mode.

Deletes PR #20's _warn_mode_b_sample_timeout and _warn_mode_a_ignores_feedback_levers
(plus the compiler's Mode-A feedback-lever warning) and their tests: under the
type split those conditions are structurally impossible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread vero/src/vero/harbor/runner.py
Comment thread vero/src/vero/harbor/runner.py
shehabyasser-scale and others added 23 commits July 7, 2026 07:35
1. Dead attempts count 0.0 in mean aggregation (n_dead in metrics). Attempts
   dying before the verifier scored were silently dropped from the mean, so
   the score estimated P(pass | attempt survived): measured live, a no-retry
   candidate won selection at an inflated 0.233 while its retry-hardened
   successors measured an honest ~0.19 and lost. All-dead samples error
   loudly instead of scoring 0.0 (an outage must stay visible).
2. 'best' trial ranking is monotone in the reward. The rank was
   (clean, has_rewards, recency), so with concurrent attempts 'best' meant
   'last clean attempt to finish' and a later clean 0.0 clobbered an earlier
   clean 1.0, violating the never-clobber-a-passing-trial invariant the
   loader documents. Reward now precedes recency in the key.
3. Strict reward_key extraction. A configured reward_key missing from a
   rewards dict no longer falls back to 'pass'/'reward' (attempts within one
   mean could be scored on different metrics), and several unrecognized keys
   are refused instead of averaged (emitting easy auxiliary metrics beside
   the real one inflated the average). Sole-key dicts stay accepted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…follow-up)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…retries, fail-safe floor)

Five gaps in the champion-selection/finalize path, all observed or provoked
live:

1. Idempotent finalize: the first completed result is cached and replayed on
   any retry. Re-running would re-rank against a DB that now contains the
   first finalize's own admin evals, so a retried finalize could crown a
   different champion than the one already reported.
2. Pooled shortlisting: recorded evals of the same commit average (not max),
   and commits with identical git TREES collapse into one candidate group.
   Max-over-rows made every re-measurement an independent lottery draw; one
   live optimizer farmed empty re-commits as 'clean independent lottery
   tickets', another refused to re-measure its champion to protect a lucky
   draw. Pooling makes re-measurement variance-reducing and stops identical
   content from stuffing the top-K shortlist.
3. Every reward-critical finalize eval (targets, shortlist re-scores, floor,
   baseline) retries transient failures; targets that persistently fail are
   floored WITH a durable target_errors marker instead of aborting finalize
   (a trial that ships no reward.json loses its result: happened live to an
   8-hour run on a disk-full host).
4. All-error evals (score(fill_score=None) is None) retry like exceptions:
   an outage must never quietly become a measured 0.0.
5. Fail-safe floor: when the baseline itself cannot be measured, revert to
   the seed rather than shipping an unverified candidate (the floor exists to
   stop shipped regressions; skipping it re-opens that hole).

Plus: verifier_timeout build field sizes Harbor's [verifier] timeout_sec for
the whole finalize battery (the old value covered ~one eval, so Harbor could
kill finalize mid-flight), and GitWorkspace.tree_hash() resolves commit
content identity for the pooling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the loop (review follow-up)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ity floor, trusted nested CLI)

Four related fixes to keep hidden-split information and scoring authority
where they belong:

1. The free baseline eval no longer rides the admin flag. engine.evaluate
   gains a distinct `free` parameter that waives only the budget debit;
   admin=True also bypassed the no_access tier gate, so the agent's one
   free eval could target the held-out test split and read its aggregate
   score off the response. The freebie is also now consumed only after a
   successful eval, so an infra failure no longer burns it.

2. serve.py now passes split_accesses into the EvaluationEngine. Without
   it the engine-side no_access gate was dormant and the budget ledger
   (no_access splits are unbudgeted) was the only gate, which is exactly
   what every unmetered path skipped.

3. k-anonymity floor on subset evals of non_viewable splits (default 5,
   configurable via build.yaml / serve.json). EvalSummary.mean_score over
   an agent-chosen singleton subset is that sample's label-derived score
   verbatim, so n singleton evals reconstructed a hidden split's labels
   wholesale. Full-split evals always pass (their aggregate is the
   intended surface), so splits smaller than the floor stay evaluable.
   The floor is advertised in status() as min_subset_samples.

4. HarborConfig.harbor_requirement: when set, the nested `harbor run` is
   layered over the candidate env with `uv run --with <spec>`, so the
   orchestrator that produces trial result.json resolves from the trusted
   spec, not from the candidate's own pyproject/uv.lock (one edited line
   there could point at a fork that fabricates results). Verified that
   uv's ephemeral overlay takes precedence over a conflicting project
   pin for both the console script and sys.path. This raises the bar,
   not a full boundary: agent code still imports into the nested harbor
   process; out-of-process verification is tracked separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alue, versioned re-evals, dead-attempt causes)

Four small fixes so recorded numbers say what they are:

1. summary.json now carries n_scored, n_errored, and score_se beside
   mean_score: a mean over 3-of-18 scored samples, or one dominated by
   errored zero-fills, is a different measurement than a clean
   full-split mean, and both the agent and any auditor should see that
   without per-sample access. All three are label-safe aggregates.

2. summary.json status now writes the enum VALUE ("success"), not
   str(enum) ("ExperimentResultStatus.SUCCESS").

3. Result dirs are versioned per eval ({split}__{commit12}__eN instead
   of wipe-and-rewrite keyed on (split, commit)): repeat measurements of
   one commit (multifidelity confirms, champion re-evals) are exactly
   the evidence worth comparing, and the second eval erased the first.

4. Mean-mode collation records dead_exception_types per sample: n_dead
   alone hides WHY attempts died, and cause matters (rate-limit deaths
   are infra noise, crashes point at the candidate; measured live,
   110/129 UnicodeDecodeError deaths sat on two never-solved tasks).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…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>
…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)
fix: [no-ticket] harbor - ops integrity (exhaust-budget instruction lever, fail-closed ledger restore)
fix: [no-ticket] harbor - honest measurement signals (summary qualifiers, versioned re-evals, dead-attempt causes)
fix: [no-ticket] harbor - access-tier integrity (free-baseline privilege, k-anonymity floor, trusted nested CLI)
fix: [no-ticket] harbor - selection/finalize integrity (idempotency, tree pooling, retries, fail-safe floor)
fix: [no-ticket] harbor - scoring integrity (dead attempts, best-rank monotonicity, strict reward key)
refactor(harbor): split Mode A / Mode B into discriminated-union configs
@varunursekar
varunursekar merged commit ecc0285 into harbor-all-fixes 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