diff --git a/backend/app/services/governance_service.py b/backend/app/services/governance_service.py index 0b5b4c76..953a2fba 100644 --- a/backend/app/services/governance_service.py +++ b/backend/app/services/governance_service.py @@ -1145,8 +1145,38 @@ class GovernanceService: def _is_real_assignee(self, value: Optional[str]) -> bool: if not value or not value.strip(): return False - normalized = value.strip().upper() - return normalized not in {"TBD", "TBD_REAL_REVIEWER", "TBD_REAL_LEGAL_REVIEWER", "TBD_REAL_BUSINESS_REVIEWER", "TBD_REAL_OPS_REVIEWER", "TBD_REAL_LAUNCH_APPROVER", "UNASSIGNED", "PENDING"} + raw_value = value.strip() + normalized = raw_value.upper() + placeholder_values = { + "TBD", + "TODO", + "TBD_REAL_REVIEWER", + "TBD_REAL_LEGAL_REVIEWER", + "TBD_REAL_BUSINESS_REVIEWER", + "TBD_REAL_OPS_REVIEWER", + "TBD_REAL_LAUNCH_APPROVER", + "UNASSIGNED", + "PENDING", + "法务负责人", + "业务负责人", + "运营负责人", + "运维负责人", + "交付负责人", + "上线批准负责人", + "待法务复核", + "待业务复核", + "待运营复核", + "待上线批准", + "待复核", + "待签收", + } + if normalized in placeholder_values or raw_value in placeholder_values: + return False + if "TODO" in normalized or "TBD" in normalized: + return False + if raw_value.startswith("待") and any(token in raw_value for token in ("复核", "签收", "批准", "确认")): + return False + return True def _is_ready_evidence_status(self, status_value: Optional[str]) -> bool: return (status_value or "").strip().lower() in {"ready", "approved", "signed", "production_ready"} diff --git a/backend/tests/test_governance_service.py b/backend/tests/test_governance_service.py index c74ae3c4..2c9cfbbb 100644 --- a/backend/tests/test_governance_service.py +++ b/backend/tests/test_governance_service.py @@ -102,6 +102,25 @@ class GovernanceServiceTestCase(unittest.TestCase): self.assertEqual(snapshot["latest_release_batch"]["batch_name"], "formal-launch-import") self.assertGreater(snapshot["approval_metrics"]["review_tasks"], 0) + def test_placeholder_assignee_names_are_not_real_reviewers(self): + placeholders = [ + "TBD_REAL_REVIEWER", + "TBD_REAL_LEGAL_REVIEWER", + "PENDING", + "法务负责人", + "运营负责人", + "交付负责人", + "待法务复核", + "待业务复核", + "待上线批准", + ] + + for value in placeholders: + with self.subTest(value=value): + self.assertFalse(self.service._is_real_assignee(value)) + + self.assertTrue(self.service._is_real_assignee("法务A")) + def test_reimport_formal_launch_does_not_duplicate_assets_or_evidences(self): first_result = self.service.import_formal_launch(self.admin_user, batch_name="formal-launch-import-1") second_result = self.service.import_formal_launch(self.admin_user, batch_name="formal-launch-import-2") diff --git a/project-docs/AI合同起草与审查助手-当前工作进度保存-2026-05-11.md b/project-docs/AI合同起草与审查助手-当前工作进度保存-2026-05-11.md index 7dac671b..e223660c 100644 --- a/project-docs/AI合同起草与审查助手-当前工作进度保存-2026-05-11.md +++ b/project-docs/AI合同起草与审查助手-当前工作进度保存-2026-05-11.md @@ -662,3 +662,56 @@ - 完成生产材料、公开法律文件、模板、知识卡、规则、条款签收。 - 最终上线批准人填写并签收 `FINAL_APPROVER/final-launch-approval-checklist.md`。 - 本轮没有伪造任何 reviewer、签收结论或批准证据。 + +## 2026-05-13 远程 PostgreSQL 真相源接通与真实 reviewer 口径修正 + +### 本轮完成项 +- 已确认远程产品数据库真实路径: + - `192.168.3.90:5432` 可连但不是 `ai-contract-platform-postgres-1` 暴露端口,直接连宿主机 5432 会命中错误 PostgreSQL 实例。 + - 正确路径为通过 SSH 隧道连接 Docker 内部 `ai-contract-platform-postgres-1:5432`,并使用 `ai-contract-platform-backend-1` 的内部 `DATABASE_URL`。 +- 已将正式上线治理台账导入远程 PostgreSQL 产品库: + - 导入前 snapshot:`total_assets=0`。 + - 导入批次:`formal-launch-remote-truth-20260513`。 + - 导入结果:`assets=117`、`assignments=167`、`decisions=0`、`evidences=142`。 +- 已修正数据库真相源的真实 reviewer 统计口径: + - `backend/app/services/governance_service.py` 的 `_is_real_assignee` 现在会把 `法务负责人`、`运营负责人`、`交付负责人`、`待法务复核`、`待业务复核`、`待上线批准` 等占位值识别为非真实人员。 + - 新增单元测试覆盖中文占位 reviewer,不再低估缺真实复核人的数量。 + +### 本轮验证 +- gstack 预检:`GSTACK_OK`。 +- 远程产品库导入: + - `FORMAL_LAUNCH_GOVERNANCE_DB_IMPORT_PASS` + - 产物:`project-docs/qa-artifacts/formal-launch-governance-db-import/2026-05-13T11-53-55-203/formal-launch-governance-db-import-summary.md` +- 远程产品库导入后 snapshot: + - `FORMAL_LAUNCH_GOVERNANCE_DB_STATE_PASS` + - 产物:`project-docs/qa-artifacts/formal-launch-governance-db-state/2026-05-13T11-56-48-679/formal-launch-governance-db-state-summary.md` +- 数据库真相源批准门禁: + - `FORMAL_LAUNCH_APPROVAL_GATE_BLOCKED` + - `source_mode=database` + - 产物:`project-docs/qa-artifacts/formal-launch-approval-gate/2026-05-13T11-56-50-814/formal-launch-approval-summary.md` +- 后端验证: + - `python -m py_compile backend/app/services/governance_service.py backend/tools/formal_launch_governance_cli.py` 通过。 + - `python -m unittest tests.test_governance_service` 通过,`5 tests OK`。 + - `python -m unittest tests.test_governance_api` 通过,`6 tests OK`。 + +### 当前状态更新 +- 正式上线批准门禁已经不再依赖 CSV fallback,可通过远程 PostgreSQL 真相源验证。 +- 当前数据库真相源关键指标: + - `total_assets=117` + - `pending_assignments=167` + - `review_tasks=167` + - `missing_reviewer_tasks=167` + - `approved_review_tasks=0` + - `approved_materials=0` + - `approved_templates=0` + - `approved_knowledge_cards=0` + - `approved_review_rules=0` + - `approved_clauses=0` + - `blocked_required=9` + +### 当前阻塞项 +- 远程 PostgreSQL 真相源已接通并有治理台账数据;当前阻塞已经回到真实业务动作: + - 为 167 个复核/签收分配填写真实人员。 + - 真实 reviewer 完成审查、签收、证据留存。 + - 最终上线批准人签署 `FINAL_APPROVER/final-launch-approval-checklist.md`。 +- 本轮只导入正式治理台账和修正统计口径,没有伪造任何批准结论。