feat(aa): AA planner — era rules, validation engine, saved plans, .aa export - #176
Merged
Conversation
… export
Era data (aas.db + aa_limits.json):
- Per-xpac node visibility curation: pre-Sentinel's-Fate eras hide class
rows 5-6 and subclass rows 16/19 (verified against live Wuoshi census —
300 max-AA chars have zero spent points beyond those rows). aa_limits
gains a visible_rows column (idempotent migration); xpac_limits returns
it; /api/aa/config exposes it and accepts ?xpac= for era overrides.
- The AA tab hides off-era nodes via the shared filterTreeForEra helper.
- /api/aa/plan-trees resolves a subclass's class/subclass/shadows/heroic
tree ids (shadows + heroic mined from live census — every shadows tree
is named "Shadows" with no class field; a test cross-checks the mapping
against node classifications so a rebuild reshuffle fails loudly).
Planner (character AA tab "Planner" mode):
- Pure validation engine: thresholds count AA points spent (rank × cost),
self-exclusive unlock counters (line/tree/global/parent-rank), the flat
100/tree cap (confirmed in census maxpointsperlevelnode data), separate
adventure/tradeskill pools, and no-stranding removals (refunds re-validate
everything taken). Shadows section gating (5 pts in the section above) is
structural — not in census node data — and lives in the engine.
- Interactive AATree: click spend / right-click refund, locked greying,
unmet requirements shown in the node tooltip and the status line.
- Era dropdown (KoS→DoV): re-plans under any era's cap/trees/rows; the
resolver offers trees the character's census record doesn't carry yet
(e.g. shadows when era-planning TSO on an EoF server).
- Saved plans: users.db aa_plans (owner-scoped in SQL, 20/character,
name profanity-screened, structural payload validation) with always-
minted share slugs; read-only /aa-plan/{slug} share page rendering under
the plan's saved era with split adventure/tradeskill point totals.
- .aa spec export (planner + current AAs + in-game profiles + share page):
the game's own Save/Load XML format, reverse-engineered from a real
export (scripts/dev/Menludiir_templar_dps.aa — all 47 node/tree pairs
match aas.db). Purchase order is emitted by replaying the plan through
the engine so every line is legal when the in-game loader replays it;
unreachable ranks are skipped with a UI warning.
Rendering + fixes:
- Per-node backdrop sprites (bg_sprite.png CSS sprite math mirroring
image/aa_tree.py) — subclass/shadows/heroic trees regain their icon
chrome; class trees unchanged.
- <select> added to the no-Preflight base reset (UA chrome was leaking
into every dropdown; first spotted on the era select).
- 422 handler now jsonable_encodes pydantic errors (field_validator
ValueErrors crashed the response serialiser — latent, first hit by the
aa_plans validators).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The full AA planner stack, user-tested locally across several rounds.
Era rules (data)
visible_rows+ idempotent migration): pre-SF eras hide class rows 5–6 and subclass rows 16/19 — verified against live Wuoshi census (300 max-AA characters, zero spent points beyond those rows). The AA tab hides off-era nodes via the sharedfilterTreeForEra./api/aa/configgainsvisible_rows+ an?xpac=override;/api/aa/plan-treesresolves a subclass's class/subclass/shadows/heroic tree ids (shadows + heroic mined from live census; a test cross-checks the shadows mapping against node classifications so a rebuild reshuffle fails loudly).Planner ("Planner" mode on the character AA tab)
maxpointsperlevelnodedata), separate adventure/tradeskill pools, no-stranding removals, and the structural shadows section gate (5 points in the section above — absent from census node data)./aa-plan/{slug}page rendering under the plan's saved era..aaexport from the planner, the Current AAs view (current + in-game profiles), and the share page. Format reverse-engineered from a real in-game export (committed as the reference sample; all 47 node/tree pairs match aas.db). Purchase order is emitted by replaying the plan through the engine so the in-game loader never jams; unreachable ranks are skipped with a warning.Rendering + fixes
<select>added to the no-Preflight base reset (UA chrome leaked into every dropdown).jsonable_encoders pydantic errors (latent crash, first hit by a raisingfield_validator).Testing
?xpac=, plan-trees resolution + shadows cross-check, aa_plans CRUD/ownership/sharing/validation). Full suite 1602 passed, pyright clean.🤖 Generated with Claude Code