Powered by AppSignal & Oban Pro

Host import

docs/livebooks/host-import.livemd

Run in Livebook

Host import

This notebook decodes the shipped artifacts, compares declared build identities with host observations, intersects bounds, calls reconcile/3, and reads each part of the resulting evidence.

The first cell installs the published package at the release candidate requirement.

Mix.install([{:agent_blueprint_protocol, "~> 1.0.0-rc.2"}])

Locate and decode both shipped artifacts and the plain JSON views used to build host observations.

dependency_path =
  try do
    Mix.Project.deps_paths() |> Map.get(:agent_blueprint_protocol)
  rescue
    _ -> nil
  end

package_root =
  [dependency_path, Application.app_dir(:agent_blueprint_protocol), File.cwd!()]
  |> Enum.reject(&is_nil/1)
  |> Enum.find(fn path -> File.regular?(Path.join(path, "examples/echo-blueprint.json")) end)

true = is_binary(package_root)

blueprint_bytes = File.read!(Path.join(package_root, "examples/echo-blueprint.json"))
deployment_bytes = File.read!(Path.join(package_root, "examples/echo-deployment.json"))
blueprint_json = JSON.decode!(blueprint_bytes)
deployment_json = JSON.decode!(deployment_bytes)

{:ok, blueprint} = AgentBlueprintProtocol.decode_blueprint(blueprint_bytes)
{:ok, deployment} = AgentBlueprintProtocol.decode_deployment(deployment_bytes)

%{blueprint_decoded: true, deployment_decoded: true}
%{blueprint_decoded: true, deployment_decoded: true}

Compare observed identities

Compatibility compares each manifest identity with an exact observed identity. The empty list and a matching list illustrate the two results.

Build the observed identity list from the shipped Deployment Manifest and compare both an empty and matching observation.

alias AgentBlueprintProtocol.Compatibility.Observed
support = %AgentBlueprintProtocol.Negotiation.Support{revisions: MapSet.new([1])}
{:ok, negotiation} = AgentBlueprintProtocol.negotiate(blueprint, support)

notices =
  Enum.map(negotiation.notices, fn
    :extension_deprecated -> :deprecated
    :extension_unknown_optional_retained -> :unknown_optional
    other -> {:unknown_notice, other}
  end)

identities =
  Enum.map(deployment_json["build_identities"], fn item ->
    %{kind: item["kind"], name: item["name"], version: item["version"], digest: item["digest"]}
  end)

none = AgentBlueprintProtocol.verify_compatibility(deployment, %Observed{identities: []})
full = AgentBlueprintProtocol.verify_compatibility(deployment, %Observed{identities: identities})

%{
  negotiated_revision: negotiation.protocol_revision,
  notices: notices,
  none: case none do {:error, error} -> error.code; {:ok, _} -> :matched end,
  full: match?({:ok, %AgentBlueprintProtocol.Evidence{}}, full)
}
%{none: :compatibility_entry_missing, full: true, notices: [], negotiated_revision: 1}

Intersect bounds

A host can narrow an operational value. A protected narrowing returns a denial under the deny posture and a clamp record under the acknowledge posture.

Narrow the example bounds and compare the deny and acknowledge postures.

alias AgentBlueprintProtocol.BoundsAlgebra
alias AgentBlueprintProtocol.BoundsAlgebra.{BoundSet, Sources}

{:ok, blueprint_bounds} = BoundsAlgebra.from_blueprint(blueprint)
{:ok, deployment_bounds} = BoundsAlgebra.from_deployment(deployment)
{:ok, host_values} = BoundSet.to_map(deployment_bounds)
host_values = %{host_values | max_attempts: 2, disclosure_ceiling: :none}
{:ok, host_bounds} = BoundSet.new(host_values)

sources = %Sources{
  blueprint: blueprint_bounds,
  deployment: deployment_bounds,
  host: host_bounds,
  protected_clamp: :deny
}

denied = BoundsAlgebra.intersect(sources)
{:ok, acknowledged} = BoundsAlgebra.intersect(%{sources | protected_clamp: :acknowledge})
{:ok, effective} = BoundSet.to_map(acknowledged.effective)

%{
  denial: case denied do {:error, error} -> error.code; {:ok, _} -> :allowed end,
  effective_attempts: effective.max_attempts,
  clamp_fields: Enum.map(acknowledged.clamps, & &1.field)
}
%{
  denial: :protected_bound_clamp_denied,
  effective_attempts: 2,
  clamp_fields: [:disclosure_ceiling, :max_attempts]
}

Observations

Descriptor observations can be absent, partial, or complete. The example Deployment has two tool bindings, so each map is made directly from those values.

Check none, partial, and full descriptor observations, then pass the complete set to reconcile/3.

alias AgentBlueprintProtocol.{Reconcile, BoundsAlgebra}

tool_bindings = deployment_json["tool_bindings"]

observed_all =
  Map.new(tool_bindings, fn binding ->
    {binding["logical_operation"], binding["descriptor_digest"]}
  end)

observed_partial = Map.take(observed_all, [hd(Map.keys(observed_all))])

observation_results =
  [
    %AgentBlueprintProtocol.Deployment.Observations{observed: %{}},
    %AgentBlueprintProtocol.Deployment.Observations{observed: observed_partial},
    %AgentBlueprintProtocol.Deployment.Observations{observed: observed_all}
  ]
  |> Enum.map(&AgentBlueprintProtocol.Deployment.verify_binding(deployment, blueprint, &1))

{:ok, host_bounds} = BoundsAlgebra.from_deployment(deployment)
support = %AgentBlueprintProtocol.Negotiation.Support{revisions: MapSet.new([1])}

inputs = %Reconcile.Inputs{
  host_bounds: host_bounds,
  support: support,
  keys: [],
  protected_clamp: :acknowledge,
  observations: %AgentBlueprintProtocol.Deployment.Observations{observed: observed_all}
}

{:ok, evidence} = AgentBlueprintProtocol.reconcile(blueprint, deployment, inputs)

%{
  observation_results: Enum.map(observation_results, &match?(:ok, &1)),
  reconcile_succeeded: is_struct(evidence, AgentBlueprintProtocol.Evidence)
}
%{observation_results: [true, true, true], reconcile_succeeded: true}

Read every evidence field

Check names and detail shapes can grow. This reader matches known shapes and keeps a catch-all. It reports the verified flag and summarizes each evidence member.

Read all Evidence fields, including verified check flags and not_verified entries, with catch-all branches for future additions.

alias AgentBlueprintProtocol.{BoundsAlgebra, Digest, Evidence}

check_view =
  Enum.map(evidence.checks, fn
    %{surface: surface, subject: subject, verified: verified, detail: detail} ->
      detail_type =
        case detail do
          nil -> :none
          %Evidence.Signatures{} -> :signatures
          %Evidence.Binding{checked: checked, not_verified: skipped} ->
            {:binding, length(checked), length(skipped)}
          %BoundsAlgebra.ClampEvidence{field: field} -> {:clamp, field}
          %Digest{} -> :digest
          other -> {:additional_detail, is_struct(other)}
        end

      %{surface: surface, subject: subject, verified: verified, detail: detail_type}

    other ->
      %{unknown_check: is_map(other)}
  end)

unverified_view =
  Enum.map(evidence.not_verified, fn
    :tenancy -> :host_owned
    :live_policy -> :host_owned
    other when is_atom(other) -> :additional_surface
    _unknown -> :unknown_shape
  end)

%{
  protocol_revision: evidence.protocol_revision,
  blueprint_digest: Digest.to_tagged(evidence.blueprint_digest),
  deployment_digest: Digest.to_tagged(evidence.deployment_digest),
  checks: check_view,
  effective_bounds: match?({:ok, _}, BoundsAlgebra.BoundSet.to_map(evidence.effective_bounds)),
  clamps: Enum.map(evidence.clamps, &{&1.field, &1.requested, &1.effective}),
  optional_extensions_retained: evidence.optional_extensions_retained,
  not_verified: unverified_view
}
%{
  protocol_revision: 1,
  checks: [
    %{detail: :none, subject: ["blueprint"], surface: :canonical, verified: true},
    %{detail: :none, subject: ["deployment"], surface: :canonical, verified: true},
    %{detail: :digest, subject: ["blueprint"], surface: :digest, verified: true},
    %{detail: :digest, subject: ["deployment"], surface: :digest, verified: true},
    %{detail: :none, subject: ["blueprint"], surface: :negotiation, verified: true},
    %{detail: :none, subject: ["deployment"], surface: :negotiation, verified: true},
    %{detail: :none, subject: ["blueprint"], surface: :structure, verified: true},
    %{detail: :none, subject: ["deployment"], surface: :structure, verified: true},
    %{detail: :none, subject: ["blueprint"], surface: :portability, verified: true},
    %{detail: :none, subject: ["deployment"], surface: :portability, verified: true},
    %{
      detail: {:additional_detail, false},
      subject: ["blueprint"],
      surface: :signatures,
      verified: false
    },
    %{
      detail: {:additional_detail, false},
      subject: ["deployment"],
      surface: :signatures,
      verified: false
    },
    %{detail: {:binding, 4, 1}, subject: ["deployment"], surface: :bind, verified: false},
    %{detail: :none, subject: ["bounds"], surface: :bounds, verified: true},
    %{
      detail: {:clamp, :disclosure_ceiling},
      subject: ["disclosure_ceiling"],
      surface: :bounds,
      verified: true
    }
  ],
  not_verified: [:host_owned, :host_owned, :additional_surface, :additional_surface,
   :additional_surface, :additional_surface, :additional_surface, :additional_surface,
   :additional_surface, :additional_surface, :additional_surface, :additional_surface],
  blueprint_digest: "sha-256:b1Aw4cU5AbV9k8bdbZkRCsySDHGpTAwB-aQm57Wh7B8",
  deployment_digest: "sha-256:tWFr0caS0AWFJd2UcB9gZv3kNjIUP8xZ08WWM_h8xgo",
  effective_bounds: true,
  clamps: [{:disclosure_ceiling, :full, :summary}],
  optional_extensions_retained: []
}

Decoder limits and error shape

A lower byte limit returns the same typed Error struct used by other fallible calls.

Decode with a deliberately small byte limit and read the stable error fields.

{:error, %AgentBlueprintProtocol.Error{} = limit_error} =
  AgentBlueprintProtocol.decode_blueprint(blueprint_bytes, %{bytes: 16})

%{code: limit_error.code, subject: limit_error.subject, detail: limit_error.detail}
%{code: {:ceiling, :bytes}, detail: nil, subject: []}

Next