# n05-salary-calc 执行合同 ## Intent Lock - **变更名称**:`n05-salary-calc` - **要解决的问题**:当前后端没有城市职工社保、公积金、大病固定费和到手工资估算能力,求职者无法基于地级行政区默认参数、个人覆盖项和累计预扣法获得可复核的结果,也无法保存独立的历史快照。 - **范围内**:新增仅限登录 `STUDENT` 的 `/salary-calculator/**` 后端模块;新增 `V40/V41` 城市政策和历史表;`V41` 采用 `CITY` 与 `PROVINCE_FALLBACK` 分层数据并覆盖全部目标城市;实现城市参数、用户覆盖、工资计算、累计预扣、历史保存/查询/物理删除、政策版本校验、幂等并发、账号注销清理、OpenAPI 和测试。 - **范围外**:前端页面、ADMIN 政策维护、企业成本、年终奖/股权/多收入来源、年度汇算、非居民税制、薪资参考、Offer 关联、个人数据导出和港澳台政策。 ## Approved Behavior - **已批准需求摘要**:`specs/salary-calculation/spec.md` 与 `specs/salary-history/spec.md` 中的 22 条 `### Requirement` 全部批准,覆盖: - STUDENT-only 权限和六个接口。 - 城市政策目录、地级行政区粒度、版本元数据和全量种子。 - 用户覆盖优先、基数截断、个人五险一金、大病固定费。 - 累计月份、专项附加扣除、居民个人综合所得累计预扣、到手工资和完整结果拆解。 - 输入范围、金额精度和 `9801–9805` 错误语义。 - 自动保存历史、完整可重建快照、幂等并发、个人隔离、分页、不可编辑、物理删除和长期保留。 - 历史不进业务审计日志或数据导出,账号注销时物理清理。 - `V40/V41` 迁移、全量城市覆盖、`CITY`/`PROVINCE_FALLBACK` 精度标识、唯一键、索引和完整性约束。 - **关键场景**:城市政策版本冲突不生成历史;覆盖基数超出城市范围返回 400;`monthIndex` 表示累计计税月份;累计税额不产生负数;相同幂等键只创建一条历史;跨用户历史统一返回 404;城市停用不影响旧历史;账号注销完成删除全部薪资历史。 - **验收检查**:六个接口的 MockMvc/E2E 场景,城市种子完整性测试,金额边界测试,幂等并发测试,权限与注销测试,OpenAPI 校验,真实 MySQL/Docker 黑盒验收。 - **未映射需求**:无。22 条需求均在 `tasks.md` 的 Requirement-to-Task Coverage 中有任务覆盖。 ## Design Constraints - **架构约束**:新增 `com.mydreamjob.salarycalculator` 模块,复用 `ApiResponse`、`PageResponse`、`SecurityContext`、`UserRepository`、`DeletionGuardInterceptor` 和现有注销事务;不引入外部服务。 - **接口约束**:只提供以下接口,并仅在成功请求时创建历史: - `GET /salary-calculator/cities` - `GET /salary-calculator/cities/{cityCode}` - `POST /salary-calculator/calculations` - `GET /salary-calculator/calculations` - `GET /salary-calculator/calculations/{id}` - `DELETE /salary-calculator/calculations/{id}` - **计算约束**:使用 `BigDecimal`;城市只提供社保/公积金/大病参数;全国税率表、速算扣除数、5,000 元减除费用和税率版本在代码中维护;`expectedPolicyVersion` 必须匹配。 - **数据约束**:只新增 `salary_city_policy` 和 `salary_calculation_history`;城市编码唯一,历史用户+幂等键唯一;城市 `data_level` 必须为 `CITY` 或 `PROVINCE_FALLBACK`,回退城市使用所属省级参数并在所有相关响应和快照中显式标记;输入、最终参数和结果 JSON 快照必须可独立读取;账号注销物理删除历史。 - **隐私约束**:日志不得记录金额、基数、税额或快照;历史不写业务审计日志、不进入个人数据导出。 ## Execution Plan - **推荐模式**:`sdd`。任务跨越迁移、查询、计算、历史、权限/注销、测试和文档多个波次,需要显式依赖和 review receipt。 - **用户确认状态**:DP-4 待 DP-3 通过后由 `build-executor` 重新运行 `ssf execution recommend` 并由用户确认。本合同不把推荐自动视为已选择。 - **执行计划命令**:待 DP-4 确认后由 `build-executor` 执行 `ssf execution plan --mode sdd --confirm --reason "<用户确认原因>" --wave ...`。 - **计划 revision / artifact hash**:由 `ssf execution plan` 或状态重建记录。 ## Execution Waves ### Wave W1 - 数据基础 - **Wave ID**:`W1` - **任务**:`1`, `2` - **依赖 wave**:无 - **策略**:`serial` - **目标**:完成 `V40` 表结构(含 `data_level`)、领域持久化基础、`V41` 分层城市政策种子及全量种子校验。 - **输入**:`V39` 现状、官方行政区划清单、公开城市政策资料、实体/Repository 约定。 - **输出**:两张业务表、实体、Repository、城市种子和迁移/种子测试。 - **完成标准**:H2/MySQL 迁移成功;目标城市全覆盖、编码唯一、字段合法、日期不晚于采集截止日、版本号非空;每条记录准确标记 `CITY` 或 `PROVINCE_FALLBACK`。 - **Review gate**:报告 `.superpowers/sdd/reviews/W1.md`;wave 完成时记录 base/head SHA;`ssf execution review` 必须为 `pass`。 ### Wave W2 - 城市查询与计算引擎 - **Wave ID**:`W2` - **任务**:`3`, `4` - **依赖 wave**:`W1` - **策略**:`serial` - **目标**:实现城市列表/详情接口和精确薪资计算引擎。 - **输入**:W1 实体/Repository/城市种子、公式约束、DTO 与校验规则。 - **输出**:城市 Service/Controller/DTO;计算器、税率表、输入/结果 DTO;服务与控制器测试。 - **完成标准**:STUDENT 可查询城市默认参数;基数截断、覆盖率、个人缴费、累计预扣、税额下限和金额精度测试通过。 - **Review gate**:报告 `.superpowers/sdd/reviews/W2.md`;wave 完成时记录 base/head SHA;`ssf execution review` 必须为 `pass`。 ### Wave W3 - 历史、幂等、权限与注销 - **Wave ID**:`W3` - **任务**:`5`, `6`, `7` - **依赖 wave**:`W2` - **策略**:`serial` - **目标**:实现计算并保存、历史 CRUD、政策版本校验、幂等并发、用户隔离、注销守卫和物理清理。 - **输入**:W2 计算服务和城市接口;历史表/Repository;现有错误码与注销事务。 - **输出**:计算/历史 Service 与 Controller、`9801–9805`、幂等指纹、注销清理调用及集成测试。 - **完成标准**:正常计算返回历史 ID;版本冲突返回 409/9805;同键重放返回原历史;跨用户 404;删除物理生效;注销完成无历史残留。 - **Review gate**:报告 `.superpowers/sdd/reviews/W3.md`;wave 完成时记录 base/head SHA;`ssf execution review` 必须为 `pass`。 ### Wave W4 - 发布证明与文档 - **Wave ID**:`W4` - **任务**:`8`, `9` - **依赖 wave**:`W3` - **策略**:`serial` - **目标**:补齐模块测试、OpenAPI、API/联调文档、README/路线图,执行全量回归和真实 MySQL/Docker 黑盒验收。 - **输入**:W1–W3 全部代码和测试;现有 OpenAPI 校验脚本。 - **输出**:六个接口的静态契约和文档、模块专项测试、全量构建结果、MySQL 黑盒验收记录。 - **完成标准**:`mvn -Dtest=Salary*Test test`、`mvn clean verify`、`python docs/verify_openapi.py` 通过;真实 MySQL/Docker 迁移与六个接口验收通过。 - **Review gate**:报告 `.superpowers/sdd/reviews/W4.md`;wave 完成时记录 base/head SHA;`ssf execution review` 必须为 `pass`。 ## Test Obligations - **必须先从失败测试开始的行为**:城市种子完整性和范围校验;基数截断与用户覆盖;个人养老/医疗/失业/公积金/大病费用;累计月份与累计预扣;政策版本冲突;幂等重放/冲突;跨用户历史隔离;物理删除;账号注销清理。 - **必需的边界情况**:基数下限、上限和区间中值;比例 0;大病固定费为 0;专项附加扣除为 0 和大于月薪;`monthIndex=1` 和 12;税率档边界;重复删除;城市停用后的旧历史;金额超过两位小数;`size=101`。 - **回归敏感区域**:现有账号注销守卫和完成事务;用户角色读取;`ErrorCode` 新增值;`SecurityConfig` 路由;既有 OpenAPI 路径总数;H2 与 MySQL 对 JSON/唯一约束的行为差异。 - **测试命令**:专项 `mvn -Dtest=Salary*Test test`;完整 `mvn clean verify`;契约 `python docs/verify_openapi.py`;发布门禁另执行真实 MySQL/Docker 黑盒验收。 ## Execution Mode - **可用方式与推荐**:`inline`、`batch-inline`、`sdd`;推荐 `sdd`。 - **用户确认的模式**:DP-4 阶段确认,本合同不代替用户选择。 - **推荐理由 / 项目事实**:9 个任务拆为 4 个有依赖的 wave,跨数据库迁移、计算、API、权限和历史生命周期,必须保留 review receipt。 - **非推荐选择的风险确认**:不适用;若用户选择非推荐模式,必须由 CLI 记录 `--acknowledge-recommendation`。 - **执行计划命令**:由 `build-executor` 在 DP-4 后运行。 - **允许的修订**:仅可保留或升级为 `sdd`;新 revision 必须先刷新 recommendation,并清除旧 receipt。 - **计划 revision / artifact hash**:执行计划保存后记录。 ## Verification Dimensions | 维度 | 状态 | 发现 | |------|------|------| | Completeness | Pending | 等待实现与测试证据 | | Correctness | Pending | 等待金额、迁移和接口验证 | | Coherence | Pending | 等待实现与规格逐条对照 | **总体结论**:Pending,等待实现和 wave review 证据。 ## Review Gates - **强制审查点**:每个 Execution Wave 完成后必须记录 `ssf execution review` 的 `pass` receipt;W1–W4 的报告路径分别由 wave 完成时生成。 - **阻塞类别**:依赖 wave 未通过、review receipt 为 `fail`、缺失或过期、合同与 specs 不一致、城市种子不完整。 - **收口条件**:W1–W4 均有当前 revision 的 `pass` receipt;专项/全量/OpenAPI/MySQL 证据存在;没有未映射需求或未解决的 P1/P2 审查问题。 ## Escalation Rules - **何时回退到 `specifying`**:目标城市定义、计算口径、权限语义、历史生命周期或错误码发生变化;新增或删除已批准需求;必须扩大范围到前端、ADMIN、奖金、年度汇算或薪资参考。 - **何时回退到 `bridging`**:`execution-contract.md` 与 proposal/spec/design/tasks 不一致;执行 wave 改变依赖或完成标准;城市数据或注销集成方案改变架构约束。 - **何时不得继续实现**:DP-3 未批准、没有当前 execution plan、依赖 wave 未 pass、review receipt 缺失/过期、V41 无法满足目标城市全量覆盖、发现未处理的安全/隐私回归。 - **DP-4 规则**:`sdd` 模式仅在重新运行 recommendation 并由用户显式确认后写入 execution plan;不得由 Agent 自动代替用户确认。