Helix CLI Session Contract v2
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.
v2 is a contract bump over v1 with one additional product guarantee: exported/session artifacts self-declare the contract identity that governs them.
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.
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 (v2)
Artifacts include:
.helixsession header:contractId(string, e.g.cli_session_contract_v2)contractHash(string, v2 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 v2-stamped artifact with a tool that only supports v1, verification fails deterministically:
- Exit code: non-zero
- Error substring:
unsupported cli session contract: cli_session_contract_v2 (tool supports up to v1)
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.
Contract hash normalization (v2)
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 (v3), not an edit-in-place of v2.
Contract bump workflow (v2 → v3)
This contract is designed to be hard to change by accident.
To intentionally change behavior:
- Add new versioned files:
tests/e2e/test_cli_session_contract_v3.pydocs/cli/session_contract_v3.md
- Update documentation pointers:
mkdocs.yml(nav entry for the new version)docs/governance_contract.md(reference the new version)
- Add a changelog entry in
CHANGELOG.md.
Enforcement:
- The CI guard
tools/check_cli_session_contract_bump.pyforbids editing/deleting existingvNcontracts. - The cross-platform workflow always runs the latest
vNviatools/run_cli_session_contract.py.
Enforcement
Source of truth:
tests/e2e/test_cli_session_contract_v2.py
Cross-platform gate (Linux/macOS):
.github/workflows/cli-session-contract.yml
Any intentional behavioral or artifact-shape change to this lifecycle should be treated as a breaking change and versioned as a new contract rather than silently drifting an existing version.