185 lines
8.9 KiB
Markdown
185 lines
8.9 KiB
Markdown
|
|
# Decision Memo state transitions v0.2
|
|||
|
|
|
|||
|
|
Actors: `requester`, `assignee` (current ready step), `party` (any listed party), `subject` (session principal after bind), `system`, `agent`.
|
|||
|
|
|
|||
|
|
Guards:
|
|||
|
|
|
|||
|
|
| Id | Meaning |
|
|||
|
|
|---|---|
|
|||
|
|
| G_STEP | Verb is in `route.steps[current].required_verbs` **or** is a always-on overlay verb for that step kind (table B) |
|
|||
|
|
| G_PRES | `presentation_id` exists, `memo_version` matches, `phase` is `pre_bind` or `bind` |
|
|||
|
|
| G_ACK | All `highlights[required_ack=true]` are in `presentation.acked_highlight_ids` |
|
|||
|
|
| G_MAND | Actor mandate covers `requested_act` + legal/value constraints |
|
|||
|
|
| G_LEVEL | Actor signature meets `step.min_binding_level` and memo `binding_level` |
|
|||
|
|
| G_REASONS | `return.reasons` has ≥1 coded reason |
|
|||
|
|
| G_TARGET | `transfer.to` is a resolvable party with compatible mandate |
|
|||
|
|
| G_ESC | Target mandate is *strictly higher* than current assignee for this act |
|
|||
|
|
| G_NOAGENT | `actor.kind ≠ agent` |
|
|||
|
|
| G_SESSION | `session.status = active` and actor is `session` subject |
|
|||
|
|
| G_HAT | `configure.hat.id` ∈ `awareness.available_hats` and `hat.elevates = false` |
|
|||
|
|
| G_PROMOTE | Field moved from awareness → binding; new memo version; presentations invalidated |
|
|||
|
|
|
|||
|
|
Overlay verbs (always available when status allows, even if not in `required_verbs`): `comment`, `discuss`.
|
|||
|
|
Requester-only overlay: `withdraw` while not terminal.
|
|||
|
|
System-only: `stamp`, expiry.
|
|||
|
|
|
|||
|
|
## A. Memo-level status machine
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
submit
|
|||
|
|
draft ──────────────► submitted
|
|||
|
|
▲ │
|
|||
|
|
│ │ route.started
|
|||
|
|
│ edit (ver++) ▼
|
|||
|
|
│ circulating
|
|||
|
|
│ │
|
|||
|
|
│ ├── first ready step → awaiting_actor
|
|||
|
|
│ ├── discuss → in_discussion
|
|||
|
|
│ │ │
|
|||
|
|
│ │ └── assignee resumes → awaiting_actor
|
|||
|
|
│ │
|
|||
|
|
│ ├── return → returned ──requester revises (ver++)──► submitted
|
|||
|
|
│ ├── last binding verb → completed (+ outcome)
|
|||
|
|
│ ├── withdraw → withdrawn
|
|||
|
|
│ └── due passed → expired (outcome timed_out)
|
|||
|
|
│
|
|||
|
|
└── completed ── new memo relation.supersedes ──► superseded
|
|||
|
|
|
|||
|
|
L0/L1 extra:
|
|||
|
|
completed + requested_act ∈ {login, elevate}
|
|||
|
|
→ session.status = active (bound_configuring window)
|
|||
|
|
→ configure / session.ended
|
|||
|
|
→ session.status = ended
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`in_discussion` is a substate of circulation. It does not reset the step.
|
|||
|
|
|
|||
|
|
## B. Verb × status × step kind
|
|||
|
|
|
|||
|
|
Legend: `✓` allowed · `—` forbidden · `C` allowed and may complete the step · `M` allowed and may complete the *memo* · `S` session-only after bind.
|
|||
|
|
|
|||
|
|
Step kinds are grouped:
|
|||
|
|
|
|||
|
|
- **Weak:** `inform`, `comment`, `review`, `acknowledge`
|
|||
|
|
- **Co-sign:** `mitzeichnung`, `approve`
|
|||
|
|
- **Bind:** `schlusszeichnung`, `sign`, `seal`, `deposit`
|
|||
|
|
|
|||
|
|
### B1. Status `draft`
|
|||
|
|
|
|||
|
|
| Verb | requester | assignee | agent | Effect |
|
|||
|
|
|---|---|---|---|---|
|
|||
|
|
| comment | ✓ | — | ✓ | thread only |
|
|||
|
|
| discuss | ✓ | — | — | stays draft |
|
|||
|
|
| withdraw | ✓ | — | — | → withdrawn |
|
|||
|
|
| accept / decline / acknowledge / return / forward / escalate / configure | — | — | — | not circulating |
|
|||
|
|
| submit (system/requester) | ✓ | — | — | → submitted |
|
|||
|
|
|
|||
|
|
### B2. Status `submitted` / `circulating` / `awaiting_actor` / `in_discussion`
|
|||
|
|
|
|||
|
|
| Verb | Weak step | Co-sign | Bind step | Guards | Status after |
|
|||
|
|
|---|---|---|---|---|---|
|
|||
|
|
| comment | ✓ any party | ✓ | ✓ | — | unchanged (`in_discussion` if was circulating) |
|
|||
|
|
| discuss | ✓ any party | ✓ | ✓ | — | `in_discussion` |
|
|||
|
|
| return | ✓ assignee | ✓ | ✓ | G_NOAGENT G_REASONS | `returned` |
|
|||
|
|
| forward | ✓ assignee | ✓ | ✓ | G_NOAGENT G_TARGET | stays circulating; step assignee replaced |
|
|||
|
|
| escalate | ✓ assignee | ✓ | ✓ | G_NOAGENT G_TARGET G_ESC | circulating; higher step inserted/activated |
|
|||
|
|
| acknowledge | C assignee | C | ✓ overlay | G_NOAGENT G_PRES G_ACK | step complete; memo completes only if this was the last step *and* `requested_act=acknowledge` |
|
|||
|
|
| accept | — | C assignee | **M** assignee | G_NOAGENT G_PRES G_ACK G_MAND G_LEVEL G_STEP | last bind/co-sign step → `completed` outcome=`accepted` |
|
|||
|
|
| decline | — | C assignee | **M** assignee | G_NOAGENT G_PRES G_STEP | → `completed` outcome=`declined` (memo ends; later steps skipped) |
|
|||
|
|
| abstain | — | C assignee | C assignee | G_NOAGENT G_PRES | step complete for this actor; parallel group may continue; if actor was sole bind step → `completed` outcome=`abstained` |
|
|||
|
|
| recuse | ✓ | C | C | G_NOAGENT G_PRES | step unassigned; must forward/escalate or return |
|
|||
|
|
| withdraw | requester only | same | same | not terminal | → `withdrawn` |
|
|||
|
|
| stamp | system | system | system | after a bind disposition or on completion | unchanged |
|
|||
|
|
| configure | — | — | — | not yet bound | — |
|
|||
|
|
| promote | requester | requester | requester | G_PROMOTE | version++; back toward submitted |
|
|||
|
|
|
|||
|
|
`accept` on a **weak** step is illegal. Weak steps take `acknowledge`. That is how Kenntnisnahme stays distinct from Schlusszeichnung.
|
|||
|
|
|
|||
|
|
### B3. Status `returned`
|
|||
|
|
|
|||
|
|
| Verb | Who | Effect |
|
|||
|
|
|---|---|---|
|
|||
|
|
| comment / discuss | any party | thread |
|
|||
|
|
| revise + submit | requester | version++; → submitted; new route from policy |
|
|||
|
|
| withdraw | requester | → withdrawn |
|
|||
|
|
| binding verbs | — | illegal on a returned version |
|
|||
|
|
|
|||
|
|
### B4. Status `completed`
|
|||
|
|
|
|||
|
|
| Verb | Who | Effect |
|
|||
|
|
|---|---|---|
|
|||
|
|
| comment | parties | thread; does not unseal |
|
|||
|
|
| stamp | system | file.stamped / bundle.sealed |
|
|||
|
|
| configure | subject | **S** session hat; see §C |
|
|||
|
|
| promote | requester | not on this version; open child memo |
|
|||
|
|
| accept / return / … | — | sealed |
|
|||
|
|
|
|||
|
|
If `requested_act ∈ {login, elevate}` then `session.status` becomes `active` at the completing accept/acknowledge.
|
|||
|
|
|
|||
|
|
### B5. Terminal `withdrawn` | `expired` | `superseded`
|
|||
|
|
|
|||
|
|
No actor verbs except system `stamp` of the evidence bundle already accumulated.
|
|||
|
|
|
|||
|
|
## C. Post-bind session transitions
|
|||
|
|
|
|||
|
|
Applies when `session.status = active`.
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
pre_bind presentation
|
|||
|
|
│ actor chooses identity + bind-scope
|
|||
|
|
│ sees proposed hat / other tenants as AWARENESS only
|
|||
|
|
▼
|
|||
|
|
bind disposition (accept | acknowledge)
|
|||
|
|
│ view_hash covers binding_slice only
|
|||
|
|
│ awareness_hash recorded alongside, not signed
|
|||
|
|
▼
|
|||
|
|
session.active
|
|||
|
|
├── configure(hat) if hat.elevates=false ∧ hat in available_hats
|
|||
|
|
├── attempt other scope
|
|||
|
|
│ requires_new_bind=false → still configure (same bind)
|
|||
|
|
│ requires_new_bind=true → emit scope.rebind_required, open child memo
|
|||
|
|
└── session.ended logout / expiry / revoke
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
| Event | In `view_hash`? | In `awareness_hash`? | Evidence event |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| Chosen identity | yes | copy ok | identity.authenticated |
|
|||
|
|
| Chosen bind-scope / tenant of *this* login | yes | copy ok | disposition.recorded |
|
|||
|
|
| Privileges granted *at the gate* | yes | preview ok | disposition.recorded |
|
|||
|
|
| Proposed / last-used hat shown | no | yes | awareness.shown |
|
|||
|
|
| Hat selected after login | no | yes | session.hat_selected |
|
|||
|
|
| Hat with `elevates=true` | must promote | — | promote + new bind |
|
|||
|
|
| Other tenant with `requires_new_bind` | no | listed | scope.rebind_required |
|
|||
|
|
|
|||
|
|
Defaulting the hat to `last_used` or `system_default` is an awareness act. Showing it on the login banner is required for situational awareness and forbidden from silently entering `view_hash`.
|
|||
|
|
|
|||
|
|
## D. Completing a step vs completing the memo
|
|||
|
|
|
|||
|
|
A step completes when the assignee records a verb in that step’s completion set:
|
|||
|
|
|
|||
|
|
| Step kind | Completion set |
|
|||
|
|
|---|---|
|
|||
|
|
| inform, review, acknowledge | acknowledge, return, recuse |
|
|||
|
|
| comment | comment (if so configured) or acknowledge |
|
|||
|
|
| mitzeichnung, approve | accept, decline, abstain, recuse, return |
|
|||
|
|
| schlusszeichnung, sign, seal, deposit | accept, decline, abstain, recuse, return |
|
|||
|
|
|
|||
|
|
The memo completes when:
|
|||
|
|
|
|||
|
|
1. A bind-step `decline` is recorded, or
|
|||
|
|
2. Every required step is `completed` or `skipped`, and at least one completing verb in the memo’s `requested_act` family was recorded, or
|
|||
|
|
3. Requester `withdraw`, or system expiry.
|
|||
|
|
|
|||
|
|
Parallel groups: all members must reach a terminal step status before the next ordinal becomes `ready`.
|
|||
|
|
|
|||
|
|
## E. Illegal combinations (explicit)
|
|||
|
|
|
|||
|
|
- Agent + any binding verb
|
|||
|
|
- `accept` on `inform`/`review`
|
|||
|
|
- `configure` before `session.active`
|
|||
|
|
- `configure` of a hat with `elevates=true`
|
|||
|
|
- `configure` of a scope with `requires_new_bind=true`
|
|||
|
|
- Binding verb whose presentation `phase=post_bind`
|
|||
|
|
- Binding verb whose presentation `awareness_hash` was substituted for `view_hash`
|
|||
|
|
- Mutating `identity_context.binding` after the first bind disposition of that version
|