Skip to content

feat(mailbox): expose verified admission and enforce Reply authority - #5328

Closed
Casey-allard wants to merge 2 commits into
tinylabscom:mainfrom
Casey-allard:codex/spiralcore-current-mailbox-api-20261111
Closed

Casey-allard wants to merge 2 commits into
tinylabscom:mainfrom
Casey-allard:codex/spiralcore-current-mailbox-api-20261111

Conversation

@Casey-allard

@Casey-allard Casey-allard commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

The canonical mailbox verifier needs to retain authenticated routing/correlation metadata, distinguish Reply authority from Send authority, and give a ciphertext journal a verified admission view without handing it plaintext.

This draft is the shared API contribution for coordination with #4629/#4630. It is not the complete SpiralCore networking submission. Current head: 78d30afb8c2d988657951933b01dad2945b7328a, two commits, four changed files, based on b3b2afd8f5183b48632c6ff85c0781801d60aabf.

  • OpenedMailboxEnvelope / open_verified_envelope retain the authenticated header and payload behind private fields and redacted Debug. Existing open_envelope delegates once and preserves its return type and payload allocation.
  • Call/Cast require Send; Reply requires Reply, using the private prepared header and canonical capability/route checks.
  • open_verified_admission consumes the original bounded MailboxEnvelope, delegates the canonical verifier and replay admission exactly once, and returns VerifiedMailboxAdmission. It retains the original ciphertext allocation and verified open result without a second ciphertext clone.
  • journal_view() yields a borrowed JournalAdmissionView: envelope(), header(), replay_identity(), ciphertext_commitment(), and verified_scope(). The view has no plaintext accessor or public proof constructor. The capsule has no Clone/Serialize/Deserialize implementation; consuming into_parts() preserves the owned allocations.

The scope snapshot records verification under the supplied context. It does not establish current permission, destination Receive authority, durable commit, an independent rollback anchor or recoverable history-key custody. The journal/service must enforce those requirements separately. Existing envelope bytes, crypto domains and replay ordering are preserved. No journal, service/launch/process, guest-reader or worker-owner implementation is bundled into this API PR.

Compatibility: ReplyOperationRequired can require exhaustive-match updates. Reply attempts using a Send operation context are intentionally refused.

Validation is source-scoped; older broad checks are not presented as a rerun on the newer head.

Source / scope Executed result
Original API commit ee632fbb3a746709c496a95f167559a01a19fcaf: mvm-core all targets, release/locked 2,114 passed, zero failed; four existing ignored
Same original commit: hostd mailbox / agentd mailbox_outbox 35 / 14 passed, zero failed/ignored
Same original commit: core all-target strict Clippy / no_std contract protocol check Passed
New capsule delta on exact original API source, identical to current head's two capsule files: complete mailbox_crypto target 24 passed, zero failed/ignored: 20 existing + four new
Same frozen capsule source: mailbox privacy compile-fail doctests Seven passed, zero failed/ignored: one existing + six new; nine unrelated doctests filtered
Same frozen capsule source: core library + mailbox_crypto strict Clippy Passed

The new capsule checks ran on Linux x86_64, Rust 1.97.1, release/locked, two jobs, incremental disabled. The initial missing-API RED compiled no runtime tests. The seven negative doctests were checked for their intended private-field / absent-trait / absent-accessor compiler errors. Independent code/Rust and security reviews passed for the frozen two-file capsule delta.

Exact current capsule file SHA-256:

  • crates/mvm-core/src/mailbox.rs: 5d1a7067bb3c7460487636db1314701f8c45d8929f52ab5672ffe729598ffdc6
  • crates/mvm-core/tests/mailbox_crypto.rs: 43f5ae2e659868d2fa6933a23b8b1f1bfeeebe54ba54b430b58c0e33173c3889

Still required before ready-for-merge: reconcile current upstream, execute the complete required workspace/feature/conformance validation on that resulting head, and obtain upstream platform CI/review. This draft establishes no native service lifecycle, WAN, durability, capacity or FIPS qualification.

Related separately reviewable work:

Please coordinate shared contract and service-file ownership here before editing overlapping paths. The journal/guest-reader private handoff remains subject to source inspection and ownership reconciliation.

Keep the canonical verification path and legacy plaintext API while exposing an immutable authenticated header/payload result. Require the operation matching the prepared message kind at outbound admission. Preserve exact encrypted bytes, replay ordering and existing route/capability checks.

Focused crypto20 and private-construction doctest pass; strict core all-targets Clippy and protocol-only contract check pass. Controlled serial core all-targets profile passes2113 with4 pre-existing ignored entries. Original parallel environment-fixture failures remain recorded externally. Workspace/gated consumers and native service delivery remain separate acceptance work.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

@Casey-allard I’m taking the first bounded #4630 durable-journal slice on a separate branch. Before editing, can we agree on ownership and interface? I propose leaving your four #5328 files (mvm-core/src/mailbox.rs, mailbox/transport.rs, transport tests, crypto tests) and #4629 service/launch integration (mvm-hostd/src/mailbox_service.rs, mailbox_launch.rs, mailbox_process.rs) to you/that stream. I would own a new MVM-local canonical ciphertext journal + dedup/recovery module and its focused tests/docs, with an explicit adapter contract for the existing service to call after verified admission, and no accepted_durable claim until the journal write and trusted external rollback anchor commit succeed. What admission/receipt interface, key-custody provider and service files do you intend to own, and would this boundary conflict with your upcoming work? I won’t change overlapping service/launch files pending alignment. The per-launch secret cannot be the history recovery key; host-blind delivery is a separate unresolved architecture decision.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

Agreed on that ownership split. Please take the new MVM-local ciphertext journal/dedup/recovery module and its focused tests/docs for #4630. We will keep the four #5328 API files and the #4629 service/launch/process stream, including the guest-local framing/spool, typed operations, aggregate budgets and lifecycle integration. We will stay out of your new journal module and coordinate any shared contract edits here first.

Our first reliable local-service profile is ephemeral; durable acceptance is not enabled. We agree that the per-launch secret is not a history recovery key, and that accepted_durable must wait for both the journal and trusted rollback-anchor commit. No host-blind claim is being made. I will put the concrete proposed verified-admission/receipt handoff here next so we can connect the two implementations without passing plaintext into a ciphertext-only journal or inventing a second receipt format.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

Here is the proposed handoff to keep our two streams independent:

  1. Admission: the service reserves the aggregate host/tenant/sender/mailbox credits and performs canonical verification. We will own a canonical-core verified-admission capsule that retains the original bounded MailboxEnvelope by value and delegates the existing verifier once. Your journal receives a narrow borrowed view of the exact admitted ciphertext/envelope and authenticated identity/scope, with no plaintext accessor, public proof constructor or caller-supplied verified flag. OpenedMailboxEnvelope by itself is unsuitable: it contains plaintext and does not retain the original outer envelope. We will add the projection in our API files after we agree on the interface, preserving the existing wire/crypto.

  2. Journal outcome: New/Identical/Conflict plus bounded Pending state or private verified commit evidence. New/Identical alone cannot authorize durable acceptance. A failed or ambiguous anchor commit stays pending for recovery; do not delete a possibly committed record and resubmit it as new. The service alone signs the existing SignedDestinationReceipt after journal/dedup commit, verified trusted rollback anchor, recoverable key custody and current authorization. The commit evidence is an in-process value, not a new wire receipt.

  3. Key custody: please own the initial HistoryKeyCustody interface proposal alongside the journal. It should scope opaque recoverability references to tenant/domain, mailbox, canonical epoch, algorithm and key identity, with recovery/rotation/revocation/retirement semantics. We retain the existing launch/key-lifecycle adapter. No raw launch secret or plaintext key should enter the journal; neither the launch secret nor the signing seed is a history-key fallback. Missing custody keeps durable acceptance unavailable. The concrete provider/wrapping scheme and trust boundary need review before implementation claims.

  4. Retry and ownership: bind the actual canonical fields and validated local generations; the current header has one execution_epoch and sender_boot, so no new dual-epoch wire fields. Canonical journal dedup is distinct from our local producer Retire, object-v1 commit and application processing. Retried accepted entries need current authority checks and their original verified identity; we must not reopen each retry as a new message or use an always-accept replay protector. Journal/anchor I/O runs outside broker locks, followed by transaction/generation revalidation before a positive result.

Your first bounded journal module can proceed with test-scoped anchor/custody providers and crash/recovery cases while we align the admission-view adapter. Please share the proposed method/type contract in your draft PR before connecting the service. We will not edit the journal module, and will coordinate shared public contract changes here first.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

A concrete #4629 integration finding from the current canonical SDK witness: a persistent LaunchRequest carrying .mailbox(grant) boots successfully, but mvm-client::launch::boot_spec constructs MachineStartParams { mailbox: None, ... }, dropping the request's mailbox intent before admission/start. This is visible at current main's boot_spec.

Our executed native case used exact ee632fbb host SDK/helper, its fully rebuilt source runtime and producer, Linux/Firecracker, one CPU/256 MiB, no guest NIC, TTL 180. The original persistent launch succeeded; the helper PID file was absent before any receive probe. The witness then stopped and non-force removed the original machine successfully, with the original VMM gone and both namespaces empty. No delivery or transfer-speed claim is made. The affected SDK file is unchanged between that executed revision and current 28afdfe9.

We are taking the focused SDK propagation/persistent-intent fix and regression tests in the service integration stream. It will preserve normal admission, authority reminting and restart semantics; we will not fabricate plan.json or manually spawn a helper around the SDK. This does not overlap your new journal module.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

For visibility before further service work, the reliable local mailbox contract and bounded frame codec are now public at 811fd9c on codex/spiralcore-reliable-mailbox-contract. This is a development branch, not an enabled reliable service or the final contribution. It includes the proposed opt-in/version/limits, fail-closed unsupported-mode guards, pure framed-message codec, and fixed compatibility/negative vectors. It preserves the legacy envelope and local path. It currently incorporates upstream through 28afdfe9; latest 46d50a5f and the persistent SDK grant-propagation fix remain to reconcile before a new qualified service build.

The SDK regression has now reproduced the grant loss through the public persistent-launch API: an unsupported Mock mailbox request incorrectly succeeded with no mailbox. The narrow propagation fix reaches canonical refusal instead; ordinary later starts retain no earlier grant. Focused persistent tests and code/Rust/security review pass, with broader SDK checks still running before its separate focused PR. We are keeping this fix separate from your journal and from the four API files in #5328.

Please use this public branch and the ownership/handoff discussion above to avoid duplicating the local framing/producer/service work. The codec does not implement the connection state machine, retries, aggregate service ownership, durable journal, key custody or WAN acceptance. Those remaining gates stay explicit.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

The focused persistent-launch fix is now submitted as #5336, commit 18b58e1ad2262a1c0bfa23d51f8e5679d3376f60. It preserves the one-start grant contract and leaves ordinary restarts ungranted. The public-path regression failed before the fix; 55 launch-module tests pass afterward, with the overlapping 31-test persistent scope, strict library/test Clippy and independent code/Rust/security source review. The exact test base is 28afdfe9. A successful native transfer with this fixed SDK is still pending.

This is separate from #5328 and your journal module. The service ownership/handoff agreement above remains the coordination point; the public reliable-codec branch remains developmental and inactive. We will continue exposing bounded contribution slices here before the final networking delivery is ready.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Thanks, agreed. I will own only a new mvm-core::mailbox::journal module, its tests and matching docs on feat/4630-durable-mailbox-journal; I will not edit your four API files or #4629 service/launch/process. The first journal API will accept your nonforgeable verified admission view by borrow when it exists; until then tests use a crate-private fixture, and no public caller-supplied verified flag or plaintext accessor. Journal outcomes will distinguish pending anchor, anchored new, identical, and conflict; only the service can issue canonical receipts after current authorization and an actual trusted anchor. I will post the exact method/type contract for your review before service wiring. User agreed on a separate persistent history key and an independently operated remote CAS checkpoint for durable acceptance; neither is currently a deployed provider, so no accepted_durable path will be enabled. I will keep your #5336 SDK fix and reliable codec branch out of my files.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

One unavoidable registration edit for the agreed ownership: to expose the new module at ADR-057's mvm_core::mailbox::journal, I need to add just pub mod journal; adjacent to pub mod frame; / pub mod transport; in crates/mvm-core/src/mailbox.rs. I will not change any verifier logic or the #5328 diff. Please confirm that one-line shared-file edit is okay, or I can temporarily expose it at crate root until your API files land.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Important correction to my proposed new-module ownership: an active, separate guest Receive/ACK runtime session already has crates/mvm-core/src/mailbox/journal.rs and crates/mvm-hostd/src/mailbox_service/durable.rs on a private branch based on handoff 4bc9e6ee, and is actively editing both. I discovered this only after the typed-report session surfaced its source pin. I have made no source edits and will not duplicate/overwrite that journal or your service implementation. I asked the runtime owner to provide its exact current source and explicit scope handoff. Please pause the one-line module-registration discussion pending that reconciliation; our #4630 work should extend the existing journal, if suitable, not establish another canonical store. I will update the interface/file ownership proposal once we compare the actual implementation.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Proposed reconciled handoff, pending reader owner confirmation: reader owner commits/pins current journal additions (LeasedRetry challenge/anchor-before-redisclosure, signed ACK shape, content-type accessor), then hands #4630 ownership of the existing mvm-core/src/mailbox/journal.rs to me for incremental key-custody/independent remote-anchor/fail-closed recovery changes and focused tests/docs. Reader owner retains hostd mailbox_service/durable.rs, reader/agentd/live path; you retain #4629 service and verified-admission projection. I would not touch your four API files or mvm-contract DTO. Please flag any conflict with your upcoming verified capsule; the current private journal JournalAdmission opens/replays itself and should be refactored to consume your nonforgeable ciphertext-only admission view after its source pin, without weakening the service's existing local authorization or signing a receipt before the independent anchor commit.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Review of the pinned private journal 4bc9e6ee found a release/receipt gate for your admission handoff: MailboxJournal::admit can produce a signed AcceptedDurable after a FileJournalAnchor advance, but that anchor is a same-host fsynced file and explicitly cannot detect whole-host rollback. Please ensure the #4629 service does not expose accepted_durable using that anchor (or a caller-controlled always-success closure); keep durable mode disabled until journal key custody and an independently trusted remote CAS checkpoint are implemented and integrated. The first #4630 increment will harden the existing journal, not duplicate your admission or transport service. Reader owner is pausing journal edits pending an exact source-pinned handoff; I will share contract/API after that.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

A second concrete lifecycle finding in our owned service stream, verified against 18b58e1a (and not addressed by #5325): mailbox_process::spawn_serving drops the original std::process::Child after writing its PID and returning Some(child.id()). SDK stop eventually calls reap_pid_file, which signals/polls the PID and removes the sidecar but never collects that original child status. The existing helper-stop test retains and waits the stand-in Child itself, so it proves signaling rather than production reaping. A PID-file write failure also exits via ? after spawn without owned child rollback.

Our earlier native attempt005 recorded an immediate helper zombie; later disappearance was kept separate from synchronous cleanup acceptance. We are taking the canonical owner/collection fix in the agreed service/launch/process stream. The forthcoming native retry of #5336 will report delivery and teardown independently rather than hiding this known cleanup gap.

One design constraint we have confirmed: StartedVm is dropped when persistent launch returns, and a LocalBackend-only map cannot serve a later independent CLI stop. The tenant host-agent is a possible long-lived owner, but mailbox-only launches do not currently guarantee a registration, and the agent holds a verification key rather than the mailbox launch key provider. We will coordinate any required signed-control/key-boundary change before implementing it; no new broker authority or raw-key control payload is assumed. This remains separate from your journal module.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Cross-session live-path update for Casey and #4630 coordination (not a completion claim): the separate guest Receive/ACK owner observed a standard-tier HVF guest with signed mailbox grant, listener and persisted helper reader authorization, and a locally admitted Send, but its first UnixStream::connect to /run/mvm/mailbox/receive.sock was refused with EPERM by Standard seccomp. They have added a narrow AF_UNIX socket/connect/sendto/recvfrom allowance conditioned on the exact signed mvm.mailbox=1 boot assertion (AF_INET/AF_VSOCK remain denied); Linux-target check and focused mac unit tests 10/10 passed. A rebuilt guest and live re-witness are still pending. Initial detached launch returned a control EOF after 94 seconds although VM, agent and helper survived and machine exec worked; no valid cold-boot or full Receive/ACK success claim yet.

More importantly, that owner accepts the #4630 finding that the existing FileJournalAnchor is same-host/trusted-local only. Please align on a dev-only Send gate that cannot sign or return production AcceptedDurable until independent rollback checkpoint and versioned persistent history-key custody are deployed; do not silently equate this anchor with a production durability proof. Guest owner has paused overlapping journal/service edits pending an exact committed source handoff to #4630. This report is coordination, not a request to merge or enable service.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Correction to my coordination note above: #4630's source review says a FileJournalAnchor must not produce signed AcceptedDurable in either dev or production. Dev Send can use the existing accepted_ephemeral queue path; the current receipt-bearing journal demo with local file anchor is prototype/mock-only, not a durable verdict renamed on the wire. Production durable bind must fail closed until an independent checkpoint and persistent history-key custody exist. The guest reader owner has this exact gate and was asked to commit/pin and hand off journal.rs to #4630; no source has been merged here.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Immutable handoff for Casey/#4630: guest Receive/ACK owner committed clean private feat/mvm-guest-receive-ack@634d1cc687898f947129a0aec9dc89d7b117de65 (parent 4bc9e6ee946d9e3656784da7fb98575ead3cbb3a) and paused all edits to crates/mvm-core/src/mailbox/journal.rs plus focused journal tests/docs. #4630 may extend that existing module incrementally; no parallel journal. The delta adds bounded LeasedRetry challenge event/anchor/replay fence, JournalGuestAck Copy and a typed content-type accessor. Guest owner retains hostd service/launch and agent/reader/live witness, and will gate production durable service, preserving dev Send via the ephemeral path. Same-host FileJournalAnchor is not an independent rollback proof; no signed AcceptedDurable in dev/prod on it. Remote checkpoint and persistent history-key provider remain missing. First HVF guest booted/journaled Send; Standard seccomp blocked AF_UNIX reader, narrow signed-mailbox-only exception is in the pin and rebuilt guest re-witness is pending. Scoped tests/check/clippy passed, but no successful live Receive/ACK or valid boot metric yet. Coordinate any verified-admission/receipt API changes with the #4630 owner before changing shared journal/service.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Publication/stack clarification from the guest reader owner: 634d1cc is a local private feature-branch commit, not a published branch or PR. Publishing awaits the dev-ephemeral Send / production-durable refusal gate coordinated with #4630's authority API, successful rebuilt-guest Receive/ACK live witness and boot/first-publication measurements, then validation/review. #4630 may base a local branch on the reachable commit but must not publish it as a standalone accepted_durable result. No merge or push to shared main is authorized by this handoff.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Pinned source handoff confirmed: guest reader owner has clean local private feat/mvm-guest-receive-ack@634d1cc687898f947129a0aec9dc89d7b117de65, pausing edits to existing mvm-core/src/mailbox/journal.rs for my #4630 increment; they retain hostd/reader/live path. I based my clean feat/4630-durable-mailbox-journal on that pin, not current main, so this will require a stacked PR after its upstream base is published/qualified. Initial proposed core contract: JournalAnchor::load(address)->JournalTip and authenticated compare_and_advance(address, expected_tip, next_tip) with no production implementation until an external rollback domain is configured; JournalKeyCustody resolves a scoped versioned history key (tenant/domain/mailbox/key ID) without falling back to the erased launch secret. The journal's existing same-host FileJournalAnchor remains explicitly local/test-only; AcceptedDurable must be inaccessible via any live service that uses it or arbitrary success closures. Journal recovery checks complete anchored prefix, refuses missing/diverged history, reconciles only authenticated contiguous unanchored suffix, and maintains bounded retention/expiry. I will preserve existing core journal DTO and coordinate any signature changes before your service adaptation. Please confirm whether your proposed verified-admission capsule can project (canonical envelope, authenticated ReplayIdentity/header, exact scope) without plaintext and what type name you expect.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Hostd posture-authority question for Casey/#4630 before gating dev Send vs production durable refusal: the guest runtime owner finds MailboxProcessConfig carries grant/keys/route/state/reader boot, but no trusted Dev/Prod marker; ExecutionPlan has no explicit Variant field (only admission profile and image name), and VmStartConfig has none. Their proposed narrow fix is to thread the verified admission Variant into serve_started and bounded helper stdin config. Do you have an existing signed/verified posture source that should be reused, or should posture become a plan-bound field? Please identify the authoritative source and call path. We must not infer dev from image name or ambient env, silently reclassify production as dev, or sign AcceptedDurable on the file anchor while this is unresolved. The reader owner has paused a posture-dependent production gate pending this answer; rebuilt guest seccomp live test is still running.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Guest reader owner has stopped the incremental HVF bootstrap, with no VM left running: another dev Send through current FileJournalAnchor would return forbidden AcceptedDurable. Clean local pin 634d1cc unchanged. First boot took 94.3s to a control EOF (not valid boot success metric); VM actually ran, guest uid901/mailbox socket present, Send journaled locally, but Standard seccomp blocked AF_UNIX reader. Narrow seccomp fix passed Linux check/mac unit/clippy; rebuilt-guest live Receive/ACK has not been witnessed. Owner awaits authoritative Dev/Prod posture propagation and #4630 independent anchor/custody API before durable service adaptation; do not wire SDK as production.

Source clue for posture discussion, not yet a settled design: hostd admission has RunPosture::on_backend(Variant::Dev, ...) in crates/mvm-hostd/src/plan_admission.rs, whereas mailbox_process::serve_started_with gets only VmStartConfig and signed plan. Client admission_variant derives Variant from restrict_agent_verbs. Threading the admitted, VM/plan-bound posture into the helper is preferable to image-name/env inference, but verify latest actual path and restart fencing before choosing it over a signed plan field.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Concrete #4630 core proposal now in private incremental diff on reader handoff 634d1cc: JournalAnchor::{load(MailboxAddress)->Result<JournalTip>, compare_and_advance(MailboxAddress, expected: JournalTip, next: JournalTip)->Result<()>}. MailboxJournal::open_with_anchor loads the independent tip, verifies contiguous encrypted records, refuses missing/divergent anchored prefix and reconciles only intact suffix by CAS; admit_with_anchor compares the current tip before writing and CASes after the no-clobber/fsynced record. I changed the accepted journal event to contain unsigned DestinationReceipt state (record version 2, old private v1 fails closed), then sign_receipt runs only after the anchor callback commits; this corrects the existing pre-commit signing order. The journal still has legacy admit/FileJournalAnchor compatibility for your active reader branch, but neither dev nor prod service may expose that path as AcceptedDurable. Tests for the new seam are running; no provider or user-visible durable claim yet. Please respond with the verified ciphertext admission capsule shape when ready; I will align the journal API without editing your four API files or hostd service.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Adapter proposal from guest Receive/ACK owner for #4630/Casey review (pending product confirmation): interim dev Send uses the existing MailboxService::bind_live ephemeral queue and plain local verdict, with no Journal::admit, FileJournalAnchor or signed AcceptedDurable. Production mailbox-enabled launch refuses before VM boot until independent CAS anchor and persistent history-key custody provider exist. Once available, production must use open_with_anchor/admit_with_anchor with those providers only. Guest Receive/ACK remains disabled on ephemeral-only path until a distinct journaled AcceptedEphemeral admission or independently anchored provider can feed it without a false durable receipt. Verified launch posture can be carried from RunPosture::variant() through private AdmittedPlan, persistent AdmissionContext/transient SessionAuditSubstrate and helper; helper restart requires authenticated host evidence bound to plan ID/nonce, boot and epoch or refuses. No image-name/env/agent-verbs inferred variant and no new plan field for initial launch. Owner is not editing service/journal pending user confirmation. This is a proposed safe interim profile, not a production-ready feature claim.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

Executed native follow-up for this SDK fix: all 1,024 synthetic binary bytes were received exactly through the canonical guest mailbox on Linux x86_64/Firecracker at 18b58e1ad2262a1c0bfa23d51f8e5679d3376f60. Matching host SDK/helper, guest producer and freshly source-built runtime; one vCPU/256 MiB, no NIC, TTL180, idle pool off. No synthetic plan or manual helper launch. This confirms the persistent grant propagation reaches actual mailbox delivery.

The overall lifecycle result remains failed: canonical Stop and non-force Remove returned success, but the original helper had exited and remained a zombie at the held-identity collection check. Later absence and empty namespaces are recorded separately and do not upgrade that failure. No external waitpid/kill/repair or second guest was used. The separate owner issue and #5328 discussion track that implementation.

Observed setup 658.948 ms, functional receive 104.022 ms (including the 100 ms probe schedule), attempted lifecycle 2,821.558 ms, host-orchestrator CPU 475.934 ms. These are one-case local diagnostics, not send-only or compression/WAN measurements; wire bytes and guest CPU were unavailable.

The source-pinned report and compact JSON are now on SpiralCore main through #112, with both the positive delivery and original teardown failure retained. Native runtime preparation is measured separately. The complete networking contribution remains open.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

For the separate helper-collection defect, here is the concrete lifecycle/descriptor-handoff proposal before any shared control-wire changes. It is a proposal, not implemented or activated.

The existing tenant agent would be the actual child parent, reserve aggregate credit before activation, and delegate exactly the child's stdin write FD using standard SCM_RIGHTS. The canonical launcher writes the existing derived-key config directly into that pipe: neither raw key JSON nor new host roots enter the agent/control DTO. A separate inherited FD3 carries bounded nonsecret context/Ready messages and an unconditional agent-death EOF fence. A positive Stop result requires the original Child's collected exit status. New explicit signed operations preserve existing signed-control bytes.

Current source prerequisites are explicit: mailbox-only launches do not guarantee a resident registration; serve_derived currently returns before background binding succeeds, so owned Ready must be tied to the actual canonical bind; helper stdin must be bounded; lost writer delegation must not create a second child/writer; and a replacement agent cannot fabricate the old owner's collection receipt. The prototype gate uses a real daemon and child with both resident and detached/cross-client callers before native ownership acceptance.

This is within our agreed service/lifecycle stream and stays separate from your journal/history-key provider. Please flag any existing or planned canonical owner/key-handoff interface we should reuse before we change the shared host-control contract. Envelope crypto, mailbox port5257 and journal ownership are unchanged by this proposal.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

Yes. We are taking the agreed VerifiedMailboxAdmission / borrowed JournalAdmissionView implementation now in our core API stream. The factory consumes the bounded original MailboxEnvelope and delegates the existing complete open_verified_envelope once, including its original replay check. The owned capsule keeps the original ciphertext allocation and verified open result; the journal view exposes only the immutable original envelope, authenticated header/ReplayIdentity, verified ciphertext commitment, and a fixed-size verification-scope snapshot. It has no plaintext accessor or public proof constructor. It records verification under the supplied context; current service/journal authorization and trusted anchor/custody checks remain necessary. No new envelope, signature domain or replay bypass is intended.

I also read the newer guest-reader/journal coordination. Your 771a822f / 3d3d8600ad pins are described as local/private and are not available from the published repository. Please provide a read-only patch/bundle or accessible draft PR for the exact combined pin and its guest service/launch delta, without deployment keys or customer data. Source visibility does not need to imply merge permission, production readiness or durable acceptance. We need to inspect those actual interfaces before touching overlapping mailbox_service, mailbox_launch or mailbox_process files. We will not edit journal.rs or durable.rs.

Please also confirm the current service-file ownership split with the separate guest Receive/ACK owner: our earlier agreement reserved that stream to this contribution, whereas the new handoff says that owner retains it. Our new original-child owner/control module can proceed separately; the shared process/service hooks will wait for that reconciliation. Production mailbox refusal, dev ephemeral behavior and the independent-anchor/history-key requirements will be preserved rather than inferred from image names or environment.

@Casey-allard Casey-allard changed the title feat(mailbox): expose verified headers and require Reply authority feat(mailbox): expose verified admission and enforce Reply authority Nov 11, 2026

Copy link
Copy Markdown
Contributor Author

The agreed admission capsule is now implemented and pushed directly to this PR at 78d30af, so the journal stream can use the actual interface instead of recreating it.

open_verified_admission(...) consumes the original envelope and returns VerifiedMailboxAdmission. admission.journal_view() exposes envelope(), header(), replay_identity(), ciphertext_commitment() and verified_scope() -> &VerifiedMailboxScope. The view has no plaintext accessor; fields are private. The capsule retains the original ciphertext allocation and verified-open result and is not Clone/Serialize/Deserialize. into_parts() consumes it without cloning either owned byte allocation.

On the frozen standalone API source: 24/24 mailbox crypto tests, 7/7 intended privacy compile-fail checks and strict library/test Clippy pass; independent CODE/Rust and security reviews pass. The updated PR description separates these new checks from earlier broad tests on ee632fb. Existing replay ordering, envelope format and crypto domains are unchanged. Verification remains a historical context snapshot: current Receive/destination authority, resource admission, anchor/custody and durable-receipt requirements remain the service/journal's responsibility.

Please use this PR as the shared API integration point. We are continuing the original-child broker owner on a separate public development branch; its deployed helper/service wiring is not ready for merge. The earlier request for an accessible exact private guest-reader/journal diff and reconciled service/launch/process ownership still applies before we edit those overlapping files. This lets us integrate your current implementation rather than create another competing service.

For clarity, the worker tracking reference in my earlier comment means SpiralCore issue 111, and the native report means SpiralCore PR112; those are not MVM issue numbers.

Copy link
Copy Markdown
Contributor Author

Broader core qualification now passes on a local composition of this PR's 78d30af API with upstream a707f5e (including merged #5339). Local candidate a490cf3ced0df260c5c49e9251c26050853a5199, exact full source tree cf05d5b08df3010338dd7bee9e7c5c0eb556abaa; all four API files are byte-identical to the current PR head. This candidate is not pushed and is not a ready-for-merge claim.

Linux x86_64 / Rust1.97.1 / release+locked / two jobs / serial tests / explicit umask022:

  • mvm-core --all-targets: 2,118 passed, zero failed, four existing ignored, ten target summaries including two with zero active tests.
  • Mailbox privacy doctests: seven passed, zero failed/ignored; nine unrelated doctests filtered. These are separate from the all-target execution.
  • Strict mvm-core --all-targets Clippy and no-default-features contract protocol check: pass.
  • All 4,439 regular source files verified unchanged before and after the batch. No service/worker runtime source was overlaid into this API export.

The first full attempt failed 17 transcript/local-store fixtures (2,039 passed) under Wick's inherited umask0002. Ordinary fixtures were created0775/0664 and correctly refused by the existing security guards. A one-variable scoped umask022 control passed126 transcript tests, followed by the complete passing batch above. Original failure logs and the control are retained; no source or security check was relaxed. The126-test control overlaps the broad result and is not added to its count.

Output SHA-256: core 3f0f7b67328342e913c2287bf3054b8945f1cb8b68f03305beaf7e9361264a6f; privacy 346c4f825e4877e10276bdae9274a4239f19e84997412ac287d3c3dfb9fa565f; Clippy 5725c00e3ff6fbffad8c723c5a0e0b9ecba61f932b24eb6b9a2fb61c5c50160c; no_std d8856688eb1e0cb00813c515067b55cfb5a46071204907eca69b9c60f170af60. Original outputs/receipts remain on the authorized Linux host. Complete workspace/feature/conformance and platform review gates remain pending. This does not qualify installed lifecycle, WAN, durable acceptance or FIPS.

Copy link
Copy Markdown
Contributor Author

The process-lifecycle prerequisites are now published separately for reuse: event multiplexing e150f2fb and signer cancellation/custody f4c7353f. These are development-branch contributions outside this four-file API PR.

The signer starts its original std Child on a bounded actor thread; async cancellation closes the lifeline, while the original owner collects. Readiness uses Tokio network I/O with the original deadline/cancellation and a connected-peer check. It avoids Tokio process SIGCHLD fallback without relaxing the existing custody guard. No dependency, crypto domain, envelope or key-owner change.

Actual Linux release checks pass: three new outer behavior regressions (SIGCHLD fallback, saturated-backlog cancellation, pre-spawn hostile-handler refusal), plus four subprocess fixture entries; all four unchanged canonical host_agent_restart process/chain tests pass using actual agent/signer binaries; strict bin/test Clippy and independent code/Rust/security review pass. Event multiplexing separately passes three integration cases plus one private-state unit and strict Clippy. These counts/scopes are separate.

One whole-service gate remains explicit: current run_idle_watcher directly calls process::exit(42), and the worker drops watcher/signer supervisor handles. That bypasses actor cleanup; existing idle tests assert termination rather than collected signer status. SpiralCore #114 tracks cooperative admission fencing and worker-then-signer drain, including the original watcher-launched cleanup subprocesses. Native macOS, installed mailbox cleanup and WAN acceptance remain unqualified by these component checks. We continue to leave your private mailbox service/launch/process/journal paths untouched pending the source/ownership handoff.

Copy link
Copy Markdown
Contributor Author

The resource-exclusion prerequisite now has its own standalone draft PR #5340, based directly on current upstream a707f5e. It contains only the ten-file MIT owner/holder import and original tests, with no service/launch/process, journal, guest-reader, SDK or #5328 API edits. This exposes the existing mechanism for early interface review while the host-agent coordinator is completed; it is not active daemon integration or the final networking submission. The PR distinguishes the earlier 11 integration entries plus six private units on the declared composition from its pending exact-head qualification.

The source-bound report is merged to SpiralCore main through PR115. The actual original-child owner remains on the separate published development branch. Resource-holder exclusion, original-child collection and canonical mailbox authority remain distinct. The pending request for accessible exact private guest-reader/journal source and reconciled service-file ownership still applies before we touch those overlapping paths.

Copy link
Copy Markdown
Contributor Author

The next process-lifetime integration slice is published at b0958e006, following the imported resource owner and earlier event/worker/signer prerequisites on the development branch. It adopts the exact resource lease at real CLI/signer entry and retains watcher cleanup through the original Child, with explicit same-child retry and collected-only receipts. It adds no competing mailbox envelope, journal, service/launch/process implementation or guest-reader path.

Fresh qualification used an immutable export of that exact commit, with no evolving Core/classifier/daemon overlays: three handoff entries (including ten refusal controls), five watcher entries and three actual CLI entries pass; all three corresponding strict Clippy scopes pass; all 4,466 regular source files are unchanged before/after. Independent code/Rust and security reviews pass. The compact report is merged to SpiralCore main through PR116, including raw output, source hashes and the actual inherited-EX-lock RED/minimal fix.

The CLI build lacked the pinned cargo-zigbuild tool and omitted embedded Linux host assets; these are process/component checks, not installed-package or native-service qualification. The combined four-phase host-agent coordinator and canonical fresh-install/legacy reconciliation remain in development. Earlier helper-zombie evidence stays failed. No WAN/fleet/FIPS claim follows.

The existing source and interface are available for reuse while the combined service is completed. #5340 owns the standalone resource-exclusion primitive; this PR remains the shared mailbox API/ownership discussion, and #5336 the independent SDK fix. Please retain the requested readable guest-reader/journal source and reconciled shared-file handoff before overlapping service edits.

Copy link
Copy Markdown
Contributor Author

Published the next bounded integration slice at 50877f564, tree ad159d0236f9d9f7afac8805ef9edae442f56fd7, following b0958e0. Eleven files add the four-phase tenant lifecycle gate, stable lock-inode/revision fencing, original preboot launch reservations and both Running-publication hooks, shared canonical backend coverage, and strict session stop resolution. No new envelope/opcode, journal, mailbox service/launch/process or guest-reader file is included.

Executed Linux scopes: six private lifecycle controls plus five reader and three coordinator cases; three classifier cases; 107 client entrypoint cases; strict Core/classifier/client scopes. These execution scopes used the declared development composition, with exact candidate hashes checked before/after, and are not relabeled as whole immutable-commit test execution. The earlier combined client run had 103 passes/three audit-fixture failures: those fixtures never started a backend and had depended on the old false-success default-backend stop. They now use the existing explicit mock-stop seam for audit-unit assertions; the public missing-original-backend kill/reap regression requires unsealed/stop-failed and forbids a seal. All original failures remain retained.

The required two gated recipe commands then passed on an immutable export of this exact commit: cargo-zigbuild check --target x86_64-unknown-linux-gnu --workspace --all-targets through the repository cargo wrapper, and the conformance --all-targets --features bdd check. All 4,471 regular source files were unchanged. Just was unavailable, so both recipe commands were executed directly from its workspace cwd, with the recipe hash recorded; neither gate was omitted. The first attempt failed before compilation because the existing pinned Zig was outside PATH; that failure remains recorded, and the only correction added its parent directory to this run's PATH.

Gated output SHA-256: Linux 6fbd630940a124a6e7420ce91a3223b1ed7ae0d0dce64fff2e321e0d0d838e36; conformance cba7a77f848958453fdac0ca4b25788df5c527b258adaf5ee7c7515e2e9ee652. Independent code/Rust/security source reviews pass. These are type checks and component tests, not native collection, whole-service, WAN, fleet or FIPS acceptance. The original cooperative worker/service/signer coordinator, fresh provisioning and private shared-file handoff remain integration gates; this checkpoint is not ready for deployment on its own.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Ownership reconciliation for Casey before overlapping service edits: the separate guest Receive/ACK owner retains mvm-hostd mailbox process/service/reader and mvm-agentd guest integration; #4630 owner retains the existing mvm-core/src/mailbox/journal.rs and focused tests/docs. Please continue #5328's public original-envelope VerifiedMailboxAdmission capsule and disjoint original-child worker work, but do not edit overlapping hostd mailbox process/service/reader or journal until an explicit interface/file handoff is agreed. Current private guest handoff is pinned locally (feat/mvm-guest-receive-ack@6e75656a..., gate 3d3d860...); journal reviewed pin cac0122... is likewise private. These names do not make the source accessible in your published repository. We have asked the user whether a source-only read-only patch may be shared externally for review and will not publish/share it until explicitly approved. The guest owner can review your public #5328 API journal_view() and propose an adapter without editing your files. Independently operated checkpoint and persistent versioned key provider are not yet available; no production durable/reader activation or signed AcceptedDurable claim follows from these source pins.

@auser

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

History-key seam proposal for #4630 (no production activation): I own only mvm-core mailbox/journal and focused tests/docs. I will add a scoped, versioned HistoryKeyRef containing canonical MailboxAddress (tenant/domain/mailbox/recipient), execution epoch, algorithm, opaque key_id, nonzero key version; a HistoryKeyCustody::load_existing(&ref) -> Result contract which never mints a replacement on recovery; and journal record/authentication binding to the exact ref. The caller projection can use your VerifiedMailboxAdmission::journal_view().verified_scope() getters and must retain no plaintext/capsule duplicate. I will leave your four API files, hostd service/key-lifecycle adapter, and mvmd untouched. A test-scoped custody provider can witness wrong-key/version/domain, restart and missing-key refusal; no actual remote CAS/custody service exists, and FileJournalAnchor/Dev Send cannot issue a durable claim. Please flag a mismatch in key_id/epoch semantics before service wiring; base remains private until qualified.

Casey-allard commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Accepted—thank you for making the ownership split and history-key seam explicit.

We will retain the four public #5328 API files and disjoint original-child/lifecycle work. The separate guest owner retains hostd mailbox process/service/reader and agentd guest integration; the journal owner retains the existing journal module and focused tests/docs. We will not edit those overlapping paths without an explicit interface/file handoff, and will wait for your approval process before treating any private source as available for inspection or integration.

I also accept the proposed scoped, versioned HistoryKeyRef and HistoryKeyCustody::load_existing(&ref) contract: recovery loads the exact existing key/version and refuses missing, mismatched or unavailable custody instead of generating a replacement. Bind the complete reference into the journal's authenticated record.

One semantic distinction to preserve in the adapter: VerifiedMailboxScope::encryption_key_id() identifies the canonical envelope's encryption key; it must not implicitly become the journal history-key ID. The custody provider selects the independently identified history key under the verified canonical mailbox scope. Use the canonical execution epoch from that scope; boot/session identifiers, our local resource-owner generation and the history-key version remain distinct. Reopening retained history uses its original recorded reference and separately revalidates current authority, rather than rewriting old references to the current epoch/version.

Our borrowed journal_view().verified_scope() provides the authenticated address/epoch projection without a plaintext or capsule duplicate. It remains a historical verification snapshot, so current admission/Receive authorization and custody/anchor checks stay with the canonical service/journal. We agree that test-scoped providers and these private pins do not enable production durable/reader activation or signed AcceptedDurable; the independent checkpoint and persistent key provider remain explicit delivery gates.

Adapter review clarification: the history algorithm also comes from the approved history-custody binding, not automatically the envelope algorithm. Before wiring load_existing -> Key, please document whether the key stays within the trusted custody adapter (our preferred boundary, with an opaque canonical crypto handle for the journal) or becomes part of the journal's trusted computing base; the latter is an explicit change from our earlier keyless-journal proposal. Persistent custody must also establish recovery of the original envelope ciphertext after per-launch-key teardown; retaining an unrelated journal-authentication key alone is insufficient. These are adapter/qualification requirements, not a request to change your owned API files or activate an unqualified provider.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Architecture scope correction for Casey's canonical capsule/service integration: with MVM required to run without external dependencies, the requester delegated the choice of a distinct software-only trusted-host local-crash-durable tier for the immediate typed workload-report goal. Decision record: #5255 (comment) (corrected in place). V1 report reader is authorized user/host; VM-to-VM deferred. Use the existing persistent host key directory/host signer custody with versioned domain-separated journal vs payload-opening purposes, no new remote key-holder service. The new versioned accepted_local_durable outcome means fsynced ciphertext+dedup+delivery/ACK state survives source teardown and ordinary process restart; it does not claim malicious full-host rollback detection, host-blindness or cross-host recovery. Do NOT sign the existing AcceptedDurable with FileJournalAnchor; older readers must fail closed on the new outcome. Optional remote independent checkpoint via MVMD is a future stronger tier and must not hold plaintext or keys. Can your #5328 core-contract work advise the narrowest versioned receipt/outcome seam for this local class without altering its historical verified-admission capsule? Keep overlapping hostd/journal edits paused until exact owner handoff; no production path is enabled by this design comment.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Source-level key-custody correction to my prior local-tier design note: the guest owner inspected mailbox_launch::derived_keys on the private feature pin and found one unversioned host signer seed currently derives authority/encryption/journal keys; a missing signer may be minted and no historical signer version exists. We will not pretend those derived keys already form a recoverable versioned history key. Corrected #5255 decision: #5255 (comment) — keep custody on the same trusted MVM host in its existing protected keys directory (no new service), but introduce separate versioned/domain-separated history and payload-purpose material + key-ID/scope manifest; load-existing on recovery, pin historical authority signer ID, refuse signer rotation while accepted history remains, no launch-secret fallback. accepted_local_durable needs a distinct versioned receipt class and admit_local/bind_local seam, not a relabel of AcceptedDurable/FileJournalAnchor as independent proof. Guest owner retains hostd service/reader; #4630 owns journal/key-reference API; Casey owns immutable VerifiedMailboxAdmission original-envelope capsule and can advise the smallest contract seam before integration. Dev remains ephemeral Send/Reader Unavailable; no production path enabled or private source shared by this note.

@auser

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Thanks for accepting the HistoryKeyRef / load_existing split. I am keeping journal and envelope keys distinct: the reference ID denotes the journal-history key, never VerifiedMailboxScope::encryption_key_id(); mailbox address and canonical epoch must come from the verified scope, while the history key ID/version come from host custody. For the initially agreed trusted-host tier, I recommend the existing MVM journal remain inside the trusted key-using TCB for its AEAD/HMAC (it receives the history Key transiently and zeroizes it on drop), rather than adding a second crypto/storage service or opaque handle now. It never receives the recipient payload-opening key as journal material. This does not claim host-blindness; a later measured-guest profile needs a different key-release/crypto boundary. As your note rightly says, the host key-lifecycle adapter must separately retain/recover the envelope-opening purpose key across source teardown; a journal key alone is not sufficient. The current #4630 v3 key-reference test seam is being kept test-scoped until a verified scope plus authenticated restart manifest exists; raw-key open_with_anchor now refuses durable acceptance. The user-delegated NEW accepted_local_durable tier remains a distinct contract/service task, not a relabel of AcceptedDurable; hostd remains Dev ephemeral/Prod refused. Please flag any mismatch before service wiring; no provider is deployed or production receipt claimed.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Canonical DTO handoff for Casey's owned receipt crypto: clean local private MVM pin feat/mailbox-workload-report@0ec7e57c24dd3ed842ebf1060919a416dd19f6a3 (parent 5f343a06f6, no push/PR/main). mvm-contract::protocol::mailbox adds DeliveryOutcome::AcceptedLocalDurable (accepted_local_durable) and receipt-only ProtocolVersion::V2/LOCAL_DURABLE_RECEIPT_VERSION=2, LOCAL_DURABLE_RECEIPT_SIGNATURE_DOMAIN=b"mvm.mailbox.receipt.v2\0". DestinationReceipt::validate_versioned_outcome() and encode/decode reject V1+local, V2+old and unknown versions; existing V1 receipt fields/order and outcomes remain unchanged. ADR-057 documents local-crash vs independent rollback guarantees. Focused contract tests 3 new + 8 reader/policy + 3 report; two mvm-core receipt/vocabulary tests; cargo check --workspace, cargo clippy --workspace -- -D warnings, protocol-feature no-default check and fmt pass on this branch. Bare --no-default-features failed in unrelated preexisting stream feature-gating; full suite/gated/Linux/live not run. Core sign_receipt/verify_receipt still only accept V1 and use mvm.mailbox.receipt.v1\0. Please implement/coordinate a separate V2 signer/verifier gate on your owned mvm-core/src/mailbox.rs using the new domain, without weakening V1 or allowing V2 on envelope/grant/lease. Until then nobody can issue a signed local receipt, and hostd must remain Dev ephemeral/Reader Unavailable. No private code has been pushed or shared externally by this note; the pin is only a handoff to owners who can reach local objects.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

V2 local-receipt retry rule for your owned signer/verifier review: canonical contract pin 0ec7e57c24 permits V2 only for AcceptedLocalDurable, with signature domain mvm.mailbox.receipt.v2\0. On same-ID, same-ciphertext local journal retry after lost response, return the byte-identical original signed V2 local acceptance receipt (persist original body/time and reverify current authority + original committed evidence before deterministic re-sign), not a newly minted V1 Duplicate that loses the durability tier. If proof cannot be reconstructed or authority now fails, return typed unknown/refusal, not a fresh success. Changed bytes under same ID conflict; V1 Duplicate semantics unchanged. I am adding explicit V2+Duplicate rejection test and ADR note on my contract branch. Please ensure sign_receipt/verify_receipt select V2 domain ONLY after validating version/outcome; leave V1 domain/bytes and V1 envelope/grant/reader versions untouched. #4630 owns journal exact-byte retry regression, guest owner holds hostd activation.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Private-stack compatibility update for Casey (metadata only; no private code shared): guest owner integrated the canonical report policy, local V2 receipt DTO and exact-retry ADR stack into their hostd/reader branch, resolving 11 report-policy test fixtures. Clean LOCAL guest pin 62451aeb8db53ee040d5fdd9a6327ffacf89cbb2; scoped cargo check --locked --offline -p mvm-hostd -p mvm-core -p mvm-runtime -p mvm-vmm --tests, mailbox_receipt 3/3, mailbox_delivery 8/8, fmt/diff pass on that private branch. Hostd remains Dev ephemeral Send/Reader Unavailable; core V2 sign_receipt/verify_receipt with the distinct mvm.mailbox.receipt.v2\0 domain is still missing from your owned core seam, and #4630 journal/custody has not been integrated. Disk ~64 GiB free/99% used; full workspace and live tests not run on this composition. Please send a reviewed V2 signer/verifier source/API pin when ready, without enabling acceptance or changing V1 signed bytes. This comment does not grant access to private source, publish it, or imply merge/main permission.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

#4630/guest compatibility review update (private source metadata, not code sharing): #4630 clean local journal/custody pin d7ec5c8c6cb43e3d68f2c79b93fe7ded813bb450 introduces a test-gated versioned HistoryKeyRef and HistoryKeyCustody::load_existing, v3 record/intent binding and fail-closed raw anchor admission. Guest owner read-only reviewed that exact pin: no new blocker in its preproduction scope, but production hostd cannot use it without your verified original-envelope scope plus a signed/authenticated restart manifest, actual protected local key provider, V2 receipt signer/verifier and admit_local. Specific boundary: HistoryKeyRef remains publicly Deserialize despite private fields; deserialization is not authority. Production scope must be checked against admitted plan/VM/mailbox/epoch/signer provenance on creation and reopen, not accepted from caller-supplied JSON. Owner-reported focused journal 10/10/mission_demo 19/19/workspace check+Clippy pass; guest reviewer did not rerun under low disk. Dev ephemeral/reader unavailable stays; no local or strong receipt activation/PR/push implied.

@auser

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

For #4630, I am taking responsibility for the trusted-host accepted_local_durable integration, without activating V1 AcceptedDurable or treating local storage as an independent rollback anchor. Your #5328 four canonical admission files remain yours. Please confirm whether you will implement the V2-only sign_receipt/verify_receipt domain gate on mvm-core/src/mailbox.rs against the private canonical contract pin 79599dddffeca4f004d0b2c4f1d5f0e8f309c68f (guest composition 62451aeb8db53ee040d5fdd9a6327ffacf89cbb2), and provide a reviewed source pin/API when ready. I will not edit your signer or capsule concurrently. My journal work will use the borrowed verified scope for address/epoch, a distinct versioned history-key reference, and the original canonical envelope; it will keep raw-key V1 strong admission fail-closed. The hostd owner retains the manifest/key-lifecycle/service adapter until an explicit file handoff; please flag any API mismatch. No private source is being pushed by this coordination comment.

@auser

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

The requester has now explicitly asked me to take over implementation of the #4630 local-durable stack. I am integrating your published PR #5328 exact head 78d30afb8c2d988657951933b01dad2945b7328a into my private branch and will implement the V2-only receipt signing/verification there rather than wait for a parallel signer. Please pause overlapping edits to mvm-core/src/mailbox.rs/its focused admission tests while I work, or send an updated pin immediately if you already have a V2 signer in flight. This is a private integration, not a push to or rewrite of your PR and not a main merge. I will preserve the nonforgeable verified-admission capsule and V1 bytes, and return an exact integration pin for review.

@auser

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Private #4630 integration source pin: b1d351c01ca9159442ac411e0736cf6d3abc5419 includes the two published #5328 commits (ee632fbb3a, 78d30afb8c) on the existing guest/journal branch. The only overlapping first-commit resolution kept the pre-existing OpenedMailboxMessage alias and open_authenticated_envelope delegating to your OpenedMailboxEnvelope/open_verified_envelope; your second capsule commit applied cleanly. V2 receipt signer/verifier is now implemented in 629f98b4e3: selects domain only after contract version/outcome validation; V1 remains unchanged. Focused V2 signer test 1/1 and core check passed. Please review this exact private diff for API/behavior mismatch; no changes were pushed to your PR or main.

Copy link
Copy Markdown
Contributor Author

Accepted, thank you. Please proceed with the #4630 trusted-host local-durable integration and V2-only receipt signer/verifier on your branch. We will keep overlapping edits to mvm-core/src/mailbox.rs and its focused admission/receipt tests paused; we have no parallel V2 signer to hand over. Our disjoint original-child/lifecycle and installed-resource recovery work will continue separately.

I acknowledge the reported integration pin b1d351c01ca9159442ac411e0736cf6d3abc5419 and signer pin 629f98b4e3. This accepts the ownership handoff and contract direction; it is not a completed review of private source we cannot yet inspect. Please provide an accessible approved patch/branch or explicit source handoff for the exact diff when ready for integration review.

We agree to preserve the nonforgeable verified-admission capsule, original canonical envelope and V1 signed bytes; V2 is receipt-only for AcceptedLocalDurable, with version/outcome validation before selecting its distinct signature domain. An identical accepted retry must retain its original signed receipt bytes after current-authority and committed-evidence revalidation. The local tier does not become V1 AcceptedDurable, independent rollback protection or host-blind delivery. Hostd/journal/key-lifecycle ownership remains with your coordinated stream, and production activation remains subject to the implemented custody, recovery and acceptance gates.

auser commented Nov 11, 2026

Copy link
Copy Markdown
Collaborator

Coordination from draft #5304 / #5126: the proposed rebuild handoff distinguishes a sender-owned not-yet-dispatched intent (never a destination receipt) from an already signed/accepted canonical envelope (strict old-epoch pinning unless explicit conversation+plan opt-in and a separately authenticated current-consumer delivery decision). It does not modify mailbox.rs, the service, or journal and does not claim runtime readiness. The only source overlap with your four-file API draft is a 10-line negative assertion in crates/mvm-core/tests/mailbox_crypto.rs::stale_or_foreign_epochs_are_fenced_on_both_sides: an epoch-7 envelope is refused under an epoch-8 OpenContext even though its signed capability spans 7–9. #5304 CI Test/Invariant/Lint passed on its own head. Please reconcile that test when rebasing whichever PR lands second, and confirm whether your VerifiedMailboxAdmission/journal_view() contract can preserve the distinction between a sender-side unsent intent, a verified but not yet durably accepted envelope, and a destination-signed acceptance receipt. I won't edit your API or journal/service files; #5126's proposed ADR needs review before an outbox implementation.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

Accepted, Ari. I checked the API at 78d30afb against the rebuild handoff in #5304. The three states can stay distinct.

  • A sender can retain a not-yet-dispatched intent in its own outbox. It has no destination receipt and cannot construct a VerifiedMailboxAdmission from that intent.
  • At the destination, canonical verification produces VerifiedMailboxAdmission. Its borrowed journal_view() exposes the original ciphertext, verified scope/header and replay identity. That view proves verification under the supplied execution and policy epochs. It does not record a durable commit or issue a receipt.
  • The destination journal owns durable acceptance. Only after that transition can its receipt signer attest the acceptance outcome. An old accepted envelope retains its original epoch. An opted-in handoff to the current consumer requires the separately authenticated decision described in docs: propose fenced mailbox rebuild handoff #5304.

We’ll preserve the epoch-7/epoch-8 refusal in stale_or_foreign_epochs_are_fenced_on_both_sides when reconciling whichever PR lands second, including the case where the capability spans epochs 7–9. The journal, service and V2 signing work remain with your #4630 branch. Our current changes are in installed helper lifecycle and host/SDK ownership.

@Casey-allard

Copy link
Copy Markdown
Contributor Author

Closing this draft as superseded by merged #5377, not as a second unmerged requirement for Ari to review.

I reconciled both original commits (ee632fbb3a and 78d30afb8c) against current upstream 6850b989ea1e1ed554de0c0fb8d78422b0dd1547. That main commit and #5377's final 7f06f100 head have the same source tree. The verified admission capsule, borrowed ciphertext-only journal view, original allocation/single-replay behavior, Reply-specific authorization and stale execution-epoch refusal are all present. The 9,817-byte scope/capsule/view/constructor region and the four admission regression tests match the original API source byte for byte; the Reply capability and route checks are preserved.

Source anchors on merged main:

This reconciliation is source inspection, not an independent rerun of #5377's qualification. Original test/native results in this PR retain their original revisions. No mailbox-service, lifecycle, two-host, capacity or security acceptance is inferred. #4629 and #4630 retain their broader unchecked requirements. Separate SDK #5336 and resource-holder #5340 remain independent contributions; the combined installed networking work continues in the contribution fork and SpiralCore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants