CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / required-checks (push) Canceled after 0s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Canceled after 0s
deploy / deploy (push) Canceled after 0s
Auto-version and Release / release (push) Canceled after 15s
CI Pipeline / go-surface (push) Canceled after 14s
CI Pipeline / lint (push) Canceled after 16s
CI Pipeline / unit-tests (push) Canceled after 16s
CI Pipeline / canary (push) Canceled after 15s
CI Pipeline / type-check (push) Canceled after 11s
CI Pipeline / gitea-offline (push) Canceled after 11s
CI Pipeline / rust-surface (push) Canceled after 20s
The system caught its own author: (1) adding the dichotomy henxel made the AGENTS.md digest stale (henxels sync + commit); (2) the ratchet-bites test referenced bare 'ruff' with no resolver — NameError on CI where ruff lives only in .ci-venv. Shared _resolve_ruff() helper (interpreter env first, PATH fallback, FileNotFoundError with install hint). 5/5 contract tests.
88 lines
5.3 KiB
Markdown
88 lines
5.3 KiB
Markdown
<!-- henxels:begin -->
|
|
|
|
## The contract (henxels)
|
|
|
|
_Auto-generated from `henxels.yaml` by `henxels sync`. Do not edit by hand._
|
|
|
|
Each bullet is a **henxel** (a rule). To disobey one, change `henxels.yaml` —
|
|
that is the only sanctioned escape. Run `henxels explain <path>` before creating
|
|
a file to see what governs that spot.
|
|
|
|
Only use `git commit --no-verify` in a genuine emergency: it bypasses the hooks that run this contract, the safety mechanism meant to protect the repository. Prefer `henxels bless <action>` or editing `henxels.yaml` — both keep the deviation visible.
|
|
|
|
### Rules
|
|
|
|
- Canaries live at the repo's canary slot and are registered in CI (in ./src/rune/**/canary_*.py)
|
|
- No secrets in tracked files
|
|
- Plans are markdown, one per build (in ./plans)
|
|
- Top-level docs are markdown or yaml references (in ./docs/*)
|
|
- The known giant stays visible — file-size debt is tracked, not silent (in ./src/rune/*)
|
|
- The umbrella impact map is complete and truthful — every module mapped, no phantom entries (in ./config/umbrellas.json)
|
|
- Umbrella canaries exist in the repo — the propagation gate cannot reference ghosts (in ./config/umbrellas.json)
|
|
- The umbrella dependency graph stays a DAG — reflexive updates cannot cycle (in ./config/umbrellas.json)
|
|
- The bug-fix discharge contract is a governed doc — it exists, is markdown, and changes are deliberate (in ./docs/bugfix-contract.md)
|
|
- The discharge checker ships with the repo — red-first enforcement is structural (in ./scripts)
|
|
- Discharge checker and its CI wiring change together
|
|
- Every workflow is registered in the pipeline registry — new pipeline machinery ships with documentation (in ./.gitea/workflows/*.yml)
|
|
- Every TUI surface is registered — no silent UI growth (in ./src/rune/*tui*.py)
|
|
- New rune modules ship with tests or a canary — no ungoverned code surfaces (in ./src/rune/*.py)
|
|
- Rust crate files stay under a line budget (in ./src/rust/*/src/*.rs)
|
|
- Go modules stay under a line budget (in ./src/go/**/*.go)
|
|
- No secrets in Rust or Go source files (in ./src/rust/*/src/*.rs, ./src/go/**/*.go)
|
|
- PRDs are living documents — their generated state sections regenerate identically from governed sources
|
|
- PRD staleness is a CI failure — docs rot is silent failure (in ./scripts/gen_prd_state.py)
|
|
- The adversarial review procedure is binding — dispatch templates must reference it (in ./docs/adversarial-review.md)
|
|
- The fixture pipeline ships with the repo — production failure capture is structural (in ./scripts)
|
|
- Production failure fixtures are a governed surface — the registry and its README exist (in ./tests/fixtures/production)
|
|
- Fixture payloads and the manifest travel together — tamper-evidence needs both
|
|
- The fixture manifest and its generated regression tests travel together
|
|
- The dichotomy is enforced at the commit boundary — every src/rune module lands in its measured side, dead oracles and wrong-language kernels fail with the correct implementation as the instruction (in ./src/rune)
|
|
|
|
### Behaviours
|
|
|
|
- warns when a new file looks like a near-copy of a committed one
|
|
|
|
### Custom henxels & contributing
|
|
|
|
**Before writing a custom check, run `henxels catalogue` and use the built-in that
|
|
matches your intent — don't reinvent one.** Never name a custom check after a built-in
|
|
or a setting (e.g. `warn_about_large_files` is a setting, not a check).
|
|
|
|
Need a check that genuinely doesn't exist? `henxels create-new-statement <name>` scaffolds a local check
|
|
(auto-loaded from `henxels_checks.py`). **If your check is reusable** — useful in
|
|
other repos, not tied to this one — contribute it upstream with `henxels contribute`.
|
|
We're in the agentic era: send a ready-to-merge PR instead of opening an issue.
|
|
<!-- henxels:end -->
|
|
|
|
## Bug fixes (binding)
|
|
|
|
Every bug found — by gates, CI, canaries, production, or humans — is fixed per
|
|
`docs/bugfix-contract.md`: red test FIRST (reproduces the cause), root-cause
|
|
fix, full pipeline re-entry (suite + ratchet + ruff + canaries + henxels;
|
|
gates for anything beyond a mechanical minor), regression tests frozen forever,
|
|
discharge recorded finding → test → commit. Symptom patches are rejected at
|
|
review. To escape: edit `henxels.yaml` or this file — visibly.
|
|
|
|
## Issue organisation standard (binding, 2026-09-19)
|
|
|
|
One open note per idea. Issues use the template spine (kind, subsystem,
|
|
version intent) with a plain-English heading that restates the subject —
|
|
no meta-labels. Before minting a standalone issue, check whether the work
|
|
belongs inside an existing parent:
|
|
|
|
- **Parked ideas under a blocked/future epic** are filed as checklist items
|
|
in the parent's "Absorbed children" section, NOT as standalone issues.
|
|
Absorption is reversible — re-mint standalone when the idea becomes live.
|
|
- **Live, dependency-tracked, or starting work** gets a standalone issue.
|
|
- **Closures state the reason as data**: `closed_because` in the spine
|
|
(completed / superseded-by-#N / absorbed-into-#N / wont-do / duplicate),
|
|
plus a standard closing comment (plain summary first).
|
|
- The reconciliation checker (`scripts/gitea_reconciliation_check.py`) must
|
|
stay green after any issue state change; the artifact is updated in the
|
|
same change that moves issues.
|
|
|
|
## Async continuation final flow proofs (R13/M9) — 2026-09-19
|
|
|
|
PR-flow live proof marker: harmless documentation addition exercising the
|
|
canonical single-continuation path on the PC-local forge. No code change.
|