docs(ui): document overlay setup and verification
Describe the compact panel, module boundaries, build and installation steps, read-only limits, and manual acceptance checks. Record user-confirmed in-game readability.
This commit is contained in:
parent
82f2c98e7e
commit
108fd8bf80
1 changed files with 198 additions and 0 deletions
198
ui/JevOverlay/README.md
Normal file
198
ui/JevOverlay/README.md
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
# Jev decision overlay
|
||||
|
||||
A separate, read-only C# mod for Slay the Spire 2. It displays the bot's existing
|
||||
`decisions.jsonl` file inside the game. It does not depend on STS2MCP at runtime.
|
||||
The bot still uses STS2MCP to observe and control the game.
|
||||
|
||||
## UI plan
|
||||
|
||||
The first version uses the compact panel selected during planning:
|
||||
|
||||
```text
|
||||
┌ Jev decisions · read only ───────── [−] ┐
|
||||
│ Read-only log · no new rows for 2s │
|
||||
│ #42 · JEV · combat │
|
||||
│ Session: … │
|
||||
│ Proposed: play_card │
|
||||
│ Parameters: {"card_index": 0} │
|
||||
│ Proposal only; execution not recorded. │
|
||||
│ Reason: … │
|
||||
│ Recorded confidence: 0.81 · 720 ms │
|
||||
│ [Show questions and answers] │
|
||||
├ Recent decisions · select to inspect ──┤
|
||||
│ #42 JEV play_card │
|
||||
│ #41 CODE use_potion │
|
||||
│ #40 FALLBACK end_turn │
|
||||
│ [Follow latest] │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- The panel starts at the top right. F8 or the header button collapses it.
|
||||
- Selecting a history row stops automatic selection of new decisions.
|
||||
- `Follow latest` resumes automatic selection.
|
||||
- The details button shows recorded Jev questions, answers, model, and latency.
|
||||
- Text areas and history scroll independently. Evidence uses plain text, not markup.
|
||||
- Source names remain visible. Blue identifies Jev; amber identifies fallback.
|
||||
- Only the panel receives mouse input. There is no full-screen input blocker.
|
||||
- The panel uses Godot's default font and controls. It needs no asset pack.
|
||||
|
||||
This is a desktop mouse-and-keyboard first version. Dragging, position persistence,
|
||||
controller navigation, filtering, and a remappable shortcut are not included.
|
||||
The panel does not pause the game or bot. Collapse it if it covers a game control.
|
||||
|
||||
## Module boundaries
|
||||
|
||||
```text
|
||||
ui/JevOverlay/
|
||||
Mod.cs mod startup, frame callback, background polling
|
||||
Core/
|
||||
OverlayConfig.cs explicit absolute log path
|
||||
LogTail.cs bounded, incremental JSONL reader
|
||||
DecisionHistory.cs session/step joins and display text
|
||||
UI/
|
||||
OverlayView.cs Godot controls and selection state
|
||||
Tests/
|
||||
Program.cs temporary-file integration checks
|
||||
JevOverlay.csproj game-facing assembly
|
||||
JevOverlay.json game mod manifest
|
||||
```
|
||||
|
||||
`Core/` has no Godot or game dependency. `UI/` has no file access or game API calls.
|
||||
`Mod.cs` connects them. All controls are built-in Godot nodes, so the mod needs no
|
||||
Godot editor project, custom node source generator, Harmony patch, or `.pck` file.
|
||||
|
||||
The game mod belongs under `ui/`, not a web `frontend/` directory. Python policy,
|
||||
the runner, and vendored code remain unchanged.
|
||||
|
||||
## Build
|
||||
|
||||
Use a .NET 9 SDK. No NuGet packages are needed; `NuGet.Config` clears package feeds.
|
||||
The game assembly paths are explicit. Builds do not install or start anything.
|
||||
|
||||
If `dotnet` is not on your PATH, a temporary Nix shell is sufficient:
|
||||
|
||||
```sh
|
||||
nix shell nixpkgs#dotnet-sdk_9
|
||||
```
|
||||
|
||||
A project flake and direnv configuration are not required for this version.
|
||||
|
||||
Run these commands from the repository root. On macOS arm64:
|
||||
|
||||
```sh
|
||||
GAME_DATA="$HOME/Library/Application Support/Steam/steamapps/common/Slay the Spire 2/SlayTheSpire2.app/Contents/Resources/data_sts2_macos_arm64"
|
||||
dotnet build ui/JevOverlay/JevOverlay.csproj -c Release \
|
||||
-p:STS2GameDataDir="$GAME_DATA"
|
||||
```
|
||||
|
||||
On other platforms, set `STS2GameDataDir` to the installed game's directory
|
||||
containing `sts2.dll` and `GodotSharp.dll`. Use assemblies from the target game build.
|
||||
|
||||
Output: `ui/JevOverlay/bin/Release/net9.0/`.
|
||||
Do not distribute game assemblies with the mod.
|
||||
|
||||
## Offline checks
|
||||
|
||||
The integration checks need .NET 9, but no game installation or connection:
|
||||
|
||||
```sh
|
||||
dotnet run --project ui/JevOverlay/Tests/JevOverlay.Tests.csproj -c Release
|
||||
```
|
||||
|
||||
The checks pass temporary files through the actual reader, history, and text formatter.
|
||||
They cover partial writes, UTF-8, malformed rows, session joins, action errors,
|
||||
rotation, truncation, bounded history, large logs, missing files, and recovery.
|
||||
They do not test Godot rendering or game input behavior.
|
||||
|
||||
## Manual installation
|
||||
|
||||
Do this only when you intend to load the mod. Close the game first.
|
||||
|
||||
1. Build against the installed game assemblies.
|
||||
2. Copy `JevOverlay.dll` and `JevOverlay.json` from the output directory into the game's `mods/` directory.
|
||||
3. Copy `JevOverlay.config.example.json` there as `JevOverlay.conf`.
|
||||
4. Set `log_path` to the absolute path of the bot's decision log.
|
||||
5. Restart the game and enable mods if prompted.
|
||||
|
||||
On macOS, the mod directory is:
|
||||
|
||||
```text
|
||||
SlayTheSpire2.app/Contents/MacOS/mods/
|
||||
```
|
||||
|
||||
Example configuration in `JevOverlay.conf` (JSON content, not a mod manifest):
|
||||
|
||||
```json
|
||||
{
|
||||
"log_path": "/absolute/path/to/sts2-bot/capture/decisions.jsonl"
|
||||
}
|
||||
```
|
||||
|
||||
Do not use `~` or environment variables in this value. For Windows JSON paths,
|
||||
use forward slashes or escape backslashes. Custom `run.py --capture-dir` locations
|
||||
need a matching `log_path`.
|
||||
|
||||
The reader waits if the file does not exist. Missing or invalid configuration
|
||||
appears in the panel. Configuration changes require a full game restart.
|
||||
The mod never creates or changes the configured log file.
|
||||
|
||||
To remove the mod, close the game and remove these three installed files.
|
||||
No saves, capture files, or existing mod files need to change.
|
||||
|
||||
## Log meaning and limits
|
||||
|
||||
The viewer consumes the current `run.py` trace format:
|
||||
|
||||
| Event | Display behavior |
|
||||
| --- | --- |
|
||||
| `decide` | Add a proposed action, identified by session and step |
|
||||
| `action_rejected` | Mark that action request as rejected |
|
||||
| `action_error` | Show the request error; completion remains unknown |
|
||||
| `session_end` | Show the session's stop reason, not action completion |
|
||||
| Model/policy failures, `no_decision` | Show a reader notice |
|
||||
| Other events | Ignore without treating them as malformed |
|
||||
|
||||
The log does not record successful action results or a per-decision dry-run flag.
|
||||
The viewer cannot distinguish an unconfirmed live proposal from a dry-run proposal.
|
||||
It never marks a proposal as executed because the next decision arrived.
|
||||
A transport error does not prove that the game failed to execute a request.
|
||||
|
||||
The policy reason is recorded text, not private model reasoning. A `jev` response
|
||||
can accompany a fallback; the `source` field identifies the actual policy path.
|
||||
Recorded answer gates can differ from policy-specific final gates. Confidence is
|
||||
not proof of correctness. No Jev response means only that none was recorded.
|
||||
|
||||
The status reports file activity, not bot or game liveness. Existing history can
|
||||
be displayed when no bot is running. Sessions remain distinct, including when
|
||||
multiple runners append to the file. The latest appended decision is selected
|
||||
when `Follow latest` is enabled; there is no session filter in this version.
|
||||
|
||||
The reader polls every 500 ms on one background worker. It reads at most 256 KiB
|
||||
per poll and starts within the last 256 KiB of an existing log. It keeps at most
|
||||
100 decisions and at most 128 KiB per incomplete line. Oversized or malformed
|
||||
lines are skipped. Display text is limited to 16,000 characters per text area.
|
||||
A displayed decision can leave history while it is selected.
|
||||
|
||||
Truncation and replacement are detected by file length, a prefix, and a checkpoint
|
||||
near the last read offset. A replacement with identical sampled bytes and no
|
||||
length decrease cannot always be distinguished from an append. This viewer is
|
||||
not a durable audit reader. Concurrent writers must still produce complete JSONL
|
||||
rows; the viewer cannot repair interleaved writes.
|
||||
|
||||
## In-game acceptance check — requires explicit approval
|
||||
|
||||
No live game action or model call is needed to validate the panel itself. Point
|
||||
`log_path` at a disposable JSONL file and use synthetic records:
|
||||
|
||||
1. Start the game with the mod installed and check the initial panel.
|
||||
2. Append a `decide` record with a session, step, and action.
|
||||
3. Confirm the panel updates and does not mark the proposal as executed.
|
||||
4. Expand the evidence area and select an older decision.
|
||||
5. Append another record and confirm the older selection remains selected.
|
||||
6. Test F8, collapse, scrolling, resizing, and clicks outside the panel.
|
||||
7. Switch game scenes and confirm there is exactly one panel.
|
||||
8. Remove or truncate the disposable file and confirm reader recovery.
|
||||
|
||||
The user confirmed that the installed panel appears and is readable in-game.
|
||||
Input routing, scene persistence, and the remaining acceptance steps are not yet
|
||||
verified. Building against game assemblies is not a substitute for these checks.
|
||||
Loading…
Add table
Add a link
Reference in a new issue