diff --git a/AGENTS.md b/AGENTS.md index 114af39895..4218bde664 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,102 +1,112 @@ + ## 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. diff --git a/CLAUDE.md b/CLAUDE.md index 9645daa7d2..f0a3601820 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,94 +1,153 @@ - +# CLAUDE.md + + + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + ## 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 -scanning cannot. +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, and give +structural context (callers, dependents, test coverage): + +- `semantic_search_nodes` / `query_graph` — find code, trace callers/callees/imports/tests +- `get_impact_radius` / `get_affected_flows` — blast radius of a change +- `detect_changes` + `get_review_context` — risk-scored code review with snippets +- `get_architecture_overview` + `list_communities` — high-level structure +- `refactor_tool` — plan renames, find dead code + +If these tools are **not** available in the current session, use the standard +Grep/Glob/Read tools as normal. + +## Project overview + +A fork of PathOfBuildingCommunity/PathOfBuilding-PoE2 — an 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. + +## Commands + +Tests use [Busted](https://lunarmodules.github.io/busted/) with LuaJIT inside +a pre-built container (`ghcr.io/pathofbuildingcommunity/pathofbuilding-tests`). +No local Lua toolchain is needed — only Docker (or Podman). + +```bash +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 works around this with 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. + +CI (`.github/workflows/ci.yml`) runs three matrix suites on PRs to `dev`: +unit (`--exclude-tags builds,data`), builds, and data — plus a coverage job. + +## Architecture + +### Entry points + +- `src/Launch.lua` — GUI entry point (SimpleGraphic-based desktop app). + It loads `src/Modules/Main.lua`, which loads everything else. +- `src/HeadlessWrapper.lua` — headless bootstrap that stubs all rendering + callbacks so PoB runs under a plain Lua interpreter. This is what the test + suite boots through, and the model for any scripted/automated use of PoB. +- `runtime/lua/` — bundled Lua libraries available at runtime. -### When to use graph tools FIRST +### The modifier system (the heart of PoB) -- **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` +Everything a character "has" is a **mod**: `mod(Name, Type, Value, source, modFlags, keywordFlags, ...tags)`. -Fall back to Grep/Glob/Read **only** when the graph doesn't cover what you need. +- `src/Modules/ModParser.lua` — converts modifier *text* (from items, passive + nodes, etc.) into structured mods via Lua patterns. The single most + load-bearing file in the project. +- `src/Modules/ModTools.lua` — the `mod()`/`flag()` constructors. +- `src/Classes/ModDB.lua`, `ModList.lua`, `ModStore.lua` — storage and lookup + for mods, with summing/flag-matching semantics (`BASE`, `INC`, `MORE`, + `OVERRIDE`, `FLAG` mod types). +- `src/Data/SkillStatMap.lua` — maps skill gem stats onto mods (same syntax, + source auto-filled). +- `src/Data/Global.lua` — `ModFlag`/`KeywordFlag` bitflag definitions. -### Key Tools +Read `docs/modSyntax.md` and `docs/addingMods.md` before touching any of this. -| 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 | +### The calculation pipeline -### Workflow +Calc engine files live flat in `src/Modules/` (there is **no** `Calcs/` +subdirectory): -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. +- `Calcs.lua` — public entry (`calcs.buildOutput`, `calcs.calcFullDPS`, node/misc calculators used by the UI for "what-if" diffs). +- `CalcSetup.lua` — builds the calculation environment: collects mods from tree, items, skills into per-actor ModDBs. +- `CalcPerform.lua` — orchestrates a full calculation pass (`calcs.perform`). +- `CalcOffence.lua` — DPS. 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 here — read `docs/calcOffence.md` first. +- `CalcDefence.lua` — life/ES/mana pools, mitigation, EHP. +- `CalcActiveSkill.lua`, `CalcTriggers.lua`, `CalcMirages.lua` — skill setup, trigger rates, mirage actors. +- `CalcSections.lua` + `CalcBreakdown.lua` — definitions for the Calcs tab breakdown UI. ---- +`Build.lua` (a Module) ties the tabs together; UI tab classes +(`CalcsTab`, `ItemsTab`, `TreeTab`, …) live in `src/Classes/`. -# Path of Building 2 — Agent Instructions +### Game data -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). +- `src/Data/` — gems (`Gems.lua`, `Skills/`), item bases (`Bases/`), uniques, + mods for crafting (`Mod*.lua`), bosses, minions. +- `src/TreeData/` — passive tree data per game version. +- `src/Export/` — scripts that regenerate `src/Data/` from the game's GGPK + files. Data files are largely **generated** — prefer fixing the exporter or + following the existing generated format over hand-editing structure. +- `src/GameVersions.lua` — supported game version constants. + +### Documentation worth reading before non-trivial changes + +`docs/rundown.md` (file-by-file tour), `docs/calcOffence.md`, +`docs/modSyntax.md`, `docs/addingMods.md`, `docs/addingSkills.md`. ## 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.** Any `ModParser.lua` change requires test + cases for the new modifier strings in `spec/System/TestModParser_spec.lua` + and a passing full suite. -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.** After modifying anything in + `src/Data/`, 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.** No type system. Guard chained + accesses (`t and t.field and t.field.sub`). Nil reference crashes are the + #1 source of bug reports. 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. - -## How to test changes + inside per-pass calc code; cache frequently-accessed table fields in locals. -```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 -``` +## Validation before opening a PR -## How to validate before opening a PR +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:`, …) -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.) +## Fork & PR rules -## Project structure +1. **NEVER open PRs against the upstream repo** + (`PathOfBuildingCommunity/PathOfBuilding-PoE2`). All PRs target this fork + (`jay9297/PathOfBuilding-PoE2`), base branch `dev`. Upstream sync is done + by merging upstream's `dev` locally, not via PRs. -- `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. +2. 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.