Spaces:
Running
Running
| # AGENTS.md β Tabras | |
| Engineering conventions for any agent or contributor working in this repo. Read alongside `README.md` (the design spec). README says *what* to build; this says *how* to write it. | |
| ## Non-negotiables | |
| ### Tests accompany all code | |
| - No code lands without tests. A feature and its tests are one unit of work, written together β not "tests later." | |
| - The deterministic core (`primitives.py`, `budget.py`, `game.py`) is pure logic with no model calls β it is fully testable and MUST be fully tested. This is where bugs hide and where balance lives. | |
| - Model-dependent code (`generator.py`, `boss.py`) is tested by mocking the model: assert the tool-call schema, the deck-context wiring, and that engine numbers (not model output) set magnitudes. Never test against live model output. | |
| ### Coverage is the bloat metric | |
| - Track code coverage on every change. Treat uncovered lines as **bloat**: if coverage is 50%, half the code is untested weight that should either be tested or deleted. | |
| - Target high coverage on the deterministic core specifically β it's pure and has no excuse to be uncovered. | |
| - Coverage is a deletion signal, not just a test signal: uncovered code is a prompt to ask "is this needed at all?" | |
| ### Functions do one thing | |
| - One function, one responsibility. If a function does two things, it's two functions. | |
| - As simple as possible, complex only where the problem genuinely requires it. Reach for complexity reluctantly and only when the domain demands it. | |
| - A function you can't describe in one line (see comments) is doing too much β split it. | |
| ### Terse, readable code | |
| - Terseness in service of readability, never against it. Shorter is better *only* when it reads more clearly. | |
| - No cleverness that costs a reader a second look. Obvious beats impressive. | |
| - Delete aggressively. The best code is no code; the second best is code that's plainly necessary. | |
| ### Comments: one line, at the function line | |
| - One-line comment at the function definition stating what it does. That's the default. | |
| - No block comments narrating internals, no inline play-by-play. If the body needs explaining, the function is too complex β simplify it instead of annotating it. | |
| - Comments state *what/why* at the boundary, never *how* line-by-line (the code is the how). | |
| ## In practice | |
| - The one-line function comment and the "describe in one line" rule are the same rule: if you can't write the comment, the function isn't doing one thing. | |
| - Coverage + terseness + one-thing functions reinforce each other: small single-purpose functions are trivial to test, which drives coverage, which exposes bloat to delete. | |
| - When in doubt: smaller function, clearer name, a test, delete the rest. | |
| ## What this looks like | |
| ```python | |
| # Convert a card's energy cost into its point budget. | |
| def budget_for(cost: int) -> int: | |
| return cost | |
| ``` | |
| Single purpose, one-line comment at the definition, terse, testable. A companion test asserts the mapping. No internal commentary. | |
| ## Order of work (per the README build order) | |
| Each step ships with its tests before the next begins: | |
| `primitives.py` β `budget.py` β `generator.py` + `game.py` β **playtest** β `boss.py` β `draft.py` β art β fine-tune. | |
| Do not move to the next file until the current one is tested and covered. | |