Changing what "done" means for a prompt, on the record.
An amendment adds, removes, or modifies a clause of a prompt's verify contract. It is the one capability in this program that can make a completed prompt mean something other than what the packet says, so it is governed more tightly than steering, which cannot.
Timing is part of the meaning
Claims in these programs are pre-registered by git commit timestamp precisely so nobody can decide what they were proving after seeing the result. An amendment that weakens a contract after a verify failure is exactly the move pre-registration exists to prevent. So the record distinguishes:
:pre_verify— before any verify attempt has run. Ordinary scope correction.:post_failure— after a verify failure. Suspect by default.:post_success— after a verify pass. Also after the fact, and named honestly rather than folded into either of the other two.
An amendment log that does not say when, relative to verification is not an audit trail.
Asymmetric by design
Adding a requirement is routine. Removing or relaxing one is the risky
direction, and takes a different verb — PromptRunner.Control.relax/3, with
an explicit confirmation — never a different argument to the same command.
Run-local by default
The packet file stays authoritative. A future re-run from clean state uses the original contract. Writing back to the packet is a separate explicit act, because a packet is a versioned artifact and editing it is a commit, not a side effect.
Summary
Functions
Appends one amendment to the prompt's amendment log.
Builds an amendment record, refusing the ones that must not be silent.
A readable packet-versus-enforced diff for one prompt.
Applies every recorded amendment for a prompt to its packet contract.
Every amendment recorded for one prompt, oldest first.
Types
@type phase() :: :pre_verify | :post_failure | :post_success
@type t() :: %{ :at => DateTime.t(), :prompt_id => String.t(), :author => String.t() | nil, :reason => String.t(), :phase => phase(), :direction => :add | :relax, :clause => String.t(), :operation => :add | :drop | :replace, optional(:entries) => [term()], optional(:run_id) => String.t() | nil, optional(:persisted) => boolean() }
Functions
Appends one amendment to the prompt's amendment log.
Builds an amendment record, refusing the ones that must not be silent.
A missing reason is refused rather than defaulted: an amendment with no stated reason is not an audit trail entry, it is a hole in one.
A readable packet-versus-enforced diff for one prompt.
If you cannot show the diff, you do not have the audit.
Applies every recorded amendment for a prompt to its packet contract.
This is what the verifier is handed. The packet's own contract is never mutated in place — it is the input to this function, and re-reading the packet gives it back unchanged.
Every amendment recorded for one prompt, oldest first.