Repository navigation
Foundation: audit actual backend calls separately from replay fixture keys - #298
Conversation
Opus merge-gate review — PR #298 (Jev-Engineering/cookbook)
Verdict summaryNo MUST CHANGE findings. The guard rewrite is not loosened anywhere — I proved this three ways 1. The guard rewrite — is anything loosened? (the central question)1a. Line-by-line reading of the two code paths
Can a recipe now satisfy the guard in a way it could not before? Two ways, both intended and
1b. 50-recipe before/after comparison (the regression proof)
Full
Also confirmed: the new code calls 1c. Adversarial scratch variants (28 built and executed against the real guard)Driven through
Three variants were accepted, each for a reason that is explicitly in scope-of-the-check:
1d. Mutation testing (22 mutations, applied in-worktree and reverted; tree verified clean after)Script All 8 10 of 12 Both Two survivors, both analysed in detail (
2.
|
| check | result |
|---|---|
ruff check . |
All checks passed! |
ruff format --check . |
393 files already formatted |
pytest (bare) |
4919 passed, 46 skipped, 50 deselected, 31 xfailed in 162.71s |
pytest tests/test_recipe_guard.py -rA |
747 passed, 43 skipped, 50 deselected, 31 xfailed |
same, on origin/main export |
747 passed, 43 skipped, 50 deselected, 31 xfailed — outcome lists identical |
pytest -m catalog_audit tests/test_recipe_guard.py |
7 failed, 43 passed — identical on origin/main (pre-existing, non-gating) |
python tools/check_hygiene.py |
Hygiene check passed: 569 file(s) scanned |
python tools/render_catalog.py --check |
exit 0 |
python tools/notebook_ci.py fixtures |
51 recipe folders, 0 failed |
python -m jev_cookbook.fixtures validate --all |
all valid, exit 0 |
| 28 adversarial notebook variants | 27/28 as expected; the 3 accepted ones analysed above |
22 mutations of accounting.py / request_audit.py / test_recipe_guard.py |
20 RED, 2 survivors analysed (1 equivalent mutant, 1 → S3); worktree verified clean after |
tools/check_notebook_fresh.py on a stale-audit pair |
exit 1, STALE: … outputs[0].text — freshness delegation confirmed |
Env B — uv venv --python 3.14 + .[dev,ml] -c .github/constraints-notebooks.txt (CPython 3.14.7)
| check | result |
|---|---|
pytest (bare) |
4919 passed, 46 skipped, 50 deselected, 31 xfailed in 135.72s |
execute scratch copy of 01-sentiment-classification + check_notebook_fresh.py |
executed exit 0; matches a fresh offline run (2 figures, identical bytes) |
36-card-game-action-selection (the scripted one) |
executed exit 0; matches a fresh offline run (3 figures) |
43-failure-recovery-selection |
executed exit 0; matches a fresh offline run (1 figure) |
50-model-comparison-and-calibration (the memoising one) |
executed exit 0; matches a fresh offline run (2 figures) |
| thread-race probe, 8×200 calls × 5 trials | 1600/1600 each, 0 returned:false entries |
Env C — uv venv --python 3.10 + .[dev,live]
| check | result |
|---|---|
pytest tests/test_live_sdk.py |
62 passed (SDK mocked; no network) |
pytest (full, with live extra) |
4982 passed, 44 skipped, 50 deselected, 31 xfailed |
(These reproduce the PR body's own numbers — 4919/46/50/31, 62, 569 files — exactly, so the PR's
"Verification" section is honest about what was measured, per CONTRIBUTING.md §2.)
Artefacts: /workspace/worktrees/_scratch/review-298a/{adversarial.py, mutate.sh, probe.py, probe2.py, guard_head.txt, guard_main.txt, o_head.txt, o_main.txt}.
OPUS-REVIEW: APPROVE f8878a1
Refs #80
What this is
Adds an optional
AuditedBackendwrapper (src/jev_cookbook/accounting.py) that counts thedecide()calls a notebook actually makes separately from the distinct replay-fixture keys those calls resolve to, and rewrites the recipe guard's README-budget check to use it. Nothing existing changes unless a notebook opts in: no backend, recipe, fixture or notebook is modified.Why: a recipe that decides the same state more than once (repeats, retries, comparison arms) makes more calls than the replay file has entries. The old guard compared a README's stated call count to
len(responses.json), which is the distinct-key count, so it could pass while the notebook made a different number of real calls (recipe 36's earlier measurement: 290 calls against 72 distinct states).decide_calls: how many timesdecide()was invoked (a call that raises counts, withreturned: false).distinct_requests: how many unique replay keys those calls had; this is the number a fixture file can match.returnedflag: no responses, contents, credentials or timing. A request that fails replay-key validation never reaches the backend and is not counted.decide()calls, not HTTP attempts; it is separate from the live backend'srequests_made.tests/test_recipe_guard.py: the README-budget check now requires, for an audited notebook, "makes exactly N calls" to equaldecide_callsand the distinct keys to equal the keys inresponses.jsonexactly; an unaudited recipe keeps the oldlen(responses.json)check, and a malformed audit fails rather than falling back to it.docs/backends.md,docs/live.md.Verification
The change is one commit (originally
9b9f73b, cherry-picked ontomainf00f56b with one docstring-only conflict resolved: the commit's rewritten bullet andmain'snoul_proposition_gold_coveragebullet both kept). 8 files, +782/-50, no recipe folder touched.pytest4919 passed / 46 skipped / 50 deselected / 31 xfailed on 3.10 (no SDK) and on 3.14;tests/test_live_sdk.py62 passed with the SDK mocked; ruff, hygiene (569 files),render_catalog --check,notebook_ci.py fixtures,fixtures validate --allclean.AuditedBackendyet, so no printed count moves).