# One mortar response per delivered observation The first firing experiment exposed a second order for the same unchanged observation after the native activity was cancelled. A cooldown alone does not make a report new. Each physical battery now owns a bounded ledger of attempted report message IDs, retained through cancellation and activity completion. Scheduling checks report eligibility before creating a downlink; `BeginRequest` claims it before cancelling an older order or incrementing the order ID. A failed/interrupted delivery consumes that battery's attempt at that observation. A newly observed and actually delivered report has a new HQ message ID and can authorize a later attempt; the code never renews observation timestamps. Different batteries maintain independent histories, although the current authored mission has one battery. Entries expire only after the original report is older than the unchanged 60-second report lifetime. The ledger rejects future, negative and stale observation times, invalid message IDs and excessive live entries. Its 128-entry bound exceeds the HQ's 64 retained contacts; a full ledger fails closed until entries expire. Each new mission owns a fresh ledger. `test_mortar_report_ledger.py` executes the actual availability/claim bodies, including repeated reads without a claim, A/B/A replay, attempted timestamp renewal, exact freshness boundary, expiry pruning, capacity and fresh-round ownership. Scheduler ordering is also checked. The new native `mortar-expiry` fixture retains an unchanged report while HQ continues running; its native result is still pending at this document's initial checkpoint. This is not full salvo, hit accuracy or multiplayer qualification.