Add Phase 12: native RPG world state

Structured world/player/NPC stats, two-way flags, and sticky milestones
per scenario (stat_schema). The AI proposes a per-turn delta; a Python
engine referees it (clamp to min/max, per-turn cap, cooldown, counters).
Band word-labels plus a fixed stat guide (descriptions + full ranges)
keep the model grounded. World State drawer + Insights delta report;
undo/retry roll it back via the Phase 11 snapshot pattern.

- migrations 26-28 (scenarios.stat_schema, adventures.world_state,
  actions.world_state_before); all nullable, additive, safe on existing rows
- migration 29 raises the default context budget 4096 -> 16384
  (custom values preserved)
- seeded demo scenario 04-rpg-world-state.json (Bandit Camp)
- 19 new tests (33 total pass)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parththakkar106
2026-07-21 14:47:29 +05:30
co-authored by Claude Opus 4.8
parent 64356414b1
commit 4dac445f90
18 changed files with 1509 additions and 5 deletions
+90
View File
@@ -576,6 +576,96 @@ button:disabled { opacity: 0.45; cursor: default; transform: none; box-shadow: n
from { opacity: 0; transform: translateX(16px); }
to { opacity: 1; transform: none; }
}
/* ---------- World State drawer (Phase 12 RPG) ---------- */
.ws-group { margin-bottom: 18px; }
.ws-group-title {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--text-dim);
margin: 0 0 8px;
}
.ws-stat { padding: 5px 0; }
.ws-stat-head {
display: flex;
justify-content: space-between;
align-items: baseline;
gap: 8px;
font-size: 0.85rem;
}
.ws-stat-name { color: var(--text); text-transform: capitalize; }
.ws-stat-val {
color: var(--text-dim);
font-variant-numeric: tabular-nums;
font-size: 0.8rem;
text-align: right;
}
.ws-band { color: var(--accent-bright); }
.ws-bar {
margin-top: 4px;
height: 5px;
border-radius: 3px;
background: var(--bg-input);
overflow: hidden;
}
.ws-bar-fill {
height: 100%;
border-radius: 3px;
background: var(--accent);
transition: width 0.35s ease;
}
.ws-milestones { list-style: none; margin: 0; padding: 0; }
.ws-milestones li {
display: flex;
gap: 7px;
align-items: flex-start;
padding: 4px 0;
font-size: 0.85rem;
color: var(--text);
}
.ws-milestones li.done { color: var(--text-dim); }
.ws-check { flex-shrink: 0; color: var(--accent-bright); }
.ws-milestones li.done .ws-check { color: var(--player); }
.ws-flags { list-style: none; margin: 0; padding: 0; }
.ws-flags li {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
font-size: 0.85rem;
color: var(--text);
}
.ws-flag-dot {
width: 9px; height: 9px; border-radius: 50%;
flex-shrink: 0;
background: var(--bg-input);
border: 1px solid var(--border);
}
.ws-flag-dot.on { background: var(--accent); border-color: var(--accent); }
.ws-flag-name { flex: 1; }
.ws-flag-val { color: var(--text-dim); font-size: 0.8rem; }
.schema-editor {
width: 100%;
font-family: var(--font-mono, monospace);
font-size: 0.82rem;
line-height: 1.5;
tab-size: 2;
white-space: pre;
overflow-x: auto;
}
.schema-error {
margin-top: 6px;
color: var(--danger, #e5484d);
font-size: 0.82rem;
}
.ws-report { list-style: none; margin: 4px 0 0; padding: 0; font-size: 0.82rem; }
.ws-report li { padding: 2px 0; color: var(--text); }
.ws-report code { color: var(--accent-bright); }
.ws-delta { color: var(--player); font-variant-numeric: tabular-nums; }
.ws-flag { color: var(--text-dim); font-style: italic; }
.ws-rejected { color: var(--text-dim); }
.side-panel-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.side-panel-header h2 {
margin: 0;