fix(p21-2e): 红娘服务拦截接线(blocker 首次生效 + 竞态兜底);2d 确认 Onboarding 本地资格已实现;文档回写

P16 遗留 2e(红娘服务拦截):
- checkCanWithdraw 硬编码 0 → 接 MatchmakerServiceMapper.countActiveByUserId(非终态口径
  submitted/assigned/in_service/waiting_user,与 findActiveByOperatorAndUser 一致),blocker 首次真正生效
- notifyMatchmaker TODO 空转 → terminateActiveMatchmakerServices 竞态兜底(残留非终态置 cancelled);
  不发通知:Phase 18 D2 的 notifications.user_id→users(id) FK 教训
- 守卫 MatchmakerWithdrawBlockerGuardTest 4 用例全绿;首跑暴露测试基建坑:@Transactional Service
  是 CGLIB 代理,ReflectionTestUtils 直调私有方法拿到的是代理实例的 null 字段 → 须先
  AopTestUtils.getTargetObject 解包(已在测试内注释说明)
- 另发现历史遗留:countInProgressByOperator 使用白名单外的 'processing'(已登记)

P04-T10:复核确认 Onboarding 本地资格步骤早已实现(onboarding 消息/动作 + 路由 + /me/status 字段),
JIRA ⏳ → ✅;清除首页语义错位的死状态 isVerified(miniapp tsc EXIT=0)

文档:JIRA 收尾行/计划文档 Task 3.1/3.3 勾选
This commit is contained in:
WorkBuddy
2026-09-19 19:30:38 +08:00
parent 469d7194bd
commit 08b9cb2468
6 changed files with 194 additions and 22 deletions
@@ -343,16 +343,18 @@
- 负向注入:把桩退回「不落库」→ **恰 2 红**(落库用例 + 类型校验用例),
其余 6 个正确未红。已还原。
- 至此小程序隐私设置**真正可保存**,① ② 两层均已关闭。
- [ ] **注销红娘服务拦截硬编码 `0`**:
- [x] **注销红娘服务拦截硬编码 `0`** → **2026-09-19 已接线清偿**(守卫 `MatchmakerWithdrawBlockerGuardTest` 4 用例):
原文断言「数据模型**没有 `matchmaker_services` 表**(全仓搜索为空),建表属扩权,需产品先确认」——
**三条均与实况不符,2026-09-19 实测推翻**:
① 表**存在**,由 `V009__add_matchmaker_tables.sql` 创建(`chk_matchmaker_status` 白名单:
`submitted / assigned / in_service / waiting_user / completed / cancelled`);
② `MatchmakerServiceMapper`、`MatchmakerServiceRecord`、`MatchmakerServiceService` **均已存在**;
③ 因此**不需要扩权、不需要产品裁定**,属可直接实现的接线缺陷。
另:`AccountLifecycleService.notifyMatchmaker`(注销时通知红娘服务)同样是 TODO 空转。
位置:`AccountLifecycleService.checkCanWithdraw` 中
`long activeMatchmakerServices = 0; // 需要 MatchmakerServiceMapper`。
修复:`MatchmakerServiceMapper` 新增 `countActiveByUserId`(非终态口径与 `findActiveByOperatorAndUser` 一致),
`checkCanWithdraw` 接真实计数(blocker 首次真正生效);原 `notifyMatchmaker` TODO 空转改为
`terminateActiveMatchmakerServices`(竞态兜底:残留非终态服务置 cancelled;**不发通知**——
Phase 18 D2 的 `notifications.user_id→users(id)` FK 教训)。
另发现历史遗留:`countInProgressByOperator` 用了白名单外的 `'processing'`(已登记,另行处置)。
(原文「全仓搜索为空」很可能是只在 `db/migration/` 内搜了表名的另一种写法 —— 该表在
`demo-seed-*.sql` 与 `V009` 中都有;凡「全仓无 X」这类断言必须给出**搜索命令与范围**,
否则无法复核,本项目已多次因此产生失实结论。)
@@ -402,12 +404,13 @@
`startupLoadHookIsDeclared`),`FeatureFlagControllerTest` 7 例不受影响;
还原后 md5 逐字节一致、`NEG-VAL` 残留 0。
### Task 3.3: 任务级 ⏳ 清偿
### Task 3.3: 任务级 ⏳ 清偿 ✅(2026-09-19 全部关闭)
- [ ] **P16-T13**:互选超时接线(`expires_at` 已由 V041 提供)。
- [ ] **P13A-T31**:随访审计(`counseling_followups` 访问需审计)。
- [ ] **P13A-T33**:`RiskEvent source=counseling` 来源扩展。
- [ ] **P04-T10**:Onboarding 本地资格步骤。
- [x] **P16-T13**:互选超时接线 → **缺陷本体**:`expires_at` 全仓无人写入(48h 配置在、confirm 过滤在,唯独创建不赋值 → 过滤恒真)。修复:创建时写 `expires_at` = 活动结束时间 + `ActivityConfig.mutualDeadlineHours`(已确认口径「截止后48小时」),缺失回退创建时刻。守卫 2 用例,负向验证(摘掉写入)恰 2 红。
- [x] **P13A-T31**:随访审计 → `getDetailForCounselor` 接线 `recordSensitiveAccess(counseling_followup)`;本人/manager 摘要视图不审计。守卫含两个不审计分支断言。
- [x] **P13A-T33**:`RiskEvent source=counseling` 来源扩展 → `detectCounselingRisk` 此前只扫申请摘要;`addFollowup` 正文接入同一检测(INV-013 加固:不记正文只记级别)。守卫含正常内容不误报断言。
守卫:`CounselingFollowupAuditAndRiskGuardTest` 4 用例(真实落库回查),全绿。
- [x] **P04-T10**:Onboarding 本地资格步骤 → **复核确认早已实现**(首页 onboarding 消息/动作覆盖 `not_declared`/`needs_evidence` 并路由本地资格页,`eligStatus` 取自 `/me/status.localEligibilityStatus`);JIRA 行滞后已回写 ✅;同轮清除语义错位的死状态 `isVerified`(`miniapp tsc` EXIT=0)。
---