Skip to content

Packet integration reference

Your application is the integration point. It calls Vertex AI, chooses which result to attest, creates one bounded packet, and uploads that packet under the deployment's artifact prefix.

Integration boundary

customer application
  -> customer-selected Vertex AI model
  -> hx.verifiable-ai.rag-packet/v1 JSON
  -> versioned Cloud Storage artifact object
  -> Eventarc finalize event
  -> internal Cloud Run adapter
  -> private HX-Provenance appliance
  -> receipt or rejection evidence

The Marketplace package does not create Vertex AI endpoints, intercept model calls, or prove that every inference was captured. The producer controls model invocation, packet construction, commitment semantics, object naming, and upload authorization.

Required packet fields

JSON path Requirement Meaning
schema Exact hx.verifiable-ai.rag-packet/v1 Versioned parser contract
envelope.packet_id Stable ASCII identifier, at most 128 characters Producer's logical packet ID
envelope.created_utc Real RFC3339 UTC timestamp Producer-declared packet creation time
content.task Exact rag-answer Supported v1 task
content.model.provider ASCII identifier, at most 128 characters Normally vertex-ai
content.model.model ASCII identifier, at most 256 characters Customer-selected model ID
content.prompt.prompt_sha256 Lowercase 64-hex SHA-256 Producer commitment to prompt material
content.retrieval.k Bounded non-negative integer Declared retrieval limit
content.retrieval.source_set_sha256 Lowercase 64-hex SHA-256 Producer commitment to the source set
content.retrieval.sources[].id Unique ASCII identifier, at most 256 characters Source IDs included in signed context
content.output.output_sha256 Lowercase 64-hex SHA-256 Producer commitment to model output
content_sha256 Lowercase 64-hex SHA-256 Producer commitment to content under its policy

The source count must not exceed retrieval.k or the configured source limit. JSON must be valid UTF-8 with an object root, no duplicate keys, and no non-finite numbers.

Extra fields are permitted but remain subject to byte, depth, node, key-length, string, and source-count bounds. Extra fields are not automatically copied into signed receipt context. Only the documented parsed fields and the adapter-computed packet-object SHA-256 are bound by the v1 receipt request.

Example packet

{
  "schema": "hx.verifiable-ai.rag-packet/v1",
  "envelope": {
    "packet_id": "rag-answer-20260804-000001",
    "created_utc": "2026-08-04T12:00:00Z"
  },
  "content": {
    "task": "rag-answer",
    "model": {
      "provider": "vertex-ai",
      "model": "gemini-model-id"
    },
    "prompt": {
      "prompt_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    },
    "retrieval": {
      "k": 2,
      "source_set_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
      "sources": [
        {"id": "source-001"},
        {"id": "source-002"}
      ]
    },
    "output": {
      "output_sha256": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
    }
  },
  "content_sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
}

The repeated hex values demonstrate format only. Do not use them in production.

Define commitment semantics

The adapter validates commitment format but does not receive or recompute every nested preimage. Define a producer policy before integration:

  1. Specify the exact bytes or canonical structure committed by each field.
  2. Include model and generation identifiers needed by your audit policy.
  3. Normalize text, Unicode, line endings, and JSON consistently.
  4. Bind source version identifiers, not only display names.
  5. Retain enough source material or independent hashes to reproduce each commitment.
  6. Version the producer policy when its canonicalization changes.

A compact canonical JSON function is:

import hashlib
import json


def canonical_json(value: object) -> bytes:
    return json.dumps(
        value,
        ensure_ascii=False,
        separators=(",", ":"),
        sort_keys=True,
    ).encode("utf-8")


def commitment(value: object) -> str:
    return hashlib.sha256(canonical_json(value)).hexdigest()

Do not describe a producer commitment as independently recomputed by HX-Provenance unless your application or another evidenced control actually performs that recomputation.

Upload contract

Upload one complete JSON object beneath the configured artifact prefix, normally packets/:

export ARTIFACT_UPLOAD_URI="gs://deployment-artifact-bucket/packets/"
export OBJECT_NAME="answer-packets/unique-packet-name.json"
gcloud storage cp packet.json "${ARTIFACT_UPLOAD_URI}${OBJECT_NAME}"

Requirements:

  • object name starts with the configured prefix and ends in .json;
  • object bytes are complete before finalization;
  • each logical packet uses an intentional object name;
  • producer identity has object creation access only if that is sufficient for the workflow; and
  • source bucket, object name, and generation are retained with application telemetry.

Object replacement creates a new generation and therefore a new provenance event. Do not overwrite an object merely to retry transient processing.

Generation-bound identity

The adapter derives event_key from:

bucket UTF-8 bytes
object-name UTF-8 bytes
generation as unsigned 8-byte big-endian integer

It uses the exact domain separator and length prefixes below:

import hashlib


def event_key(bucket_name: str, object_name: str, generation: int) -> str:
    if not 0 < generation < 2**63:
        raise ValueError("generation must be a positive signed 64-bit integer")
    value = bytearray(b"HX-GCS-FINALIZED-EVENT-V1\0")
    for field in (bucket_name.encode("utf-8"), object_name.encode("utf-8")):
        value.extend(len(field).to_bytes(8, "big", signed=False))
        value.extend(field)
    value.extend(generation.to_bytes(8, "big", signed=False))
    return hashlib.sha256(value).hexdigest()

The Eventarc event ID is not part of this identity. The default evidence paths are:

receipts/<first-two-event-key-hex>/<event-key>.receipt.json
rejections/<first-two-event-key-hex>/<event-key>.rejection.json

Accepted outcome

For a valid packet, the adapter:

  1. generation-pins metadata and byte reads;
  2. computes SHA-256 over the exact object bytes;
  3. parses the bounded packet contract;
  4. requests an appliance receipt over private, verified HTTPS;
  5. verifies the signature, exact request bindings, public key, and fingerprint independently;
  6. writes create-only canonical receipt evidence; and
  7. MERGEs one BigQuery row by event_key.

A stored receipt is accepted only after independent adapter verification. BigQuery contains accepted receipts only.

Rejected outcome

Permanent JSON, schema, or configured packet-limit failures create deterministic rejection evidence. The rejection contains the generation-specific source tuple, storage size/checksum metadata, event_key, schema, and fixed outcome code. It does not contain packet bytes.

The adapter acknowledges a permanent rejection only after create-only evidence persists. Rejected packets bypass the appliance and BigQuery. Correct the producer and create a new object generation; do not delete the earlier rejection merely to hide a failed input.

Retry behavior

Eventarc delivery is at least once. Retries converge because:

  • event_key is deterministic for one source generation;
  • receipt and rejection writes are create-only;
  • an existing receipt is re-read and fully re-verified;
  • a create race succeeds only when canonical bytes are identical; and
  • BigQuery uses MERGE ... ON event_key.

A 5xx response means the operation may succeed on retry. A 2xx response means accepted receipt evidence or authoritative rejection evidence persisted. Monitor artifact generations that have neither outcome.

Producer security checklist

  • Vertex AI and packet-producing code run in the intended customer project and identity boundary.
  • Commitments use a documented canonicalization and retained preimages or hashes.
  • Object names do not expose regulated or confidential data.
  • Producer IAM is no broader than required.
  • Packet bodies and secrets are excluded from ordinary logs and support email.
  • Source tuple and application trace identifiers are retained.
  • Receipt verification pins an independently obtained key and fingerprint.
  • Claim language distinguishes cryptographic inclusion from factual correctness.

Start with the Quickstart, then use Operations and Troubleshooting for production rollout.