Completion gate
The deterministic check a final reply has to pass before the task completes.
A final reply must claim goalSatisfied, report no remaining work, and cite the observations that did the work. The gate then checks the recorded facts: every required tool has a successful call, a required send has send evidence, a tool whose side-effect class changes something has a cited successful observation, and delivered attachments exist and validate. The gate decides by side-effect class, never by tool name.
When the contract names a result to grade, when a side-effecting tool is required or was called, or when the request carried an image, the gate is followed by the completion judge: a second model call that reads the ledger, may ask to expand up to eight observations, and returns missing work with reasons. A rejection stands until the ledger changes, so sending the same final reply again cannot reroll the verdict. When the judge itself fails, the ledger records completion_judge.degraded and the reply is accepted.
After two refusals with nothing done in between, the loop withdraws the final reply from the action schema; after three it offers both the reply and fail.