feat: add structured push result contract - #369
Merged
Conversation
A 201 status code alone did not prove the hosted control plane retained the intended artifact. Require the complete server-owned identity chain in hosted.push() itself, so the human-readable command gets the same protection as --json: the server ingest id, the artifact kind and hash, a governed next action for a recording, and, for a bundle, the accepted status plus the exact retained version binding (id, org, workflow, artifact hash, resolved run, runtime-validation id, version number). Anything short of that is an uncertain delivery, never a success. Also: - Upload a verified private snapshot of the approved archive so a path swap between approval and egress cannot ship unapproved bytes. - Bind the accepted workflow to the requested --workflow-id, and the retained version's promoted_from_run_id to --resolves-run-id. - Replace the review "command" string with a typed review_sanitized action plus a separate original_path, so a controller never builds a shell command from a local path. The human-readable output still prints the review command. - Pin the accepted runtime-validation attestation schemas to v1, v2 and v3, and require the governed authorization template exactly on v3. - Accept canonical RFC 9562 UUID versions 1-8 for server-owned identifiers, matching the hosted control plane's own check and Flow's report-run regex. - Collapse the obsolete invalid_ingest_response failure code into delivery_uncertain, and carry the local reconciliation binding into it. - Report an uncertain delivery in human-readable mode with the artifact hash and an explicit do-not-retry instruction, without leaking server text. Verified against openadapt-cloud origin/main: /api/ingest returns ingest.artifact_ingest_id for accepted, deduplicated, and recording responses, and the accepted bundle response carries the retained version record.
abrichr
force-pushed
the
codex/push-json-contract
branch
from
August 18, 2026 23:02
37a8ba7 to
763079f
Compare
abrichr
marked this pull request as ready for review
August 19, 2026 21:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
openadapt-flow push --jsonwith the versionedopenadapt.push-result/v1controller contractpaused_for_review,accepted_for_ingest,failed, anddelivery_uncertainhosted.push()itself, so the human-readable command gets the same protection as--jsonpushoutput when--jsonis absentSafety contract
paused_for_reviewand fully boundaccepted_for_ingest201status code alone is never proof. Flow also requires the server ingest id, artifact kind and hash, a governed next action for a recording, and, for a bundle,status: acceptedplus a retained version that exactly binds organization, workflow, artifact hash, version number, resolved run, and runtime-validation idworkflow_idorartifact_ingest_id--workflow-id, and the retainedpromoted_from_run_idto--resolves-run-iddelivery_uncertain; require reconciliation before retry. The human-readable mode prints the artifact hash and an explicit do-not-retry instruction, and leaks no server textcommandstring with the typedreview_sanitizedaction plus a separateoriginal_path, so a controller never builds a shell command from a local pathCross-repository verification
Verified read-only against
openadapt-cloudorigin/main:/api/ingestreturnsingest.artifact_ingest_idfor accepted, deduplicated, and recording responses(
src/lib/artifactIngestResponse.ts), and an accepted bundle response carriesthe retained
versionrecord withid,org_id,workflow_id,version,artifact_sha256,runtime_validation_id, andpromoted_from_run_id. Cloudmints server ids as RFC 9562 version-5 UUIDs in mock mode, which is why Flow
accepts versions 1-8 rather than 1-5.
Validation
pytest -q tests/test_hosted.py tests/test_runtime_validation.py tests/test_sanitized_artifact.py— 294 passed, 1 skippedpytest -q --ignore=tests/e2e --ignore=tests/test_install_playwright_browser.py) — passruff check openadapt_flow,ruff format --check openadapt_flow tests,mypy— passpython scripts/check_consistency.py,python scripts/check_release_consistency.py— passschemas/push-result-v1.json, andpublic-artifacts.jsonpins its SHA-256🤖 Generated with Claude Code