Files
2026-02-02 11:22:35 +08:00

144 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# User Profile Scoring任务清单 · V1.2
> 依据:`spec_kit/User Profile Scoring/plan.md`V1.2
>
> 规则目标:在客户端实现“问卷答案(可跳过)→ 用户画像(含 profile_answered/confidence+ 硬规则输出”,供推荐/Push/Widget 复用。
## 任务状态说明
- `[ ]`:未开始
- `[~]`:进行中
- `[x]`:已完成
- `[-]`:已取消/不做
---
## A. 代码实现(客户端 TypeScript 模块)
### A1. 建立目录与导出入口
- [x]`client/src/features/` 下新增目录 `userProfileScoring/`
- **验收**:目录存在,且后续文件均放入该目录
- [x] 新建 `client/src/features/userProfileScoring/index.ts`
- **内容**:对外导出主函数与类型(避免上层直接深路径 import
- **验收**:上层可仅从 `.../userProfileScoring` 引入
### A2. 定义类型与枚举V1.2
- [x] 新建 `client/src/features/userProfileScoring/types.ts`
- **定义输入类型**`QuestionnaireAnswersV1_2`
- 字段允许 `undefined`/`null``mom_stage/emotion/context/need`
- **定义输出类型**`UserProfileV1_2`
- 固定 `profile_version: "v1.2"``profile_source: "questionnaire"`
- `profile_answered``{ stage; emotion; context; need }`
- `emotion_score: number | null`
- `context/need: Record<string, 1>`(稀疏 one-hot跳过为 `{}`
- **定义扩展输出类型**`UserProfileV1_2_Extended`
- `rule_hits: string[]`
- `hard_rules: { forbidden_risk_flags: string[]; forbidden_content_predicates: ... }`
- **验收**:类型字段与 `spec_kit/User Profile Scoring/spec.md`V1.2)一致
### A3. 实现答案归一化(非法值按跳过)
- [x] 新建 `client/src/features/userProfileScoring/scoring.ts`
- [x] 实现 `normalizeAnswers(raw): QuestionnaireAnswersV1_2`
- **规则**
- 值不在枚举内 → 归一化为 `undefined`
- `null` 保留为 `null`(表示显式跳过/无值)
- **验收**:任意输入不抛错;输出只包含合法枚举/`undefined`/`null`
### A4. 计算 profile_answeredV1.2
- [x] 实现 `computeProfileAnswered(normalized)`
- `stage = (mom_stage !== undefined && mom_stage !== null)`
- `emotion/context/need` 同理
- **验收**:与 `spec.md` 6.1.1 一致;可区分“缺失/跳过”与“明确作答”
### A5. 计算时间衰减 conf_time
- [x] 实现 `computeTimeConfidence(generatedAt, now): number`
- **规则**(与 `spec.md` 6.2 一致):
- 07 天1.0
- 730 天:线性衰减到 0.7
- 30 天以上0.5
- **验收**:给定固定时间输入,输出符合分段规则(允许浮点误差)
### A6. 计算 profile_confidenceV1.2 完整度因子 + clamp
- [x] 实现 `computeProfileConfidence(conf_time, profile_answered): number`
- **规则**(与 `设计说明文档/客戶端問卷打分規則.md` V1.2 一致):
- `answered_count = Σ I[profile_answered.* = true]`
- `completion = answered_count / 4`
- `completion_factor = 0.5 + 0.5 * completion`
- `conf = clamp(conf_time * completion_factor, 0.2, 1.0)`
- **验收**
- 全部跳过且 `conf_time=1``conf=0.5`
- 全部作答且 `conf_time=1``conf=1.0`
- 极端情况下不会低于 0.2 / 高于 1.0
### A7. 生成四维度画像字段(含跳过策略)
- [x] 实现 `buildUserProfileFromQuestionnaire(answers, options)`
- **元信息**
- `profile_version="v1.2"`
- `profile_source="questionnaire"`
- `profile_generated_at`:允许注入;默认 `new Date().toISOString()`
- **stage**
-`mom_stage` 缺失/为 `null`:按安全策略输出 `stage.unknown=1`
- 若为枚举:对应 one-hot
- **emotion_score**
- 若跳过:`null`
- 否则按映射表输出数值
- **context/need**
- 若跳过:输出 `{}`
- 否则输出稀疏 one-hot例如 `{ work: 1 }`
- **验收**:与 `spec.md` 4.2/5.x/6.x 一致
### A8. 硬规则与可观测输出rule_hits / hard_rules
- [x]`buildUserProfileFromQuestionnaire` 内生成 `rule_hits``hard_rules`
- **risk_flags 映射规则**(与 `spec.md` 7 一致):
- `stage.unknown=1``unsafe_for_stage_unknown`
- `stage.parenting=1``unsafe_for_stage_parenting`
- `emotion_score !== null && emotion_score<=0.2``unsafe_for_emotion_low`
- **跨维度规则谓词**(与 `spec.md` 7、客户端规则 V1.2 一致):
-`stage.unknown=1`:追加谓词
- `id`: 建议 `unknown_block_parenting_pressure_personalized`
- `when_user`: `{ stage_unknown: true }`
- `forbid_content`: `{ need: "parenting_pressure", personalization_power: 1 }`
- **验收**
- 输出结构稳定
- 不依赖内容侧字段(本模块只输出“可执行条件”)
---
## B. 单元测试(只测纯函数)
> 若当前工程暂不引入测试框架,可先把测试用例写成“可执行脚本/最小断言”;但建议最终落地 `vitest` 或 `jest`。
### B1. 建立测试框架(可选但建议)
- [x]`client/` 尚无测试:引入 `vitest`(或 `jest`)并添加 `test` 脚本
- **验收**:能在本机运行测试并输出结果
### B2. 覆盖 spec.md 的关键用例
- [x] 用例:完整作答映射正确(对应 `spec.md` 用例 A/B
- [x] 用例:时间衰减(对应 `spec.md` 用例 C/D/E
- [x] 用例:全部跳过 `{}`(对应 `spec.md` 用例 A2
- 断言:`profile_answered` 全 false`stage.unknown=1``emotion_score=null``context/need={}``profile_confidence=0.5`(当 conf_time=1
- [x] 用例:硬规则命中
- `emotion_score<=0.2` → 含 `unsafe_for_emotion_low`
- `stage.parenting=1` → 含 `unsafe_for_stage_parenting`
- `stage.unknown=1` → 含 `unsafe_for_stage_unknown` 且带跨维度谓词
---
## C. 接入与文档回写(后续任务)
- [ ] Onboarding 提交问卷处接入本模块(调用 `buildUserProfileFromQuestionnaire`
- **验收**:提交后能生成并持久化/上传画像对象(具体存储策略由上层决定)
- [ ] 在推荐/Push/Widget 侧消费 `hard_rules`
- **验收**Hard Filter 在打分前执行;且能使用跨维度谓词表达 unknown+育儿压力强个性化禁推