# Independent H79 review probes

Reviewed source: `2da38f74b9ce5feae0d129abe4e2770f5f65ddbb`. These probes demonstrate observed defects; a passing probe confirms the current defective outcome, not acceptance of the implementation. No H numbers assigned here.

Run from the repository root with the project's Python test dependencies:

```sh
python3 -B research/hesper/h79-review/runner_probe.py -q
python3 -B research/hesper/h79-review/arithmetic_probe.py
python3 -B -m unittest hesper.tests.test_h79_arrival hesper.tests.test_gather -q
```

The runner probe uses temporary synthetic worlds, a local loopback API, signed POST /api/actions submissions and the real turn runner. Arrival timestamps and malformed tool data are explicit fixture setup. No production databases or credentials are required. The arithmetic probe uses a seeded reference allocator and separate temporary SQLite phase fixtures. The portable runner probe explicitly stubs both sealing transports; no external network seals are attempted.

## Findings

1. **Equal sharing uses action count rather than citizen count.** `gather.py:435–442` creates one puller per action. Two citizens with identical arrival and equal four-pull demand split a six-unit stand 4/2 when one submits two two-pull actions and the other one four-pull action. Both plans pass real admission. Expected citizen-level sharing is 3/3.
2. **Failed-action rollback does not restore remaining resource memory.** `gather.py:505–507` decrements `left_on` before `_wear` at line 541. Valid JSON containing `worn_turn:"bad"` produces a caught ValueError; SQL rolls back, but the next action writes a quantity calculated from the decremented memory. Real runner: initial stand 4, first citizen receives 0, second receives 2, remaining stand 0. Two units disappear.
3. **The indivisible remainder follows submission time before hash order.** `gather.py:201–202` orders queued rows by `(at_ms, hash, idx)`; `allocate` uses that order for the remainder at lines 290–295. The SQLite phase fixture deliberately has the later submitted request sort first by hash, yet the earlier submission gets the sole unit. This reproduction exercises the real phase and queue, not the full runner.
4. **Equal old arrival cohorts are reported as arriving this turn.** In the first runner fixture both avatars arrived at turn 38 and gather after turn 40; report text nevertheless says “both arrived this turn.” Persisted split records omit the own-arrival value needed to distinguish it (`gather.py` contention record; `reports.py:474` wording). The first runner test can run after another test, so the exact resolving turn can be later than 41; the arrivals are old in either case.

## Results and boundaries

Initial verification: 2 runner probe tests passed in 0.753s, confirming findings 1/2 and checking finding 4; 10,000 arithmetic cases matched an independent unit-at-a-time water-filling reference. Conservation, demand caps, redistribution, earlier-arrival priority and unknown arrivals behaved correctly for unique action entries. Finding 3 is separately demonstrated after those clean arithmetic checks.

Existing H79/gather suite: 22 tests passed in 2.871s. These tests do not cover the demonstrated integration defects. Local Python 3.9.6 with cryptography available. No engine edits, migrations or hash-format modifications were made. This is a bounded allocation review, not a complete H79 or security audit.
