carlos / platform Public

Revise maintenance protocol after independent review

Paul Campbell pushed by paul@keymail.dev 78b56feb1e4dd0bf65f11f60dfb14f9d705447f1 parent 11a3039
2 files changed, +1523 −0
  • implementation/maintenance-protocol/proposal.json +345 −0
  • implementation/maintenance-protocol/schemas.json +1178 −0

CI passed — run details

diff --git a/implementation/maintenance-protocol/proposal.json b/implementation/maintenance-protocol/proposal.json
new file mode 100644
index 000000000..8925b9e79
--- /dev/null
+++ b/implementation/maintenance-protocol/proposal.json
@@ -0,0 +1,345 @@
+{
+ "status": "PROPOSED interface choices, not authority approval; no implementation or deployment",
+ "sources": [
+ {
+ "name": "approved-maintenance",
+ "revision": "6a81dacfe4949520efce8fb55dec1dbec8e43bfd",
+ "path": "/home/paulca/amadan.net/carlos/platform/.claude/worktrees/overnight-maintenance-design/implementation/maintenance-exec.md",
+ "sections": [
+ "CLI/API surface",
+ "Private transport",
+ "Environment pinning",
+ "Durable guard and lifecycle",
+ "Resume"
+ ]
+ },
+ {
+ "name": "launch-delta-unreviewed",
+ "revision": "caf47fb",
+ "path": "/home/paulca/amadan.net/carlos/platform/.claude/worktrees/overnight-maintenance-launch/implementation/maintenance-launch.md",
+ "note": "4605a54 base approved; caf47 delta has no approval verdict"
+ },
+ {
+ "name": "platform-foundations",
+ "revision": "11a303996d5503d29ede77598243ddc66f735279",
+ "root": ".",
+ "paths": [
+ "internal/maintenance/envelope.go",
+ "internal/maintenance/input.go",
+ "internal/maintenance/result.go",
+ "internal/maintenanceguard/types.go",
+ "internal/maintenanceguard/store.go",
+ "internal/privatefile/privatefile.go",
+ "internal/provision/maintenance.go",
+ "internal/console/authcli.go:411",
+ "internal/console/stepup.go:249",
+ "internal/console/stepup.go:396",
+ "internal/console/apiconfig.go:251",
+ "internal/edge/storedoor.go:100",
+ "internal/host/agent.go:2772"
+ ],
+ "note": "This proposal branch is based on this merged revision; these exact existing primitive sources are included in its review archive."
+ },
+ {
+ "name": "Home-prepared-protocol",
+ "revision": "7e282e2a363b9cc90cd74dd97809e6613a699af8",
+ "root": "/home/paulca/amadan.net/oficina/home/.claude/worktrees/overnight-provisioner-prepare",
+ "paths": [
+ "internal/provisioner/prepare_linux.go",
+ "internal/provisioner/installations_linux.go",
+ "internal/operator/protocol.go",
+ "internal/operator/open_linux.go",
+ "cmd/oficina/main_linux.go"
+ ]
+ }
+ ],
+ "approved_requirements": [
+ "Exact account/app/primary-host scope; no first-visitor authority",
+ "Private JSON stdin <=65536; argv 1..32 and aggregate <=8192; result <=65536; default timeout300s hard600s",
+ "Existing CME1 P256/HKDF-SHA256/AES-GCM binding and CMI1 exact-byte framing; no new crypto",
+ "Input encrypts to deployment secrets public key; result to durable per-request CLI key; console never gets private decrypting key",
+ "Fresh browser current-owner review, immutable preflight/env/artifact/record/recipient pins; bearer is not fresh consent",
+ "No execution until matching durable guard+record projection, lifecycle, checked lease/stop/DB/containment prerequisites",
+ "Private payload expiry24h; immutable nonsecret receipt retained; lost/unpublished output is unavailable or ambiguous",
+ "Explicit retry and resume; no implicit command rerun or fence clearing"
+ ],
+ "new_wire_choices": [
+ "All endpoint paths and schema definitions",
+ "Client-generated separate random request_id and attempt_id before encryption",
+ "Target GET and two-step server preflight then browser approval",
+ "Retry creates a linked new PLATFORM request/attempt, with unchanged APP operation bytes; no new app-level authorization",
+ "Closed pending-local JSON format and explicit file flags",
+ "Specific resume proposal object and status vocabulary",
+ "Environment plaintext closed map-entry schema inside existing DirectionEnvironment envelope; this plaintext shape is proposed, not an existing codec",
+ "Proposed worker publication interface, intentionally unavailable pending authenticated enrollment design",
+ "Server-derived stable lifecycle OperationID and constant-depth authoritative lineage-head CAS, separate from platform request/attempt IDs and private app operation ID"
+ ],
+ "endpoints": [
+ {
+ "method": "GET",
+ "path": "/api/cli/apps/{account}/{app}/instances/{host}/maintenance/target",
+ "request_schema": null,
+ "response_schema": "target",
+ "authorization": "human-owner-cli",
+ "success_http_status": [
+ 200
+ ]
+ },
+ {
+ "method": "POST",
+ "path": "/api/cli/apps/{account}/{app}/instances/{host}/maintenance/requests",
+ "request_schema": "prepare",
+ "response_schema": "prepared",
+ "authorization": "human-owner-cli",
+ "success_http_status": [
+ 201,
+ 200
+ ]
+ },
+ {
+ "method": "GET",
+ "path": "/api/cli/apps/{account}/{app}/instances/{host}/maintenance/requests/{request_id}",
+ "request_schema": null,
+ "response_schema": "status",
+ "authorization": "human-owner-cli",
+ "success_http_status": [
+ 200
+ ]
+ },
+ {
+ "method": "GET",
+ "path": "/api/cli/apps/{account}/{app}/instances/{host}/maintenance/requests/{request_id}/result",
+ "request_schema": null,
+ "response_schema": "result",
+ "authorization": "human-owner-cli",
+ "success_http_status": [
+ 200
+ ]
+ },
+ {
+ "method": "POST",
+ "path": "/api/cli/apps/{account}/{app}/instances/{host}/maintenance/requests/{request_id}/retry",
+ "request_schema": "retry",
+ "response_schema": "prepared",
+ "authorization": "human-owner-cli",
+ "success_http_status": [
+ 201,
+ 200
+ ]
+ },
+ {
+ "method": "POST",
+ "path": "/api/cli/apps/{account}/{app}/instances/{host}/maintenance/requests/{request_id}/resume",
+ "request_schema": "resume",
+ "response_schema": "resume_proposed",
+ "authorization": "human-owner-cli",
+ "success_http_status": [
+ 202,
+ 200
+ ]
+ },
+ {
+ "method": "GET",
+ "path": "/a/{sqid}/apps/{app}/instances/{host}/maintenance/{request_id}/review",
+ "request_schema": null,
+ "response_schema": "HTML immutable nonsecret review",
+ "authorization": "browser-current-owner",
+ "success_http_status": [
+ 200
+ ]
+ },
+ {
+ "method": "POST",
+ "path": "/a/{sqid}/apps/{app}/instances/{host}/maintenance/{request_id}/approve",
+ "request_schema": "approval_form",
+ "response_schema": "303 Location: /a/{sqid}/apps/{app}/instances/{host}/maintenance/{request_id}/review (same new request; review page renders current status)",
+ "authorization": "session-CSRF-current-owner-fresh-auth",
+ "success_http_status": [
+ 303
+ ]
+ }
+ ],
+ "wire_rules": {
+ "schemas": "schemas.json; every object additionalProperties=false, all listed fields required; nullable only where declared",
+ "json": "UTF-8; reject duplicate keys, case aliases, trailing data, invalid/noncanonical encodings, out-of-range/noninteger numbers; parse int64/uint64 without float64. Request JSON schema is not a runtime parser implementation.",
+ "scope": "Canonical configured HTTPS console origin, exact controlname account/app/host; path selectors and every body selector agree. No alias, wildcard, path route, selector default, environment override or executable path.",
+ "bytes": "Envelope strings are unchanged canonical StdBase64 CME1; envelope digest is SHA256 of exact ASCII envelope bytes, declared new wire convention. Public hashes never cover argv/stdin/environment plaintext. Recipient is SHA256 of raw P256 public point per existing RecipientFingerprint.",
+ "caps": {
+ "prepare_body": 131072,
+ "status_body": 16384,
+ "result_body": 98304,
+ "approval_form_body": 4096,
+ "worker_environment_publication_body": 2097152,
+ "private_pending_body": 196608
+ },
+ "headers": {
+ "all": "Cache-Control:no-store,no-transform; X-Content-Type-Options:nosniff; exact JSON Content-Type where JSON",
+ "review": "Referrer-Policy:no-referrer; same-origin form action; no private payload or result data in HTML",
+ "result": "No caller-specified redirect or ciphertext URL; response uses authenticated console connection"
+ },
+ "errors_http": {
+ "400": "invalid-request",
+ "401": "not-signed-in",
+ "403": "service credentials refused before membership-dependent details; fixed generic body",
+ "404": "not-found for inaccessible/missing account/app/host/request",
+ "409": "conflict or result-unavailable",
+ "412": "precondition-failed",
+ "410": "payload-expired",
+ "429": "rate-limited; bounded Retry-After",
+ "503": "unsupported or unavailable; no worker provenance means unavailable, never assumed success"
+ },
+ "approval_forms": "application/x-www-form-urlencoded; exact fields in approval_form, one value each; reject unknown/duplicate fields. csrf uses existing console field and is never copied into durable approval metadata. Browser Origin/CSRF checks must match normal console/router contract; any stronger Origin rule needs explicit integration tests.",
+ "metadata_digest": "New proposal: deterministic Go encoding/json serialization of the declared version-1 typed object in schemas.json property order, no indentation or appended newline, normal Go HTML escaping; sorted unique required-contract arrays and sorted unique environment entry names. Compare exact stored bytes for reference digests; no float64 intermediates.",
+ "approval_endpoint": "The single review/approve path uses the NEW request_id for operation, retry, or resume. Server immutable request kind determines the required operation or compatibility/resume checks. Predecessor is metadata, never substituted into the approval path. Missing/mismatched kind/pins refuses.",
+ "browser_scope": "Use existing accountApp sqid routing and resolve sqid to exact account before comparing stored scope; sqid is not an account slug. Approval redirects 303 to the same new request review URL /a/{sqid}/apps/{app}/instances/{host}/maintenance/{request_id}/review. Owner and fresh-auth gate order is unchanged.",
+ "predecessor_agreement": "Initial POST /requests requires predecessor=null. Retry and resume require non-null predecessor; predecessor.id equals path request_id and its digest equals that exact predecessor request reference (not an outcome ID). Server resolves that request to its immutable authoritative outcome and current lineage head; every body selector must agree. Missing outcome, stale predecessor or mismatch refuses. New body request_id is distinct from predecessor/path request_id.",
+ "result_semantics": "GET /result resolves status.outcome from authoritative current request metadata. Pending resume, including compatibility-checked/resume-ready, returns409 result-unavailable; it never returns the intermediate checker receipt as resumed. Before a final outcome status.result_state=pending and result_envelope_digest=null; historical compatibility/evidence refs may be non-null. For final resume outcome, return that final outcome/ref and exact retained checker envelope whose digest is copied unchanged from compatibility_outcome; server verifies both immutable receipts and linkage under the same request/attempt/scope/recipient. No checker output yet or lost output yields409 unavailable; expired private payload yields410. Final failed/ambiguous resume may expose an existing validated checker result but state remains failed/ambiguous and CLI must not report resumed. Operation result semantics remain exact command ciphertext under its final outcome. Result envelope alone never establishes outcome or admission."
+ },
+ "cli": [
+ {
+ "command": "carlos maintenance prepare --account A --app APP --host H --input ABS_FILE --pending ABS_FILE --label LABEL --timeout 300 -- ARG...",
+ "behavior": "Resolve authenticated target, read private 0600 regular bounded exact JSON, generate IDs/key, SealInput, durably save pending, then upload. Explicit shell-free argv only; worker supplies executable and DB path. No private argv in public status/logging."
+ },
+ {
+ "command": "carlos maintenance status --account A --app APP --host H --request ID",
+ "behavior": "Read-only current-owner status. Optional bounded watch polling; Ctrl-C stops polling, not operation."
+ },
+ {
+ "command": "carlos maintenance result --account A --app APP --host H --request ID --pending ABS_FILE --output ABS_FILE",
+ "behavior": "Current-owner fetch of authenticated receipt plus exact ciphertext, local binding verification and OpenResult, exclusive durable private output. Never stdout; no arbitrary ciphertext input flag."
+ },
+ {
+ "command": "carlos maintenance retry --account A --app APP --host H --request OLD_ID --pending OLD_FILE --new-pending ABS_FILE",
+ "behavior": "Fetch authenticated immutable predecessor outcome; verify exact retained signed input bytes by private hash; generate new platform IDs/key/envelope under new binding, save new pending before POST. New owner approval mandatory. Does not generate new Home operation or signature."
+ },
+ {
+ "command": "carlos maintenance resume --account A --app APP --host H --request OLD_ID --artifact VERSION --required-contract NAME... --check-input ABS_FILE --pending ABS_FILE --timeout 300 -- CHECK_ARG...",
+ "behavior": "Allocate new transport request/attempt and recipient key; SealInput preserves private non-serving checker argv and exact JSON stdin; save pending before resume POST. Fixed executable is the pinned serving release. Same browser owner gate approves exact checker ciphertext, artifact/environment/record and required contracts. No CLI approval. Checker command selection must match the reviewed app compatibility contract; arbitrary migration/server argv cannot be relabeled as a checker."
+ }
+ ],
+ "ordering": [
+ "Target GET is read-only, human-current-owner authorized. Public deployment encryption key comes from authenticated console Config.SecretsPub source, not silent terminal env override. Pin target artifact signed manifest and record identity/revision; target response is not preflight or approval.",
+ "Client creates independent cryptographic32-byte request/attempt IDs and per-request result key. Read exact input privately; SealInput with binding Version1/DirectionInput and deployment recipient. App operation IDs remain only inside private signed stdin.",
+ "Build exact prepare JSON once. Store private key, IDs, fingerprint, exact body, input path/private hash in exclusive0600 pending file outside repositories. Check file sync/close and parent sync before POST. Interrupted file is preserved; a read is not durability proof. Future pending loader must validate all bindings and execute a checked durability barrier before resend.",
+ "Authenticated POST creates immutable server request bytes and server metadata once. Same request ID with identical body returns same request/digest/expiry. Any differing bytes/scope/recipient/attempt gives409. Lost response resends identical body; do not re-encrypt. Client-supplied predecessor is only a reference and never execution authorization.",
+ "Coordinator assigns exactly one authenticated enrolled box to immutable request/attempt. Preflight reads existing DB/record/artifact/config without stopping serving, restoring, seeding, or EnsureAdminToken. Worker returns encrypted DirectionEnvironment snapshot plus authoritative preflight facts; console cannot decrypt the map.",
+ "Immutable request digest is SHA256 of the deterministic server encoding of the validated prepare object; it includes randomized ciphertext/digests but no raw stdin hash. Exact upload bytes remain the idempotency comparison. Each preflight/publication/approval reference digest binds its exact stored immutable bytes. Server builds immutable approval candidate digest from request reference, assignment, preflight reference, exact pins and result recipient; browser displays these nonsecret facts and fixed warning that inputs remain private. Never render arbitrary argv or plaintext hashes. The candidate MUST also bind server-derived lifecycle_operation_id, exact expected lineage-head revision (explicit absent sentinel for initial operation), and exact predecessor request and resolved outcome references (explicit null for initial operation). These typed fields participate in candidate_digest, not merely page display. candidate_revision identifies this immutable candidate, not an independently refreshable head. Step-up replay rereads those exact expectations and CAS cannot substitute a newer head.",
+ "POST approval: session, CSRF using existing form field csrf (never persisted; step-up injects it from current cookie), current owner byte-identical404, requireFreshAuth last. Existing stepup can replay the session-bound single-use held POST through router; exact candidate digest/revision survives and every owner/pin check reruns. Missing pins never mean approve latest. Browser intent is the original explicit POST, not CLI token auth_time.",
+ "Worker rechecks current owner authorization and immutable candidate, exact record revision and private merged environment equality, artifact signature/hash, guard/projection/lifecycle and lease/containment before durable executing state and one spawn. The approved private snapshot is actual command environment. Any changed source or pin refuses; no refresh of approval in place.",
+ "Capture bounded stdout; independently verify Wait, process-tree cleanup, lease, DB, checkpoint/restore and semantic receipts. SealResult is only encryption. Publication and terminal outcome require the authenticated-worker path below; missing publication never becomes invented empty success.",
+ "CLI fetch verifies authenticated server outcome and stored reference digest, assigned worker provenance established server-side, request/attempt/scope, approved record/artifact/environment/input ciphertext hashes, recipient and terminal outcome, then decrypts. Save output durably before optional explicit key cleanup; failed output retains pending key.",
+ "Home completion adapter additionally checks existing signed app receipt against retained installation/role/generation/authorization stream and exact prepared operation. It finalizes encrypted result record and independent floor before accepted-head CAS. A local parseable file, CME1 success, or browser approval alone cannot advance Home accepted state."
+ ],
+ "worker_provenance": {
+ "status": "UNRESOLVED DESIGN DEPENDENCY; no endpoint may publish accepted execution until this is implemented and reviewed",
+ "existing_options": [
+ {
+ "source": "internal/edge/storedoor.go:100 and TunnelHub.VerifyDynamic",
+ "facts": "Dynamic fleet name plus bearer validated against current fleet box table; fleet account mapping checked. Store door excludes control/maintenance and instance record writes. A narrowly scoped typed endpoint could reuse verified fleet identity, but token/enrollment is not universal and cached revocation semantics require explicit review."
+ },
+ {
+ "source": "internal/host/agent.go:2772 openDeployStoreEnv",
+ "facts": "Shared/root boxes currently prefer deployment bucket/directory credentials. These are broad store access, not an authenticated per-box worker result channel. They cannot establish exact worker origin by themselves."
+ }
+ ],
+ "minimum_new_interface": {
+ "authentication": "AuthenticateWorker(request) must derive current deployment_origin, box_id and enrollment_generation from real supported enrollment, never body strings. Authority to create enrollment and revocation propagation remain unresolved. Do not mint universal credentials or reuse human/service CLI token.",
+ "assignment": "Read immutable server assignment bound to deployment/box/account/app/host/request/attempt, current placement and current owner approval. Wrong box, revoked enrollment, stale generation or lost lifecycle cannot publish.",
+ "paths": [
+ "POST /internal/maintenance/assignments/{assignment_id}/preflight",
+ "POST /internal/maintenance/assignments/{assignment_id}/outcome"
+ ],
+ "preflight_body": "schemas.json preflight_publication; principal/assignment supplied by server context, body copies must agree. Proposed environment_private plaintext is bounded to existing MaxEnvelopePlaintext=1048576, with unique variable names; empty values allowed. This plaintext schema needs review and adds no new encryption format.",
+ "outcome_body": "schemas.json outcome_publication; publication_id is random immutable receipt identity, reused byte-exact after lost response. All reference digests rederived and checked; no generic bucket-key or result-upload CLI endpoint. Missing result envelope cannot assert success; empty application results depend on reviewed app contract, Home rejects empty. Checked worker coordinator, not an HTTP boolean, establishes execution_evidence.",
+ "publication": "Store private encrypted payload create-only, finalize immutable receipt with its digest and exact approved refs, then CAS current attempt terminal pointer only for assigned generation. Crash before pointer leaves orphan ciphertext/receipt, no accepted outcome. One publisher; identical retry idempotent, changed receipt conflict. Compatibility-check success in a resume request is intermediate: CAS only the historical compatibility_outcome reference, never the final status.outcome pointer. The resume_checker_transport publication and result_semantics rules specify the subsequent final receipt and unchanged ciphertext linkage.",
+ "readback": "Console result handler resolves current attempt and immutable receipt through trusted internal store and verifies receipt/payload digests plus authentication provenance. Human CLI may read ciphertext but cannot publish outcome. No signed offline worker receipt format is invented here."
+ },
+ "opaque_references": "worker_assignment, worker_evidence, execution_evidence and resume_ready_evidence are opaque server-internal immutable references. Their storage encoding and validator are dependencies of the future enrolled-worker coordinator, not wire objects defined here and not assertions of an existing assignment store. Server computes/checks ID and SHA256 over exact retained internal bytes. CLI compares authenticated references for binding only; it cannot independently validate their contents or present them as credentials. No worker token, signature format, endpoint authority or offline proof is introduced."
+ },
+ "retry_and_cancellation": {
+ "upload_disconnect": "Unknown acceptance: recover same pending and repeat exact original prepare. No operation starts without browser approval.",
+ "preflight_timeout": "Remains unavailable/refused without app mutation; no signature, Home expiry, input expiry or approval expiry extension.",
+ "execution_disconnect": "HTTP client disconnect does not cancel durable worker ownership. Worker timeout/lease loss invokes checked stop and publishes failed/ambiguous when possible; never automatically retries.",
+ "retry": "New platform request linked to immutable predecessor receipt. Same exact app stdin/argv required: client validates retained private hash; worker independently compares decrypted predecessor input with new input while private predecessor payload exists. Expired/missing predecessor payload refuses retry; operator may prepare a separately reviewed recovery request preserving Home idempotency, never rewrite old authority. No fresh Home signature is generated by carlos.",
+ "concurrency": "One exact active request per retained lifecycle ownership. Concurrent retries may prepare but only approved matching claim can execute; no last-writer-wins head. Existing incomplete lifecycle claim must be recovered explicitly rather than stolen.",
+ "resume": "Original operation may have succeeded, failed, or become ambiguous; resume eligibility requires checked stop/containment and a NEW independently successful app-specific non-serving compatibility-check command from the pinned serving release, under the retained guard/lifecycle/lease. Private checker argv/stdin use unchanged CMI1+DirectionInput; stdout uses CaptureResult+SealResult to the newly durable per-request CLI key. Approval pins exact checker ciphertext, artifact/manifest, environment snapshot, record identity/revision, predecessor and required contracts. Validate checker exit plus app-specific compatibility result, then integrity and final checkpoint/restore evidence. Publish immutable resume-ready evidence while guard remains in the existing ResumeRequested phase; do not invent a new guard enum. Only then start exact serving artifact and hand lease to replication, verify health/version, and CAS matching resumed guard+projection. Failure keeps serving admission closed. Migration success is not compatibility proof; checker cannot rerun the original mutation.",
+ "expiry": "Server immutable payload expiry24h from first accepted upload; idempotent resend never extends it. Proposed preflight review expiry5min; expiry requires fresh preflight/new candidate and explicit review, never silently renew old consent. Execution must begin before candidate expiry; child and operation deadlines independently bounded."
+ },
+ "Home_integration": {
+ "actual": "7e native prepare emits exact signed JSON on inherited anonymous write pipe only, after local journal+floor durability, with public state local-request. It is not a regular-file writer or network submit command.",
+ "needed_adapter": "A future native submission adapter supervises that pipe, captures <=65536 exact bytes with cancellation, writes exclusive private input file, then invokes shell-free carlos prepare or its library. No terminal redirect of secrets, no LLM handling. On capture cancellation replay exact saved Home request.",
+ "actions_ready": [
+ "directory.initialize",
+ "credential.owner-seed",
+ "directory.seed-team",
+ "directory.provision-consumer"
+ ],
+ "actions_refused_until_evidence": [
+ "directory.verify-consumer",
+ "directory.activate-consumer"
+ ],
+ "launch": "caf47 unreviewed context owns fd3 and verified artifact fd4; platform hashes exact stdin and binds request/record/artifact/env plus DB identity/deadline. Home verifies private signed stdin, role/origin/action from approved pinned environment, exact opened SQLite file and self executable. Home cannot independently compare worker-owned expected environment/record digests against invented duplicated flags.",
+ "authority": "Home operator signing/floor, platform browser owner approval, worker execution provenance and application result verification are separate checks; none substitutes for another.",
+ "completion_classification": "Only authenticated execution_kind=operation outcomes for the exact prepared Home mutation may advance its accepted authorization head. Compatibility-check and resume receipts are separate proof/history and cannot be consumed as successful mutation results."
+ },
+ "dependencies_before_mount": [
+ "Review this new wire proposal; caf47 launch delta remains unapproved",
+ "Concrete shared/root and fleet worker authentication/enrollment with revocation and exact assignment publication path",
+ "Immutable request/approval/attempt storage and CAS terminal state machine; receipt validators and durable private-payload expiry",
+ "Complete all ordinary writer/lifecycle/config/adoption/always-awake admission fences; record serialization alone is insufficient",
+ "Actual worker preflight environment capture/compare and signed artifact, existing DB, lease/cgroup/checkpoint/restore/semantic-receipt executor",
+ "Checked resume and durable supported-contract floors across startup/adoption/rollback",
+ "Native pending-file format/loader checked resume-durability barrier and Home submission/completion adapter; supported non-Linux custody still absent",
+ "Independent whole-code review, native/cross/CI and isolated deployed rehearsals before any real DB operator invocation",
+ "Actual app-specific non-serving compatibility checker in pinned serving artifact, private checker-result validator, and resume-ready evidence publication; prior mutation success cannot satisfy this"
+ ],
+ "acceptance_cases": [
+ "Changed request/attempt/scope/direction/recipient rejects existing envelope; existing golden vectors unchanged",
+ "65536 input/result exact boundary succeeds; 65537 refuses; JSON/metadata/base64 expansion is accounted separately",
+ "Crash or sync failure before pending durability makes zero upload calls; reopen alone cannot permit upload; same-ID changed bytes conflict",
+ "Lost upload reply plus repeated exact request returns same IDs/digest/expiry, not duplicate command",
+ "Every service role refused; nonowner byte-identical404; stale browser with validCSRF still steps up; missingOrigin/crosssite POST refuses; ownership changed during stepup refuses",
+ "Changed approval digest/revision, record ETag, artifact hash, box overlay or recipient prevents spawn; no EnsureAdminToken or restore side effect in preflight",
+ "Worker publication by CLI bearer, wrong/revoked/unassigned box or naked result ciphertext never produces accepted outcome; orphan payload/receipt does not advance terminal pointer",
+ "Cancelled stdout capture, child never readsstdin, descendant holds pipe, overflow, nonzero exit, lost lease all terminate/check containment and preserve ambiguity correctly",
+ "Result wrong authenticated receipt/ref/ciphertext digest/binding refuses before output; exclusive output existing/symlink/failedsync never overwrites or deletes pending key",
+ "Retry binds immutable predecessor, unchanged app bytes, new explicit approval, same app operation; no counter/signature regeneration, no expiry extension",
+ "Resume cannot run mutation; every partial guard/projection/startup/replication write keeps admission closed until both resumed records and health agree",
+ "Home actual prepared pipe to private input and byte-exact stdin preserved; received ciphertext without authenticated outcome cannot finalize encrypted result/floor/accepted head",
+ "Existing record without projection remains compatible; malformed projection protects existing registry state without new serving authority",
+ "Fresh actual shared-box/fleet enrollment and revocation rehearsal required; static synthetic WorkerPrincipal fixtures are not provenance proof",
+ "Failed/ambiguous original mutation can reach resume only after independent compatibility checker plus integrity/checkpoint success; successful original migration without new checker cannot resume",
+ "Checker wrong argv/serving artifact/ciphertext/recipient/environment/record pins prevents launch; checker failure, malformed output, timeout or lease loss prevents resume-ready",
+ "Retry/resume new request+attempt retain same trusted lifecycle OperationID; forged root, missing head, stale predecessor or simultaneous forked approval cannot replace claim or execute",
+ "Lineage lookup uses bounded current trusted references, never arbitrary-depth predecessor traversal; crash during head/guard/projection updates stays fenced",
+ "Maximal 32-argument CMI1 frame73868 bytes plus CME1 overhead97 yields98620 base64 characters, accepted by both input schema fields; old98616 cap rejects it.",
+ "Browser sqid resolves through accountApp; mismatched stored account refuses before fresh-auth and 303 returns exact review route.",
+ "Changing lifecycle OperationID, expected head revision or predecessor outcome invalidates candidate_digest and held-POST approval; no latest-head substitution.",
+ "Retry null predecessor and retry/resume predecessor differing from path reject before draft creation; predecessor digest means request reference, not outcome reference.",
+ "Resume-ready has no final outcome and GET result returns409; final resumed outcome links immutable checker outcome/evidence and returns unchanged checker envelope. Failed handoff never reports resumed or clears guard."
+ ],
+ "lifecycle_lineage": {
+ "stable_identity": "Server derives lifecycle_operation_id from the retained trusted initial request anchor (proposed equal to initial platform request_id) and existing Guard.OperationID/lifecycle claim. New retry/resume request_id and attempt_id never create a new app claim or replace OperationID before Resumed. Caller has no lifecycle-operation-ID write field.",
+ "lookup_bound": "At most four bounded trusted objects: current lifecycle claim/head, current guard, root anchor, exact current predecessor receipt. Head/root references are server-maintained CAS data outside app prefix; no recursive traversal of caller-supplied predecessor links. Missing/inconsistent lineage refuses. History remains immutable but is not walked to authorize a request.",
+ "head_transition": "Preparation can create competing drafts without changing active lineage. Approval compares exact expected head revision and predecessor receipt, then CASes single current head for the new request/attempt, bound to same lifecycle operation and guard generation. A lost CAS or stale forked approval refuses before execution. Crash retains explicit incomplete transition for idempotent recovery; no timeout unlock or replacement claim. Candidate digest binds stable lifecycle_operation_id, exact expected head revision and predecessor request plus server-resolved outcome references; step-up replay cannot replace these with current values.",
+ "source_boundary": "This lookup/head shape is a proposed wire/integration choice; approved guard.validAdvance already requires unchanged OperationID until Resumed. Atomic cross-object transition and crash recovery still need implementation/review; this is not a claim of cross-object atomicity."
+ },
+ "resume_checker_transport": {
+ "input": "Exactly maintenance.Input{Arguments:CHECK_ARG,Stdin:private JSON}, EncodeInput/SealInput to approved deployment key with new request/attempt and DirectionInput. Worker supplies executable and database path; no caller environment or fd/path authority. Generic limits remain 32args/8192 aggregate/65536 stdin.",
+ "output": "Exact <=65536 bytes on dedicated stdout, captured to EOF and encrypted with existing SealResult/DirectionResult to new request recipient. App-specific checker JSON/schema and compatibility validation belong to reviewed serving artifact contract. Platform does not accept an arbitrary compatible=true body or a caller-uploaded checker receipt.",
+ "authority": "Approved serving artifact must actually expose the intended non-serving checker; no guessed Home command or unmounted dispatcher is treated as implemented. Worker executes/checks it under the same fence/lease and authenticated provenance as mutations; independent integrity/checkpoint follows success.",
+ "publication": "Checker success publishes immutable compatibility-checked outcome with execution_kind=compatibility-check and private checker result. status.compatibility_outcome retains that reference; status.outcome stays null while final resume is pending. Resume-ready evidence links that exact outcome, immutable approval candidate, final checkpoint/restore and exact serving pins. status.resume_ready_evidence is set only after validated publication, with guard still ResumeRequested. After handoff, exact health/version and matched resumed guard/projection, publish a NEW immutable outcome state=resumed, execution_kind=resume, referencing compatibility_outcome and resume_ready_evidence; CAS status.outcome to it. No receipt is overwritten. Final result_envelope_digest is the SAME checker ciphertext digest, encrypted under the same resume request/attempt/key; no second command/output or re-encryption. Historical compatibility receipt stays reachable from final outcome. Failure after checker success may publish final failed/ambiguous resume outcome with existing compatibility/evidence links but never resumed; serving stays fenced.",
+ "expiry": "Fresh approval and exact checker input expiry are checked independently. No retry/resume extends prior Home authorization, payload expiry, worker lease or operation timeout."
+ },
+ "revision_note": "R2 addresses Fable seven blockers on bae085e; now based on merged11a3039 with exact primitive sources included. Interface-only proposal; no runtime implementation, worker authority or deployment approval.",
+ "status_and_guard_mapping": {
+ "authority": "Status is per request workflow metadata, never serving admission authority. Guard phase plus matching projection remains authoritative. Draft retry/resume does not change the predecessor guard. The mapping below distinguishes workflow overlays and guard phases; do not infer absence or clear a guard from draft/refusal/expiry.",
+ "awaiting-preflight, awaiting-approval": "No new guard transition. Initial request has no fence; retry/resume retains the current predecessor guard and denial.",
+ "approved": "Owner gesture accepted, before durable requested fence (initial/retry) or ResumeRequested transition (resume); no command may launch from this status. Existing fence remains intact.",
+ "requested, quiescing, fenced, executing, succeeded, failed, ambiguous": "Operation workflow states map to identical guard phases after matching durable references. Resume checker execution/failure is instead a substate under ResumeRequested: guard must not move backward to Executing/Failed. State alone never authorizes serving.",
+ "resume-requested": "Guard ResumeRequested after fresh resume approval and required CAS; all checker, validation and serving handoff steps remain denied.",
+ "resume-ready": "Workflow substate only; guard remains ResumeRequested. Immutable checker outcome and resume-ready evidence exist but no resumed claim.",
+ "resumed": "Only after exact serving health/version, lease handoff, and both matching guard Resumed and record projection. No premature success pointer.",
+ "refused, expired": "Pre-execution workflow refusal/expiry creates no fence and clears none. A previous active guard remains unchanged. After fence acceptance approval expiry cannot undo it; command/lease failures map failed/ambiguous for operations or stay ResumeRequested for resume."
+ }
+}
diff --git a/implementation/maintenance-protocol/schemas.json b/implementation/maintenance-protocol/schemas.json
new file mode 100644
index 000000000..d7b2e62d3
--- /dev/null
+++ b/implementation/maintenance-protocol/schemas.json
@@ -0,0 +1,1178 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "title": "Proposed maintenance REST and local custody objects; NOT approved or mounted",
+ "$defs": {
+ "id": {
+ "type": "string",
+ "pattern": "^[A-Za-z0-9_-]{43}$",
+ "x-validation": "maintenanceguard.ValidID, including canonical last base64 bits"
+ },
+ "digest": {
+ "type": "string",
+ "pattern": "^[a-f0-9]{64}$"
+ },
+ "v": {
+ "const": 1
+ },
+ "time": {
+ "type": "string",
+ "format": "date-time",
+ "maxLength": 35,
+ "x-validation": "UTC RFC3339Nano; exact parse; server-generated except immutable client command timeout"
+ },
+ "scope": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "console_origin",
+ "account",
+ "app",
+ "host"
+ ],
+ "properties": {
+ "console_origin": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 253
+ },
+ "account": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ },
+ "app": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ },
+ "host": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 253
+ }
+ }
+ },
+ "reference": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "id",
+ "digest"
+ ],
+ "properties": {
+ "id": {
+ "$ref": "#/$defs/id"
+ },
+ "digest": {
+ "$ref": "#/$defs/digest"
+ }
+ }
+ },
+ "recipient": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "public_key",
+ "fingerprint"
+ ],
+ "properties": {
+ "public_key": {
+ "type": "string",
+ "minLength": 88,
+ "maxLength": 88
+ },
+ "fingerprint": {
+ "$ref": "#/$defs/digest"
+ }
+ }
+ },
+ "config_source": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "kind",
+ "revision"
+ ],
+ "properties": {
+ "kind": {
+ "enum": [
+ "default",
+ "named",
+ "instance",
+ "box-overlay"
+ ]
+ },
+ "revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 256
+ }
+ }
+ },
+ "target": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "scope",
+ "deployment_recipient",
+ "record_identity",
+ "record_revision",
+ "artifact_version",
+ "artifact_digest",
+ "manifest_digest",
+ "platform_version"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "scope": {
+ "$ref": "#/$defs/scope"
+ },
+ "deployment_recipient": {
+ "$ref": "#/$defs/recipient"
+ },
+ "record_identity": {
+ "$ref": "#/$defs/digest"
+ },
+ "record_revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 256
+ },
+ "artifact_version": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ },
+ "artifact_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "manifest_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "platform_version": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ }
+ }
+ },
+ "prepare": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "request_id",
+ "attempt_id",
+ "operation_label",
+ "target",
+ "result_recipient",
+ "input_envelope",
+ "input_envelope_digest",
+ "timeout_seconds",
+ "predecessor"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "request_id": {
+ "$ref": "#/$defs/id"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "operation_label": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ },
+ "target": {
+ "$ref": "#/$defs/target"
+ },
+ "result_recipient": {
+ "$ref": "#/$defs/recipient"
+ },
+ "input_envelope": {
+ "type": "string",
+ "maxLength": 98620,
+ "minLength": 1
+ },
+ "input_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "timeout_seconds": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 600
+ },
+ "predecessor": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ }
+ },
+ "prepared": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "request_id",
+ "attempt_id",
+ "request_digest",
+ "state",
+ "status_url",
+ "review_url",
+ "payload_expires_at",
+ "lifecycle_operation_id"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "request_id": {
+ "$ref": "#/$defs/id"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "request_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "state": {
+ "enum": [
+ "awaiting-preflight",
+ "awaiting-approval"
+ ]
+ },
+ "status_url": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1024
+ },
+ "review_url": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1024
+ },
+ "payload_expires_at": {
+ "$ref": "#/$defs/time"
+ },
+ "lifecycle_operation_id": {
+ "$ref": "#/$defs/id"
+ }
+ }
+ },
+ "preflight": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "request",
+ "attempt_id",
+ "worker_assignment",
+ "scope",
+ "record_identity",
+ "record_revision",
+ "artifact_version",
+ "artifact_digest",
+ "manifest_digest",
+ "input_envelope_digest",
+ "result_recipient_fingerprint",
+ "environment_envelope_digest",
+ "config_sources",
+ "worker_evidence",
+ "expires_at",
+ "lifecycle_operation_id",
+ "execution_kind"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "request": {
+ "$ref": "#/$defs/reference"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "worker_assignment": {
+ "$ref": "#/$defs/reference",
+ "description": "Opaque server-internal immutable reference; encoding and authenticated producer validation remain unresolved worker-coordinator dependencies. CLI comparison is not provenance verification."
+ },
+ "scope": {
+ "$ref": "#/$defs/scope"
+ },
+ "record_identity": {
+ "$ref": "#/$defs/digest"
+ },
+ "record_revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 256
+ },
+ "artifact_version": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ },
+ "artifact_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "manifest_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "input_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "result_recipient_fingerprint": {
+ "$ref": "#/$defs/digest"
+ },
+ "environment_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "config_sources": {
+ "type": "array",
+ "maxItems": 8,
+ "items": {
+ "$ref": "#/$defs/config_source"
+ }
+ },
+ "worker_evidence": {
+ "$ref": "#/$defs/reference",
+ "description": "Opaque server-internal immutable reference; encoding and authenticated producer validation remain unresolved worker-coordinator dependencies. CLI comparison is not provenance verification."
+ },
+ "expires_at": {
+ "$ref": "#/$defs/time"
+ },
+ "lifecycle_operation_id": {
+ "$ref": "#/$defs/id"
+ },
+ "execution_kind": {
+ "enum": [
+ "operation",
+ "compatibility-check"
+ ]
+ }
+ }
+ },
+ "approval_form": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "csrf",
+ "request_id",
+ "attempt_id",
+ "candidate_digest",
+ "candidate_revision"
+ ],
+ "properties": {
+ "csrf": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 256
+ },
+ "request_id": {
+ "$ref": "#/$defs/id"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "candidate_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "candidate_revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512
+ }
+ }
+ },
+ "status": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "scope",
+ "request",
+ "attempt_id",
+ "revision",
+ "state",
+ "preflight",
+ "approval",
+ "outcome",
+ "result_state",
+ "result_envelope_digest",
+ "payload_expires_at",
+ "updated_at",
+ "lifecycle_operation_id",
+ "compatibility_outcome",
+ "resume_ready_evidence"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "scope": {
+ "$ref": "#/$defs/scope"
+ },
+ "request": {
+ "$ref": "#/$defs/reference"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512
+ },
+ "state": {
+ "enum": [
+ "awaiting-preflight",
+ "awaiting-approval",
+ "approved",
+ "requested",
+ "quiescing",
+ "fenced",
+ "executing",
+ "succeeded",
+ "failed",
+ "ambiguous",
+ "resume-requested",
+ "resumed",
+ "refused",
+ "expired",
+ "resume-ready"
+ ]
+ },
+ "preflight": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "approval": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "outcome": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "result_state": {
+ "enum": [
+ "pending",
+ "available",
+ "unavailable",
+ "expired"
+ ]
+ },
+ "result_envelope_digest": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/digest"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "payload_expires_at": {
+ "$ref": "#/$defs/time"
+ },
+ "updated_at": {
+ "$ref": "#/$defs/time"
+ },
+ "lifecycle_operation_id": {
+ "$ref": "#/$defs/id"
+ },
+ "compatibility_outcome": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "resume_ready_evidence": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "resumed"
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "outcome": {
+ "$ref": "#/$defs/reference"
+ },
+ "compatibility_outcome": {
+ "$ref": "#/$defs/reference"
+ },
+ "resume_ready_evidence": {
+ "$ref": "#/$defs/reference"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "resume-ready"
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "outcome": {
+ "type": "null"
+ },
+ "compatibility_outcome": {
+ "$ref": "#/$defs/reference"
+ },
+ "resume_ready_evidence": {
+ "$ref": "#/$defs/reference"
+ },
+ "result_state": {
+ "const": "pending"
+ },
+ "result_envelope_digest": {
+ "type": "null"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "outcome": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "scope",
+ "request",
+ "attempt_id",
+ "worker_assignment",
+ "preflight",
+ "approval",
+ "record_identity",
+ "record_revision",
+ "artifact_digest",
+ "environment_envelope_digest",
+ "input_envelope_digest",
+ "recipient_fingerprint",
+ "guard_generation",
+ "guard_digest",
+ "state",
+ "execution_evidence",
+ "result_envelope_digest",
+ "completed_at",
+ "lifecycle_operation_id",
+ "execution_kind",
+ "compatibility_outcome",
+ "resume_ready_evidence"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "scope": {
+ "$ref": "#/$defs/scope"
+ },
+ "request": {
+ "$ref": "#/$defs/reference"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "worker_assignment": {
+ "$ref": "#/$defs/reference",
+ "description": "Opaque server-internal immutable reference; encoding and authenticated producer validation remain unresolved worker-coordinator dependencies. CLI comparison is not provenance verification."
+ },
+ "preflight": {
+ "$ref": "#/$defs/reference"
+ },
+ "approval": {
+ "$ref": "#/$defs/reference"
+ },
+ "record_identity": {
+ "$ref": "#/$defs/digest"
+ },
+ "record_revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 256
+ },
+ "artifact_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "environment_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "input_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "recipient_fingerprint": {
+ "$ref": "#/$defs/digest"
+ },
+ "guard_generation": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 9223372036854775807
+ },
+ "guard_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "state": {
+ "enum": [
+ "succeeded",
+ "failed",
+ "ambiguous",
+ "resumed",
+ "compatibility-checked"
+ ]
+ },
+ "execution_evidence": {
+ "$ref": "#/$defs/reference",
+ "description": "Opaque server-internal immutable reference; encoding and authenticated producer validation remain unresolved worker-coordinator dependencies. CLI comparison is not provenance verification."
+ },
+ "result_envelope_digest": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/digest"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "completed_at": {
+ "$ref": "#/$defs/time"
+ },
+ "lifecycle_operation_id": {
+ "$ref": "#/$defs/id"
+ },
+ "execution_kind": {
+ "enum": [
+ "operation",
+ "compatibility-check",
+ "resume"
+ ]
+ },
+ "compatibility_outcome": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "resume_ready_evidence": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/reference"
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "resumed"
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "execution_kind": {
+ "const": "resume"
+ },
+ "compatibility_outcome": {
+ "$ref": "#/$defs/reference"
+ },
+ "resume_ready_evidence": {
+ "$ref": "#/$defs/reference"
+ },
+ "result_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "state": {
+ "const": "compatibility-checked"
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "execution_kind": {
+ "const": "compatibility-check"
+ },
+ "compatibility_outcome": {
+ "type": "null"
+ },
+ "resume_ready_evidence": {
+ "type": "null"
+ },
+ "result_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ }
+ }
+ }
+ },
+ {
+ "if": {
+ "properties": {
+ "execution_kind": {
+ "const": "operation"
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "compatibility_outcome": {
+ "type": "null"
+ },
+ "resume_ready_evidence": {
+ "type": "null"
+ },
+ "state": {
+ "enum": [
+ "succeeded",
+ "failed",
+ "ambiguous"
+ ]
+ }
+ }
+ }
+ }
+ ]
+ },
+ "result": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "outcome",
+ "outcome_reference",
+ "result_envelope"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "outcome": {
+ "$ref": "#/$defs/outcome"
+ },
+ "outcome_reference": {
+ "$ref": "#/$defs/reference"
+ },
+ "result_envelope": {
+ "type": "string",
+ "maxLength": 87512,
+ "minLength": 1
+ }
+ }
+ },
+ "resume": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "request_id",
+ "attempt_id",
+ "predecessor",
+ "expected_status_revision",
+ "target",
+ "required_contracts",
+ "result_recipient",
+ "checker_input_envelope",
+ "checker_input_envelope_digest",
+ "timeout_seconds"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "request_id": {
+ "$ref": "#/$defs/id"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "predecessor": {
+ "$ref": "#/$defs/reference"
+ },
+ "expected_status_revision": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512
+ },
+ "target": {
+ "$ref": "#/$defs/target"
+ },
+ "required_contracts": {
+ "type": "array",
+ "maxItems": 16,
+ "items": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ }
+ },
+ "result_recipient": {
+ "$ref": "#/$defs/recipient"
+ },
+ "checker_input_envelope": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 98620
+ },
+ "checker_input_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "timeout_seconds": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 600
+ }
+ }
+ },
+ "resume_proposed": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "request",
+ "attempt_id",
+ "lifecycle_operation_id",
+ "state",
+ "review_url",
+ "status_url"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "request": {
+ "$ref": "#/$defs/reference"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "lifecycle_operation_id": {
+ "$ref": "#/$defs/id"
+ },
+ "state": {
+ "enum": [
+ "awaiting-preflight",
+ "awaiting-approval"
+ ]
+ },
+ "review_url": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1024
+ },
+ "status_url": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1024
+ }
+ }
+ },
+ "error": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "code"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "code": {
+ "enum": [
+ "invalid-request",
+ "not-signed-in",
+ "not-found",
+ "conflict",
+ "precondition-failed",
+ "payload-expired",
+ "result-unavailable",
+ "unsupported",
+ "rate-limited",
+ "unavailable"
+ ]
+ }
+ }
+ },
+ "pending_local": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "scope",
+ "request_id",
+ "attempt_id",
+ "recipient_private_key",
+ "recipient_fingerprint",
+ "private_input_path",
+ "private_input_sha256",
+ "exact_request_body_base64",
+ "request_kind"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "scope": {
+ "$ref": "#/$defs/scope"
+ },
+ "request_id": {
+ "$ref": "#/$defs/id"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "recipient_private_key": {
+ "type": "string",
+ "minLength": 44,
+ "maxLength": 44
+ },
+ "recipient_fingerprint": {
+ "$ref": "#/$defs/digest"
+ },
+ "private_input_path": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 4096
+ },
+ "private_input_sha256": {
+ "$ref": "#/$defs/digest"
+ },
+ "exact_request_body_base64": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 174764
+ },
+ "request_kind": {
+ "enum": [
+ "operation",
+ "retry",
+ "resume"
+ ]
+ }
+ }
+ },
+ "environment_private": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "entries",
+ "box_overlay_identity"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "entries": {
+ "type": "array",
+ "maxItems": 512,
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 256
+ },
+ "value": {
+ "type": "string",
+ "maxLength": 65536
+ }
+ }
+ }
+ },
+ "box_overlay_identity": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 512
+ }
+ }
+ },
+ "preflight_publication": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "publication_id",
+ "preflight",
+ "environment_envelope"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "publication_id": {
+ "$ref": "#/$defs/id"
+ },
+ "preflight": {
+ "$ref": "#/$defs/preflight"
+ },
+ "environment_envelope": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 1398232
+ }
+ }
+ },
+ "outcome_publication": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "publication_id",
+ "outcome",
+ "result_envelope"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "publication_id": {
+ "$ref": "#/$defs/id"
+ },
+ "outcome": {
+ "$ref": "#/$defs/outcome"
+ },
+ "result_envelope": {
+ "anyOf": [
+ {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 87512
+ },
+ {
+ "type": "null"
+ }
+ ]
+ }
+ }
+ },
+ "retry": {
+ "type": "object",
+ "additionalProperties": false,
+ "required": [
+ "version",
+ "request_id",
+ "attempt_id",
+ "operation_label",
+ "target",
+ "result_recipient",
+ "input_envelope",
+ "input_envelope_digest",
+ "timeout_seconds",
+ "predecessor"
+ ],
+ "properties": {
+ "version": {
+ "$ref": "#/$defs/v"
+ },
+ "request_id": {
+ "$ref": "#/$defs/id"
+ },
+ "attempt_id": {
+ "$ref": "#/$defs/id"
+ },
+ "operation_label": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 64
+ },
+ "target": {
+ "$ref": "#/$defs/target"
+ },
+ "result_recipient": {
+ "$ref": "#/$defs/recipient"
+ },
+ "input_envelope": {
+ "type": "string",
+ "maxLength": 98620,
+ "minLength": 1
+ },
+ "input_envelope_digest": {
+ "$ref": "#/$defs/digest"
+ },
+ "timeout_seconds": {
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 600
+ },
+ "predecessor": {
+ "$ref": "#/$defs/reference"
+ }
+ },
+ "description": "Same prepare fields; predecessor is required non-null and its ID must equal the route request_id. Digest binds predecessor request bytes; server resolves its outcome."
+ }
+ }
+}