Skip to content

[codex] Add endpoint audit fixes - #85

Open
CompleteDotTech wants to merge 194 commits into
Gennadiyev:mainfrom
CompleteDotTech:codex/endpoint-audit-fixes
Open

[codex] Add endpoint audit fixes#85
CompleteDotTech wants to merge 194 commits into
Gennadiyev:mainfrom
CompleteDotTech:codex/endpoint-audit-fixes

Conversation

@CompleteDotTech

Copy link
Copy Markdown
Contributor

Summary

Ports the implementation from CompleteDotTech#2 onto Gennadiyev/STS2MCP.

This is a broad endpoint-contract hardening pass. It adds read-only metadata endpoints and MCP wrappers, standardizes JSON response envelopes, makes endpoint failures structured and non-2xx, enriches profile/save/current-run context, expands card/action readiness metadata, and adds static/live audit coverage so the documented API surface stays aligned with the implementation.

Major Changes

API index and endpoint discovery

  • Shapes GET / as a structured API index.
  • Advertises status, kind: api_index, version, endpoint_count, bound prefixes, and endpoint rows.
  • Adds audit coverage for endpoint count, duplicate route detection, method/path/description field types, semantic version shape, and docs/index parity.

New read-only endpoint surfaces

  • Adds /api/v1/settings.
  • Adds /api/v1/bestiary.
  • Adds /api/v1/glossary/cards.
  • Adds /api/v1/glossary/relics.
  • Adds /api/v1/glossary/potions.
  • Adds /api/v1/glossary/keywords.
  • Extends /api/v1/profile, /api/v1/compendium, and /api/v1/profiles with structured envelopes and save/run context.

MCP wrappers

Adds MCP wrappers for the read-only surfaces:

  • get_api_index
  • get_settings
  • get_profile
  • get_compendium
  • get_bestiary
  • get_glossary_cards
  • get_glossary_relics
  • get_glossary_potions
  • get_glossary_keywords
  • list_profiles
  • switch_profile
  • delete_profile

The MCP bridge now preserves structured endpoint error bodies and adds http_status, so MCP clients can branch on the same error_code fields as HTTP clients.

Response envelopes and current-run context

JSON read endpoints now expose explicit status and kind fields.

State, profile, Compendium, and glossary responses expose active profile/save/current-run context where available:

  • profile_id
  • progress_path
  • resolved_progress_path
  • profile_root
  • save_scope
  • current_run

Path-like fields are normalized with forward slashes, including Windows absolute paths and Compendium run-history paths.

Structured errors

Route, validation, action, read, and state-conflict failures now return structured non-2xx JSON instead of successful HTTP 200 error payloads.

Examples include:

  • method_not_allowed
  • not_found
  • invalid_json
  • missing_action
  • invalid_action_type
  • invalid_action_payload
  • missing_profile_id
  • invalid_profile_id
  • invalid_profile_id_type
  • unknown_profile_action
  • invalid_format
  • not_singleplayer_run
  • not_multiplayer_run
  • run_not_in_progress
  • run_in_progress
  • active_profile_delete
  • blocking_popup_active
  • timeline_manual_action_required
  • action_error

Unsupported methods are rejected before singleplayer/multiplayer run-mode guards, so invalid methods consistently return HTTP 405 regardless of current game mode.

Profile and Compendium shape

  • Adds explicit status/kind envelopes.
  • Adds profile/save/current-run identity fields.
  • Sorts profile and Compendium metadata deterministically.
  • Adds run-history section audits.
  • Adds active profile slot schema and validation audits.
  • Returns structured HTTP errors for invalid profile actions, invalid profile IDs, active-profile delete attempts, and switch-during-run conflicts.

Glossary and Bestiary

  • Keeps glossary endpoints active-run scoped.
  • Includes current character context plus shared pools.
  • Adds profile/save/current-run context to successful glossary responses and no-run errors.
  • Handles no active RunManager.Instance as run_not_in_progress instead of startup/teardown 500s.
  • Hardens keyword glossary collection against null or unstable hover-tip sources.
  • Shapes /api/v1/bestiary with deterministic status, kind, counts, sorted monsters, sorted encounters, and sorted nested metadata.

Card and state metadata

  • Adds card upgrade metadata to glossary cards and visible state card payloads.
  • Adds upgraded-preview cost/star-cost/description fields.
  • Adds requires_target and valid_targets to enemy-targeted hand cards.
  • Expands pile card state with core card fields.
  • Adds shop card upgrade previews in payload and markdown.

Action readiness and UI guards

State payloads now expose action-readiness metadata for:

  • card selection
  • hand selection
  • card rewards
  • event options
  • rest options
  • relic selection
  • bundle selection
  • shop/fake merchant purchases
  • treasure relic claims
  • Crystal Sphere choices
  • rewards
  • map travel
  • combat and multiplayer end turn
  • potion use/discard
  • enemy targeting

Actions are hardened so hidden, disabled, or stale UI nodes are not clicked through old indices. Proceed actions are gated on visible enabled controls while preserving the shop close-inventory-then-proceed behavior.

Menu and multiplayer routing

  • menu_select retries through /api/v1/multiplayer when the singleplayer route correctly rejects the call during an active multiplayer run.
  • Adds static MCP route-helper parity checks so mp_ tools stay on multiplayer helpers and non-MP tools do not accidentally call multiplayer helpers.

Documentation

This PR updates:

  • README.md
  • docs/raw-full.md
  • docs/raw-simplified.md
  • mcp/README.md
  • AGENTS.md

It also adds:

  • docs/endpoint-contracts.md

The new endpoint-contract doc summarizes response envelopes, current-run context, profile/Compendium behavior, glossary scope, structured error codes, action-readiness fields, MCP coverage, and audit commands.

Audit And Test Coverage

Adds:

  • scripts/audit_endpoints.py
  • scripts/test_mcp_server.py

The audit script covers endpoint/index/doc parity, route/index shape, structured errors, settings/profile/Compendium/glossary/Bestiary schemas, normalized save paths, state envelopes, action-readiness fields, validation failures, and live endpoint behavior when run against a loaded mod.

Validation

Completed locally on this branch:

  • python3 -m py_compile scripts/audit_endpoints.py scripts/test_mcp_server.py mcp/server.py
  • python3 scripts/audit_endpoints.py --skip-live
  • uv run --project mcp python scripts/test_mcp_server.py
  • "/mnt/c/Program Files/dotnet/dotnet.exe" build STS2_MCP.csproj -c Release -o out/STS2_MCP -p:STS2GameDir="C:\Program Files (x86)\Steam\steamapps\common\Slay the Spire 2"

The .NET build completed successfully with 0 warnings and 0 errors.

Live audit was not rerun as part of this port because it requires installing/restarting the game with the built DLL. The source PR includes extensive live verification notes from the fork.

CompleteDotTech and others added 30 commits March 26, 2026 11:50
The map screen's player summary only included hp, gold, and potion slot
counts. This adds full relic and potion data to BuildMapState so external
tools can display them outside of combat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Map data is now always returned alongside any game state (combat, event,
shop, etc.) so external tools can display the map without caching. Also
adds a version marker for verifying mod DLL is loaded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Always attach BuildPlayerState output at the top level of every response
so external tools have access to HP, gold, relics, potions, deck piles,
and powers regardless of which screen is active.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exposes player.Deck.Cards in BuildPlayerState so the full deck
composition is available on every screen, not just during combat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Some screens (e.g. treasure) can cause null reference exceptions
when BuildPlayerState accesses combat-only properties.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When NMapScreen is not open (during combat, events, etc.), compute
next_options from the current map point's children so external tools
always have the available path choices.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GET /api/v1/glossary — returns all categories
GET /api/v1/glossary/cards — all cards with pool grouping
GET /api/v1/glossary/relics — all relics with pool grouping
GET /api/v1/glossary/potions — all potions with pool grouping
GET /api/v1/glossary/keywords — unique keywords from all items

Uses current character's pools during a run, plus colorless/curse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tries http://+:15526/ first for network access, falls back to
localhost-only if the URL ACL is not configured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Returns all cards from the current character's card pool during an
active run. Includes id, name, type, cost, description, rarity, pool,
and keywords for each card.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Returns relics from the current character's relic pool. Shared/event
relics not yet accessible — canonical instance lookup returns null
at runtime. Will revisit access pattern later.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Returns potions from the current character's potion pool.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Harvests unique keywords from all cards, relics, and potions in the
current character's pools. Returns name and description for each.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows visible menu buttons as numbered options in player stats widget.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects main menu, singleplayer mode select, and character select screens.
Shows available options with enabled/locked state. Character select includes
HP, gold, energy, starting relics, starting deck, and pool counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Supports navigating Main Menu, Singleplayer Mode Select, and Character
Select screens. Includes back button, character selection with lock
detection, and embark/confirm to start a run.

Actions: menu_select with options:
- Main menu: singleplayer, multiplayer, settings, quit, etc.
- Mode select: standard, daily, custom, back
- Character select: IRONCLAD, SILENT, etc., confirm, back

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects NGameOverScreen overlay as state_type: game_over with
continue and main_menu options. Handles via menu_select action.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exposes player profile data: character stats (wins, losses, ascension,
streaks), card stats (pick/skip/win/loss), encounter and enemy stats,
discovered items, total playtime, score, and floors climbed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Profile endpoint now includes by_character win/loss for each encounter
and enemy. Widgets show the breakdown under each entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds ancient stats with per-character breakdown, epoch milestones,
unlocked achievements, and global stats (wins, losses, runs, best
streak, fastest victory, architect damage).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GET /api/v1/bestiary returns 126 monsters (HP range, moves) and
95 encounters (type, tier). Widget merges with profile win/loss stats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Encounters now include min/max gold reward and likely_monsters
inferred from encounter name. Widget shows gold and monster columns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Timeline shows epoch names, descriptions, and unlock requirements.
Multiplayer submenu shows host/join/load options. Settings, compendium,
and timeline screens properly detected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Timeline widget now groups epochs into Completed (green), Locked (yellow
with unlock requirements), and hidden count.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No more flickering from mouse hover. Shows earned epochs from save
data with slot counts for remaining.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@CompleteDotTech

Copy link
Copy Markdown
Contributor Author

Issue coverage note: this PR should resolve or materially address:

I would still keep the issues open until this PR is merged and the scenarios are live-verified.

@Ryson-32

Ryson-32 commented Jun 2, 2026

Copy link
Copy Markdown

I tested this branch locally against the Kifuda deck enchant flow and found one remaining issue that seems related to the new card selection state handling.

NDeckEnchantSelectScreen does not appear to store its selected state on the card holders. The real selected cards are in the screen's private _selectedCards set. Because of that, the API can still report selected_cards: [] / selected_count: 0 even after cards are visibly selected, which can make an agent select cards repeatedly.

I also found that confirm_selection needs a special path for this screen. The top-level confirm button can enter/handle the preview path, but the final completion goes through the game's own ConfirmSelection / CheckIfSelectionComplete flow.

I opened a small follow-up PR against this branch here: CompleteDotTech#8

That patch:

  • reads selected cards from _selectedCards
  • reads selector prefs from _prefs where needed
  • treats 0 selected cards as not confirmable for this enchant screen
  • confirms NDeckEnchantSelectScreen through the game's own ConfirmSelection

Verified locally:

  • Release build passes with 0 warnings / 0 errors
  • python scripts/audit_endpoints.py --skip-live passes
  • uv run --project mcp python scripts/test_mcp_server.py passes
  • Live Kifuda flow works: selected Bloodletting, Dominate, and Feed; selected_count=3; confirm returned to the shop; Kifuda was added; all three selected cards gained the enchant text.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants