Repository navigation
fix(novelty): atoms, probes, grades and batches stop at a run-wide provider error - #767
Open
antonwolfy wants to merge 4 commits into
Open
antonwolfy wants to merge 4 commits into
antonwolfy wants to merge 4 commits into
Conversation
…ovider error (intel#708) Extraction, the faithfulness check, probe wording generation, probe answers and grades, the value and conflict batches (`ask_in_batches`) and the retention adjudication each caught every `Exception` per item. With no credentials, a permission error or an unknown model each of them went on and made, and recorded as failed, every remaining call. Each now stops at the first error for which `routing_stop.is_run_wide` is true, the test `novelty routing` uses (intel#677), and raises it as a `SpendCapReached` with `reason` `permanent_error`, which the cap-stop paths already keep as a partial result: extraction marks the unread spans and sets `report.partial`, `run_measurement` counts the jobs not run in `not_run` and carries the stop (an answer already paid for stays, ungraded), `analyze` writes its partial record, and `ask_in_batches` returns the chunks answered so far with the stop on `BatchResult.stop`, which `judge_value` and `detect_conflicts` raise. A refusal, an unparseable reply and a context-length rejection stay one item's failure. `is_retryable` alone would stop on those too. The readers of a partial file and the rerun hints no longer advise a higher `--max-usd` after this stop, and `novelty.v1.json` lists `permanent_error` as a `partial.reason`. `test_a_recovered_parse_error_does_not_hide_the_failure_that_lost_spans` used an `AuthenticationError` as its example of a lost batch: it is a `BadRequestError` there now, since a bad key stops the run. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
|
✅ OpenCodeReview: Review complete: 0 finding(s) across 1 selected item(s). CI at Review details
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #767 +/- ##
=======================================
Coverage 95.72% 95.72%
=======================================
Files 415 415
Lines 55362 55408 +46
Branches 9516 9522 +6
=======================================
+ Hits 52993 53041 +48
+ Misses 1466 1465 -1
+ Partials 903 902 -1
🚀 New features to boost your workflow:
|
Conflicts: dokimi/dokimi/novelty/routing_stop.py and dokimi/docs/skill-novelty.md. routing_stop.py: main renamed the credential marker tuple to `_NON_RETRYABLE_MESSAGES` (imported from dokimi.llm); `is_run_wide` now reads it, and the branch's `permanent_stop` and `stop_if_run_wide` stay. skill-novelty.md: the permanent-error paragraph takes main's wording (the AWS credential cases) and keeps the branch's sentence on atoms, probe, analyze and shorten. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
exai-bot
reviewed
Nov 14, 2026
… error; a late answer is not graded after a stop Settles the two review threads on intel#767. A reply that would not parse (a ValueError from the JSON extractors) quotes the reply in its message, so a model answering about "Unable to locate credentials" matched the no-credentials marker and stopped the run. is_run_wide now treats a ValueError as one failed item. With concurrency above 1, a worker whose answer came back after another worker recorded a permanent stop went on to grade it. run_measurement now keeps that answer ungraded, through the path a capped grade takes, and sends the judge nothing more. Signed-off-by: Anton Volkov <antonwolfy@gmail.com>
…cted request The conflict-check and wording-generation rejected-request tests checked only the call count. The conflict test now asserts the failed batch's atoms land in report.unchecked. The wording test replies with valid paraphrases and asserts that only the failed request is rejected and the other two are kept. Signed-off-by: vchamarthi <123653452+vchamarthi@users.noreply.github.com>
Contributor
|
Pushed 1 commit to
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
#708: the per-item
except Exceptionin atom extraction, the faithfulness check, probe wording generation, probe answers and grades, the batched value and conflict calls and the retention adjudication had no run-wide check, so with missing credentials each made, and recorded as failed, every remaining call (the same cause #709 fixed innovelty routing). Onmain, with a client whose every call raises an authentication error ("Unable to locate credentials"):mainextract_atoms, 200 spans in 8 batchesExtractionError: no atoms: every extraction call failedreport.partialhasreasonpermanent_error, the spans are marked unreadrun_measurement, 10 probes in 2 arms, 1 workerERROREDanswer,not_run0,stopNonenot_run20,stop("permanent_error", "permanent error: Unable to locate credentials")ask_in_batches(value and conflict batches),verify_atoms, probe wordings, the retention oracleThe fix takes
is_run_widefromrouting_stop.py, as #709 does, and notis_retryablealone (one of the issue's two options). A context-length rejection, a refusal or an odd reply is non-retryable and yet one item's own failure, so stopping on it would lose the rest of a run; each site has a test that it does not stop. A run-wide error is raised as theSpendCapReachedthe cap stops use, withreasonpermanent_error, so every path that keeps a cap stop's partial result keeps this one's.Closes #708
The same cause in a site the issue does not name was searched for in
dokimi/novelty/and the novelty commands; the sites found are all fixed here (see Changes), so there is no follow-up.Changes
novelty/routing_stop.py:permanent_stop(exc)builds the stop (reasonpermanent_error, messagepermanent error: <error>) andstop_if_run_wide(exc)raises it whenis_run_wide(exc).novelty/atoms.py:extract_atomsandverify_atomscall the model throughbatching.or_stop, which raises that stop for a run-wide error. In extraction it lands in the existingexcept SpendCapReached, so the atoms read stay and the unread spans are marked, as at the cap. A partial atoms file with this reason is refused with "Fix the error and rerun", not a--max-usdhint.novelty/measure.py:run_measurementand_graderaise the stop first in theirexcept Exceptionhandlers. Jobs not yet started when it is recorded are not run (not_run); an answer already paid for whose grade met the error stays, ungraded, as for a cap. At mostconcurrencycalls are in flight when it is recorded.novelty/routing_stop.py:is_run_wideis false for aValueError, which is what the JSON extractors raise for a reply that will not parse and quote the reply in; a model that answers with "Unable to locate credentials" is one failed item, not a provider error. Provider errors are notValueErrors.novelty/measure.py: withconcurrencyabove 1, a worker whose answer returns after another recorded the stop keeps it ungraded (_grade_unless_stopped, through the capped-grade path) and sends the judge nothing.novelty/batching.py:ask_in_batchesstops at a run-wide error, returns the chunks answered so far, puts the chunk and those not yet asked infailed, and setsBatchResult.stop.classify.judge_valueandclassify.detect_conflictsraise it, as a cap stop propagates.novelty/probes.py(_generate) andnovelty/retention.py(_adjudicate): the same first-statement check.artifacts.load_artifact,commands/novelty_budget.replay_hintandcommands/novelty_atoms_file._verdicts_hintno longer advise a higher--max-usdafter this stop;novelty.v1.jsonlistspermanent_errorinpartial.reason.docs/skill-novelty.md: one sentence extends the routing passage to these steps, and theanalyzepartial block lists the new reason.tests/test_novelty_permanent_stop.py: a test per site that the step stops at the first run-wide error and keeps its partial result, and a counterexample per site that a context-length rejection of one item leaves the rest of the run going.test_a_recovered_parse_error_does_not_hide_the_failure_that_lost_spansintests/test_novelty_atoms.pyused anAuthenticationErroras its example of a lost batch, which is now a stop; it uses aBadRequestErrorand asserts the same.Risk
A run whose extractor, answerer, judge or adjudicator has no credentials, no permission or an unknown model now ends at the first call, with a partial result and exit 1 as at the cap, where
atomsraisedExtractionErrorandprobeandanalyzefinished with every answerERRORED. Apartial.reasonofpermanent_erroris new inatomsandnovelty.jsonpartial files (the schema lists it); readers that refuse partial files refuse these too. Any other failure of one item is recorded as before.The branch merges
main, which changed the routing paragraph ofdocs/skill-novelty.mdthat this change extends (the AWS credential cases) and renamed the credential marker tuplerouting_stop.pyreads (now_NON_RETRYABLE_MESSAGES); both conflicts are resolved keeping both sides. No other open PR touches the lines changed here (#692 changesretention.pyinverdict, not_adjudicate; #729 only adds comments to theexcept Exceptionlines; #697 changessave_atoms; #489 wraps_gradeper judge inrun_measurement).Testing
On a Linux review host, at
ee3e586(onmaincc2ca31):make ci-local: 33 passed, 0 failed, 14 skipped. The skips are steps that need Docker and the network, the pinned Claude Code install, the jobs that run only onmainor from another job's matrix, conda-forge, the fuzz run and semgrep. 20473 tests passed, 19 skipped.main(8 and 20 calls), passes here (1 call each). The new test file againstmain's code: 13 of its 21 tests fail, and the 8 that pass are the counterexamples that a per-item error does not stop.verify_atoms, the answer, the grade and probe wording calls without the check,ask_in_batcheswithout the check,judge_valueordetect_conflictswithoutraise result.stop, the retention check removed, later jobs still run after the stop, the check widened to every non-retryable error instop_if_run_wideand inask_in_batches(the counterexamples fail), the stop message without its prefix, and the--max-usdadvice kept in the atoms reader, the artifact reader andreplay_hint.Unable to locate credentials: see the AWS docs.) as a batch reply or a judge reply: with theValueErrorrule removed, the batch run stops withpermanent_errorand the grade run stops; here the batch is answered and the 8 grades areERROREDwithstopNone. A two-worker measurement whose second answer is held until the first worker's grade has raised the authentication error: 1 judge call, 2 runs kept ungraded, 6 not run; with the check removed the second answer is graded (the test fails).Revert
A plain revert restores the old per-item handling. Partial files written with
reasonpermanent_errorstay valid JSON, but the restored schema would reject that reason in anovelty.jsonpartial record.Checklist
pytestpassesruff,mypy, and schema checks passAGENTS.md.github/.licenserc.yaml)