Skip to content

test(store): pin the PHI-at-rest assertion FORM with a negative control - #171

Closed
wshallwshall wants to merge 1 commit into
mainfrom
claude/at-rest-assertion-negative-control
Closed

test(store): pin the PHI-at-rest assertion FORM with a negative control#171
wshallwshall wants to merge 1 commit into
mainfrom
claude/at-rest-assertion-negative-control

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

One new file, +106. Closes a review gap on the PHI-at-rest work: the check that justified changing those assertions existed only as a throwaway rig, so the property it established was unpinned.

That matters because of what the change looks like from the outside. The old assertion was flaky — roughly 1 red CI leg in 2,222 per assertion on correct encryption. The obvious response to a flaky assertion is to weaken it until it stops failing, and from a diff alone that is indistinguishable from strengthening it. The only thing that separates the two is a control proving the assertion still detects the leak it exists to catch. Without one committed, the next person to see a red leg can weaken it back and nothing stops them.

Four tests over the assertion FORM

  • The marker check alone does not detect a leak — a body carrying mfenc: while sitting in cleartext satisfies the prefix assertion completely.
  • Whole-plaintext absence detects a leak — the control proper: marker present, body never enciphered, assertion fails as it must.
  • It does not flake on real ciphertext — the deterministic half, over many random-keyed draws.
  • A short substring is not a substitute — asserted over the same draws, so it cannot pass by sampling luck: the substring form registers hits while the whole-plaintext form registers none.

Proven to fail: weakening the predicate back to a short-substring check turns the last test red.

Why it is a separate branch rather than a commit on the PHI PR

That PR is armed. Pushing to an armed branch that may be deleted on merge is how a stale pre-squash ref got recreated earlier today — a branch carrying six already-merged commits whose three-dot diff read as 6,937 insertions. New file, no overlap with the other branch's edits, so the two land in either order.

No ledger token: this is a follow-up to an item, not an item.

…tive control

Closes a review gap the coordinator raised on PR #168: the "against a simulated leaking
store the new assertion fails" check was the single most important claim in that change
-- it is what separates strengthening an assertion from silencing one -- and it existed
only as a throwaway rig. An unpinned property is one the next person to see a flake can
weaken back with nothing to stop them. Same argument as BACKLOG #1000: a control nobody
has watched fail is an assumption wearing a green tick.

Four tests, over the assertion FORM rather than the store:

  1. the marker check alone does NOT detect a leak. Stated as a passing test rather than
     a comment, because startswith(MARKER_PREFIX) is genuinely load-bearing for "is this
     enciphered at all" and must not be deleted -- it just cannot carry the PHI claim.
  2. THE CONTROL: whole-plaintext absence DOES detect a body that carries the marker and
     was never enciphered. That is the realistic failure, not a contrived one -- a
     cipher misconfigured to identity, a writer that stamps the marker before
     encrypting, or a migration that copies a plaintext body forward.
  3. it does not flake on real ciphertext (200 real tokens, real key). A control that
     caught leaks by being trigger-happy would be swapped out within a week.
  4. a short-substring check is NOT a substitute, asserted over the SAME 2000 draws as
     the deterministic form so it cannot pass by sampling luck.

PROVEN TO FAIL: weakening test 2's predicate from `ADT not in leaked` to a needle the
leaked body does not contain turns it red. Restored, 4 pass, ruff clean.

Deliberately a SEPARATE FILE from test_store_encryption.py. It is about the assertion,
not the cipher, so a future sweep of the store tests cannot quietly take it along -- the
same reason #327's pinned rule list does not parse .gitignore.

Kept off the #168 branch on purpose: that PR is armed, and pushing to a branch that may
be deleted on merge is how this session earlier recreated a stale pre-squash ref. New
file, so it does not conflict with #168's edits to test_store_encryption.py and can land
in either order.
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Superseded by #177, which batches this with the other two small code changes into one CI cycle.

Nothing is dropped — this commit is carried across verbatim in #177. Closing rather than leaving it open because strict: true makes every open PR pay a full ~32-minute re-run each time anything else merges, so N open code PRs cost ~N sequential cycles. Three separate PRs was ~96 minutes of serialised draining for ~290 lines; batched it is one cycle. #175 had already gone DIRTY from that pressure.

🤖 Batched by Claude Code

auto-merge was automatically disabled August 4, 2026 14:09

Pull request was closed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant