Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 68 additions & 58 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,102 +1,112 @@
<!-- cspell:ignore callees pathofbuildingcommunity pathofbuilding -->
<!-- code-review-graph MCP tools -->
## MCP Tools: code-review-graph

**IMPORTANT: This project has a knowledge graph. ALWAYS use the
code-review-graph MCP tools BEFORE using Grep/Glob/Read to explore
the codebase.** The graph is faster, cheaper (fewer tokens), and gives
you structural context (callers, dependents, test coverage) that file
This project may have a knowledge-graph MCP server (`code-review-graph`)
configured. **When its tools are available in the session, prefer them over
Grep/Glob/Read for exploration** — they are faster, cheaper (fewer tokens),
and give structural context (callers, dependents, test coverage) that file
scanning cannot.

### When to use graph tools FIRST
### When to use graph tools first

- **Exploring code**: `semantic_search_nodes` or `query_graph` instead of Grep
- **Understanding impact**: `get_impact_radius` instead of manually tracing imports
- **Code review**: `detect_changes` + `get_review_context` instead of reading entire files
- **Finding relationships**: `query_graph` with callers_of/callees_of/imports_of/tests_for
- **Architecture questions**: `get_architecture_overview` + `list_communities`
- **Planning refactors**: `refactor_tool` for renames and dead code

Fall back to Grep/Glob/Read **only** when the graph doesn't cover what you need.

### Key Tools

| Tool | Use when |
|------|----------|
| `detect_changes` | Reviewing code changes — gives risk-scored analysis |
| `get_review_context` | Need source snippets for review — token-efficient |
| `get_impact_radius` | Understanding blast radius of a change |
| `get_affected_flows` | Finding which execution paths are impacted |
| `query_graph` | Tracing callers, callees, imports, tests, dependencies |
| `semantic_search_nodes` | Finding functions/classes by name or keyword |
| `get_architecture_overview` | Understanding high-level codebase structure |
| `refactor_tool` | Planning renames, finding dead code |

### Workflow

1. The graph auto-updates on file changes (via hooks).
2. Use `detect_changes` for code review.
3. Use `get_affected_flows` to understand impact.
4. Use `query_graph` pattern="tests_for" to check coverage.
If these tools are **not** available in the current session, use the standard
Grep/Glob/Read tools as normal.

---

# Path of Building 2 — Agent Instructions

You are working on a fork of PathOfBuildingCommunity/PathOfBuilding-PoE2, an
offline build planner for Path of Exile 2. The codebase is ~100% Lua (5.1 / LuaJIT).
offline build planner for Path of Exile 2. The codebase is ~100% Lua
(5.1 / LuaJIT). The project's core value is correctly modelling PoE2's stat
math; correctness of numeric calculations outranks everything else.

## Critical rules

1. **Never break numeric calculations.** PoB's value is in correctly modelling
PoE2's stat math. If you touch anything in `src/Modules/Calcs/` or `src/Modules/CalcSections.lua`,
you MUST add or update tests in `spec/System/` that assert specific stat values
within tolerance (±0.01 for DPS, exact for hit point pools).
1. **Never break numeric calculations.** If you touch any
`src/Modules/Calc*.lua` file, you MUST add or update tests in
`spec/System/` that assert specific stat values within tolerance
(±0.01 for DPS, exact for hit point pools).

2. **Modifier parsing is fragile.** `src/Modules/ModParser.lua` is the single most
load-bearing file. Any change requires:
- Adding test cases for the new modifier strings in `spec/System/TestModParser.lua`
- Verifying existing test suite still passes (`docker compose run --rm tests`)
2. **Modifier parsing is fragile.** `src/Modules/ModParser.lua` is the single
most load-bearing file. Any change requires:
- Test cases for the new modifier strings in `spec/System/TestModParser_spec.lua`
- A passing full suite (`docker compose run --rm busted-tests`)

3. **Data file changes need validation.** Game data lives in `src/Data/`. After
modifying any data file, run the data validation tests (`docker compose run --rm tests --tags data`).
3. **Data file changes need validation.** Game data lives in `src/Data/`.
After modifying any data file, run
`docker compose run --rm busted-tests --tags data`.

4. **Lua nil-safety is your responsibility.** Lua does not have a type system.
When you call `someTable.field.subfield`, guard with `someTable and someTable.field and someTable.field.subfield`
or use `rawget`. Nil reference crashes are the #1 source of bug reports in PoB.
4. **Lua nil-safety is your responsibility.** Lua has no type system. Guard
chained accesses (`t and t.field and t.field.sub`). Nil reference crashes
are the #1 source of bug reports in PoB.

5. **Performance matters in calculation hot loops.** Avoid table allocations
inside `Calc:Build*` functions; reuse tables and use local variable caching
for frequently-accessed table fields.
inside per-pass calc code; cache frequently-accessed table fields in locals.

## How to test changes

Tests use Busted with LuaJIT inside a pre-built container
(`ghcr.io/pathofbuildingcommunity/pathofbuilding-tests`). Only Docker (or
Podman) is needed — no local Lua toolchain.

```bash
docker compose run --rm tests # full Busted suite
docker compose run --rm tests --tags builds # build snapshot tests (slow)
docker compose run --rm tests --tags data # data file validation only
docker compose run --rm tests --coverage # with luacov
docker compose run --rm busted-tests # full suite
docker compose run --rm busted-tests --exclude-tags builds,data # unit tests only (what CI calls "unit")
docker compose run --rm busted-tests --tags builds # build snapshot tests (slow)
docker compose run --rm busted-tests --tags data # data file validation only
docker compose run --rm busted-tests --filter="pattern" # single test by describe/it name (Lua pattern)
```

Notes:
- The compose service is named `busted-tests` (not `tests`).
- The compose volume is mounted read-only, so `--coverage` cannot write
`luacov.report.out` through compose. CI uses a plain `docker run` that
bind-mounts only the report file writable (see `.github/workflows/ci.yml`).
- Busted config is in `.busted`: it runs from `src/` with
`HeadlessWrapper.lua` as the helper and discovers specs in `spec/`.
- Baseline on `dev`: **370 successes**, plus two known failures in
`spec/System/TestWard_spec.lua` (Ward regen/bypass not yet implemented).
Don't "fix" those by weakening assertions.

## How to validate before opening a PR

1. All tests pass: `docker compose run --rm tests`
2. Coverage did not drop: compare `luacov.report.out` against main
3. No new luac warnings: `luac -p src/**/*.lua`
4. The commit message follows Conventional Commits (`feat:`, `fix:`, `refactor:`, etc.)
1. Full suite passes: `docker compose run --rm busted-tests`
2. Coverage did not drop: compare `luacov.report.out` against the base branch
3. Commit messages follow Conventional Commits (`feat:`, `fix:`, `refactor:`, …)

## Project structure

- `src/` — main Lua source. Entrypoint is `src/Launch.lua`.
- `src/Modules/Calcs/` — the calculation engine. The most important code in the project.
- `src/Modules/ModParser.lua` — converts modifier strings into structured stat objects.
- `src/Data/` — game data: gems, items, passive tree, base item types.
- `spec/System/` — Busted test suite.
- `runtime/lua/` — extra Lua libraries used at runtime.
- `tests/` — Docker-based test harness.
- `src/Launch.lua` — GUI entry point; loads `src/Modules/Main.lua`, which loads everything else.
- `src/HeadlessWrapper.lua` — headless bootstrap (what the test suite and any scripted use of PoB boots through).
- `src/Modules/Calc*.lua` — the calculation engine, flat files (there is **no** `Calcs/` subdirectory): `Calcs.lua` (public entry), `CalcSetup.lua`, `CalcPerform.lua`, `CalcOffence.lua`, `CalcDefence.lua`, `CalcActiveSkill.lua`, `CalcTriggers.lua`, `CalcMirages.lua`, plus `CalcSections.lua`/`CalcBreakdown.lua` for the breakdown UI.
- `src/Modules/ModParser.lua` — converts modifier text into structured mods; `src/Modules/ModTools.lua` has the `mod()`/`flag()` constructors.
- `src/Classes/` — UI tab classes and the mod storage classes (`ModDB.lua`, `ModList.lua`, `ModStore.lua`).
- `src/Data/` — game data: gems, item bases, uniques, crafting mods. Largely **generated** by `src/Export/` from GGPK files — prefer fixing the exporter over hand-editing structure.
- `src/TreeData/` — passive tree data per game version.
- `spec/System/` — Busted test suite (`*_spec.lua`).
- `runtime/lua/` — bundled Lua libraries available at runtime.
- `docs/` — read `rundown.md`, `calcOffence.md`, `modSyntax.md`, `addingMods.md`, `addingSkills.md` before non-trivial changes.

In `CalcOffence.lua`, attacks run **per-hand passes**: inside a pass the local
`output` is `actor.output.MainHand`/`OffHand` and `globalOutput` is
`actor.output`; hand results are merged with `combineStat`. Misattributing
output to the wrong table is the classic bug — read `docs/calcOffence.md` first.

## Fork rules

1. **NEVER open PRs against the upstream repo** (`PathOfBuildingCommunity/PathOfBuilding-PoE2`). All PRs must target the fork (`jay9297/PathOfBuilding-PoE2`). Upstream sync is done by merging `origin/dev` locally, not via PRs.
1. **NEVER open PRs against the upstream repo** (`PathOfBuildingCommunity/PathOfBuilding-PoE2`). All PRs must target the fork (`jay9297/PathOfBuilding-PoE2`), base branch `dev`.

2. **Default push target is `fork`.** All `git push` and PR operations default to `fork/dev`. The git config enforces this via `remote.pushDefault=fork` and `branch.dev.remote=fork`.

3. **Upstream sync is via local merge, not PR.** To sync with upstream: `git fetch origin && git merge origin/dev` on the local `dev` branch, then push to fork.

4. This fork runs automated AI workflows (`ai-fix.yml` triggered by the `ai-fix` issue label, `ai-review.yml`, `auto-merge.yml`). See "AI Workflow Escape Hatches" in `README.md` for how to control them.
Loading
Loading