Repository navigation
feat(verify-run): judge any executor's write from the system of record, aligned with RFC-0002 - #1198
Merged
Merged
Conversation
…of record (prototype) openadapt-flow verify-run reads the store through an existing EffectVerifier (built from the deployment.yaml effects: shape) and rules on an effect_contract.yaml list. The executor's run record is bound by digest and never read as evidence; contract params come from --params, not from the executor. VERIFIED needs every effect CONFIRMED by a system-of-record read; screen read-backs are refused and separate-session reads stop at reconciliation_required. The output keeps every ExecuteEvidenceReceiptV1 field, adds executor_kind, executor_ref_sha256, and effect_verdict under schema openadapt.effect-receipt/v1, and binds an evidence manifest through evidence_digest. It is unsigned; a seal-signature/v1 over it verifies with openadapt_types.seal and openadapt-agent seal verify unchanged. Tests: MockMed fault server as the system of record, with test code as the external actor (correct, wrong note, wrong patient, duplicate, phantom write, no baseline, unreachable store). Ported from openadapt-flow feat/verify-any-executor (8f363086). Signed-off-by: Richard Abrich <richard.abrich@mldsai.com>
verification_tier (independent_readback | screen_readback | unchecked) goes on the receipt and the evidence manifest; only independent_readback can yield verified, and check refuses a verified receipt without it. authorization.approver is null until the openadapt-types approver identity exists (RFC-0002). Ported from openadapt-flow feat/verify-any-executor (0139e1b8). Signed-off-by: Richard Abrich <richard.abrich@mldsai.com>
- Signatures are openadapt.effect-seal-signature/v1 over their own domain (issuer openadapt-cloud:unattested-verifier); an Execute Seal verifier refuses an effect receipt, and an Execute signature on one is refused here. - Per-run 256-bit salt (openadapt.run-salt/v1): the run record, authorization reference, baseline and every bound parameter are HMAC-SHA256 digests; evidence carries only the salt commitment. The salt stays in the 0600 baseline or effect-run.private.json. - Baselines start the run (execution_id), hold exactly six keys, bind five, work once, and count as absent outside max_execution_window_s. REST reads carry X-OpenAdapt-Execution-Id and traceparent. - verification_tier follows the RFC tier rule: independent_readback only for system-of-record reads (Flow tier 1); a separate UI session is screen_readback. - A self-approved write is rejected_policy. - New optional --remediates <receipt_id> and --correlation-id, signed into the receipt body when given. - --check reports the signature and the outcome separately; exit 0 needs both, or an outcome named with --accept-outcome. Signed-off-by: Richard Abrich <richard.abrich@mldsai.com>
RFC-0002 makes openadapt.verify/v1 one file for both commands. verify-run
now ignores the qualify-only sections (app, save_step, inputs, campaign,
verifier.session), expands record with qualify's own record_effects,
expands ${NAME} references with qualify's expander, and computes
workflow_digest with qualify's verify_config_sha256, so a receipt and a
qualification result over one file name the same contract.
abrichr
added a commit
that referenced
this pull request
Oct 17, 2026
Signed-off-by: Richard Abrich <richard.abrich@mldsai.com>
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.
Ports the Chief Architect's
feat/verify-any-executorprototype (8f363086,0139e1b8) intopackages/flowand aligns it with RFC-0002 (Open Effect Receipt).openadapt-flow verify-runreads the system of record through an existing effect verifier and rules on a declared effect contract. The executor can be an agent, a script, a person or a Flow replay. The executor's run record is hashed into the receipt and never read as evidence. It writes an unsignedopenadapt.effect-receipt/v1; it never signs, uploads or calls a model.RFC-0002 alignment:
openadapt.effect-seal-signature/v1(issueropenadapt-cloud:unattested-verifier) over its own domain. A pre-RFC Execute Seal verifier refuses an effect receipt, and--checkrefuses an Execute-domain signature on one.openadapt.run-salt/v1): the run record, the authorization reference, the baseline and every bound parameter in an effect's contract hash are HMAC-SHA256 under a 256-bit salt drawn for the run. The evidence keeps onlysalt_commitment. The salt stays in the 0600 baseline, or ineffect-run.private.jsonwhen there is no baseline.execution_id), holds exactly six keys and binds five, works once, and counts as absent outsidemax_execution_window_s. Each REST read carriesX-OpenAdapt-Execution-Idandtraceparent.independent_readbackonly when every effect was read from the system of record without the UI (Flow tier 1). A separate signed-in UI session isscreen_readback. Onlyindependent_readbackcan yieldverified.rejected_policy.--remediates <receipt_id>and--correlation-id <id>, both opaque ids. They appear in the receipt body only when given, and are then insidereceipt_sha256and so inside the signature.--check: reports the signature (verified) and the outcome (verified_outcome) separately. It exits 0 only when both hold, or when the outcome is one named with--accept-outcome. An unsigned file is never a pass.verify.yamlwith qualify (feat(qualify): declarative qualify from verify.yaml (carry-over of openadapt-flow#532) #1186): verify-run ignores the qualify-only sections andverifier.session, expandsrecordand${NAME}with qualify's own code, and computesworkflow_digestwith qualify'sverify_config_sha256.Tests:
tests/test_verify_run.py(35 tests: salting, one-use and windowed baselines, the window and unsalted checks in--check, the link fields, self-approval, accept-outcome, the domain separation, and the qualify file). Local: ruff, format and mypy are clean; the verify-run and qualify tests pass.Follow-ups:
forbidden_effects(RFC "proposed") isn't implemented yet. The approver shape is a placeholder until the approval contracts from #1187 are wired in.