fix(web): stabilize governance tab hydration
Some checks failed
Code Review / ai-code-review (push) Successful in 15s
CD Pipeline / tests (push) Successful in 1m39s
CD Pipeline / build-and-deploy (push) Successful in 8m54s
CD Pipeline / post-deploy-checks (push) Successful in 1m47s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-27 12:26:49 +08:00
parent 6dca808d71
commit c8016fe651
2 changed files with 26 additions and 10 deletions

View File

@@ -13,6 +13,7 @@
* @created 2026-05-02 Claude Sonnet 4.6 — governance PR 2
*/
import { useEffect, useState } from 'react'
import { useTranslations } from 'next-intl'
import Link from 'next/link'
import {
@@ -33,12 +34,11 @@ import { AutomationInventoryTab } from './tabs/automation-inventory-tab'
export default function GovernancePage({
params,
searchParams,
}: {
params: { locale: string }
searchParams?: { tab?: string | string[] }
}) {
const t = useTranslations('governance')
const [requestedTab, setRequestedTab] = useState<string | undefined>(undefined)
const governanceSections = [
{ id: 'slo', order: '01', label: t('tabs.slo'), content: <SloTab />, Icon: Radar },
@@ -47,14 +47,16 @@ export default function GovernancePage({
{ id: 'agent-market', order: '04', label: t('tabs.agentMarket'), content: <AgentMarketTab />, Icon: BrainCircuit },
{ id: 'automation-inventory', order: '05', label: t('tabs.automationInventory'), content: <AutomationInventoryTab />, Icon: ShieldCheck },
]
const requestedTab = Array.isArray(searchParams?.tab) ? searchParams?.tab[0] : searchParams?.tab
const activeSection = governanceSections.find(section => section.id === requestedTab) ?? governanceSections[0]
const orderedSections = activeSection
? [
activeSection,
...governanceSections.filter(section => section.id !== activeSection.id),
]
: governanceSections
useEffect(() => {
const tab = new URLSearchParams(window.location.search).get('tab') ?? undefined
setRequestedTab(tab)
if (!tab) return
const section = document.getElementById(tab)
section?.scrollIntoView({ block: 'start' })
}, [])
return (
<AppLayout locale={params.locale}>
@@ -100,7 +102,7 @@ export default function GovernancePage({
</section>
<div className="grid min-w-0 gap-4">
{orderedSections.map((section) => {
{governanceSections.map((section) => {
const Icon = section.Icon
return (
<section key={section.id} id={section.id} className="min-w-0 scroll-mt-24">

View File

@@ -1,3 +1,17 @@
## 2026-06-27Governance 正式 hydration 修補:`?tab=` 不再改變 SSR section 順序
**背景**P2-415 i18n 修補完成部署後,正式瀏覽器 console 已無 `controlled_apply_ready` 缺字串,但仍出現 React hydration 類錯誤。追查後發現 `/governance` 是 client page卻用 `searchParams.tab` 在 SSR 階段重排 section`?tab=automation-inventory` 會讓 server / client 初始 section 順序不穩,造成 hydration mismatch。
**完成內容**
- `/zh-TW/governance` 的 section 順序固定為 SLO、治理事件、AI 待辦、Agent 市場、自動化盤點。
- 舊 `?tab=` deep link 只在 client mount 後讀取 `window.location.search`,用於高亮與 `scrollIntoView`,不再改變 SSR 初始 DOM。
**驗證結果**
- `pnpm --filter @awoooi/web typecheck`:通過。
**目前真相邊界**
- 本段只修補 Governance 前端 hydration 穩定度;不改任何 API snapshot、executor、Telegram、runtime gate 或正式寫入權限。
## 2026-06-27P2-415 正式瀏覽器讀回修補controlled apply i18n 缺字串歸零
**背景**P2-415 已推上正式環境並可由正式 API / 前台讀回,但瀏覽器 console 顯示既有 `controlled_apply_ready` 狀態缺少繁中 message key造成 `reportRuntimeReadiness``reportRuntimeDryRun` 兩段出現 `MISSING_MESSAGE` 雜訊。