@chenmk/superflow 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/README.zh-CN.md +1 -0
- package/assets/manifest.json +3 -1
- package/assets/prompts/superflow-clarify.md +6 -0
- package/assets/prompts/superflow-pipeline.md +8 -0
- package/assets/scripts/superflow-archive-command-hook.sh +80 -0
- package/assets/scripts/superflow-delivery-check.sh +23 -4
- package/assets/skills/superflow-archive/SKILL.md +5 -0
- package/assets/skills/superflow-clarify/SKILL.md +26 -7
- package/assets/skills/superflow-design/SKILL.md +46 -5
- package/assets/skills/superflow-docs/SKILL.md +27 -0
- package/assets/skills/superflow-implement/SKILL.md +17 -0
- package/assets/skills/superflow-pipeline/SKILL.md +47 -0
- package/assets/skills/superflow-pipeline/references/api-design-template.md +11 -0
- package/assets/skills/superflow-pipeline/references/batch-prompt-template.md +44 -0
- package/assets/skills/superflow-pipeline/references/implementation-prompt-template.md +48 -0
- package/assets/skills/superflow-pipeline/references/money-precision-algorithms.md +85 -0
- package/assets/skills/superflow-pipeline/references/quality-gate.md +3 -0
- package/assets/skills/superflow-pipeline/references/reviewer-checklist.md +17 -1
- package/assets/skills/superflow-pipeline/references/superpower-technical-design-template.md +90 -0
- package/assets/skills/superflow-pipeline/references/test-execution-template.md +26 -0
- package/assets/skills/superflow-pipeline/scripts/superflow-guard.sh +231 -0
- package/assets/skills/superflow-verify/SKILL.md +23 -1
- package/assets/skills-en/superflow-archive/SKILL.md +6 -0
- package/assets/skills-en/superflow-clarify/SKILL.md +26 -7
- package/assets/skills-en/superflow-design/SKILL.md +45 -4
- package/assets/skills-en/superflow-docs/SKILL.md +27 -0
- package/assets/skills-en/superflow-implement/SKILL.md +10 -0
- package/assets/skills-en/superflow-pipeline/SKILL.md +38 -0
- package/assets/skills-en/superflow-pipeline/references/api-design-template.md +13 -0
- package/assets/skills-en/superflow-pipeline/references/batch-prompt-template.md +28 -0
- package/assets/skills-en/superflow-pipeline/references/implementation-prompt-template.md +33 -0
- package/assets/skills-en/superflow-pipeline/references/money-precision-algorithms.md +96 -0
- package/assets/skills-en/superflow-pipeline/references/quality-gate.md +26 -0
- package/assets/skills-en/superflow-pipeline/references/reviewer-checklist.md +15 -0
- package/assets/skills-en/superflow-pipeline/references/superpower-technical-design-template.md +95 -0
- package/assets/skills-en/superflow-pipeline/references/test-execution-template.md +30 -0
- package/assets/skills-en/superflow-pipeline/scripts/superflow-guard.sh +231 -0
- package/assets/skills-en/superflow-verify/SKILL.md +24 -1
- package/dist/app/commands/archive.js +7 -3
- package/dist/app/commands/archive.js.map +1 -1
- package/dist/app/commands/change-guard.js +27 -0
- package/dist/app/commands/change-guard.js.map +1 -0
- package/dist/app/commands/design.js +2 -20
- package/dist/app/commands/design.js.map +1 -1
- package/dist/app/commands/init.js +1 -5
- package/dist/app/commands/init.js.map +1 -1
- package/dist/app/commands/update.js +2 -5
- package/dist/app/commands/update.js.map +1 -1
- package/dist/app/commands/verify.js +7 -3
- package/dist/app/commands/verify.js.map +1 -1
- package/dist/domains/config/context.js +1 -5
- package/dist/domains/config/context.js.map +1 -1
- package/dist/domains/deps.js +1 -5
- package/dist/domains/deps.js.map +1 -1
- package/dist/domains/hook.js +1 -0
- package/dist/domains/hook.js.map +1 -1
- package/dist/platform/assets.js +9 -0
- package/dist/platform/assets.js.map +1 -0
- package/package.json +3 -2
- package/scripts/release-notes-check.js +102 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# 金额精度算法基线
|
|
2
|
+
|
|
3
|
+
金额正确性不是“统一保留两位小数”,而是表示、币种单位、计算、舍入、分配、
|
|
4
|
+
汇率、存储和审计共同构成的合同。涉及金额的技术详设、实现提示、评审和验证必须
|
|
5
|
+
应用本基线;若法律、财税、清算机构或支付渠道另有规则,以有证据的外部合同为准。
|
|
6
|
+
|
|
7
|
+
## 1. 精确表示与单位
|
|
8
|
+
|
|
9
|
+
- 计算态使用十进制精确类型(如 Java `BigDecimal`、JSR 354 `MonetaryAmount`)
|
|
10
|
+
或带明确币种的整数最小单位。禁止用二进制 `float`/`double` 表示或计算金额。
|
|
11
|
+
- 从字符串、整数最小单位或精确数据库值构造十进制金额;禁止从 `double` 构造。
|
|
12
|
+
- 每个金额合同必须携带币种、金额单位和 scale。不得假定所有币种都是两位小数;
|
|
13
|
+
同时区分 ISO 4217 小数位、内部计算 scale、结算 scale 和支付渠道最小单位。
|
|
14
|
+
- 对外转换为整数最小单位时,只在适配器边界转换,并校验范围、溢出和渠道规则。
|
|
15
|
+
- 数据库使用 `DECIMAL`/`NUMERIC`,代码、DDL、Mapper 和 API 的 precision/scale
|
|
16
|
+
必须一致。数据库写入时的隐式截断或舍入不能代替业务舍入合同。
|
|
17
|
+
|
|
18
|
+
## 2. 舍入策略矩阵
|
|
19
|
+
|
|
20
|
+
每个舍入点必须声明:业务层级(明细/订单/发票/支付/展示)、输入精度、输出
|
|
21
|
+
scale、rounding mode、币种或现金最小增量、规则来源。禁止全局默认 `HALF_UP`,
|
|
22
|
+
也禁止在同一恒等式中混用“逐行舍入”和“汇总后舍入”而没有对账规则。
|
|
23
|
+
|
|
24
|
+
- 除法必须显式声明精度和 rounding mode;预期精确的运算可用 `UNNECESSARY`
|
|
25
|
+
作为断言,使非整除或意外舍入直接失败。
|
|
26
|
+
- 中间费率、数量、乘积、比例和汇率保留计算精度,只在合同指定的结算边界舍入。
|
|
27
|
+
- `CEILING`、`FLOOR` 等模式对负数含义不同;退款、冲正、负数分摊必须单独验证,
|
|
28
|
+
不能用正数用例推断。
|
|
29
|
+
- 税额和发票必须冻结逐行或整单口径,只实现一个权威路径;若外部合同允许另一
|
|
30
|
+
口径,差异必须进入显式调节或对账规则。
|
|
31
|
+
|
|
32
|
+
## 3. 权威总额与差额反推
|
|
33
|
+
|
|
34
|
+
若合同存在 `总额 = 组成项 1 + ... + 组成项 N`,先识别权威总额。只独立计算
|
|
35
|
+
N-1 个组成项,最后一项按 `权威总额 - 其余组成项合计` 差额反推。禁止所有组成
|
|
36
|
+
项分别计算、分别舍入后相加重建权威总额。确实不适用时,必须记录真实权威来源和
|
|
37
|
+
owner 证据。
|
|
38
|
+
|
|
39
|
+
## 4. 比例分配与尾差
|
|
40
|
+
|
|
41
|
+
比例分配必须先计算高精度理想份额,再量化到结算最小单位:
|
|
42
|
+
|
|
43
|
+
1. 将权威总额转换为目标最小单位,得到必须守恒的整数总量。
|
|
44
|
+
2. 计算各明细高精度理想份额及基础分配额。
|
|
45
|
+
3. 计算 `剩余单位 = 权威总额单位 - 基础分配单位合计`。
|
|
46
|
+
4. 每次分配一个最小单位,直到剩余为零。
|
|
47
|
+
5. 明确确定性策略和稳定 tie-breaker(同余数时按业务主键等稳定字段排序)。
|
|
48
|
+
|
|
49
|
+
默认优先使用最大余数法:按被截去余数从大到小补单位;退款或负数按相同绝对
|
|
50
|
+
排序规则对称扣减。合同也可指定最大金额、最后一行等策略,但必须说明依据,不能
|
|
51
|
+
依赖数据库自然顺序。必须验证合计守恒、顺序稳定、重复执行幂等。
|
|
52
|
+
|
|
53
|
+
## 5. 汇率换算
|
|
54
|
+
|
|
55
|
+
- 汇率是带方向的数据:记录 base/quote 币种、来源、时间点、有效期和精度。
|
|
56
|
+
- 禁止提前截断或舍入汇率;存在权威方向汇率时,不用其倒数构造替代汇率。
|
|
57
|
+
- 冻结唯一换算路径;跨币种中转使用合同指定的基准币种和顺序,最终仅在目标
|
|
58
|
+
结算边界按目标币种或渠道单位舍入。
|
|
59
|
+
- 往返换算只能验证合同容差,不能当作精确恒等式。
|
|
60
|
+
|
|
61
|
+
## 6. 审计与验证
|
|
62
|
+
|
|
63
|
+
金额证据至少记录原始输入、公式/版本、币种与单位、舍入前值、舍入策略、舍入后
|
|
64
|
+
值、尾差和尾差接收方;汇率场景另记录汇率元数据。测试至少覆盖正数、零、负数/
|
|
65
|
+
退款、半最小单位、非整除、多明细、并列余数、极值/溢出和重复执行。
|
|
66
|
+
|
|
67
|
+
核心不变量:
|
|
68
|
+
|
|
69
|
+
- 权威总额始终等于组成项合计。
|
|
70
|
+
- 分配结果始终等于目标结算金额。
|
|
71
|
+
- 相同输入、策略版本和稳定排序始终产生相同结果。
|
|
72
|
+
- 持久化、API 和支付渠道转换不会静默改变金额。
|
|
73
|
+
|
|
74
|
+
## 官方依据
|
|
75
|
+
|
|
76
|
+
- ISO 4217 currency codes:<https://www.iso.org/iso-4217-currency-codes.html>
|
|
77
|
+
- JSR 354 Money and Currency API:<https://www.jcp.org/en/jsr/detail?id=354>
|
|
78
|
+
- Java `BigDecimal`:<https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigDecimal.html>
|
|
79
|
+
- MySQL exact-value `DECIMAL`:<https://dev.mysql.com/doc/refman/en/fixed-point-types.html>
|
|
80
|
+
- PostgreSQL exact `numeric`:<https://www.postgresql.org/docs/15/datatype-numeric.html>
|
|
81
|
+
- Stripe smallest currency unit:<https://docs.stripe.com/api/payment_intents/object>
|
|
82
|
+
- Adyen currency minor units:<https://docs.adyen.com/development-resources/currency-codes/>
|
|
83
|
+
- EU conversion and rounding rules:<https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A31997R1103>
|
|
84
|
+
- HMRC VAT rounding:<https://www.gov.uk/hmrc-internal-manuals/vat-trader-records/vatrec12030>
|
|
85
|
+
- SAP allocation residual strategies:<https://help.sap.com/docs/PRODUCT_ID/56471df1959f4cfd9e3bf7a6d2d5be42/56a2dfe71e8b2ea1e10000000a42189c.html>
|
|
@@ -62,6 +62,9 @@
|
|
|
62
62
|
| 44 | **上下文防漂移 handoff** | **所有进入实现的任务强制** | `.sdd/handoff/sdd-context.md`、`.json`、`.sha256` 和 `.sdd/state.yaml` 已生成;design.md、sdd-quality-gate.md、prompt、test-report 记录同一 handoff_hash;`superflow-guard.sh <change-dir> docs` 通过 |
|
|
63
63
|
| 45 | **SDD 状态机字段** | **所有进入实现的任务强制** | `.sdd/state.yaml` 包含 workflow、phase、handoff_hash、build_mode、isolation、tdd_mode、review_mode、verify_mode、implementation_prompt、verification_report、archived;`superflow-state.sh status/next/recover` 输出一致 |
|
|
64
64
|
| 46 | **外部枚举绑定确认** | **涉及第三方、SDK、BEM/停车、支付退款、财务展示、来源字段、状态同步或外部字典时强制** | api.md、sdd-quality-gate.md 和 Superpowers 技术详设包含 `外部枚举绑定确认` / `External Enum Binding`,列出 `业务字段 | 本系统真源字段/枚举 | 外部系统字段 | 外部枚举/字典值 | 展示文案/业务语义/财务语义 | 取值来源 | owner/确认时间 | 不确定项/阻塞处理 | 测试证据`;不得用请求成功、值非空或字段存在替代业务语义确认;未确认时必须阻塞 |
|
|
65
|
+
| 47 | **金额精度边界** | **涉及金额、费用、优惠、抵扣、退款、分账、支付、发票、余额、电费、服务费、套餐结算、比例分摊、明细分配、对账或财务展示时强制** | Superpowers 技术详设包含 `Money Precision Boundary` 及金额恒等式、权威总额、独立计算项、差额反推项与公式、计算态来源、中间精度、舍入边界、scale/rounding mode、分配/对账规则、禁止提前舍入点和测试证据;存在加法恒等式且总额是真源时,最后一个组成项必须由权威总额减去其余组成项合计得到,禁止所有组成项分别计算和舍入后重建总额;测试必须覆盖半分、尾差或多明细分配场景 |
|
|
66
|
+
| 48 | **外部集成配置与部署合同** | **涉及第三方平台/工具、SDK、MQ/Kafka、回调、支付渠道、云服务或其他外部集成时强制** | api.md、sdd-quality-gate.md、Superpowers 技术详设和实现 prompt 包含 `外部集成配置与部署合同` / `External Integration Configuration And Deployment Contract`;列出 endpoint、应用/租户/项目 ID、Topic/Tag/Consumer Group、namespace、webhook、ACL/role、开关、超时和凭据引用在本地/测试/生产的来源与创建方式,以及注入方式、运行 owner、创建 owner/时点、就绪证据、回滚、密钥处理和阻塞项;环境相关值不得只硬编码在注解/常量/业务代码;测试自动创建、历史资源或本地启动成功不能证明生产就绪,缺少生产创建证据必须阻塞发布 |
|
|
67
|
+
| 49 | **并发与幂等归属** | **涉及并发、批量下发/开通/续费、重复提交/回调/消费或重复外部调用时强制** | sdd-quality-gate.md、Superpowers 技术详设和实现 prompt 包含 `Concurrency And Idempotency Ownership` / `并发与幂等归属`;明确业务幂等键、应用层原子占用 owner、短事务边界、PENDING/SUCCESS/FAILED 状态流转、重试复用原业务编码、外部调用边界和不确定结果对账;唯一索引不作为默认方案,只能在自然唯一、历史数据、NULL/软删除和冲突处理合同明确后作为可选兜底;测试覆盖并发、重复和重试 |
|
|
65
68
|
|
|
66
69
|
### 文档完整性强制检查(新增,全部项目必做)
|
|
67
70
|
|
|
@@ -133,12 +133,28 @@
|
|
|
133
133
|
| 54 | 真实入口日志闭环 | 检查服务日志 | 从入口日志到业务校验、DB 查询、外部调用或异常返回有同一 trace/业务单号串联 |
|
|
134
134
|
| 55 | 泛化失败归因 | 检查外部错误、业务日志和 DB 旁证 | 外部平台泛化失败时未直接写通过;已区分外部阻塞、合同漂移、代码异常 |
|
|
135
135
|
|
|
136
|
+
## 金额精度检查
|
|
137
|
+
|
|
138
|
+
| # | 检查项 | 检查方法 | 通过标准 |
|
|
139
|
+
|---|--------|----------|----------|
|
|
140
|
+
| 56 | 计算态与结算态分离 | 检查金额计算链和技术详设 | 最终边界前保留原始费率、数量、乘积和比例精度,未提前舍入后继续计算 |
|
|
141
|
+
| 57 | 舍入边界明确 | 检查 `setScale`、`RoundingMode`、DB/API/展示转换 | 每个舍入点都有合同依据、scale 和 rounding mode,不存在隐式 double/float 精度损失 |
|
|
142
|
+
| 58 | 分配与尾差确定性 | 检查比例分摊、明细拆分、退款和优惠分配 | 尾差按确定性规则落到明确明细,分配合计等于目标金额 |
|
|
143
|
+
| 59 | 金额证据闭环 | 检查 tests.md 和 test-report.md | 覆盖半分、尾差或多明细场景,并证明原始金额、优惠金额、实付/退款金额及分配合计满足合同恒等式 |
|
|
144
|
+
| 60 | 权威总额与恒等式 | 检查金额合同和真源证据 | 明确哪个总额是合同真源,以及总额与各组成项之间的加法恒等式;不适用时有真实真源和 owner 证据 |
|
|
145
|
+
| 61 | 差额反推算法 | 检查金额组成项计算代码 | 存在权威总额时只独立计算 N-1 个组成项,最后一个组成项由权威总额减去其余组成项合计得到;未分别计算和舍入所有组成项后重建总额 |
|
|
146
|
+
| 62 | 币种与最小单位 | 检查 DTO、适配器、支付渠道和数据库 | 未默认两位小数;内部 scale、ISO/渠道最小单位及转换边界明确,整数转换有溢出校验 |
|
|
147
|
+
| 63 | 舍入策略来源 | 检查逐行/整单/发票/支付边界 | 每个舍入点有层级、scale、mode 和合同来源,未全局硬编码同一策略 |
|
|
148
|
+
| 64 | 最大余数与稳定排序 | 检查多明细分配 | 高精度理想份额量化后逐最小单位分配尾差,同余数按稳定业务键排序,不依赖数据库自然顺序 |
|
|
149
|
+
| 65 | 负数与退款对称性 | 检查退款、冲正和负数分摊 | 正数、零、负数/退款均有证据,明确 `CEILING`/`FLOOR` 等模式的符号差异 |
|
|
150
|
+
| 66 | 汇率路径与元数据 | 检查跨币种换算 | base/quote、来源、时间、精度和唯一换算路径明确,只在目标结算边界舍入 |
|
|
151
|
+
|
|
136
152
|
## 检查记录格式
|
|
137
153
|
|
|
138
154
|
```
|
|
139
155
|
批次评审报告:P{n} - {名称}
|
|
140
156
|
|
|
141
|
-
检查项总数:
|
|
157
|
+
检查项总数:66
|
|
142
158
|
通过:X 项
|
|
143
159
|
未通过:X 项
|
|
144
160
|
不适用:X 项
|
|
@@ -60,6 +60,47 @@ orchestrator unless the OpenSpec/SDD contract explicitly says that module owns
|
|
|
60
60
|
the new entry point and records the owner approval. If the correct owner is
|
|
61
61
|
unclear, mark the design blocked.
|
|
62
62
|
|
|
63
|
+
## External Integration Configuration And Deployment Contract
|
|
64
|
+
|
|
65
|
+
Use this whenever the change integrates with a third-party platform/tool, SDK,
|
|
66
|
+
MQ/Kafka, callback, payment gateway, cloud service, or other external system.
|
|
67
|
+
|
|
68
|
+
| External dependency/resource | Config/resource item | Local source/provisioning | Test source/provisioning | Production source/provisioning | Injection/creation method | Runtime owner | Provisioning owner/time | Readiness evidence | Rollback | Secret handling | Blocker |
|
|
69
|
+
| ---------------------------- | -------------------- | ------------------------- | ------------------------ | ------------------------------ | ------------------------- | ------------- | ----------------------- | ------------------ | -------- | --------------- | ------- |
|
|
70
|
+
| `<TDMQ>` | `<Consumer Group>` | `<auto/manual/IaC>` | `<existing resource>` | `<pre-created by ops>` | `<config/secret/IaC/console>` | `<service>` | `<owner + before deploy>` | `<console/API/trace>` | `<disable/rollback>` | `<secret reference only>` | `<none/blocker>` |
|
|
71
|
+
|
|
72
|
+
Required checks:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
rg -ni "https?://|endpoint|base.?url|app.?id|tenant|project.?id|topic|tag|consumer.?group|namespace|webhook|acl|role|secret|token|password|timeout" <source-and-config-paths>
|
|
76
|
+
rg -ni "@.*Listener|new.*Client|builder\(|System\.getenv|ConfigurationProperties|Value\(" <source-and-config-paths>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Do not hard-code environment-dependent endpoints, resource names, identifiers,
|
|
80
|
+
credentials, ACLs, or operational switches in annotations, constants, or
|
|
81
|
+
business code. Stable protocol constants may remain code constants only when
|
|
82
|
+
the design proves they are not environment-specific and no server-side
|
|
83
|
+
resource must be provisioned. Test auto-creation, a successful local startup,
|
|
84
|
+
or an already-existing test resource is not evidence that production is
|
|
85
|
+
ready. Every server-side resource must have an explicit production owner,
|
|
86
|
+
creation timing, readiness check, and rollback path. Missing production
|
|
87
|
+
provisioning evidence is a blocker.
|
|
88
|
+
|
|
89
|
+
## Concurrency And Idempotency Ownership
|
|
90
|
+
|
|
91
|
+
批量开通、批量续费、并发请求、重复回调、重复消费或重复外部下发时必须填写。
|
|
92
|
+
|
|
93
|
+
| 场景 | 业务幂等键 | 原子占用 owner/资源 | 应用层原子占用操作 | 短事务边界 | 状态流转 | 重试复用编码 | 外部调用边界 | 结果不确定处理 | 唯一索引角色 | 测试证据 |
|
|
94
|
+
| ---- | ---------- | ------------------- | ------------------ | ---------- | -------- | ------------ | ------------ | -------------- | ------------ | -------- |
|
|
95
|
+
| `<批量下发>` | `<套餐+车辆+周期>` | `<周期记录>` | `<锁定 owner 后写 PENDING>` | `<独立事务提交占用>` | `PENDING/SUCCESS/FAILED` | `<复用原业务单号>` | `<提交后调用>` | `<阻止重复并进入对账>` | `<非默认;必要时兜底>` | `<并发/重复/重试用例>` |
|
|
96
|
+
|
|
97
|
+
应用层原子占用是默认方案:先用稳定业务幂等键在短事务内锁定明确的 owner 资源,
|
|
98
|
+
写入 `PENDING` 并提交,再释放数据库锁后执行外部调用。外部调用成功或失败后更新
|
|
99
|
+
状态;重试必须复用原业务单号。结果不确定时必须阻止重复下发并保留人工对账入口。
|
|
100
|
+
禁止用“先查再插”、单进程锁或随机单号冒充跨实例幂等,也禁止在外部调用期间持有
|
|
101
|
+
长事务或数据库锁。唯一索引不是默认方案;仅当自然唯一语义、历史数据清理、NULL/
|
|
102
|
+
软删除行为和冲突处理合同都已明确时,才可作为数据库兜底。
|
|
103
|
+
|
|
63
104
|
## Field And Status Reverse Impact
|
|
64
105
|
|
|
65
106
|
Use this whenever changing field values, enum/status values, derived fields,
|
|
@@ -107,6 +148,52 @@ successful request, non-null value, or "field exists" proof is not enough. Do
|
|
|
107
148
|
not invent numeric enum values, source/origin values, financial display
|
|
108
149
|
semantics, fallback values, or compatibility mappings without owner approval.
|
|
109
150
|
|
|
151
|
+
## Money Precision Boundary
|
|
152
|
+
|
|
153
|
+
Use this whenever the change involves amount, fee, discount, deduction, refund,
|
|
154
|
+
sharing, payment, invoice, balance, electricity fee, service fee, package
|
|
155
|
+
settlement, proration, allocation, reconciliation, or financial display.
|
|
156
|
+
|
|
157
|
+
| Amount identity | Authoritative total | Exact type/construction | Currency and unit | Calculation-state source | Rounding level/boundary | Scale/mode/source | Allocation strategy/tie-breaker | Complement derivation | Audit evidence | Test evidence |
|
|
158
|
+
| --------------- | ------------------- | ----------------------- | ----------------- | ------------------------ | ----------------------- | ----------------- | ------------------------------- | --------------------- | -------------- | ------------- |
|
|
159
|
+
| `original = discount + actual` | `original` | `<BigDecimal from string>` | `<CNY; internal scale; provider minor unit>` | `<rate * quantity>` | `<order/payment adapter>` | `<2/HALF_UP/contract>` | `<largest remainder/business key>` | `actual = original - discount` | `<pre/post round; residual recipient>` | `<positive/zero/refund/half-unit/tied residual IDs>` |
|
|
160
|
+
|
|
161
|
+
Use `money-precision-algorithms.md` to complete the contract. State the exact
|
|
162
|
+
decimal representation and construction source; currency and ISO/provider
|
|
163
|
+
minor-unit boundary; rounding level, mode, and policy source; deterministic
|
|
164
|
+
residual strategy and stable tie-breaker; negative/refund symmetry; persistence
|
|
165
|
+
precision/scale and overflow checks. Never assume every currency has two
|
|
166
|
+
decimal places or use database implicit conversion as the rounding policy.
|
|
167
|
+
|
|
168
|
+
For FX changes, additionally record:
|
|
169
|
+
|
|
170
|
+
| Base/quote | Rate source/time | Rate precision | Canonical path | Target unit/rounding | Round-trip tolerance | Evidence |
|
|
171
|
+
| ---------- | ---------------- | -------------- | -------------- | -------------------- | -------------------- | -------- |
|
|
172
|
+
| `<base/quote>` | `<source/timestamp>` | `<scale>` | `<direct/triangulated order>` | `<currency/provider rule>` | `<contract tolerance>` | `<case IDs>` |
|
|
173
|
+
|
|
174
|
+
Required precision checks:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
rg -ni "setScale|round|RoundingMode|BigDecimal|double|float|money\\(" <source-and-test-paths>
|
|
178
|
+
rg -ni "amount|fee|price|discount|deduction|refund|pay|invoice|balance|serviceFee|chargeFee" <source-and-test-paths>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The design must separate calculation-state money from settlement/display-state
|
|
182
|
+
money. Intermediate calculations must keep original rate, product, proportion,
|
|
183
|
+
process evidence, and allocation precision. Round only at explicit outbound
|
|
184
|
+
boundaries such as settlement posting, persistence fields that require cents,
|
|
185
|
+
payment/fiscal interfaces, invoices, exports, or display. For multi-detail
|
|
186
|
+
allocation, compute the high-precision target first, then distribute the final
|
|
187
|
+
rounded amount deterministically so totals match and identities such as
|
|
188
|
+
`original = discount + actual` hold. When an additive identity exists and its
|
|
189
|
+
total is the authoritative source, calculate only the required N-1 components
|
|
190
|
+
independently and derive the final complement as `authoritative total - sum(other
|
|
191
|
+
components)`. Do not independently calculate and round every component and then
|
|
192
|
+
rebuild the authoritative total. If complement derivation is not applicable,
|
|
193
|
+
record why, identify the actual source of truth, and provide owner evidence.
|
|
194
|
+
Do not calculate later slices, discounts, ratios, or unit prices from
|
|
195
|
+
already-rounded money.
|
|
196
|
+
|
|
110
197
|
## Execution Architecture
|
|
111
198
|
|
|
112
199
|
- Worker boundaries:
|
|
@@ -144,6 +231,9 @@ semantics, fallback values, or compatibility mappings without owner approval.
|
|
|
144
231
|
that only shows "can call through this module" is not ready.
|
|
145
232
|
- For field/status changes, prove reverse impact before coding: writers,
|
|
146
233
|
readers, filters, derived sync paths, external consumers, and tests.
|
|
234
|
+
- For money changes, prove the precision boundary before coding: calculation
|
|
235
|
+
state, settlement/display state, final rounding point, allocation rule, and
|
|
236
|
+
half-cent/residual tests.
|
|
147
237
|
- Do not invent API fields, DB columns, status semantics, fallback behavior, or
|
|
148
238
|
acceptance criteria.
|
|
149
239
|
- Keep unresolved source facts as blockers. Do not convert them to guesses.
|
|
@@ -98,6 +98,22 @@ Controller、mock endpoint、绕过鉴权端点只能填写 `Mock only` 或 `测
|
|
|
98
98
|
HTTP 200、字段非空、mock-only、DB-only、`BUILD SUCCESS`、`Tests are skipped`
|
|
99
99
|
都不能单独作为接口通过证据。
|
|
100
100
|
|
|
101
|
+
## 4.4 金额精度边界证据
|
|
102
|
+
|
|
103
|
+
涉及金额计算、结算、比例分摊、明细分配、优惠抵扣、退款、支付、开票或财务展示时
|
|
104
|
+
必须填写:
|
|
105
|
+
|
|
106
|
+
| 用例 ID | 恒等式/权威总额 | 币种/最小单位 | 差额反推 | 舍入前/后 | 策略/尾差接收方 | 正数/零/退款/并列余数 | 对账结论 |
|
|
107
|
+
| ------- | ---------------- | ------------- | -------- | ----------- | ----------------- | --------------------- | -------- |
|
|
108
|
+
| TC-M01 | 原始=优惠+实付/原始金额 | CNY/分 | 实付=原始-优惠 | ____/____ | 最大余数/____ | ____ | 一致/阻塞 |
|
|
109
|
+
|
|
110
|
+
必须证明计算态在最终边界前未提前舍入,并证明原始金额、优惠金额、实付金额、退款金额
|
|
111
|
+
或分配合计满足设计合同。存在权威总额时,还必须证明最后一个组成项确实由权威总额
|
|
112
|
+
减去其余组成项合计得到,而不是所有组成项分别计算和舍入。只验证最终展示两位
|
|
113
|
+
小数,不足以证明金额精度正确。证据还必须包含币种、渠道最小单位、舍入前值、
|
|
114
|
+
舍入后值、尾差接收方,以及正数、零、负数/退款、并列余数和幂等验证。汇率场景
|
|
115
|
+
另附 base/quote、汇率来源和目标结算舍入证据。
|
|
116
|
+
|
|
101
117
|
## 5. 详细结果
|
|
102
118
|
|
|
103
119
|
### 5.1 通过的测试
|
|
@@ -150,6 +166,16 @@ HTTP 200、字段非空、mock-only、DB-only、`BUILD SUCCESS`、`Tests are ski
|
|
|
150
166
|
## 9. 结论
|
|
151
167
|
|
|
152
168
|
[是否达到交付标准,是否可以进入下一阶段]
|
|
169
|
+
|
|
170
|
+
验证结果: PASS / FAIL / BLOCKED / PARTIALLY_VERIFIED
|
|
171
|
+
归档就绪: PASS / BLOCKED
|
|
172
|
+
|
|
173
|
+
`verify_mode: full` 时必须填写:
|
|
174
|
+
|
|
175
|
+
- 测试环境:
|
|
176
|
+
- 分支/commit/构建号或镜像:
|
|
177
|
+
- Base URL:
|
|
178
|
+
- 验证时间:
|
|
153
179
|
```
|
|
154
180
|
|
|
155
181
|
## 任务完成 Checklist(全部满足才能标记完成)
|
|
@@ -178,6 +178,60 @@ require_state_file() {
|
|
|
178
178
|
require_file .sdd/state.yaml
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
require_tasks_complete() {
|
|
182
|
+
local task_count unchecked_count
|
|
183
|
+
require_file tasks.md
|
|
184
|
+
[[ -f "$CHANGE_DIR/tasks.md" ]] || return 0
|
|
185
|
+
task_count="$(grep -Ec '^[[:space:]]*-[[:space:]]+\[[ xX]\]' "$CHANGE_DIR/tasks.md" || true)"
|
|
186
|
+
unchecked_count="$(grep -Ec '^[[:space:]]*-[[:space:]]+\[[[:space:]]\]' "$CHANGE_DIR/tasks.md" || true)"
|
|
187
|
+
[[ "$task_count" -gt 0 ]] || issues+=("tasks.md has no checkbox tasks")
|
|
188
|
+
[[ "$unchecked_count" -eq 0 ]] || issues+=("$unchecked_count unchecked task(s) remain in tasks.md")
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
verification_report_path() {
|
|
192
|
+
local value
|
|
193
|
+
value="$(state_get verification_report)"
|
|
194
|
+
[[ -n "$value" && "$value" != "null" ]] || return 1
|
|
195
|
+
if [[ -f "$CHANGE_DIR/$value" ]]; then
|
|
196
|
+
printf '%s\n' "$CHANGE_DIR/$value"
|
|
197
|
+
return 0
|
|
198
|
+
fi
|
|
199
|
+
if [[ -f "$value" ]]; then
|
|
200
|
+
printf '%s\n' "$value"
|
|
201
|
+
return 0
|
|
202
|
+
fi
|
|
203
|
+
return 1
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
require_closeout_markers() {
|
|
207
|
+
local report="${1:-$CHANGE_DIR/test-report.md}"
|
|
208
|
+
if [[ ! -f "$report" ]]; then
|
|
209
|
+
issues+=("verification report path does not exist: $report")
|
|
210
|
+
return 0
|
|
211
|
+
fi
|
|
212
|
+
if ! grep -Eiq '(Verification Result|验证结果|验证结论)[[:space:]::|*-]*(PASS|通过)' "$report"; then
|
|
213
|
+
issues+=("verification result PASS marker not found in verification report")
|
|
214
|
+
fi
|
|
215
|
+
if ! grep -Eiq '(Archive Readiness|归档就绪)[[:space:]::|*-]*(PASS|READY|通过|就绪)' "$report"; then
|
|
216
|
+
issues+=("archive readiness PASS marker not found in verification report")
|
|
217
|
+
fi
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
require_branch_handled() {
|
|
221
|
+
local branch_status
|
|
222
|
+
branch_status="$(state_get branch_status)"
|
|
223
|
+
[[ "$branch_status" == "handled" ]] || issues+=("branch_status must be handled before verification closeout")
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
require_full_verification_fingerprint() {
|
|
227
|
+
local report="$CHANGE_DIR/test-report.md"
|
|
228
|
+
[[ "$(state_get verify_mode)" == "full" ]] || return 0
|
|
229
|
+
require_grep '测试环境|test environment|staging|sandbox' "$report" "full verification test environment"
|
|
230
|
+
require_grep '分支|提交|版本|构建号|镜像|branch|commit|tag|build|image' "$report" "full verification deployment fingerprint"
|
|
231
|
+
require_grep 'https?://|Base URL|基础地址' "$report" "full verification base URL"
|
|
232
|
+
require_grep '验证时间|执行时间|timestamp|verified[_ -]?at|20[0-9]{2}-[0-9]{2}-[0-9]{2}' "$report" "full verification timestamp"
|
|
233
|
+
}
|
|
234
|
+
|
|
181
235
|
require_spec_doc() {
|
|
182
236
|
if [[ -f "$CHANGE_DIR/spec.md" ]]; then
|
|
183
237
|
return
|
|
@@ -259,6 +313,50 @@ change_has_external_enum_risk() {
|
|
|
259
313
|
"$CHANGE_DIR"/specs/*/spec.md 2>/dev/null
|
|
260
314
|
}
|
|
261
315
|
|
|
316
|
+
change_has_external_config_risk() {
|
|
317
|
+
grep -RIEiq \
|
|
318
|
+
'第三方|外部平台|外部工具|外部集成|third[- ]party|external (platform|tool|integration|system)|SDK|MQ|Kafka|RocketMQ|TDMQ|callback|回调|webhook|支付渠道|payment gateway|cloud service|云服务' \
|
|
319
|
+
"$CHANGE_DIR/proposal.md" \
|
|
320
|
+
"$CHANGE_DIR/api.md" \
|
|
321
|
+
"$CHANGE_DIR/design.md" \
|
|
322
|
+
"$CHANGE_DIR/tests.md" \
|
|
323
|
+
"$CHANGE_DIR/spec.md" \
|
|
324
|
+
"$CHANGE_DIR"/specs/*/spec.md 2>/dev/null
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
change_has_concurrency_idempotency_risk() {
|
|
328
|
+
grep -RIEiq \
|
|
329
|
+
'并发|批量下发|批量开通|批量续费|重复提交|重复回调|重复消费|重复下发|幂等|竞态|原子占用|concurren|idempoten|race condition|duplicate (request|callback|consumption|delivery)|atomic claim' \
|
|
330
|
+
"$CHANGE_DIR/proposal.md" \
|
|
331
|
+
"$CHANGE_DIR/api.md" \
|
|
332
|
+
"$CHANGE_DIR/design.md" \
|
|
333
|
+
"$CHANGE_DIR/tests.md" \
|
|
334
|
+
"$CHANGE_DIR/spec.md" \
|
|
335
|
+
"$CHANGE_DIR"/specs/*/spec.md 2>/dev/null
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
change_has_money_precision_risk() {
|
|
339
|
+
grep -RIEiq \
|
|
340
|
+
'金额|费用|价格|优惠|折扣|抵扣|退款|分账|支付|发票|余额|电费|服务费|套餐结算|比例分摊|明细分配|尾差|精度|舍入|(^|[^[:alnum:]_])(amount|fee|fees|price|discount|deduction|refund|payment|invoice|balance|proration|allocation|reconciliation|rounding)([^[:alnum:]_]|$)|revenue sharing|profit sharing|split payment|serviceFee|chargeFee|totalAmount|actualAmount|payAmount|refundAmount|discountAmount|invoiceAmount|balanceAmount' \
|
|
341
|
+
"$CHANGE_DIR/proposal.md" \
|
|
342
|
+
"$CHANGE_DIR/api.md" \
|
|
343
|
+
"$CHANGE_DIR/design.md" \
|
|
344
|
+
"$CHANGE_DIR/tests.md" \
|
|
345
|
+
"$CHANGE_DIR/spec.md" \
|
|
346
|
+
"$CHANGE_DIR"/specs/*/spec.md 2>/dev/null
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
change_has_fx_precision_risk() {
|
|
350
|
+
grep -RIEiq \
|
|
351
|
+
'汇率|换汇|外汇|币种转换|跨币种|兑换率|(^|[^[:alnum:]_])(exchange rate|fx rate|currency conversion|cross.currency|base currency|quote currency)([^[:alnum:]_]|$)' \
|
|
352
|
+
"$CHANGE_DIR/proposal.md" \
|
|
353
|
+
"$CHANGE_DIR/api.md" \
|
|
354
|
+
"$CHANGE_DIR/design.md" \
|
|
355
|
+
"$CHANGE_DIR/tests.md" \
|
|
356
|
+
"$CHANGE_DIR/spec.md" \
|
|
357
|
+
"$CHANGE_DIR"/specs/*/spec.md 2>/dev/null
|
|
358
|
+
}
|
|
359
|
+
|
|
262
360
|
change_has_architecture_boundary_risk() {
|
|
263
361
|
grep -RIEiq \
|
|
264
362
|
'跨仓|跨服务|sibling|SDK|MQ|topic|consumer|scheduler|定时|device|设备|callback|回调|third[- ]party|第三方|mini[- ]program|小程序|gateway|网关|adapter|适配|protocol|协议|interconnect|互联互通|调用链|入口|出口' \
|
|
@@ -303,6 +401,87 @@ require_external_enum_contract() {
|
|
|
303
401
|
require_grep '不确定|阻塞|blocker|unknown|待确认' "$path" "$label unresolved/blocker column"
|
|
304
402
|
}
|
|
305
403
|
|
|
404
|
+
require_external_config_contract() {
|
|
405
|
+
local path="$1"
|
|
406
|
+
local label="$2"
|
|
407
|
+
require_grep 'External Integration Configuration And Deployment Contract|外部集成配置与部署合同|外部配置.*部署合同' "$path" "$label"
|
|
408
|
+
require_grep '本地.*测试.*生产|local.*test.*production|local.*staging.*production' "$path" "$label environment matrix"
|
|
409
|
+
require_grep '注入|创建方式|provision|injection|IaC|Secret|控制台|console' "$path" "$label injection/provisioning"
|
|
410
|
+
require_grep '运行 owner|创建 owner|provisioning owner|runtime owner|owner.*时点|owner.*time' "$path" "$label owner and timing"
|
|
411
|
+
require_grep '就绪|readiness|消息轨迹|trace|health' "$path" "$label readiness evidence"
|
|
412
|
+
require_grep '回滚|rollback|禁用|disable' "$path" "$label rollback"
|
|
413
|
+
require_grep '密钥|凭据|secret|credential' "$path" "$label secret handling"
|
|
414
|
+
require_grep '不得.*硬编码|禁止.*硬编码|not.*hard.?cod|must not.*hard.?cod|do not hard.?code' "$path" "$label no hard-coded external config"
|
|
415
|
+
require_grep '测试.*生产|test.*production|staging.*production' "$path" "$label test-production distinction"
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
require_concurrency_idempotency_contract() {
|
|
419
|
+
local path="$1"
|
|
420
|
+
local label="$2"
|
|
421
|
+
require_grep 'Concurrency And Idempotency Ownership|并发与幂等归属|应用层原子占用' "$path" "$label"
|
|
422
|
+
require_grep '业务幂等键|business idempotency key|business key' "$path" "$label business idempotency key"
|
|
423
|
+
require_grep '应用层原子占用|application.layer atomic claim|atomic claim' "$path" "$label application-layer atomic claim"
|
|
424
|
+
require_grep '短事务|short transaction|事务边界|transaction boundary' "$path" "$label short transaction boundary"
|
|
425
|
+
require_grep '待处理|pending|成功|success|失败|failed|状态流转|state machine' "$path" "$label state machine"
|
|
426
|
+
require_grep '重试|retry' "$path" "$label retry contract"
|
|
427
|
+
require_grep '外部调用|external call|third.party call' "$path" "$label external-call boundary"
|
|
428
|
+
require_grep '唯一索引.*(不是|不得|不作为).*默认|unique index.*not.*default|do not.*default.*unique index' "$path" "$label unique index is not the default"
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
require_money_precision_contract() {
|
|
432
|
+
local path="$1"
|
|
433
|
+
local label="$2"
|
|
434
|
+
require_grep 'Money Precision Boundary|金额精度边界' "$path" "$label"
|
|
435
|
+
require_grep '计算态|calculation.state|calculation source|intermediate precision' "$path" "$label calculation state"
|
|
436
|
+
require_grep '结算态|展示态|settlement|display.state|rounding boundary' "$path" "$label settlement/display boundary"
|
|
437
|
+
require_grep 'scale|rounding mode|RoundingMode|舍入模式' "$path" "$label scale and rounding mode"
|
|
438
|
+
require_grep '分配|对账|allocation|reconciliation|residual|尾差' "$path" "$label allocation/reconciliation rule"
|
|
439
|
+
require_grep '权威总额|真源总额|authoritative total|source.of.truth total' "$path" "$label authoritative total"
|
|
440
|
+
require_grep '差额反推|总额.*减|authoritative total.*minus|derive.*complement|complement amount' "$path" "$label complement derivation"
|
|
441
|
+
require_grep '禁止.*分别计算|不得.*分别计算|禁止.*独立.*舍入|do not.*independently|must not.*calculate.*separately' "$path" "$label independent calculation prohibition"
|
|
442
|
+
require_grep '禁止提前舍入|不得提前.*舍入|forbidden early rounding|do not.*round' "$path" "$label forbidden early rounding"
|
|
443
|
+
require_grep '半分|尾差|多明细|half.cent|residual|multi.detail' "$path" "$label boundary test evidence"
|
|
444
|
+
require_grep 'BigDecimal|MonetaryAmount|整数最小单位|integer minor unit|exact decimal' "$path" "$label exact representation"
|
|
445
|
+
require_grep '禁止.*(float|double)|不得.*(float|double)|never.*(float|double)|do not.*(float|double)' "$path" "$label binary floating-point prohibition"
|
|
446
|
+
require_grep '币种|currency' "$path" "$label currency contract"
|
|
447
|
+
require_grep '最小单位|minor unit|provider unit|渠道单位' "$path" "$label minor-unit boundary"
|
|
448
|
+
require_grep '舍入层级|舍入点|rounding level|rounding point|明细.*整单|line.level.*aggregate' "$path" "$label rounding level"
|
|
449
|
+
require_grep '规则来源|合同依据|policy source|contract source' "$path" "$label rounding policy source"
|
|
450
|
+
require_grep '最大余数|largest remainder|稳定.*排序|stable tie.break|业务主键' "$path" "$label deterministic residual tie-breaker"
|
|
451
|
+
require_grep '正数.*零.*负数|正数.*退款|positive.*zero.*negative|positive.*refund' "$path" "$label signed-value evidence"
|
|
452
|
+
require_grep '舍入前.*舍入后|pre.round.*post.round' "$path" "$label rounding audit evidence"
|
|
453
|
+
require_grep 'DECIMAL|NUMERIC|数据库.*不适用|持久化.*不适用|persistence.*not applicable' "$path" "$label persistence precision contract"
|
|
454
|
+
if change_has_fx_precision_risk; then
|
|
455
|
+
require_grep 'base/quote|基础币种.*目标币种|基准币种.*报价币种' "$path" "$label FX direction"
|
|
456
|
+
require_grep '汇率来源|rate source' "$path" "$label FX source"
|
|
457
|
+
require_grep '汇率.*时间|rate.*timestamp|rate.*effective' "$path" "$label FX timestamp"
|
|
458
|
+
require_grep '唯一换算路径|权威换算路径|canonical conversion path|canonical path' "$path" "$label FX canonical path"
|
|
459
|
+
require_grep '目标.*结算.*舍入|target.*settlement.*round' "$path" "$label FX target rounding"
|
|
460
|
+
fi
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
require_money_precision_evidence() {
|
|
464
|
+
local path="$1"
|
|
465
|
+
local label="$2"
|
|
466
|
+
require_grep 'Money Precision Boundary|金额精度边界' "$path" "$label"
|
|
467
|
+
require_grep '半分|尾差|多明细|half.cent|residual|multi.detail' "$path" "$label boundary cases"
|
|
468
|
+
require_grep '原始金额|优惠金额|实付金额|分配合计|对账|original.*discount.*actual|allocated total|reconciliation' "$path" "$label reconciliation evidence"
|
|
469
|
+
require_grep '权威总额|真源总额|authoritative total' "$path" "$label authoritative total evidence"
|
|
470
|
+
require_grep '差额反推|总额.*减|authoritative total.*minus|derive.*complement|complement amount' "$path" "$label complement derivation evidence"
|
|
471
|
+
require_grep '币种|currency' "$path" "$label currency evidence"
|
|
472
|
+
require_grep '最小单位|minor unit|provider unit|渠道单位' "$path" "$label minor-unit reconciliation"
|
|
473
|
+
require_grep '正数.*零.*负数|正数.*退款|positive.*zero.*negative|positive.*refund' "$path" "$label signed-value cases"
|
|
474
|
+
require_grep '舍入前.*舍入后|pre.round.*post.round' "$path" "$label rounding audit evidence"
|
|
475
|
+
require_grep '尾差接收方|residual recipient' "$path" "$label residual audit evidence"
|
|
476
|
+
require_grep '并列余数|tied remainder' "$path" "$label tied-residual cases"
|
|
477
|
+
require_grep '幂等|idempoten' "$path" "$label allocation idempotence"
|
|
478
|
+
if change_has_fx_precision_risk; then
|
|
479
|
+
require_grep 'base/quote|基础币种.*目标币种|基准币种.*报价币种' "$path" "$label FX direction evidence"
|
|
480
|
+
require_grep '汇率来源|rate source' "$path" "$label FX source evidence"
|
|
481
|
+
require_grep '目标.*结算.*舍入|target.*settlement.*round' "$path" "$label FX target rounding evidence"
|
|
482
|
+
fi
|
|
483
|
+
}
|
|
484
|
+
|
|
306
485
|
transition_event=""
|
|
307
486
|
|
|
308
487
|
if [[ -x "$VALIDATE" && -f "$CHANGE_DIR/.sdd/state.yaml" ]]; then
|
|
@@ -336,6 +515,16 @@ case "$PHASE" in
|
|
|
336
515
|
require_external_enum_contract api.md "external enum binding contract"
|
|
337
516
|
require_external_enum_contract sdd-quality-gate.md "external enum binding quality gate"
|
|
338
517
|
fi
|
|
518
|
+
if change_has_external_config_risk; then
|
|
519
|
+
require_external_config_contract api.md "external integration configuration contract"
|
|
520
|
+
require_external_config_contract sdd-quality-gate.md "external integration deployment gate"
|
|
521
|
+
fi
|
|
522
|
+
if change_has_concurrency_idempotency_risk; then
|
|
523
|
+
require_concurrency_idempotency_contract sdd-quality-gate.md "concurrency and idempotency ownership quality gate"
|
|
524
|
+
fi
|
|
525
|
+
if change_has_money_precision_risk; then
|
|
526
|
+
require_grep 'Money Precision Boundary|金额精度边界' sdd-quality-gate.md "money precision quality gate"
|
|
527
|
+
fi
|
|
339
528
|
require_markdown_links_valid
|
|
340
529
|
transition_event="docs-complete"
|
|
341
530
|
;;
|
|
@@ -371,6 +560,15 @@ case "$PHASE" in
|
|
|
371
560
|
if change_has_external_enum_risk; then
|
|
372
561
|
require_external_enum_contract "$technical_design_rel" "external enum binding matrix"
|
|
373
562
|
fi
|
|
563
|
+
if change_has_external_config_risk; then
|
|
564
|
+
require_external_config_contract "$technical_design_rel" "external integration configuration and deployment contract"
|
|
565
|
+
fi
|
|
566
|
+
if change_has_concurrency_idempotency_risk; then
|
|
567
|
+
require_concurrency_idempotency_contract "$technical_design_rel" "concurrency and idempotency ownership contract"
|
|
568
|
+
fi
|
|
569
|
+
if change_has_money_precision_risk; then
|
|
570
|
+
require_money_precision_contract "$technical_design_rel" "money precision boundary"
|
|
571
|
+
fi
|
|
374
572
|
fi
|
|
375
573
|
fi
|
|
376
574
|
require_grep 'Superpowers Technical Design Handoff|Superpower 技术详设|technical_design|源码级 HOW' design.md "Superpowers technical design handoff"
|
|
@@ -399,6 +597,15 @@ case "$PHASE" in
|
|
|
399
597
|
if change_has_external_enum_risk; then
|
|
400
598
|
require_external_enum_contract "$prompt_rel" "prompt external enum binding inheritance"
|
|
401
599
|
fi
|
|
600
|
+
if change_has_external_config_risk; then
|
|
601
|
+
require_external_config_contract "$prompt_rel" "prompt external integration configuration inheritance"
|
|
602
|
+
fi
|
|
603
|
+
if change_has_concurrency_idempotency_risk; then
|
|
604
|
+
require_concurrency_idempotency_contract "$prompt_rel" "prompt concurrency and idempotency ownership inheritance"
|
|
605
|
+
fi
|
|
606
|
+
if change_has_money_precision_risk; then
|
|
607
|
+
require_money_precision_contract "$prompt_rel" "prompt money precision inheritance"
|
|
608
|
+
fi
|
|
402
609
|
fi
|
|
403
610
|
require_grep '上下文防漂移|handoff_hash|sdd-context' "$prompt_rel" "prompt context drift inheritance"
|
|
404
611
|
fi
|
|
@@ -418,6 +625,7 @@ case "$PHASE" in
|
|
|
418
625
|
;;
|
|
419
626
|
verify)
|
|
420
627
|
require_state_file
|
|
628
|
+
require_tasks_complete
|
|
421
629
|
require_file test-report.md
|
|
422
630
|
require_grep 'RED|失败证据' test-report.md "RED evidence"
|
|
423
631
|
require_grep 'GREEN|通过证据' test-report.md "GREEN evidence"
|
|
@@ -427,7 +635,21 @@ case "$PHASE" in
|
|
|
427
635
|
if change_has_external_enum_risk; then
|
|
428
636
|
require_grep 'External Enum Binding|外部枚举绑定|第三方字段语义绑定|外部展示|展示文案|业务语义|财务语义|BEM|真实入口' test-report.md "external enum binding runtime evidence"
|
|
429
637
|
fi
|
|
638
|
+
if change_has_external_config_risk; then
|
|
639
|
+
require_grep 'External Integration Configuration And Deployment Contract|外部集成配置与部署合同' test-report.md "external integration configuration runtime evidence"
|
|
640
|
+
require_grep '生产.*就绪|production.*ready|provision.*verified|资源.*存在|resource.*exists' test-report.md "external production readiness evidence"
|
|
641
|
+
fi
|
|
642
|
+
if change_has_concurrency_idempotency_risk; then
|
|
643
|
+
require_grep 'Concurrency And Idempotency Ownership|并发与幂等归属|应用层原子占用' test-report.md "concurrency and idempotency runtime evidence"
|
|
644
|
+
require_grep '并发|concurren|重复|duplicate|重试|retry' test-report.md "concurrency duplicate and retry cases"
|
|
645
|
+
fi
|
|
646
|
+
if change_has_money_precision_risk; then
|
|
647
|
+
require_money_precision_evidence test-report.md "money precision runtime evidence"
|
|
648
|
+
fi
|
|
430
649
|
require_test_report_lint
|
|
650
|
+
require_closeout_markers "$CHANGE_DIR/test-report.md"
|
|
651
|
+
require_branch_handled
|
|
652
|
+
require_full_verification_fingerprint
|
|
431
653
|
require_markdown_links_valid
|
|
432
654
|
if [[ "$(state_get verification_report)" == "" || "$(state_get verification_report)" == "null" ]]; then
|
|
433
655
|
"$STATE" set "$CHANGE_DIR" verification_report test-report.md
|
|
@@ -436,11 +658,20 @@ case "$PHASE" in
|
|
|
436
658
|
;;
|
|
437
659
|
archive)
|
|
438
660
|
require_state_file
|
|
661
|
+
require_tasks_complete
|
|
439
662
|
verify_result="$(state_get verify_result)"
|
|
440
663
|
[[ "$verify_result" == "pass" ]] || issues+=("verify_result must be pass before archive")
|
|
441
664
|
archived="$(state_get archived)"
|
|
442
665
|
[[ "$archived" != "true" ]] || issues+=("archived is already true")
|
|
443
666
|
require_state_value verification_report "verification_report"
|
|
667
|
+
report_path="$(verification_report_path || true)"
|
|
668
|
+
if [[ -z "$report_path" ]]; then
|
|
669
|
+
issues+=("verification_report path does not exist")
|
|
670
|
+
else
|
|
671
|
+
require_closeout_markers "$report_path"
|
|
672
|
+
fi
|
|
673
|
+
require_branch_handled
|
|
674
|
+
require_state_value verified_at "verified_at"
|
|
444
675
|
transition_event="archived"
|
|
445
676
|
;;
|
|
446
677
|
*)
|
|
@@ -43,6 +43,16 @@ Use `.sdd/state.yaml` `verify_mode` after `scale`.
|
|
|
43
43
|
prove the complete evidence chain: source/Mapper/XML, DB when needed, real
|
|
44
44
|
entry point, interface automation, logs, SQL sync, and consumer behavior.
|
|
45
45
|
|
|
46
|
+
Money-related changes always require full verification of
|
|
47
|
+
`Money Precision Boundary`: original calculation inputs and intermediate precision, the actual
|
|
48
|
+
rounding boundary and mode, half-cent/residual/multi-detail cases, deterministic
|
|
49
|
+
allocation, and reconciliation identities. A final two-decimal display value
|
|
50
|
+
or unit-test-only evidence is not sufficient.
|
|
51
|
+
For additive identities, verification must prove which total was authoritative,
|
|
52
|
+
which N-1 components were calculated independently, and which final complement
|
|
53
|
+
was derived as `authoritative total - sum(other components)`. Evidence that all
|
|
54
|
+
components were independently calculated and rounded is a failure.
|
|
55
|
+
|
|
46
56
|
## Required Superpowers
|
|
47
57
|
|
|
48
58
|
Immediately load and apply these Superpowers when available:
|
|
@@ -94,8 +104,20 @@ Before pass:
|
|
|
94
104
|
delivery or branch closeout.
|
|
95
105
|
5. Code review findings are either fixed or explicitly recorded with accepted
|
|
96
106
|
risk.
|
|
97
|
-
6.
|
|
107
|
+
6. For money-related changes, `test-report.md` records the `Money Precision
|
|
108
|
+
Boundary` cases and proves original, discount, actual/refund, and allocated
|
|
109
|
+
totals reconcile without early rounding. For additive identities it also
|
|
110
|
+
records the authoritative total and the subtraction used to derive the final
|
|
111
|
+
complement.
|
|
112
|
+
7. Branch/worktree status is handled and `.sdd/state.yaml` has:
|
|
98
113
|
`branch_status: handled`.
|
|
114
|
+
8. Every checkbox in `tasks.md` is checked. A completed implementation with
|
|
115
|
+
stale task documentation is a verification failure, not an archive-time
|
|
116
|
+
cleanup item.
|
|
117
|
+
9. `test-report.md` ends with the machine-checkable closeout markers
|
|
118
|
+
`验证结果: PASS` and `归档就绪: PASS`. For `verify_mode: full`, it also
|
|
119
|
+
records the test environment, branch/commit/build or image fingerprint,
|
|
120
|
+
Base URL, and verification timestamp.
|
|
99
121
|
|
|
100
122
|
Only then run:
|
|
101
123
|
|