Establish INTENT, Stage 1 GOAL, and founding workplan
Claim ownership of the browser-facing approver UI that approval-engine deliberately does not contain. approval-engine's INTENT names an approvals inbox under Non-Goals, and docs/keycape-service-registrations.md records that the human approver client's client_id and callback URI "must come from its owner once it exists" — leaving key-cape's KEY-WP-0013-T02 blocked on an unassigned component. - INTENT.md: Decision Memo concept, the binding/awareness split and the two hashes, ownership and non-ownership against the named estate repositories, and a provisional PEP-shaped layer placement flagged for a gate-house ruling rather than asserted. - GOAL.md: Stage 1 is the L3 approval approver surface — the narrowest real consumer with a live blocking dependency — plus the written answer to who owns the approver UI. - workplans/INFD-WP-0001: founding documents, the gate-house layer/ownership ruling, the four specs (PRD, UseCaseCatalog, ArchitectureBlueprint, EvidenceModel), schema and canonicalizer promotion out of history/ with the isolation vectors under test, the key-cape client registration, and a walking skeleton that includes return and discuss. history/ is preserved unmodified as provenance. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V3W1dQG7GFFM9d94jFx7iR Assistant: claude-code Assistant-Model: opus Assistant-Process: 1565372@bnt-lap001 Assistant-Session: 16bb2f25-b34c-49ef-8e94-5fec3567a568
This commit is contained in:
parent
771ddb9ced
commit
ee2cca579c
16 changed files with 3218 additions and 1 deletions
149
history/20260909-initial-exploration/decision-memo-schema.md
Normal file
149
history/20260909-initial-exploration/decision-memo-schema.md
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
# Decision Memo object schema v0.2
|
||||
|
||||
Machine-readable schema: `decision-memo.schema.json`
|
||||
Worked example: `decision-memo.example.json`
|
||||
|
||||
The Decision Memo is one object at every depth (L0 login banner through L5 multi-party instrument). Depth changes which fields are populated, not which types exist.
|
||||
|
||||
## 1. Object graph
|
||||
|
||||
```
|
||||
DecisionMemo
|
||||
├── requester / subject / parties[] identity + mandate
|
||||
├── question + requested_act + binding_level what is being asked
|
||||
├── brief + consequences
|
||||
├── identity_context.binding PRE-SIGN identity + scope (in view_hash)
|
||||
├── identity_context.awareness hats, last-used, other tenants (awareness_hash)
|
||||
├── session POST-SIGN live hat inside the bound scope
|
||||
├── packet[] files, hashed
|
||||
├── highlights[] pointers into packet
|
||||
├── route.steps[] Laufweg / Zeichnungsleiste
|
||||
├── thread[] discussion stays on the object
|
||||
├── presentations[] what each actor was shown
|
||||
├── dispositions[] comment | return | forward | accept…
|
||||
├── relations[] supersedes / relates_to
|
||||
└── evidence hash-chained event log + optional seal
|
||||
```
|
||||
|
||||
## 2. Lifecycle
|
||||
|
||||
```
|
||||
draft
|
||||
→ submitted
|
||||
→ circulating / awaiting_actor / in_discussion
|
||||
→ returned ──(new version)──→ submitted
|
||||
→ completed (outcome set)
|
||||
→ withdrawn | expired
|
||||
completed ─(new memo)→ superseded
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Edits in `draft` bump `version` without a new `id`.
|
||||
- After `submitted`, content edits that change `brief`, `packet`, or `highlights` **must** bump `version` and invalidate unused presentations.
|
||||
- `return` sets status `returned`, does not mutate the sealed packet in place. Requester opens version N+1, which `supersedes` the circulation of N.
|
||||
- `forward` replaces the current step assignee. `escalate` adds or replaces a step of higher competence.
|
||||
- Terminal statuses: `completed`, `withdrawn`, `expired`, `superseded`.
|
||||
- `outcome` is only set when `status=completed` (or timed-out/cancelled mappings).
|
||||
|
||||
## 3. Invariants
|
||||
|
||||
I1. **One question.** `question` is a single present-tense sentence. If you need two questions, you need two memos.
|
||||
|
||||
I2. **Presentation binds the act.** Every `disposition` with verb in `{acknowledge, accept, decline, abstain, recuse, sign}` MUST reference a `presentation_id` whose `memo_version` equals the memo version at act time.
|
||||
|
||||
I3. **Dynamic linking.** Binding acts at `aes` or higher MUST set `signature.presentation_bound=true` and include `presentation.view_hash` in the signed attributes.
|
||||
|
||||
I4. **Required highlights.** If any highlight has `required_ack=true`, a binding act is invalid unless those ids are in `presentation.acked_highlight_ids`.
|
||||
|
||||
I5. **Mandate fit.** The actor on a `schlusszeichnung` / `sign` step MUST carry a `mandate` whose scope covers `requested_act` and any `legal` / value constraints.
|
||||
|
||||
I6. **Packet integrity.** `packet[].hash` is content-addressed. Replacing bytes is a new `item.id` (or a new item version + `replaces`).
|
||||
|
||||
I7. **Evidence is append-only.** `evidence.events[].event_hash = H(seq || type || at || payload_hash || prev_hash)`. `head_hash` is the last `event_hash`.
|
||||
|
||||
I8. **Agents may draft, not bind.** `party.kind=agent` may create highlights and brief text. Agents MUST NOT emit binding verbs.
|
||||
|
||||
I9. **Return is data.** `verb=return` requires `return.reasons[]`. Empty “please fix” is invalid.
|
||||
|
||||
I10. **Whole instrument vs excerpt.** Highlights never narrow the legal object. `legal` and the primary packet item define what is bound; highlights are attention, not scope.
|
||||
|
||||
I11. **Pre-sign vs post-sign.** `identity_context.binding` is in `view_hash`. `identity_context.awareness` is only in `awareness_hash`. Binding verbs sign the former. `configure` mutates `session` after bind and never rewrites `binding`.
|
||||
|
||||
I12. **Hats are not scopes.** A hat (`elevates=false`) is a perspective inside an already bound scope. A scope with `requires_new_bind=true` (other tenant, other identity, elevating hat) is a new memo.
|
||||
|
||||
I13. **Defaults are awareness.** `proposed_hat_source` of `last_used` or `system_default` must be shown and must not be silently copied into `view_hash`.
|
||||
|
||||
## 4. Disposition verbs
|
||||
|
||||
| Verb | Changes route? | Binding? | Required payload |
|
||||
|---|---|---|---|
|
||||
| comment | no | no | body |
|
||||
| discuss | may set `in_discussion` | no | body + optional transfer.to for requester |
|
||||
| return | yes → requester | no | return.reasons |
|
||||
| forward | yes → peer assignee | no | transfer.to |
|
||||
| escalate | yes → higher mandate | no | transfer.to + reason |
|
||||
| acknowledge | completes inform/review step | weak | presentation_id |
|
||||
| accept | may complete memo | yes | presentation_id + optional signature |
|
||||
| decline | may complete memo | yes | presentation_id + body |
|
||||
| abstain / recuse | completes step for actor | yes | presentation_id + reason |
|
||||
| withdraw | terminal | requester only | body |
|
||||
| stamp | no | system/org seal | signature on listed items |
|
||||
|
||||
## 5. Canonical `view_hash`
|
||||
|
||||
Serialize, UTF-8, JCS (RFC 8785), then hash:
|
||||
|
||||
```json
|
||||
{
|
||||
"memo_id": "...",
|
||||
"memo_version": 2,
|
||||
"question": "...",
|
||||
"requested_act": "accept",
|
||||
"binding_level": "aes",
|
||||
"brief": "...",
|
||||
"packet": [{"item_id":"...","hash":"sha256:..."}],
|
||||
"highlights": [{"id":"...","item_id":"...","locator":{...},"required_ack":true}],
|
||||
"ui_release": "informed-decision@0.3.1",
|
||||
"locale": "en"
|
||||
}
|
||||
```
|
||||
|
||||
That document is what “informed” means in the evidence bundle.
|
||||
|
||||
## 6. Evidence event minimum set
|
||||
|
||||
For a completed accept:
|
||||
|
||||
1. `memo.created`
|
||||
2. `memo.submitted`
|
||||
3. `packet.attached` (per item)
|
||||
4. `highlight.added` (per required highlight)
|
||||
5. `route.started`
|
||||
6. `identity.authenticated`
|
||||
7. `presentation.opened`
|
||||
8. `presentation.highlight_acked`
|
||||
9. `disposition.recorded` (accept)
|
||||
10. `signature.created` (if aes/qes)
|
||||
11. `timestamp.qualified` (if qes / long retention)
|
||||
12. `file.stamped` (per `is_to_be_stamped`)
|
||||
13. `bundle.sealed`
|
||||
|
||||
## 7. Field usage by depth
|
||||
|
||||
| Field | L0 login | L1 elevate | L2 ADR | L3 approval | L4 contract | L5 treaty |
|
||||
|---|---|---|---|---|---|---|
|
||||
| identity_context | required | required | optional | optional | rare | rare |
|
||||
| packet | optional | ticket + change | ADR + links | memo + annexes | contract + annexes | instruments + translations |
|
||||
| highlights | optional | blast-radius | rollback / cost | risk spans | clauses | reservations |
|
||||
| binding_level | acknowledgment / organizational | organizational | organizational / aes | organizational / aes | aes / qes | qes per party |
|
||||
| route | one step | requester → approver | review → accept | matrix | sequential/parallel signers | hybrid + deposit |
|
||||
| legal.form_requirement | none | none | none | none / textform | textform / schriftform | varies by party |
|
||||
|
||||
## 8. What is deliberately not in v0.1
|
||||
|
||||
- Full mandate-graph resolution (referenced by `mandate.policy_ref`, not modelled here)
|
||||
- Payment / consideration objects
|
||||
- Translation alignment and reservation semantics for L5
|
||||
- Raw PII in evidence (use `ip_hash`, identifier schemes)
|
||||
- UI widget tree — only `ui_release` + canonical view
|
||||
Loading…
Add table
Add a link
Reference in a new issue