Repository navigation
fix(harnesses): a verifier sidecar removal that times out keeps the verdict and is retried - #234
Conversation
…erdict and is retried In the intel#218 review the verifier sidecar's teardown had a second gap, left to the author and not changed before the merge: `_verify_phase` stops the `-verify` sidecar in a `finally` with `stop_proxy`, which raises `TimeoutExpired` when `docker rm` times out. That replaced the reward the verifier had just computed with a TIMEOUT cell (exit 124, reward 0), and `ContainerSandbox.close()` could not retry, because it did not know the verifier sidecar, which then stayed on the network that `close()` removes. `verifier_sidecar()` now records the sidecar on its sandbox. The verify phase stops it with the new `stop_proxy_quietly`, which logs a timed-out removal instead of raising, and `close()` uses it for both sidecars, so a removal that timed out is retried before `network rm`. The solve sidecar's stop before the verifier still raises: the verifier must not start while it may still run. `docker_solver.py` keeps its 900 lines. Each of 5 mutants of the fix fails the new test. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #234 +/- ##
==========================================
+ Coverage 92.25% 92.94% +0.69%
==========================================
Files 239 241 +2
Lines 29937 30653 +716
Branches 4918 5060 +142
==========================================
+ Hits 27618 28491 +873
+ Misses 1632 1460 -172
- Partials 687 702 +15
🚀 New features to boost your workflow:
|
|
@exai-bot /review |
exai-bot
left a comment
There was a problem hiding this comment.
Note
AI-generated review of 1d2dbd8b5f48, requested by @vchamarthi, using the default review skill. It can be wrong: verify a finding before acting on it. React with a thumbs up or down on a finding to tell the bot whether it helped.
Model us.anthropic.claude-sonnet-5-5, effort default, 3 of 80 turns, 0.2 of 40 minutes, 59k in / 1k out tokens.
The change records the verifier sidecar on its sandbox and adds stop_proxy_quietly, which logs a timed-out docker rm instead of raising. _verify_phase uses it, so a removal timeout no longer replaces the computed reward. close() now stops the verifier sidecar and then the solve sidecar, so a failed removal is retried before network rm. I found no defects. The one removal path that still raises is the solve sidecar's stop before the verifier, and that is intended. The new test covers the verdict, verify_egress, and the retry happening before network rm.
No issues found.
Not verified
I did not run the tests. I read stop_proxy's retry behaviour. A retry after the sidecar is already gone keeps the first successful log read (_log_read), and _stopped makes a second call a no-op. That reading supports the claim that verify_egress stays valid.
napetrov
left a comment
There was a problem hiding this comment.
Review of 1d2dbd8. No fixes pushed; I found nothing that needs a change.
Summary. _verify_phase now stops the -verify sidecar with stop_proxy_quietly, so a timed-out docker rm after test.sh no longer replaces the verdict. close() retries the verifier sidecar's removal, then the solve sidecar's, before network rm. The solve sidecar's stop before the verifier still raises, as intended. This adds nothing to the earlier bot review; I checked its points by running the tests.
Open items. None blocking.
- Nit (introduced, optional):
_verifierholds only the most recent verifier sidecar. That is fine today because_verify_phasemakes one per run. If a second verifier sidecar is ever started on the same sandbox, the first would no longer be retried.
Test evidence (Linux review host, head 1d2dbd8)
uv run pytest tests/test_network_policy.py tests/test_container_agent*.py tests/test_docker_solver*.py: 172 passed, 1 skipped.- Mutant: with
_verify_phaseback onstop_proxy, the new test fails. The new test therefore covers the fix. ruff check dokimi tests: clean.
vchamarthi
left a comment
There was a problem hiding this comment.
Approved.
Sidecar-removal timeout no longer replaces the verdict, and close() retries it before network rm. Read stop_proxy and close at 1d2dbd8: a retry keeps the first log read (_log_read) and is a no-op once _stopped, so verify_egress stays valid. No defects found.
CI at send time: 0 failing, 0 pending.
…o start, or a crashed run left From vlad-perevezentsev's review of intel#234: - `verifier_sidecar()` recorded the sidecar on its sandbox only after a successful start. If the start failed and the removal in its `except` timed out, `close()` did not know the sidecar, which stayed on the run's network. It is recorded before the start now; a removal there that works marks it stopped, so `close()` does not touch it again. - `open()` cleared a crashed run's container and solve sidecar, but not its `-verify` sidecar, so a leftover one still held the network and `network create` failed the next cell with the same id. It is cleared with the others. The test that counts the solve sidecar's removals on a timeout now leaves the verifier sidecar's leftover removal out of its count. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
|
@napetrov on the optional nit: I kept a single |
Summary
Follow-up to the review of #218 (thread). The thread had two parts:
_verify_phasestops the-verifysidecar in afinallywithstop_proxy, which raisesTimeoutExpiredwhen itsdocker rmtimes out. That replaced the reward the verifier had just computed with a TIMEOUT cell.close()could not retry the removal either, because the sandbox did not know the verifier sidecar, which stayed on the networkclose()removes.On
main, take a fake docker whoserm -f <name>-verifytimes out.docker-oraclewith--network verify=allowlist:pypi.org, on a task whosetest.shpasses, gives returncode 124 and reward 0.0. After the verifier, the only removal of the sidecar is the one that timed out.Changes
dokimi/harnesses/container_agent.py:verifier_sidecar()records the sidecar on its sandbox.stop_proxy_quietly()isstop_proxyfor teardown. A removal that times out is logged torun.log([sidecar removal] <name> timed out after ...), not raised.close()stops the verifier sidecar, then the solve sidecar, with it. A removal that timed out is therefore retried beforenetwork rm.verifier_sidecar()records the sidecar before its start, soclose()also retries one whose start failed and whose removal then timed out; a removal there that works marks it stopped.open()also clears a-verifysidecar a crashed run with the same id left, before it removes and creates the network.dokimi/harnesses/docker_solver.py:_verify_phasestops the verifier sidecar withstop_proxy_quietly, so the verdict andmetrics.network.verify_egressstand. The file keeps its 900 lines: one call changes.test_stop_proxy_timeout_aborts_before_verification).Changelog fragment (Fixed).
Risk
Only the teardown after the verifier changes. The log line
close()writes for a timed-out removal of the solve sidecar now names the sidecar. A run without an allowlisted verifier has no verifier sidecar, so its teardown makes the same docker calls as before.Testing
On a Linux review host, at
84c9f2c(onmain54ce188):make ci-local CI_LOCAL_ARGS='--with-docker': 33 passed, 0 failed, 6 skipped (test-latest, thecli-surfacepackaging step, conda-forge-deps without micromamba, docsdeploy, the pip-audit report, semgrep). 8,203 tests passed, 2 skipped; changed-line coverage 100%.1d2dbd8: a verify sidecar whose failed start cannot be removed gets its retry inclose(), one whose removal worked is not touched again, andopen()clears a leftover-verifysidecar. The first two fail at1d2dbd8; 4 mutants each fail a test (no leftover removal, the sidecar recorded after the start, a failed start never or always marked stopped).test_a_verify_sidecar_removal_that_times_out_keeps_the_verdict_and_is_retried: onmainit gives(124, 0.0)for(0, 1.0). Here the verdict andverify_egressstand, and the sidecar gets two removals after the verifier, both before the lastnetwork rm._verify_phaseback onstop_proxy, the verifier sidecar not recorded,close()skipping it or stopping only the solve sidecar, andstop_proxy_quietlyraising.main54ce188 (0a5717c): the full suite (8,232 passed, 2 skipped), the growth check,mypyandruffpass.Checklist
pytestpassesruff,mypy, and schema checks pass.github/.licenserc.yaml)