Add attended sender release with sealed sources and recovery
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
This commit is contained in:
parent
c0c3221855
commit
e795b2970c
9 changed files with 900 additions and 12 deletions
61
docs/sender-attended-entry-2026-10-31.json
Normal file
61
docs/sender-attended-entry-2026-10-31.json
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"schema": "email-connect.sender-attended-entry-preparation.v1",
|
||||
"recorded_at": "2026-10-31T16:16:52.410337+00:00",
|
||||
"status": "entry_implemented_owner_return_pending",
|
||||
"owner_task_id": "da56d175-3126-5eaa-90c5-dd1e9da050d5",
|
||||
"owner_task_observed_status": "todo",
|
||||
"live_preparation_result": {
|
||||
"status": "sender_release_refused",
|
||||
"reason": "verified_credential_owner_return_required",
|
||||
"retry_automatically": false
|
||||
},
|
||||
"live_proposal_sealed": false,
|
||||
"node_contacted_by_preparation": false,
|
||||
"application_changed": false,
|
||||
"mail_sent": false,
|
||||
"new_assembly_tests_passed": 21,
|
||||
"suite_passed": 270,
|
||||
"suite_existing_optional_skips": 21,
|
||||
"suite_seconds": 36.83,
|
||||
"native_kubernetes_effects_in_assembly": "modeled",
|
||||
"sqlite_and_runtime_probes": "actual_synthetic_subprocess_and_local_wsgi",
|
||||
"sources": [
|
||||
{
|
||||
"path": "scripts/release-sender.py",
|
||||
"sha256": "98a59ebefc36094a01beaa7359f2508f54e2d59f87646e5219deeaae4b767c5a"
|
||||
},
|
||||
{
|
||||
"path": "scripts/sender_release.py",
|
||||
"sha256": "3415b03757fcfcaf4fce69e7b7c2e99702f4b238e19d9b2f8d021b01b3de68fc"
|
||||
},
|
||||
{
|
||||
"path": "tests/test_sender_release.py",
|
||||
"sha256": "d353f78da47c8d4d64b0faba3af5fa79d6756f9df9256bfd9812b3818d83e843"
|
||||
},
|
||||
{
|
||||
"path": "scripts/sender_native.py",
|
||||
"sha256": "41722d23f7d04a41c7fb428cb25a24438a144684cfbc5dcd875d5299ec6ffc71"
|
||||
},
|
||||
{
|
||||
"path": "scripts/sender_transition.py",
|
||||
"sha256": "fa80b428b6231b74578baf23ff5977b6ce871a84321718adb2ba15d314f7abe1"
|
||||
},
|
||||
{
|
||||
"path": "scripts/capture-ledger.py",
|
||||
"sha256": "7994fe7b4fbf72e28a4296212005a88d0ef9fcb626b066e6bcf2885500bc69d6"
|
||||
},
|
||||
{
|
||||
"path": "scripts/ledger_archive.py",
|
||||
"sha256": "92d9d5e1908c7d433eb3f4ada6460f7d9b639017a4c2311cb7ffaacd262f33c3"
|
||||
},
|
||||
{
|
||||
"path": "scripts/inspect-sender-ledger.py",
|
||||
"sha256": "262d6d52d5c10fb8583e0828ed34945b647f1d53bf9de5286374fef85cf76a8d"
|
||||
},
|
||||
{
|
||||
"path": "scripts/rehearse-ledger.py",
|
||||
"sha256": "5c43b655149d8ae577fab80e76358be35f90cb0357df9b726ac7cb23346946a0"
|
||||
}
|
||||
],
|
||||
"all_projection_resource_uids_bound": true
|
||||
}
|
||||
110
docs/sender-attended-entry-2026-10-31.md
Normal file
110
docs/sender-attended-entry-2026-10-31.md
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
# Attended sender release preparation
|
||||
|
||||
The source-bound launcher and node coordinator are implemented. Twenty-one new tests
|
||||
pass; the full owner suite reports **270 passed, 21 existing optional harness
|
||||
skips in 36.83s**. This does not establish live sender deployment. No runnable
|
||||
proposal has been sealed: the exact credential owner task RPF-WP-0068-T04 is still
|
||||
`todo`, and the preparation command refuses before contacting the node.
|
||||
|
||||
EMAIL-WP-0010-T02 now waits for that owner return so the live proposal and its
|
||||
exact digest can be prepared and reviewed. T03/T04 retain attended execution and
|
||||
independent acceptance. The existing native adapter's five server dry-runs and
|
||||
pinned-image snapshot rehearsal remain source-valid; those sources did not change.
|
||||
|
||||
## Source binding and admission
|
||||
|
||||
`scripts/release-sender.py` is the workstation entry point. It defaults to no
|
||||
action and requires an explicit prepare/show/inspect/execute/recover selection.
|
||||
Preparation requires a private fresh output path and the complete successful
|
||||
foundation journal. It checks that the exact RPF-WP-0068-T04 UUID and workplan UUID
|
||||
are marked done in State Hub before any node call. The owner handoff must include
|
||||
the review's Warden session revocation/cleanup, CCR verification and rotation
|
||||
inventory obligations; the consumer never marks that task done itself.
|
||||
|
||||
The node repeats the owner check, validates the foundation receipt's fixed digest
|
||||
and proof fields, verifies current projection specs/Ready/ownership and the
|
||||
admitted service-account UID, then performs the five native server dry-runs. Its
|
||||
proposal binds complete before/after observations, the exact foundation contract,
|
||||
all four projection resource UIDs, successful owner receipt, completed task
|
||||
identity and eight source hashes. A replaced projection refuses forward execution
|
||||
even if its spec is unchanged; explicit configuration recovery remains available.
|
||||
The capsule contains those eight exact files, including launcher and coordinator.
|
||||
It is saved exclusively as mode 0600 in a private operator directory.
|
||||
|
||||
Execution requires the retained capsule, unchanged reviewed source bytes, the
|
||||
full proposal digest, a human terminal and the exact `DEPLOY <digest>` response.
|
||||
It rechecks the owner return and native preimages. Source transfer uses a fixed
|
||||
SSH target and a quoted Python bootstrap; payload data never enters shell code.
|
||||
The bootstrap verifies source hashes and uses a temporary private directory with
|
||||
isolated Python imports. No generic archive extraction or persistent installation
|
||||
is involved.
|
||||
|
||||
## Durable execution and recovery
|
||||
|
||||
The node creates one exclusive attempt directory under
|
||||
`/var/lib/email-connect-sender-release/<proposal-sha256>/`. It retains the capsule,
|
||||
private append-only journal, process identity and ledger snapshots. The journal
|
||||
is exclusively locked; the existing ledger capture lock excludes concurrent
|
||||
backup capture. The coordinator invokes the actual native adapter and protocol
|
||||
for pause, fence, capture/replay, configuration change, resume, runtime checks,
|
||||
postflight comparison and UID-bound helper cleanup.
|
||||
|
||||
The successful forward result is `sender_deployed_verified`; successful explicit
|
||||
recovery is `configuration_recovered_verified`. The final journal phase is the
|
||||
durable evidence if the launcher's response is lost. A failed response or timeout
|
||||
is **unconfirmed**, not proof that the node stopped. The launcher never retries.
|
||||
|
||||
`--inspect` checks the retained capsule, process PID plus Linux start ticks, the
|
||||
journal and current recognized configuration. It checks recovery processes as
|
||||
well as the original process. A running attempt is reported as running. After
|
||||
the process exits, it reports the journal phase and actual sender/replica count;
|
||||
it does not mutate or resume the application. Inspection refuses a truncated
|
||||
journal or unrelated native drift instead of reporting success.
|
||||
|
||||
`--recover` requires the same capsule/digest and a human `RECOVER <digest>`
|
||||
confirmation. It does not depend on a still-healthy new projection or a renewed
|
||||
owner approval: it restores the already reviewed original configuration after
|
||||
capturing the **current** ledger. It retains subsequent accepted and uncertain
|
||||
sends, suppression and consumed/canceled handles. It never restores an older
|
||||
database, clears unknown reservations or sends a message. Repeated forward
|
||||
execution and completed recovery refuse. If source files have changed, restore
|
||||
the exact reviewed capsule sources before invoking its launcher; never edit or
|
||||
reseal a retained attempt to bypass a mismatch.
|
||||
|
||||
Some ambiguous states require separate inspection: a truncated journal, a crash
|
||||
during initial metadata creation, an unconfirmed helper creation without a
|
||||
recorded UID, or unrelated configuration drift. The tool does not silently adopt
|
||||
pods, discard evidence or invent a recovery from those states. A missing local
|
||||
capsule must be recovered from the retained private node copy, not reconstructed
|
||||
from current configuration.
|
||||
|
||||
## Validation scope
|
||||
|
||||
The assembly tests invoke the actual coordinator, protocol and native adapter.
|
||||
Kubernetes transport is modeled with synthetic objects; SQLite capture/replay
|
||||
runs in real subprocesses, and runtime probes contact the actual scoped WSGI
|
||||
application on local loopback with zero synthetic provider sends. Host path/UID
|
||||
substitutions are explicit in that harness. It is not a real Kubernetes rollout
|
||||
or a new pinned-image claim; the separate isolated-image rehearsal covers that
|
||||
snapshot path.
|
||||
|
||||
Tests cover complete forward/recovery, a lost native configuration reply, later
|
||||
accepted and uncertain sends, capture-lock contention, retained exclusive attempts,
|
||||
source/proposal/foundation/owner drift, private complete final foundation receipts,
|
||||
terminal and exact confirmation gates, bootstrap hash refusal, unconfirmed SSH
|
||||
timeouts and real process lifetime observation. The earlier protocol tests retain
|
||||
their ten real abrupt child exits around phase boundaries.
|
||||
|
||||
Ruff passes. Suite log: `/tmp/email-sender-release-final-check-20261031.log`.
|
||||
Source hashes and the live owner-gate refusal are in
|
||||
`sender-attended-entry-2026-10-31.json`.
|
||||
|
||||
## Next owner handoff
|
||||
|
||||
After RPF-WP-0068-T04 has its verified native return, prepare a fresh private
|
||||
capsule using `--prepare --packet <new-private-path> --foundation-receipt
|
||||
<successful-private-journal>`. Preparation is read-only for production. Review
|
||||
the resulting digest, native preimages and bound sources; publish the concrete
|
||||
execution/recovery packet before asking for attended execution. The actual
|
||||
`--execute` and `--recover` calls then use that retained `--packet` and its exact
|
||||
`--expect-digest`. No live digest or execution instruction is claimed ready here.
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
# Native sender adapter preparation
|
||||
|
||||
EMAIL-WP-0010-T02 remains in progress. `scripts/sender_native.py` connects the
|
||||
The native adapter is implemented. `scripts/sender_native.py` connects the
|
||||
sender transition protocol to the existing Kubernetes, ledger capture and
|
||||
isolated replay tools. It has no CLI; default construction permits reads and
|
||||
server dry-runs only. The attended entry point and final source-bound release
|
||||
packet still need preparation. No production sender change occurred.
|
||||
server dry-runs only. The attended entry point is now implemented separately;
|
||||
EMAIL-WP-0010-T02 waits for the verified owner return before sealing the final
|
||||
live release packet. No production sender change occurred.
|
||||
|
||||
## Implemented native checks
|
||||
|
||||
|
|
@ -68,6 +69,11 @@ tests. Ruff passes. Log: `/tmp/email-sender-native-check-20261031.log`.
|
|||
|
||||
## Remaining T02 work
|
||||
|
||||
Update: the launcher, source binding and assembled protocol/adapter tests are now
|
||||
implemented in [the attended entry review](sender-attended-entry-2026-10-31.md).
|
||||
T02 waits for the verified owner receipt before sealing the live proposal and
|
||||
publishing its concrete execution/recovery digest.
|
||||
|
||||
Bind the complete executor and dependencies into the final capsule, implement the
|
||||
attended entry point with exact proposal digest and owner-return verification,
|
||||
and prove the assembled forward/recovery path. Prepare the concrete execution and
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
# Sender transition protocol preparation
|
||||
|
||||
EMAIL-WP-0010-T02 is in progress. `scripts/sender_transition.py` is a tested
|
||||
`scripts/sender_transition.py` is a tested
|
||||
protocol core, with no production CLI or Kubernetes credentials. It does not
|
||||
establish native fencing, credential admission or an execution-ready release.
|
||||
The adapter and attended entry point are now implemented separately; T02 waits
|
||||
for the verified owner return before sealing the final live proposal.
|
||||
|
||||
## Concrete behavior
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue