Implement lifecycle workspace publication and audit delivery
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
parent
ee472acc87
commit
5fec7de4cb
21 changed files with 1022 additions and 78 deletions
|
|
@ -77,19 +77,19 @@ legacy `save_memo` behavior. Existing stale-presentation guards see the same mem
|
|||
versions. Approval-bound/sealed revision handling requires the later review
|
||||
integration; this repository refuses those lifecycle revision commands.
|
||||
|
||||
Pending lifecycle events are durable local obligations. They are not emitted as
|
||||
invented Audit Core event types or reported delivered. The existing review audit
|
||||
queue remains unchanged. Before exposure, T02/T03 must settle receiver admission,
|
||||
payload/privacy, delivery retries and readiness accounting for the new queue.
|
||||
Runtime readiness now refuses while lifecycle events remain pending, and the
|
||||
admin inspection command reports content-free lifecycle counts. No events are
|
||||
marked delivered without the future admitted receiver adapter.
|
||||
Pending lifecycle events are durable local obligations. The opt-in runtime audit
|
||||
adapter stages immutable `informed-decision.lifecycle` commitments into the
|
||||
existing transactional outbox and clears pending obligations only after a receiver
|
||||
receipt. Content remains in local custody; the independent commitment contains
|
||||
its digest and existence assertion. Readiness refuses while lifecycle delivery
|
||||
is pending. See `LifecycleWorkspaceDelivery.md` for the platform tenant boundary,
|
||||
retries, heartbeats and outstanding production admission.
|
||||
|
||||
## Remaining contracts
|
||||
|
||||
T02 remains in progress: production identity/policy composition, versioned HTTP schemas,
|
||||
publication audience policy, incomplete drafts, non-cluster workload identity,
|
||||
legacy record enrollment, source fetching/retention, independent evidence delivery
|
||||
production publication audience policy, incomplete drafts, non-cluster workload identity,
|
||||
legacy record enrollment, source fetching/retention, live independent evidence delivery
|
||||
and non-approval binding integration. T03 is started with this persistence slice;
|
||||
it is not complete. T04/T05 continue to own HTTP and UI exposure. Native runtime
|
||||
intake and admission remain with `INFD-WP-0005`.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ existing browser app or public ingress.
|
|||
|
||||
| Method and path | Input | Result |
|
||||
| --- | --- | --- |
|
||||
| `GET /v1/decisions` | Optional `q` (up to 200 characters), opaque `cursor` | Authorized current revision summaries and `next_cursor` |
|
||||
| `POST /v1/decisions/{id}/publications` | `version`, `audience` with explicit `subjects` and `groups` lists | Durable publication event receipt |
|
||||
| `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 |
|
||||
|
|
@ -19,7 +21,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. Search, publication and disposition routes are not yet exposed.
|
||||
revision numbers and truncated bodies are rejected. Disposition routes are not exposed.
|
||||
|
||||
Authentication runs before routing or reading a mutation body. The composition
|
||||
must explicitly supply a bearer-token verifier returning an authenticated
|
||||
|
|
@ -40,8 +42,9 @@ 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: search/publication contracts, admitted authenticators,
|
||||
canonical browser URLs and runtime wiring. Current
|
||||
T04 remains in progress: admitted workload authenticators and API listener
|
||||
composition. The browser workspace uses verified sessions through a separate
|
||||
adapter (see LifecycleWorkspaceDelivery.md). 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
|
||||
|
|
@ -64,8 +67,11 @@ 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.
|
||||
`/v1/decisions/{id}?version={version}` and a `workspace_url` at
|
||||
`https://decisions.coulomb.social/decisions/{id}?version={version}`. The latter
|
||||
is an authorized authoring workspace, not a binding review link. The API remains
|
||||
unmounted. Search cursors are caller/tenant/query scoped, expire after five
|
||||
minutes and are invalidated on process restart. Every page rechecks policy.
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
2026-10-04; `INFD-WP-0007-T02/T03`. Implemented in
|
||||
`informed_decision/lifecycle_service.py`, above `LifecycleRepository`.
|
||||
This is a headless Python application interface. No HTTP route or production
|
||||
composition enables it yet.
|
||||
This is a headless Python application interface. An optional runtime composition
|
||||
enables the browser workspace; production admission is still outstanding.
|
||||
|
||||
## Caller and authority
|
||||
|
||||
|
|
@ -23,8 +23,8 @@ Non-cluster/workload composition remains T02/T04 work.
|
|||
The service consumes `PolicyClient` observations. It neither evaluates policy
|
||||
nor falls back to local permissions. New proposed action names are
|
||||
`lifecycle.register`, `lifecycle.revise`, `lifecycle.source`,
|
||||
`lifecycle.evaluation`, `lifecycle.comment`, `lifecycle.read`, and
|
||||
`lifecycle.events`. These are not added to the existing review-action allowlist;
|
||||
`lifecycle.evaluation`, `lifecycle.comment`, `lifecycle.read`,
|
||||
`lifecycle.events`, `lifecycle.publish`, `lifecycle.search` and `lifecycle.packet`. These are not added to the existing review-action allowlist;
|
||||
review and human disposition contracts remain unchanged.
|
||||
|
||||
The request carries the authenticated subject, tenant, resource `memo:<id>`,
|
||||
|
|
@ -35,7 +35,17 @@ and context:
|
|||
* `memo_version`: submitted/requested revision, or null for latest retrieval and
|
||||
record-wide event retrieval;
|
||||
* `command_digest`: SHA-256 of canonical command JSON, including mutation content,
|
||||
expected revision and idempotency key, or the read/page parameters.
|
||||
expected revision and idempotency key, or the read/page parameters;
|
||||
* `record`: tenant-partitioned registration facts, original registering actor,
|
||||
current revision and latest publication audience for the requested revision;
|
||||
* `publication_audience`: explicit subjects/groups for a publication command.
|
||||
|
||||
Search uses resource `decisions`, type `decision-collection`, then independently
|
||||
authorizes each candidate with `lifecycle.read`. A page examines at most 50
|
||||
candidates; denied records are omitted, unavailable policy fails the request.
|
||||
Opaque cursors are scoped to caller/tenant/query and expire after five minutes.
|
||||
Packet access checks its own action and a revision-specific packet index; a
|
||||
known content digest grants no retrieval capability.
|
||||
|
||||
The command digest correlates the requested operation; it is not `view_hash`,
|
||||
an approval binding digest or an authorization verdict. No presentation evidence
|
||||
|
|
@ -53,7 +63,8 @@ policy pins, response lifetime and the supported effect.
|
|||
|
||||
Mutation commands snapshot supplied content before the network call. Under the
|
||||
repository's write transaction, a guard rechecks caller and decision expiry and
|
||||
the persisted observation before even returning an idempotent replay. New events
|
||||
the persisted observation and unchanged record/audience facts before even
|
||||
returning an idempotent replay. New events
|
||||
carry `body.policy_observation_id`; receipts replay their original event and
|
||||
observation link while the fresh retry check remains in policy history. The
|
||||
identity/policy guard does not perform network calls while holding the write lock.
|
||||
|
|
@ -61,26 +72,27 @@ identity/policy guard does not perform network calls while holding the write loc
|
|||
Read authorization precedes repository lookup. Denied requests therefore cannot
|
||||
distinguish missing and existing records through lookup errors. The service
|
||||
rechecks identity and decision expiry after retrieving content and before returning
|
||||
it. Repository tenant partition enforcement also applies. Record-wide event
|
||||
it, including unchanged record/audience facts. Repository tenant partition enforcement also applies. Record-wide event
|
||||
access requires its own action; it does not inherit a memo-read grant.
|
||||
|
||||
The existing `decision_attributable: false` declaration remains in force. A
|
||||
matched, recorded response is not proof of signed PDP attribution. New lifecycle
|
||||
events still reside in the durable pending queue until an Audit Core contract
|
||||
and delivery adapter are admitted.
|
||||
events remain pending until the opt-in audit adapter obtains a receiver receipt.
|
||||
See LifecycleWorkspaceDelivery.md for custody, reconciliation and admission.
|
||||
|
||||
## Error and integration contract
|
||||
|
||||
`LifecycleError` supplies bounded status/code pairs: 401 for expired identity,
|
||||
403 for a policy deny, and 503 for unavailable or unusable policy evidence.
|
||||
The repository retains `Conflict`, `EvidenceUnavailable` and validation errors;
|
||||
the future HTTP adapter must map these to bounded envelopes without echoing
|
||||
the HTTP adapter maps these to bounded envelopes without echoing
|
||||
content, credentials or raw exception diagnostics.
|
||||
|
||||
No accept/publish endpoint is implied by this interface. Human acceptance stays
|
||||
on the existing presentation/disposition path; publication needs an explicit
|
||||
audience and separately authorized transition. The service supplies the shared
|
||||
operations that subsequent HTTP and UI adapters will invoke.
|
||||
Publication appends an immutable event for the current revision with an explicit
|
||||
nonempty audience (at most 32 subjects and 32 groups, no wildcard). A successor
|
||||
revision does not inherit publication. Audience facts are inputs to Access Engine,
|
||||
never local permissions. Human acceptance requires the separate existing
|
||||
presentation/disposition path; the lifecycle-to-review handoff is still open.
|
||||
|
||||
Before enabling a listener, T02/T04 must provide: reviewed lifecycle PDP package
|
||||
and action/context fixtures; admitted human/workload identity adapters; closed
|
||||
|
|
|
|||
70
docs/specs/LifecycleWorkspaceDelivery.md
Normal file
70
docs/specs/LifecycleWorkspaceDelivery.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Lifecycle workspace and delivery
|
||||
|
||||
2026-10-04; INFD-WP-0007-T02 through T06, source implementation.
|
||||
|
||||
## Human workspace
|
||||
|
||||
With `lifecycle_policy` configured, the signed-in home links to `/decisions`.
|
||||
The workspace uses the same headless service as the API. Existing KeyCape
|
||||
sessions establish identity; existing origin and CSRF checks protect forms.
|
||||
Users can search, prepare a draft, record source metadata and evaluations,
|
||||
comment, publish to explicit members/groups, refine, compare consecutive
|
||||
revisions and download authorized packet entries. Source content is not fetched.
|
||||
Packet uploads currently use the API. All forms receive fresh policy checks;
|
||||
rendering a button grants no authority.
|
||||
|
||||
Publication records an audience for one revision. Access Engine determines access
|
||||
using authenticated identity and retained record facts. Publication creates no
|
||||
approval and no human disposition. New revisions require their own publication.
|
||||
The workspace explicitly states that human acceptance is unavailable for these
|
||||
drafts. Connecting a lifecycle revision to the existing protected presentation
|
||||
and Approval Engine path remains T03/T05 work.
|
||||
|
||||
## Runtime and deployment inputs
|
||||
|
||||
The optional runtime `lifecycle_policy` object requires exactly `origin`,
|
||||
`package`, `version`, `package_digest`, `caller_token_file`. Its package must
|
||||
differ from the review package. No default policy or identity fallback exists.
|
||||
The optional boolean `lifecycle_delivery` defaults to false. Configure both
|
||||
for an admitted workspace with evidence delivery.
|
||||
|
||||
The deployment renderer accepts the same separate policy pins plus `pod_name`,
|
||||
requires explicit `lifecycle_delivery: true` with that package, and generates
|
||||
exact egress and an owner-review ingress proposal. It references the existing
|
||||
mounted workload policy credential path; this does not authorize that workload
|
||||
for a new package. Existing admission inputs render without lifecycle changes.
|
||||
The API still requires its own admitted bearer verifier and listener composition.
|
||||
|
||||
## Independent evidence
|
||||
|
||||
On an enabled audit tick, up to 100 pending mutations are staged as immutable
|
||||
`informed-decision.lifecycle` commitments in the existing outbox. The event UUID
|
||||
is the delivery identity. Commitment metadata includes memo id, revision,
|
||||
operation, a content digest and an existence assertion. The digest covers the
|
||||
retained event and historical memo. Advisory text stays in source custody;
|
||||
commitment delivery does not provide independent content reconstructability.
|
||||
|
||||
Pending obligations clear only after the outbox retains a receiver reference.
|
||||
Lost replies retry with the same identity. The existing worker supplies bounded
|
||||
delivery, reconciliation and a 24-hour lifecycle heartbeat. Undelivered evidence
|
||||
keeps runtime readiness false. The current sink/reconciliation identity is
|
||||
platform-scoped; other tenants fail closed at staging. Multi-tenant receiver
|
||||
admission is not claimed. Kubernetes traffic readiness behavior is unchanged.
|
||||
|
||||
Tests use the actual local Audit Core receiver contract, including deduplication
|
||||
and reconciliation. The agent-to-human collaboration scenario creates two
|
||||
records, publishes/comments/refines and drains five events with unchanged runtime
|
||||
configuration bytes. Its identity and PDP transport are synthetic. It proves
|
||||
source behavior, not deployed workload authority or all seven acceptance cases.
|
||||
|
||||
## Remaining delivery work
|
||||
|
||||
T02/T04 require owner-admitted lifecycle policy actions/context, workload identity
|
||||
and API ingress. The policy must cover all actions in LifecycleServiceContract,
|
||||
including collection search and per-record checks. Existing compact-sitting pins
|
||||
do not supply these grants. WP-0005 retains private intake composition work.
|
||||
|
||||
T03/T05 require the durable review handoff and human-only acceptance integration.
|
||||
T06 requires full acceptance evidence, sender/cadence admission, immutable image,
|
||||
database backup/migration and rollback verification. T07 requires the separately
|
||||
approved concrete live rollout. No production pins or resources changed here.
|
||||
Loading…
Add table
Add a link
Reference in a new issue