Add lifecycle registration and revisions with atomic packet uploads
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
parent
7ce1e589f7
commit
ee472acc87
10 changed files with 332 additions and 35 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# Lifecycle HTTP adapter — initial subset
|
||||
# Lifecycle HTTP adapter — registration, revisions and collaboration
|
||||
|
||||
2026-10-04; INFD-WP-0007-T04, in progress. `LifecycleAPI` is an unmounted WSGI
|
||||
adapter over `LifecycleService`. It starts no listener and adds no route to the
|
||||
|
|
@ -6,6 +6,8 @@ existing browser app or public ingress.
|
|||
|
||||
| Method and path | Input | Result |
|
||||
| --- | --- | --- |
|
||||
| `POST /v1/decisions` | `memo`, optional `documents` | Register an unbound version-one memo and return event/record/revision/resource receipt |
|
||||
| `POST /v1/decisions/{id}/revisions` | `memo`, `expected_version`, `summary`, optional `documents` | Compare-and-append successor revision; same receipt shape |
|
||||
| `GET /v1/decisions/{id}` | Optional positive integer `version` | Existing Memo JSON for the current or specified revision |
|
||||
| `GET /v1/decisions/{id}/events` | Optional `after` sequence cursor, `limit` 1–100 | `{"events": [...]}` ordered by sequence; use last returned sequence for next page |
|
||||
| `POST /v1/decisions/{id}/comments` | `{"version": 1, "body": {"text": "...", "locator": "optional"}}` | Durable event receipt |
|
||||
|
|
@ -17,8 +19,7 @@ Ids are 1–256 ASCII letters/digits or `.`, `_`, `:`, `-`. POST requires exact
|
|||
nonempty `Idempotency-Key` up to 256 characters. Mutation receipts are HTTP 200
|
||||
for both first submission and replay, with `event_id`, `memo_id`, `version`.
|
||||
Unknown fields, duplicate JSON/query keys, non-finite JSON values, boolean
|
||||
revision numbers and truncated bodies are rejected. Version-one registration,
|
||||
revision, search, publication and disposition routes are not yet exposed.
|
||||
revision numbers and truncated bodies are rejected. Search, publication and disposition routes are not yet exposed.
|
||||
|
||||
Authentication runs before routing or reading a mutation body. The composition
|
||||
must explicitly supply a bearer-token verifier returning an authenticated
|
||||
|
|
@ -39,9 +40,45 @@ identity, 403 policy denial, 404 unavailable record/route, 405 unsupported metho
|
|||
service or unusable policy evidence. Raw exception text and credentials are never
|
||||
returned. Upstream raw diagnostics are not forwarded.
|
||||
|
||||
T04 remains in progress: complete closed memo mutation schemas, canonical URLs,
|
||||
search/publication contracts, admitted authenticators and runtime wiring. Current
|
||||
T04 remains in progress: search/publication contracts, admitted authenticators,
|
||||
canonical browser URLs and runtime wiring. Current
|
||||
tests use the real service/repository/PolicyClient with synthetic authenticator
|
||||
and PDP transport; they establish adapter behavior, not live identity admission.
|
||||
Runtime must not expose this adapter before lifecycle policy and independent
|
||||
event-delivery contracts are accepted and readiness can be satisfied.
|
||||
|
||||
## Memo commands and packet custody
|
||||
|
||||
`memo` uses the existing application Memo JSON representation returned by GET,
|
||||
with the model's defaults available on input. `lifecycle_commands.decode_memo`
|
||||
derives closed fields and types from the existing dataclasses; it does not add
|
||||
fields to or replace the governed portable Decision Memo schema. This is the
|
||||
current application's projection, not a claim to accept every portable schema
|
||||
field. Nested unknown fields, wrong scalar types (including booleans as version
|
||||
numbers), duplicate packet/highlight ids, invalid digests, excessive nesting and
|
||||
secret markers are rejected. Approval pins and seals cannot be submitted. The
|
||||
question must pass the existing one-question check. Both L0 and L3 use the same
|
||||
model/decoder. The memo's proposed binding principal is not caller identity.
|
||||
|
||||
Registration is `{ "memo": <Memo JSON>, "documents": [...] }`. Revision adds
|
||||
`expected_version` and a nonempty `summary`; its memo id must match the path and
|
||||
its version must be exactly expected_version + 1. Every mutation requires
|
||||
Idempotency-Key. Register/revise receipts include a relative API resource link
|
||||
`/v1/decisions/{id}?version={version}`. This does not claim that an unpublished
|
||||
draft has a human review URL or that the API is publicly mounted.
|
||||
|
||||
Each document has exactly `digest`, `media_type`, `content_base64`. At most 100
|
||||
documents are allowed; the total JSON request remains bounded at 256 KiB and
|
||||
each decoded document at 192 KiB. SHA-256 must match the supplied bytes and a
|
||||
packet entry. Duplicate/orphan documents are refused. UTF-8 packet content uses
|
||||
the existing secret-marker scan. Supplied hashes are never proof of custody.
|
||||
Registration must include all packet content. Revision may retain content from
|
||||
the current revision's packet, and must supply bytes for any new digest. Knowing
|
||||
a digest stored under a different record grants no reuse capability.
|
||||
|
||||
Memo, new documents, lifecycle event, pending delivery and idempotency receipt
|
||||
commit together. A write failure rolls them all back. Policy authorization covers
|
||||
the command including documents; identity and decision freshness are rechecked
|
||||
in the write transaction. Replays are reauthorized and return the original event.
|
||||
Conflicting content for a key, stale revision preconditions and attempts to
|
||||
replace an existing digest's media type produce 409 without a partial write.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue