| 1 — Module Decoupling | Service importing a concrete repo class instead of a protocol. Non-composition-root code importing from multiple unrelated packages. |
| 2 — All Code Must Be Tested | New public functions/classes with no corresponding test. Test files that mock the database instead of using in-memory SQLite. |
| 3 — Secrets via Env Vars | Hardcoded API keys, tokens, passwords, or credentials anywhere in source. URLs with embedded credentials. |
| 4 — Model Generality | Code that names a specific model (e.g., if model == "marcel") outside that model's own package. CLI commands that hardcode a model name instead of accepting it as an argument. |
| 5 — Interaction Mode Generality | Business logic inside CLI commands, agent tools, or HTTP handlers instead of in services. A service importing from cli/, agent/, tools/, or HTTP code. |
| 6 — Module Public API via Re-exports | New public symbols added to a package without updating __init__.py and __all__. Consumers importing from a submodule when a re-export exists. |
| 7 — Domain Models Are Pure Data | Domain dataclass with custom methods (beyond __post_init__). Domain model importing infrastructure (repos, HTTP clients). Non-frozen dataclass in domain/. |
| 8 — Unidirectional Layer Dependencies | Lower layer importing a higher layer (e.g., repo importing a service, domain importing a repo). |
| 9 — Raw Parameterized SQL | String interpolation of values into SQL (f-strings with user data). Missing ? placeholders. |
| 10 — Result Types for Recoverable Errors | Raising exceptions for expected, recoverable failures instead of returning Result[T, E]. Bare except clauses that swallow errors. |
| 11 — Simple Functional Interfaces | Protocol with many methods when a Callable or single-method protocol would suffice. New multi-method protocol where the methods aren't cohesive. |