feat: Decide mode — a tie-breaker that settles choices instead of listing options

Brian's bottleneck is committing, not generating options, so a pros/cons dump makes
it worse. Decide mode's card: get the real decision crisp, weigh it against what HE
values + past regrets (pull running_stats/recent_sessions for poker/money calls),
MAKE the call with the one or two reasons that tip it, pressure-test it once, and
stand behind it — no "it's up to you." Read-only lookups, no live logging.

Sixth mode (Talk/Poker/Build/Explore/Study/Decide); added to UI selectors, labels,
badge-cycle. Suite 96 green, ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-24 16:21:03 +00:00
parent 03aceec6fa
commit 17ab95dc98
3 changed files with 33 additions and 4 deletions
+23 -1
View File
@@ -59,6 +59,9 @@ _TALK_TOOLS = _BASE + _LOOKUPS + ("start_session",)
# Study = poker review away from the table: read-only lookups + equity, no live logging.
_STUDY_TOOLS = _BASE + _LOOKUPS + ("analyze_spot",)
# Decide = help him settle a choice; read-only lookups for bankroll/variance context.
_DECIDE_TOOLS = _BASE + _LOOKUPS
_CASH_CARD = """You are copiloting Brian's LIVE cash game right now — you're at the table with him, \
a session is (or should be) open. You move between two registers depending on what he's doing:
@@ -151,6 +154,24 @@ Connect it to his actual tendencies and known leaks when you can (his profile, p
genuinely close and explain what tips it. This is the slow, careful counterpart to live Poker mode."""
_DECIDE_CARD = """You're in DECIDE mode — Brian is indecisive and needs help SETTLING a \
choice, not generating more options. Be the tie-breaker who knows him. His bottleneck is \
committing, so a pros/cons dump makes it WORSE — don't do that.
• GET THE REAL DECISION CRISP. What's actually being chosen, the genuine constraints, the \
deadline. Cut the noise to the one or two things that actually decide it.
• WEIGH IT AGAINST HIM. Use what you know about him — his values, what he genuinely enjoys, \
how he's felt about similar calls before, his energy/schedule, his bankroll and how he's \
running if money's involved (pull running_stats / recent_sessions when it's a poker call). \
The point is HIS satisfaction and regret, not a generic optimum.
• MAKE THE CALL. Give a clear recommendation and the one or two reasons that genuinely tip \
it. Commit — don't hedge, don't hand the indecision back with "it's up to you."
• PRESSURE-TEST YOUR OWN CALL ONCE: the strongest reason you might be wrong, and the one \
thing that would flip it. Then hold your recommendation unless he pushes back with something real.
Warm but firm — he asked you to help him stop spinning. Decide, and stand behind it."""
TALK = Mode(
key="conversation",
label="Talk",
@@ -168,8 +189,9 @@ CASH = Mode(
BUILD = Mode(key="build", label="Build", card=_BUILD_CARD, tools=_BASE)
EXPLORE = Mode(key="explore", label="Explore", card=_EXPLORE_CARD, tools=_BASE)
STUDY = Mode(key="study", label="Study", card=_STUDY_CARD, tools=_STUDY_TOOLS)
DECIDE = Mode(key="decide", label="Decide", card=_DECIDE_CARD, tools=_DECIDE_TOOLS)
MODES: dict[str, Mode] = {m.key: m for m in (TALK, CASH, BUILD, EXPLORE, STUDY)}
MODES: dict[str, Mode] = {m.key: m for m in (TALK, CASH, BUILD, EXPLORE, STUDY, DECIDE)}
DEFAULT = TALK.key
+5 -2
View File
@@ -30,6 +30,7 @@
<option value="build">🛠 Build</option>
<option value="explore">🔭 Explore</option>
<option value="study">📐 Study</option>
<option value="decide">⚖️ Decide</option>
</select>
</div>
@@ -73,6 +74,7 @@
<option value="build">🛠 Build</option>
<option value="explore">🔭 Explore</option>
<option value="study">📐 Study</option>
<option value="decide">⚖️ Decide</option>
</select>
<button id="settingsBtn" style="margin-left: auto;">⚙ Settings</button>
<div id="theme-toggle">
@@ -613,8 +615,9 @@
// ----- Conversation modes (Talk / Poker / Build / Explore / Study) -----
const MODE_LABELS = { conversation: "💬 Talk", poker_cash: "♠ Poker",
build: "🛠 Build", explore: "🔭 Explore", study: "📐 Study" };
const MODE_ORDER = ["conversation", "poker_cash", "build", "explore", "study"];
build: "🛠 Build", explore: "🔭 Explore", study: "📐 Study",
decide: "⚖️ Decide" };
const MODE_ORDER = ["conversation", "poker_cash", "build", "explore", "study", "decide"];
// Reflect a mode value across the controls + header accent (no network call).
function applyMode(value) {
+5 -1
View File
@@ -50,7 +50,11 @@ def test_every_mode_tool_exists(lyra):
def test_work_modes_present_and_gated(lyra):
_, _, modes, tools = lyra
# the full set Brian chose
assert set(modes.MODES) == {"conversation", "poker_cash", "build", "explore", "study"}
assert set(modes.MODES) == {"conversation", "poker_cash", "build", "explore", "study", "decide"}
# Decide = read-only lookups for context, no live logging; has a real card
decide = _names(tools.specs(modes.DECIDE.tools))
assert {"running_stats", "recent_sessions"} <= decide and "log_hand" not in decide
assert modes.DECIDE.card
# Build/Explore are conversational: base agency tools only, no live poker logging
for key in ("build", "explore"):
names = _names(tools.specs(modes.get(key).tools))