state-hub/deploy/informed-decision/README.md

74 lines
4.3 KiB
Markdown
Raw Normal View History

# Private memo dispatch candidate
STATE-WP-0096 / INFD-WP-0007. The founder selected the State Hub workload.
`python -m api.services.memo_dispatch` is a private worker, separate from the
State Hub API process. Its queue contains explicitly submitted memo envelopes;
it does not scan decisions or lend its credential to a public Hub endpoint.
An admitted agent registers, refines and publishes using the lifecycle service,
then requests review. The returned immutable `envelope` is the queue input; no
projection or regeneration is needed. Queue the envelope using `enqueue
--envelope <private-file>` in the worker's authorized workload context. This
command validates and retains it without a network side effect. The running
worker forwards it to the fixed intake endpoint using its rotating projected
token. `status` prints counts; `once` performs at most one due attempt. Native
intake receipts retain approval pins in private custody. No credential, content
or upstream error body is printed. Browser review uses the returned lifecycle
outcome link, never a worker-constructed approval.
The original dev fixture remains injectable. The production wrapper adds private
0700/0600 storage, symlink refusal, a lock across remote attempt/local receipt,
5-second transport timeout, bounded JSON, disabled proxies and no redirects.
A lost reply replays the same envelope/key. Intake's unresolved-create refusal
blocks the queue row; it never creates another native approval automatically.
Concurrent enqueue may report queue_busy while dispatch is in flight; retry the
same explicit enqueue after the bounded attempt. SIGTERM stops between attempts.
The worker uses the selected existing State Hub service account. It has no
Service/Ingress, database credential, browser route or approval scopes. Separate 600-second tokens are projected for intake and lifecycle audiences.
The dispatcher reads only intake-token; admitted headless lifecycle clients use
lifecycle-token inside this workload context. Neither token is printed or
exported through the Hub API. Token mounts are read-only without subPath.
The worker image does not change the Hub API image or PostgreSQL schema.
All execution that can write this private queue or run commands as this workload
is trusted to pose memos under its existing admission. Kubernetes exec/filesystem
custody is the boundary. Adding a public enqueue API needs independent caller
identity and authorization; it is not silently enabled here.
Live deployment is still a distinct reviewed change. Deploy after CCR-2026-0032
requester delivery, the INFD lifecycle service and policy candidates. Retain the
PVC and rows on withdrawal; rollback stops the worker but does not undo submitted
memos, native approvals or human acts. Native human acceptance and audit receipts
remain STATE-WP-0096-T03 / INFD-WP-0007-T07.
Explicit queueing from an authorized workstation session (the file contains the
exact envelope returned by lifecycle request-review, not an access token):
```sh
kubectl -n state-hub exec -i deployment/state-hub-memo-dispatch -- \
python -m api.services.memo_dispatch --queue /data/private enqueue \
--envelope /dev/stdin < /private/review-envelope.json
```
This is a per-decision data operation, not a deployment. Headless clients call
8081 with the appropriate projected audience and the normal API idempotency key;
they never request approval:approve or approval:consume. Automatic scanning and
a public delegate endpoint are deliberately outside this worker's contract.
Final candidate image (Forgejo commit 4a59b23):
forgejo.coulomb.social/coulomb/state-hub-memo-dispatch@sha256:410fb6b6c9fd7a7ee0b63d727fd3249fb3ae13943421d6a5ce88b7ad2520bd2f
Live observation: State Hub's API Service selects app=state-hub. This worker
does not carry that label, so it cannot enter the API endpoints. At inspection
there were no other State Hub NetworkPolicies; recheck effective selection before
activation. Its own policy allows only DNS and the exact intake peer on 8081.
The approved Kubernetes deployment prepares the private queue with a non-root
init container using the identical image. It removes inherited setgid only on
an empty, owned 2700 directory and otherwise requires 0700. It never changes
existing nonempty evidence custody. This covers local-path fsGroup behavior
that a plain Docker volume does not reproduce.