# PR #4 (H70, per-action isolation) — what I checked myself

Reviewed 2026-09-10, session 42, against `f459881`. Two scripts, both run from
the root of whichever checkout you point them at, so the same file answers the
question on `main` and on the branch.

    python research/hesper/pr4-review/broken_tent_turn.py
    cd research/hesper/pr4-review && python report_delivery.py

## 1. Does a tent whose `state_json` is not JSON kill a real turn?

The PR's own upkeep tests call `upkeep.run` directly. The defect is *the
boundary dies*, and only `turn.resolve` can show that, so this goes through the
real runner.

| | `main` | PR #4 |
|---|---|---|
| `turn.resolve` | `JSONDecodeError` | resolved |
| `current_turn` after | NULL (never advanced) | 1 |
| tent `state_json` | preserved | preserved |
| food in the unreadable tent | 2 (untaken) | 2 (untaken) |
| owner's `ap_budget` | 10 | 10 |
| report notices | — | `upkeep_meal_data_error` |

The claim holds. The turn survives and the bytes are not repaired, which was
the condition: a phase that rewrites what it could not read destroys the
evidence.

## 2. Does the citizen ever read the notice?

No — and not for the reason the branch's spec gives. On the branch,
`reports.build` over the same world raises **`JSONDecodeError` at
`reports.py:206`**: `status_line` parses every thing on the citizen's tile with
a bare `json.loads`. Reports are rendered outside the turn transaction and
inside a `try` (`turn.py:297`), so the turn still commits; the price is one
line on stderr and no report for anybody that turn — including the citizen the
notice was written for.

Soften that one parse and the same build then raises `OperationalError:
malformed JSON` from `_carried`, which is H72. So report delivery needs **both**
fixes, and the branch's sentence — "full report delivery depends on resolving
H72" — is incomplete: H72 alone leaves the report broken.

## 3. The AP sentence

`actions.ap_budget_of` returns `min(ap_budget, ap_newcomer)` = 5 for the
batches targeting `landed+1 … landed+4`. The notice, the event's `ap_next` and
the spec paragraph all say the budget "remains 10" — to the citizens most
likely to hold a fresh malformed tent, since `land()` creates it.

Full review: parley `hesper` #68.
