jouleclaw-diagnose: a cross-model panel, so a verdict can rest on concurring models, or say they did not concur #277
Merged
dcharlot
merged 1 commit from 2026-10-16 09:41:50 -04:00
feat/diagnose-panel-entailer into main 2026-10-16
jouleclaw-diagnose: a cross-model panel, so a verdict can rest on concurring models, or say they did not concur
All checks were successful
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 59s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 34s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 5s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 1m7s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 3m9s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m11s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 54s
`Backing::Concurring` and `Backing::Contested` were in the schema, and `require_substantive_grounding` already accepted them. But nothing produced either: diagnose only ever declared one entailer's fixed backing. A verdict could never say "two independent models agreed", nor record that they did not. - `PanelEntailer`: at least two members, each a different model. Each consulted (claim, item) pair is put to every member, and the report carries every member's result under its own model id, so `require_substantive_grounding`'s check that the claim matches the evidence holds. - Its backing is read from the results (`Entailer::backing_of`): `Concurring` when every member gave the same label on every pair, and `Contested` when any two differed. A panel is only as substantive as its members. A fixture member makes the whole panel a fixture, and an unstated member leaves it unstated, so a stand-in's labels never become corroboration. - Grounding is unanimous per item: an item grounds a claim only when every result for that pair entails it. One model's "entails" no longer outvotes another's "neutral", and a claim some model entailed, without every model's agreement on an item, says `models_disagree: true`. A pair one member entails and another contradicts is the existing consistency conflict. - Single-model behaviour is unchanged. Each pair has one result, so "every result entails" is "it entails". The new detail key appears only where a panel split, so a single model's report keeps its bytes. The trait's two new methods are provided, so existing entailers are untouched. Co-Authored-By: Claude Opus 5.5 <[email protected]>