Engineering Policy (Beta)

The key words MUST, MUST NOT, SHOULD, and MAY are used as in RFC 2119. These are the working rules for all Beta implementation work; they exist so the Alpha cleanup cost (#215's 50-item audit) doesn't repeat.

Class hierarchies: behavior in bases, leaves earn their existence

Shared behavior MUST live in a base class with a clear interface — Enemy owns AI dispatch, status handling, damage intake; WolfEnemy / SmallEnemy-style subclasses exist only where behavior genuinely diverges (a different FSM, a different movement model). This applies to enemies, player classes, weapons, and shops alike.

Tech debt: blocked by default, loud when deliberate

The CI ratchet (code_graph.py --check) fails any PR introducing new duplication, dead code, complexity, or coupling. Accepting debt by growing a baseline is possible but MUST be acknowledged: the baseline-debt guard fails any PR that increases an accepted-debt count unless a commit carries a Debt-Accepted: <reason> trailer.

Testing: two layers for anything that moves

Every gameplay mechanic — and especially attacks, timing windows, and frame-dependent behavior — MUST ship with both layers:

LayerWhatCatches
UnitSeeded test in test_runner.gd pinning the math / window classification / state transition (the test_element_status / test_player_states pattern)formula and logic regressions, deterministically
Post-buildAn autopilot probe — a matrix phase, smoke script, or sanity checkpoint that exercises the mechanic in the running gameintegration breakage units can't see (the #335 lesson: the unit suite was green while the autopilot hung)

A combat increment whose plan has only one layer is not done being planned. The unit layer is the merge gate in CI; the post-build layer runs in the sanity check (every merge) and the full matrix (every combat-behavior PR).

Enforced by