Voucher Lifecycle States
The system has two separate state machines. They must stay separate in API, CLI, UI, and agent output.
Staged Operation State
staged_operations.status describes a proposed or reviewed action:
| Status | Meaning |
|---|---|
staged | Waiting for approval or operator review. |
approved | Approved and ready to execute/apply. |
executed | The operation has run. Check execution_reference_* for what it affected. |
rejected | Operator rejected it. |
failed | Execution failed. |
cancelled | Operation was cancelled. |
staged_operations.max_effect describes the strongest accounting effect the
operation is allowed to have:
| Value | Meaning |
|---|---|
draft | Applying can only create or update draft/review state. It must not post a voucher. |
post | Applying is allowed to post if the operation logic says it will post. |
max_effect=post is a cap, not a promise. Use
lifecycle.will_post from the staged-operation response to show whether this
specific operation intends to post.
Ledger Entry State
ledger_entries.status describes an actual voucher/ledger entry:
| Status | Meaning |
|---|---|
draft | A ledger-entry draft exists and can be reviewed or posted. |
posted | The voucher is posted. |
partially_cleared | Posted voucher is partly cleared against bank/payment state. |
cleared | Posted voucher is fully cleared. |
reversed | Voucher has been reversed. |
cancelled | Voucher was cancelled. |
archived | Voucher is archived from the active workflow. |
Derived API Lifecycle
Staged-operation responses include lifecycle to connect the two state
machines without merging them:
| Field | Meaning |
|---|---|
stage | Derived stage such as staged_create_proposal, staged_operation, ledger_entry_linked, or terminal_without_ledger_entry. |
ledger_entry_id | Actual ledger entry id when one is known. |
ledger_entry_ref_source | entity_id or execution_reference, showing where the ledger entry id came from. |
voucher_materialized | True only when a ledger-entry row is known. |
will_create_entry | True when the preview says applying will create a ledger entry. |
will_post | True when the preview says applying will post. |
needs_apply_to_create_draft | True for the proposal state: there is no draft yet, and apply is needed before the draft appears in ledger/bookkeeping views. |
The receipt-create proposal shape is:
{
"status": "staged",
"entity_type": "ledger_entry",
"entity_id": null,
"max_effect": "post",
"preview": {
"accounting_effect": {
"will_create_entry": true,
"will_post": false
}
},
"lifecycle": {
"stage": "staged_create_proposal",
"voucher_materialized": false,
"needs_apply_to_create_draft": true
}
}
That is not a ledger-entry draft. The UI and CLI must label it as a proposal that still needs apply before a review draft exists.
UI Display Rule
Materialized ledger rows must display only ledger_entries.status as the
current voucher state. A row may say Posted only when the materialized ledger
entry status is posted.
Preview rows are different: operation_preview_entities.row_payload.status
describes the proposed after-state of a staged operation. For example, a staged
accounting_entries.post operation can have preview status posted while the
actual ledger entry is still draft. The UI must label that preview as
Will post, not Posted.