Repository navigation
feat: S5 โ Scry & Hex reactions - #9
Merged
Merged
Conversation
Each player holds one Scry and one Hex per round, spent permanently. A resolved Ask opens a reaction window owned by the asker; a resolved Cast closes it, so a Cast is structurally never interruptible (the win check stays sacred); consuming or declining a reaction closes it, so at most one reaction lands per window. Charges and the window reset with the round. Exposes reactionAvailable, reactionWindow, consumeReaction, and declineReaction as the primitives the reaction policy resolves over. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com>
reactions.ts owns the reaction policy over the engine's window/charge primitives: Pass lets the Ask stand and spends nothing; Scry/Hex need an open window owned by the rival and an unspent charge, then spend it and resolve as shareAnswer (Scry overhears the answer) or killAnswer (Hex silences the question). Hex's no-answer-to-anyone is the action layer withholding the asker's answer โ the engine still spent the turn at Ask time. Route React through resolveReaction; add the 95/90 coverage floor. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com>
ReactionPrompt renders the ux-copy ยง3 interrupt โ "Skรถll asks. Answer it?" with Scry / Hex / Let it pass. Only held reactions are offered, so a spent one simply vanishes (no "spent" copy). Built and tested now; the live trigger lights up in S6 when Skรถll Asks through the same interface, the same way the Skรถll turn pill is staged. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com>
Check off S5 in the implementation checklist with the engine-state / reactions-policy split and the S6 live-trigger note, and the section-5 reaction test rows in the test checklist. Skรถll's live Ask/reaction stays open for S6. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Implements the S5 โone-use reactionsโ mechanic (Scry/Hex) by adding per-round reaction charges and an Ask-triggered interrupt window to the engine, a dedicated reaction policy module for resolving choices, and a new UI prompt component for human-side reactions.
Changes:
- Add reaction state to the engine (per-player Scry/Hex charges + interrupt window) and wire a new
Reactaction result that carries a reaction outcome. - Introduce
resolveReactionpolicy (reactions.ts) and add ReactionPrompt UI + component tests. - Update coverage thresholds and checklists/tests to reflect S5 completion.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| vite.config.ts | Adds coverage gate for the new reactions module. |
| src/lib/server/engine/engine.ts | Adds reaction charges + reaction window state and APIs to consume/decline reactions. |
| src/lib/server/engine/reactions.ts | New policy module to validate/resolve Scry/Hex/Pass against engine state. |
| src/lib/server/engine/actions.ts | Routes React through resolveReaction and returns structured outcome. |
| src/lib/components/ReactionPrompt.svelte | New UI prompt offering Scry/Hex/Pass based on held charges. |
| tests/lib/server/engine/engine.test.ts | Adds unit coverage for reaction charges/window behavior and round reset. |
| tests/lib/server/engine/reactions.test.ts | New unit tests for resolveReaction policy outcomes and constraints. |
| tests/lib/server/engine/actions.test.ts | Updates integration tests for React routing/outcomes. |
| tests/routes/api/action/server.test.ts | Updates API response expectations for React to include outcome. |
| tests/lib/components/ReactionPrompt.svelte.test.ts | New component tests for prompt copy/choices and spent-reaction hiding. |
| docs/v1-implementation-checklist.md | Marks S5 items complete and documents the implementation approach. |
| docs/test-checklist.md | Marks S5 reaction test gates complete and updates related gating notes. |
๐ก Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Pass unconditionally closed the window, so the asker could send
{reaction:'Pass'} to slam their own window shut and deny the rival a
reaction โ violating "only the rival may respond." Gate it like Scry/Hex:
Pass closes the window only when it is open and owned by the other player;
otherwise it is a harmless no-op. Caught in review (PR #9).
Generated-by: Claude Opus 4.8
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com>
The reaction window was a side effect of a *resolved* Ask โ it only existed after engine.ask had already computed and returned the answer, so a Hex's killAnswer claimed to kill something already handed back. Reframe the window as a *pending* Ask: openReactionWindow marks it before the Ask is answered, decoupled from ask itself. Now a Hex resolves first and the orchestration simply never asks for the answer (S6 wires Skรถll's Ask: open window -> react -> ask-and-deliver on Pass/Scry, or spend his turn unanswered on Hex). ask no longer touches the window; a resolved Cast still closes it (sacredness). Caught in review (PR #9, P1). Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



S5 โ Scry & Hex reactions
Builds the one-use reaction system (
v1-implementation-checklist.mdS5). The engine owns the state; a dedicated policy module owns the rules; a component carries the human prompt. Live trigger lights up in S6 when Skรถll Asks through the same interface โ same staging as the dormant Skรถll turn pill.What lands
engine.ts) โ one Scry + one Hex per player per round, plus an interrupt window: a resolved Ask opens it (owned by the asker), a resolved Cast closes it, a reaction/decline closes it. Charges + window reset with the round.reactions.ts, new) โresolveReaction: Pass lets the Ask stand; Scry/Hex need an open window owned by the rival and an unspent charge, then resolve asshareAnswer/killAnswer.actions.ts) โReactroutes throughresolveReaction, carrying the outcome.ReactionPrompt.svelte, new) โ "Skรถll asks. Answer it?" โ Scry / Hex / Let it pass; spent reactions vanish (no "spent" copy).Invariants held structurally (not by convention)
Scope note
The live trigger is S6 (Skรถll has no Ask yet). The prompt is built + tested now, lit up when the Gemini opponent Asks. No dormant/uncovered page branches.
Tests & gates
engine.ts100% line/branch ยทreactions.ts100% line/branch (floor 95/90).๐ค Generated with Claude Code