evalkit filter slot key omits against, so two role-fit cases can silently drop one #267
Labels
No labels
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agent-compose#267
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Outcome
Add
againstto the competition slot key inevalkit/filter.py, so two role-fit cases for one role cannot collide and lose a case to a silent drop.Found on 2026-08-11 during the ops pilot slice of the #262 board. Read at
evalkit/filter.pyonmain.What the slot key is for
filter.rungroups candidate variants into slots, keeps the variant whose failure count sits closest to the midpoint, and records every loser aslost slot <slot>. The slot is what says "these two samples compete for the same board position".filter.py:121:againstis not in that tuple. For a role-fit sample,boundary,half, andtraitare allNone, so the key reduces to role, test type, and target text.The failure
Every role carries three role-fit cases: one within-role and two against declared adjacents. Their slots are distinguished only by their
targetstrings differing.Two role-fit cases for one role that happen to share a target land in the same slot. The filter then treats four candidates as competitors for one position, keeps one, and reports the other three as
lost slot. A whole board position disappears into a line that reads like normal item analysis.The drop is reported, so this is not silent truncation in the sense
FilterReportguards against. It is worse in one way: the report says the sample lost a competition it was never meant to enter.Why the target is a weak key
_slotreadstargetbecause a target is a natural per-case string. It is prose written by a generator, and nothing enforces uniqueness across a role's three role-fit cases. Two adjacency edges with similar reasons invite similar targets. The ops pilot avoided it only because the three targets were written to differ.againstis the axis the case is actually about, androle_fitsamples already require it (schema.py:105).Fix
One line, plus a regression test that two role-fit samples for one role with an identical target and different
againststay in separate slots.Note on the boundary tier
Boundary samples are safe today, because
boundaryandhalfalready separate them. Addingagainstdoes not change their keys, since it isNonethere.Complete when
_slotcarriesagainst.againstrole-fit samples staying separate.ward exec evalkit-checkpasses.