helixordevelopers

Operational excellence

Run packs the way you run code: version them, test them in CI, promote them through environments, and watch what they decide. This page gives you the log schema, the metrics, the promotion flow and the runbooks.

Log receipts, not payloads#

Write one structured log line per decision. Include the fields you need to explain it later and nothing that repeats the sensitive input:

{
  "ts": "2026-09-27T14:03:11Z",
  "request_id": "req_8f2c",
  "pack_id": "custom.claims_guard.v1",
  "pack_version": "1.4.0",
  "pack_digest": "sha256:9d1e…",
  "action": "redact_and_permit_contact_pii",
  "invariants_passed": false,
  "rule_ids": ["RULE-GDPR-EMAIL-REDACT"],
  "redactions": 1,
  "receipt_hash": "hx_proof_ddaca3a134e0b6e6599f3ecd",
  "latency_us": 19.7,
  "caller_latency_ms": 0.4
}
  • Never log the input text, triggers[].matched_items or a full result object. See Security.
  • Add the pack version and digest yourself. The receipt covers the pack ID but not its version. Take the version from your deployment metadata and the digest from the .hxpack file you deployed.
  • Log errors by type. Log the exception class and your request ID, not the message payload.

Metrics to emit#

The runtime exports no metrics endpoint. Emit these from your application or service wrapper:

MetricTypeLabelsWhy
helixor_decisions_totalcounterpack_id, actionVolume, plus the block/redact/permit mix. A sudden shift usually means a pack or input change.
helixor_rule_fired_totalcounterpack_id, rule_idWhich rules do the work, and which never fire.
helixor_decision_errors_totalcountererror_typeEvery error is a fail-closed block. Alert on any increase.
helixor_decision_latency_secondshistogramplacementMeasured at the caller, not from latency_us.
helixor_stream_halted_totalcounterpack_idStreams stopped by a fatal rule.
helixor_license_days_remaininggaugelicense_idFrom the daily expiry check in Reliability.
helixor_pack_infogauge (1)pack_id, version, digestWhich pack each instance is running, for mixed-version detection during rollouts.

Distributed tracing and a built-in metrics endpoint are Planned. Until then, wrap the evaluate call in a span of your own. Put only the action, pack ID and receipt hash on the span.

Version and promote packs#

Playbookreviewed commit CIcompile + golden tests Artifact storepack + digest Stagingcanary traffic Productionapproved
The reviewed playbook is the source of truth. Every environment runs a pack built from a tested commit.
  • Bump version in the playbook for every change. The runtime carries the version but does not enforce ordering, so your pipeline must.
  • Identify builds by digest. Compiling the same playbook twice produces different bytes, because each compile uses a fresh random nonce. Record the source commit and the SHA-256 of the .hxpack you promote. Promote that file; do not rebuild it later.
  • Mind the license binding. A pack opens only with the license it was compiled for. If staging and production use different licenses, compile the same reviewed commit once per license in CI, and test both builds.
  • Keep an approval record. Record which version and digest are approved for each environment, and require a review to change it.

Test packs in CI with golden sets#

A golden set is a file of inputs with the action you expect for each one. Include at least one input per rule that should fire, one per rule that must not fire, and your known tricky cases: values split across chunks, near-miss numbers that fail the checksum, and long inputs.

#!/usr/bin/env bash
set -euo pipefail
helixor-pack compile --playbook playbooks/claims_guard.yaml \
  --license "$HELIXOR_LICENSE_FILE" --out build/claims_guard.hxpack
sha256sum build/claims_guard.hxpack > build/claims_guard.hxpack.sha256

fail=0
while IFS=$'\t' read -r expected text; do
  actual="$(helixor-pack run --pack build/claims_guard.hxpack \
            --license "$HELIXOR_LICENSE_FILE" --text "$text" | python3 -c 'import json,sys; print(json.load(sys.stdin)["action"])')"
  if [ "$actual" != "$expected" ]; then
    echo "FAIL: expected $expected, got $actual"; fail=1
  fi
done < tests/golden/claims_guard.tsv
exit $fail
  • Keep golden inputs synthetic. Use the standard test values (123-45-6789, 4111-1111-1111-1111, example.com addresses, 555 numbers), never production data.
  • Fail the build on any mismatch, and on any rule that no golden input exercises.
  • Provide the CI license from your secret store at job time. Do not commit it.

The testing policies tutorial builds a full test suite.

Runbooks#

Service will not start#

  1. Read the error type in the container log.
  2. PackUnsealError after a license change: the packs were not rebuilt for the new license. Deploy the pack set built for it, or roll back to the previous pair.
  3. LicenseExpiredError: the grace period has ended. Deploy the renewed license with packs rebuilt for it.
  4. LicenseSignatureInvalidError: the license file was altered or truncated in transit. Restore it from your secret manager.
  5. LicenseEntitlementError: the pack or a solver it uses is not in your license. Check with helixor-pack inspect-license.

License expiring#

  1. Request the renewal as soon as the 30-day warning fires.
  2. Follow the rotation procedure in Reliability.
  3. Confirm helixor_license_days_remaining reflects the new license after rollout.

Instance running the wrong pack#

  1. Compare helixor_pack_info across instances.
  2. If any instance reports the Community pack when you expected your own, stop it. A missing file made it fall back.
  3. Check the mounts, then redeploy.

Sudden change in block or redaction rate#

  1. Check whether a pack rollout coincides with the change (helixor_pack_info).
  2. Check helixor_rule_fired_total to find the rule responsible.
  3. If the pack changed, roll back and add the triggering inputs to the golden set. If the pack did not change, investigate the upstream data source.

Decision errors rising#

  1. Every error is a block, so users are affected. Check the error type.
  2. DeveloperQuotaExceededError in production means a Developer license was deployed. Replace it with your production license.