diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 98fc8b98a..b8320e293 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -5780,10 +5780,16 @@ "label": "執行閘門" } }, + "blockerFocus": { + "title": "目前卡在 G1:等待脫敏回覆", + "body": "先收五條路線的負責人角色、判定、範圍、理由與脫敏證據參照;未收到前不進預檢。", + "state": "阻塞焦點:S4.9 負責人回覆中繼資料", + "progress": "完成 0 / 3" + }, "nextGates": { "redactedOwnerResponse": { "title": "收到脫敏回覆", - "body": "先收到五條路線的 owner response metadata。" + "body": "先收到五條路線的負責人回覆中繼資料。" }, "preflightChecks": { "title": "通過六項預檢", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 98fc8b98a..b8320e293 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -5780,10 +5780,16 @@ "label": "執行閘門" } }, + "blockerFocus": { + "title": "目前卡在 G1:等待脫敏回覆", + "body": "先收五條路線的負責人角色、判定、範圍、理由與脫敏證據參照;未收到前不進預檢。", + "state": "阻塞焦點:S4.9 負責人回覆中繼資料", + "progress": "完成 0 / 3" + }, "nextGates": { "redactedOwnerResponse": { "title": "收到脫敏回覆", - "body": "先收到五條路線的 owner response metadata。" + "body": "先收到五條路線的負責人回覆中繼資料。" }, "preflightChecks": { "title": "通過六項預檢", diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx index ec873c6ce..9ace9aa13 100644 --- a/apps/web/src/app/[locale]/iwooos/page.tsx +++ b/apps/web/src/app/[locale]/iwooos/page.tsx @@ -1060,10 +1060,22 @@ const s49OwnerResponseIntakeNextGates: S49OwnerResponseIntakeNextGate[] = [ { key: 'humanAcceptance', gate: 'G3', value: '0 / 5', icon: ShieldCheck, tone: 'locked' }, ] +const s49OwnerResponseIntakeBlockerFocus = { + key: 'currentBlocker', + gate: 'G1', + value: '0 / 3', + icon: Clock3, + tone: 'warn' as const, +} + const s49OwnerResponseIntakeBoundaries = [ 's4_9_owner_response_intake_frontstage_lane_count=5', 's4_9_owner_response_intake_next_gate_count=3', 's4_9_owner_response_intake_next_gate_passed_count=0', + 's4_9_owner_response_intake_blocker_focus_count=1', + 's4_9_owner_response_intake_current_blocker_gate=G1', + 's4_9_owner_response_intake_next_gate_completion_count=0', + 's4_9_owner_response_intake_next_gate_total=3', 's4_9_owner_response_intake_received_count=0', 's4_9_owner_response_intake_preflight_passed_count=0', 's4_9_owner_response_intake_accepted_count=0', @@ -10808,6 +10820,7 @@ function IwoooSS49RequestDraftDetailBoard() { function IwoooSS49OwnerResponseIntakeBoard() { const t = useTranslations('iwooos.s49OwnerResponseIntake') const textWrap = { overflowWrap: 'anywhere' as const, wordBreak: 'break-word' as const } + const BlockerIcon = s49OwnerResponseIntakeBlockerFocus.icon const metrics = [ { key: 'received', value: '0 / 5', tone: 'warn' as const }, { key: 'preflight', value: '0 / 6', tone: 'locked' as const }, @@ -10873,6 +10886,63 @@ function IwoooSS49OwnerResponseIntakeBoard() { ))} +
+
+ +
+
+ {t('blockerFocus.title')} +
+
+ {t('blockerFocus.body')} +
+
+
+
{s49OwnerResponseIntakeBlockerFocus.gate}
+
{s49OwnerResponseIntakeBlockerFocus.value}
+
+
+
+ {s49OwnerResponseIntakeNextGates.map(item => ( +
+ ))} +
+
+ {t('blockerFocus.state')} + {t('blockerFocus.progress')} +
+
None: "s2_161_iwooos_s49_request_draft_detail_layer", "s2_162_iwooos_s49_owner_response_intake_first_layer", "s2_163_iwooos_s49_owner_response_intake_next_gates", + "s2_164_iwooos_s49_owner_response_intake_blocker_focus", ] assert_equal( "progress_delta_ledger.delta_ids", @@ -1816,6 +1817,26 @@ def validate(root: Path) -> None: iwooos_projection["summary"]["s4_9_owner_response_intake_next_gate_passed_count"], 0, ) + assert_equal( + "iwooos_projection.summary.s4_9_owner_response_intake_blocker_focus_count", + iwooos_projection["summary"]["s4_9_owner_response_intake_blocker_focus_count"], + 1, + ) + assert_equal( + "iwooos_projection.summary.s4_9_owner_response_intake_current_blocker_gate", + iwooos_projection["summary"]["s4_9_owner_response_intake_current_blocker_gate"], + "G1", + ) + assert_equal( + "iwooos_projection.summary.s4_9_owner_response_intake_next_gate_completion_count", + iwooos_projection["summary"]["s4_9_owner_response_intake_next_gate_completion_count"], + 0, + ) + assert_equal( + "iwooos_projection.summary.s4_9_owner_response_intake_next_gate_total", + iwooos_projection["summary"]["s4_9_owner_response_intake_next_gate_total"], + 3, + ) for count_key in [ "s4_9_owner_response_intake_received_count", "s4_9_owner_response_intake_preflight_passed_count", @@ -13180,6 +13201,71 @@ def validate(root: Path) -> None: f"iwooos_projection.s4_9_owner_response_intake_next_gates.{item['gate_id']}.not_authorization", item["not_authorization"], ) + s4_9_owner_response_intake_blocker_focus = iwooos_projection[ + "s4_9_owner_response_intake_blocker_focus" + ] + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.focus_id", + s4_9_owner_response_intake_blocker_focus["focus_id"], + "currentBlocker", + ) + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.display_mode", + s4_9_owner_response_intake_blocker_focus["display_mode"], + "first_screen_s4_9_owner_response_intake_blocker_focus", + ) + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.current_gate", + s4_9_owner_response_intake_blocker_focus["current_gate"], + "G1", + ) + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.current_gate_id", + s4_9_owner_response_intake_blocker_focus["current_gate_id"], + "redactedOwnerResponse", + ) + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.blocker_state", + s4_9_owner_response_intake_blocker_focus["blocker_state"], + "waiting_redacted_owner_response", + ) + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.completion_count", + s4_9_owner_response_intake_blocker_focus["completion_count"], + 0, + ) + assert_equal( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.gate_total", + s4_9_owner_response_intake_blocker_focus["gate_total"], + 3, + ) + for count_key in [ + "received_response_count", + "preflight_passed_count", + "accepted_response_count", + "runtime_gate_count", + ]: + assert_equal( + f"iwooos_projection.s4_9_owner_response_intake_blocker_focus.{count_key}", + s4_9_owner_response_intake_blocker_focus[count_key], + 0, + ) + assert_false( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.headline_review_authorized", + s4_9_owner_response_intake_blocker_focus["headline_review_authorized"], + ) + assert_false( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.runtime_execution_authorized", + s4_9_owner_response_intake_blocker_focus["runtime_execution_authorized"], + ) + assert_false( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.action_buttons_allowed", + s4_9_owner_response_intake_blocker_focus["action_buttons_allowed"], + ) + assert_true( + "iwooos_projection.s4_9_owner_response_intake_blocker_focus.not_authorization", + s4_9_owner_response_intake_blocker_focus["not_authorization"], + ) for text in [ 'data-testid="iwooos-first-screen-depth-map-board"', 'data-testid="iwooos-first-screen-depth-map-layers"', @@ -13423,6 +13509,8 @@ def validate(root: Path) -> None: for text in [ 'data-testid="iwooos-s49-owner-response-intake-board"', 'data-testid="iwooos-s49-owner-response-intake-metrics"', + 'data-testid="iwooos-s49-owner-response-intake-blocker-focus"', + 'data-testid="iwooos-s49-owner-response-intake-completion-rail"', 'data-testid="iwooos-s49-owner-response-intake-next-gates"', "iwooos-s49-owner-response-intake-next-gate-${item.key}", 'data-testid="iwooos-s49-owner-response-intake-lanes"', @@ -13430,8 +13518,10 @@ def validate(root: Path) -> None: "IwoooSS49OwnerResponseIntakeBoard", "s49OwnerResponseIntakeLanes", "s49OwnerResponseIntakeNextGates", + "s49OwnerResponseIntakeBlockerFocus", "s49OwnerResponseIntakeBoundaries", "s49OwnerResponseIntake", + "blockerFocus", "nextGatesTitle", "nextGates", "redactedOwnerResponse", @@ -13477,6 +13567,10 @@ def validate(root: Path) -> None: "s4_9_owner_response_intake_frontstage_lane_count=5", "s4_9_owner_response_intake_next_gate_count=3", "s4_9_owner_response_intake_next_gate_passed_count=0", + "s4_9_owner_response_intake_blocker_focus_count=1", + "s4_9_owner_response_intake_current_blocker_gate=G1", + "s4_9_owner_response_intake_next_gate_completion_count=0", + "s4_9_owner_response_intake_next_gate_total=3", "s4_9_owner_response_intake_received_count=0", "s4_9_owner_response_intake_preflight_passed_count=0", "s4_9_owner_response_intake_accepted_count=0",