Orchestrata Ultimate › Gates › generated-artifacts
Gate: generated-artifacts
At a glance
| Purpose | Refuse a registered generated artifact that git ignores or does not track, and a generator that vanished while files still name it. |
| Where it runs | The scripts/gates.py battery (registered as generated-artifacts, input root !always, never cached); scripts/health_check.py. |
| Trigger | Every battery run (it is never reused from the cache); a health check. |
| Exact command | python scripts/check_generated_artifacts.py |
| Blocks | Exit 1 on violations, 2 when the gate could not do its job, 0 pass. Non-waivable. |
| Ruling / ADR | RUL-030 (gate scripts/check_generated_artifacts.py RUL-030). |
| Last recorded verdict | ok: true in the primary checkout's .cache/gates.json (file last written 2026-09-22 10:01 local). wt-MAP-PRECOMMIT has no .cache/gates.json. |
What it refuses
A registered generated artifact that git ignores or does not track — and, in the other direction, a generator that has vanished while files still claim it produced them.
Why it exists
Module docstring:
"Generated-artifacts gate — the mechanism for ruling RUL-030. User ruling, 2026-08-13: 'generated artifacts belong in git.'
The dispute this settles is concrete.
plans/ast-*.jsonandreports/run-tests-latest.jsonwere committed by some sessions … and deliberately withheld by others, so the working tree carried a permanent diff nobody could resolve, and a reader could not tell whether a missing snapshot meant 'not regenerated' or 'we don't keep those'. A generated artifact is a snapshot of project state at a commit; if it is not in the commit, the commit does not describe the project."
The other direction has its own recorded incident:
"On 2026-07-09, commit
6a186c9ddeletedscripts/ast_serializer/testgen/(9 files, 2,392 lines) with the rationale 'audited, zero consumers', because the audit equated no importer with no consumer. For a generator, the consumer is its OUTPUT, not its callers: ~100 files undertests/generated_recovery/still namedast_serializer.testgenin their headers, but that directory sits under--ignore=tests/generated_recoveryin pytest addopts, so nothing ever executed those files and nothing went red. The deletion was invisible… Self-fulfilling."
The boundary (what counts as an artifact)
The docstring's mechanical test — three properties, all required:
- Derived — "reproducible by running a named generator, never hand-authored."
- Read — "something consumes it: a gate, a doc @import, a report, a human."
- A function of the commit — "regenerating it at the same commit on another machine yields the same content. This is what excludes machine-local caches, per-run telemetry, wall-clock logs and locks."
Exclusions live in NOT_ARTIFACTS with a reason each, "so the exclusions are
visible and auditable rather than implicit in a .gitignore line nobody reads"
(e.g. reports/test-durations.ndjson — "282 MB of append-only per-run telemetry").
How it runs
- Command:
python scripts/check_generated_artifacts.py - When it fires: the
scripts/gates.pybattery (registered asgenerated-artifacts);scripts/health_check.py. - The checks:
- ignored —
git check-ignorematches a registered artifact ("the violation the ruling names"), reported with the offending.gitignoreline. - untracked — exists on disk, not tracked ("generated and never added"). A tracked-but-dirty artifact PASSES: "regeneration cadence is a workflow question, not this ruling."
- forward (
check_generators_exist) — every registry entry'sgeneratorpath must exist. - discovery (
check_generator_headers) — "the direction that would actually have caught 6a186c9d, because it does not trust the registry at all": every file undertests/,src/,docs/claiming machine generation in its header must name a producer that exists on disk — "a file's own header cannot be argued with."
- ignored —
- Inputs / caching: never cached (
!always). The registry comment: its subject is "three things a single content fingerprint cannot jointly cover: git's INDEX state…, git's FULL HISTORY (the LOSS-vs-NEVER-EXISTED check walksgit log --all, which can change when a new ref is fetched with no working-tree diff at all), and the CONTENT of every header under tests/src/docs… it must never serve a stale cached PASS for a generator that was deleted since the cache was written."
RUL-030 at commit time
The same ruling is why the codebase maps are regenerated at commit time. Commit
b5468cb1c (2026-10-22): "The maps are tracked (RUL-030) but only the SessionStart
hook rewrote them, so every new checkout showed them modified. The pre-commit hook
now runs the map generator when a commit stages Python and stages both maps; a
failure warns and never blocks." scripts/hooks/pre-commit's _refresh_maps
carries the same comment ("docs/CODEBASE_MAP.md and docs/CODEBASE_MAP_FULL.md
are tracked artifacts (RUL-030)"). That step is not this gate and never blocks a
commit; this gate is what would refuse the maps being ignored or untracked.
Typical failures and how to fix them
- Exit codes: "0 pass · 1 violations found · 2 the gate could not do its job."
- No escape hatch, by declaration: "This check is deliberately NON-WAIVABLE.
It does not import
core/gate_waivers.pyand must never be made to… A missing generator is … a fact about the filesystem and git history, and a loss-detector a line comment can silence is exactly the mechanism that let 6a186c9d go unnoticed for a month. There is likewise no--warn-only/--severity/env-var downgrade path." - It proves it looked: "an empty registry, or a registry whose entries all
resolve to nothing on disk, is a FAILURE, not a clean run — and every run prints
the number of artifacts examined alongside the verdict." Where a violation touches
a graded requirement it also names the
REQ-*id, read fromdocs/rtm.json. - Un-blocking:
git addthe artifact (and remove the ignore rule), restore or re-register the generator, or — for a genuine retirement — retire the artifacts and their headers in the same change.
Wiring
- Invokers:
scripts/gates.py(battery),scripts/health_check.py. - Tests:
tests/scripts/test_check_generated_artifacts.py(which theGATESregistry's own comments note unpacks the registry's exact 2-tuple shape — one reason the registry keeps that shape).
Related
- Gates master index
- Development workflow — where the pre-commit map regeneration sits
- RUL-030 — Generated artifacts belong in git
- feature-loss — the spec/requirement half of the same 2026 loss incidents; "the two gates cross-reference each other on purpose; neither replaces the other"
- worktree-envs — the other
!alwaysgate