Skip to content

Optimize Tiny Stories end-to-end target-mode flow - #21

Merged
lishehao merged 6 commits into
mainfrom
codex/tiny-stories-target-mode
Jul 15, 2026
Merged

Optimize Tiny Stories end-to-end target-mode flow#21
lishehao merged 6 commits into
mainfrom
codex/tiny-stories-target-mode

Conversation

@lishehao

Copy link
Copy Markdown
Owner

What changed

  • Preserve Story Butler facts and player role across Story Brief and opening generation.
  • Keep the ready Story Brief surface compact while retaining planning details on demand.
  • Make fallback openings use the accepted Brief instead of unrelated stock copy.
  • Keep end-of-run summaries sentence-safe, including CJK text without spaces.
  • Align the automatic Story Brief handoff: once readiness is reached, Story Butler announces the already-rendered Brief instead of asking whether to create it.
  • Add focused regression coverage for story-fact handoff, automatic Brief readiness, and ending excerpts.

Why

The target-mode audit found three player-visible reliability gaps:

  1. accepted story facts could weaken between Create, Brief, and opening;
  2. a ready Live Butler reply could ask permission to create a Brief that was already visible;
  3. deterministic ending excerpts could stop in the middle of a word.

Product impact

The full flow now reads coherently from Home -> New Story -> Story Butler -> automatic Story Brief -> Generate -> Play -> ending -> replay -> Home. Existing Play, reviewer, privacy, retry, and QA-route contracts remain covered by the full test suite.

Validation

  • Full backend pytest -q: passed (one existing skip).
  • npm --prefix frontend2 run check: passed.
  • npm --prefix frontend2 run build: passed; existing Vite large-chunk warning only.
  • In-app Browser: fresh Live session completed 12/12 turns to a Victory/Redemption ending, opened Full Replay, and returned to Home.
  • Live telemetry: Story Butler context/turn, Story Brief, opening, 12 Play turns, ending, branches, and highlights all live/success; zero fallback reasons.
  • 390px Home and Replay: no horizontal overflow.
  • Browser console warnings/errors: zero.
  • Player-facing provider/debug/raw JSON leakage: none.

Environment note

The local Live acceptance also uncovered an ignored .env issue: a valid singular key was shadowed by a stale explicit key pool. The local pool was corrected without committing or exposing credentials; no secret is part of this PR.

@lishehao
lishehao marked this pull request as ready for review July 15, 2026 17:20
@lishehao
lishehao merged commit 5facdec into main Jul 15, 2026
2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c08ab2754

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +461 to +464
mentioned_entities = (
guide_entities
if len(guide_entities) >= 3
else _dedupe_preserving_order([*guide_entities, *_extract_entities(clean_seed)])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Merge seed cast even with three guide entities

When guide_context.cast_or_factions already has three entries, this branch stops reading entities from clean_seed entirely. In the guided flow the context extractor often stores role-level terms such as producer, sponsor representative, and backup dancer, while the seed may contain the actual names (for example Cast: Alice the producer, Bob the sponsor representative, Cara the backup dancer). The resulting Brief and fallback opening drop the user-supplied names even though they are still present in the accepted seed; merging/deduping seed entities after guide entities would preserve those facts.

Useful? React with 👍 / 👎.

Comment on lines +2854 to +2857
and not (
brief.player_role
and entity.display_name.strip().casefold() == brief.player_role.strip().casefold()
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep excluding the player role in fallback cast

This filter is undone as soon as fewer than three non-player entities remain: the fallback block below rebuilds primary_entities from primary plus secondary entities without applying the same brief.player_role exclusion. For guided briefs with a player role and only two other parties, a live-opening failure will still stage the player as an NPC/cast member while also offering them as the player role, which is the incoherence this new filter is trying to avoid.

Useful? React with 👍 / 👎.

Comment on lines +781 to +782
if len(participants) >= 2:
slots["active_cast"] = " / ".join(participants)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve named cast when no role nouns are present

For seeds such as At the gala, Alice and Bob argue over a missing contract, _extract_active_cast returns no participants because the names do not match PARTICIPANT_RE, and this branch only fills active_cast from recognized role nouns. The previous conjunction fallback treated that seed as cast evidence; now Story Butler asks for cast again and can delay the automatic Brief even though the user already named the parties.

Useful? React with 👍 / 👎.

Comment on lines +95 to +97
PLAYER_ROLE_CAPTURE_RE = re.compile(
r"\b(?:i am|i'm|i play as|i play|my role is|make me|player is|protagonist is|player should be)\s+(?:a\s+|an\s+|the\s+)?([^.!?;,]{2,100})",
re.I,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept role-correction phrases when updating player role

For corrections like Actually, change me to the publicist or switch me to the backup dancer, classify_story_guide_input routes the turn as correction_update, but this new capture regex no longer includes the change me to / switch me to / i should be forms that the old detector accepted. Because correction turns do not fall back to nextMissing, the previous player_role remains in the context and the Brief/opening can preserve the wrong identity.

Useful? React with 👍 / 👎.

display_title: str | None = Field(default=None, min_length=1, max_length=72)
display_intro: str | None = Field(default=None, min_length=1, max_length=140)
premise_summary: str = Field(min_length=1, max_length=260)
player_role: str | None = Field(default=None, max_length=160)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce brief player role during opening consistency

Adding player_role makes the player's identity part of the reviewed Brief, but check_story_brief_opening_consistency never compares this field with opening.player_role_options or the opening text. If the live opening returns an otherwise valid cast and pressure while using a generic or different player role, the consistency gate passes and starts the session from the wrong identity instead of retrying or falling back.

Useful? React with 👍 / 👎.

Comment on lines +495 to +497
guide_context: {
scene_summary: guideLoopState.context.scene_summary,
player_role: guideLoopState.context.player_role,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Populate guide context when frontend fallback is used

When createNarrativeStoryGuideTurn fails, appendGuideTurn falls back to the local advanceStoryGuideLoop, whose state keeps the filled slots but does not populate context. This new payload then sends an empty guide_context, so the backend cannot set StoryBrief.player_role or preserve confirmed cast/pressure for that otherwise supported fallback path; synthesize the guide context from slots/accepted turns before calling the Brief API.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant