本卡屬 FR-089(母卡 CM-1688),整體 arc review,只讀不修。建議 model:Opus,effort:high——要對 21 支套件與主專案 20 支接線做「同形」判定,並自己開檔復核五個 agent 的結論,不是機械核對。
FR-089 這條線要把 21 支 jedi-* 套件整理成同一種形狀(每支的 plugin 分五檔、api 分四件、logger 同名、實體一律 dataclass、能力點清單跟著套件走),並把主專案接套件的方式收成固定三步(pyproject 一行、core/plugins/<pkg>.py 一個檔三段、清單加一列)。共三段:jedi-asset 先定形(3 卡)→ FR-090 主專案側收斂(7 卡)→ FR-091 21 支套用(28 卡)。38 張卡都逐張驗過 Done,但每張驗的是「這張卡要做的 X 做了沒」,沒有人回頭問「38 張加起來,是不是真的做到了決策者要的『接手的人不用在一堆地方找設定』」。這一棒把整體看一遍,找出結構性問題,決策者拿結果一起裁發版、DI 瘦身、migrate FR 的順序。
docs/features/FR-089-2609-package-shape-unification/plugin-anatomy.md
「標準形狀」節六條規定=完成定義;「主專案怎麼接」「新手教程」=主專案側完成定義
docs/features/FR-069-2608-jedi-module-extraction/extraction-sop.md
§4.3 plugin 分檔規格(含 CAPABILITIES 三條硬規則、頂層不平鋪、api 四件、port 只在 domain/ports.py、tests 在套件根)
§5.1 主專案側五條、§5.2 接一支套件三步(capabilities= 不可省)
§3.4 logger 名 common.jedi_<pkg>
docs/features/FR-069-2608-jedi-module-extraction/design.md 第 3 節 D6/D7(插件契約與 harness,FR-089 不可違反的邊界)
docs/features/FR-089-2609-package-shape-unification/handoff/FR-089-STATE.md §2 已定裁示(14 條,review 不重開)
docs/features/FR-089-2609-package-shape-unification/handoff/FR-089-LOG.md(各棒決策與推翻紀錄,找「為什麼這樣做」用)
docs/features/FR-090-2609-host-side-residue-cleanup/README.md、docs/features/FR-091-2609-package-shape-rollout/README.md(卡表)
已有一份前置 review 涵蓋 FR-080(docs/review/2026-09-11-fr080-arc-review.md,3 Critical 9 Important 已全修)。這次接續不重做:那份看的是「有沒有做成插件」,這次看的是「形狀有沒有統一」。但要驗那份的修正在本 arc 大量搬檔後有沒有被搬壞。
BE /Users/chouraymond/Projects/Billows/Audit-Manager/compliance-manager-be
84ea07ef..0422c5d6(118 commits;非 docs 改動 233 檔 +5,709/-4,777)
重點:core/plugins/(22 檔)、app/auth/ 與 infra/iam/(FR-090 第 3 棒)、common/util/audit_nickname.py(第 4 棒)、
test/test_module_boundaries.py(守衛從 90 → 100 條)、config/app_modules.py
套件 /Users/chouraymond/Projects/Jedicogy/module/jedi-python-package
da25a8d..c26a313(172 commits;1,253 檔 +39,546/-27,052,21 支全動)
最大五支:jedi-iam 183 檔、task-platform 114、compliance-audit 107、detection 97、survey 93
FE/test 本 arc 不動。
兩 repo 都在 feature/FR-075,BE 領先 origin 數個 docs commit(0422c5d6 已在本機)。
plugin/contract.py、api/guards.py、plugin/__init__.py 三檔並排看:runtime() 的取法、三個 lazy decorator 的寫法、register() 的簽名、__all__ 的組成,有沒有「名字一樣、行為不一樣」的地方。這是本次 review 最重要的一題——形狀不統一就白做了。core/plugins/ 20 支接線檔是不是真的「照抄任一支就會」:_di()、_lazy()、host_defaults() 的用法有幾種變體?mount() 有幾種簽名?哪幾支沒走 register() 而是自己掛(survey socketio、task/compliance_audit attach、remote_agent 逃生門)——這些例外有沒有在檔頭講清楚為什麼。CAPABILITIES 宣告 80 筆、主專案 Plugin.capabilities 引用、seed 檔 127 筆、DEV DB 實際列。四者對得上嗎?DEFAULT_* 常數是不是真的從清單取(AST 守衛擋字面量,但有沒有套件用別的方式繞過)。survey/detection 從寫死字串收成 config,有沒有哪條 route 漏收、守門名字對不上 seed 導致永遠 403(這種錯不會有測試變紅,要靠開檔對)。common/util/audit_nickname.py 現在是主專案補暱稱的唯一路徑,守衛 test_audit_nickname_enrichment_has_single_implementation 擋手寫複本。但 app/flow_control/service/project_service.py:315(受評標的負責人)與 feedback_issue_dto.py 刻意不收(STATE §4 記了)——review 要判這兩處是「真的不是審計暱稱」還是漏網。_PORT_IMPL_ALLOWED_OUTSIDE_PLUGINS 白名單(test/test_module_boundaries.py:1162):每列都寫了「誰在用它」,逐列驗那個 caller 現在還在不在。搬檔 118 commit 後,白名單有沒有變成「理由已失效但沒人拿掉」。path.exists()/檔名字串判的(首腦驗 1737 時 test_converged_plugin_adapters_do_not_return_to_infra 被 __pycache__ 假紅過)、哪些能被「檔案改名」或「內容搬到別檔」繞過。列出有牙齒和沒牙齒的。harness/dev_app.py、17 支有 --smoke。三支沒 harness 的是哪三支、為什麼;有 --smoke 的抽五支實跑(asset/iam/detection/task-platform/compliance-audit,後兩支首腦記得沒 testcontainers 整合測試),跑不起來就是 Critical。pr-review-toolkit:code-reviewer ×2
A. spec 符合度:plugin-anatomy「標準形狀」六條 × 21 支逐支打勾表;SOP §5.1 五條 × 20 支接線檔逐支;
FR-069 D6/D7 有沒有違反;STATE §2 十四條裁示有沒有被某棒偷偷做成另一種
B. code 品質:CLAUDE.md DDD 層級/@transaction/error code/authz 走 common.authz 不另立/
審計欄位 enrich 走 D8;搬檔後有沒有「同一件事兩套讀法」(shim 與正本並存、re-export 指向舊物件)
pr-review-toolkit:silent-failure-hunter
runtime() 取不到 service 是當場炸還是回 None(asset 定的是炸);_assert_api_wiring 有沒有被某支改成「有就用沒有就跳」;
lazy provider 解析失敗的路徑;capability 名對不上 seed 的靜默 403;harness --smoke 假綠
pr-review-toolkit:type-design-analyzer
21 支 contract.py 的五個 dataclass(<Pkg>Adapters/Services/PluginConfig/SchemaExtensions/PluginHandle):
欄位是不是 frozen、Services 存 provider 不存實例有沒有型別表達、Capability 型別的不變量(name==resource.action);
entity 改 dataclass 後與 ORM 欄位對照(inspect.signature)有沒有漏
pr-review-toolkit:comment-analyzer
本 arc 一條硬規則:檔案內註解只留「為什麼」與「陷阱」,施工日誌進 commit message。
21 支+core/plugins/ 20 檔掃:還有沒有「第 N 棒/CM-xxxx/抽出前/原本/改判/等發版」;
另一方向:哪些真正的陷阱(例如 TaskLookupAdapter.status 不可正規化、identity 要給兩處)被收掉了不該收。
列清單不動檔。