Repository navigation
Conversation
A single-artifact or --all-vs-all routing run that hit the spend cap exited with 'nothing was written', losing every call already paid for. It now writes --out with the completed calls scored, a partial block (reason spend_cap, calls_done, calls_planned), prints the summary and cost lines, and still exits non-zero. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
There was a problem hiding this comment.
🟡 Changes recommended
Capped runs can overwrite finished results in a fallback report file, while partial all-vs-all runs omit required summaries, partial-run labels, and low-sample warnings.
2 open issues
What changed in this PR
2 new findings.
This PR preserves partial novelty-routing measurements when --max-usd stops a run, rather than discarding completed work.
Changes:
- Retains completed model calls, marks capped results as partial, and excludes unfinished work from scoring and repeat-noise calculations.
- Adds partial-result saving and reporting while retaining a nonzero exit.
- Adds regression tests and documents capped-run behavior.
| File | Description |
|---|---|
dokimi/tests/test_novelty_routing_spend_cap_partial.py |
Tests partial results, scoring, output, and file preservation. |
dokimi/scripts/growth_baseline.json |
Lowers the command module’s size baseline. |
dokimi/dokimi/novelty/routing.py |
Retains completed rows when the spend cap interrupts routing. |
dokimi/dokimi/novelty/client.py |
Removes the unconditional “nothing was written” claim. |
dokimi/dokimi/novelty/all_vs_all.py |
Aggregates partial results and marks unreached calls unscored. |
dokimi/dokimi/commands/novelty.py |
Saves partial results before exiting routing commands. |
dokimi/dokimi/commands/novelty_routing_report.py |
Adds partial-result persistence, reporting, and exit helpers. |
dokimi/docs/skill-novelty.md |
Documents partial records, scoring, and reruns. |
dokimi/docs/skill-novelty-walkthrough.md |
Explains routing’s exception to cap-triggered data loss. |
dokimi/changelog.d/20261104_130000_napetrov_fix-cap-partial-save.md |
Announces partial-result preservation. |
Review effort: Balanced
|
OpenCodeReview: Commit 8560de6 was not reviewed. This PR has reached its review limit (6 reviews). CI at `8560de6`: 7 still running, 7 passing, 2 skipped
To review this commit: re-request review from exai-bot in the Reviewers list. <details><summary>Last review (d9a7538): no findings</summary> Open threads from the bot: 0 </details> |
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #406 +/- ##
==========================================
+ Coverage 94.99% 95.00% +0.01%
==========================================
Files 363 364 +1
Lines 48348 48437 +89
Branches 8318 8332 +14
==========================================
+ Hits 45928 46019 +91
+ Misses 1531 1530 -1
+ Partials 889 888 -1
🚀 New features to boost your workflow:
|
A capped run no longer overwrites a finished sidecar: the partial result goes to the first of <stem>.partial.json, <stem>.partial2.json, ... that is free or already partial. A call the cap stops after it was paid for (price unknown) keeps its reply: it is scored, then the run stops, and the query enters the noise block when all its repeats are in. A capped all-vs-all run prints the same summary as a finished one (field line, attractors), with the model line `partial: N of M calls` and the fewer-than-five warning. partial_record and repeat_noise move to novelty/noise.py to keep routing.py under its size cap. Thread: PRRT_kwDOVBg7g86z4hq2 Thread: PRRT_kwDOVBg7g86z4hrt Thread: PRRT_kwDOVBg7g86z4ihc Thread: PRRT_kwDOVBg7g86z4ihf Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
No code change in this commit: the fixes are in 86903d8. The findings nested in the Copilot review body have no thread, and the exai review body has no finding of its own, so this commit names those reviews. Thread: PRR_kwDOVBg7g88AAAABWG2GsA#1: already fixed in 86903d8 Thread: PRR_kwDOVBg7g88AAAABWG2GsA#2: already fixed in 86903d8 Thread: PRR_kwDOVBg7g88AAAABWG2GsA: already fixed in 86903d8 Thread: PRR_kwDOVBg7g88AAAABWG2g-w: already fixed in 86903d8 Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The Codecov patch report found three uncovered lines in novelty_routing_report.py: a sidecar this cannot read, a partial model line with five answered calls, and the blind-skill warning without a lexical arm. The code is right on head; these tests pin it. Thread: IC_kwDOVBg7g88AAAABjDYjMg: accept, test-only Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
|
Both findings are answered below (#1, #2), fixed in 64b71de. "Avoid overwriting finished results at fallback output paths": fixed in 64b71de by Nikolay Petrov. A capped run writes to the first free "Show partial all-vs-all summaries when budget limits a run": fixed in 64b71de by Nikolay Petrov. A capped all-vs-all run prints the summary, Its findings are the threads PRRT_kwDOVBg7g86z4ihc and PRRT_kwDOVBg7g86z4ihf, fixed in 64b71de. Nothing to change: this summary reports 0 findings on 86903d8, so there is no claim to act on. Covered in b5fdca5: tests for the unreadable sidecar and two more lines. Test-only; the code was right. |
antonwolfy
left a comment
There was a problem hiding this comment.
The cap handling holds up: a capped routing run writes a partial result, keeps finished files safe, and still exits non-zero. One risk is left in the tests for the capped --all-vs-all --repeats N path, and one doc page is now stale.
What I ran, on a Linux review host at b5fdca5:
make ci-local: 29 passed, 1 failed, 7 skipped; 15,724 tests. The failure istest_unbalanced_quote_in_hook_completes_quickly(a 1 s timing bound, 2.09 s measured) plus two 60 s timeouts intest_audit_test_quality.py. Both files pass on a rerun (680 passed), and the PR does not touch them. The changed-line coverage step passes.- Reproductions for the code findings, with the LLM transport mocked.
- A mutation run over the new code: 68 mutants, 19 of which pass the new tests plus
tests/test_novelty*.py.
Other finding, outside the diff:
- Nit:
docs/reviewing.md:79-80still says--max-usd"writes no artifact when the cap trips" fornoveltysteps. That is no longer true fornovelty routing --model, which now saves apartialfile or a.partial.jsonsidecar. Suggestion: add "exceptnovelty routing, which saves the calls it made as apartialresult", as the walkthrough page now does.
Checked, no issues
- Sidecar naming: a finished
--outsends the partial result to<stem>.partial.json, then.partial2.json, and the exit message names the path. - Documented keys:
partial,status,n_calls,n_unscored,own_rate: nulland the noise exclusion match the output of a mocked capped run. - Cap on the first call: zero rows,
calls_done0, no crash, both modes. - Failed calls with the cap: counted in
n_failed, and the refused calls land inn_unscored. - Repo rules: changelog fragment, growth baseline, docs nav and the offline tests pass; the new tests write only under
tmp_path. - Commits: all four carry
Signed-off-by.
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
antonwolfy
left a comment
There was a problem hiding this comment.
I pushed a commit per nit, up to 664b082, which fix the nit from my review:
664b082:dokimi/docs/reviewing.md:79: the--max-usdsentence now saysnovelty routing --modelis the exception and saves the calls it made as apartialresult.
make ci-local at 664b082: 30 passed, 0 failed, 7 skipped.
Not approving yet. Still open: the risk from my review.
The capped --all-vs-all --repeats N path had no test with more than one repeat. The new test stops a run mid-query over three skills and checks calls_done and calls_planned, n_unscored for the stopped and the never reached skill, and the noise block. Each of the four mutants in the review fails it. Thread: PRRT_kwDOVBg7g860Dr0t Thread: PRR_kwDOVBg7g88AAAABWOVf0w Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Baseline: commands/novelty.py at 921, its merged length (main 928, branch 1014). Name the capped steps by their intel#396 paths (skill novelty analyze/atoms/probe, skill shorten) in skill-novelty.md and the changelog fragment. Signed-off-by: Alexander Rybkin <alexander.rybkin@intel.com>
antonwolfy
left a comment
There was a problem hiding this comment.
Review at d9a7538. Both points from my last review are fixed: the reviewing.md sentence names the routing exception, and the new repeat-run test pins calls_done, calls_planned, both n_unscored values and the noise block. The problems are at the edges of the unpriced-call path and in two measurements the tests do not pin. Three things are worth fixing before merge, plus one nit inline.
What I ran, on a Linux review host at d9a7538:
make ci-local: 30 passed, 0 failed, 7 skipped. Changed-line coverage passes.- Reproductions for the code findings, with the LLM transport mocked.
- A mutation run over the new code: 67 mutants applied, 22 of which pass the new test file. Two of the survivors are inline below.
Checked, no issues
- Uncapped output: a finished single-artifact run writes the same
routing.jsonon the PR's base and on head, apart from the artifact path. - Schema: routing files are written with
write_text, carry noschema_versionand are not validated againstnovelty.v1.json, sostatusandpartialneed no schema change. - Sidecars: a finished
--outsends the partial result to<stem>.partial.json, then.partial2.json; the exit message names the path. - Commits: all non-merge commits carry
Signed-off-by. - Docs: the keys and console lines documented in
skill-novelty.mdmatch a mocked capped run, single and--all-vs-all --repeats 2.
Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
antonwolfy
left a comment
There was a problem hiding this comment.
I pushed a commit per nit, up to 8560de6, which fix the nit from my review:
8560de6:dokimi/docs/skill-novelty.md:762: the resume advice now saysDOKIMI_RESPONSE_CACHEmust also have been set on the capped run.
make ci-local at 8560de6: 29 passed, 1 failed (host timing flake, green on rerun), 7 skipped.
GitHub CI has not been waited for at this head: the Actions queue held the runs for over an hour, so the fix is not checked there yet. Locally the fix commit passes the CI steps; the only failures are load-sensitive timeouts in files the docs change does not touch.
Not approving yet. Still open: the bug and the two risks from my review.
A run whose last planned call comes back unpriced has nothing left to run, so it is complete: no partial block, status ok, exit 0. The stop is kept as cap_stop, not as partial, so all-vs-all still asks no later skill unmetered after an unpriced reply. Thread: PRRT_kwDOVBg7g860fvOE Thread: PRRT_kwDOVBg7g860fvON Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Thread: PRRT_kwDOVBg7g860fvON Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Thread: PRRT_kwDOVBg7g860fvOQ Review: PRR_kwDOVBg7g88AAAABWbHvBQ Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com> # Conflicts: # dokimi/dokimi/commands/novelty.py # dokimi/dokimi/commands/novelty_routing_report.py # dokimi/dokimi/novelty/routing.py
Review nits on the merge resolution: drop the second Path import under TYPE_CHECKING, and say the partial marker is set only when the cap stops the arm before every planned call. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>
The growth ratchet caps a function at complexity 10; model_routing reached 11 with the cap's stop logic. The repeat loop of one query moves to _ask_query, with no change in the calls, rows or order. Signed-off-by: Nikolay Petrov <nikolay.a.petrov@intel.com>


Summary
When
novelty routing --model --max-usdhit the cap, it exited withspend cap reached ...; nothing was written, and every paid call was lost. On real skill-repo runs this lost more than $9, one run at 444 of 456 calls.--all-vs-all--outwritten withstatus: "partial"andpartial: {reason: "spend_cap", calls_done, calls_planned}own_rate: nulland its queries go ton_unscoredpartial: N of M calls; warning when fewer than 5 calls answered--outalready holds a full result<stem>.partial.jsonnext to it; the exit message names the pathA finished run is unchanged: JSON, stdout, exit code and files written are identical on base and head for 7 scenarios.
Evidence
tests/test_novelty_routing_spend_cap_partial.pyfail on base and pass on head;make ci-localpassesstatus: "ok"; the model line had no partial tag), both fixed and confirmed by probes in pass 2Merge danger
analyze,atoms,probe,shortenstill write nothing at the cap (each writes once after several stages, so it is a larger change per command)--outnames share one.partial.json; when a call has no price, its paid reply is not kept; when the cap and failed calls both happen, the exit message names only the cap🤖 Generated with Claude Code