The one call per import : the composed non-authorizing pass over a Blueprint + Deployment pair under host inputs. Stage order is PINNED — canonical → digest → negotiation → structure → portability → signatures → bind → bounds — each stage reject-or-annotate, never repair, the earliest defect reported.
Stage machinery (each denies typed, subject naming its side):
canonical— re-encode both artifacts' values (RFC 8785). A struct has no bytes to compare against, so this stage catches only what ENCODE denies: the ceiling family ({:ceiling, :bytes}— the:canonical_bytes_exceededname),:integer_magnitude(a hand-built above-I-JSON integer), and the encode-side Json reasons.:non_canonical_bytesis decode-time only (it needs the original bytes).digest— recompute each artifact's content digest over its covered members and compare against the declared member (:digest_mismatch).negotiation— both artifacts againstInputs.support. Extension facts land as checks: a quarantined optional namespace is%{surface: :extensions, verified: false}(the unscanned honesty), a retained one%{surface: :extensions, verified: true, detail: "retained"}. Notices stay in theNegotiation.Outcomefor standalone callers — the frozen Evidence struct has no notices field.structure—Registryvalidation against each artifact's table (the closed world, cardinalities, member checks).portability— the DIRECT scans under the authored channel re-derived from THIS import's negotiated critical extensions (F8): non-authored extension bodies, eligibility expressions, every core string, and signature key_ids (:forbidden_portable_value). The registry half of the decode pipeline is NOT re-run here — it is stage 4's own catch, and re-running it would make that stage's guard unobservable.signatures— everysignaturesentry verifies againstInputs.keysAND its signedcontent_digestBINDS to the artifact's recomputed digest: an honestly-signed statement naming a different digest is evidence over THAT digest, not this artifact (:digest_mismatch). Attestations need no pass here — the registry table denies any non-empty attestation member today (the kind registry is empty; the fail-closed posture).bind—Deployment.verify_binding/3underInputs.observations(host clock, attestation age, observed descriptor digests).bounds—from_blueprint/from_deployment/host intersected underInputs.protected_clamp. Every clamp lands asEvidence.clampsand as onesurface: :boundscheck whose detail is the%ClampEvidence{};:clamp_appliedremains the notice code for the notice machinery (a clamp notice cannot ride the negotiation Outcome — bounds runs after it).
The result is %Evidence{} — never a decision; not_verified names
the seven host-owned surfaces by construction (Evidence.build/1).
Summary
Functions
Run the eight-stage composed pass. Denies typed at the earliest failing stage; every malformed input shape (either artifact, or any Inputs field) denies typed without raising.
Functions
@spec reconcile( AgentBlueprintProtocol.Blueprint.t(), AgentBlueprintProtocol.Deployment.t(), AgentBlueprintProtocol.Reconcile.Inputs.t() ) :: {:ok, AgentBlueprintProtocol.Evidence.t()} | {:error, AgentBlueprintProtocol.Error.t()}
Run the eight-stage composed pass. Denies typed at the earliest failing stage; every malformed input shape (either artifact, or any Inputs field) denies typed without raising.