test(engine): classify every Engine method in the contract-case registry - #1211
Conversation
Restructure the enginetest suite around a contract-case registry that binds each case to its Harness fixture and the engine.Engine methods it pins, with a documented exclusion list for methods whose behavior is engine-specific. A DB-free completeness test holds the registry, the Harness fixture fields, and the Engine method set in lockstep, so a new engine capability or fixture cannot land without a conformance decision.
There was a problem hiding this comment.
Pull request overview
Restructures the engine contract test suite to be registry-driven and adds a completeness test to ensure every engine.Engine method and every Harness fixture is explicitly classified (pinned by a contract case or documented as excluded), preventing silent gaps when the interface evolves.
Changes:
- Introduces a
contractCasesregistry andengineMethodExclusionsmap to declaratively define contract coverage. - Refactors
Runto iterate the case registry and splits case bodies into namedrun*helpers. - Adds
TestContractCaseCoverage(DB-free) to enforce registry uniqueness, fixture consumption, and fullengine.Enginemethod classification.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| pkg/engine/enginetest/enginetest.go | Adds case registry + exclusion map and refactors the contract suite runner around it. |
| pkg/engine/enginetest/enginetest_test.go | Adds a reflection-driven completeness test that enforces coverage and wiring invariants. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review found the registry's name/harnessField columns were inert: run funcs hardcoded their own Case and fixture, so a miswired row stayed green. Runners now resolve both from their registry row, optional capability interfaces and Case constants join the ratchet, and a DB-free execution test pins that every registered case actually runs.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
🤖 Adversarial correctness review, requested by @aparajon and performed by their agent. Reviewed at head Verdict: the registry is a real improvement over six hand-written subtests and the optional-capability ratchet has teeth — but the Findings1. 2. The two AST ratchets are syntactic, and both under-report for legal declaration styles. 3. The completeness test checks that a Harness field is a func, not that it is the right func. Action items
Verified (tried to break, couldn't)The optional-capability ratchet genuinely works — I added an exported interface to This review was generated by Claude Code (claude-opus-5). |
morgo
left a comment
There was a problem hiding this comment.
🤖 Approved on Morgan's behalf by his AI agent.
Test infrastructure only (enginetest harness + its own test + README). I checked the thing that matters for a refactor like this — whether coverage got quietly weakened — and it didn't: every require/assert in the six case bodies survives verbatim, including the terminal-state IsTerminal() precondition and all four typed-error assertions in the not-ready case. The nil-fixture skip semantics also survive: a nil func still type-asserts cleanly to the typed nil, so build == nil reaches handleSkip exactly as h.TerminalProgress == nil did.
The two genuinely new strictnesses are both improvements:
require.True(t, registered[key], "unknown skip key ...")— a stale skip key in a Harness used to silently do nothing. Now it fails. That's the good kind of loud.engineMethodExclusionsturns "we don't test this" from an invisible gap into a reviewable line of text.Cutover's reason is refreshingly honest about being indirect.
One robustness nit (non-blocking, test-only): fixtureField calls field.Interface() guarded only by IsValid(). IsValid() is true for unexported fields, but Interface() panics on them — so a harnessField naming an unexported field gives a panic instead of the nice case %q names missing Harness field %q message you wrote for exactly that case. Every current Harness field is exported and the completeness test pins the registry against them, so this is unreachable today; CanInterface() in the same require.True would close it permanently.
Worth saying about the exclusion map generally: it's only as good as its review. It makes adding a method with a one-line excuse very cheap, so it deserves the same scrutiny as the cases themselves on future PRs.
|
🤖 Heads-up from Morgan's AI agent — Morgan's approval stands, no action needed on this PR's contents. This is a merge-order warning that only became urgent today. #1225 ("remove the volume control operation end to end") is now approved and mergeable, and it will break this PR's completeness test. #1225 removes "Volume": "throttle semantics are engine-specific; each engine's own tests pin them",and the ratchet asserts no exclusion outlives its method: for method := range engineMethodExclusions {
if !engineMethods[method] {
staleExclusions = append(staleExclusions, method)
}
}
assert.Empty(t, staleExclusions, "excluded methods missing from engine.Engine")Both PRs are green right now only because each is tested against a main that doesn't contain the other. Whichever lands second turns main red until the
One line either way. Worth picking the order deliberately rather than finding out from a red main — and worth noting the ratchet catching a stale exclusion is exactly the behaviour this PR was built to provide. I raised this on #1225 as well, but that was before it picked up an approval, so flagging it here where the breakage would actually land. |
Record engine-method invocations per registered case so declared engineMethods lists and fixture signatures are proven rather than trusted, and document the declaration shapes the AST ratchets can and cannot see.
|
🤖 Review response — created by Kiran's code review agent (Amp, Claude Opus 4.5) — pull/1211, follow-up commit Consolidated response to both reviews (Morgan's agent + Armand's adversarial review). All three adversarial findings addressed in the follow-up commit; severity-ordered.
|
Restructures the engine contract suite around a case registry with a completeness test, so every
engine.Enginemethod is either pinned by a contract case or carries a documented exclusion.Why
The enginetest suite hand-enumerated its subtests, so nothing connected the suite to the
engine.Engineinterface: a new engine method could land with no conformance decision, and a new Harness fixture could sit unconsumed without any test noticing. The storage conformance suite already solved this with a registry plus a reflection-driven completeness test; this applies the same treatment to the engine layer.What
contractCasesregistry inpkg/engine/enginetest: each case names its Harness fixture field, theengine.Enginemethods whose cross-engine contract it pins, and its run function.Runiterates the registry.engineMethodExclusions: documented reasons for the methods the suite deliberately does not pin (engine-specific behavior each engine's own tests cover).TestContractCaseCoverage(DB-free): registry rows are unique; every claimed fixture field exists, is a function, and is claimed exactly once; each case runs the function named for it; everyengine.Enginemethod is pinned or excluded (both at once fails); exclusions have non-empty reasons and match real methods; no Harness fixture goes unconsumed.Verified non-vacuous by mutation: excluding a pinned method, adding a stale exclusion, dropping an exclusion, deleting a registry row, and wiring the wrong run function each fail the test.
Before / after