test(environments): pin the suite scoring rule and document a red suite - #124
Conversation
HenryNdubuaku
left a comment
There was a problem hiding this comment.
The tests are good and pass with the case-insensitive scoring now on main. README and doc/environments.md conflict with main; rebase and I'll merge.
The rule that decides a suite's result — at least 90% passed with zero critical failures — was documented but untested, so it could have changed silently. These tests drive the harness through a stubbed engine that picks its reply from the query, which needs no native engine and so runs in CI. The 28-of-32 case is deliberately load-bearing: it separates the harness's round(0.9 * 32) == 29 from a floor variant, which would wrongly pass 28/32. Co-authored-by: CommandCodeBot <noreply@commandcode.ai> Signed-off-by: Som Samantray <som.samantray@gmail.com>
Review found three factual or mechanical defects, and one leak the tests themselves introduced. The measurement paragraph named `negation` among the failing categories, but re-measuring the six suites shows zero negation failures at either gate; the sentence now describes the spread it actually observed. Both doc sentences also over-claimed: a red suite can mean the reply contract is not what the harness expects, not only that the model missed, and only the threshold and the critical-flag effect are pinned. The module contract table stated the rule as a flat ">=90% pass", which `round(0.9 * len(TEST_CASES))` is not for every suite size, so it now states the rule the code computes. The aggregate test forced its one failing environment to the first name in the list, so an implementation that inspected only that module would still have passed; it now fails the last one. The fixture claimed NEEDLE_STRICT_VALIDATE so agent_for's setdefault cannot leak it into the rest of the process, and a new case pins that the confidence gate is a strict comparison, so a call exactly at the threshold is acted on. Also folds in the simplification pass: the fixture no longer fires telemetry per case (96 daemon threads and outbound requests per run, now zero), the query prefixes the stub branches on are shared constants rather than repeated literals, the dead `_library_path` patch and unused fixture return are gone, and the buffer's position in the variadic signature is documented. Co-authored-by: CommandCodeBot <noreply@commandcode.ai> Signed-off-by: Som Samantray <som.samantray@gmail.com>
doc/environments.md was deleted upstream in the Needle 3 restructure and its content folded into a terser llms.txt section that dropped the scoring rule, the min_confidence gate's refusal behavior, and the red-suite caveat. Restore that detail in llms.txt's style so the pinned contract (round(0.9 * n) cases, zero critical failures) stays documented somewhere a reader will find it. Signed-off-by: Som Samantray <som.samantray@gmail.com> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
b9e4717 to
dbd6ec0
Compare
|
Rebased onto |
Summary
The scoring rule behind the frozen acceptance suites is now pinned by tests, and its documentation states what a red suite reports. Issue #121 asked whether the six suites are meant to be green today; neither the package nor CI answered that, and the prior documentation described the rule without its consequence.
The rule — at least
round(0.9 * len(TEST_CASES))cases passed with zero critical failures, plus amin_confidencegate that treats a sub-threshold call as a refusal — was documented in detail but never exercised.tests/test_environments.pycovered schemas, case shape and tool execution, and its one engine-gated smoke test skips wherever no engine is installed, so a change to the rule would have shipped silently. The new tests drive the harness through a stubbed engine that picks its reply from the query, which needs no native engine and therefore runs in CI.They pin the accepted floor, the exact threshold (28 of 32 must fail, which separates
roundfrom a floor variant), thecriticaloverride, the strictmin_confidencecomparison, and the aggregate that ANDs all six.Rebased onto
main(2026-09-20) to resolve conflicts a reviewer flagged, caused by the "Needle 3" restructure landing after this PR was opened:maindeleteddoc/environments.md(anddoc/apis.md,doc/finetuning.md), folding a terser environments summary intollms.txt, and rewrote the README sections this PR had touched. Those now-stale README/doc edits were dropped rather than reintroduced.doc/environments.mdis instead folded intollms.txt's## Environmentssection, so the pinned contract (theround(0.9 * n)threshold, themin_confidencerefusal behavior, the red-suite caveat) stays documented in the file that replaced it.mainalso changed_harness.run_testsscoring to be case-insensitive (commit10fbeb5) and to fold integral floats to ints; this PR's tests are unaffected since they compare distinct values, not case or numeric-type variants — verified by re-running the full suite post-rebase (see Validation).Related: #121
Validation
NEEDLE_TELEMETRY=0 python3 -m pytest tests/test_environments.py -q— 31 passed, 1 skipped (engine-gated smoke test, expected without a native engine).maincheckout in the same environment for comparison:NEEDLE_TELEMETRY=0 python3 -m pytest -q -m "not slow" --continue-on-collection-errors.mainbaseline: 14 failed / 75 passed / 6 skipped / 12 deselected / 4 errors (all 14 failures are pre-existingModuleNotFoundErrors for optionaljax/pydantic, unrelated to this change). This branch: the same 14 failed / 81 passed / 6 skipped / 12 deselected / 4 errors — the 6 new tests pass, nothing regresses.roundtointin_harness.run_testsfails the 28-of-32 case. Makingenvironments.run_testsinspect only the first module fails the aggregate case. Changing the confidence gate's<to<=fails the threshold-equality case. The production files were restored after each and verified unchanged againstmain.The measurement was taken by running all six suites against the shipped base model on the cached engine 2.0.4 at both gates, and the per-category counts behind the new prose were re-measured directly rather than inferred.
Session-settled decisions carried from planning: correcting the documented contract rather than the suites (user-directed — the expectations are the product spec, and relaxing them would hide the acceptance gap); delivery as a fork pull request (user-directed — the contributing account has pull-only access upstream); a DCO sign-off on every commit (user-directed); folding the scoring-rule documentation into
llms.txtrather than recreatingdoc/environments.md(user-directed, made necessary by the upstream restructure).Unapplied review findings
function_callspresent,argumentsa dict, a numericconfidence). The stub fabricates that contract, so a drift between the engine and the harness would leave every new test green while the suites went red. A gate that compares aNoneconfidence raisesTypeErroron that path. Not applied: theNonepath is unreachable through_harness.agent_for, which builds an agent without weights, and changing the gate would alter untouched production behavior outside this plan's scope.Suggested fix: add cases whose envelope omits
confidenceand whoseconfidenceisnull, then make the gate total.criticalmapping and the order-insensitiveparallelcomparison are unpinned. Not applied: the page no longer claims the whole rule is pinned, having been narrowed to the threshold and thecriticaleffect, so this is a coverage gap rather than a false claim. Every synthetic case carries a single-elementcallslist, so the sorted-comparison branch never runs.min_confidence=0.4"the production contract" is pre-existing wording, but no shipped entry point applies it: every default is 0.0, includingpython -m needle.environments.<name>, so a reader who adopts 0.4 gets a different result from the one the page records. Not applied: shipping a way to select the gate is an API decision for the maintainers.roundagainstfloor; a 2-case suite diverges the same way. Kept deliberately: 32 mirrors the shipped suite size so the tests pin the documented 29-of-32 boundary, and with telemetry neutered each suite costs about a millisecond.needle/agent/fetch.py's pinned engine version changes would prompt a re-measurement.needle._libwith a plain Python object bypasses ctypesargtypescoercion, so an argument-order or argument-type regression betweenNeedle._completeandneedle_completewould not be caught here.test_grounding.py,test_weights.py, and this file) intotests/conftest.py. Not applied: it would edittests/test_grounding.py, which PR fix(grounding): stop rejecting thousands-separated numbers #123 modifies, and would exceed this plan's declared scope.Review run context: run_id
20260911-221145-7caa3fca, artifacts at/tmp/compound-engineering-501/ce-code-review/20260911-221145-7caa3fca/.