← Docs
Helix CLI docs
Browse Helix CLI docs

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:

  1. simulate — produce a .helix session from a config
  2. run — alias of simulate (must be identical)
  3. report — produce deterministic HTML reports from a session
  4. export — produce deterministic exported artifacts (JSON + PNG + provenance sidecar)
  5. simulate --append — append runs to an existing session in order

Guarantees

Under deterministic mode (PYTHONHASHSEED=0 + HELIX_DETERMINISTIC=1):

  • Alias parity: simulate and run produce byte-for-byte identical .helix sessions for the same config.
  • Deterministic artifact trees: report and export are 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 --append preserves run order (session evolution is deterministic).
  • Contract stamping: session and export provenance include contract_id + contract_hash so 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:

  • .helix session header:
    • contractId (string, e.g. cli_session_contract_v2)
    • contractHash (string, v2 contract hash)
  • *.export.json provenance block:
    • contract_id
    • contract_hash
  • *.png.provenance.json:
    • contract_id
    • contract_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 is sha256(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 / contractHash keys (to avoid self-referential hashing).
    • Digest is sha256(canonical_json_bytes) where canonical JSON uses sort_keys=True and separators (",", ":").
  • PNG provenance sidecars (*.png.provenance.json):
    • First, validate the sidecar’s artifact_sha256 exactly matches sha256(png_file_bytes) (byte-level binding).
    • Then, hash a canonicalized JSON payload where:
      • artifact_sha256 is rewritten to the PNG pixel digest (sha256_pixels:<…>) (pixel-stable across OS),
      • contract_hash is stripped (to avoid self-referential hashing).

Tree hash:

  • Build a JSON object {relative_path: per_file_digest} with keys sorted.
  • Compute sha256(canonical_json_bytes) where canonical JSON uses sort_keys=True and 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:

  1. Add new versioned files:
    • tests/e2e/test_cli_session_contract_v3.py
    • docs/cli/session_contract_v3.md
  2. Update documentation pointers:
    • mkdocs.yml (nav entry for the new version)
    • docs/governance_contract.md (reference the new version)
  3. Add a changelog entry in CHANGELOG.md.

Enforcement:

  • The CI guard tools/check_cli_session_contract_bump.py forbids editing/deleting existing vN contracts.
  • The cross-platform workflow always runs the latest vN via tools/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.