Helix CLI Session Contract v3
This document defines the black-box contract for the Helix CLI session lifecycle. It is enforced as bytes-on-disk, not as internal implementation behavior.
v3 is a contract bump over v2 with one additional product guarantee: exported artifacts embed the full scientific contract header (policy/semantics/determinism/backend fingerprint), including explicit downgrade markers when an escape hatch is used.
Scope
Contracted lifecycle:
simulate— produce a.helixsession from a configrun— alias ofsimulate(must be identical)report— produce deterministic HTML reports from a sessionexport— produce deterministic exported artifacts (JSON + PNG + provenance sidecar)simulate --append— append runs to an existing session in order
Guarantees
Under deterministic mode (PYTHONHASHSEED=0 + HELIX_DETERMINISTIC=1):
- Alias parity:
simulateandrunproduce byte-for-byte identical.helixsessions for the same config. - Deterministic artifact trees:
reportandexportare deterministic across repeated runs. - Filtered report determinism:
report --run-id <id>emits only the requested run’s report with stable output. - Export provenance coupling: exports include a PNG provenance sidecar that correctly hashes the emitted PNG.
- Append semantics:
simulate --appendpreserves run order (session evolution is deterministic). - Contract stamping: session and export provenance include
contract_id+contract_hashso evidence bundles are portable across time/CI logs. - Scientific contract header stamping (new in v3):
*.export.jsonpayloads include a top-levelheaderthat binds:policyHash,semanticHash,determinismClass, and backend fingerprint (backend.kind,backend.details).- Any explicit downgrade (e.g., D2 unpinned policy escape hatch) is emitted as an auditable entry under
header.downgrades. - Any contract identity env fallback used by the writer is recorded as
provenance_block.contract_env_fallback_keys.
Failure behavior (golden paths)
Contracted failures must be deterministic:
- Non-zero exit codes for invalid inputs.
- Stable error messages (at least at the “reason substring” level).
- Predictable partial outputs (e.g., created directories without a verdict when pack selection fails).
Contract stamp (v3)
Artifacts include:
.helixsession header:contractId(string, e.g.cli_session_contract_v3)contractHash(string, v3 contract hash)
*.export.jsonprovenance block:contract_idcontract_hash
*.png.provenance.json:contract_idcontract_hash
contract_hash is a constant shipped in code and updated only via the vN → vN+1 bump workflow.
Compatibility (downgrade story)
Artifacts are version-stamped. Verification tooling should never claim “OK” for an artifact governed by a newer contract than it understands.
If you try to verify a v3-stamped artifact with a tool that only supports v2, verification fails deterministically:
- Exit code: non-zero
- Error substring:
unsupported cli session contract: cli_session_contract_v3 (tool supports up to v2)
This is intentional: older tools cannot safely validate newer contract semantics (normalization rules, lifecycle behavior, and failure taxonomy). The correct fix is to upgrade the Helix toolchain used for verification.
Downgrade is a tooling/verification compatibility story only; it does not “downgrade” the underlying simulation semantics or re-interpret artifacts to match older assumptions.
Contract hash normalization (v3)
The cross-platform gate compares a single contract hash derived from the full output tree.
Hash inputs:
- All files under the contract test’s output root directory are included.
- Paths are hashed by their relative POSIX path (stable across OS runners).
Per-file normalization rules:
- Non-PNG files: digest is
sha256(file_bytes)except for contract-stamped JSON (below). - PNG files (
*.png): digest issha256(decoded_RGBA_pixels + {size, mode}).- This ignores platform-specific PNG encoding differences (metadata/chunk ordering/compression), while still treating the image as deterministic data.
- Contract-stamped JSON (
*.helix,*.export.json):- Parse JSON.
- Strip
contract_hash/contractHashkeys (to avoid self-referential hashing). - Digest is
sha256(canonical_json_bytes)where canonical JSON usessort_keys=Trueand separators(",", ":").
- PNG provenance sidecars (
*.png.provenance.json):- First, validate the sidecar’s
artifact_sha256exactly matchessha256(png_file_bytes)(byte-level binding). - Then, hash a canonicalized JSON payload where:
artifact_sha256is rewritten to the PNG pixel digest (sha256_pixels:<…>) (pixel-stable across OS),contract_hashis stripped (to avoid self-referential hashing).
- First, validate the sidecar’s
Tree hash:
- Build a JSON object
{relative_path: per_file_digest}with keys sorted. - Compute
sha256(canonical_json_bytes)where canonical JSON usessort_keys=Trueand separators(",", ":").
If any of the above normalization rules change, that is a spec change and requires a new contract version (v4), not an edit-in-place of v3.
Enforcement
Source of truth:
tests/e2e/test_cli_session_contract_v3.py
Cross-platform gate (Linux/macOS):
.github/workflows/cli-session-contract.yml