feat(harbor): the agent's first baseline eval is budget-free#25
feat(harbor): the agent's first baseline eval is budget-free#25shehabyasser-scale wants to merge 2 commits into
Conversation
The seeded baseline is the reference every candidate is implicitly compared to, yet it can never win selection (auto_best excludes base_commit by design), so metering it forced the optimizer to choose between flying blind and paying a budgeted eval for an unselectable commit. Observed live twice: the incident behind #11/#12 (an optimizer burned its whole budget measuring the baseline), and exp5's optimizer which, warned off by #12, skipped the reference entirely, could not tell its no-op edit (train 0.375) from an improvement, and quit with 3 of 5 evals unspent. The first eval whose transferred commit resolves to base_commit now runs unmetered (engine admin path) while results still route through the agent's real split tier. Capped at one: later baseline evals debit normally, so free compute is bounded. /status exposes base_commit and whether the free reference eval is still available. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Nit found by the review panel for #26 while verifying this PR's semantics: |
Setting _free_baseline_used before the await burned the agent's one free baseline on a transient engine failure, forcing the retry to be metered: the exact pay-for-it failure the feature prevents. Move the flag write to after a successful evaluate (safe in the single-threaded asyncio loop, no await between the check and the write) so a failed baseline eval can be retried for free. Adds two tests: an admin re-score of the base commit must not consume the free slot, and a failed baseline eval must leave the slot available for a free retry. Addresses Greptile P1 on this PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… constant The compiler introspects StatusSummary for the free-baseline field name; that string was an unnamed literal, the sole coupling to the field PR #25 adds on a separate chain. Hoist it to _FREE_BASELINE_FIELD so the compiler<->protocol contract has one documented source. A hard import-time assert cannot live here: the field is legitimately absent on this branch's base until the sidecar PR merges, which is why the render is introspection-gated in the first place. Addresses Greptile P2 on this PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| free_baseline = ( | ||
| not admin | ||
| and self.base_commit is not None | ||
| and sha == self.base_commit | ||
| and not self._free_baseline_used | ||
| ) | ||
| exp = await self.engine.evaluate( | ||
| replace(req, commit=sha), admin=admin or free_baseline | ||
| ) | ||
| # Consume the free slot only after the eval actually succeeds. Setting it | ||
| # before the await would burn the one free baseline on a transient engine | ||
| # failure (timeout, infra), forcing the agent to pay for the retry, which is | ||
| # the exact failure mode this feature prevents. Safe in the single-threaded | ||
| # asyncio loop: no await runs between the check above and this write. | ||
| if free_baseline: | ||
| self._free_baseline_used = True |
There was a problem hiding this comment.
Race window defeats the "capped at one" guarantee
The _free_baseline_used read at line 87 (inside free_baseline = (... and not self._free_baseline_used)) is separated from the write at line 98 by await self.engine.evaluate(...). If two concurrent evaluate coroutines arrive while none have completed yet, both will read False, both will set free_baseline = True, and both will be served as admin calls — violating the explicit "capped at exactly one" design goal.
The comment "no await runs between the check above and this write" is true about the if free_baseline: … assignment site alone, but that is not the relevant check. The check that controls the boolean is not self._free_baseline_used in the free_baseline tuple expression, and that read is separated from the write by a full await. In a single-threaded asyncio event loop two coroutines can both be suspended at await self.engine.evaluate(...) having already recorded free_baseline = True.
Fixing this requires setting the flag before the await (then restoring it on exception), or guarding it with a sentinel that is set synchronously before yielding — the mirror of the reasoning that justified moving the assignment after the await in the previous review.
Prompt To Fix With AI
This is a comment left during a code review.
Path: vero/src/vero/harbor/server.py
Line: 83-98
Comment:
**Race window defeats the "capped at one" guarantee**
The `_free_baseline_used` read at line 87 (inside `free_baseline = (... and not self._free_baseline_used)`) is separated from the write at line 98 by `await self.engine.evaluate(...)`. If two concurrent `evaluate` coroutines arrive while none have completed yet, both will read `False`, both will set `free_baseline = True`, and both will be served as admin calls — violating the explicit "capped at exactly one" design goal.
The comment "no await runs between the check above and this write" is true about the `if free_baseline: …` assignment site alone, but that is not the relevant check. The check that controls the boolean is `not self._free_baseline_used` in the `free_baseline` tuple expression, and that read is separated from the write by a full `await`. In a single-threaded asyncio event loop two coroutines can both be suspended at `await self.engine.evaluate(...)` having already recorded `free_baseline = True`.
Fixing this requires setting the flag **before** the await (then restoring it on exception), or guarding it with a sentinel that is set synchronously before yielding — the mirror of the reasoning that justified moving the assignment *after* the await in the previous review.
How can I resolve this? If you propose a fix, please make it concise.
Stacked on #20 (top of the sidecar chain: #11 -> #19 -> #20 -> this).
The problem, observed twice in live trials
The seeded baseline is the reference every candidate is implicitly compared to, yet it can never win selection (auto_best excludes
base_commit, correctly, so "do nothing" cannot win). Metering its evaluation therefore forces the optimizer into a bad choice:#12 treated the symptom (don't waste budget); this treats the cause (the reference measurement should not cost budget).
The fix
EvaluationSidecar.evaluate: when the transferred commit resolves tobase_commitand the free eval hasn't been used, run it through the engine's unmetered (admin) path while still routing results through the agent's real split tier. Capped at exactly one, so free compute is bounded; subsequent baseline evals debit normally./statusnow reportsbase_commitandfree_baseline_available, so agents can discover the mechanism.Selection integrity is untouched: the baseline experiment is recorded as before and remains excluded from auto_best by the existing
base_commitfilter.Tests
Seven new tests: first baseline eval unmetered but tier-routed; second one metered; non-baseline commits always metered; no-
base_committasks never free;/statussurfaces and flips the flag.Follow-up (separate, compiler layer): update the #12 instruction paragraph to say the first baseline eval is free once this lands.
🤖 Generated with Claude Code
Greptile Summary
This PR makes the agent's first evaluation of the seeded baseline commit budget-free by routing it through the engine's admin (unmetered) path while still writing results to the agent volume via the normal tier. The flag is consumed only after a successful engine response so transient failures don't permanently burn the free slot, and
/statusnow exposesbase_commitandfree_baseline_availableso agents can discover the mechanism.server.py: adds_free_baseline_usedinstance flag;evaluatedetects baseline-sha match and passesadmin=Trueto the engine while keepingadmin=Falsefor result routing;status()forwards the new fields.protocol.py/serve.py: additive plumbing —StatusSummarygainsbase_commit/free_baseline_available;ServeConfig.base_commitis threaded into the sidecar constructor.test_harbor_server.py: seven new tests cover the happy path, second-call metering, non-baseline commits, no-base_committasks, status surfacing, admin isolation, and engine-failure resilience.Confidence Score: 4/5
Safe to merge for sequential agents; a concurrency edge case in server.py should be addressed before the sidecar is exposed to parallel request patterns.
The core logic is well-reasoned and the test suite is thorough, but the "capped at one" free-baseline guarantee in server.py can be broken when two evaluate coroutines for the same baseline are in-flight simultaneously — both read _free_baseline_used = False before either writes True, so both are served as unmetered admin calls. The safety comment in the code focuses on the assignment site and is correct there, but misses the window opened by the earlier read being separated from the write by an await. In a single-agent, sequential-request context the practical risk is low, but the invariant is explicitly stated as a design constraint and the reasoning justifying its safety is incorrect.
vero/src/vero/harbor/server.py — specifically the _free_baseline_used read/write pattern around the await self.engine.evaluate() call.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Agent participant Sidecar as EvaluationSidecar participant Engine as EvaluationEngine Note over Sidecar: _free_baseline_used = False Agent->>Sidecar: "evaluate(commit=base_commit) [1st call]" Sidecar->>Sidecar: "_transfer_commit → sha == base_commit" Sidecar->>Sidecar: "free_baseline = True" Sidecar->>Engine: "evaluate(admin=True) [unmetered]" Engine-->>Sidecar: Experiment Sidecar->>Sidecar: "_free_baseline_used = True" Sidecar->>Sidecar: "_route_results(admin=False) → write to agent volume" Sidecar-->>Agent: EvalSummary (budget_remaining reported) Agent->>Sidecar: /status Sidecar-->>Agent: "free_baseline_available=False" Agent->>Sidecar: "evaluate(commit=base_commit) [2nd call]" Sidecar->>Sidecar: "free_baseline = False (_free_baseline_used=True)" Sidecar->>Engine: "evaluate(admin=False) [metered]" Engine-->>Sidecar: Experiment Sidecar-->>Agent: EvalSummary (budget decremented) Agent->>Sidecar: "evaluate(commit=candidate_sha)" Sidecar->>Engine: "evaluate(admin=False) [always metered]" Engine-->>Sidecar: Experiment Sidecar-->>Agent: EvalSummary%%{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 Note over Sidecar: _free_baseline_used = False Agent->>Sidecar: "evaluate(commit=base_commit) [1st call]" Sidecar->>Sidecar: "_transfer_commit → sha == base_commit" Sidecar->>Sidecar: "free_baseline = True" Sidecar->>Engine: "evaluate(admin=True) [unmetered]" Engine-->>Sidecar: Experiment Sidecar->>Sidecar: "_free_baseline_used = True" Sidecar->>Sidecar: "_route_results(admin=False) → write to agent volume" Sidecar-->>Agent: EvalSummary (budget_remaining reported) Agent->>Sidecar: /status Sidecar-->>Agent: "free_baseline_available=False" Agent->>Sidecar: "evaluate(commit=base_commit) [2nd call]" Sidecar->>Sidecar: "free_baseline = False (_free_baseline_used=True)" Sidecar->>Engine: "evaluate(admin=False) [metered]" Engine-->>Sidecar: Experiment Sidecar-->>Agent: EvalSummary (budget decremented) Agent->>Sidecar: "evaluate(commit=candidate_sha)" Sidecar->>Engine: "evaluate(admin=False) [always metered]" Engine-->>Sidecar: Experiment Sidecar-->>Agent: EvalSummaryPrompt To Fix All With AI
Reviews (2): Last reviewed commit: "fix(harbor): consume the free baseline s..." | Re-trigger Greptile