本卡屬 FR-089(母卡 CM-1688),修 arc review CM-1738 的 I-1 與 I-2,Important。建議 model:Opus,effort:medium——動 jedi-common 這支全體套件的下層,且要判斷「查不到回填 login_name」是不是前端依賴的行為。
I-1:把帳號換成暱稱填進 created_user_name/updated_user_name 這段程式碼,本 arc 在四支套件各複製了一份 app/service/_audit_names.py(asset/iam/survey/compliance-audit,前三支函式體逐字相同),加上主專案 common/util/audit_nickname.py 共五份。iam 那份註解寫「與 jedi_asset 是同一份的第二份拷貝,改這裡要一起改那裡」,寫下時 survey 與 compliance-audit 兩份還沒出現。五份會各自漂移,症狀是某支的人名恆為空白,靜默。
I-2:主專案守衛 test_audit_nickname_enrichment_has_single_implementation 判準是檔案裡有沒有 "UserQueryEntity(_in_login_name" 字串,只掃 app/ 與 common/。infra/readmodel/oscal/resource_library_query.py:132 用裸 SQL SELECT login_name, nickname FROM public.users WHERE login_name = ANY(:ln) 完全繞過,而且行為已經漂了:canonical 查不到補 None(common/util/audit_nickname.py:47-48),這份查不到回填 login_name(app/oscal/service/resource_library_app_service.py:139-141)。同一個欄位對前端吐不同語意。不是本 arc 引入,但本 arc 的 SOP §5.1 第 4 條正把這條守衛當「已焊死」。
jedi monorepo
jedi-common/jedi_common/identity/context.py:60 IdentityContext(:69 resolve_user_names)=新家
jedi-asset/jedi_asset/app/service/_audit_names.py:16 fill_user_names(dtos, identity)
jedi-iam/jedi_iam/app/service/_audit_names.py:19(含過期註解)
jedi-survey/jedi_survey/app/service/_audit_names.py:17
jedi-compliance-audit/jedi_compliance_audit/app/service/_audit_names.py:17 fill_user_names + :47 fill_user_names_in_rows(dict 版)
caller:asset device_service.py:45/information_system_service.py:46、iam user_service.py:71/role_service.py:25、bulletin bulletin_service.py:113(自己寫的 _fill_user_names,看它是不是又一份)、survey/compliance-audit 各 service
BE
common/util/audit_nickname.py(主專案 canonical,內部經 IdentityContext)
test/test_module_boundaries.py:1330 test_audit_nickname_enrichment_has_single_implementation
infra/readmodel/oscal/resource_library_query.py:132 get_user_nicknames 裸 SQL
app/oscal/service/resource_library_app_service.py:129-141 caller
jedi_common/identity/audit_names.py(或併進 context.py,看哪個讓 from jedi_common.identity import fill_user_names 最自然),內容取 asset 那份(含 fill_user_names_in_rows dict 版,compliance-audit 需要)。四支套件的 _audit_names.py 改成一行 re-export shim 或直接刪掉改 import(先 grep 各支 caller 數,少就直接改 import 刪檔,多就留 shim 一個發版週期)。iam 那條「第二份拷貝」註解刪。bulletin 的 _fill_user_names 開檔看,若是第六份一併收。pyproject.toml 查 jedi-common 那行),改動重啟即生效,不 bump 版本、不發版。但四支套件 pyproject.toml 對 jedi-common 的相依下限若寫了版號,要對到實際會有這個函式的版本——這條是 memory feedback_review_before_publish_and_dep_floor 的坑,先看現在寫多少,回寫時說明「發版時下限要提到 X」。test_audit_nickname_enrichment_has_single_implementation 掃描範圍加 core 與 infra/readmodel;判準除字串外加「同一檔內出現 nickname 且出現 created_user_name 或 updated_user_name 賦值」(AST 或 regex 都可,寫明選哪種與為什麼)。加完會把 resource_library_query.py/resource_library_app_service.py 照出來。resource_library_app_service.py:129-141 改呼叫 common/util/audit_nickname.py 的 canonical(看它的 signature 收 dict list 還是 obj list,選對的那支),刪 resource_library_query.get_user_nicknames。「查不到回填 login_name」這個行為差異要先查 FE:grep -rn "created_user_name" ~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/views/oscal ~/Projects/Billows/Audit-Manager/compliance-manager-fe/src/components 找資源庫頁面怎麼顯示,若 FE 對 null 有 fallback 顯示 login_name 就照 canonical 補 None;若 FE 直接顯示會變空白,先回寫本卡問決策者選「canonical 加 fallback 參數」或「FE 補 fallback」,再動手。_audit_names 測試若有,改指新位置後要綠。resource_library_query.py:132 那段裸 SQL 加回去(或不刪先跑)→ 守衛要紅。core/plugins/ 任一檔塞一段 nickname+created_user_name = 賦值 → 守衛要紅(證明範圍真的擴到 core)。還原。全量:jedi-common/asset/iam/survey/compliance-audit/bulletin 六支 tests/ 各 tail -1(自己 commit 的 worktree);BE pytest test/test_module_boundaries.py test/test_fr048_*.py -q。
POST /api/1.0/devices、使用者列表、問卷列表、資源庫列表(oscal resource library 端點,從 api/oscal/ 抓)各打一次帶 token,回應裡 created_user_name 有暱稱(blsadmin 建的資料應顯示其 nickname)。jedi_common.identity.fill_user_names」;docs/claude/domain-capabilities.md 若有登記 audit_nickname 那列,補 jedi-common 這支。