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:
- Specify the exact bytes or canonical structure committed by each field.
- Include model and generation identifiers needed by your audit policy.
- Normalize text, Unicode, line endings, and JSON consistently.
- Bind source version identifiers, not only display names.
- Retain enough source material or independent hashes to reproduce each commitment.
- 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:
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:
- generation-pins metadata and byte reads;
- computes SHA-256 over the exact object bytes;
- parses the bounded packet contract;
- requests an appliance receipt over private, verified HTTPS;
- verifies the signature, exact request bindings, public key, and fingerprint independently;
- writes create-only canonical receipt evidence; and
- 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_keyis 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.