Skip to content

Illusion Temple mini game, rebased on master with the review findings fixed - #974

Open
sven-n wants to merge 18 commits into
masterfrom
claude/pr-893-review-19p1pr
Open

sven-n wants to merge 18 commits into
masterfrom
claude/pr-893-review-19p1pr

Conversation

@sven-n

@sven-n sven-n commented Sep 24, 2026

Copy link
Copy Markdown
Member

Continues @bulgarashi's Illusion Temple work from #893, which has gone quiet. Master moved on quite a bit since that branch was last updated, so this brings it up to date and fixes the findings from the review on #893.

The author's commits are preserved: this branch is a merge of feature/illusion-temple-mini-game into current master, so the history and attribution stay intact. #893 can be closed in favour of this one, or this can be pushed to that branch instead if @bulgarashi would rather keep it — happy either way.

Adapting to master

The mini game code was refactored on master since the branch was written:

  • MiniGameManager — the context factory moved out of GameContext, so the IllusionTemple case was added there instead.
  • MiniGameRewardService — reward granting moved out of MiniGameContext. The temple needs to grant its rewards in two steps (experience when the match ends, so it can be shown in the result packet; the rest only when the player claims it), so GiveRewardsAndGetBonusScoreAsync gained an optional reward filter. Existing callers are unaffected.
  • Winner determination — the temple has a winning team, not a winning player, and the reward success flags classify winners by party. Rather than duplicating the flag logic, MiniGameContext got two overridable predicates, IsWinner and IsInWinningParty, which the reward service now uses. The default implementations are behaviour-preserving for every other mini game; I checked the rewritten conditions against the original boolean expressions for Winner, Loser, WinningParty and WinnerOrInWinningParty.
  • PlayerMapTransitions/spawn gate plug-ins — the branch had already been adapted to these by the author; only GetSpawnGate had to be re-added to MiniGameContext.
  • Migration — AddMiniGameMinimumPlayerCount was renumbered behind AddNetworkObservation, which master added in the meantime, and its model snapshot was refreshed so the migration chain stays consistent.

Review fixes

Character class on the result screen. The conversion packed the evolution step into the upper nibble as internal % 4, which is right for the lines with three tiers but wrong for Magic Gladiator, Dark Lord and Rage Fighter: they have no second class, so their master classes sit at internal step 1 (Duel Master 13, Lord Emperor 17, Fist Master 25) and were sent with a step the client doesn't define. New IllusionTempleCharacterClassTests covers all 18 character classes.

"Event ended" ordering. The Ended state is now sent after the result has been shown. The packet's own documentation says the client closes the event interface on it, and the result dialog's Close button is what triggers the reward request in the first place.

Relic carrier race on pickup. Picking the relic up off the ground claimed the carrier slot with a plain check-then-set, while the statue already used Interlocked.CompareExchange. Both paths now claim it the same way.

Reported experience. The score board's experience was recalculated from the reward definitions, which ignored the server's experience rates and the maximum level. It's now measured from the character's actual experience around the grant.

Enter handler bounds. An ItemSlot below the inventory (i.e. an equipment slot) turned into a large index when cast to byte, pointing at an unrelated slot. It's refused instead.

Skill-end notification. Subscribed after the effect list accepted the effect, so an immediately replaced effect can't report itself as ended before it applied.

Smaller things. Field naming (_camelCase), constant and static-field ordering, file names matching their type names (…Plugin.cs → …PlugIn.cs), the two sub-packet handlers that were missing their [Display] resources, an unused using, and several stale or copy-pasted comments.

Deliberately not in this PR

  • IllusionTempleSkillRequest.TargetObjectIndex is a single byte. Every other client-to-server skill packet encodes the target as a two-byte big-endian id right after the skill id, and the packet's 8 bytes are exactly header + short skill + short target with nothing left for the Distance byte the definition claims. If that's right, the handler reads only the high byte and the two targeted skills (Restraint, Weaken) can't resolve their target. The definition predates this work and I can't verify it without a client capture, so I left it alone rather than guess at a protocol change. Worth one capture of a Restraint cast — if it is a big-endian short, only the XML needs changing; UseSkillAsync already takes a ushort.
  • IllusionTempleHolyItemRelics field lengths. Its Name field has no declared length, so the generator emits both a fixed packet Length and a GetRequiredSize. It works because the view plugin sizes the span exactly, but it should get <Length>10</Length> like PlayerResult.Name did. Left out because I had no way to run the XSLT generation here, and hand-editing generated packet structs seemed worse than leaving a known nit.
  • MiniGameOpeningStateRequestAction still answers "event not implemented yet" for Illusion Temple in its fallback branch. That branch is only reached when the start plug-in is missing or no temple matches the player's level, but the message is stale now and could use a better one.

Testing

No .NET SDK was available in my environment, so I could not build or run the tests — CI is the first real verification. The changes were made against the refactored APIs by reading, and every base-class member the context uses was cross-checked against MiniGameContext. Please treat the CI result as the gate here rather than my word.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UYEj5xw6iAJKEoDX3hyMZh


Generated by Claude Code

bulgarashi and others added 13 commits August 27, 2026 22:32
…ills

Implements the full Illusion Temple event as a team-based PvP mini game:
- Stone Statue (NPC 380) holds a sacred relic; a player talks to it to
  become the carrier, delivers it to his team's storage (383/384) to
  score, and drops it on death or when leaving.
- Two teams (Allied/Illusion Forces), assigned and spawned on game start,
  with a live per-player state update (own team positions, relic carrier,
  remaining time) and an end-of-game result screen.
- A team needs at least 2 points, and more than the opposing team, to be
  declared the winner - matching the original event (a 1:0 finish is a
  draw, like in the reference server).
- Experience is granted automatically to the winning team at game end;
  other reward types (item drops) are only granted once the player
  explicitly claims them (0xBF05), closing the result dialog - mirroring
  the original "click Close to be compensated" flow.
- Skill points (start at 10, cap 90): +1 for killing an enemy player, +2
  for killing a roaming arena monster. They fuel four special skills
  (210 Order of Protection, 211 Restraint, 212 Tracking, 213 Weaken),
  each costing 10 points, requested via a dedicated 0xBF02 packet.
- MiniGameDefinition.MinimumPlayerCount is now admin-configurable (EF
  migration included) instead of hardcoded per event type.
- Fixed a base MiniGameContext bug where players stuck on an event map
  with too few participants were never moved back to safezone.

New server<->client packets: IllusionTempleEventState, HolyItemRelics,
SkillUsageResult, SkillPointUpdate, SkillEnded, RewardRequest handling,
and corrected byte layouts for IllusionTempleState/Result (missing
RelicCarrierId field, wrong array offset, and a 3-byte padding gap in
PlayerResult that the original client's C struct alignment expects).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Registers the periodic mini game start plugin (every 2 hours, matching
the official Webzen server's Illusion Temple schedule) and its game
server state tracking, plus a chat command for game masters to start an
Illusion Temple match on demand for testing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Corrects the statue/guardian/relic-box spawn data on all six temple
maps, verified against a working Season 6 Episode 3 server's spawn
list: two stone statue positions (not three), added the two decorative
team guardian NPCs (381/382), and fixed both relic storage box
coordinates, which were off by one tile.

Adds the 32 roaming "Illusion Sorc. Spirit" arena monster spawns (NPC
386-399, cycling per temple level) to temples 1-5 - temple 6 has none,
matching the reference data.

Also sets each temple's safezone map to Devias explicitly: without it,
a temple's own spawn gate made BaseMapInitializer default the safezone
to the temple map itself, so a player warped to "safezone" (e.g. when
too few players joined) was simply sent back into the arena instead of
actually leaving it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Existing servers won't get the Illusion Temple changes above just from
an EF migration - the mini game definitions, monster/item data and map
spawns are seed data, normally only created on a fresh install. This
update plugin applies all of it to an already-running database instead:

- Fixes the "Illusion Sorcerer Covenant"/"Scroll of Blood" ticket item
  numbers (50/51 were swapped - IllusionTempleInitializer expects the
  ticket at Group 13, Number 51), by correcting the Number field on the
  existing item entities so already-owned instances keep working.
- Adds the sacred relic item (Group 14, Number 64) if missing.
- Adds the 14 arena monster definitions (386-399) and their spawns, the
  corrected statue/guardian/box spawns, and the safezone map fix - all
  matching the fresh-install map data from the previous commit.
- Adds the two special-skill magic effects (210/211).
- Creates the mini game definitions on a database that doesn't have
  Illusion Temple at all yet, or backfills MinimumPlayerCount on ones
  that already do.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers entrance/entry timing, finishing early when too few players
remain, team assignment for even and odd player counts, game start,
the statue/relic pickup-death-pickup loop, scoring for the carrier's
own team vs. the enemy's, and the end-of-game reward flow (experience
granted immediately, an item reward only once claimed).

MiniGameContext auto-starts a real-time countdown on construction
(clamped to at least 30s), far too slow for a test suite, so these
tests build a fully wired IllusionTempleContext and drive its lifecycle
hooks directly via reflection instead of waiting on the real timers.

Extends GameContextTestHelper.CreateGameContext with an optional
IDropGenerator parameter (needed to test item rewards) and a
MaximumLevel default (needed for AddExperienceAsync to actually grant
anything - it no-ops above the configured max level, which defaulted
to 0).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Removed the unused _activeStatue field (only ever written, never
  read) and made the two team spawn coordinate fields readonly, since
  neither is ever reassigned after construction.
- Renamed a local variable in TeleportToStartCoordinatesAsync that was
  shadowing the illusionForcesCoordinates field.
- In the test file: documented why the two reflection calls that bypass
  accessibility are safe (test-only code, hardcoded member names, no
  external input), replaced a switch without a default case with
  if/else, dropped a redundant explicit default-value argument, gave
  the fake IDropGenerator's genuinely unused interface parameters
  discard-style names, and made the test spawn-area helper actually use
  its "number" parameter to build a stable Guid.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The DyingDropsTheRelicAndItCanBePickedUpAgain test was failing
deterministically: the test entered players via TryEnterAsync and the
client map-change handshake, but skipped the WarpToAsync to the event
entrance that EnterMiniGameAction performs in between. Without it the
players stayed on the default map instead of the mini game's own map
instance, so the dropped relic landed on a map the event isn't
subscribed to and OnItemDroppedOnMap - the single place that clears the
relic carrier - never ran. The entry helper now mirrors the real server
flow, and the whole suite passes.

Codacy follow-ups:
- Moved the usings of IllusionTempleContext inside the namespace, as
  the rest of the code base does, and dropped two that were genuinely
  unused. The System.Collections.Concurrent one is kept - it is used by
  the ConcurrentDictionary fields.
- Documented the two reflection helpers with SuppressMessage
  justifications instead of only comments: both are test-only, operate
  on types from this solution, and are passed hardcoded member names.
- Gave the fake IDropGenerator its interface parameter names back and
  justified them at class level - they are mandated by the interface and
  deliberately ignored.
- Added the missing else branch in AwaitResultAsync.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Blocking:
- Added the missing <summary> tag on UpdateVersion.IllusionTempleData
  (the number collision with AddCastleSiegeData resolved itself when the
  branch was rebased - it's 104 now).
- OnObjectRemovedFromMapAsync no longer warps the leaving player: it runs
  from inside WarpToAsync, so warping again nested the warps and left the
  player on two maps with duplicate map-change packets, while also
  bypassing the per-temple safezone. It's now pure state cleanup; leaving
  is done by ClaimRewardAsync and the base class's exit handling.
- ToIllusionTempleEnterResult actually maps its parameter now, instead of
  reporting success for every refusal.
- Item rewards reached only the first winner, because DoesRewardApply
  compares parties and a party is disposed once fewer than two members
  remain. The winner-related predicates moved into overridable
  IsWinner/IsInWinningParty/IsWinnerOrInWinningParty methods, which the
  illusion temple answers by team - so every member of the winning team
  is rewarded.
- The 20 second preparation delay is configurable (PreparationDuration).
  The tests set it to zero, which brings the suite from ~4.8 minutes down
  to ~5 seconds.

Correctness:
- Team mates are spread over consecutive tiles again - the previous code
  incremented a copy of a readonly field, so everyone stacked on one
  tile. Typo in the comment fixed as well.
- Dropped the redundant "player.Party = null", which bypassed
  KickMySelfAsync and left the player in the old party's member array.
- Restraint and Weaken only hit opponents now, and using a special skill
  requires a running event and a living caster.
- The reported experience mirrors what is actually granted, including the
  per-remaining-second reward type.
- Talking to the statue claims the carrier slot atomically, so two
  players can't both walk away with a relic, and the item is only created
  after the inventory-space check succeeds (with the orphan deleted if it
  doesn't).
- The relic is taken away when its carrier leaves, so it can't stay in an
  inventory after the match.
- The Ended and WaitingRoom event states are sent now, and the skill-ended
  view plugin is wired to the magic effect's timeout.
- The hardcoded Devias gate is gone; leaving uses the map's configured
  safezone.

Consistency:
- The mini game entry refusals are localized PlayerMessage resources
  instead of hardcoded English strings (including the backtick typo).
- Fixed copy-paste documentation in the chat command, the game server
  state and MiniGameContext.GetSpawnGate.
- The chat command reports back when the event isn't configured, which
  also resolves its CS1998.
- Collapsed the identical 383/384 cases in TalkNpcAction and indented the
  switch properly.
- IllusionTempleTeam moved to the MiniGames namespace, matching its
  folder.
- Removed the whitespace noise in MiniGameContext and Player.
- GameContextTestHelper takes the maximum level as a parameter instead of
  changing it globally for every test.
- Deduplicated the relic's group/number checks behind IsRelicDefinition.
- The update plugin removes the obsolete 658-668 statue spawns, so
  existing databases don't keep the placeholders next to the new ones.
- FinishesWhenTooFewPlayersRemainAsync asserts that the match actually
  ends, not just the precondition.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Character class:
The result screen showed the same wrong class for every player. A packet
capture confirmed the server sends correct, distinct values, so the
client decodes them differently than assumed: it reads the class line
from the lower nibble (0 Dark Wizard, 1 Dark Knight, 2 Fairy Elf,
3 Magic Gladiator, 4 Dark Lord, 5 Summoner, 6 Rage Fighter) and the
evolution step from the upper one, while the internal numbering packs
both the other way around. Two players of different lines therefore
collapsed onto the same entry whenever the sent values happened to share
their lower nibble - both were shown as the Magic Gladiator line's master
class. The conversion is inverted accordingly and verified on a live
client.

Uninitialized packet bytes:
Each player entry carries three alignment bytes which are never written,
and the pipe buffer isn't zeroed, so leftovers of previous packets went
out on the wire. The buffer is cleared before writing now.

Entry dialog couldn't be opened a second time:
The player state is only reset back to EnteredWorld after the dialog has
been shown, so a failure while querying the temple user counts left the
player stuck in NpcDialogOpened - and opening the dialog requires exactly
that transition. The reset moved into a finally block. The user count
view plugin also missed the connection check every other view plugin has,
which is one way that query could throw.

Statue could stay locked for the rest of the match:
Claiming the carrier slot before looking up the relic item meant an
exception (e.g. a database without the item) left the slot claimed
forever, and nobody could pick up the relic anymore. The claim is now
released on every failure path, and a missing item definition is logged
instead of thrown.

Also reverted the WaitingRoom event state which was sent on entry: it was
added on the assumption that the unused enum value belongs there, without
evidence from the reference server, and it sent a new packet to the client
before the player was even on the event map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings the Illusion Temple mini game (PR #893 by @bulgarashi) up to date with
master and fixes the findings from its review.

Adapted to the mini game refactorings on master:
- The context is created by MiniGameManager instead of GameContext.
- The reward flow goes through MiniGameRewardService: it gained an optional
  reward filter, so a game can hand out its rewards in more than one step, and
  the winner checks are routed through two new overridable predicates.
- The migration is renumbered behind the migrations master added in the
  meantime, and its model snapshot is refreshed accordingly.

Review fixes:
- The character class conversion for the result screen reported Duel Master,
  Lord Emperor and Fist Master with an evolution step the client doesn't know,
  because those three lines have no second class. Covered by a new test over
  every character class.
- The "event ended" state is sent after the result has been shown, so it can't
  close the dialog whose Close button triggers the reward request.
- The relic carrier is claimed atomically when picking the relic up from the
  ground, like it already was at the statue.
- The granted experience is measured instead of recalculated, so the score
  board also reflects experience rates and the maximum level.
- The enter handler refuses an inventory slot which isn't in the inventory,
  instead of wrapping it around into an unrelated one.
- Skill-end notifications are subscribed after the effect was accepted.
- Naming and member ordering, file names matching their types, missing plugin
  display resources, and a few stale comments.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYEj5xw6iAJKEoDX3hyMZh
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Deploying openmudocs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 92c2bce
Status: ✅  Deploy successful!
Preview URL: https://d5bc0e22.openmudocs.pages.dev
Branch Preview URL: https://claude-pr-893-review-19p1pr.openmudocs.pages.dev

View logs

Resolves the conflicts with the Doppelganger event which landed on master:
both events add their own enter-result conversion, initializer, plugin
resources and update version, so both sides are kept and the illusion temple
update moves to version 116, behind the doppelganger one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYEj5xw6iAJKEoDX3hyMZh
DeliveringTheRelicScoresAPointAsync failed intermittently with "An item with
the same key has already been added. Key: IIllusionTempleStateViewPlugin".

The illusion temple pushes its state to the players from two tasks: the cyclic
update loop which runs while the match is on, and the immediate push after a
point was scored. MiniGamePlayerRegistry.ForEachAsync fans the players out with
WhenAll, so both reach InvokeViewPlugInAsync for the same player at the same
time. On the first request for a view plugin, both missed the lookup and both
added it, and one of them threw.

The real container keeps its plugins in a ConcurrentDictionary and only reads
from them at that point, so this is not a problem in the game itself - only the
mock, which creates its plugins on demand from a plain dictionary, wasn't safe
for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYEj5xw6iAJKEoDX3hyMZh
Both sides added an update version and an entry to the season 6 configuration
initializer, so the illusion temple update moves to version 118, behind the
item rule and dark horse ones, and its initializer runs before the item rules
which master wants to run last.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYEj5xw6iAJKEoDX3hyMZh

sven-n commented Sep 27, 2026

Copy link
Copy Markdown
Member Author

The Azure build failure, and local verification

The MUnique.OpenMU pipeline run on 92c2bce failed with "1 errors / 0 warnings". I couldn't read the Azure log (the project needs authentication), so I installed a .NET 10 SDK locally and reproduced the pipeline's own commands. It was not a compile error — the solution builds clean in Release with -p:ci=true. It was one intermittent test failure:

Failed DeliveringTheRelicScoresAPointAsync
System.ArgumentException : An item with the same key has already been added.
  Key: MUnique.OpenMU.GameLogic.MiniGames.IIllusionTempleStateViewPlugin
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at MUnique.OpenMU.Tests.MockViewPlugInContainer.GetPlugIn[T]()
   at MUnique.OpenMU.GameLogic.ObservableExtensions.InvokeViewPlugInAsync[TViewPlugIn]()
   at MUnique.OpenMU.GameLogic.MiniGames.MiniGamePlayerRegistry.ForEachAsync()
   at MUnique.OpenMU.GameLogic.MiniGames.IllusionTempleContext.TalkToNpcTeamStorageAsync()

The temple pushes its state to the players from two tasks: the cyclic update loop that runs during a match, and the immediate push right after a point is scored. MiniGamePlayerRegistry.ForEachAsync fans the players out with WhenAll, so both reach InvokeViewPlugInAsync for the same player at the same moment. On the first request for a given view plugin, both missed the lookup and both added it, and one threw.

This is not a problem in the game itself. CustomPlugInContainerBase keeps its plugins in a ConcurrentDictionary, fills them in Initialize(), and GetPlugIn<T>() only reads. Only MockViewPlugInContainer, which creates its mocks on demand from a plain Dictionary, wasn't safe for concurrent access — this branch is simply the first code to ask one player for the same view plugin from two tasks at once. Fixed in 3d6cb7d by giving the mock a ConcurrentDictionary and GetOrAdd, which matches what the real container does.

Evidence: before the fix the failure hit 2 of 9 full runs of MUnique.OpenMU.Tests; after it, 8 of 8 runs were clean. GetOrAdd is atomic, so that particular exception can't occur any more by construction.

Full local test run

Now that I have an SDK, the whole suite has actually been executed against current master (merged in 0782fc2), rather than just compiled:

Project Result
AttributeSystem.Tests 44 passed
ChatServer.Tests 26 passed
Network.Packets.Tests 603 passed
Network.Tests 73 passed, 4 skipped
Pathfinding.Tests 10 passed
Persistence.Initialization.Tests 30 passed, 6 skipped
PlugIns.Tests 41 passed
MUnique.OpenMU.Tests 1070 passed
Web.Tests 95 passed

That includes the 37 Illusion Temple tests and the new IllusionTempleCharacterClassTests over all 18 character classes. This supersedes the "I could not build or run the tests" caveat in the PR description.

What's still needed from a maintainer

The MUnique.OpenMU, MUnique.OpenMU Docker and Codacy checks sit at action_required on each new commit, so they only run when someone releases them. I can't trigger a re-run myself. The GitHub Actions build check is green on every push.

Master has also moved three times since this PR opened (Doppelganger, item rules, dark horse), and each time the update version and the season 6 initializer list collided. Resolved each time, most recently to IllusionTempleData = 118.


Generated by Claude Code

sven-n commented Sep 27, 2026

Copy link
Copy Markdown
Member Author

Correction: the MUnique.OpenMU check is red repo-wide, not on this PR

It failed again on 0782fc2d with the same opaque "1 errors / 0 warnings", so I checked whether it is actually this branch's failure. It isn't — the same check is failing on other recent pull requests, including ones that were merged through it:

PR MUnique.OpenMU Merged
#989 Discord notification workflow failure (build 4899, 15:22) yes, 15:24
#983 item rule flags failure (build 4893, 13:24) yes, 14:55
#973 Doppelganger event failure (build 4860) yes
#974 (this one) failure (builds 4894, 4903) —

Each of those was red before it merged, so this is a condition of the pipeline rather than anything the Illusion Temple work introduces. I'm standing down on it: I can't read the Azure log (the project needs authentication) and I can't re-run the check, so there is nothing further I can do here without a maintainer. If someone pastes the failing task's output I'll happily chase it, but I'm not going to keep pushing speculative changes at an error I can't see.

To be clear about what this does not excuse: the first Azure failure led me to a genuine bug, which is fixed in 3d6cb7d and stands on its own — MockViewPlugInContainer was doing a check-then-add into a plain Dictionary while the temple pushes state to a player from two tasks at once. I reproduced that locally (2 failures in 9 full runs), and after the fix 8 of 8 full runs and 25 of 25 focused runs were clean.

Everything I can verify is green on the current head (0782fc2d, master merged in at bb17089f):

  • dotnet build --configuration Release -p:ci=true — 0 errors
  • all nine test projects pass, 1070 in MUnique.OpenMU.Tests alone
  • the GitHub Actions build check is green on every push
  • no merge conflict

Generated by Claude Code

The Raklion event took update version 118 and added its own plugin resources,
so the illusion temple update moves to 119 and both resource entries are kept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYEj5xw6iAJKEoDX3hyMZh

This branch has not been deployed

No deployments
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