Plan Review — bsmart-system
sab-branch transplant onto main
計劃評審 — bsmart-system
從 sab-branch 移植到 main

TRA-31 18 subtasks · 10 sub-PRs · 12 production gates18 個子任務 · 10 個 sub-PR · 12 道生產 gate QA-revisedQA 已修訂 2026-05-06

01Summary摘要

sab-branch is not a branch — it is an alternative timeline. It diverged from main 208 commits ago and rebuilt the commission engine, client model, claim workflow, and added two new modules (CRICOS registry + partner portal). A direct merge would silently delete six months of main-branch work. The plan’s core insight: treat the transplant as a cherry-pick replay, not a merge — and slice destructive changes into atomic backend+frontend co-commits so finance dashboards can’t regress mid-deploy.

sab-branch 不是一條普通分支 — 它是一條平行時間線。從 main 分岔出去後又走了 208 個 commit,重寫了佣金引擎、客戶模型、申領流程,並新增兩個模組(CRICOS 公開資料註冊 + 仲介自助門戶)。直接 merge 會悄悄洗掉 main 過去半年的工作。本計劃的核心洞見:把這次移植當作 cherry-pick replay,而不是 merge — 並把破壞性變更切成「後端 + 前端同 commit」的原子小包,避免財務 dashboard 在部署中途破掉。

Scope (verified against main HEAD): 90 files affected on sab-branch, ~+25,232 / −1,428 lines, spanning 12 product modules. The plan organises these into 18 Multica subtasks (TRA-32 → TRA-50, two new gates added after QA review), with 10 sub-PR splits inside three high-blast tasks and 12+ explicit production-safety gate items in the data-migration and security paths.

範圍(已對 main HEAD 實測):sab-branch 影響 90 個檔案,~+25,232 / −1,428 行,跨 12 個產品模組。本計劃把這些工作組織成 18 個 Multica 子任務(TRA-32 → TRA-50,QA 審查後新增兩個 gate),其中 3 個高風險任務再拆成 10 個 sub-PR,加上 12+ 條明確的生產安全 gate 散佈在資料遷移與安全路徑上。

02Impact dashboard影響評估儀表板

208
Commits Behind落後 commits
sab vs origin/main
90
Files Affected影響檔案數
on sab-branch diffsab-branch diff 上
+25,232
Lines Added新增行數
net of deletions扣除刪除後
−1,428
Lines Removed移除行數
incl. legacy paths含 legacy 路徑
+2,190
Test Lines測試行數
commission_semesters 245 → 2,435
12
Safety Gates安全 gate
data-migration + security資料遷移 + 安全
18
Subtasks子任務
TRA-32 → TRA-50
10
Sub-PR SplitsSub-PR 拆分
inside TRA-38/40/44在 TRA-38/40/44 內
9
New DB Tables新增 DB 表
kb_ + commission_ + partner_
5
Tables Altered修改的表
clients, institutions, courses, enrolments, commission_tracking
14
New Sheets新增 Sheet
finance + entity creation財務 + 實體建立
~1,016
i18n keys
509 EN + 507 zh-TW

Plan completeness indicators計劃完整度指標

Test coverage測試覆蓋
Sab-branch ships +5,500 test lines incl. test_commission_semesters.py 10× expansion. Covered.
sab-branch 帶來 +5,500 行測試,含 test_commission_semesters.py 10× 擴充。已覆蓋。
Docs / README文件
Plan doesn’t mention CLAUDE.md, MULTI_TENANT_SETUP.md, or API docs updates. Port required, not on plan.
計劃未提 CLAUDE.mdMULTI_TENANT_SETUP.md 或 API 文件更新。需要移植但不在計劃內。
Migration / rollback遷移與回滾
Covered. TRA-45 + TRA-46 each carry 5 explicit gates: dry-run, backup, staging-validate, rollback rehearse, idempotency proof.
已覆蓋。TRA-45 + TRA-46 各帶 5 道明確 gate:dry-run、備份、staging 驗證、回滾演練、idempotency 證明。
Security review安全審查
Covered. TRA-50 holds an explicit checklist (static analysis, JWT isolation, auth audit, security-reviewer agent pass, mount feature-flag).
已覆蓋。TRA-50 有明確 checklist(靜態分析、JWT 隔離、auth audit、security-reviewer agent pass、mount feature-flag)。
Performance效能
Lighthouse non-regression on ClientDetailPage is mentioned in TRA-44. FIFO recompute at scale is not benchmarked — gap.
TRA-44 提到 ClientDetailPage Lighthouse 不退步。FIFO recompute 在規模化下沒做 benchmark — 缺口。
Observability / metrics可觀察性
No mention of dashboards, alerts, or Sentry tags for the new commission flows. Gap.
完全沒提新佣金流程的 dashboard、警報或 Sentry tag。缺口。

03Current architecture現況架構 (main HEAD)(main HEAD)

Existing module既有模組
Will change destructively將被破壞性變更
Will be removed/deprecated將被移除或廢棄

A · CURRENT — main branch HEADA · 現況 — main 分支 HEAD

Ctrl/Cmd + wheel to zoom · drag to pan · double-click to fit · ⛶ opens full sizeCtrl/Cmd + 滾輪縮放 · 拖曳平移 · 雙擊回到 fit · ⛶ 開啟全頁

Loading…

04Planned architecture計劃架構 (after all 18 subtasks)(18 個子任務全部完成後)

Unchanged不變
New module全新模組
Heavily rewritten重度改寫
Schema changeSchema 變更

B · PLANNED — after sab cherry-pick replayB · 計劃 — sab cherry-pick replay 完成後

Same node names & layout direction as A — visual diff is the new emerald nodes.與 A 相同 node 名稱與佈局方向 — 視覺差異即新增的 emerald node。

Loading…

05Change-by-change breakdown變更細節

Phase 0 · P0 Gate Branch reconciliation — replay, not merge分支對帳 — replay 而非 merge TRA-49 [urgent]
Current現況
  • origin/sab-branch is 208 commits behind origin/main (verified).
  • Direct merge would silently delete those 208 commits (621 files diff, large deletions).
  • No reconciliation branch, no replay manifest, no sequencing decision.
  • origin/sab-branch 落後 origin/main 208 個 commit(已驗證)。
  • 直接 merge 會悄悄刪掉那 208 個 commit(diff 621 個檔,大量刪除)。
  • 沒有 reconciliation 分支、沒 replay manifest、沒排序決策紀錄。
Planned計劃
  • Create reconcile/sab-replay from fresh origin/main.
  • Dry-run cherry-pick of anchor commit c3ea8e5d first.
  • Build REPLAY-MANIFEST.md labelling every commit as replay | skip | mediate | drop.
  • Hold all destructive gates until manifest is signed.
  • 從 fresh origin/main 建立 reconcile/sab-replay
  • 先做 anchor commit c3ea8e5d 的 dry-run cherry-pick。
  • 建立 REPLAY-MANIFEST.md,給每個 commit 標 replay | skip | mediate | drop
  • 所有破壞性 gate 在 manifest 簽核前都凍結。
Rationale: sab and main are siblings that diverged. Merging conflates two timelines. Replaying gives an explicit audit trail. Documented QA verified 208; replay is the only safe option.
底層邏輯:sab 與 main 是分岔的兄弟。直接 merge 等於把兩條時間線揉在一起。Replay 提供明確的 audit trail。理由完整QA 已驗證 208;replay 是唯一安全選項。
Phase 1 · FoundationPhase 1 · 基礎 DB schema — additive first, drop laterDB schema — 先 additive,drop 後做 TRA-32 / TRA-33 / TRA-34
Current現況
  • No kb_cricos_*, commission_school_receipts, commission_invoice_items, or partner_portal_users tables.
  • commission_tracking.overall_status read in 11+ places in commissions.py alone (verified at lines 26, 115, 273, 309, 310, 336, 377, 415, 422, 450).
  • schemas/client.py (singular) is 6.5 KB; no is_company; enrolments table is thin.
  • Alembic migrations live in webapp/migrations/ + webapp/backend/migrations/ (two paths).
  • main 沒有 kb_cricos_*commission_school_receiptscommission_invoice_itemspartner_portal_users 等表。
  • commission_tracking.overall_statuscommissions.py 就被讀取 11+ 處(第 26、115、273、309、310、336、377、415、422、450 行)。
  • schemas/client.py(單數)共 6.5 KB;沒 is_companyenrolments 表很薄。
  • Alembic migrations 散在 webapp/migrations/ + webapp/backend/migrations/(兩條路徑)。
Planned計劃
  • TRA-32: add 9 new tables in one migration set — pure ADD, zero conflict.
  • TRA-33 (revised): add columns to 5 existing tables AND keep overall_status with a DeprecationWarning. Drop split into two future sub-gates (NOT yet in Multica).
  • TRA-34: add pypdf>=4.0.0 + start-dev.sh.
  • TRA-32:一次 migration set 加 9 張新表 — 純 ADD,零衝突。
  • TRA-33(已修訂):給 5 張現有表加欄位,並保留 overall_status 但發 DeprecationWarning。Drop 拆成兩個未來 sub-gate(尚未在 Multica 建)。
  • TRA-34:pypdf>=4.0.0 + start-dev.sh
Rationale: QA blocked the immediate column drop because main has 11+ live readers. Three-step deprecation avoids the "delete-while-still-read" foot-gun. Cognitive debt The two TRA-33-DROP sub-gates exist only in TRA-33's text — not as Multica issues.
底層邏輯:QA 擋住立即 drop,因為 main 有 11+ 個現役 reader。三步 deprecation 避開「邊讀邊刪」炸點。認知債兩個 TRA-33-DROP sub-gate 只活在 TRA-33 內文 — 沒在 Multica 建任務。
Phase 2 · Backend CorePhase 2 · 後端核心 Client v2, Workflow SSOT, CRICOSClient v2、Workflow SSOT、CRICOS TRA-35 / TRA-36 / TRA-37
Current現況
  • routers/clients.py 1,551 lines (2nd-largest backend file). Single name, no is_company.
  • VALID_STAGES is a global list — every visa type shares the same enum.
  • No routers/cricos.py on main (verified).
  • Pydantic schema at schemas/client.py (singular).
  • routers/clients.py 共 1,551 行(後端第二大檔)。單一 name,沒 is_company
  • VALID_STAGES 是全域 list — 每種簽證類型共用同一 enum。
  • main 沒有 routers/cricos.py(已驗證)。
  • Pydantic schema 在 schemas/client.py(單數)。
Planned計劃
  • TRA-35: Pydantic discriminated union on is_company. Discrepancy plan refers to schemas/clients.py — actual file is singular.
  • TRA-36: new core/workflow.py with valid_stages_for(...). 9 new stages. Visa enum renames.
  • TRA-37: brand-new module — routers/cricos.py + import script + 2 KB tables. Zero conflict.
  • TRA-35:Pydantic 在 is_company 上 discriminated union。不一致計劃寫 schemas/clients.py — 實際是單數。
  • TRA-36:新檔 core/workflow.pyvalid_stages_for(...)。9 個新 stage,Visa enum 改名。
  • TRA-37:全新模組 — routers/cricos.py + 匯入 script + 2 張 KB 表。零衝突。
Rationale: Per-type stages exist because branching if app_type == X in 30+ places became unmaintainable. kb_cricos_* shared (no tenant_id) is a deliberate read-only pattern with explicit "promote" copy-on-write.
底層邏輯:per-type stages 出現,是因為 30+ 處 if app_type == X 已不可維護。kb_cricos_* 共用(無 tenant_id)是刻意的 read-only 模式,搭配明確「promote」copy-on-write。
Phase 3 · Backend FeaturesPhase 3 · 後端功能 Commission Engine v2 — split into 3 sub-PRs佣金引擎 v2 — 拆成 3 個 sub-PR TRA-38 ⚠️ + TRA-39 + TRA-40 + TRA-41
Current現況
  • commissions.py 1,036 lines, commission_semesters.py 698 lines — combined ~1,734 lines using claimed, approved, overall_status.
  • _sync_commission_stats returns approved_amount, invoiced_amount, paid_amount.
  • Backend consumers: 7 files. Frontend consumers: 3 files (verified).
  • routers/enrolments.py 294 lines — no CoE parser.
  • commissions.py 1,036 行、commission_semesters.py 698 行 — 合計 ~1,734 行使用 claimedapprovedoverall_status
  • _sync_commission_stats 回傳 approved_amountinvoiced_amountpaid_amount
  • 後端使用者:7 個檔。前端使用者:3 個檔(已驗證)。
  • routers/enrolments.py 共 294 行 — 沒 CoE parser。
Planned計劃
  • TRA-38 Sub-PR 1: new commission_engine.py — FIFO, derive_overall_status().
  • TRA-38 Sub-PR 2: remove claimed/approved; new state machine.
  • TRA-38 Sub-PR 3 (atomic): Stats API rename — all 10 files in one commit.
  • TRA-39: enrolments.py 294 → 1,038 lines + coe_parser.py (208 LOC).
  • TRA-40 split into 4: Steps 4/5/6/7.
  • TRA-41: Partner portal behind feature flag.
  • TRA-38 Sub-PR 1:commission_engine.py — FIFO、derive_overall_status()
  • TRA-38 Sub-PR 2:移除 claimed/approved;新狀態機。
  • TRA-38 Sub-PR 3(原子):Stats API 改名 — 10 個檔同 commit
  • TRA-39:enrolments.py 294 → 1,038 行 + coe_parser.py(208 行)。
  • TRA-40 拆 4:Step 4/5/6/7。
  • TRA-41:仲介門戶藏在 feature flag 後面。
Rationale: QA caught that "TRA-38 = one PR" would tear backend from frontend, making finance pages blank between deploys. Atomic Sub-PR 3 is the fix. Cognitive flag "10-file atomic" rule isn't tooling-enforced. Mitigation: CI check that fails if Stats API changes without 3 frontend files in same commit.
底層邏輯:QA 抓到「TRA-38 = 一個 PR」會撕裂後端與前端,部署中財務頁變空白。原子 Sub-PR 3 即是針對此。認知 flag「10 檔原子」沒被工具強制。建議:加 CI 規則,若 Stats API 改了而前端 3 檔沒同 commit 就 fail。
Phase 4 · FrontendPhase 4 · 前端 SSOT helpers, i18n, 14 new sheets — 3 sub-PRsSSOT helpers、i18n、14 個新 sheet — 3 sub-PR TRA-42 + TRA-43 + TRA-44
Current現況
  • statusConfig.js as badge-renderer; no getStagesForType.
  • useFetch 30s GET cache; no force=true.
  • ClientDetailPage.jsx 58.6 KB (largest frontend). No Enrolments tab.
  • i18n: ~7 locales.
  • None of EnrolmentFormPage, CricosRegisterPage, UploadCoESheet exist (verified).
  • statusConfig.js 只是 badge renderer;沒 getStagesForType
  • useFetch 30s GET cache;沒 force=true
  • ClientDetailPage.jsx 58.6 KB(前端最大)。沒 Enrolments tab。
  • i18n:共 ~7 種 locale。
  • EnrolmentFormPage、CricosRegisterPage、UploadCoESheet 都不存在(已驗證)。
Planned計劃
  • TRA-42: add helpers, force-refresh, dark-mode select fallbacks.
  • TRA-43: +509 EN + 507 zh-TW keys (additive).
  • TRA-44 i: 8 finance sheets (depends on TRA-38 SubPR3).
  • TRA-44 ii: 6 entity-creation sheets.
  • TRA-44 iii: 3 new pages + ClientDetail Enrolments tab (lazy).
  • TRA-42:加 helpers、force-refresh、dark mode select fallback。
  • TRA-43:+509 EN + 507 zh-TW key(純新增)。
  • TRA-44 i:8 個財務 sheet(依賴 TRA-38 SubPR3)。
  • TRA-44 ii:6 個實體建立 sheet。
  • TRA-44 iii:3 個新頁面 + ClientDetail Enrolments tab(lazy)。
Rationale: Frontend split mirrors backend SubPR3 atomicity — sheets can’t merge until API rename PR is in. i18n separated so 1,000-key diff doesn’t drown review. Why missing TRA-44 doesn’t justify why 14 sheets up-front (vs. thin slice).
底層邏輯:前端拆分對應後端 SubPR3 原子性 — sheet 不能在 API 改名 PR 進來前 merge。i18n 獨立,避免 1,000-key diff 淹沒 review。理由缺失TRA-44 沒說明為何要一次出 14 個 sheet(而非薄薄一層)。
Phase 5 · Data MigrationPhase 5 · 資料遷移 course_enrollment → enrolments + receipts backfillcourse_enrollment → enrolments + receipts 回填 TRA-45 + TRA-46 (each behind 5 gates)
Current現況
  • applications table holds rows where application_type='course_enrollment' — these belong in enrolments.
  • commission_tracking FKs reference application_id.
  • commission_school_receipts table empty post-Phase-1.
  • applications 表中 application_type='course_enrollment' 的 row — 應屬於 enrolments
  • commission_tracking FK 指向 application_id
  • Phase 1 後 commission_school_receipts 表為空。
Planned計劃
  • TRA-45: SELECT/INSERT migration; rewrite FKs; archive old rows for 30 days.
  • TRA-46: create receipt per historical paid invoice; rerun recompute.
  • 5 gates each: dry-run · backup · staging-validate · rollback rehearse · idempotency proof.
  • TRA-45:SELECT/INSERT migration;改寫 FK;舊 row 封存 30 天。
  • TRA-46:給每筆歷史已付 invoice 建一筆 receipt;重跑 recompute。
  • 各 5 道 gate:dry-run · 備份 · staging 驗證 · 回滾演練 · idempotency 證明。
Rationale: 5-gate model encodes painful past lessons. Why partial Plan doesn't name DRI for hitting --commit.
底層邏輯:5-gate 編碼過去的痛苦教訓。理由不完整計劃沒指名按 --commit 的 DRI。
Phase 3D · Security GatePhase 3D · 安全 Gate Partner Portal — isolation proof before mount仲介門戶 — 上線前須證明隔離 TRA-50 [high]
Current現況
  • No /partner/* routes. No bcrypt JWT module. No partner_portal_users table.
  • /partner/* route。沒 bcrypt JWT 模組。沒 partner_portal_users 表。
Planned計劃
  • Independent auth/partner_portal_auth.py with bcrypt + separate JWT key.
  • Static-analysis grep gate on every SELECT in partner routes.
  • JWT negative tests: cross-tenant + cross-partner reads return 403.
  • Mount behind feature flag, OFF in prod until founder + security agent sign off.
  • 獨立 auth/partner_portal_auth.py,bcrypt + 獨立 JWT 金鑰。
  • 每個 SELECT 都做靜態分析 grep gate。
  • JWT 負面測試:跨 tenant + 跨 partner 讀取回 403。
  • 掛 feature flag 後面,prod 預設關,需要 founder + security agent 雙簽。
Rationale: One missing WHERE = data breach. Three layers of defence. Cognitive flag grep alone is fragile; feature flag depends on env-var hygiene.
底層邏輯:少一個 WHERE = 資料外洩。三層防線。認知 flag單靠 grep 太脆弱;feature flag 仰賴環境變數衛生。

06Dependency & ripple analysis連動分析

overall_status drop ripple — 11+ reader sitesoverall_status drop 連動 — 11+ reader 點
File檔案Sites點數Plan covers計劃覆蓋
routers/commissions.py11Yes
routers/claims.py≥1Implicit隱含
routers/finance_dashboard.py≥1Implicit隱含
routers/invoices.py≥1Implicit隱含
schema_manager.py≥1Yes
frontend reading overall_status前端讀 overall_status?Not surveyed未盤點
Stats API rename ripple — 10 files atomicStats API 改名連動 — 10 檔原子
Layer層級File檔案Plan covers計劃覆蓋
Backendrouters/commissions.pyYes / 是
Backendrouters/claims.pyYes / 是
Backendrouters/finance_dashboard.pyYes / 是
Backendrouters/invoices.pyYes / 是
Backendutils/sql_safe.pyYes / 是
Backendutils/sql_builder.pyYes / 是
Backendschema_manager.pyYes / 是
FrontendRevenueWidget.jsx (15.6 KB)Yes / 是
FrontendRevenueWidget.test.jsx (13.5 KB)Yes / 是
Frontendrevenue.schema.js (768 B)Yes / 是
Files NOT yet on main (no merge conflict risk)main 上還沒有的檔案(無 merge 衝突)
File檔案Owner subtask負責子任務
backend/utils/coe_parser.pyTRA-39
backend/routers/cricos.pyTRA-37
backend/routers/partner_portal.pyTRA-41
backend/routers/partner_auth.pyTRA-41
backend/auth/partner_portal_auth.pyTRA-41
backend/core/workflow.pyTRA-36
frontend/src/pages/EnrolmentFormPage.jsxTRA-44 iii
frontend/src/pages/CricosRegisterPage.jsxTRA-44 iii
frontend/src/components/.../UploadCoESheet.jsxTRA-44 ii
Likely ripple the plan does NOT mention計劃沒提到但可能波及
Surface表面Likely impact可能影響Plan計劃
export.py (70.9 KB) Reads client.name — dual-identity affects CSV exportsclient.name — 雙身份影響 CSV 匯出 Implicit隱含
routers/agent.py (51.3 KB) AI prompts may break with stage renameAI prompt 可能因 stage 改名破壞 Not mentioned未提
routers/automation.py (45.0 KB) Automations match on overall_status自動化以 overall_status 配對 Not mentioned未提
routers/audit.py (30.0 KB) Audit logs quote stage names稽核紀錄引用 stage 名稱 Implicit隱含
Sentry / observabilitySentry / 可觀察性 No new fingerprints/dashboards/alerts無新 fingerprint/dashboard/警報 Not mentioned未提

07Risk assessment風險評估

Edge: legacy claimed/approved rows邊緣:舊有 claimed/approved row
High
TRA-38 SubPR2 removes claimed/approved states. If prod rows carry these at deploy, engine throws on read.
TRA-38 SubPR2 移除 claimed/approved 狀態。若 prod 還有這些 row,engine 讀取就 throw。
Mitigation: pre-deploy SELECT COUNT(*) check; non-zero requires state-translation step.
建議:部署前 SELECT COUNT(*);非零就必須加 state 轉譯。
Ordering: SubPR3 must merge before TRA-44 i順序:SubPR3 必須在 TRA-44 i 之前
High
14 sheets read new keys. Wrong order = white-screen finance dashboards.
14 個 sheet 讀新 key。順序錯 = 財務 dashboard 白屏。
Mitigation: CI fail if old keys still referenced.
建議:CI 若舊 key 仍被引用就 fail。
Rollback: TRA-45 partly irreversible回滾:TRA-45 部分不可逆
High
FK rewrites reversible only if archive intact. After 30 days, rollback impossible.
FK 改寫只在封存完整時可回滾。30 天後無法回滾。
Mitigation: extend retention to 90 days OR cold storage.
建議:保留期延到 90 天或冷儲存。
Migration directory ambiguityMigration 目錄歧義
Med
Main has 3 migration dirs (webapp/migrations/, webapp/backend/migrations/, supabase/migrations/). Plan picks one without explanation.
main 有 3 個 migration dir。計劃只選一個沒解釋。
Mitigation: Phase 1 first sub-step clarifies active path.
建議:Phase 1 第一個 sub-step 釐清活的路徑。
Cognitive: TRA-33-DROP only in prose認知:TRA-33-DROP 只在內文
Med
Two future drop sub-tasks mentioned but never created in Multica. Column will linger forever.
兩個未來 drop 子任務有提但沒在 Multica 建。欄位永久殘留。
Mitigation: file TRA-33-DROP-A/B as blocked issues now.
建議:立刻把 TRA-33-DROP-A/B 建成 blocked issue。
Cognitive: grep static-gate fragile認知:grep 靜態 gate 脆弱
Med
Single missing WHERE = breach. Grep false-negatives on multi-line SQL or ORM.
少一個 WHERE = 外洩。grep 在多行 SQL 或 ORM 上 false negative。
Mitigation: back grep with integration test (cross-partner read returns 403).
建議:用 integration test 補 grep(跨 partner 讀回 403)。
Edge: PRISMS PDF format drift邊緣:PRISMS PDF 格式漂移
Med
CoE parser is pure regex. Format drift fails silently to manual fallback.
CoE parser 純 regex。格式漂移靜默失敗到手動 fallback。
Mitigation: Sentry breadcrumb for "parsed-fewer-than-N-fields".
建議:加 Sentry breadcrumb「parsed-fewer-than-N-fields」。
CRICOS XLSX import idempotentCRICOS XLSX 匯入 idempotent
Low
"Upsert on code" is safe. Read-only kb_ tables isolate tenant edits.
「Upsert on code」安全。Read-only kb_ 表隔離 tenant 編輯。
Mitigation: none required.
建議:無需處理。

08Plan review — Good · Bad · Ugly · Questions計劃審查 — 好 · 壞 · 醜 · 疑問

Good · what the plan gets right好 · 計劃做對的地方
  • Replay over merge. Acknowledging sab is a parallel timeline and refusing direct merge is the highest-leverage decision.
  • Atomic 10-file Stats API rename. SubPR3 forces backend + frontend in one commit.
  • Three-step deprecation of overall_status. Avoids "delete-while-still-read" outage.
  • Five gates on every data migration. Encodes painful past lessons.
  • Partner portal feature-flagged OFF in prod by default. Defence-in-depth.
  • Quantified done-when on every task. Specific tests, E2E flows, commit SHAs.
  • Replay 而非 merge。承認 sab 是平行時間線,拒絕直接 merge — leverage 最高的決定。
  • 原子 10 檔 Stats API 改名。SubPR3 強制後端 + 前端同 commit。
  • 三步 deprecation overall_status避開「邊讀邊刪」outage。
  • 每個資料遷移 5 道 gate。編碼了過去的痛苦教訓。
  • 仲介門戶 feature flag 預設關。縱深防禦。
  • 每個任務 done-when 量化。具體 test、E2E flow、commit SHA。
Bad · gaps that need filling壞 · 需要填的缺口
  • TRA-33-DROP sub-gates not in Multica. Risk: column drop never happens.
  • schemas/clients vs client path discrepancy. Coder will spend 5 minutes confused.
  • Migration directory ambiguity. 3 dirs, plan picks one.
  • No mention of export.py, agent.py, automation.py, audit.py ripple. ~200 KB at risk.
  • No DRI named for production migration runs.
  • i18n scope only EN + zh-TW. Other 5 locales unaccounted.
  • TRA-33-DROP sub-gate 沒在 Multica。風險:欄位 drop 永遠不發生。
  • schemas/clients vs client 路徑不一致。Coder 會困惑 5 分鐘。
  • Migration 目錄歧義。3 個 dir,計劃只挑一個。
  • 沒提 export.pyagent.pyautomation.pyaudit.py ripple。~200 KB 風險。
  • 生產 migration 沒指名 DRI。
  • i18n 範圍只 EN + zh-TW。其他 5 種 locale 沒交代。
Ugly · subtle concerns at scale醜 · 規模化下的細微疑慮
  • 10-file atomic SubPR3 will be enormous. Reviewers rubber-stamp due to diff fatigue.
  • FIFO recompute not benchmarked. 8 semesters × 10,000 students = seconds wait?
  • Two parallel auth surfaces. Doubles attack surface long-term.
  • Replay manifest = single Coder judgement. Out-of-order replay = silent corruption.
  • No sunset criterion for partner-portal feature flag. Toxic config risk.
  • 10 檔原子 SubPR3 龐大。Reviewer 因 diff 疲勞 rubber-stamp。
  • FIFO recompute 未 benchmark。8 學期 × 10,000 學生 = 秒級等待?
  • 兩套並行 auth。長期雙倍攻擊面。
  • Replay manifest = 單一 Coder 判斷。亂序 replay = 靜默損壞。
  • 仲介門戶 feature flag 沒退場條件。Toxic config 風險。
Questions · need clarification疑問 · 待釐清
  • Q1. Big-bang transplant or wave-by-wave deploy?
  • Q2. Who is the named DRI for prod --commit?
  • Q3. Are the 5 non-EN/non-zh-TW locales abandoned?
  • Q4. Lighthouse non-regression: CI baseline or manual?
  • Q5. Cleanup criterion for feature_flag_partner_portal_enabled?
  • Q1. 大爆炸移植還是 wave-by-wave 部署?
  • Q2. Prod --commit 的 DRI 是誰?
  • Q3. 5 個非 EN/zh-TW locale 是被放棄?
  • Q4. Lighthouse 不退步:CI baseline 還是人工?
  • Q5. feature_flag_partner_portal_enabled 的清理條件?

09Understanding gaps認知缺口

Decision rationale coverage決策理由覆蓋
Phase 0Phase 0
100%
Phase 1 schemaPhase 1 schema
75%
Phase 2 backendPhase 2 後端
60%
Phase 3 featuresPhase 3 功能
90%
Phase 4 frontendPhase 4 前端
55%
Phase 5 migrationsPhase 5 遷移
85%
Phase 3D securityPhase 3D 安全
95%
Cognitive complexity flags認知複雜度 flag
10-file atomic rename no CI10 檔原子改名無 CI
High
TRA-33-DROP only in proseTRA-33-DROP 只在內文
Med
Feature flag depends on env-varFeature flag 依賴環境變數
Med
PRISMS PDF drift silentPRISMS PDF 漂移靜默
Med
Replay manifest single judgementReplay manifest 單一判斷
Med
FIFO recompute unbenchmarkedFIFO recompute 未 benchmark
Med

Recommendations before implementation動工前的建議

R1 ·File TRA-33-DROP-A/B in Multica today (status = blocked).立刻在 Multica 建 TRA-33-DROP-A/B(status = blocked)。
R2 ·Add CI rule that enforces TRA-38 SubPR3 atomicity (Stats API + 3 frontend files in same commit).加 CI 規則強制 TRA-38 SubPR3 原子性(Stats API + 3 前端檔同 commit)。
R3 ·Name explicit DRIs in TRA-45/46 (DRI-on-keyboard / DRI-on-call).在 TRA-45/46 明確指名 DRI(鍵盤手 / on-call)。
R4 ·Add audit task for export.py, agent.py, automation.py, audit.py ripple (~200 KB).新增稽核任務:export.pyagent.pyautomation.pyaudit.py ripple(~200 KB)。
R5 ·Replace TRA-50 grep gate with integration test (cross-partner read returns 403).把 TRA-50 grep gate 換成 integration test(跨 partner 讀回 403)。
R6 ·Document partner-portal feature-flag sunset plan in TRA-41.在 TRA-41 寫清楚仲介門戶 feature flag 的退場計劃。