DOCEXESIV.DEVREV2026.07
← RETURN // FIELD NOTES

The .architecture system

Ref
FLD-46BD69
Published
2026-04-26
Kind
DEVLOG
Project
Sidebar Agent
Author
Roman Sanine

An agent that wakes up cold each session has no memory of the project except what's in the repo. If the repo is just code, the agent re-derives intent from scratch every time — and gets it wrong, because intent isn't always recoverable from a diff. The .architecture/ directory is the workaround. It's the thing that makes session 2 competent.

The premise is one sentence: architecture is the source of truth, code reflects it. A bug isn't fixed by writing the patch — it's fixed by updating its yaml record with a fix_approach, then writing code that implements that approach. The patch is the consequence.

The shape

.architecture/
  _config.yaml          # topology: layers, domains, conflict detection
  _cycle-state.yaml     # current TDD phase per active feature
  constitution.md       # MUST / SHOULD principles
  inbox/                # raw user reports, pre-triage
  bugs/                 # BUG-NNN.yaml records
  bugs/archived/        # closed bugs, kept for reoccurrence detection
  <layer>/<domain>/     # feature folders, one per active design decision
  history.jsonl         # append-only log of state transitions

_config.yaml declares the topology — layers (frontend, backend, integration, infrastructure), domains, the TDD cycle (red → green → refactor → runtime), and gates between feature states.

# _config.yaml (excerpt from decent-td)
topology_type: hybrid
primary_axis: layer
secondary_axis: domain
workflow:
  tdd_cycle: [red, green, refactor, runtime]
  gates:
    feature_to_active: ['requirements_defined']
    active_to_in_progress: ['design_approved', 'tests_planned']
    in_progress_to_completed: ['all_tests_passing', 'acceptance_criteria_met']

The gates are enforced — a feature can't go in_progress → completed without all_tests_passing. Skipping that step requires marking it explicitly, which is auditable.

Two paths for new work

Trivial bugs go through hotfix. ≤2 files, ≤50 lines, single layer. The bug stays as a yaml record in .architecture/bugs/. The fix is direct, verification is fast.

# bugs/BUG-018-tower-turret-vertical-centering.yaml
id: BUG-018
title: Tower turret vertically miscentered on slope cells
status: fixed
severity: low
layer: frontend
component: game/Tower.vue
reproduction:
  - place tower on a sloped grid cell
  - observe turret model is offset ~0.3u above the base
fix_approach: |
  Tower placement was using cell.center.y; should use
  cell.surface.y (which accounts for slope normal).
  One-line fix in Tower.vue:42.
verified_in: production

Complex bugs and features expand into feature folders with standard artifact names — REQ.yaml, DES.yaml, TODO.yaml, TEST.yaml. The names are not negotiable: an agent looking for "the requirements" should always look at REQ.yaml, never have to guess at auth-rewrite-spec.yaml vs auth_requirements.md.

.architecture/backend/multiplayer/lobby-sync/
  REQ.yaml      # what we're solving and for whom
  DES.yaml      # how we'll solve it (chosen approach + alternatives rejected)
  TODO.yaml     # ordered work items, each linked to a test
  TEST.yaml     # acceptance + unit + integration tests, with current status

Escalation criteria are concrete: cross-layer changes, architectural implications, anything needing a real design decision. A race condition that touches the websocket plugin and three components is not a hotfix.

Why the constitution exists

constitution.md is short, project-specific, and re-read at the start of any non-trivial task. For Decent TD:

### MUST (Critical - violations block implementation)
1. Server-Authoritative — game state lives server-side
2. Stateless Backend — server can restart without losing state
3. Real-time First — game interactions use WebSocket, not REST polling
4. Security by Default — endpoints require auth except public pages

Constitutions get violated by accident, not on purpose. A coding agent will reach for REST polling for "simplicity" if nothing tells it that's banned. The constitution is the thing that says.

The MUST/SHOULD split matters: SHOULD violations are allowed with a written justification logged in the feature's DES.yaml. MUST violations block implementation outright.

The bug ledger as memory

Closed bugs don't get deleted — they archive. When a new report comes in, triage matches against past bugs by error code, message, stack trace, or component location.

For example, BUG-011 was filed as "missing combat audio" — fixed, verified, archived. Two weeks later, a similar report came in. The matcher caught it: same component, similar symptom. Reopened with a reoccurrence_count: 2 flag. The investigation found the original fix had introduced an excessive debounce (BUG-013), which was the actual root cause. Without the reoccurrence link, BUG-013 would have been filed as a new bug and we'd have re-debugged the audio pipeline from scratch.

A bug that reoccurs twice is no longer a bug — it's a design problem masquerading as one. The ledger surfaces that.

Status discipline

The rule that costs agents the most: don't mark status: fixed until verified in production. Use status: deployed if you can't verify yet. The temptation to write the patch, run the tests, mark it fixed, and move on is constant — and a year of "fixed" bugs that quietly regressed is how a codebase rots.

For the website project, "verified in production" means the devtools-proxy loop: navigate to the affected route, console clean, screenshot matches intent. For Decent TD, it means a real game session reproduces the original report and the fix path doesn't trigger.

Resumable mid-feature work

_cycle-state.yaml is the file that makes session 2 work:

# _cycle-state.yaml
active_features:
  - path: backend/multiplayer/lobby-sync
    phase: green                     # red | green | refactor | runtime
    last_test: TEST.yaml#unit-007
    blockers: []
  - path: frontend/game-ui/wave-banner
    phase: refactor
    last_test: TEST.yaml#integration-003
    blockers: ['waiting on visual review']

A new session reads this, sees lobby-sync is mid-green, opens TODO.yaml, finds the next unchecked item, continues. No "what was I working on" reconstruction from chat history.

What this enables

A few patterns fall out:

  • Multi-agent parallelism. Two agents working on different feature folders can't conflict if the topology config marks them in non-overlapping layers/domains. Conflict detection runs by proximity in the layer × domain space.
  • Auditable history. history.jsonl is append-only — every state transition (filed → triaged → in-progress → fixed → reopened) leaves a trace. "Why did we change this?" has an answer.
  • Triage is mechanical. New report → check against archived bugs → either reopen-with-reoccurrence or file new → match against severity rules → set initial gate. The agent doing triage is doing a checklist, not a judgment call.

The trade-off

The system has a real cost: a non-trivial slice of every task is yaml editing. For a single human writing code in flow, that overhead is irritating. For an agent that wakes up cold each session, that overhead is the memory. The yaml is what makes the agent competent on session 2, session 7, session 30.

The bet is that per-task overhead is repaid by every session that doesn't have to start from scratch. Three months in, that bet has held — and the bug reoccurrence detection alone has paid for the rest.

Sign in to react
Comments
No comments yet.
Comments are reviewed before appearing.
EXESIV.DEV — EXESIV lab builds agentic systems and components for the self-running business — autonomous, policy-driven operations, logged in the open across four sections: Almanac, Works, Field Notes, Seeds.