Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0193vBv6w5MV2cifdTUu9H5P
75 lines
7.1 KiB
Markdown
75 lines
7.1 KiB
Markdown
# TASK · 领域命名审计:health / health_pressure 与 occupation / other 两组别名在十处比较里各走各的,统一成一处归并(2026-09-09)
|
||
|
||
- 基线:`origin/staging` @ `4067aff8`
|
||
- 分支:`codex/rectification-domain-alias-audit-20260909`,基于 `origin/staging`;与 `codex/rectification-skipped-health-deadend-20260909`(BUG-626/627)串行——**本单包含它的决策 1**,若它先合入则本单只补其余站点
|
||
- 执行方:coding agent;验收:Claude
|
||
- 涉及文件:`frontend/src/lib/rectification-agentic/v9/method-followup.ts`、`core/candidate-contrast-packet.ts`、`v9/server-focus.ts`、`scripts/rectification/event_probes.py`、`scripts/rectification/refinement_packet.py`、`scripts/rectification/contracts.py`
|
||
- BUG 编号起点:**BUG-628**(`docs/BUG_HISTORY.md` 当前最大 BUG-627)
|
||
- 优先级:**P1**(产品追问"其他领域会不会出现同样的问题":健康线还有六处同类漏洞;职业线一处;其余五个领域全线一致,无问题)
|
||
|
||
## 1. 审计结论
|
||
|
||
三套词汇并存:
|
||
|
||
| 层 | 健康 | 职业 |
|
||
| --- | --- | --- |
|
||
| 证据账本(`EVIDENCE_DOMAINS`、引擎事件、`contracts.py`) | `health`(`health_pressure` 仅作 v1 兼容) | `occupation` |
|
||
| 焦点 / 拒答记录(DB `target_domain` 约束,`persistableFocusDomain`) | `health` | **`other`** |
|
||
| 计划层、引擎探针 / 分盘层 / 盘外提示、题干与关键词表 | `health_pressure` | `occupation` |
|
||
|
||
教育、事业、感情、迁居、财务、家人六个领域三层同名,逐站核过,**没有同类问题**。
|
||
|
||
## 2. 逐站清单(健康)
|
||
|
||
| # | 位置 | 比较的两边 | 后果 | 现状 |
|
||
| --- | --- | --- | --- | --- |
|
||
| H1 | `method-followup.ts::holdoutFollowupFor` `!declined.has(item.domain)` | 拒答记录 `health` vs 盘外提示 `health_pressure` | 拒答 / 跳过的健康线被当作"没用过"再问,撞同 id 焦点静默 | BUG-626 |
|
||
| H2 | 同函数 `occupied` | 账本 `health` vs 提示 `health_pressure` | 已修(BUG-590 决策 4) | 已修 |
|
||
| H3 | `remainingReverseVerifyProbes` L718 `declined.has(probe.domain)` | 拒答 `health` vs 引擎探针 `health_pressure` | 采用后核对仍会问拒答过的健康线 | 未修 |
|
||
| H4 | `remainingConflictProbes` L789 同上 | 同上 | 区分题仍会问拒答过的健康线 | 未修 |
|
||
| H5 | `probeYearAlreadyCovered` L427 `item.domain !== domain` | 账本 `health` vs 探针 `health_pressure` | 用户已报 2024-10 受伤,仍可能被问"2024 年 10 月前后有没有生病受伤" | 未修 |
|
||
| H6 | 引擎 `oos_blind_prompts` `covered` 用事件域 | 事件 `health` vs 目录 `health_pressure` | 有健康事件时仍下发"还没用过健康压力这条线"(真实 Case JSON 已见) | 未修 |
|
||
| H7 | 引擎 `_event_years(events, "health_pressure")` → `_existence_blocked_years` | 同上 | 已报年份不阻断健康探针,出重复 / 引导题 | 未修 |
|
||
| H8 | 引擎 `volunteered` 集合(`VOLUNTEER_ONLY` 含 `health_pressure`) | 事件 `health` 永远不等于 `health_pressure` | 用户主动报了健康事件,D30 层仍被当"未主动提及"永不进入探针顺序——健康线被系统性低用 | 未修 |
|
||
| H9 | `candidate-contrast-packet.ts` L237 `item.domain === "health_pressure" \|\| HEALTH_RE.test(summary)` | 用摘要正则补别名 | 能工作,但是靠文案猜;摘要不含关键词就漏 | 改为归并 |
|
||
| H10 | `datedCollectDomainBlocked` / `hasConfirmedHealth` / `declinedHealth` | 已归并 | — | 已修 |
|
||
|
||
## 3. 逐站清单(职业)
|
||
|
||
| # | 位置 | 后果 | 现状 |
|
||
| --- | --- | --- | --- |
|
||
| O1 | `declinedDomains` 对职业焦点得到 `other`,`declined.has("occupation")` 永远为假(L1348 / L1386 / L1957 三处) | 靠 `occupationCollectFocusClosed` 按 `questionId` 前缀兜底;L1957 的兜底还额外要求 `careerCovered`——事业未覆盖时拒答职业会被再问 | 部分修 |
|
||
| O2 | `declinedDomains` 把职业拒答记成 `other` 塞进集合 | 目前无人查 `declined.has("other")`,无害 | 顺手清理 |
|
||
|
||
## 4. 决策记录
|
||
|
||
1. **一个归并函数,两侧各一份,语义相同。** TS:`canonicalCollectDomain(raw, questionId?)`:`health` → `health_pressure`;`target_domain === "other"` 且 `questionId` 以 `collect:occupation:` 开头 → `occupation`;其余原样。放在 `v9/domain-alias.ts`,`method-followup.ts`、`candidate-contrast-packet.ts` 全部经它比较;`hasConfirmedHealth` / `declinedHealth` 改为它的薄封装并保留。Python:`event_probes.py` 加 `canonical_domain(raw)`(`health` → `health_pressure`),`_event_years`、`oos_blind_prompts.covered`、`volunteered` 三处经它;`contracts.py` 的 v1 兼容项不动。
|
||
2. **DB 不改**:`target_domain` 约束仍是 `health` / `other`;归并只发生在读取侧。`persistableFocusDomain` 不变。
|
||
3. **H8 单独确认产品口径**:健康线本来就是"只有用户主动说才问"(SKILL.md §5),修完归并后主动报过健康事件的用户会开始收到 D30 层探针——这是原设计意图,不是新行为;进度记录写明。
|
||
4. 不动门槛、四选项合同、`SCORE_DELTA`;Skill 不 bump。
|
||
|
||
## 5. 任务分解
|
||
|
||
- 5.1 TS 归并函数 + H1/H3/H4/H5/H9/O1 六站改用;用例——每站一条:账本 `health` + 拒答 `health` + 探针 `health_pressure` → 不再问;职业拒答(topic `other` + `collect:occupation:` id)→ `declined.has("occupation")` 语义成立且事业未覆盖时也不再问职业。
|
||
- 5.2 Python 归并 + H6/H7/H8;用例(`tests/test_rectification_event_probes.py`)——事件域 `health` 2024-10 → `oos_blind_prompts` 不含 `health_pressure`;`_existence_blocked_years("health_pressure")` 含 2024;`volunteered` 含 `health_pressure`,D30 进入顺序。
|
||
- 5.3 源码合同:`agent-voice-copy-contract` 或新合同测试锁"`method-followup.ts` 里除归并函数外不得出现字面量 `"health"` 比较"(`grep -n '"health"' ` 只允许在 `domain-alias.ts`)。
|
||
- 5.4 记录:BUG-628(关联 BUG-590 决策 4、BUG-626、BUG-586 决策 2);`CHANGELOG.md`;`PROGRESS-…`;`CONTEXT.md` 术语表补一条"领域别名:health ≡ health_pressure,occupation 在焦点层存为 other"。
|
||
|
||
## 6. 让步顺序
|
||
|
||
5.1 与 5.2 必做同一提交;5.3 必做(防第三次复发);5.4 不可省。
|
||
|
||
## 7. 开工前置命令
|
||
|
||
```bash
|
||
git fetch origin --prune
|
||
git worktree add -b codex/rectification-domain-alias-audit-20260909 .worktrees/rectification-domain-alias-audit-20260909 origin/staging
|
||
cd .worktrees/rectification-domain-alias-audit-20260909
|
||
ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules
|
||
ln -s /workspace/Jyotisha/.venv .venv
|
||
grep -n '"health"' frontend/src/lib/rectification-agentic/v9/method-followup.ts frontend/src/lib/rectification-agentic/core/candidate-contrast-packet.ts scripts/rectification/event_probes.py scripts/rectification/refinement_packet.py
|
||
cd frontend && ./node_modules/.bin/tsc --noEmit; npm run lint 2>&1 | tail -1
|
||
ls tests/rectification-*.test.ts | grep -v database | xargs npx tsx --test 2>&1 | grep -E "^# (tests|pass|fail)"
|
||
cd .. && .venv/bin/python -m pytest tests/test_rectification_event_probes.py tests/test_rectification_v5_services.py -q
|
||
```
|