fix(test): one window predicate, called by the tool and by the fixture #30
No reviewers
Labels
No labels
waiting-on-julian
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/carddav-mcp!30
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/window-predicate-shared"
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?
Held for your review. Not merging this one.
Reproduced your mutation on my tree before changing anything:
days_until > params.days→>=atsrc/mcp.rs:593, 107 passed, 0 failed. The gap isexactly as you describe.
Why it survived
src/birthday.rsfiltered withdays_until(b, today) <= daysin the fixturebody while the tool compared
days_until > params.daysinline. Twoimplementations of one decision, so the test exercised its own copy and the
tool's was covered by nothing.
within(30) == 3was true of a correct call siteand of a broken one alike.
The predicate
birthday::within_window(&bday, today, days) -> Option<u32>is now the onlyplace that comparison is written. The tool calls it; the fixture calls it.
remaining <= days→remaining < dayswithin_window_includes_the_last_day_and_excludes_the_nextandthe_thirty_day_window_answers_where_the_fourteen_day_window_is_emptyboth failremaining <= days→remaining <= days + 1Tightening and loosening both bite, so the boundary is pinned from both sides
rather than only against being too strict.
Extraction alone would not have closed it, and this is the part I would not
have done unprompted
After extracting, I put the inline comparison back at the call site,
bypassing the predicate. All 108 tests passed. One predicate is not a
guarantee that one predicate is used.
So
days_untilis now private. The same bypass no longer compiles:Reintroducing the drift now requires re-exporting it, which is a visible change
in a diff rather than a one-character edit. That is a narrowing rather than a
proof: nothing at the unit level can stop someone who changes the visibility
too, and driving the tool handler itself would need a mock CardDAV server and an
rmcp request context, which is a larger piece of work than this defect warrants.
Verification
fmt, clippy
-D warnings, 108 tests,cargo deny, all green atad7d4425.No behaviour change. The deployed filter is identical to the one
v0.1.6ships, so the tag stands, the running image is untouched, and the live 30-day
answer is still 3. What changed is that the number is now pinned.
Recorded in
AGENTS.mdas the general form: a test that reimplements acomparison tests its own copy, and the repair is one predicate both sides call
plus the visibility that stops the second copy coming back.
108 passed at
ad7d442in my own run, and all three checks behave as described.The loosening reds the live-pair fixture as well as the boundary test, which is what makes it a pin on the number the acceptance turns on rather than only on the helper.
And the bypass now fails to compile rather than passing quietly. That is the whole of what the extraction bought once you found extraction alone did not close it.
The finding is worth more than the fix and it is yours
You extracted, put the inline comparison back, and 108 passed. I would have shipped the extraction believing it closed. One predicate is not a guarantee that one predicate is used, and nothing in the extracted form makes a bypass visible.
Calling the privacy a narrowing rather than a proof is the right register. Someone changing the visibility gets there again, and it is a visible change rather than a one-character one, which is the property being bought.
Declining to drive the tool handler is right too. A mock CardDAV server and an rmcp context to pin one comparison is a cost that buys a second thing to be wrong about.
No behaviour change
v0.1.6stands, the image is untouched, the live 30-day answer is still 3. What changed is that the 3 is now pinned.Merging.