# IHVRK findings register

Defects found while building and testing IHVRK, newest last. "Test bug" rows are mistakes in the tests, kept
because hiding them would overstate how clean the first run was.

| ID | Found by | Defect | Severity | Fix | Regression test | Retest |
|---|---|---|---|---|---|---|
| F-001 | first ledger verification | Ledger records mixed two time bases: the OS clock in the ledger, the trusted clock in the service. The verifier reported CLOCK_REGRESSION on a valid run. It came back in the cross-process test, where child writers used the OS clock. | Low (false alarm, but it would hide real regressions) | `AppendOnlyLedger(clock=…)`: every record uses the deployment's trusted clock; fallback records are labelled `system-fallback` | `test_flow::test_happy_path…` (ledger ok), `I9` | pass |
| F-002 | race test D4 | Duplicate deliveries of a valid approval each counted as a "rejected attempt" once the winner had consumed the nonce. After 5 of them, `stop()` moved the request DENIED while the winner was mid-authorization. Fail-closed, but honest retries could kill a valid request. | Medium (liveness) | attempts can deny only from `AWAITING_HUMAN` (`stop(only_from=…)`, checked inside the transaction) | `D4` (12 concurrent duplicates → exactly 1 permit) | pass; mutant M28 killed |
| F-003 | runtime test F8 | Gatekeeper PID-reuse check accepted a **zombie**: after the frozen process was killed, its pid, start time and cgroup line stayed until its (frozen) parent reaped it, and the gatekeeper thawed the cgroup on AUTHORIZE. | Medium | `pid_start` treats state `Z`/`X` as gone; the cgroup stays frozen (exit 12) | `F8` | pass |
| F-004 | mutation testing, run 1 (25/30) | Four security checks had no test that failed when they were removed: M10 (UNKNOWN status carrying an authorizing model), M14 (gate audience), M17 (verifier approving a request made under its own id), M18 (low AAL rejected before the challenge is consumed). | Medium (untested guards) | tests added | `H9`, `D11`, `E7`, `A12` | 30/30 killed |
| F-005 | mutation testing | Mutant M08 was *equivalent* (`now−u ≥ exp` rewritten to `now ≥ exp+u`), a defect in the mutation tooling, not the code. | – | replaced with a real removal | – | killed |
| T-1 | unit run 1 | Test bug: expected DENY at `now = expiry` with uncertainty 2. The correct answer is INDETERMINATE, because the true time may still be before expiry. Both block. | – | boundary expectations corrected (DENY from `now ≥ exp+u`) | `test_single_fault[now-*]` | pass |
| T-2 | adversarial run 1 | Test bugs: floats inside bodies that were then signed (signing correctly refused them); H6 case `expires_at=2^52` expected a denial, but the approval is capped by the request deadline by design. | – | floats injected after signing; cap asserted explicitly (`H6c`) | `B1`, `H6b`, `H6c` | pass |
| T-3 | runtime runs | Test races: a non-atomic decision-file write (the gatekeeper read an empty word and correctly stayed frozen), and SIGKILL sent before the freeze completed. | – | atomic `os.replace`, wait-for-frozen | F1, F4, F6, F12 | the remaining intermittent failure was traced to F4/F12 fixed sleeps; after the fix 15/15 runs pass |
| O-1 | TLC `no_nonce_consume` | Not a defect: removing nonce consumption does not break safety in the model, because the request-state CAS already prevents a second acceptance. | – | documented as defence in depth | – | – |
| P-1 | process | The first IHVRK commit (56d7cfe5) was made by a command that did not gate on the test result, while one run had a failing runtime test (F12 timing). The commit was local and unpublished; the cause was fixed in the next commit. | – | commit only after a green run | – | – |
