---
name: cleveragents-contributing
description: |
  Project-specific contributing rules for the CleverAgents repository. Covers
  every rule, convention, command, and workflow that is particular to THIS project
  and supplements or overrides the generic cleverthis-guidelines skill.
references:
  - testing
  - ci-cd
  - toolchain
  - langchain-langgraph
  - file-organization
  - cli-workflow
---

# CleverAgents Contributing — Project-Specific Guidelines

## ⚠️  THIS SKILL OVERRIDES `cleverthis-guidelines`

This skill takes ABSOLUTE PRECEDENCE over the `cleverthis-guidelines` skill.
Whenever a rule, value, or procedure in this skill contradicts anything in
`cleverthis-guidelines`, the rule stated HERE is the one that applies. Apply
this skill's rules eagerly and without hesitation. Do not fall back to the
generic skill for anything covered here.

This skill does not repeat general rules that have no project-specific
variation. Consult `cleverthis-guidelines` for company-wide policy on
anything not covered here. For anything covered here — use only what is here.

## When to use this skill

Use this skill whenever you need to know: exactly which directories files
go in, exactly which nox sessions to run, which test framework to use
(Behave for unit, Robot Framework for integration), how the TDD bug fix tag
system works with its exact validation rules, what all CI jobs are and which
are required for merge, how to create a well-formed issue (Metadata, Subtasks,
Definition of Done, 11 quality criteria), how tickets are triaged and what
state they should be in, how commits must be structured and what the commit
message first line rule is, how PRs must be submitted and what the dependency
direction rule is, how to write code spec-first with argument validation,
how documentation traceability works (module path not line number), how
the v3 vs legacy CLI plan workflow differs and why they cannot be mixed,
how LangChain/LangGraph code should be structured and tested, what the
Python import rules are, what the exact backwards compatibility policy is
(none before v3.0.0), what the project's directory layout is, what branch
name to use, whether something should be an Issue vs Epic vs Legendary, or
any other project-specific question.

Some examples of things covered by this skill:

- Exact directory layout (src/cleveragents, features/, features/mocks/, robot/,
  docs/, config/, scripts/, examples/, k8s/, benchmarks/)
- Issue anatomy (Metadata section, Subtasks checklist, Definition of Done, 11
  quality criteria, label rules, Ref field, parent links)
- Ticket hierarchy (Issue vs Epic vs Legendary)
- Ticket lifecycle state machine (Unverified → Verified → In progress → In
  review → Completed)
- Triaging rules
- Branch naming (feature/mN-, bugfix/mN-, tdd/mN- with milestone number)
- Commit quality rules (atomic, bisect-friendly, prescribed first line from
  Metadata, interactive staging, squash/rebase hygiene)
- PR requirements (all 12 requirements, critical dependency direction: PR blocks
  issue not vice versa, one Epic per PR, milestone, Type/label, post-submission
  responsibilities)
- Code writing rules (spec-first, ADR for architectural changes, argument
  validation first in every public method, SOLID patterns)
- Documentation traceability (no line numbers, module.class.method + commit hash,
  same-commit requirement, single canonical surface, ADR process)
- Behave BDD unit testing with exact step-file naming rules and Gherkin quality
- Robot Framework integration testing (real services, no mocks), full TDD bug
  fix workflow with three-tag system and AssertionError enforcement
- Multi-level testing mandate (unit + integration + benchmarks for every task)
- All nox sessions (unit_tests, integration_tests, e2e_tests, coverage_report,
  lint, typecheck, security_scan, dead_code, complexity, benchmark,
  benchmark_regression, docs, build, format)
- 97% coverage as hard merge gate (measured by Slipcover via nox -s
  coverage_report)
- Pyright strict type checking (no # type: ignore ever)
- Python import rules (top of file, if TYPE_CHECKING: exception)
- Mock placement (features/mocks/ only)
- All 13 CI/CD jobs and 3 workflow files with triggers, 5 required-for-merge
  checks
- LangChain/LangGraph patterns (TypedDict state, MemorySaver, BaseLanguageModel,
  FakeListLLM, RxPY streams)
- Plan lifecycle migration (agents plan use vs agents tell, ULID format, separate
  storage backends, no migration path)
- Backwards compatibility policy (none pre-v3.0.0)
- docs/specification.md as authoritative source
- Hatch + pyproject.toml toolchain
- Pre-commit hooks via scripts/setup-dev.sh.

## ⚡ Quick Command Reference

```bash
# ── Full quality gate (run before every commit and PR) ──────────────────────
nox                             # all default sessions — must be fully green

# ── Per-concern sessions ─────────────────────────────────────────────────────
nox -s lint                     # ruff linting + format check
nox -s format                   # auto-format with ruff (modifies files)
nox -s format -- --check        # format check only — no changes (CI mode)
nox -s typecheck                # Pyright strict (ZERO suppressions tolerated)
nox -s security_scan            # bandit + semgrep + vulture
nox -s dead_code                # vulture dead-code detection
nox -s complexity               # Radon complexity analysis (nightly sweep)

# ── Test sessions ────────────────────────────────────────────────────────────
nox -s unit_tests               # Behave BDD tests (features/)
nox -s integration_tests        # Robot Framework via pabot (robot/) — real services
nox -s e2e_tests                # Robot Framework with REAL LLM API keys
nox -s coverage_report          # Slipcover — MUST be ≥ 97% (hard merge gate)
nox -s benchmark                # Airspeed Velocity (ASV) benchmarks
nox -s benchmark_regression     # ASV regression check (PRs only)

# ── Build / docs sessions ────────────────────────────────────────────────────
nox -s docs                     # MkDocs documentation build
nox -s build                    # wheel distribution build

# ── Dev environment setup ────────────────────────────────────────────────────
scripts/setup-dev.sh            # install pre-commit hooks — run once after cloning
hatch env create                # create the Hatch project environment

# ── Commit helper ────────────────────────────────────────────────────────────
git cz                          # Commitizen guided commit (replaces git commit)

# ── CLI workflow (v3 — always use this, never legacy) ────────────────────────
agents plan use local/<action> <project>   # create a v3 plan → returns ULID
agents plan execute <ULID>                 # execute the plan
agents plan apply <ULID>                   # apply the changes
```

**NEVER invoke Behave, Robot Framework, Pyright, ruff, or any other tool
directly.** Always go through nox. If a session is missing, add it to
`noxfile.py` BEFORE running.

---

## 🔴 Override Highlights

The rules below differ from or are more specific than `cleverthis-guidelines`.
They apply immediately and without negotiation:

| Topic | cleverthis-guidelines says | This project says |
|---|---|---|
| Unit test framework | Any BDD framework | **Behave only** (no pytest, no xUnit) |
| Unit test directory | Designated unit test dir | **`features/`** exclusively |
| Mock location | Designated mock subdirectory | **`features/mocks/`** exclusively |
| Integration test dir | Designated integration dir | **`robot/`** exclusively |
| Task runner | Any task runner (nox as example) | **`nox` only** |
| Type checker | Any static type checker | **Pyright only** (`nox -s typecheck`) |
| Inline type suppression | Never suppress | Never — **`# type: ignore` is prohibited** |
| Linter / formatter | Any linter | **ruff** (`nox -s lint`, `nox -s format`) |
| Coverage threshold | ≥ 97% | **≥ 97%** — Slipcover via `nox -s coverage_report`, **hard merge gate** |
| Source directory | `src/<package>/` | **`src/cleveragents/`** |
| Import style | Language-idiomatic | **Python: all at top, `from X import Y`, `if TYPE_CHECKING:` only exception** |
| Project manifest | Language manifest | **`pyproject.toml`** — all config lives here |
| Pre-commit setup | `pre-commit install` | **`scripts/setup-dev.sh`** |
| Project manager | Language env tool | **Hatch** (`hatch env create`) |
| Benchmarks | Language benchmark tool | **ASV** (`nox -s benchmark`) |
| Backwards compat | Check project policy | **NONE before v3.0.0; begins at v3.0.0** |
| PR approvals | 1 (self-approval OK) | Same — **1 minimum, self-approval permitted** |
| Commit first line | Conventional Changelog format | **Verbatim from issue Metadata section when prescribed** |
| PR dep direction | PR blocks issue | Same — **critical: PR→blocks→issue, NEVER reversed** |

---

## 🧭 Master Decision Tree

```
What am I doing?
│
├─ Creating or updating an issue / ticket
│   ├─ New issue → "Am I creating an issue?" tree
│   ├─ Choosing Issue vs Epic vs Legendary → "Should this be an Issue, Epic, or Legendary?" tree
│   ├─ Checking issue quality → "Is this ticket well-scoped?" tree
│   ├─ Moving ticket state → "What state should this ticket be in?" tree
│   └─ Triaging unverified tickets → "Am I triaging a ticket?" tree
│
├─ Choosing a branch name
│   └─ → "What branch name should I use?" tree
│
├─ About to start writing code
│   └─ → "Am I about to write code?" tree
│
├─ About to make a commit
│   └─ → "Am I about to commit?" tree
│
├─ Submitting a Pull Request
│   └─ → "Am I submitting a PR?" tree
│
├─ Reviewing someone else's PR
│   └─ → "Am I reviewing a PR?" tree
│
├─ Writing or placing a file
│   └─ → "Which directory does this file go in?" tree
│
├─ Writing tests
│   ├─ Unit-level behavior → Behave (.feature + steps) in features/
│   ├─ Integration test → Robot Framework in robot/ (real services)
│   ├─ End-to-end → Robot Framework in robot/ (real LLM keys required)
│   └─ → "Am I writing tests?" tree
│
├─ Fixing a bug
│   └─ → "Am I fixing a bug? (TDD workflow)" tree
│
├─ Writing a TDD issue-capture test
│   └─ → "Am I writing a TDD issue-capture test?" tree
│
├─ Running quality checks
│   └─ → "Which nox session do I run?" tree
│
├─ Looking at a CI failure
│   └─ → "Am I looking at a CI failure?" tree
│
├─ Writing or updating documentation
│   └─ → "Am I documenting something?" tree
│
├─ Working with the plan CLI
│   └─ → "Am I using the plan CLI?" tree
│
├─ Writing LangChain / LangGraph code
│   └─ → "Am I writing LangChain/LangGraph code?" tree
│
├─ Writing Python imports
│   └─ → "Am I writing Python imports?" tree
│
├─ Handling errors or exceptions in code
│   └─ → "Am I writing error handling?" tree
│
├─ Setting up the development environment
│   └─ → "Am I setting up my development environment?" tree
│
├─ Releasing a new version
│   └─ → "Am I releasing a new version?" tree
│
├─ Checking if all work is complete
│   └─ → "Is my work done?" tree
│
├─ Choosing a design pattern
│   └─ → "What design pattern should I use?" tree
│
└─ Anything not listed above
    └─ → Consult cleverthis-guidelines (general rules apply)
```

---

## 🔄 Project-Specific Decision Trees

### "Should this be an Issue, Epic, or Legendary?"

```
Ticket hierarchy decision — pick the RIGHT level before creating:
│
├─ CAN IT BE DONE IN ONE COMMIT BY ONE DEVELOPER?
│   ├─ YES AND it addresses exactly one concern → ISSUE (atomic work unit)
│   │   ├─ Maps to exactly 1 commit
│   │   ├─ One developer owns it completely
│   │   ├─ Has its own Metadata, Subtasks, and Definition of Done sections
│   │   └─ Must belong to at least one parent Epic
│   └─ NO → not an Issue — continue below
│
├─ DOES IT GROUP MULTIPLE ISSUES INTO A DEMONSTRABLE CAPABILITY?
│   ├─ YES → EPIC (capability unit)
│   │   ├─ Contains at least 2 child issues
│   │   ├─ When complete, you can SHOW something working to a stakeholder
│   │   ├─ Has own acceptance criteria beyond "all children closed"
│   │   ├─ Typically aligns with a single milestone
│   │   ├─ Must belong to at least one parent Legendary
│   │   └─ Closed ONLY when all children closed AND own criteria met
│   └─ NO → not an Epic — continue below
│
├─ IS IT A MAJOR STRATEGIC PILLAR spanning multiple milestones?
│   ├─ YES → LEGENDARY (strategic pillar)
│   │   ├─ Contains at least 2 child Epics
│   │   ├─ Spans multiple milestones (single-milestone scope = probably an Epic)
│   │   ├─ Has an articulated end state (what "this is fully realized" means)
│   │   ├─ Progress measured by Epic completion, not issue counts
│   │   └─ No parent — Legendaries are root nodes
│   └─ NO → reconsider; decompose further or absorb into existing hierarchy
│
├─ PROMOTION AND DEMOTION RULES
│   ├─ Issue grows → needs multiple commits → PROMOTE to Epic, break into issues
│   ├─ Epic → only 1 issue needed → DEMOTE; absorb issue into another Epic
│   └─ Legendary → only 1 child Epic → DEMOTE; absorb into another Legendary
│
└─ QUICK SELF-TEST
    ├─ "Can I describe it in one commit message?" → Issue
    ├─ "Can I demo it working when done?" → Epic
    ├─ "Is it a major dimension of project success?" → Legendary
    └─ "Does it need 'and' between unrelated actions?" → split into two
```

### "Is this ticket well-scoped?"

```
11 quality criteria — ALL must pass before an issue is considered ready:
│
├─ 1. ATOMICITY
│   ├─ Smallest meaningful unit of work that produces ONE verifiable change
│   └─ If describing it requires "and" between unrelated actions → split
│
├─ 2. SINGLE COMMIT
│   ├─ Maps to exactly ONE commit
│   └─ One issue = one commit (no multi-commit issues)
│
├─ 3. SINGLE RESPONSIBILITY
│   ├─ Addresses exactly one concern: one bug fix, one function, one doc update
│   └─ Mixed concerns → separate issues
│
├─ 4. ASSIGNABILITY
│   ├─ One developer can own and execute it completely
│   └─ No synchronization with other in-flight work required
│
├─ 5. VERIFIABILITY
│   ├─ Has a clear binary verification criterion
│   └─ Any reviewer can independently verify pass/fail
│
├─ 6. SELF-CONTAINMENT
│   ├─ All context present in the issue description + parent Epic
│   └─ Developer can begin without seeking clarification
│
├─ 7. IMPLEMENTATION INDEPENDENCE
│   ├─ Can ideally be implemented without blocking on other open issues
│   └─ If ordering dependencies exist → explicitly documented via Forgejo linking
│
├─ 8. SUBTASK DECOMPOSITION
│   ├─ Has a ## Subtasks checkbox list (unless trivially obvious single step)
│   └─ Subtasks are documentation within the issue body, NOT child tickets
│
├─ 9. LEAF NODE
│   ├─ Has NO child tickets
│   └─ If decomposition needed → promote to Epic, break into issues
│
├─ 10. MANDATORY PARENT
│   ├─ Linked to at least one parent Epic (no orphan issues)
│   └─ An issue may have more than one parent Epic when it genuinely serves both
│
└─ 11. FINITE COMPLETION
    ├─ Done when one commit is merged and criteria pass
    ├─ No ongoing or recurring obligation
    └─ Cannot be reopened — create a NEW issue for follow-up work
```

### "What ticket state should this be in?"

```
Ticket lifecycle state machine — every transition has a rule:
│
├─ State/Unverified  (ALL new issues start here — no exceptions)
│   ├─ When: just created by anyone
│   ├─ Who can move it OUT: maintainer ONLY (not the author)
│   └─ Transitions:
│       ├─ → State/Verified    (maintainer accepts and validates it)
│       ├─ → State/Wont Do     (deliberate decision not to address; comment required)
│       └─ → Duplicate         (link to original before closing)
│
├─ State/Verified
│   ├─ When: maintainer has confirmed it is valid, actionable, not a duplicate
│   ├─ Required for: entering a sprint, getting assigned, point estimation
│   └─ Transitions:
│       ├─ → State/In progress  (contributor starts working; assign yourself)
│       └─ → State/Wont Do      (maintainer decision; comment required)
│
├─ State/In progress
│   ├─ When: someone is actively working on this issue
│   ├─ Who sets it: contributor starting the work
│   └─ Transitions:
│       ├─ → State/Paused        (blocked by dependency; add Blocked label + link)
│       └─ → State/In review     (PR submitted)
│
├─ State/Paused
│   ├─ When: blocked by another unresolved issue
│   ├─ Required: Blocked label MUST also be applied; blocking issue linked in comment
│   └─ Transitions:
│       ├─ → State/In progress   (blocker resolved; remove Blocked label)
│       └─ → State/Wont Do       (decision to drop it; comment required)
│
├─ State/In review
│   ├─ When: PR is submitted and awaiting review
│   ├─ Who sets it: contributor who submitted the PR
│   └─ Transitions:
│       ├─ → State/Completed     (PR merged, all criteria met; close ticket)
│       └─ → State/In progress   (reviewer requests significant changes; reopen)
│
├─ State/Completed
│   ├─ When: PR merged, all subtasks checked off, DoD met
│   └─ Close the ticket immediately — completed = done forever
│
└─ State/Wont Do
    ├─ When: deliberate decision not to address the issue
    ├─ REQUIRED: a comment explaining the reason
    └─ Can happen from ANY state; maintainer authority
```

### "Am I triaging a ticket?"

```
Triaging unverified tickets — maintainer responsibilities:
│
├─ WHO TRIAGES
│   ├─ Maintainers only — contributors do NOT move their own issues out of Unverified
│   └─ Triage happens: at sprint planning, during sprint review, or on demand
│
├─ TRIAGE DECISION PROCESS
│   │
│   ├─ STEP 1: Read the issue fully — is it valid and actionable?
│   │
│   ├─ STEP 2: Is it a duplicate of an existing issue?
│   │   ├─ YES → mark Duplicate, add comment linking to original, close it
│   │   └─ NO → continue
│   │
│   ├─ STEP 3: Is it something the project will address?
│   │   ├─ NO → move to State/Wont Do, comment explaining why
│   │   └─ YES → continue
│   │
│   ├─ STEP 4: Is the issue complete enough to work on?
│   │   ├─ Missing context/repro steps → comment asking for more info; leave Unverified
│   │   └─ Complete → continue
│   │
│   ├─ STEP 5: Apply labels
│   │   ├─ Keep State/Unverified → State/Verified
│   │   ├─ Set/confirm Type/ label (Bug, Feature, Task, Testing, Epic, Legendary)
│   │   ├─ Set Priority/ label:
│   │   │   ├─ Bug → always Priority/Critical
│   │   │   ├─ High-impact blocking work → Priority/High
│   │   │   ├─ Normal work → Priority/Medium or Priority/Low
│   │   │   └─ Default if unsure → Priority/Backlog
│   │   └─ ⚠️ Do NOT set MoSCoW/ labels — that is the project owner's role
│   │
│   ├─ STEP 6: Assign a milestone
│   │   ├─ Non-Epic, non-Legendary issues in any state beyond Unverified → MANDATORY
│   │   └─ No appropriate milestone → discuss with project owner before proceeding
│   │
│   └─ STEP 7: Link to parent Epic (if applicable)
│       ├─ Open the issue → add parent under "blocks"
│       └─ OR open the parent → add child under "depends on"
│
├─ FOR BUG ISSUES (Type/Bug)
│   ├─ Priority is ALWAYS Priority/Critical — set it if it's missing
│   ├─ Check: does a companion TDD issue already exist?
│   │   ├─ NO → the bug reporter or triager must create the TDD issue immediately
│   │   └─ YES → verify the Forgejo dependency direction is correct
│   └─ The bug issue DEPENDS ON the TDD issue (TDD blocks the bug)
│
└─ FOR EPICS AND LEGENDARIES (Type/Epic, Type/Legendary)
    ├─ Epics/Legendaries are NEVER given a point estimate
    ├─ Epics/Legendaries do NOT get milestone assignments themselves
    │   (milestones are assigned to child issues; Epics inherit temporal presence)
    ├─ Closing an Epic requires: ALL children closed AND own acceptance criteria met
    │   → Signed-off:Owner + Signed-off:Scrum Master + Signed-off:Tech Lead required
    └─ Closing a Legendary: same sign-off process as Epic
```

### "What branch name should I use?"

```
Branch naming rules for this project (milestone number N is required):
│
├─ WHAT TYPE OF WORK IS THIS?
│   │
│   ├─ New feature or user story
│   │   └─ feature/mN-<descriptive-name>
│   │       e.g. feature/m3-tool-cli
│   │            feature/m5-plan-lifecycle-refactor
│   │
│   ├─ Bug fix (the implementation of the fix)
│   │   └─ bugfix/mN-<descriptive-name>
│   │       e.g. bugfix/m3-shacl-crash
│   │       ⚠️ The suffix MUST match the companion tdd/ branch name exactly
│   │
│   ├─ TDD issue-capture test (proves a bug exists — NOT the fix)
│   │   └─ tdd/mN-<descriptive-name>
│   │       e.g. tdd/m3-shacl-crash
│   │       ⚠️ The suffix MUST match the companion bugfix/ branch name exactly
│   │
│   ├─ Chore, refactor, infrastructure, or dependency update
│   │   └─ feature/mN-<descriptive-name>  (use feature/ prefix)
│   │       e.g. feature/m4-upgrade-langchain-deps
│   │
│   └─ Documentation-only change
│       └─ feature/mN-<descriptive-name>
│           e.g. feature/m2-update-spec-resource-model
│
├─ WHERE DOES THE MILESTONE NUMBER (N) COME FROM?
│   ├─ It is the milestone number assigned to the linked issue
│   ├─ e.g. if the issue is in milestone "v3.4.0" → N = 4 (use m4-)
│   └─ The branch MUST match the Branch field in the issue's ## Metadata section
│
├─ NAMING RULES
│   ├─ Use kebab-case (lowercase, hyphens, no spaces, no underscores)
│   ├─ Descriptive — reader should understand the scope from the name
│   ├─ Not too long — aim for 3–5 words after the prefix
│   └─ Must match the Branch field in the issue's ## Metadata section verbatim
│
├─ TRACEABILITY RULE (TDD + bugfix pairs)
│   ├─ Bug #123 on milestone m3 → tdd/m3-shacl-crash AND bugfix/m3-shacl-crash
│   ├─ Shared suffix enables: tracking which fix addresses which TDD test
│   └─ CI uses the suffix match to validate the workflow was followed correctly
│
└─ EXAMPLES
    ├─ tdd/m3-shacl-crash        ← TDD test for bug #123 in milestone m3
    ├─ bugfix/m3-shacl-crash     ← Fix for bug #123 in milestone m3
    ├─ feature/m4-acms-context   ← New context assembly feature in milestone m4
    └─ feature/m2-update-readme  ← Documentation update in milestone m2
```

### "Am I creating an issue?"

```
Issue creation — complete requirements:
│
├─ BEFORE CREATING: does a similar issue already exist?
│   ├─ YES → add context to the existing issue; do NOT create a duplicate
│   └─ NO → continue
│
├─ DECIDE THE TYPE FIRST (before writing anything)
│   └─ → "Should this be an Issue, Epic, or Legendary?" tree
│
├─ TITLE
│   ├─ Specific and descriptive — reader understands scope from title alone
│   ├─ e.g. "Fix null pointer when parsing empty configuration file"
│   ├─ e.g. "Add SHACL validation to resource registration"
│   └─ ⚠️ NEVER vague: not "Fix bug", "Improve performance", "Update tests"
│
├─ MANDATORY LABELS (set at creation)
│   ├─ State/Unverified ← ALL new issues start here, no exceptions
│   ├─ Type/ label ← exactly one (Bug, Feature, Task, Testing, Epic, Legendary)
│   └─ Priority/ label ← suggest Priority/Backlog if unsure; maintainer adjusts
│   ⚠️ DO NOT set MoSCoW/ labels — project owner ONLY sets these
│
├─ MILESTONE
│   ├─ At creation (State/Unverified): optional
│   └─ Once in any active state (Verified, In progress, etc.): MANDATORY
│       If no appropriate milestone exists → discuss with project owner first
│
├─ BRANCH/TAG REF FIELD (the "Ref" field on the issue form)
│   ├─ Development issues (feature, fix, chore, refactor):
│   │   → Must be set to the SAME branch named in the Metadata section
│   │   → Required once issue moves to State/In progress or later
│   │   → Must reference a BRANCH, never a tag
│   └─ Non-development issues (bug reports, questions, support):
│       → May be left blank, or set to the branch/tag where the issue occurs
│
├─ DESCRIPTION — MANDATORY SECTIONS (in this order)
│   │
│   ├─ ## Metadata  ← MUST be at the top
│   │   ├─ Commit Message: feat(scope): exact first line for the commit
│   │   │   e.g. feat(cli): add tool and validation commands
│   │   │   → This EXACT text is the commit message first line (verbatim)
│   │   │   → Must follow Conventional Changelog format
│   │   └─ Branch: feature/m3-tool-cli
│   │       → This EXACT branch name is used for all work on this issue
│   │
│   ├─ Background and context
│   │   → Why does this issue exist? What is the motivation?
│   │
│   ├─ Current behavior (for bugs: repro steps, error messages, logs)
│   │   → What is happening now that is incorrect or undesirable?
│   │
│   ├─ Expected behavior
│   │   → What should happen instead? What does "done" look like?
│   │
│   ├─ Acceptance criteria
│   │   → Testable list of conditions — each one BINARY (passes or fails)
│   │   → Any reviewer can independently verify each criterion
│   │   → GOOD: "The CLI exits 0 when a valid YAML config is provided"
│   │   → BAD:  "The code should handle YAML files correctly"
│   │
│   ├─ Supporting information
│   │   → Links to related issues, docs, screenshots, logs, external references
│   │
│   ├─ ## Subtasks  ← REQUIRED (except trivially obvious single-line changes)
│   │   ├─ Each subtask is a Markdown checkbox: - [ ] description
│   │   ├─ Break work into discrete, trackable steps
│   │   └─ Example:
│   │       - [ ] Implement input validation for configuration parser
│   │       - [ ] Add error messages for malformed YAML files
│   │       - [ ] Tests (Behave): Add scenarios for config parsing edge cases
│   │       - [ ] Tests (Robot): Add integration test for config loading
│   │       - [ ] Verify coverage >=97% via nox -s coverage_report
│   │       - [ ] Run nox (all default sessions), fix any errors
│   │
│   └─ ## Definition of Done  ← REQUIRED
│       └─ Example:
│           This issue is complete when:
│           - All subtasks above are completed and checked off.
│           - A Git commit is created where the first line matches the
│             Commit Message in Metadata exactly.
│           - The commit is pushed to the branch matching the Branch in
│             Metadata exactly.
│           - The commit is submitted as a PR to master, reviewed, and merged.
│
├─ 11 QUALITY CRITERIA (verify before submitting — see "Is this ticket well-scoped?")
│   ├─ Atomicity: one verifiable change
│   ├─ Single Commit: exactly one commit
│   ├─ Single Responsibility: one concern only
│   ├─ Assignability: one developer, no sync required
│   ├─ Verifiability: binary pass/fail criterion
│   ├─ Self-Containment: all context in the issue + parent Epic
│   ├─ Implementation Independence: no hidden ordering constraints
│   ├─ Subtask Decomposition: checkbox list present
│   ├─ Leaf Node: no child tickets
│   ├─ Mandatory Parent: linked to at least one Epic
│   └─ Finite Completion: done when commit merged, no reopening
│
├─ PARENT LINK (hierarchy)
│   ├─ If this is a child of an Epic or Legendary:
│   │   → Open the child issue → add parent under "blocks"
│   │   OR open the parent → add child under "depends on"
│   └─ ⚠️ NEVER reference parent tickets by number in the description body
│       The Forgejo dependency link is the ONLY mechanism
│
├─ BLOCKING LINKS
│   ├─ If this issue is blocked by another issue:
│   │   1. Add Blocked label
│   │   2. Comment: "Blocked by #57"
│   │   3. Add Forgejo dependency: blocking issue BLOCKS this issue
│   │   4. If no ticket exists for the blocker → create one first
│   │   5. Move to State/Paused
│   └─ When blocker resolves → remove Blocked label → return to State/In progress
│
├─ SPECIAL CASE: Bug issue (Type/Bug)
│   ├─ Priority is ALWAYS Priority/Critical — no exceptions
│   ├─ MoSCoW is ALWAYS MoSCoW/Must Have — project owner sets this
│   ├─ You MUST also immediately create a companion Type/Testing issue:
│   │   ├─ Title: "TDD: <exact description from the bug issue>"
│   │   ├─ Same Priority/Critical + MoSCoW/Must Have
│   │   └─ Set Forgejo dependency: Bug issue DEPENDS ON the TDD issue
│   └─ See "Am I fixing a bug? (TDD workflow)" for the full process
│
└─ AFTER CREATING
    ├─ The issue starts in State/Unverified — maintainer triages it
    └─ Contributors do NOT move their own issues out of State/Unverified
```

### "Am I about to write code?"

```
Before touching any production code:
│
├─ STEP 1: READ docs/specification.md FIRST (mandatory)
│   ├─ Find the sections relevant to your task
│   ├─ Read them completely — understand the intended design
│   ├─ If the spec and the current codebase disagree:
│   │   → The SPEC is correct. Align the code to the spec.
│   │   → NEVER adjust the spec to match broken code
│   └─ Architectural changes → ADR process required BEFORE writing any code
│       1. Write the ADR document (see "Am I documenting something?" for format)
│       2. Submit for review and approval via PR
│       3. Once approved → update docs/specification.md
│       4. THEN write the code
│
├─ STEP 2: Does a verified issue exist for this work?
│   ├─ NO → Create the issue first (see "Am I creating an issue?" tree)
│   └─ YES → Is it in State/Verified?
│       ├─ State/Unverified → wait for triage; do NOT start
│       └─ State/Verified → move to State/In progress and assign yourself
│
├─ STEP 3: Are you on the correct topic branch?
│   ├─ Branch name must match the Branch field in the issue Metadata section
│   ├─ Format: feature/mN-<name>, bugfix/mN-<name>, or tdd/mN-<name>
│   ├─ If the branch doesn't exist yet → create it from master
│   └─ → "What branch name should I use?" tree for details
│
├─ STEP 4: Do tests exist for the new behavior FIRST?
│   └─ Write tests BEFORE writing implementation — no exceptions
│       (See "Am I writing tests?" for the multi-level testing mandate)
│
├─ CODE STYLE REQUIREMENTS (apply while writing)
│   ├─ Files under 500 lines — break into focused modules if approaching limit
│   ├─ Every public/protected method validates ALL arguments first, before logic
│   │   (See "Am I writing error handling?" for the exact validation pattern)
│   ├─ Type annotations on every function signature, variable, and return type
│   ├─ Never hardcode secrets, tokens, API keys, or environment-specific values
│   ├─ Use SOLID principles throughout:
│   │   ├─ SRP: each class has ONE reason to change
│   │   ├─ OCP: open for extension, closed for modification
│   │   ├─ LSP: subtypes substitutable for their base types
│   │   ├─ ISP: small specific interfaces, not fat ones
│   │   └─ DIP: depend on abstractions, not concretions
│   ├─ Use design patterns over ad-hoc solutions
│   │   └─ → "What design pattern should I use?" tree for the full categorized list
│   └─ Use dependency injection — do not create dependencies internally
│
├─ WHAT IS PROHIBITED
│   ├─ ⚠️ No half-done work — only commit when fully implemented and tested
│   ├─ ⚠️ No debug statements in committed code
│   ├─ ⚠️ No # type: ignore comments anywhere
│   ├─ ⚠️ No hardcoded secrets or credentials
│   ├─ ⚠️ No production code in test directories (src/ is production only)
│   ├─ ⚠️ No test or mock code in src/cleveragents/
│   └─ ⚠️ No if testing: guards or test-only paths in production code
│
└─ BEFORE STOPPING FOR THE DAY (WIP management)
    ├─ Use feature branches and stashing for work in progress
    ├─ NEVER commit incomplete or untested code to shared history
    ├─ git stash → save work in progress safely
    └─ Draft commits on your OWN branch are OK — just don't push to master
```

### "Am I about to commit?"

```
Commit quality checklist — every single commit:
│
├─ IS THE WORK COMPLETE AND TESTED?
│   ├─ Feature or fix fully implemented?
│   ├─ All new behavior covered by tests?
│   ├─ nox → all sessions green? (run it now if not)
│   ├─ nox -s coverage_report → still ≥ 97%?
│   └─ ⚠️ If any of the above is NO → do NOT commit yet
│
├─ SELF-REVIEW THE DIFF (mandatory before every commit)
│   ├─ git add -p → use interactive staging to select ONLY intended changes
│   ├─ git diff --staged → review exactly what will be committed
│   ├─ Are there debug statements? Remove them.
│   ├─ Are there temporary comments? Remove them.
│   ├─ Are there unrelated changes? Unstage them — put them in a SEPARATE commit.
│   └─ Are there cosmetic changes mixed with functional changes?
│       → Separate them into distinct commits (cosmetic first, then functional)
│
├─ IS THIS COMMIT ATOMIC?
│   ├─ One logical change only — one bug fix OR one feature OR one refactor
│   ├─ If it requires "and" to describe → split it into two commits
│   ├─ Related edits across multiple files → OK in one commit
│   ├─ Unrelated edits that happen to touch the same file → split into separate commits
│   ├─ Code move/rename → one commit; modifications → next commit
│   └─ Never bundle formatting fixes with functional changes
│
├─ IS THE COMMIT COMPLETE?
│   ├─ Tests for this change included in this SAME commit?
│   ├─ Documentation updated for this change in this SAME commit?
│   ├─ Changelog updated in this same commit (one entry)?
│   ├─ Ancillary files updated (config, build scripts, etc.)?
│   └─ ⚠️ "I'll add tests later" is NEVER acceptable
│
├─ IS THE COMMIT INDEPENDENTLY BUILDABLE AND REVERTIBLE?
│   ├─ If someone checks out ONLY this commit: does the project build?
│   ├─ If someone checks out ONLY this commit: do all tests pass?
│   ├─ If this commit is reverted: does the codebase still make sense?
│   ├─ Does this commit secretly depend on a FUTURE commit to work?
│   │   → That is a bug in your commit strategy — fix it before committing
│   └─ Keep history bisect-friendly: every commit is a valid testable state
│
├─ COMMIT MESSAGE FIRST LINE (critical)
│   │
│   ├─ DOES THE ISSUE HAVE A Metadata section with a Commit Message field?
│   │   ├─ YES → Use that text EXACTLY as the first line — verbatim, copy-paste
│   │   │   → Do NOT paraphrase, reword, or reformat it
│   │   │   → e.g. feat(cli): add tool and validation commands
│   │   └─ NO → Write your own following Conventional Changelog format:
│   │       <type>(<scope>): <description in imperative mood>
│   │       Types: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert
│   │       50-72 characters max, no period at end
│   │
│   ├─ COMMIT BODY (free-form, after a blank line)
│   │   ├─ Explain WHAT was done and WHY (not HOW — the diff shows how)
│   │   ├─ What the diff does NOT explain (context, motivation, trade-offs)
│   │   ├─ Why this approach was chosen over alternatives
│   │   ├─ Any risks or caveats the next developer should know
│   │   └─ Footer: ISSUES CLOSED: #N  (or Refs: #N if not closing)
│   │   Example body: "Switched from synchronous to async processing because
│   │   the service timed out under load (issue #87). The sync path remains
│   │   as a fallback for CLI-only invocations where the event loop isn't
│   │   guaranteed to be running."
│   │
│   └─ USE COMMITIZEN (strongly recommended):
│       git cz  →  interactive guided message creation with validation
│
├─ PRE-COMMIT HOOKS (automatic when setup-dev.sh was run)
│   ├─ Hooks run automatically on git commit — they enforce quality locally
│   ├─ Format, lint, typecheck, security scan, commit message validation
│   ├─ If a hook fails → fix the issue; NEVER use --no-verify to bypass
│   └─ If hooks are not installed → run scripts/setup-dev.sh first
│
└─ COMMIT HYGIENE (before merging to master)
    ├─ Commit often during development — small commits are easier to handle
    ├─ Before opening a PR: clean up history with interactive rebase
    │   → git rebase -i HEAD~N  → squash fixup commits, fix typos
    │   → Goal: every commit in the PR is meaningful and clean
    │   → "wip: halfway there" should NOT appear in merged history
    ├─ Use topic branches — develop on a branch, never directly on master
    └─ Reference issues in every commit footer (ISSUES CLOSED: #N)
```

### "Am I submitting a Pull Request?"

```
Pull Request requirements — ALL must be satisfied before review:
│
├─ PRE-SUBMISSION CHECKLIST (12 items — PR will not be reviewed until all pass)
│   │
│   ├─ 1. DETAILED DESCRIPTION
│   │   ├─ Summary of changes and the motivation behind them
│   │   ├─ Closing keyword for every linked issue: Closes #N or Fixes #N
│   │   │   (PR without issue reference will NOT be reviewed)
│   │   └─ Create an issue first if none exists — see "Am I creating an issue?"
│   │
│   ├─ 2. FORGEJO DEPENDENCY DIRECTION (CRITICAL — deadlock risk if wrong)
│   │   ├─ On the PR: add the linked issue under "blocks"
│   │   ├─ Result: on the issue, the PR appears under "depends on"
│   │   ├─ ⚠️ CORRECT:   PR → blocks → issue
│   │   ├─ ⚠️ WRONG:     issue → blocks → PR  ← UNRESOLVABLE DEADLOCK
│   │   │   If reversed, Forgejo prevents the PR from being merged until
│   │   │   the issue resolves, but the issue can't close until PR merges
│   │   └─ Verify: open the issue, confirm PR appears under "depends on"
│   │
│   ├─ 3. ONE EPIC SCOPE PER PR
│   │   ├─ Each PR is associated with exactly one Epic
│   │   └─ Changes spanning multiple Epics → split into separate PRs
│   │
│   ├─ 4. ATOMIC, WELL-SCOPED COMMITS
│   │   ├─ All commits follow commit quality rules (see "Am I about to commit?")
│   │   ├─ Each commit is small, self-contained, independently buildable
│   │   └─ History cleaned up before submission (no "wip" commits)
│   │
│   ├─ 5. COMMIT MESSAGES REFERENCE TICKETS
│   │   └─ Every commit footer includes ISSUES CLOSED: #N or Refs: #N
│   │
│   ├─ 6. CONVENTIONAL CHANGELOG FORMAT
│   │   └─ All commit messages follow type(scope): description format
│   │
│   ├─ 7. CHANGELOG UPDATED
│   │   └─ One new entry per commit, describing the change for users
│   │
│   ├─ 8. NO BUILD OR INSTALL ARTIFACTS
│   │   └─ No .egg-info, __pycache__, dist/, *.pyc in any commit
│   │
│   ├─ 9. CONTRIBUTORS.md UPDATED
│   │   └─ Add your name if not already listed (first contribution only)
│   │
│   ├─ 10. VERSION BUMP (when warranted — most PRs do NOT need one)
│   │   ├─ New functionality → bump MINOR in pyproject.toml
│   │   ├─ Bug fix in a released version → bump PATCH
│   │   ├─ Breaking API change → bump MAJOR
│   │   └─ Refactor / docs / tests / unreleased work → NO bump needed
│   │
│   ├─ 11. ALL CI CHECKS PASS
│   │   ├─ Run nox locally — full suite must be green before submitting
│   │   └─ PRs with failing CI will NOT be reviewed
│   │
│   └─ 12. MILESTONE AND TYPE LABEL
│       ├─ Assigned to the same milestone as the linked issue(s)
│       └─ Exactly one Type/ label: Type/Bug, Type/Feature, or Type/Task
│
├─ AFTER SUBMISSION
│   ├─ Move linked issue(s) to State/In review
│   ├─ Watch CI — if it fails AFTER submission, fix it immediately
│   │   → Push a new commit fixing the issue; do NOT force-push
│   │   → CI re-runs automatically on the new push
│   ├─ Respond to review comments constructively
│   ├─ If reviewer requests major changes:
│   │   → Make the changes in new commits (do NOT amend + force-push)
│   │   → Address EVERY comment, either by changing the code or explaining why not
│   │   → When all addressed, re-request review from the reviewer
│   └─ After merge → move linked issue(s) to State/Completed
│
└─ MERGE REQUIREMENTS (ALL conditions before merging)
    ├─ PR description includes closing keywords (Closes #N)
    ├─ Forgejo dependency direction correct: PR blocks issue
    ├─ All CI checks pass (lint, typecheck, security, unit_tests, coverage)
    ├─ Coverage ≥ 97%
    ├─ At least 1 approving review (formal APPROVED or LGTM/✅; self-approval OK)
    ├─ No open "Request Changes" or "Rejected" reviews
    ├─ All commits follow Conventional Changelog format
    ├─ Every commit references its issue
    ├─ Changelog updated
    ├─ CONTRIBUTORS.md updated (if applicable)
    ├─ Correct milestone assigned
    └─ Exactly one Type/ label applied
```

### "Am I reviewing a PR?"

```
Code review — what to assess and how to decide:
│
├─ ELIGIBILITY AND APPROVAL RULES
│   ├─ Anyone may review any PR
│   ├─ Minimum 1 approving review required before merge
│   ├─ Self-approval IS permitted (including bot PRs)
│   ├─ Valid approval = formal "APPROVED" status OR comment with LGTM/✅/Approved
│   └─ No open "Request Changes" reviews at merge time
│
├─ CI GATE (check this first — do not review if CI is red)
│   ├─ All required jobs must be green: lint, typecheck, security, unit_tests, coverage
│   ├─ status-check job provides consolidated summary
│   └─ If CI is failing → ask the author to fix it BEFORE you review
│
├─ WHAT TO EVALUATE (in order of importance)
│   │
│   ├─ CORRECTNESS
│   │   ├─ Does it do what the linked issue says it should do?
│   │   ├─ Do all acceptance criteria in the issue pass?
│   │   └─ Are there edge cases not covered that could cause production failures?
│   │
│   ├─ SPECIFICATION ALIGNMENT
│   │   ├─ Does it align with docs/specification.md?
│   │   └─ If code departs from spec → it is wrong; request correction
│   │
│   ├─ TEST QUALITY
│   │   ├─ Are there Behave BDD scenarios for all new behavior?
│   │   ├─ Are integration tests updated if component interfaces changed?
│   │   ├─ Are edge cases AND error/failure paths covered?
│   │   ├─ Does coverage stay ≥ 97%?
│   │   ├─ For bug fixes: does a @tdd_issue_N regression test exist?
│   │   └─ Are Gherkin scenarios well-named and readable as living documentation?
│   │
│   ├─ TYPE SAFETY
│   │   ├─ Are all function signatures, variables, and return types annotated?
│   │   └─ ⚠️ Zero tolerance for # type: ignore — reject any PR that adds one
│   │
│   ├─ READABILITY
│   │   ├─ Clear, descriptive names for classes, functions, variables?
│   │   ├─ No magic numbers or unexplained constants?
│   │   └─ Easy to follow logic without reading the whole file?
│   │
│   ├─ PERFORMANCE
│   │   ├─ Unnecessary inefficiencies or redundant operations?
│   │   ├─ N+1 query patterns in loops?
│   │   └─ Potential scalability concerns at production scale?
│   │
│   ├─ SECURITY
│   │   ├─ Any hardcoded secrets, tokens, or credentials?
│   │   ├─ SQL/command injection, path traversal, or unsafe patterns?
│   │   └─ All inputs from external sources validated?
│   │
│   ├─ CODE STYLE
│   │   ├─ SOLID principles followed?
│   │   ├─ Appropriate design patterns used?
│   │   ├─ Files under 500 lines?
│   │   └─ Follows ruff conventions (lint CI job enforces this)?
│   │
│   ├─ DOCUMENTATION
│   │   ├─ All public functions/classes have docstrings?
│   │   └─ Documentation updated alongside code in the same commit?
│   │
│   └─ COMMIT AND PR QUALITY
│       ├─ Each commit atomic and self-contained?
│       ├─ Commit first lines follow Conventional Changelog (or match Metadata)?
│       ├─ Each commit footer has ISSUES CLOSED: #N?
│       ├─ Changelog updated with one entry per commit?
│       ├─ No WIP commits in the history (clean rebase done)?
│       ├─ Dependency direction correct: PR blocks issue?
│       ├─ Correct milestone assigned?
│       └─ Exactly one Type/ label?
│
├─ HOW TO LEAVE REVIEW COMMENTS
│   ├─ BLOCKING comment (must be fixed before approval)
│   │   → "This silently drops the exception — it must propagate or be handled."
│   │   → Request Changes (not just a comment) so the author knows it's blocking
│   ├─ SUGGESTION (would improve but not blocking)
│   │   → "Suggestion: consider using a more descriptive variable name here."
│   │   → Mark as a suggestion or non-blocking in the comment
│   └─ QUESTION (clarification, not necessarily a change)
│       → "Question: why was this approach chosen over X?"
│       → Author can answer without necessarily changing code
│
├─ WHEN REQUESTING CHANGES
│   ├─ Be specific and constructive — explain WHY, suggest HOW
│   ├─ Document ALL findings in the PR discussion thread
│   ├─ Use "Request Changes" status for blockers; comment for suggestions
│   └─ Author must address EVERY comment before re-review
│
├─ APPROVING WITH OUTSTANDING SUGGESTIONS
│   ├─ OK to approve when: all BLOCKERS are fixed, only suggestions remain
│   ├─ Leave suggestions as comments, approve, note "minor suggestions left"
│   └─ Author can implement suggestions in a follow-up issue if they prefer
│
└─ MAINTAINER OVERRIDE
    └─ Project owner may merge with fewer requirements in urgent situations
        (this is rare and the exception, not the norm)
```

### "Which directory does this file go in?"

```
File placement rules for this project (every path is exact — no variations):
│
├─ Is this PRODUCTION SOURCE CODE?
│   └─ → /src/cleveragents/
│       ├─ Python packages, modules, and subpackages
│       ├─ ⚠️ ABSOLUTELY NO: tests, mocks, fixtures, test data, docs, examples
│       └─ If you're tempted to put a mock here → put it in features/mocks/
│
├─ Is this a BDD UNIT TEST (Gherkin feature file or step definition)?
│   └─ → /features/
│       ├─ *.feature files go directly under features/ or a logical subdirectory
│       ├─ Step definitions → features/steps/
│       └─ /features/mocks/ → ALL mocks, fakes, stubs, test doubles
│           ⚠️ This is the ONLY place mocks are permitted in this project
│
├─ Is this a MOCK, FAKE, STUB, or TEST DOUBLE?
│   └─ → /features/mocks/  ← ONLY valid location
│       ⚠️ Never in src/, never in scripts/, never anywhere else
│
├─ Is this a ROBOT FRAMEWORK TEST (integration or e2e)?
│   └─ → /robot/
│       ├─ .robot files and .resource files
│       └─ ⚠️ No mocks allowed here — real services ONLY
│
├─ Is this a PERFORMANCE BENCHMARK?
│   └─ → /benchmarks/
│       └─ ASV (Airspeed Velocity) benchmark files
│
├─ Is this DOCUMENTATION?
│   └─ → /docs/
│       ├─ Must be written in MkDocs-compatible markdown
│       ├─ docs/specification.md → THE authoritative architecture spec
│       │   ⚠️ Only modify via ADR process, never to match broken code
│       └─ Build with: nox -s docs
│
├─ Is this a CONFIGURATION FILE?
│   └─ → /config/
│       (pyproject.toml stays in root — it's a recognized root-level convention)
│
├─ Is this a UTILITY SCRIPT?
│   └─ → /scripts/
│       ⚠️ Must NOT contain: mock code, test data, or production source
│
├─ Is this EXAMPLE CODE?
│   └─ → /examples/
│
├─ Is this a KUBERNETES / HELM resource?
│   └─ → /k8s/
│       └─ Kubernetes Helm chart for server deployment
│
└─ ROOT LEVEL (reserved for widely recognized conventions ONLY)
    ├─ pyproject.toml — all project configuration
    ├─ noxfile.py — all nox session definitions
    ├─ .pre-commit-config.yaml — pre-commit hooks
    ├─ robot.cfg — Robot Framework configuration
    ├─ README, CONTRIBUTING, LICENSE, CHANGELOG, CONTRIBUTORS.md
    ├─ .forgejo/ — Forgejo Actions workflow definitions
    └─ ⚠️ No arbitrary files in root
```

### "Am I writing tests?"

```
Testing rules and multi-level mandate for this project:
│
├─ MULTI-LEVEL TESTING MANDATE (applies to every coding task)
│   ├─ Every task MUST include or update tests at ALL of these levels:
│   │   ├─ 1. Unit tests (Behave BDD scenarios)
│   │   ├─ 2. Integration tests (Robot Framework — real services)
│   │   └─ 3. Performance benchmarks (ASV) — for performance-sensitive code
│   ├─ Testing is NON-OPTIONAL — it is part of the definition of done
│   └─ Work is NOT done until all three levels are addressed
│
├─ WHICH FRAMEWORK DO I USE?
│   │
│   ├─ Unit-level behavior → Behave (Cucumber/Gherkin)
│   │   ├─ Feature files: features/*.feature or features/<topic>/*.feature
│   │   ├─ Step definitions: features/steps/<name>_steps.py
│   │   ├─ Mocks: features/mocks/ (FakeListLLM, in-memory repos, etc.)
│   │   └─ Run: nox -s unit_tests
│   │
│   ├─ Integration test (real services, NO mocks) → Robot Framework
│   │   ├─ Tests component interactions with REAL databases, services, files
│   │   ├─ Good integration tests exercise:
│   │   │   ├─ CLI command end-to-end (runs the actual CLI binary)
│   │   │   ├─ Database persistence and retrieval (real SQLite/PostgreSQL)
│   │   │   ├─ File system operations (real temp directories)
│   │   │   └─ Service layer with real repository implementations
│   │   ├─ Tests must be independent — each test suite leaves a clean state
│   │   ├─ Location: robot/*.robot or robot/<topic>/*.robot
│   │   └─ Run: nox -s integration_tests (via pabot for parallel execution)
│   │
│   └─ End-to-end test (requires REAL LLM API keys) → Robot Framework
│       ├─ Tests complete workflows with real LLM providers
│       ├─ Separate from integration tests — REAL API credentials required
│       ├─ Location: robot/*.robot (e2e-tagged or e2e subdirectory)
│       └─ Run: nox -s e2e_tests (requires OPENAI_API_KEY, etc. set)
│       ⚠️ Do NOT use nox -s e2e_tests in CI without setting secrets
│       ⚠️ integration_tests ≠ e2e_tests — the latter uses real LLM calls
│
├─ WHAT MAKES A GOOD GHERKIN SCENARIO
│   ├─ Use Given/When/Then correctly:
│   │   ├─ Given: establish the pre-conditions (state of the world)
│   │   ├─ When:  the action that triggers the behavior being tested
│   │   └─ Then:  the observable outcome that must be verified
│   ├─ And / But (continuation keywords — use to extend the same step type)
│   │   ├─ Given ... / And ...    ← additional pre-conditions
│   │   ├─ Then ...  / And ...    ← additional outcomes (same assertion group)
│   │   └─ Then ...  / But ...    ← contrasting outcome (e.g. "but X does NOT happen")
│   ├─ Scenario Outline (for data-driven scenarios — same behavior, different inputs)
│   │   ├─ Use when: same scenario must verify multiple valid/invalid values
│   │   ├─ Format: Scenario Outline: + Examples: table with <placeholders>
│   │   └─ Avoid: don't use Outline just to avoid writing two clear scenarios
│   ├─ Scenarios are documentation — a non-developer should understand them
│   ├─ Scenario title should describe the BEHAVIOR, not the test mechanics
│   │   ✓ "Scenario: Valid configuration file loads without error"
│   │   ✓ "Scenario: Missing required field causes validation failure with message"
│   │   ✗ "Scenario: Test configuration parser with valid input"
│   │   ✗ "Scenario: Test case 1"
│   ├─ One scenario = one behavior (don't test multiple things in one scenario)
│   └─ Avoid implementation details in step text (test behavior, not internals)
│       ✗ "When the PlanService._resolve_invariants() method is called"
│       ✓ "When the plan enters the Strategize phase"
│
├─ WHAT TESTS MUST COVER
│   ├─ Normal operation (the happy path)
│   ├─ All error and exception paths
│   ├─ Edge cases and boundary conditions
│   ├─ Failure modes that could occur in production
│   └─ Every new behavior introduced — not just line coverage
│
├─ WHAT AM I PROHIBITED FROM DOING?
│   ├─ ⚠️ NO pytest-style unit tests — ever
│   ├─ ⚠️ NO tests/ directory — it intentionally does not exist
│   ├─ ⚠️ NO mocks in integration or e2e tests — real services ONLY
│   └─ ⚠️ NO placeholder steps (never commit unimplemented step definitions)
│
├─ BEHAVE STEP FILE RULES (strictly enforced)
│   ├─ Before creating a NEW step file → check if an existing file already
│   │   covers the same behavior and extend it instead
│   ├─ Steps used ONLY by foo.feature → must live in foo_steps.py
│   ├─ Steps used by MULTIPLE features → clearly named, shared file
│   │   (prefer updating an existing shared file over creating another)
│   └─ Every .feature file must ship with ALL its steps fully implemented
│
├─ MOCK PLACEMENT (absolute rule)
│   ├─ All mocks/fakes/stubs/fixtures → features/mocks/ ONLY
│   ├─ Never in src/cleveragents/
│   ├─ Never in scripts/
│   └─ Use dependency injection — never if-testing guards in production code
│
├─ PROPERTY-BASED TESTING (Hypothesis)
│   ├─ Use Hypothesis for boundary testing and invariant verification
│   ├─ Especially valuable for:
│   │   ├─ Decision tree operations (structural invariants hold after any mutation)
│   │   ├─ Merge strategies (no data loss for any combination of changes)
│   │   ├─ Context tier boundary calculations (tokens never exceed budget)
│   │   ├─ Confidence score aggregation (score always in 0.0–1.0 range)
│   │   ├─ ULID generation (monotonicity, lexicographic ordering)
│   │   └─ Invariant reconciliation (precedence rules hold for any input set)
│   ├─ Write Hypothesis strategies for your domain types, not just raw primitives
│   └─ Hypothesis tests run via: nox -s unit_tests (integrated with Behave)
│
├─ COVERAGE (hard merge gate)
│   ├─ Threshold: ≥ 97% at all times
│   ├─ Measured by: nox -s coverage_report  (Slipcover)
│   ├─ PR is BLOCKED automatically if coverage drops below 97%
│   ├─ Exception: project owner can grant a documented exception
│   └─ Any exclusion from coverage: explicit project owner approval required
│
├─ TEST FAILURE REMEDIATION
│   ├─ Any test failure during development → immediately becomes blocking task
│   ├─ Document the failure context
│   ├─ Resolve it BEFORE progressing to other work
│   ├─ If the failure reveals a genuine bug in production code:
│   │   → The TDD workflow gets triggered: create TDD issue → write failing test
│   │   → THEN fix the bug (see "Am I fixing a bug?" tree)
│   ├─ Exception: @tdd_expected_fail tests are tracked failures (not unaddressed)
│   └─ Never leave a known-failing test unaddressed
│
├─ PERFORMANCE BENCHMARKS (ASV)
│   ├─ Write ASV benchmarks for all performance-sensitive code
│   ├─ Location: benchmarks/ (not features/ or robot/)
│   ├─ Focus areas: plan generation latency, CLI startup, indexing throughput
│   ├─ Run: nox -s benchmark
│   ├─ PRs: regression check via nox -s benchmark_regression (10% regression = fail)
│   └─ Benchmark results uploaded as artifacts for manual inspection
│
└─ LangChain/LangGraph testing
    ├─ Use FakeListLLM or custom mock providers in unit tests (features/)
    │   → NEVER use real LLM API in unit tests
    ├─ Test each graph node's state transformation independently
    ├─ Verify complete workflow with expected state transitions
    ├─ For streaming: test both event emission AND final results
    └─ For memory: verify conversation history and entity tracking
```

### "Am I fixing a bug? (TDD workflow)"

```
Mandatory Bug Fix TDD Workflow — no exceptions:
│
├─ STEP 1: Create the TDD issue FIRST (before writing any code)
│   ├─ Type: Type/Testing
│   ├─ Title prefix: "TDD: <exact description from bug issue>"
│   ├─ Priority: Priority/Critical
│   ├─ MoSCoW: MoSCoW/Must Have
│   └─ Forgejo dependency: bug issue DEPENDS ON this TDD issue
│       (TDD issue blocks the bug issue — set this direction exactly)
│
├─ STEP 2: Write the failing test on a tdd/ branch
│   ├─ Branch name: tdd/mN-<descriptive-name>  (N = milestone number)
│   │   e.g. tdd/m3-shacl-crash
│   ├─ Write a Behave scenario that proves the bug exists
│   │   (the assertion should fail when the bug is present)
│   ├─ Apply ALL THREE tags — missing any one is a CI validation error:
│   │   @tdd_issue            ← permanent filter tag
│   │   @tdd_issue_N          ← permanent issue link (N = bug issue number)
│   │   @tdd_expected_fail    ← inverts pass/fail while bug unfixed (TEMPORARY)
│   └─ ⚠️ ASSERTION TYPE: use assert or raise AssertionError ONLY
│       Never use ValueError, RuntimeError, OSError, or any non-assertion
│       exception — those are NOT inverted by the TDD hook and will break CI
│
├─ STEP 3: Merge the TDD PR to master
│   ├─ CI passes because @tdd_expected_fail inverts the result
│   ├─ Reviewer checks: test quality, correct tagging, AssertionError usage
│   ├─ Merge via normal PR process
│   └─ Close the TDD issue
│
├─ STEP 4: Implement the fix on a bugfix/ branch
│   ├─ Branch name: bugfix/mN-<same-descriptive-name-as-tdd-branch>
│   │   e.g. bugfix/m3-shacl-crash  (suffix matches tdd/m3-shacl-crash)
│   │   ⚠️ SAME suffix required — enables traceability between branches
│   ├─ Implement the actual fix
│   ├─ REMOVE @tdd_expected_fail (leave @tdd_issue and @tdd_issue_N forever)
│   ├─ Test must now PASS normally
│   └─ PR: "Closes #<bug_issue_number>"
│
├─ STEP 5: CI gate verification (automatic)
│   ├─ CI checks @tdd_expected_fail is ABSENT — blocks merge if still present
│   ├─ CI checks @tdd_issue_N test EXISTS for bug #N — blocks if TDD was skipped
│   ├─ Test now runs normally and must pass
│   └─ Coverage must still be ≥ 97%
│
├─ STEP 6: Merge and close
│   ├─ Merge the bug fix PR
│   ├─ Close the bug issue
│   └─ @tdd_issue and @tdd_issue_N tags stay in codebase PERMANENTLY
│       as regression guards — never remove them after the fix
│
├─ WHAT IF THE BUG REVEALS A DEEPER PROBLEM?
│   ├─ If the bug is a symptom of a deeper architectural issue:
│   │   → Still write the TDD test for the specific symptom
│   │   → Then create a SEPARATE issue for the architectural fix
│   └─ If fixing it requires significant refactoring:
│       → Create the TDD test first (proves the bug)
│       → Create a separate Epic/Issue for the refactor
│       → The bugfix can be minimal (just fix the symptom); refactor follows
│
├─ PRIORITY RULES
│   ├─ Type/Bug issues: always Priority/Critical + MoSCoW/Must Have
│   ├─ Their TDD issues: same priority
│   └─ Bug work takes precedence over all feature and task work
│
└─ ASSIGNEE PREFERENCE (not mandatory, but strongly preferred)
    ├─ TDD issue → Developer A (proves the bug)
    └─ Bug fix issue → Developer B (proves the fix)
        (independent verification; share when capacity requires it)
```

### "Am I writing a TDD issue-capture test?"

```
Exact TDD tag rules (all enforced by CI hooks):
│
├─ THE THREE REQUIRED TAGS
│   │
│   ├─ @tdd_issue
│   │   ├─ Present on EVERY TDD issue-capture test without exception
│   │   ├─ Used to filter, list, and count TDD tests across the codebase
│   │   ├─ Lifecycle: PERMANENT — never removed after merging
│   │   └─ CI rule: if @tdd_issue_N is present, @tdd_issue MUST be present
│   │
│   ├─ @tdd_issue_N  (N = the bug issue number, e.g. @tdd_issue_123)
│   │   ├─ Links this test to the specific bug issue it captures
│   │   ├─ CI checks for this tag when a bug fix PR closes issue #N
│   │   │   → PR is BLOCKED if no @tdd_issue_N test exists in the codebase
│   │   ├─ Lifecycle: PERMANENT — serves as a regression reference forever
│   │   └─ CI rule: if @tdd_expected_fail is present, @tdd_issue_N MUST be present
│   │
│   └─ @tdd_expected_fail
│       ├─ Behavioral switch: inverts test pass/fail while bug is unfixed
│       │   → Test PASSES CI when the underlying assertion FAILS (bug present)
│       │   → Test FAILS CI when the underlying assertion PASSES (bug fixed
│       │      without removing this tag — catches accidental "fixes")
│       ├─ CI rule: if present, both @tdd_issue AND @tdd_issue_N MUST be present
│       ├─ CI rule: bug fix PR closing #N MUST remove this tag
│       │   → PR is BLOCKED if tag is still present
│       └─ Lifecycle: TEMPORARY — removed by the bug fix developer only
│
├─ ASSERTION TYPE RULE (critical — enforced by CI hooks)
│   ├─ Steps signaling "bug still present" MUST use Python's AssertionError
│   │   ├─ assert some_condition, "descriptive message"
│   │   └─ raise AssertionError("bug still present: <description>")
│   ├─ ⚠️ DO NOT USE:
│   │   ├─ ValueError  → NOT inverted — treated as runtime error
│   │   ├─ RuntimeError → NOT inverted — treated as infrastructure error
│   │   └─ OSError, TypeError, or any other non-assertion exception
│   └─ Reason: the TDD hook only inverts AssertionError; other exceptions
│       fail the suite regardless of @tdd_expected_fail
│
├─ EXAMPLE — before fix (all three tags present):
│
│   @tdd_issue @tdd_issue_123 @tdd_expected_fail
│   Scenario: Bug #123 — SHACL validation rejects valid graph
│     Given a valid resource graph
│     When SHACL validation is applied
│     Then the validation should succeed
│     # ↑ this assertion fails while bug exists → CI passes via inversion
│
├─ EXAMPLE — after fix (bug fix dev removes @tdd_expected_fail):
│
│   @tdd_issue @tdd_issue_123
│   Scenario: Bug #123 — SHACL validation rejects valid graph
│     Given a valid resource graph
│     When SHACL validation is applied
│     Then the validation should succeed
│     # ↑ now passes normally — regression guard stays in codebase forever
│
└─ VALIDATION CHECKLIST before opening the TDD PR
    ├─ All three tags present on the scenario?
    ├─ Only AssertionError used in expected-fail steps?
    ├─ Assertion actually fails when running without @tdd_expected_fail?
    ├─ Branch name follows tdd/mN-<name> pattern?
    └─ Bug issue has Forgejo dependency: depends on this TDD issue?
```

### "Which nox session do I run?"

```
Complete nox session reference for this project:
│
├─ BEFORE EVERY COMMIT (all must be green):
│   ├─ nox -s lint                # ruff linting + format check
│   ├─ nox -s typecheck           # Pyright strict (zero suppressions)
│   ├─ nox -s unit_tests          # Behave BDD scenarios
│   └─ nox -s coverage_report     # Slipcover ≥ 97%
│
├─ BEFORE SUBMITTING A PR (run the full suite):
│   ├─ nox                        # all default sessions — must be fully green
│   ├─ nox -s security_scan       # bandit + semgrep + vulture
│   ├─ nox -s dead_code           # vulture unused code detection
│   └─ nox -s integration_tests   # Robot Framework (parallel via pabot)
│
├─ SESSION REFERENCE (what each session does):
│   ├─ nox -s lint                # ruff: find linting violations + check formatting
│   ├─ nox -s format              # ruff: AUTO-FIX formatting (modifies files)
│   ├─ nox -s format -- --check   # ruff: check formatting ONLY, no changes (CI mode)
│   │   ⚠️ format and format --check are different:
│   │   → format: changes your files (run locally to fix)
│   │   → format --check: reports violations without changing (CI uses this)
│   ├─ nox -s typecheck           # Pyright strict type checking
│   ├─ nox -s security_scan       # bandit + semgrep + vulture
│   ├─ nox -s dead_code           # vulture dead code detection
│   ├─ nox -s complexity          # Radon complexity (nightly quality sweep)
│   ├─ nox -s unit_tests          # Behave BDD tests (features/)
│   ├─ nox -s integration_tests   # Robot Framework integration tests (robot/)
│   ├─ nox -s e2e_tests           # Robot Framework e2e (REAL LLM keys required)
│   ├─ nox -s coverage_report     # Slipcover coverage (fail-under 97%)
│   ├─ nox -s benchmark           # ASV performance benchmarks
│   ├─ nox -s benchmark_regression# ASV benchmark regression (PRs only)
│   ├─ nox -s docs                # MkDocs documentation build
│   └─ nox -s build               # wheel distribution build
│
├─ CI JOB → SESSION MAPPING:
│   ├─ lint job            → nox -s lint  +  nox -s format -- --check
│   ├─ typecheck job       → nox -s typecheck
│   ├─ security job        → nox -s security_scan  +  nox -s dead_code
│   ├─ quality job         → nox -s complexity
│   ├─ unit_tests job      → nox -s unit_tests
│   ├─ integration_tests   → nox -s integration_tests
│   ├─ e2e_tests           → nox -s e2e_tests
│   ├─ coverage job        → nox -s coverage_report  (fail-under 97%)
│   ├─ benchmark-regression→ nox -s benchmark_regression
│   ├─ benchmark-publish   → nox -s benchmark  (publish variant)
│   ├─ build job           → nox -s build
│   └─ docker job          → Docker build + smoke test (no nox session)
│
├─ REQUIRED FOR MERGE (status-check gate — ALL must pass):
│   ├─ lint ✓      typecheck ✓      security ✓
│   ├─ unit_tests ✓                 coverage ✓  (≥ 97%)
│   └─ integration_tests, e2e_tests, benchmark-regression = informational only
│
└─ RULES:
    ├─ NEVER invoke behave, robot, pyright, ruff, bandit directly
    ├─ If a session is missing → add it to noxfile.py BEFORE running
    └─ Test failure → immediately blocking task; fix before any other work
```

### "Am I looking at a CI failure?"

```
Diagnosing CI failures in this project:
│
├─ WHERE TO LOOK
│   ├─ PR → Checks tab → each job is a separate named check
│   ├─ Click failed job → view full log
│   └─ status-check job provides a consolidated pass/fail summary
│
├─ REQUIRED JOBS FOR MERGE (blocking if red):
│   ├─ lint       → nox -s lint  +  nox -s format -- --check  (Ruff)
│   ├─ typecheck  → nox -s typecheck  (Pyright strict)
│   ├─ security   → nox -s security_scan  +  nox -s dead_code
│   ├─ unit_tests → nox -s unit_tests  (Behave BDD)
│   └─ coverage   → nox -s coverage_report  (Slipcover, fail-under 97%)
│
├─ DIAGNOSING EACH FAILURE:
│   │
│   ├─ lint failure
│   │   ├─ Run locally: nox -s lint  → see exact violations with line references
│   │   ├─ Auto-fix formatting: nox -s format  (modifies files)
│   │   ├─ Remaining violations after auto-fix → fix manually, then re-run
│   │   └─ Common causes: unused imports, line length, style violations
│   │
│   ├─ typecheck failure
│   │   ├─ Run locally: nox -s typecheck  → see Pyright errors with context
│   │   ├─ Fix ALL type errors — every single one
│   │   ├─ ⚠️ NEVER add # type: ignore — this is prohibited unconditionally
│   │   ├─ ⚠️ NEVER disable Pyright in pyproject.toml or noxfile.py
│   │   └─ Common causes: missing annotations, wrong return types, None handling
│   │
│   ├─ security failure
│   │   ├─ Run: nox -s security_scan  → bandit + semgrep findings
│   │   ├─ Run: nox -s dead_code  → vulture findings
│   │   ├─ High-severity bandit findings → must be fixed, not suppressed
│   │   ├─ Low-severity bandit findings → suppress ONLY with justification comment
│   │   └─ Dead code → remove it or document why it must remain
│   │
│   ├─ unit_tests failure
│   │   ├─ Run: nox -s unit_tests  → see failing Behave scenarios with context
│   │   ├─ Read the failing scenario and step output carefully
│   │   ├─ Fix the failing step definition or the production code it exercises
│   │   ├─ ⚠️ @tdd_expected_fail failure = bug was fixed WITHOUT removing the tag
│   │   │   → remove @tdd_expected_fail from the scenario, re-run
│   │   ├─ ⚠️ "Step not found" error = placeholder step was committed → implement it
│   │   └─ ⚠️ Test failure that reveals a REAL bug in production code:
│   │       → This triggers the TDD workflow:
│   │       → 1. Create a Type/Bug issue
│   │       → 2. Create a companion Type/Testing TDD issue
│   │       → 3. Write the @tdd_expected_fail scenario on a tdd/ branch
│   │       → 4. THEN fix the bug on a bugfix/ branch
│   │       → See "Am I fixing a bug?" tree
│   │
│   ├─ coverage failure
│   │   ├─ Run: nox -s coverage_report  → look for COVERAGE OK / COVERAGE FAILED
│   │   ├─ Open the coverage HTML report to find specific uncovered lines
│   │   ├─ Add Behave scenarios or Robot tests for the uncovered paths
│   │   ├─ Focus on untested error paths, edge cases, and branches
│   │   └─ Exclusions require explicit project owner approval
│   │
│   ├─ TDD tag gate failure
│   │   ├─ "@tdd_expected_fail still present on @tdd_issue_N" →
│   │   │   remove @tdd_expected_fail from the scenario
│   │   └─ "no @tdd_issue_N test found for bug #N" →
│   │       TDD step was skipped; must write the TDD test first
│   │
│   ├─ integration_tests failure (informational, not blocking)
│   │   ├─ Run: nox -s integration_tests  → see which Robot scenarios failed
│   │   ├─ Common causes: real service not running, schema mismatch, env vars missing
│   │   ├─ Check that required services are available in the test environment
│   │   └─ If a service is genuinely broken → may trigger a bug issue + TDD workflow
│   │
│   ├─ quality failure (Radon complexity — informational, runs nightly)
│   │   ├─ Run: nox -s complexity  → see complex functions/methods
│   │   ├─ Refactor functions with high complexity (cyclomatic complexity > 10)
│   │   └─ Break large functions into smaller, focused ones
│   │
│   └─ benchmark-regression failure (informational, not blocking)
│       ├─ Check the artifact uploaded by the benchmark-regression job
│       ├─ Download and inspect the ASV comparison report
│       ├─ If regression > 10% → investigate and fix before the PR merges
│       └─ Acceptable causes: intentional trade-off (document it in PR description)
│
└─ AFTER FIXING
    ├─ Run the affected nox session locally to confirm the fix
    ├─ Run nox (full suite) to ensure no regressions introduced
    └─ Push — CI re-runs automatically on the new commit
```

### "Am I documenting something?"

```
Documentation standards for this project:
│
├─ WHERE DOES DOCUMENTATION LIVE?
│   ├─ Architecture and design decisions → docs/specification.md
│   │   (modify only via ADR process — see below)
│   ├─ User-facing guides, API docs, how-tos → docs/ (MkDocs format)
│   ├─ Code documentation → docstrings/inline comments in source files
│   └─ Change history → CHANGELOG (one entry per commit, user perspective)
│
├─ SINGLE CANONICAL SURFACE (mandatory)
│   ├─ Each type of documentation has exactly ONE home
│   ├─ Do NOT scatter related notes across multiple files
│   ├─ If a doc already exists for this purpose → UPDATE it, don't create parallel
│   └─ If multiple sources of truth exist → consolidate them into one
│
├─ TRACEABILITY RULES (strictly enforced)
│   ├─ Reference code by LOGICAL LOCATION — never by line number
│   │   ├─ ⚠️ NEVER: mypackage/services.py:142  ← line numbers shift constantly
│   │   ├─ CORRECT format: module.class.method
│   │   │   e.g. cleveragents.services.plan_service.PlanService.execute
│   │   └─ Why: line numbers become misleading with every edit
│   ├─ Include the commit hash at time of writing
│   │   └─ e.g. "At commit a3f92b1, PlanService.execute was refactored to..."
│   │   → If names are later refactored, the commit hash traces the original
│   └─ Record substantive design decisions alongside the logical code references
│
├─ CONTINUOUS DOCUMENTATION (same-commit rule)
│   ├─ Documentation changes go in the SAME commit as the code they document
│   ├─ ⚠️ "I'll document it later" is never acceptable
│   ├─ If you discovered something during implementation → document it immediately
│   └─ Work is NOT done until all affected documentation is updated
│
├─ CODE-LEVEL DOCUMENTATION
│   ├─ All public classes → class-level docstring explaining purpose and usage
│   ├─ All public methods and functions → docstring with:
│   │   ├─ What the method does (purpose)
│   │   ├─ Args (name, type, description)
│   │   ├─ Returns (type, description)
│   │   └─ Raises (exception types and when)
│   ├─ Non-obvious logic → inline comment explaining WHY (not WHAT)
│   │   e.g. # must copy here — caller holds a reference to original
│   └─ Never write comments that merely restate the code:
│       ⚠️ WRONG: x = x + 1  # increment x
│       ✓ RIGHT: x = x + 1  # offset by one to skip the sentinel value
│
├─ CHANGELOG ENTRIES
│   ├─ One entry per commit, added in the same commit
│   ├─ Written from the user's perspective (what changed for them)
│   ├─ ✓ "Add support for multiple --invariant flags on agents plan use"
│   ├─ ✓ "Fix null pointer when resource DAG contains circular references"
│   └─ ✗ "Refactored PlanService._resolve_invariants() method"
│
├─ ADR PROCESS (for architectural changes)
│   ├─ When: any change to the architecture or design of the system
│   ├─ WHAT AN ADR CONTAINS:
│   │   ├─ Title: short description of the decision
│   │   ├─ Status: proposed | accepted | deprecated | superseded
│   │   ├─ Context: what problem is being solved and why it matters
│   │   ├─ Decision: what was decided (the chosen approach)
│   │   ├─ Consequences: trade-offs, risks, follow-up work required
│   │   └─ Alternatives considered: other options and why they were rejected
│   ├─ PROCESS:
│   │   1. Create the ADR document in docs/adr/ (ADR-NNN-title.md)
│   │   2. Submit for review via PR (labeled as an ADR)
│   │   3. Approved → update docs/specification.md with the new decision
│   │   4. THEN write the code
│   └─ ⚠️ Never edit docs/specification.md to match incorrect code
│
├─ DOCS/SPECIFICATION.MD (the most important doc)
│   ├─ Read this BEFORE starting any task — relevant sections
│   ├─ When code and spec disagree → code is wrong; align code to spec
│   ├─ Proposing a spec change → ADR process required first
│   └─ Never edit to reflect incorrect code — only to reflect approved decisions
│
└─ MKDOCS DOCUMENTATION (docs/)
    ├─ All markdown in docs/ must be valid MkDocs-compatible format
    ├─ Build and preview locally: nox -s docs
    └─ API docs, user guides, architecture overviews all live here
```

### "Am I using the plan CLI?"

```
CleverAgents plan workflow — two mutually exclusive systems:
│
├─ ⚠️ THESE SYSTEMS CANNOT BE MIXED — EVER
│   Choosing a system commits you for the ENTIRE lifecycle of that plan.
│
├─ V3 SYSTEM — ALWAYS USE THIS FOR NEW WORK
│   ├─ Commands:
│   │   ├─ agents plan use local/<action> <project>  → returns a ULID
│   │   ├─ agents plan execute <ULID>
│   │   └─ agents plan apply <ULID>
│   ├─ Identifiers: ULID — 26-character Crockford base32
│   │   e.g. 01HXM8C2ZK4Q7C2B3F2R4VYV6J
│   ├─ Storage: PlanLifecycleService
│   └─ Authority: this is the authoritative workflow per docs/specification.md
│
├─ LEGACY SYSTEM — DEPRECATED, DO NOT START NEW WORK HERE
│   ├─ Commands:
│   │   ├─ agents tell -n "my-plan" "Devise a plan to..."
│   │   ├─ agents build
│   │   └─ agents apply my-plan
│   ├─ Identifiers: human-readable names (e.g. "64-bit port plan")
│   ├─ Storage: PlanService  (completely separate from v3 — invisible to v3)
│   └─ These commands emit deprecation warnings — they will be removed
│
├─ WHY THEY CANNOT BE MIXED
│   ├─ Completely separate storage backends (PlanService vs PlanLifecycleService)
│   ├─ Legacy plan created with "agents tell" → INVISIBLE to any v3 command
│   ├─ v3 command with a name (not ULID) → explicit error with explanation
│   └─ There is NO automatic migration path
│
├─ IF YOU SEE THIS ERROR:
│   "Error: Plan 'my-legacy-plan' not found."
│   → You created with legacy ("agents tell") and tried v3 ("agents plan execute")
│   → These are incompatible storage systems — you cannot mix them
│   → Start fresh: agents plan use <action> <project>
│
└─ MIGRATION (when needed)
    ├─ 1. Understand what the legacy plan was intended to accomplish
    ├─ 2. Create a new v3 plan: agents plan use <action> <project>
    └─ 3. Use v3 commands exclusively from that point forward
```

### "Am I writing LangChain/LangGraph code?"

```
LangChain/LangGraph design and implementation rules:
│
├─ GRAPH / WORKFLOW DESIGN
│   ├─ State: always use TypedDict classes with clear field documentation
│   │   ├─ Include error fields for graceful failure tracking
│   │   └─ Never use untyped dicts or Any-typed state
│   ├─ Node naming: descriptive verb-based names
│   │   e.g. analyze_requirements, generate_plan, validate_output
│   ├─ Checkpointing: ALWAYS integrate MemorySaver for workflow resumption
│   │   → Compile EVERY graph with checkpointer=MemorySaver()
│   │   → Never omit for graphs with more than one execution step
│   └─ Conditional edges: clear decision functions with descriptive names
│
├─ LANGCHAIN INTEGRATION
│   ├─ Provider abstraction: ALWAYS use BaseLanguageModel or BaseLLM
│   │   NEVER hardcode a specific provider (OpenAI, Anthropic, etc.) directly
│   ├─ All prompts via ChatPromptTemplate or PromptTemplate — never f-strings
│   │   ⚠️ f-strings as prompts are not composable, traceable, or testable
│   ├─ Implement BOTH sync (invoke) AND async (ainvoke) with streaming
│   ├─ Memory classes:
│   │   ├─ ConversationBufferMemory → for conversation history across turns
│   │   └─ EntityMemory → for tracking named entities across a conversation
│   └─ Output parsing: StrOutputParser (text), JsonOutputParser (structured)
│
├─ RxPY REACTIVE STREAMS (for real-time event routing)
│   ├─ Use Subject for hot observable streams (plan events, actor outputs)
│   ├─ Use BehaviorSubject when late subscribers need the last emitted value
│   ├─ Use ReplaySubject for buffering historical events (e.g. session replay)
│   ├─ Operators: map, filter, flat_map, debounce, throttle, scan
│   ├─ Bridge: use RxPY for event routing BETWEEN actors/graphs
│   └─ Backpressure: use throttle or debounce for high-frequency streams
│
├─ CONFIGURATION
│   ├─ Environment variables: use standard LangChain env vars
│   │   (LANGCHAIN_TRACING_V2, LANGCHAIN_API_KEY)
│   ├─ Observability: LangSmith/OpenTelemetry DISABLED by default
│   │   (user must opt in via configuration — never enabled automatically)
│   ├─ Multi-provider: support multiple providers via config, never hardcoded
│   ├─ Retry logic: LangChain's built-in retry decorators for LLM calls
│   └─ Token limits: chunking strategy must respect model token limits
│
├─ CANONICAL NODE PATTERN (follow this template exactly):
│
│   async def analyze_requirements(state: PlanGenerationState) -> dict:
│       """Analyze requirements node with proper error handling."""
│       try:
│           prompt = ChatPromptTemplate.from_template(
│               "Analyze these requirements: {requirements}"
│           )
│           chain = prompt | llm | StrOutputParser()
│           analysis = await chain.ainvoke({"requirements": state["description"]})
│           return {"analysis": analysis}
│       except Exception as e:
│           return {"error": f"Analysis failed: {str(e)}"}
│
├─ TESTING LANGGRAPH CODE
│   ├─ Use FakeListLLM or a custom mock provider — NEVER the real LLM API in unit tests
│   ├─ Test each node's state transformation in isolation
│   ├─ Test complete workflow end-to-end with expected state transitions
│   ├─ For streaming: test both event emission AND final results
│   └─ For memory: verify conversation history and entity tracking
│
└─ WHAT IS PROHIBITED
    ├─ Hardcoding a specific LLM provider in production code
    ├─ Using real LLM API calls in unit tests (features/)
    ├─ Enabling LangSmith by default
    ├─ Using f-strings directly as prompts (always use PromptTemplate)
    └─ Missing MemorySaver in any graph that has more than one execution step
```

### "Am I writing Python imports?"

```
Python-specific import rules for this project:
│
├─ WHERE DO IMPORTS GO?
│   ├─ ALL imports must be at the TOP of the file
│   ├─ Before: module docstring → __all__ → imports
│   ├─ ⚠️ NEVER inside functions, methods, or class bodies
│   └─ ⚠️ NEVER inside if, try, for, while, or with blocks
│
├─ THE ONLY EXCEPTION
│   └─ TYPE_CHECKING imports (for circular dependency avoidance ONLY):
│       from __future__ import annotations
│       from typing import TYPE_CHECKING
│       if TYPE_CHECKING:
│           from mypackage.module import SomeType
│       ⚠️ Only use this when absolutely necessary for circular import avoidance
│       ⚠️ Do NOT use it as a general pattern — imports at top is the rule
│
├─ HOW TO IMPORT
│   ├─ Prefer specific symbols: from module import ClassName, function_name
│   ├─ ⚠️ Avoid importing entire modules when only a few names are used
│   └─ ⚠️ No wildcard imports: never "from module import *"
│
└─ ORDER (follow isort / ruff conventions, enforced by nox -s lint)
    ├─ Standard library imports  (e.g. import os, from typing import Any)
    ├─ Third-party imports        (e.g. from langchain_core.llms import BaseLLM)
    └─ Local application imports  (e.g. from cleveragents.services import PlanService)
    (blank line between each group — ruff auto-enforces and auto-fixes this)
```

### "Am I writing error handling?"

```
Error and exception handling rules for this project:
│
├─ ARGUMENT VALIDATION — MANDATORY IN EVERY PUBLIC/PROTECTED METHOD
│   ├─ Validate ALL arguments FIRST, before any other logic
│   ├─ This is not optional — it is enforced in code review
│   ├─ Checks to perform (in order):
│   │   ├─ Null/None checks → reject None where not expected
│   │   ├─ Type verification → prefer compile-time (Pyright) over runtime checks
│   │   │   Use runtime type checks ONLY at untyped boundaries (deserialized input,
│   │   │   dynamic plugin APIs, data from external systems)
│   │   ├─ Value range → numeric values within acceptable bounds
│   │   ├─ Empty strings → reject where non-empty is required
│   │   ├─ Empty collections → reject where elements are required
│   │   └─ Invalid states → verify object state is valid for the operation
│   └─ Example (Python):
│       def process_data(self, data: list[str], threshold: int) -> None:
│           if data is None:
│               raise ValueError("data cannot be None")
│           if not data:
│               raise ValueError("data cannot be empty")
│           if not all(isinstance(item, str) for item in data):
│               raise TypeError("data must contain only strings")
│           if threshold < 0 or threshold > 100:
│               raise ValueError(
│                   f"threshold must be between 0 and 100, got {threshold}"
│               )
│           # ONLY NOW: actual business logic begins
│
├─ EXCEPTION PROPAGATION (critical rule)
│   ├─ Let exceptions propagate to top-level — do NOT suppress them
│   ├─ ⚠️ NEVER catch an exception just to log it and re-raise
│   │   → just let it propagate naturally
│   ├─ ⚠️ NEVER use bare except: or except Exception: without re-raising
│   │   unless you have SPECIFIC recovery logic (retry, cleanup, add context)
│   ├─ ⚠️ NEVER return None or a default value to mask an error condition
│   │   → raise an exception or return an explicit error type
│   └─ ONLY catch when you can MEANINGFULLY HANDLE:
│       ├─ Retry logic (transient network errors, rate limits)
│       ├─ Resource cleanup (release file handles, close connections)
│       └─ Adding diagnostic context BEFORE re-raising
│
├─ FAIL-FAST PRINCIPLES
│   ├─ Check preconditions at function ENTRY, not deep inside logic
│   ├─ Make failure conditions explicit — never implicit or hidden
│   ├─ Use assertions for invariants that should NEVER be violated
│   └─ Benefits: bugs surface closer to their source; stack traces are meaningful
│
└─ TDD EXPECTED-FAIL EXCEPTION: use AssertionError ONLY
    ├─ In @tdd_expected_fail Behave steps:
    │   → assert condition, "message"  OR  raise AssertionError("...")
    ├─ ⚠️ NOT ValueError, RuntimeError, OSError, or any other exception type
    └─ The TDD hook ONLY inverts AssertionError — other exceptions break CI
```

### "Am I setting up my development environment?"

```
Development environment setup for this project:
│
├─ STEP 1: Clone the repository
│   └─ git clone <repo-url> && cd cleveragents
│
├─ STEP 2: Install pre-commit hooks (MANDATORY — do this first)
│   ├─ scripts/setup-dev.sh
│   └─ This installs all pre-commit hooks that enforce quality on every commit
│
├─ STEP 3: Create the Hatch environment
│   └─ hatch env create
│
├─ STEP 4: Verify everything works
│   └─ nox  (full suite — ALL sessions must be green before any work begins)
│
├─ STEP 5: Install Commitizen (recommended for guided commit messages)
│   ├─ npm install -g commitizen@2.8.6 cz-customizable@4.0.0
│   └─ Use git cz instead of git commit going forward
│
├─ STEP 6: Read docs/specification.md
│   └─ Before touching ANY code, read the relevant specification sections
│
├─ COMPLETE TOOL INVENTORY FOR THIS PROJECT
│   ├─ Hatch         → project management (hatch env create, hatch build)
│   ├─ nox           → ALL task automation (single entry point — never bypass)
│   ├─ pyproject.toml → ALL project configuration (single source of truth)
│   ├─ Behave        → BDD unit tests (features/)
│   ├─ Robot Framework + pabot → integration and e2e tests (robot/)
│   ├─ Pyright       → strict static type checking (zero tolerance for errors)
│   ├─ ruff          → linting and auto-formatting
│   ├─ Slipcover     → coverage measurement (fail-under 97%)
│   ├─ bandit        → Python security scanning
│   ├─ semgrep       → cross-language security rules
│   ├─ vulture       → unused code detection
│   ├─ Radon         → code complexity analysis
│   ├─ ASV           → Airspeed Velocity performance benchmarks
│   ├─ Hypothesis    → property-based testing (invariants, boundary conditions)
│   ├─ MkDocs        → documentation builder
│   ├─ Commitizen    → interactive commit message generation
│   └─ pre-commit    → git hook automation
│
└─ VERIFICATION CHECKLIST (all must be green before starting work)
    ├─ nox -s lint          → green?
    ├─ nox -s typecheck     → green?
    ├─ nox -s unit_tests    → green?
    ├─ nox -s coverage_report → ≥ 97%?
    └─ Pre-commit hooks trigger on git commit?
```

### "Am I releasing a new version?"

```
Release process for this project:
│
├─ BACKWARDS COMPATIBILITY POLICY (project-specific)
│   ├─ Before v3.0.0: NO backwards compatibility
│   │   ├─ No migration guides
│   │   ├─ No compatibility shims
│   │   └─ No support for old configurations or data formats
│   └─ From v3.0.0 onward: backwards compatibility required
│
├─ WHEN TO BUMP (most PRs do NOT need a version bump)
│   ├─ Breaking API change → MAJOR (incompatible public API change)
│   ├─ New backwards-compatible functionality → MINOR
│   ├─ Bug fix in a released version → PATCH
│   └─ Refactor / docs / tests / unreleased work → NO bump needed
│
├─ STEP 1: Verify readiness
│   ├─ nox (full suite) → all green
│   ├─ Changelog updated with all changes since last release
│   ├─ Version bumped in pyproject.toml (if warranted)
│   └─ All required CI checks passing on master
│
├─ STEP 2: Create and push version tag
│   ├─ git tag v<MAJOR>.<MINOR>.<PATCH>
│   └─ git push origin v<MAJOR>.<MINOR>.<PATCH>
│   (pushing a v* tag is the ONLY trigger for the release workflow)
│
├─ STEP 3: release.yml runs automatically
│   ├─ Builds wheel via nox -s build
│   ├─ Builds Docker image tagged with version + "latest"
│   ├─ Pushes Docker image to container registry
│   └─ Creates Forgejo release with wheel attached as artifact
│
├─ IF THE RELEASE WORKFLOW FAILS
│   ├─ Check: are all required repository secrets set?
│   │   (CONTAINER_REGISTRY, CONTAINER_REGISTRY_USER, CONTAINER_REGISTRY_PASSWORD,
│   │    FORGEJO_TOKEN, FORGEJO_URL)
│   ├─ Check: does nox -s build pass locally?
│   ├─ If the tag was pushed but workflow failed:
│   │   → Fix the underlying issue
│   │   → Delete the tag: git tag -d vX.Y.Z && git push origin :refs/tags/vX.Y.Z
│   │   → Re-tag and re-push once the fix is in master
│   └─ Never create a release directly on Forgejo without the workflow
│
└─ REQUIRED REPOSITORY SECRETS (must all be present — check before releasing)
    ├─ CONTAINER_REGISTRY   → Docker registry URL
    │   (e.g. registry.cleverthis.com/cleveragents/core)
    ├─ CONTAINER_REGISTRY_USER     → registry auth username
    ├─ CONTAINER_REGISTRY_PASSWORD → registry auth password
    ├─ FORGEJO_TOKEN        → API token for creating releases
    └─ FORGEJO_URL          → Forgejo instance URL
    (e.g. https://git.cleverthis.com)
```

### "Is my work done?"

```
Definition of Done — complete checklist. Work is done only when ALL pass:
│
├─ IMPLEMENTATION
│   ├─ Feature or fix fully implemented (no stubs, no placeholder code)?
│   ├─ All subtasks in the issue checklist are checked off?
│   └─ No debug statements, no commented-out code left behind?
│
├─ TESTS — THREE LEVELS (all required)
│   ├─ 1. Unit tests (Behave BDD scenarios):
│   │   ├─ Written BEFORE the implementation (test-first)?
│   │   ├─ Cover the happy path AND all error/exception paths?
│   │   ├─ Cover edge cases and boundary conditions?
│   │   ├─ Gherkin scenarios are readable as documentation?
│   │   └─ No placeholder steps committed?
│   ├─ 2. Integration tests (Robot Framework — real services):
│   │   └─ Updated if component interfaces changed?
│   └─ 3. Performance benchmarks (ASV):
│       └─ Written for any new performance-sensitive code?
│
├─ COVERAGE
│   ├─ nox -s coverage_report → ≥ 97%?
│   └─ No new coverage exclusions without project owner approval?
│
├─ CODE QUALITY (all must be green)
│   ├─ nox -s lint → green (ruff)?
│   ├─ nox -s typecheck → green (Pyright, zero errors, no suppressions)?
│   ├─ nox -s security_scan → green (bandit + semgrep)?
│   ├─ nox -s dead_code → green (vulture)?
│   └─ nox (full suite) → all default sessions green?
│
├─ THE COMMIT
│   ├─ Commit is atomic (one logical change)?
│   ├─ Commit builds and all tests pass independently?
│   ├─ First line matches issue Metadata Commit Message EXACTLY (if prescribed)?
│   ├─ Commit body explains WHAT was done and WHY?
│   ├─ Footer includes ISSUES CLOSED: #N (or Refs: #N)?
│   ├─ Tests included in same commit as implementation?
│   └─ Documentation updated in same commit as code?
│
├─ DOCUMENTATION
│   ├─ CHANGELOG updated with one user-perspective entry for this commit?
│   ├─ CONTRIBUTORS.md updated (if first contribution)?
│   └─ Public functions/classes have docstrings?
│
├─ THE PULL REQUEST
│   ├─ PR description is detailed with summary + closing keywords (Closes #N)?
│   ├─ Forgejo dependency direction correct: PR → blocks → issue?
│   ├─ PR associated with exactly one Epic?
│   ├─ Milestone assigned (same as linked issue)?
│   └─ Exactly one Type/ label applied?
│
├─ CI CHECKS
│   ├─ All required jobs pass: lint, typecheck, security, unit_tests, coverage?
│   └─ No outstanding CI failures from this PR?
│
└─ ISSUE STATE
    ├─ Linked issue moved to State/In review (after PR submitted)?
    └─ Linked issue moved to State/Completed (after PR merged)?
```

### "What design pattern should I use?"

```
Design patterns in this project — use liberally, ad-hoc is NOT acceptable:
│
├─ CREATIONAL PATTERNS (object creation)
│   ├─ Factory Pattern
│   │   ├─ Use: object creation with complex initialization logic
│   │   └─ e.g. ActorFactory.create(config) → right concrete Actor subtype
│   ├─ Abstract Factory Pattern
│   │   ├─ Use: creating families of related objects without specifying concrete classes
│   │   └─ e.g. ProviderFactory that creates LLM + embeddings + tokenizer together
│   ├─ Builder Pattern
│   │   ├─ Use: constructing complex objects step by step with fluent interfaces
│   │   └─ e.g. PlanBuilder.with_action(...).with_project(...).with_invariant(...).build()
│   ├─ Prototype Pattern
│   │   ├─ Use: cloning objects instead of creating from scratch
│   │   └─ e.g. cloning an Action template before binding it to a project
│   ├─ Singleton Pattern
│   │   ├─ Use: single-instance resources ONLY (use sparingly — prefer DI)
│   │   └─ e.g. global DI container, global config store
│   ├─ Object Pool Pattern
│   │   ├─ Use: reusing expensive-to-create objects
│   │   └─ e.g. database connection pool, LLM client pool
│   └─ Dependency Injection
│       ├─ Use: everywhere — for testability and inversion of control
│       └─ ⚠️ Never instantiate dependencies internally; always receive them
│
├─ STRUCTURAL PATTERNS (class/object composition)
│   ├─ Adapter Pattern
│   │   ├─ Use: interface compatibility between incompatible classes
│   │   └─ e.g. MCPToolAdapter, LSPToolAdapter
│   ├─ Bridge Pattern
│   │   ├─ Use: separating abstraction from implementation
│   │   └─ e.g. separate sandbox interface from git-worktree/copy-on-write impl
│   ├─ Composite Pattern
│   │   ├─ Use: treating individual objects and compositions uniformly
│   │   └─ e.g. Skill containing other Skills; Actor graph containing Actors
│   ├─ Decorator Pattern
│   │   ├─ Use: extending functionality without modifying original code
│   │   └─ e.g. caching decorator on a Tool, retry decorator on LLM calls
│   ├─ Facade Pattern
│   │   ├─ Use: simplified interface to complex subsystems
│   │   └─ e.g. PlanService facade over PlanLifecycle + Invariant + Context
│   ├─ Flyweight Pattern
│   │   ├─ Use: sharing common state among many objects (memory efficiency)
│   │   └─ e.g. sharing immutable LLM prompt templates across requests
│   ├─ Proxy Pattern
│   │   ├─ Use: controlling access to objects (lazy loading, access control, logging)
│   │   └─ e.g. A2A local facade proxying in-process service calls
│   └─ Module Pattern
│       ├─ Use: encapsulating related functionality in cohesive units
│       └─ e.g. each service module in src/cleveragents/services/
│
├─ BEHAVIORAL PATTERNS (algorithm and responsibility)
│   ├─ Chain of Responsibility
│   │   ├─ Use: passing requests along a chain of handlers
│   │   └─ e.g. invariant reconciliation: plan → action → project → global
│   ├─ Command Pattern
│   │   ├─ Use: encapsulating operations as objects (undo, queue, log)
│   │   └─ e.g. each CLI command as a Command object sent via A2A
│   ├─ Iterator Pattern
│   │   ├─ Use: sequential access to collection elements
│   │   └─ e.g. iterating decision tree nodes, streaming plan events
│   ├─ Mediator Pattern
│   │   ├─ Use: centralizing complex communications between objects
│   │   └─ e.g. PlanLifecycleService mediating between actor, sandbox, checkpoint
│   ├─ Memento Pattern
│   │   ├─ Use: capturing and restoring object state without violating encapsulation
│   │   └─ e.g. checkpoints capturing full sandbox + actor state for rollback
│   ├─ Observer Pattern
│   │   ├─ Use: event-driven architectures and loose coupling (publisher/subscriber)
│   │   └─ e.g. plan phase change events via RxPY Subject; domain event bus
│   ├─ State Pattern
│   │   ├─ Use: altering object behavior when internal state changes
│   │   └─ e.g. Plan phase state machine (Action → Strategize → Execute → Apply)
│   ├─ Strategy Pattern
│   │   ├─ Use: algorithms selectable at runtime without changing their clients
│   │   └─ e.g. sandbox strategy (git_worktree vs copy_on_write vs transaction)
│   ├─ Template Method Pattern
│   │   ├─ Use: defining algorithm skeletons with customizable steps
│   │   └─ e.g. base tool lifecycle (discover/activate/execute/deactivate)
│   ├─ Visitor Pattern
│   │   ├─ Use: separating algorithms from the objects they operate on
│   │   └─ e.g. visiting decision tree nodes for rendering, correction, export
│   └─ Null Object Pattern
│       ├─ Use: providing default behavior instead of null references
│       └─ e.g. NoOpSandbox for read-only plans, NullCheckpointService for tests
│
└─ ARCHITECTURAL PATTERNS (system organization)
    ├─ Repository Pattern
    │   ├─ Use: data access abstraction and separation from business logic
    │   └─ e.g. PlanRepository, DecisionRepository, ResourceRepository
    ├─ Unit of Work Pattern
    │   ├─ Use: maintaining objects affected by transactions and coordinating writes
    │   └─ e.g. UnitOfWork for atomic database commits across multiple repositories
    ├─ Service Layer Pattern
    │   ├─ Use: defining application boundaries and encapsulating business logic
    │   └─ e.g. PlanService, ProjectService, ActorService (Application Layer)
    ├─ MVC (Model-View-Controller)
    │   ├─ Use: separating data, presentation, and control logic
    │   └─ e.g. Domain models / CLI output renderers / A2A request handlers
    ├─ CQRS (Command Query Responsibility Segregation)
    │   ├─ Use: separating read and write operations for different optimization
    │   └─ e.g. separate read models for plan tree display vs write models for mutations
    ├─ Event Sourcing Pattern
    │   ├─ Use: storing state changes as a sequence of events
    │   └─ e.g. decision tree as an append-only event log with superseded decisions
    └─ Specification Pattern
        ├─ Use: encapsulating business rules as reusable, composable objects
        └─ e.g. invariant specifications that compose and resolve via precedence
```

---

## 📏 Key Numbers — Project-Specific Values

| Rule | Value | Notes |
|------|-------|-------|
| Coverage threshold | **97%** | Hard merge gate — Slipcover via `nox -s coverage_report` |
| PR approvals required | **1** (self-approval OK) | Formal review or LGTM/✅ comment both accepted |
| Max file size | **500 lines** | Break into focused modules if approaching limit |
| Source directory | **`/src/cleveragents/`** | Exact path — no variation |
| Unit test directory | **`/features/`** | Behave only — no `tests/` directory |
| Mock location | **`/features/mocks/`** | ONLY valid location for mocks/fakes/stubs |
| Integration test dir | **`/robot/`** | Robot Framework only — real services, no mocks |
| Benchmark directory | **`/benchmarks/`** | ASV benchmark files |
| Task runner | **`nox`** | Never invoke tools directly |
| Type checker | **Pyright** | `nox -s typecheck` — no suppressions ever |
| Inline type suppression | **PROHIBITED** | `# type: ignore` is never acceptable |
| Linter / formatter | **ruff** | `nox -s lint`, `nox -s format` |
| Security scanner | **bandit + semgrep + vulture** | `nox -s security_scan` + `nox -s dead_code` |
| Coverage tool | **Slipcover** | `nox -s coverage_report` |
| Benchmark tool | **ASV (Airspeed Velocity)** | `nox -s benchmark` |
| Benchmark regression threshold | **10%** | nox -s benchmark_regression — informational |
| Complexity tool | **Radon** | `nox -s complexity` (nightly sweep) |
| Complexity limit | **cyclomatic > 10** | Refactor when exceeded |
| Property-based testing | **Hypothesis** | For invariants, boundaries, merge strategies |
| Project manager | **Hatch** | `hatch env create`, `hatch build` |
| Project manifest | **`pyproject.toml`** | ALL config lives here |
| Pre-commit setup | **`scripts/setup-dev.sh`** | Run once after cloning |
| CI workflow: full | **`ci.yml`** | Push to master/develop; PRs to master/develop* |
| CI workflow: nightly | **`nightly-quality.yml`** | Daily midnight UTC |
| CI workflow: release | **`release.yml`** | Push of v* tags |
| Required for merge | **lint, typecheck, security, unit_tests, coverage** | status-check gate |
| Dep caching | **`actions/cache@v3` on `pyproject.toml` hash** | Auto-invalidated on dep changes |
| Plan CLI: v3 identifier | **ULID** | 26-character Crockford base32 |
| Plan CLI: legacy id | **human-readable name** | Deprecated — do not start new work |
| Backwards compat | **None before v3.0.0** | Begins at v3.0.0 |
| TDD branch prefix | **`tdd/mN-`** | N = milestone number |
| Bug fix branch prefix | **`bugfix/mN-`** | Same suffix as companion tdd/ branch |
| Feature branch prefix | **`feature/mN-`** | N = milestone number |
| TDD assertion type | **`AssertionError` ONLY** | `assert` or `raise AssertionError(...)` |
| TDD permanent tags | **`@tdd_issue`, `@tdd_issue_N`** | Never removed after merging |
| TDD temporary tag | **`@tdd_expected_fail`** | Removed by bug fix developer |
| Architecture spec | **`docs/specification.md`** | Authoritative — code aligns to it, not vice versa |
| Commit first line | **Verbatim from issue Metadata** | When issue prescribes one — copy exactly |
| PR dep direction | **PR → blocks → issue** | NEVER reversed — causes unresolvable deadlock |
| Multi-level testing | **Unit + Integration + Benchmarks** | Every task must address all three |
| Test failure handling | **Immediately blocking** | Resolve before any other work |
| Argument validation | **First guard in every public/protected method** | Before any other logic |
| Issue quality criteria | **11 criteria** | See "Is this ticket well-scoped?" tree |
| Bug priority | **Priority/Critical** | Always, no exceptions |
| TDD: different assignees | **Preferred** | One proves bug, one proves fix |

---

## 📂 Reference Index

| Reference | Covers |
|-----------|--------|
| `references/testing/` | Behave setup and rules, Robot Framework, TDD tag system, coverage, mocks, ASV |
| `references/ci-cd/` | All 13 CI jobs, 3 workflows, triggers, required checks, secrets, caching |
| `references/toolchain/` | nox sessions, Pyright, ruff, Hatch, pyproject.toml, pre-commit, Commitizen |
| `references/langchain-langgraph/` | State patterns, node naming, providers, prompts, RxPY, testing with FakeListLLM |
| `references/file-organization/` | Exact directory rules, what goes where, what's prohibited where |
| `references/cli-workflow/` | v3 vs legacy plan lifecycle, ULID format, storage backends, migration |
