Skip to content

PMX: Restructure obtainment, add format skills, tighten CI - #6

Merged
codebend3r merged 14 commits into
mainfrom
obtain-structural-cleanup
Aug 22, 2026
Merged

PMX: Restructure obtainment, add format skills, tighten CI#6
codebend3r merged 14 commits into
mainfrom
obtain-structural-cleanup

Conversation

@codebend3r

@codebend3r codebend3r commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Behavior-preserving structural cleanup of the obtainment feature — one commit per finding from a code-quality audit of #5. The branch also picked up the repo's commit/PR format skills, a CI pass, and a husky fix; see Notes on that scope.

Obtainment restructure

  • generations.ts now owns REGIONS + REGION_OF_VERSION_GROUP; ObtainMethods.tsx drops VG_REGION, REGION_ORDER, REGION_LABELS, and GAMES_BY_REGION derives from it
  • kills the getGen(gen).region fallback — a second source of truth that was wrong for every remake, which is why VG_REGION existed as a patch table
  • useObtainData returns one ObtainState union (idle / loading / error / ready), replacing {data, loading, error} plus the view's compensating loading || (enabled && !data && !error)
  • ObtainMethods goes from five props to two; the ready branch splits into ObtainRegions so the data is non-null by type
  • Set<string> | null expansion state becomes plain useState<Set<string>> — the default region is known at mount inside ObtainRegions
  • CONDITION_PREFIXES, conditionMeta's if-chain, and LEGEND_CONDITIONS collapse into one CONDITION_FAMILIES table; the legend derives from it instead of restating icon and color by hand
  • RODS deleted in favor of ROD_METHODS, exported from @/obtain/pokeapi and shared by the build parser and the chip renderer
  • display vocabulary moves to src/obtain/labels.ts; ObtainMethods.tsx drops from 410 lines to 176 of rendering
  • ObtainMethod derives from a new OBTAIN_METHODS list and isObtainFile validates game and entry shape against it — the renderer previously indexed METHOD_LABEL on unvalidated strings
  • dead clause dropped from encountersToEntries: nothing in METHOD_MAP maps to 'special', so the second half of method === 'special' && !METHOD_MAP[slug] could never be false when the first was true

Commit and PR format skills

  • CLAUDE.md has mandated a commit-format skill since e1a3761, but no file existed at the path it named — the rule was unenforceable
  • both skills now live in .claude/skills/, not ~/.claude/skills/, so they travel with the repo
  • the commit skill is named commit-format, not pokemax-commit-format — the repo name is redundant inside the repo
  • its rules were measured from the last 60 commits: 188 body bullets, 0 ending in a period, 0 prose lines, subject median 53 chars
  • create-pull-request fixes the body contract: a lede, then per-subsystem sections, then verification and notes
  • both mandate a PMX: repo-code prefix on every commit subject and PR title, following the sister repo's CJR: form
  • both require -F - / --body-file over -m / --body: backticks inside a double-quoted shell string are executed, and this repo backticks nearly every identifier
  • CLAUDE.md previously pointed the commit skill at PR titles too; that bullet now scopes to commits, and a second bullet hands PRs to create-pull-request
  • AGENTS.md pointed at ~/.Codex/skills/pokemax-commit-format/SKILL.md, which never existed; it now names the repo-local file

GitHub Actions

  • ci.yml ran on both push: branches: ['**'] and pull_request, so every commit on a PR branch triggered two identical full runs — push now scopes to main
  • bun-version: latest made CI non-deterministic; both workflows pin 1.4.0, matching the local toolchain and the existing .nvmrc / engines pinning style
  • actions/cache@v4 added on ~/.bun/install/cache, keyed by bun.lock
  • ci.yml gains permissions: contents: read; it inherited the repo default and needs no write scope
  • timeout-minutes on all three jobs, workflow_dispatch on ci.yml, and the concurrency group now keys on github.workflow
  • workflow-level names gain emoji to match the jobs and steps, which already had them

Husky fix

  • .husky/pre-commit blocked any commit staging only .md, .svg, or .png
  • oxfmt exits 2 when no staged file is a type it formats, and husky runs hooks under set -e, so the bare unformatted=$(…) assignment inherited that 2
  • || true on the assignment restores the intent: nothing formattable means nothing to reformat
  • latent since the hook was written; it surfaced only once bun install recreated .husky/_ and the hooks began running at all

Verification

  • bun run system-check green — oxfmt --check clean on 128 files, tsc -b silent, oxlint silent, vite build ok
  • 143 tests passed, 2 skipped, across 29 files; three new test files (regions, obtainLabels, obtainTypes)
  • isObtainFile: all 1351 files in public/obtain/ still pass the tightened guard
  • CONDITION_FAMILIES: old vs new implementations diffed over all 341 distinct condition slugs in the dataset — 0 differences in label, icon, or color
  • no public/obtain/ regeneration and no data changes
  • history rewrite verified content-neutral: git diff between the pre-rewrite tag and the rewritten tip is empty
  • the workflow changes cannot be verified until they run on GitHub; both files were parsed and every job and step confirmed named

Notes

  • This branch now spans two unrelated subsystems. The obtainment restructure and the tooling work (skills, CI, husky, CLAUDE.md) share no files. Splitting the tooling commits onto their own branch would review better; left as one branch because the tooling was requested while this one was open.
  • all 14 commits were rewritten to carry the PMX: prefix and the branch force-pushed, with explicit approval
  • revised one audit finding mid-flight: the audit said to reuse useExpandedRegions for the region collapse state, but that hook persists to localStorage, so one Pokémon's open region would carry onto the next, whose regions are a different set. Plain useState instead, with a comment saying why.
  • deploy.yml keeps its own test step even though CI now covers mainworkflow_dispatch can ship a commit CI never gated
  • CI checks were not split into parallel jobs: each job would re-install dependencies, and for a suite this size the sequential single job is cheaper in minutes and wall-clock
  • GameId 'lets-go' is the one id that isn't its PokéAPI version-group slug; that divergence is now one named entry in trainers.ts instead of spread across region tables. Renaming it would touch trainer data, routes, and stored prefs — left alone.
  • adjacent, not fixed here: scripts/ is in no tsconfig include, so build-obtain-data.mts is never type-checked by tsc -b
  • docs/superpowers/plans/2026-07-31-obtainment-methods.md still cites the old skill name and is left alone — it records what was true when it was written
  • this branch and PR exist because they were explicitly requested; CLAUDE.md otherwise says commit straight to main

@netlify

netlify Bot commented Aug 21, 2026

Copy link
Copy Markdown

Deploy Preview for thepokemax ready!

Name Link
🔨 Latest commit 9c4fa66
🔍 Latest deploy log https://app.netlify.com/projects/thepokemax/deploys/6a8a051e400e890008f0cea0
😎 Deploy Preview https://deploy-preview-6--thepokemax.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codebend3r
codebend3r force-pushed the obtain-structural-cleanup branch from f4eb6c8 to d62f8b0 Compare August 21, 2026 13:19
codebend3r added a commit that referenced this pull request Aug 22, 2026
- PR bodies drifted in shape across `#3`, `#5`, and `#6` — bullets in two,
  bold-lead paragraphs in the third, section names picked per PR
- skill fixes the contract: lede, `## What changed`, `## Verification`,
  `## Notes`, with per-subsystem sections when the change spans several
- bullets are the default form; prose is confined to the lede
- title rules mirror the commit-subject style already in `git log`
- `--body-file` is required, not preferred: backticks inside a
  double-quoted `--body` string are executed by the shell
- carries `CLAUDE.md`'s zero-AI-attribution rule into PR titles and bodies
@codebend3r codebend3r changed the title Restructure the obtainment feature without changing behavior Restructure obtainment, add format skills, tighten CI Aug 22, 2026
@codebend3r codebend3r changed the title Restructure obtainment, add format skills, tighten CI PMX: Restructure obtainment, add format skills, tighten CI Aug 22, 2026
- `METHOD_MAP` has no entry mapping to `'special'`
- so `method === 'special'` already implies `!METHOD_MAP[slug]`
- second clause could never be false when the first was true
- derive `ObtainMethod` from a new `OBTAIN_METHODS` list — one vocabulary
- guard now checks `games[].gen`/`versionGroup`/`versions`/`entries`
- rejects entries whose `method` is not a known method
- previously `ObtainMethods.tsx` indexed `METHOD_LABEL` on unvalidated strings
- verified all 1351 files in `public/obtain/` still pass
- new `REGIONS` + `REGION_OF_VERSION_GROUP` map every version group to its setting
- `GAMES_BY_REGION` now derives from `REGIONS` instead of restating it
- `ObtainMethods.tsx` drops `VG_REGION`, `REGION_ORDER`, `REGION_LABELS`
- kills the `getGen(gen).region` fallback, which was wrong for every remake
  and was the reason `VG_REGION` had to exist as a patch table
- Hisui's note comes from `REGIONS`, not a one-entry label override
- rename `crt-obtain-gen`/`crt-obtain-gen-toggle` — the rows are regions, not gens
- new `regions.test.ts` pins coverage and ordering against `GENERATIONS`
- `useObtainData` returns `ObtainState` — `idle` / `loading` / `error` / `ready`
- the enabled-but-not-yet-started frame now reports `loading` from the hook
- drops the compensating `loading || (enabled && !data && !error)` in the view
- drops the stale-id reconciliation — `settled.id` scopes failures to their id
- `ObtainMethods` takes `state` + `currentGen`, down from five props
- `enabled` no longer passed twice from `PokemonCard.tsx`
- ready branch split into `ObtainRegions` so the data is non-null by type
- loading/idle tests move to `useObtainData.test.ts` where the inputs live
- `Set<string> | null` existed only because the default region was unknown
  until the file loaded — inside `ObtainRegions` it is known at mount
- plain `useState<Set<string>>` with a lazy initializer replaces it
- `toggle` no longer closes over a render-scoped `expanded` fallback
- not routed through `useExpandedRegions` on purpose: its persisted value
  would carry one Pokémon's open region onto the next
- `CONDITION_PREFIXES`, `conditionMeta`'s if-chain, and `LEGEND_CONDITIONS`
  all dispatched on the same slug families — a new family meant three edits
- one table now carries prefix, icon, color, label strip, and legend gloss
- `LEGEND_CONDITIONS` derives from it instead of restating icon/color by hand
- `RODS` deleted — `ROD_METHODS` exported from `@/obtain/pokeapi` and shared
  by the build parser and the chip renderer
- diffed old vs new over all 341 condition slugs in `public/obtain/` — identical
- new test pins one chip per family, including the unknown-slug fallback
- `ObtainMethods.tsx` was 410 lines, ~250 of them static label tables
- `METHOD_LABEL`, `METHOD_COLOR`, `CONDITION_*`, `LEGEND_*`, `levelRate`,
  `prettyCondition`, `conditionMeta` now live beside the domain they describe
- component drops to 176 lines of rendering
- `regionLabel` takes `RegionMeta` instead of an ad-hoc object shape
- `LEGEND_CONDITIONS` uses `flatMap` so it narrows without `?? ''` padding
- new `obtainLabels.test.ts` pins label/color/gloss coverage to `OBTAIN_METHODS`
- PR bodies drifted in shape across `#3`, `#5`, and `#6` — bullets in two,
  bold-lead paragraphs in the third, section names picked per PR
- skill fixes the contract: lede, `## What changed`, `## Verification`,
  `## Notes`, with per-subsystem sections when the change spans several
- bullets are the default form; prose is confined to the lede
- title rules mirror the commit-subject style already in `git log`
- `--body-file` is required, not preferred: backticks inside a
  double-quoted `--body` string are executed by the shell
- carries `CLAUDE.md`'s zero-AI-attribution rule into PR titles and bodies
- line 13 claimed `pokemax-commit-format` governed "PR titles and bodies
  too" — two skills owning PR format is the drift the new skill removes
- that bullet now scopes to commit messages; a new bullet hands PR titles
  and bodies to `create-pull-request`
- both still carry the zero-AI-attribution rule, so narrowing one bullet
  does not open a gap
- `CLAUDE.md` has mandated this skill since `e1a3761` but no file existed
  at the path it named, so the rule was unenforceable
- rules derived by measuring the last 60 commits, not invented: 188 body
  bullets, 0 ending in a period, 0 prose lines, subject median 53 chars
- lands in `.claude/skills/` beside `create-pull-request` rather than
  `~/.claude/skills/` — pokemax skills belong to the repo
- `CLAUDE.md` path updated to match; the `Don't` section reference needed
  no change since it names the skill without a path
- `ci.yml` ran on `push: branches: ['**']` and `pull_request`, so every
  commit on a PR branch triggered two identical full runs
- push now scopes to `main`; `pull_request` covers branch work
- `bun-version: latest` made CI non-deterministic — a bun release could
  break a green tree with no repo change; both workflows pin `1.4.0`,
  matching the local toolchain and the `.nvmrc`/`engines` pinning style
- `actions/cache@v4` on `~/.bun/install/cache`, keyed by `bun.lock`
- `ci.yml` gains `permissions: contents: read`; it inherited the repo
  default and needs no write scope
- `timeout-minutes` on all three jobs so a hung runner cannot burn minutes
- `workflow_dispatch` added to `ci.yml` for manual re-runs
- concurrency group keys on `github.workflow` too, so `ci.yml` and a future
  workflow on the same ref cannot cancel each other
- deploy keeps its own `test` step on purpose — `workflow_dispatch` can
  ship a commit CI never gated
- both skills previously banned prefixes outright, matching the 60 commits
  measured at the time — that rule is now reversed by convention
- `PMX: ` is mandatory on every hand-written commit subject and PR title
- form follows the sister repo's `CJR:` convention: code, colon, one space
- pokemax capitalizes the first word after the prefix; `codebender-portfolio`
  lowercases it, so the two repos differ past the colon
- version bumps take the prefix too — `PMX: 0.3.4`
- `(#5)` squash suffixes still come from GitHub, never typed by hand
- this subject is the first commit written under the new rule
- `oxfmt` exits 2 when no staged file is a type it formats, printing to
  stderr and leaving stdout empty
- husky runs hooks under `set -e`, so the bare `unformatted=$(…)`
  assignment inherited that 2 and aborted the commit
- any commit staging only `.md`, `.svg`, or `.png` was blocked
- `|| true` on the assignment restores the intended behavior: no
  formattable files means nothing to reformat, so the hook exits 0
- latent since the hook was written; surfaced once `bun install` recreated
  `.husky/_` in this worktree and the hooks began running at all
- the skill lives in the pokemax repo, so the repo name in the skill name
  was redundant — `.claude/skills/commit-format/`
- frontmatter `name:` and the `# Commit format` heading follow the path
- `CLAUDE.md` and `AGENTS.md` updated in both the Do and Don't sections
- `AGENTS.md` pointed at `~/.Codex/skills/pokemax-commit-format/SKILL.md`,
  which never existed; it now names the repo-local file like `CLAUDE.md`
- `docs/superpowers/plans/2026-07-31-obtainment-methods.md` still cites the
  old name and is left alone — it records what was true when it was written
@codebend3r
codebend3r force-pushed the obtain-structural-cleanup branch from e1f91a4 to 9c4fa66 Compare August 22, 2026 20:22
@codebend3r
codebend3r merged commit e0e180e into main Aug 22, 2026
5 checks passed
@codebend3r
codebend3r deleted the obtain-structural-cleanup branch August 22, 2026 20:31
@codebend3r
codebend3r restored the obtain-structural-cleanup branch August 22, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant