diff --git a/frontend2/src/pages/play/components/play-action-jump.tsx b/frontend2/src/pages/play/components/play-action-jump.tsx
index 5c9a3721..21321b2d 100644
--- a/frontend2/src/pages/play/components/play-action-jump.tsx
+++ b/frontend2/src/pages/play/components/play-action-jump.tsx
@@ -34,7 +34,6 @@ export function PlayActionJumpButton({
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 12 }}
transition={transitions.snap}
- onPointerDown={onClick}
onClick={onClick}
aria-label={t("play.action_jump_title")}
title={t("play.action_jump_title")}
diff --git a/frontend2/src/shared/ui/header.tsx b/frontend2/src/shared/ui/header.tsx
index cdb0df0d..93d462b7 100644
--- a/frontend2/src/shared/ui/header.tsx
+++ b/frontend2/src/shared/ui/header.tsx
@@ -18,7 +18,6 @@ export function Header({
const { lang, setLang, t } = useLanguage()
const [menuOpen, setMenuOpen] = useState(false)
const accountName = auth.user?.display_name?.trim() || "reader"
- const accountInitial = accountName.slice(0, 1).toUpperCase()
const accountLabel = t("header.account")
const handleLogin = () => {
@@ -61,9 +60,6 @@ export function Header({
aria-expanded={menuOpen}
title={accountName}
>
-
- {accountInitial}
-
{accountLabel}
{menuOpen ? (
diff --git a/tests/test_author_product_api.py b/tests/test_author_product_api.py
index e65bd296..96903557 100644
--- a/tests/test_author_product_api.py
+++ b/tests/test_author_product_api.py
@@ -582,6 +582,24 @@ def test_author_job_service_loading_cards_are_stage_adaptive() -> None:
import rpg_backend.author.jobs as jobs_module
service = AuthorJobService()
+ settings = get_settings()
+ uncached_input_tokens = max(240 - 160 - 30, 0)
+ estimated_cost_rmb = (
+ uncached_input_tokens * settings.responses_input_price_per_million_tokens_rmb / 1_000_000
+ + 160
+ * settings.responses_input_price_per_million_tokens_rmb
+ / 1_000_000
+ * settings.responses_session_cache_hit_multiplier
+ + 30
+ * settings.responses_input_price_per_million_tokens_rmb
+ / 1_000_000
+ * settings.responses_session_cache_creation_multiplier
+ + 60 * settings.responses_output_price_per_million_tokens_rmb / 1_000_000
+ )
+ estimated_cost_usd = round(estimated_cost_rmb, 6) * settings.responses_usd_per_rmb
+
+ def expected_token_budget(total_tokens: int) -> str:
+ return f"{total_tokens} total tokens · USD {estimated_cost_usd:.6f} est."
def build_record(stage: str, stage_index: int, total_tokens: int | None) -> jobs_module._AuthorJobRecord:
metrics = None
@@ -622,7 +640,7 @@ def build_record(stage: str, stage_index: int, total_tokens: int | None) -> jobs
225,
{"theme", "structure", "working_title", "tone", "story_premise", "story_stakes", "generation_status", "token_budget"},
"Story frame drafted. Title, premise, and stakes are set.",
- "225 total tokens · USD 0.000020 est.",
+ expected_token_budget(225),
),
(
"cast_ready",
@@ -630,7 +648,7 @@ def build_record(stage: str, stage_index: int, total_tokens: int | None) -> jobs
300,
{"theme", "structure", "working_title", "tone", "story_premise", "story_stakes", "cast_count", "cast_anchor", "generation_status", "token_budget"},
"Cast roster drafted. NPC tensions are in place.",
- "300 total tokens · USD 0.000020 est.",
+ expected_token_budget(300),
),
(
"beat_plan_ready",
@@ -638,7 +656,7 @@ def build_record(stage: str, stage_index: int, total_tokens: int | None) -> jobs
360,
{"theme", "structure", "working_title", "tone", "story_premise", "story_stakes", "cast_count", "cast_anchor", "beat_count", "opening_beat", "final_beat", "generation_status", "token_budget"},
"Beat plan drafted. Main progression is mapped.",
- "360 total tokens · USD 0.000020 est.",
+ expected_token_budget(360),
),
(
"completed",
@@ -646,7 +664,7 @@ def build_record(stage: str, stage_index: int, total_tokens: int | None) -> jobs
570,
{"theme", "structure", "working_title", "tone", "story_premise", "story_stakes", "cast_count", "cast_anchor", "beat_count", "opening_beat", "final_beat", "generation_status", "token_budget"},
"Bundle complete. Story package is ready.",
- "570 total tokens · USD 0.000020 est.",
+ expected_token_budget(570),
),
]
diff --git a/tests/test_navigation_mental_model_contract.py b/tests/test_navigation_mental_model_contract.py
index a2940727..45a775f3 100644
--- a/tests/test_navigation_mental_model_contract.py
+++ b/tests/test_navigation_mental_model_contract.py
@@ -1110,6 +1110,8 @@ def test_home_topbar_account_ia_keeps_creation_in_hero() -> None:
assert "topbar-account__label" in header
assert "topbar-lang" in header
assert "topbar-account" in header
+ assert "accountInitial" not in header
+ assert 'className="topbar-account__avatar"' not in header
assert '"header.account": "Account"' in strings
assert '"header.account": "账号"' in strings
diff --git a/tests/test_play_direction_a_editorial_primitives_contract.py b/tests/test_play_direction_a_editorial_primitives_contract.py
index 8b361916..ccd9141f 100644
--- a/tests/test_play_direction_a_editorial_primitives_contract.py
+++ b/tests/test_play_direction_a_editorial_primitives_contract.py
@@ -2550,7 +2550,8 @@ def test_play_has_jump_to_action_affordance_when_choices_are_below_viewport() ->
assert "data-play-action-jump-stage={stage}" in action_jump
assert 'data-play-action-jump-compact={compactJump ? "true" : "false"}' in action_jump
assert 'data-play-action-jump-detail="true"' in action_jump
- assert "onPointerDown={onClick}" in action_jump
+ assert "onPointerDown={onClick}" not in action_jump
+ assert "onClick={onClick}" in action_jump
assert "isPlayElementAwayFromViewport" in action_jump_utils
assert "scrollToPlayActionArea" in action_jump_utils
assert "scrollToPlayImpactSummaryOrAction" in action_jump_utils