Add lifecycle browser authoring and durable review handoff retrieval

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
tegwick 2026-10-05 00:48:07 +02:00
parent 52d372df0b
commit 9bc581a547
20 changed files with 632 additions and 74 deletions

View file

@ -0,0 +1,28 @@
# Lifecycle authoring validation — 2026-10-05
Source implementation evidence; this increment has not been deployed.
The browser can prepare approval or discussion drafts, append immutable text
supporting documents and required acknowledgments, compare revisions, publish,
and download the retained review request for the admitted State Hub workload.
The shared service also exposes exact-version handoff retrieval under the
existing lifecycle events permission. Preparation does not create an approval;
only a human can complete a disposition through the existing review surface.
Validation:
- Locked project environment, actual owner Flex Auth, Approval Engine, Audit Core
and State Hub sources: 669 passed, 1 skipped.
- Final focused lifecycle UI/review/HTTP regression run: 50 passed, 2 skipped
(optional real-engine checks excluded from this focused run).
- Chromium: 16 checks passed using real HTTPS and the actual lifecycle policy
package, with synthetic identity and TokenReview. This is fixture evidence,
not another native acceptance claim.
- Desktop and mobile screenshots inspected; no viewport overflow observed.
- Coverage includes replay, restart, stale revision refusal, protected export,
CSRF refusal, rejected documents without partial writes, and no approval entry
created by review-request preparation.
The browser receipt includes the existing fixture human review's single entry;
the new lifecycle preparation adds no entry. Fixture databases, TLS keys and
session credentials are deliberately excluded from this directory.

View file

@ -0,0 +1,154 @@
{
"fixture_only": true,
"browser": "Chromium",
"checks_passed": 16,
"checks": [
"PKCE callback and secure browser session",
"Home overview lists the open memo addressed to the reviewer",
"Entitled page escapes memo and packet markup",
"Server refuses bypass of missing acknowledgments",
"Explicit acknowledgment unlocks the form",
"Complete attachment download stays behind entitlement",
"Return records a memo response without an engine entry",
"Mobile review fits the viewport",
"One actual approval entry, stable on browser reload",
"Audit receiver holds all commitments; unsigned decision gap retained",
"Browser creates an approval draft and immutable supporting document revision",
"Browser publication and durable handoff download use the actual lifecycle PDP",
"Prepared request creates no approval or human entry; lifecycle audit is delivered",
"Real workload caller refusal hides review content",
"Sign-out clears the session; all forms carry the exact origin",
"No page errors or injected script execution"
],
"fixture_transport": "real HTTPS on ephemeral ports; synthetic issuer and TokenReview",
"native_human_login_proven": false,
"native_policy_admitted": false,
"factory_attempts": 0,
"paid_model_calls": 0,
"final_component_state": {
"entries": 1,
"intents": [
{
"disposition_id": "disp-2e416ff7-a0b8-4e6a-bf5f-fd90e65f9d18",
"approval_id": "fixture",
"subject": "human-fixture",
"state": "confirmed",
"attempt": "a693dad4-6d79-4ab3-b177-9a93de7bbdb9",
"approved_at": "2026-10-04T22:44:43+00:00",
"presentation_id": "pres-af92dcbd-51e7-4089-ba1e-76fdffcd9e8c",
"operation_id": "cc819583-73a7-4f24-8723-2aa4aaeb4280"
}
],
"outbox_states": [
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered",
"delivered"
],
"policy_outcomes": [
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"allow",
"caller_refused"
],
"decision_attributable": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"entry_posts": 1,
"consume_calls": 0,
"tokenreviews": 15
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View file

@ -1,7 +1,9 @@
# Decision lifecycle service
Status: product direction requested by the founder on 2026-10-04; architecture
and API below are proposed delivery contracts, not shipped endpoints.
Status: initial audience deployed and human-accepted on 2026-10-05.
This is the product contract, including wider capabilities not yet delivered.
LifecycleHTTPContract.md names the implemented routes and source-only additions;
SCOPE.md and the workplan distinguish current delivery from remaining work.
Workplan: `INFD-WP-0007`; intake prerequisite: `INFD-WP-0005`.
## Outcome and boundaries

View file

@ -1,8 +1,9 @@
# 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
existing browser app or public ingress.
2026-10-05; INFD-WP-0007. `LifecycleAPI` is a WSGI adapter over
`LifecycleService`, mounted on the admitted private 8081 listener. It adds no
route to public ingress. The direct retained-handoff GET is a source addition
awaiting a separate release; the other routes below are deployed.
| Method and path | Input | Result |
| --- | --- | --- |
@ -11,6 +12,7 @@ existing browser app or public ingress.
| `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 |
| `POST /v1/decisions/{id}/review-requests` | `version`, `options` per LifecycleReviewHandoff | Durable request receipt and exact intake envelope |
| `GET /v1/decisions/{id}/review-requests` | Required positive `version` | Exact retained request receipt/envelope, checked as `lifecycle.events`; no submission |
| `GET /v1/decisions/{id}/outcomes` | Required positive `version` | Correlated review/disposition evidence and submission state |
| `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 |
@ -28,8 +30,8 @@ revision numbers and truncated bodies are rejected. Disposition routes are not e
Authentication runs before routing or reading a mutation body. The composition
must explicitly supply a bearer-token verifier returning an authenticated
`Caller`. There is no default or testing fallback. Cookies are not credentials
for this adapter; its future human browser integration must provide a separately
reviewed session/CSRF boundary or admitted bearer identity. Neither the intake SA
for this adapter; the browser workspace uses the separate
verified session/CSRF adapter. Neither the intake SA
audience nor the browser's approval-engine access token is implicitly admitted.
Every handled command invokes the shared policy-consuming service. Clients cannot
@ -44,13 +46,12 @@ 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: 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
event-delivery contracts are accepted and readiness can be satisfied.
The deployed runtime authenticates the selected State Hub service account using
Kubernetes TokenReview and the lifecycle audience. See LifecycleProductionRuntime.md.
Human workspace forms use verified KeyCape sessions through a separate adapter.
Native admission, negative identity tests and initial human acceptance are
recorded in ../evidence/2026-10-05-lifecycle-cutover/. New clients still require
owner-reviewed admission; this contract does not widen identity or listeners.
## Memo commands and packet custody
@ -72,7 +73,7 @@ Idempotency-Key. Register/revise receipts include a relative API resource link
`/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
private. 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

View file

@ -1,8 +1,9 @@
# Initial production runtime candidate
# Initial production runtime
INFD-WP-0007 / INFD-WP-0005. Founder selected net-kingdom-admins humans and
system:serviceaccount:state-hub:state-hub on 2026-10-04. This is a preparation
contract; deployment still requires the concrete rollout approval.
system:serviceaccount:state-hub:state-hub on 2026-10-04. The concrete rollout was approved and accepted on 2026-10-05.
This describes the deployed initial runtime; later artifacts require their own
release verification.
## Identity and listeners
@ -28,11 +29,11 @@ package, version and digest from human review. Only humans can bind via the
existing protected review flow. Access Engine keeps the authorization decision;
Approval Engine keeps authoritative approval state.
## Initial proposal data
## Admitted initial data
`deploy/lifecycle/lifecycle-callers.json` names the exact State Hub account and
platform tenant. The intake registry permits only decision-record class and
net-kingdom-admins, with a proposed cap of 50 new attempts per UTC day. Replays
net-kingdom-admins, with a cap of 50 new attempts per UTC day. Replays
do not spend a second attempt; uncertain creation never automatically reposts.
The cap and routing are configuration, not per-decision deployments.
@ -64,7 +65,7 @@ forwarding route. Queueing is trusted workload execution. New review envelopes
are data operations and do not change deployments. The exact lifecycle snapshot
id/key is preserved without inventing a Hub relationship when serves is absent.
Lost replies replay the same envelope; native-create uncertainty blocks the row.
Native deployment/acceptance still remains open. Notification/write-back receiver
Native deployment and human acceptance passed. Notification/write-back receiver
admission is unchanged; INFD_HUB_WRITEBACK remains off.
The image migrates schema 2 to schema 5 on open. Existing records, presentations,
@ -74,16 +75,16 @@ new evidence, and restore a verified pre-cutover copy on a separate private volu
only under the reviewed recovery plan. An in-flight/unresolved human submission
must be reconciled, never retried or discarded to make rollback convenient.
## Remaining live gates
## Observed acceptance and remaining scope
- CCR-2026-0032 requester projection: current namespace has only the audit
ExternalSecret; requester custody, native identity/path refusals and rotation
evidence remain with RPF-WP-0051.
- FLEX-WP-0033: publish scanned policy artifact; approve exact policy/RBAC/network
objects and native caller/subject allow/refusal tests.
- INFD-WP-0005 / STATE-WP-0096: activate and verify the prepared private State Hub
dispatcher and its projected tokens; retain gated resolution write-back.
- INFD-WP-0007-T06/T07: backup/restore, exact rollout approval, native human review
and independent audit receipts across two decisions and a revision with unchanged
release/configuration pins. Browser packet authoring and broader binding profiles
remain on T05; the supported review handoff profile is documented separately.
CCR-2026-0032 delivery is applied: actual receiving mount/exchange and bounded
identity/path/scope/revocation tests passed. FLEX-WP-0033 and STATE-WP-0096
completed native deployment and human acceptance. INFD-WP-0007-T06/T07 retain
backup/restore, caller isolation, unchanged pins across two records/a revision,
restart retention and independent audit proof. See
../evidence/2026-10-05-lifecycle-cutover/acceptance-summary.json.
Issuer rotation remains separately governed under Platform RPF-IN-0004.
Browser authoring continuation is T05; new source features do not imply a
production update. Wider identity/binding/publication and optional Hub write-back
contracts remain explicit T02 work. No new caller, group or listener is admitted.

View file

@ -1,6 +1,8 @@
# Revision-specific lifecycle review handoff
2026-10-04; INFD-WP-0007-T02 through T06. Source implementation, not deployed.
2026-10-05; INFD-WP-0007-T02/T05. The initial handoff is deployed and
human-accepted; browser document authoring and direct handoff retrieval below
are the next source increment, not yet deployed.
## Headless contract
@ -22,8 +24,9 @@ The envelope is also retained in authorized event history for recovery.
The handoff currently supports the platform tenant, English organizational
`approve` memos at the current renderer release, and the intake's nonempty UTF-8
packet profile. Unsupported projections are refused rather than dropping fields.
Broader L0/L2 profiles, browser packet authoring and automated forwarding remain
live work in T02/T04/T05 and WP-0005. There is no automatic submitter or default
The admitted State Hub dispatcher performs explicit forwarding. Browser packet
authoring and handoff preparation now have a source implementation; broader
L0/L2 binding and automatic discovery remain separate contracts. There is no automatic submitter or default
workload credential. A caller-selected submitter is a routing request, not identity.
The local use of intake's shape validator does not grant admission: intake always
reauthenticates the workload and reloads its actual grant and recipient mapping.
@ -75,8 +78,8 @@ outboxes and receipt requirements. The integration test creates an approval via
the real Approval Engine API, records a signed-fixture human entry, retrieves the
confirmed result for source revision two, and delivers lifecycle and review
commitments to the real Audit Core receiver. Identity and PDP transport are
synthetic. Production grants, private listener/forwarding composition, full
release/rollback evidence and separately approved rollout remain outstanding.
synthetic. Native initial-audience grants, forwarding, human acceptance and
restart/audit evidence are recorded in ../evidence/2026-10-05-lifecycle-cutover/.
## Migration and rollback boundary
@ -88,3 +91,37 @@ retain the normal database backup and image/config pins. An older-image rollback
requires a compatible restored database plus reconciliation of any subsequent
engine side effects; it cannot safely discard new review/entry evidence. A
reviewed forward fix remains preferable once new handoffs have been written.
## Browser authoring and retained handoff retrieval
New browser drafts explicitly select organizational human approval or discussion
only. Existing rendered forms without that field retain the earlier draft type;
there is no silent conversion of existing records. Discussion drafts cannot
enter the approval handoff. The shared structural profile check is descriptive,
not an authorization grant.
A text document is appended through the shared revise command with its actual
UTF-8 bytes, digest and optional required highlight. The complete form is limited
to 64 KiB by the existing adapter; large/binary packets remain available through
the bounded API. Previous packets and highlights are preserved, and a new
revision requires new publication. Comparison shows changed documents/digests
and acknowledgment text as well as the question and brief.
The browser prepares the same immutable request with an explicit approval purpose
and responsible principal. Its initial routing is State Hub / decision-record /
net-kingdom-admins. This route is checked by the existing PDP, and intake still
authenticates the actual submitter and assigns the configured named recipient.
Preparation alone does not enqueue, create an approval, notify or bind.
`GET /v1/decisions/{id}/review-requests?version=N` returns the exact retained
`event_id`, `review_memo_id` and `envelope`. It requires a fresh `lifecycle.events`
decision for that revision, preserving the permission already required to read
the envelope in history. Missing requests return 404; invalid/nonpositive versions
return 400. Reads do not create requests or repeat external effects. Historical
exports remain historical: intake refuses a stale source revision.
The browser equivalent `/decisions/{id}/review-request?version=N` downloads
only the envelope as an attachment. It uses the same service check, without
credential copying or a public privileged forwarding API. A prepared current
request links to this download; a loaded request links to protected human review.
The original idempotency identity survives download, retry and process restart.

View file

@ -3,7 +3,7 @@
2026-10-04; `INFD-WP-0007-T02/T03`. Implemented in
`informed_decision/lifecycle_service.py`, above `LifecycleRepository`.
This is a headless Python application interface. An optional runtime composition
enables the browser workspace; production admission is still outstanding.
enables the browser workspace; the initial audience is deployed and accepted.
## Caller and authority
@ -21,7 +21,7 @@ The existing intake TokenReview audience is not silently reused for this service
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
nor falls back to local permissions. The admitted action names are
`lifecycle.register`, `lifecycle.revise`, `lifecycle.source`,
`lifecycle.evaluation`, `lifecycle.comment`, `lifecycle.read`,
`lifecycle.events`, `lifecycle.publish`, `lifecycle.search`, `lifecycle.packet`,
@ -93,8 +93,8 @@ 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 source handoff now follows LifecycleReviewHandoff.md. Production forwarding
and broader review profiles remain open.
presentation/disposition path; the source handoff now follows LifecycleReviewHandoff.md. The selected State Hub dispatcher forwards explicit requests; broader review
profiles remain open.
Before enabling a listener, T02/T04 must provide: reviewed lifecycle PDP package
and action/context fixtures; admitted human/workload identity adapters; closed
@ -108,3 +108,8 @@ Production candidate record facts also include `revision_by`, the immutable acto
of the requested revision. This lets its editor retain access to an unpublished
successor after refining a published decision. Original authorship remains
`registered_by`; both facts participate in the same transaction/read race guard.
The next source increment adds `review_handoff(caller, memo_id, version)`, a
revision-specific read of the exact immutable request under `lifecycle.events`.
It reuses the event permission and post-read currency checks, adds no grant, and
never forwards or regenerates the envelope. See LifecycleReviewHandoff.md.

View file

@ -1,6 +1,7 @@
# Lifecycle workspace and delivery
2026-10-04; INFD-WP-0007-T02 through T06, source implementation.
2026-10-05; INFD-WP-0007-T02/T05. Initial workspace deployed; document
authoring and review-request preparation are implemented for the next release.
## Human workspace
@ -10,7 +11,8 @@ 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;
The next release adds short text documents and optional required highlights
through immutable revisions. Large or binary packets continue to 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
@ -33,7 +35,8 @@ 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.
The deployed private API has its own admitted TokenReview verifier and separate
listener; browser sessions are not bearer credentials there.
## Independent evidence
@ -57,15 +60,21 @@ records, publishes/comments/refines and drains five events with unchanged runtim
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
## Delivery boundary and continuation
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.
The initial rollout passed native agent-to-human-to-agent acceptance, restart
retention, public/private isolation and Audit Core reconciliation. See
../evidence/2026-10-05-lifecycle-cutover/. Those receipts describe the deployed
804d89fb image; they do not prove the next source increment is live.
The source handoff now integrates human-only acceptance for the admitted intake
profile; T03/T05 retain broader profiles and browser authoring/forwarding work.
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.
Browser authoring now exposes explicit approval/discussion draft types, document
addition with required acknowledgment, packet/highlight comparisons, and durable
review-request preparation/download. The adapter calls only the shared service;
no store access, local permit or automatic privileged forwarding is introduced.
LifecycleReviewHandoff.md specifies the shared retrieval and profile contract.
Review overview discovery remains exact-record-only under compact-sitting v12.
The lifecycle workspace discovers authorized records and exposes their outcomes.
A later change to legacy overview discovery needs an Access Engine contract,
not a consumer-side policy bypass. Broader binding profiles, external identities,
source connectors and optional Hub write-back remain T02/T05 work.