Skip to content

Add flexible loadout resolution by slot, exact name, or substring#201

Merged
DiamondDagger590 merged 4 commits into
recodefrom
claude/loadout-custom-names-VBfQY
Mar 12, 2026
Merged

Add flexible loadout resolution by slot, exact name, or substring#201
DiamondDagger590 merged 4 commits into
recodefrom
claude/loadout-custom-names-VBfQY

Conversation

@DiamondDagger590
Copy link
Copy Markdown
Owner

@DiamondDagger590 DiamondDagger590 commented Mar 11, 2026

Summary

Implement a flexible loadout resolution system that allows players to reference loadouts by slot number, exact name, or unique partial name match. This improves the user experience for loadout commands by reducing the need to remember exact slot numbers.

Key Changes

  • New LoadoutResolution sealed interface (LoadoutResolution.java): Represents the result of resolving a player's input string to a loadout with three outcomes:

    • Found: A single loadout was unambiguously resolved
    • Ambiguous: Multiple loadouts matched the input
    • NotFound: No loadout matched the input
  • New resolveLoadout() method in LoadoutHolder: Implements a priority-based resolution chain:

    1. Slot index — if input is a valid integer mapping to an existing slot
    2. Exact name match — case-insensitive comparison against plain-text display names
    3. Substring match — case-insensitive containment check against plain-text display names
    • Strips MiniMessage formatting tags when matching against display names
    • Returns Ambiguous if multiple loadouts match at any step
  • Updated LoadoutEditCommand and LoadoutSetCommand:

    • Changed slot argument parser from IntegerParser to StringParser to accept flexible input
    • Integrated LoadoutResolution to handle all three resolution outcomes
    • Added user-friendly error messages for ambiguous matches
    • Simplified logic by delegating resolution to LoadoutHolder
  • Localization updates (en_commands.yml):

    • Updated error messages to reflect new resolution behavior
    • Added new ambiguous-matches message with <loadout-matches> placeholder
    • Clarified that commands accept slot numbers or names
  • New test suite (LoadoutHolderResolutionTest.java): Comprehensive test coverage with 11 test cases covering:

    • Valid slot number resolution
    • Boundary cases (max slot)
    • Out-of-range slots
    • Exact name matching (case-insensitive)
    • Substring matching (unique and ambiguous)
    • MiniMessage formatting tag stripping
    • Slot index priority over name matches
    • Exact name collisions

Notable Implementation Details

  • The resolution method only considers loadouts with user-set display names for name-based matching
  • Slot index resolution takes priority over name matching, ensuring /loadout set 2 always targets slot 2 even if a loadout name contains "2"
  • Plain-text serialization of MiniMessage-formatted names ensures consistent matching regardless of formatting
  • The Ambiguous result includes the list of matching loadouts for potential future UI enhancements

https://claude.ai/code/session_0137VbcTTRzaaw6Rc4zsZbh2

Summary by CodeRabbit

  • New Features

    • Loadout commands accept slot number, exact name, or partial name; editing without an argument opens the current loadout GUI. Ambiguous inputs list matching loadouts and guide the user.
  • Documentation / Localization

    • Updated loadout command messages to explain matching behavior and include ambiguous-match lists.
  • Tests

    • Added comprehensive tests covering found, ambiguous, and not-found resolution cases.
  • Chores

    • Added an automated AI persona review workflow for PRs.

Loadout commands now accept slot index, exact name, or unique partial
name in addition to the previous integer-only slot argument.

Resolution priority: slot index → exact name match → substring match.
If multiple loadouts match a partial name, the player is shown which
loadouts collide so they can be more specific.

- Add LoadoutResolution sealed interface (Found / Ambiguous / NotFound)
- Add LoadoutHolder.resolveLoadout(String) with MiniMessage tag stripping
- Migrate LoadoutSetCommand and LoadoutEditCommand from IntegerParser to
  StringParser.greedyStringParser() and wire up resolveLoadout
- Add LOADOUT_MATCHES placeholder and two new localization keys
  (ambiguous-matches) for set and edit commands
- Add LoadoutHolderResolutionTest covering all resolution branches

https://claude.ai/code/session_0137VbcTTRzaaw6Rc4zsZbh2
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 11, 2026

Walkthrough

Adds a loadout resolution feature allowing inputs to be resolved by numeric slot, exact name, or substring. Introduces sealed LoadoutResolution (Found, Ambiguous, NotFound), LoadoutHolder.resolveLoadout(String), updates loadout edit/set commands to use resolution flow, adds ambiguous-match localization and tests, and a CI persona-review workflow.

Changes

Cohort / File(s) Summary
Core resolution
src/main/java/us/eunoians/mcrpg/loadout/LoadoutResolution.java, src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java
Adds sealed LoadoutResolution (Found/Ambiguous/NotFound) and LoadoutHolder.resolveLoadout(String) with numeric, exact, and substring matching plus plain-text name extraction and ambiguity handling.
Commands
src/main/java/us/eunoians/mcrpg/command/loadout/LoadoutEditCommand.java, src/main/java/us/eunoians/mcrpg/command/loadout/LoadoutSetCommand.java
Switches slot argument parsing from integer to string. Use resolveLoadout(input) and handle Found/Ambiguous/NotFound paths (open GUI / set slot / send ambiguous/no-match messages). Adds helpers for GUI opening and match-placeholder formatting. Renames getPlaceholders(int)getSlotPlaceholders(int).
Placeholders & localization
src/main/java/us/eunoians/mcrpg/command/CommandPlaceholders.java, src/main/java/us/eunoians/mcrpg/configuration/file/localization/LocalizationKey.java, src/main/resources/localization/english/en_commands.yml
Adds LOADOUT_MATCHES placeholder and two ambiguous-matches localization keys. Updates English messages to reference "slot number or name" and to include ambiguous-match lists via the new placeholder.
Tests
src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java
Adds comprehensive unit tests covering numeric slot resolution (including bounds), exact and case-insensitive name matches, unique substring matches, ambiguous matches, formatting-stripping, slot preference over names, and exact-name collisions.
CI workflow
.github/workflows/ai-persona-review.yml
Adds a GitHub Actions workflow for persona-based AI PR reviews (workflow_run/manual), sparse-checkout persona prompts, persona jobs calling Claude, and posting persona review comments to PRs.
Small enum change
src/main/java/us/eunoians/mcrpg/command/CommandPlaceholders.java
Adds enum constant LOADOUT_MATCHES("loadout-matches").

Sequence Diagram

sequenceDiagram
    participant Player as Player
    participant Command as LoadoutEditCommand / LoadoutSetCommand
    participant Holder as LoadoutHolder
    participant Resolution as LoadoutResolution

    Player->>Command: provide slot-or-name input
    Command->>Holder: resolveLoadout(input)
    
    alt Numeric slot resolved
        Holder->>Resolution: Found(loadout)
        Resolution-->>Command: Found
        Command->>Command: open GUI or set slot
        Command-->>Player: success message
    else Unique name/substring resolved
        Holder->>Resolution: Found(loadout)
        Resolution-->>Command: Found
        Command->>Command: open GUI or set slot
        Command-->>Player: success message
    else Multiple matches
        Holder->>Resolution: Ambiguous(matches)
        Resolution-->>Command: Ambiguous
        Command->>Command: format matches -> `loadout-matches`
        Command-->>Player: ambiguous message with matches
    else No matches
        Holder->>Resolution: NotFound()
        Resolution-->>Command: NotFound
        Command-->>Player: no-match message
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: introducing flexible loadout resolution that supports multiple lookup methods (slot, exact name, substring). It's concise, specific, and clearly reflects the primary objective of this PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/loadout-custom-names-VBfQY

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java`:
- Around line 187-193: The input parsing currently accepts slot numbers <=0
because hasLoadout(int) only enforces an upper bound; update the parsing and
helper so invalid low slots are rejected: in LoadoutHolder.replace the try-block
that parses int slot should check slot >= 1 && slot <= getMaxLoadoutAmount()
before returning new LoadoutResolution.Found(getLoadout(slot)), otherwise return
NotFound; also modify LoadoutHolder.hasLoadout(int) (and any shared slot helper
methods) to enforce the same lower bound (slot >= 1) in addition to the existing
upper bound to prevent other callers (e.g., LoadoutSetCommand) from persisting
impossible active slots.
- Around line 198-206: The loop currently calls getLoadout(slot) which
auto-creates missing loadouts and causes side effects; change it to a read-only
lookup that does not materialize slots (e.g., use an existing non-creating
accessor or directly check the internal map/registry) so only existing loadouts
are inspected. Specifically, in LoadoutHolder replace getLoadout(slot) in this
loop with a non-mutating lookup (for example getLoadoutIfPresent(slot) or
loadouts.get(slot)) and only add to namedLoadouts when that lookup returns a
non-null/Optional and its display name is present.

In `@src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java`:
- Around line 71-101: Add two regression tests in LoadoutHolderResolutionTest
targeting LoadoutHolder.resolveLoadout(String): one that calls
resolveLoadout("0") and resolveLoadout("-1") and asserts the result is an
instance of LoadoutResolution.NotFound (verifying lower-bound handling), and
another that attempts a name-based lookup with a non-matching string and then
asserts the holder's observable state (e.g., currently selected loadout slot or
loadout list via mcRPGPlayer.asSkillHolder() / holder) remains unchanged after
the NotFound result; use the existing patterns from
resolveLoadout_returnsNotFound_whenSlotExceedsMax and
resolveLoadout_returnsFound_whenInputIsValidSlotNumber to locate method names
and assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dc9f4cbd-1e54-4f08-ad68-38b6a851c229

📥 Commits

Reviewing files that changed from the base of the PR and between 41cab19 and 0360c5a.

📒 Files selected for processing (8)
  • src/main/java/us/eunoians/mcrpg/command/CommandPlaceholders.java
  • src/main/java/us/eunoians/mcrpg/command/loadout/LoadoutEditCommand.java
  • src/main/java/us/eunoians/mcrpg/command/loadout/LoadoutSetCommand.java
  • src/main/java/us/eunoians/mcrpg/configuration/file/localization/LocalizationKey.java
  • src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java
  • src/main/java/us/eunoians/mcrpg/loadout/LoadoutResolution.java
  • src/main/resources/localization/english/en_commands.yml
  • src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java

Comment thread src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java Outdated
Comment thread src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/ai-persona-review.yml:
- Around line 197-209: The workflow step uses an unverified model name
("claude-sonnet-4-6") and pipes the curl output silently which can hide
failures; update the payload construction to derive the model from a validated
env var (e.g., ANTHROPIC_MODEL) or confirm the exact model string, and add
explicit error handling around the curl/jq commands (check curl/JQ exit codes,
capture and log response errors, and fail the job on non-2xx responses) so
failures are visible; specifically modify the JSON payload where "model":
"claude-sonnet-4-6" is set, and wrap the curl | jq pipeline used before gh pr
comment to detect errors and output a clear error message instead of producing
an empty comment.
- Around line 171-183: The workflow step hardcodes an unverified model name
("claude-sonnet-4-6") and silently proceeds on failures; update the payload so
the model is sourced from a validated variable (e.g., MODEL or ANTHROPIC_MODEL)
or confirm the exact supported model name, and add robust error handling around
the curl/jq pipeline by checking the curl/http exit status and the response for
errors before writing comment.md and running gh pr comment; specifically modify
the JSON payload construction that contains "model": "claude-sonnet-4-6" and add
checks after the curl invocation (and before jq/gh calls) to detect non-2xx
responses or missing .content[0].text, log or write the API error to comment.md,
and fail the step when appropriate.
- Around line 145-157: The workflow step uses a hard-coded model name
"claude-sonnet-4-6" and pipes the curl response into jq without checking for
failures, so update the step to validate or parameterize the model name (replace
the literal "claude-sonnet-4-6" with a workflow input or environment variable
and verify it before the call) and add explicit error handling around the curl
call (check HTTP status, capture curl exit code/response on failure, and fail
the job or write a clear error message instead of producing an empty comment);
locate the block building the JSON payload and the curl invocation (the lines
constructing "model": "claude-sonnet-4-6", the curl -sf
https://api.anthropic.com/v1/messages call, and the subsequent jq -> gh pr
comment pipeline) and modify them so failures are detected and surfaced and the
model name is configurable/validated.
- Around line 115-131: The workflow currently streams pr.diff into the jq
payload without guarding against huge diffs; before the jq invocation (the run
block that builds the JSON with --rawfile prompt
.claude/commands/review-gui-ux.md --rawfile diff pr.diff and posts to the
Anthropiс API), add a size check that computes DIFF_SIZE from pr.diff, compares
it to a MAX_DIFF_SIZE constant, and when over the limit truncates pr.diff into a
temp file (e.g., pr.diff.truncated), appends a short "[Diff truncated due to
size...]" note, and then use that truncated file as the --rawfile diff input (or
set DIFF_FILE variable and pass that to jq) so the constructed payload cannot
exceed the model token/context limits.
- Around line 66-74: The script uses a variable named "test" which shadows the
shell builtin test; rename this variable (e.g., to "is_test" or "tests_changed")
everywhere it's declared and referenced in the while-loop and after the loop,
and update any jq or downstream uses that check this variable's value
accordingly; keep the other flags (gui, config, api) unchanged and ensure all
occurrences of "test" in the file and in the jq command are replaced with the
new name to avoid ambiguity with the shell builtin.
- Around line 119-131: The current pipeline pipes the Anthropic response through
jq and overwrites comment.md without handling non-200 or error-shaped responses;
update the shell block that builds and posts the request (the curl + jq ->
comment.md and gh pr comment steps) to capture HTTP status and raw body, check
for HTTP errors or a JSON "type":"error" payload before extracting
.content[0].text, and write a meaningful diagnostic into comment.md on failure
(include raw response or error.message), then only call gh pr comment when a
valid review body is present; reference the existing curl invocation, the jq
extraction of .content[0].text, the temporary comment.md output, and the gh pr
comment invocation so the check is inserted between those steps.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: adcd8eff-31cc-4148-9ffc-c56661647ea0

📥 Commits

Reviewing files that changed from the base of the PR and between 0360c5a and f56c90d.

📒 Files selected for processing (1)
  • .github/workflows/ai-persona-review.yml

Comment thread .github/workflows/ai-persona-review.yml Outdated
Comment thread .github/workflows/ai-persona-review.yml
Comment thread .github/workflows/ai-persona-review.yml Outdated
Comment thread .github/workflows/ai-persona-review.yml Outdated
Comment thread .github/workflows/ai-persona-review.yml Outdated
Comment thread .github/workflows/ai-persona-review.yml Outdated
…ona review workflow

- hasLoadout(int) now enforces slot >= 1, preventing slot 0 and negatives
  from being treated as valid loadout slots
- resolveLoadout name-matching loop now iterates loadouts.values() directly
  instead of calling getLoadout(slot), which was auto-creating empty Loadout
  objects for every slot just to check for display names
- Add regression tests: slot 0, slot -1 -> NotFound; name resolution with
  no match leaves getCurrentLoadoutSlot() unchanged
- Workflow: rename 'test' bash var to 'tests_changed' (shadows shell builtin)
- Workflow: pull model name into job-level ANTHROPIC_MODEL env var
- Workflow: add shared claude-helper.sh with explicit HTTP status and
  .content[0].text checks so failures surface as ::error:: annotations
- Workflow: add diff truncation step (128 KB cap) before persona steps

https://claude.ai/code/session_0137VbcTTRzaaw6Rc4zsZbh2
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java (1)

129-130: ⚠️ Potential issue | 🟠 Major

Clamp resolution to configured slot bounds, not raw map contents.

hasLoadout() still treats any preexisting backing-map key as valid, and the name pass now iterates every loadouts.values() entry without checking Loadout#getLoadoutSlot(). If a player already has legacy slot 0/-1 data or MAX_LOADOUT_AMOUNT is lowered, resolveLoadout() can surface impossible name matches or trip SelectedLoadoutAboveMaxException on numeric input.

🔧 Minimal hardening
 public boolean hasLoadout(int loadoutSlot) {
-    return loadoutSlot >= 1 && (loadouts.containsKey(loadoutSlot) || loadoutSlot <= getMaxLoadoutAmount());
+    return loadoutSlot >= 1 && loadoutSlot <= getMaxLoadoutAmount();
 }
 ...
 List<Loadout> namedLoadouts = new ArrayList<>();
 for (Loadout loadout : loadouts.values()) {
-    if (loadout.getDisplay().getDisplayName().isPresent()) {
+    int slot = loadout.getLoadoutSlot();
+    if (slot >= 1 && slot <= getMaxLoadoutAmount()
+            && loadout.getDisplay().getDisplayName().isPresent()) {
         namedLoadouts.add(loadout);
     }
 }

Also applies to: 198-205

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java` around
lines 129 - 130, hasLoadout currently validates by checking the backing map keys
directly which allows legacy/invalid slots (e.g., 0 or negative) and name-based
resolution iterates loadouts.values() without verifying each
Loadout#getLoadoutSlot(), causing impossible matches or
SelectedLoadoutAboveMaxException when max slots change. Fix hasLoadout to ensure
loadoutSlot is between 1 and getMaxLoadoutAmount() and that the resolved loadout
itself (use getLoadout(loadoutSlot) or check loadouts.get(loadoutSlot) != null
AND its getLoadoutSlot() is within bounds); update resolveLoadout/name-lookup
(the method resolveLoadout) to only consider entries whose
Loadout#getLoadoutSlot() is within 1..getMaxLoadoutAmount() (and reject
legacy/negative slots) so name and numeric resolution are clamped to configured
slot bounds.
src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java (1)

211-220: ⚠️ Potential issue | 🟡 Minor

This regression still misses the old side effect.

The buggy lookup path materialized missing loadouts without touching currentLoadout, so asserting only getCurrentLoadoutSlot() would still pass if that regression came back. Please assert the backing loadout collection is unchanged instead, e.g. by constructing LoadoutHolder with a shared Map<Integer, Loadout> and comparing size() before/after the lookup.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java`
around lines 211 - 220, The test currently only asserts getCurrentLoadoutSlot(),
which won't catch regressions that mutate the backing loadout collection; update
the test to construct the LoadoutHolder with a shared Map<Integer, Loadout>
(e.g. create a Map, pass it into the LoadoutHolder/constructor or factory used
in the test), capture its size before calling
holder.resolveLoadout("nonexistent"), then after asserting result is instance of
LoadoutResolution.NotFound and that getCurrentLoadoutSlot() is unchanged, also
assert the backing map's size is unchanged (compare size() before/after) to
ensure no loadouts were added/removed by resolveLoadout.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/ai-persona-review.yml:
- Around line 60-65: Update the curl invocation that sets HTTP_CODE to be
resilient: replace the `-s` flag with `-sS` to surface curl errors, add
`--connect-timeout 10` and `--max-time 120` to impose connection and total
request timeouts, and keep the rest of the command that writes to response.json
and reads payload.json unchanged; additionally, set a job-level
`timeout-minutes: 10` in the GitHub Actions job to provide a workflow-level
backstop.

In `@src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java`:
- Around line 187-194: The current slot-first logic in LoadoutHolder (the
Integer.parseInt(input) block using hasLoadout and returning
LoadoutResolution.NotFound) prematurely returns NotFound when a numeric input
parses but the slot is invalid; change it so that after parsing the slot you
only return new LoadoutResolution.Found(getLoadout(slot)) when hasLoadout(slot)
is true, but do not return NotFound on a failed slot check—allow execution to
fall through to the subsequent exact and substring name matching logic (keep the
NumberFormatException catch as-is). Ensure references to hasLoadout, getLoadout,
and LoadoutResolution.Found/NotFound are preserved and used as described.
- Around line 240-243: The getPlainDisplayName method is directly calling
McRPG.getInstance().getMiniMessage().deserialize(...) which bypasses the
project's localization pipeline; change this to route the display name
conversion through the localization manager (use the localization
service/component used elsewhere) so that
Loadout->getDisplay()->getDisplayName() is passed into the LocalizationManager
(or equivalent) and then serialized with
PlainTextComponentSerializer.plainText().serialize(...) — update
getPlainDisplayName to call the localization manager's parse/resolve method
instead of McRPG.getInstance().getMiniMessage().deserialize to produce the plain
text string.

---

Duplicate comments:
In `@src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java`:
- Around line 129-130: hasLoadout currently validates by checking the backing
map keys directly which allows legacy/invalid slots (e.g., 0 or negative) and
name-based resolution iterates loadouts.values() without verifying each
Loadout#getLoadoutSlot(), causing impossible matches or
SelectedLoadoutAboveMaxException when max slots change. Fix hasLoadout to ensure
loadoutSlot is between 1 and getMaxLoadoutAmount() and that the resolved loadout
itself (use getLoadout(loadoutSlot) or check loadouts.get(loadoutSlot) != null
AND its getLoadoutSlot() is within bounds); update resolveLoadout/name-lookup
(the method resolveLoadout) to only consider entries whose
Loadout#getLoadoutSlot() is within 1..getMaxLoadoutAmount() (and reject
legacy/negative slots) so name and numeric resolution are clamped to configured
slot bounds.

In `@src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java`:
- Around line 211-220: The test currently only asserts getCurrentLoadoutSlot(),
which won't catch regressions that mutate the backing loadout collection; update
the test to construct the LoadoutHolder with a shared Map<Integer, Loadout>
(e.g. create a Map, pass it into the LoadoutHolder/constructor or factory used
in the test), capture its size before calling
holder.resolveLoadout("nonexistent"), then after asserting result is instance of
LoadoutResolution.NotFound and that getCurrentLoadoutSlot() is unchanged, also
assert the backing map's size is unchanged (compare size() before/after) to
ensure no loadouts were added/removed by resolveLoadout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 01f095eb-8635-44b8-b37e-67102b5fe139

📥 Commits

Reviewing files that changed from the base of the PR and between f56c90d and 205f291.

📒 Files selected for processing (3)
  • .github/workflows/ai-persona-review.yml
  • src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java
  • src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java

Comment thread .github/workflows/ai-persona-review.yml Outdated
Comment thread src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java
Comment thread src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java
…d curl resilience

- resolveLoadout: remove premature NotFound after a numeric input fails the
  slot check; execution now falls through to name matching so loadouts whose
  display name happens to be a number (e.g. '5' when max is 3) are reachable
- resolveLoadout name loop: filter loadouts.values() to only entries whose
  slot is within 1..getMaxLoadoutAmount(), guarding against stale map entries
  left behind when the configured max slot count is lowered
- Add LoadoutHolder.getLoadedLoadoutCount() — returns loadouts.size() without
  auto-creating entries; used by tests to assert no side-effect mutation
- Strengthen state-unchanged test to also assert getLoadedLoadoutCount() is
  unchanged, catching any future re-introduction of the auto-create side-effect
- Add test: numeric input beyond max falls through and matches by name
- Workflow: add timeout-minutes: 10 at job level as a backstop
- Workflow curl: replace -s with -sS (surfaces transport errors), add
  --connect-timeout 10 and --max-time 120 to prevent indefinite hangs

https://claude.ai/code/session_0137VbcTTRzaaw6Rc4zsZbh2
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/ai-persona-review.yml:
- Around line 54-67: The jq payload construction can fail but the script always
proceeds to curl; after the jq invocation that writes payload.json (using
--rawfile prompt "$prompt_file" and pr.diff), check jq's exit status and that
payload.json is non-empty, and if either check fails log an error referencing
payload.json and the prompt_file and exit non-zero before running the curl that
sets HTTP_CODE; ensure the failure path returns a non-zero exit code so the
workflow fails fast.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 40f4ea15-90a1-4765-9b45-b885fad81cff

📥 Commits

Reviewing files that changed from the base of the PR and between 205f291 and fdd87a9.

📒 Files selected for processing (3)
  • .github/workflows/ai-persona-review.yml
  • src/main/java/us/eunoians/mcrpg/entity/holder/LoadoutHolder.java
  • src/test/java/us/eunoians/mcrpg/loadout/LoadoutHolderResolutionTest.java

Comment thread .github/workflows/ai-persona-review.yml
@DiamondDagger590 DiamondDagger590 merged commit 5176750 into recode Mar 12, 2026
3 checks passed
@DiamondDagger590 DiamondDagger590 deleted the claude/loadout-custom-names-VBfQY branch March 12, 2026 03:17
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.

2 participants