The Shanda sponsor logo's alt text was `666ghj%2MiroFish | Shanda`,
missing the `F` from the URL-encoded `/`. Every other badge in both
READMEs uses the correct `666ghj%2FMiroFish`. Bring this one in line
with the rest.
- Add return type annotation (list[str]) to Config.validate()
- Add type annotations (msg: str, -> None) to logger convenience functions
- Add FileParser.is_supported() classmethod for checking file format support
- New Vue views: GodModeView (inject event, modify emotions with
preloaded current values, kill character with typed-name
confirmation) and WorldBuilderView (rules editor, locations with
cinematic atmosphere field, event log viewer)
- Shared sim-nav strip across Story/GodMode/World views
- Location schema extended with optional atmosphere field — a short
mood phrase that anchors the opening visual of every scene set there
- Translator's _format_world_locations surfaces atmosphere to the LLM
prompt so the field actually influences generation
- Routes added for /godmode/:simId and /world/:simId
Tests: 39/39 passing (added test_location_atmosphere_surfaces_in_prompt).
Frontend builds clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Six new endpoints under /api/narrative/*:
- GET /world/<sim_id> — full world state
- POST /world/<sim_id>/rules — replace rules list
- POST /world/<sim_id>/locations — upsert location
- POST /godmode/<sim_id>/inject-event — inject world event
- POST /godmode/<sim_id>/modify-emotion — overwrite emotions
- POST /godmode/<sim_id>/kill — kill character
Validation:
- 400 on missing required fields (description, character_id, rules)
- 400 on invalid round (must be non-negative int or null)
- 404 on character not found (from ValueError in handlers)
Smoke-tested via Flask test client — all 11 response codes correct.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When Marcus (the only round-2 actor) was killed, generate_prose
short-circuited on empty actions without calling the LLM, so
mock_llm.call_args_list only had one entry. Added Elena as a
second round-2 actor to exercise the filter with a live participant.
- PROSE_PROMPT_TEMPLATE extended with world_rules, world_events,
world_locations, and event_enforcement substitution fields
- EVENT_ENFORCEMENT_STRENGTH set to "hard" — opening line MUST
reference the most recent world event (aligns with existing
punchy, cinematic voice)
- Character summaries now resolve location id → name for prompts
- translate_round loads world_state and filters dead characters
from both the roster and the action list before prose generation
- User-supplied strings (rules, events, locations) brace-escaped
before str.format() to prevent KeyError on stray { or }
Tests: 36/36 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
10-task TDD plan covering:
- WorldStateStore (rules, locations, event log)
- Character status field
- 3 God Mode handlers (inject_event, modify_emotion, kill_character)
- Translator prompt extension + dead filter + brace escape
- E2E integration tests for injection and kill
- 6 API endpoints with validation
- 2 Vue views with shared nav + typed-name kill confirmation
Includes 2 marked user-contribution points:
- EVENT_ENFORCEMENT_STRENGTH (soft/medium/hard)
- Location schema fields (minimal vs atmosphere vs time_of_day)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Minimal scope: 3 God Mode interventions (inject event, modify emotion,
kill character) + 3 World State primitives (locations, rules, event
log). File-based only — no OASIS simulation changes for v1.
Design trade-off: v1 God Mode affects the prose layer, not the
simulation loop. Agents don't "see" injected events; only the narrator
does. This ships faster and fits the creative-authoring use case.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Full-pipeline test: fake simulation dir → actions.jsonl → two
translate_round calls → assertions on beat persistence, character
evolution, and translator offset advancement.
Final test suite: 20/20 passing across action mapper, character
engine, story store, translator (read + prose + orchestration), and
E2E.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New frontend surface for reading generated stories:
- StoryBeat.vue: renders a round's prose with character attribution
- CharacterCard.vue: compact roster card with animated emotion bars
- StoryTimelineView.vue: reading view with Init Characters, Refresh,
Translate Next Round, and a tone input
- Route: /story/:simulationId
Recently-active characters are highlighted in the roster. Styling uses
the project's cream/brass palette for consistency with existing views.
Frontend builds cleanly (vite build).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five named exports covering narrative endpoints, following the
existing pattern in frontend/src/api/simulation.js (service +
requestWithRetry + named exports).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five endpoints under /api/narrative/*:
- GET /story/<sim_id> — full story so far
- GET /story/<sim_id>/round/<num> — single round
- POST /translate — translate a round on demand
- GET /characters/<sim_id> — roster with emotional state
- POST /characters/<sim_id>/init — bootstrap from OASIS profiles
Blueprint registered alongside existing graph/simulation/report
blueprints following the established pattern. Smoke-tested via Flask
test client.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
translate_round() ties together:
- reading the round's actions from actions.jsonl
- generating prose via the LLM
- updating per-character emotional state
- persisting the beat, characters, and file offset
Full test suite now at 19/19 passing across action mapper, character
engine, story store, and translator.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Module-level call_llm() wrapper (patchable by tests) drives
PROSE_PROMPT_TEMPLATE rendering with character summaries, actions,
previous beats, and user-selected tone. Prompt tuned for punchy,
cinematic, dialogue-heavy voice.
Tests: 5/5 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reads one round's worth of agent actions from the OASIS log file,
tracking file offset so callers can resume across translation calls.
Handles missing files, malformed JSON lines, and non-target rounds
gracefully.
Tests: 3/3 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Character profiles now track a six-dimension emotional state (anger,
fear, joy, sadness, trust, surprise) that evolves based on actions
taken. Initial deltas for all 13 OASIS actions chosen as a balanced
baseline (see module docstring for tuning guidance).
Tests: 5/5 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three JSON files per simulation under narrative/ subdir:
- story_beats.json: chronological story passages
- translator_state.json: per-platform file offsets
- characters.json: extended character profiles
Tests: 4/4 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New narrative package with action_mapper module that maps the 13 OASIS
action types (CREATE_POST, LIKE_POST, REPOST, etc.) to narrative verbs
and interpretations used when generating story prose.
Tests: 4/4 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- docs/superpowers/specs/2026-03-26-narrative-layer-design.md
- docs/superpowers/plans/2026-03-26-narrative-layer-foundation.md
Spec extends MiroFish into a creative storytelling platform via a new
narrative layer over the existing OASIS simulation engine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add sans-serif font for English left-pane (status, workflow sections)
- Shorten English workflow step descriptions
- Reduce English report title font-size from 36px to 28px
- Use sans-serif font for English titles, descriptions and navbar
- Shorten English hero text to avoid overflow
- Fix :global() scoped CSS issue that was setting root font-size to 3.5rem
- Use separate unscoped style block for html[lang] selectors