create-yss-spec 3.3.4 → 3.3.7
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 +2 -2
- package/package.json +1 -1
- package/src/template/instance-runtime.js +8 -2
- package/src/validation/snapshot.js +7 -0
- package/template/.agents/skills/.strategic-design-skills-manifest.json +7 -5
- package/template/.agents/skills/archify/SKILL.md +1 -1
- package/template/.agents/skills/code-review/SKILL.md +6 -0
- package/template/.agents/skills/i-have-adhd/LICENSE +21 -0
- package/template/.agents/skills/i-have-adhd/SKILL.md +26 -0
- package/template/.agents/skills/i-have-adhd/agents/openai.yaml +6 -0
- package/template/.agents/skills/i-have-adhd/references/yss-adaptation.md +21 -0
- package/template/.agents/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
- package/template/.agents/skills/prototype-review/SKILL.md +2 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
- package/template/.agents/skills/yss-openapi-governance/SKILL.md +6 -0
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
- package/template/.agents/skills/yss-prototype-stage/SKILL.md +6 -0
- package/template/.agents/skills/yss-research/SKILL.md +6 -0
- package/template/.agents/skills/yss-stage-decision/SKILL.md +19 -4
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.agents/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.agents/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.agents/skills/yss-technical-design/SKILL.md +6 -0
- package/template/.codex/skills/archify/SKILL.md +1 -1
- package/template/.codex/skills/code-review/SKILL.md +6 -0
- package/template/.codex/skills/i-have-adhd/LICENSE +21 -0
- package/template/.codex/skills/i-have-adhd/SKILL.md +26 -0
- package/template/.codex/skills/i-have-adhd/agents/openai.yaml +6 -0
- package/template/.codex/skills/i-have-adhd/references/yss-adaptation.md +21 -0
- package/template/.codex/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
- package/template/.codex/skills/prototype-review/SKILL.md +2 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
- package/template/.codex/skills/yss-openapi-governance/SKILL.md +6 -0
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
- package/template/.codex/skills/yss-prototype-stage/SKILL.md +6 -0
- package/template/.codex/skills/yss-research/SKILL.md +6 -0
- package/template/.codex/skills/yss-stage-decision/SKILL.md +19 -4
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.codex/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.codex/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.codex/skills/yss-technical-design/SKILL.md +6 -0
- package/template/.cursor/skills/archify/SKILL.md +1 -1
- package/template/.cursor/skills/code-review/SKILL.md +6 -0
- package/template/.cursor/skills/i-have-adhd/LICENSE +21 -0
- package/template/.cursor/skills/i-have-adhd/SKILL.md +26 -0
- package/template/.cursor/skills/i-have-adhd/agents/openai.yaml +6 -0
- package/template/.cursor/skills/i-have-adhd/references/yss-adaptation.md +21 -0
- package/template/.cursor/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
- package/template/.cursor/skills/prototype-review/SKILL.md +2 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
- package/template/.cursor/skills/yss-openapi-governance/SKILL.md +6 -0
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
- package/template/.cursor/skills/yss-prototype-stage/SKILL.md +6 -0
- package/template/.cursor/skills/yss-research/SKILL.md +6 -0
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +19 -4
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.cursor/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.cursor/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.cursor/skills/yss-technical-design/SKILL.md +6 -0
- package/template/.pi/skills/archify/SKILL.md +1 -1
- package/template/.pi/skills/code-review/SKILL.md +6 -0
- package/template/.pi/skills/i-have-adhd/LICENSE +21 -0
- package/template/.pi/skills/i-have-adhd/SKILL.md +26 -0
- package/template/.pi/skills/i-have-adhd/agents/openai.yaml +6 -0
- package/template/.pi/skills/i-have-adhd/references/yss-adaptation.md +21 -0
- package/template/.pi/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
- package/template/.pi/skills/prototype-review/SKILL.md +2 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
- package/template/.pi/skills/yss-openapi-governance/SKILL.md +6 -0
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
- package/template/.pi/skills/yss-prototype-stage/SKILL.md +6 -0
- package/template/.pi/skills/yss-research/SKILL.md +6 -0
- package/template/.pi/skills/yss-stage-decision/SKILL.md +19 -4
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
- package/template/.pi/skills/yss-stage-decision/references/validation-rules.md +2 -2
- package/template/.pi/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
- package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
- package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
- package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
- package/template/.pi/skills/yss-technical-design/SKILL.md +6 -0
- package/template/docs/agents/yss-skill-registry.yaml +22 -0
- package/template/docs/plan/templates/plan-template.md +8 -4
- package/template/docs/process/document-writing.md +77 -0
- package/template/docs/process/frontend-backend-delivery.md +7 -4
- package/template/docs/process/schemas/backend-delivery.schema.json +4 -0
- package/template/docs/process/schemas/frontend-delivery-acceptance-v1.schema.json +200 -0
- package/template/docs/process/schemas/frontend-delivery-acceptance.schema.json +37 -3
- package/template/docs/process/schemas/frontend-strategic-preflight.schema.json +32 -0
- package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +2 -1
- package/template/docs/process/schemas/strategic-consumer-feedback.schema.json +40 -0
- package/template/docs/process/schemas/strategic-design-handoff-v3.schema.json +743 -0
- package/template/docs/process/schemas/strategic-design-handoff-v4.schema.json +712 -0
- package/template/docs/process/schemas/strategic-feedback-adjudication.schema.json +42 -0
- package/template/docs/process/schemas/strategic-handoff-domain-strategy-v3.schema.json +216 -0
- package/template/docs/process/schemas/strategic-handoff-import-receipt.schema.json +39 -0
- package/template/docs/process/schemas/strategic-handoff-stage-decision-package-v3.schema.json +148 -0
- package/template/docs/process/strategic-handoff-package.md +37 -4
- package/template/docs/process/templates/lifecycle-checkpoint-template.yaml +1 -0
- package/template/docs/process/templates/stage-checkpoint-template.md +1 -0
- package/template/docs/templates/examples/lifecycle-writing-examples.md +138 -0
- package/template/docs/templates/spec-template.md +16 -3
- package/template/docs/templates/vertical-slice-ticket-template.md +8 -4
- package/template/scripts/lib/approval-record.mjs +2 -1
- package/template/scripts/lib/backend-delivery.mjs +15 -3
- package/template/scripts/lib/frontend-delivery-boundary.mjs +20 -4
- package/template/scripts/lib/frontend-delivery.mjs +66 -2
- package/template/scripts/lib/profile-skill-sync.mjs +336 -0
- package/template/scripts/lib/strategic-feedback.mjs +33 -0
- package/template/scripts/lib/strategic-handoff-consumption.mjs +5 -0
- package/template/scripts/lib/strategic-handoff-io.mjs +1 -0
- package/template/scripts/lib/strategic-handoff.mjs +101 -10
- package/template/scripts/lib/user-decision-reuse.mjs +38 -0
- package/template/scripts/strategic-feedback +10 -0
- package/template/scripts/sync-profile-skills +43 -0
- package/template/scripts/verify-frontend-strategic-preflight +12 -0
- package/template/skills-lock.json +38 -20
- package/template.manifest.json +1 -0
- package/template.snapshot.json +6 -5
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Plan、Spec、Ticket 写作对照
|
|
2
|
+
|
|
3
|
+
性质:虚构的写作示例,非产品资产,不代表业务术语或批准记录。
|
|
4
|
+
|
|
5
|
+
本文件配合[中文写作规范](../../process/document-writing.md)。每组先给固定输入,再给两种表达,最后逐项核对。三组独立提供事实,不表示真实项目已经从 Plan 进入 Spec 或取得任何批准。“原写法”由作者构造,不是对模型运行结果或真实文档的抽样。
|
|
6
|
+
|
|
7
|
+
## 1. Plan:让业务问题和取舍可见
|
|
8
|
+
|
|
9
|
+
### 固定输入
|
|
10
|
+
|
|
11
|
+
| 示例编号 | 已提供信息 |
|
|
12
|
+
|---|---|
|
|
13
|
+
| P1 | 示例访谈中,一名采购申请人说申请曾因缺少材料被退回;未提供访谈记录或样本统计 |
|
|
14
|
+
| P2 | 本期候选范围是在提交前检查必填附件,并指出缺少的材料;业务价值尚待验证 |
|
|
15
|
+
| P3 | 材料真实性识别、审批路线调整不在本期范围 |
|
|
16
|
+
| P4 | 建议用缺材料退回比例观察效果;基线、统计口径和目标值尚未确认 |
|
|
17
|
+
| P5 | 必填材料清单尚未确认,影响关键业务规则;需求经理需在进入 Spec 前取得业务负责人确认,并交接给 Spec 起草者 |
|
|
18
|
+
| P6 | 当前范围及成功标准仍待用户确认,本组示例不能支持 Plan 流转 |
|
|
19
|
+
|
|
20
|
+
### 原写法:事实齐全,但结论被修饰语遮住
|
|
21
|
+
|
|
22
|
+
为全面提升采购协作体验,本阶段拟通过前置校验能力构建高效闭环,实现申请质量的持续优化。一名申请人在示例访谈中提到材料缺失导致退回,但尚无访谈原始记录及统计数据。规划提交前检查必填附件并提示缺少材料,业务价值待验证;材料真实性识别和审批路线调整不纳入本期。建议围绕缺材料退回比例建立成效评估体系,相关基线、统计口径和目标值有待明确。必填清单影响关键业务规则,由需求经理在进入 Spec 前取得业务负责人确认并交给 Spec 起草者;范围和成功标准也待用户确认,当前不能流转。
|
|
23
|
+
|
|
24
|
+
### 改写:按问题、范围和未决决定组织
|
|
25
|
+
|
|
26
|
+
本期建议在采购申请提交前检查必填附件,直接告诉申请人缺少哪些材料。
|
|
27
|
+
|
|
28
|
+
问题线索来自一名申请人对材料缺失退回的描述;目前没有原始访谈记录和统计数据,尚不能判断问题发生频率或预期收益。
|
|
29
|
+
|
|
30
|
+
本期不做材料真实性识别,也不调整审批路线。建议观察缺材料退回比例是否下降;统计口径、基线和目标值仍待确认。
|
|
31
|
+
|
|
32
|
+
进入 Spec 前,需求经理需要取得业务负责人对必填材料清单的确认,并交给 Spec 起草者。清单影响关键业务规则;当前范围和成功标准也未取得用户确认,因此本组规划尚不能流转。
|
|
33
|
+
|
|
34
|
+
### 保真核对
|
|
35
|
+
|
|
36
|
+
| 输入 | 改写落点 | 保留语义 |
|
|
37
|
+
|---|---|---|
|
|
38
|
+
| P1 | 问题线索段 | 保留单一样本和来源缺口,没有改写成普遍问题 |
|
|
39
|
+
| P2 | 首段及问题线索段 | 范围保持候选语气,没有承诺已验证收益 |
|
|
40
|
+
| P3 | 非目标句 | 两项非目标均保留 |
|
|
41
|
+
| P4 | 指标句 | 基线、口径、目标均未凭空补值 |
|
|
42
|
+
| P5 | 最后一段 | 保留关键程度、负责人、确认方、时点和接收方 |
|
|
43
|
+
| P6 | 最后一句 | 未将文字完善解释为可以流转 |
|
|
44
|
+
|
|
45
|
+
## 2. Spec:让规则可以转成验收
|
|
46
|
+
|
|
47
|
+
### 固定输入
|
|
48
|
+
|
|
49
|
+
以下是假设已由业务提供的七条规则,用于独立演示;它们不是从上一组待确认的 Plan 自动推导的决定。
|
|
50
|
+
|
|
51
|
+
| 示例编号 | 已提供信息 |
|
|
52
|
+
|---|---|
|
|
53
|
+
| S1 | 校验发生在申请人点击提交时 |
|
|
54
|
+
| S2 | 缺少任一必填附件时,拒绝提交,申请保持草稿 |
|
|
55
|
+
| S3 | 逐一列出所有缺少附件的名称,不只显示第一项 |
|
|
56
|
+
| S4 | 校验拒绝后,保留本次页面已填写内容;未承诺关闭或刷新页面后仍保留 |
|
|
57
|
+
| S5 | 补齐附件后,再次提交时重新校验 |
|
|
58
|
+
| S6 | 附件齐全且其他既有提交条件通过时,沿用既有提交流程;附件齐全本身不保证提交成功 |
|
|
59
|
+
| S7 | 不检查材料真实性;必填清单读取失败时如何处理尚未确认,交业务负责人在 Spec 冻结前确认 |
|
|
60
|
+
|
|
61
|
+
### 原写法:规则挤在一段中
|
|
62
|
+
|
|
63
|
+
系统应提供完善的附件校验能力和友好的异常反馈。在申请人点击提交时进行检查,缺少任一必填附件即拒绝并保持草稿,完整列出所有缺少附件名称,且保留本次页面输入,但不保证刷新或关闭页面后保留。补齐后再次提交需重新校验,只有附件齐全且其他既有条件也通过才能沿用既有流程,附件齐全不能单独保证成功。不校验材料真实性;清单读取失败行为尚未明确,需业务负责人在 Spec 冻结前确认,以保障整体体验。
|
|
64
|
+
|
|
65
|
+
### 改写:规则和例子对应
|
|
66
|
+
|
|
67
|
+
申请人点击提交时,系统检查必填附件。缺少任一附件即拒绝提交,申请保持草稿,并逐一列出所有缺少附件的名称。
|
|
68
|
+
|
|
69
|
+
| 条件 / 操作 | 可观察结果 | 对应输入 |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| 缺少任一必填附件,点击提交 | 拒绝提交;申请仍为草稿;列出全部缺失名称 | S1、S2、S3 |
|
|
72
|
+
| 因附件缺失被拒绝 | 本次页面已填写内容仍在;不承诺刷新或关闭后的保存 | S4 |
|
|
73
|
+
| 补齐附件后再次点击提交 | 重新执行附件校验 | S5 |
|
|
74
|
+
| 附件齐全且其他既有条件通过 | 进入既有提交流程 | S6 |
|
|
75
|
+
|
|
76
|
+
附件齐全不代表其他提交条件已经通过。本功能不检查材料真实性。
|
|
77
|
+
|
|
78
|
+
验收例子:在示例清单中,“报价单”和“采购说明”均为必填,申请人两项都未提供。点击提交后,应看到两个缺失名称,申请仍为草稿,当前页面已填写内容保留。这里的附件名称是测试数据,不扩展实际必填清单。
|
|
79
|
+
|
|
80
|
+
待确认:必填清单读取失败时的行为,由业务负责人在 Spec 冻结前确认。当前不能将失败默认解释为放行或拒绝。
|
|
81
|
+
|
|
82
|
+
### 保真核对
|
|
83
|
+
|
|
84
|
+
| 输入 | 改写落点 | 保留语义 |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| S1、S2 | 首段、首行条件 | 触发点和状态保持不变 |
|
|
87
|
+
| S3 | 首段、首行结果、验收例子 | “所有”未缩为一项,没有五项展示上限 |
|
|
88
|
+
| S4 | 第二行结果 | 页面内保留未扩展成持久保存 |
|
|
89
|
+
| S5 | 第三行 | 保留再次校验 |
|
|
90
|
+
| S6 | 第四行及后续限定句 | 保留与其他条件的合取关系 |
|
|
91
|
+
| S7 | 非目标与待确认段 | 未新增真实性检查,也未决定故障降级行为 |
|
|
92
|
+
|
|
93
|
+
本例比原文更长,增加的是规则之间的边界和定位信息;这不构成效果退步。
|
|
94
|
+
|
|
95
|
+
## 3. Ticket:把交付行为与实现就绪区分清楚
|
|
96
|
+
|
|
97
|
+
### 固定输入
|
|
98
|
+
|
|
99
|
+
| 示例编号 | 已提供信息 |
|
|
100
|
+
|---|---|
|
|
101
|
+
| T1 | 切片交付“提交申请时校验必填附件并展示拒绝结果”,覆盖所需前后端行为,不以技术层横拆 |
|
|
102
|
+
| T2 | 示例内给定 Spec v2 的规则 R1 和 OpenAPI v3 已冻结;它们只是虚构输入标签,没有真实批准记录 |
|
|
103
|
+
| T3 | 验收覆盖缺失时拒绝且不提交、全部缺失名称可见、页面输入保留,以及补齐后重新校验 |
|
|
104
|
+
| T4 | 公共测试 seam 是提交接口和申请表单交互;命令应从真实工程与实现合同读取,示例未提供命令 |
|
|
105
|
+
| T5 | Slice Implementation Contract v1 仍为草案、生命周期批准 pending;依赖的必填材料配置切片未完成 |
|
|
106
|
+
| T6 | 当前 Ticket 状态为 ready-for-human;不存在实现或测试通过证据;真实性识别不在范围内 |
|
|
107
|
+
|
|
108
|
+
### 原写法:重点埋在实现名词之后
|
|
109
|
+
|
|
110
|
+
本任务将全面完善前后端附件校验链路,覆盖提交接口、页面交互及相关测试,遵循示例 Spec v2 / R1 和冻结 OpenAPI v3,以端到端切片交付提交申请时的必填附件校验及拒绝反馈,不按技术层横拆。需验证缺失拒绝且不提交、完整提示缺失名称、保留页面输入和补齐后重新校验;公共 seam 为提交接口与申请表单,命令需读取工程和合同。实现合同 v1 为草案且批准 pending,必填材料配置依赖尚未完成。状态 ready-for-human,尚无实现或测试通过证据,真实性识别不在范围。
|
|
111
|
+
|
|
112
|
+
### 改写:先说交付,再列验收和阻塞
|
|
113
|
+
|
|
114
|
+
本切片交付:申请人提交申请时,系统校验必填附件,并在拒绝提交后展示缺失材料。交付覆盖所需前后端行为。
|
|
115
|
+
|
|
116
|
+
范围依据:示例 Spec v2 / R1、冻结 OpenAPI v3;材料真实性识别不在本切片范围。
|
|
117
|
+
|
|
118
|
+
验收项均待验证:
|
|
119
|
+
|
|
120
|
+
- [ ] 缺少必填附件时拒绝提交,申请未提交。
|
|
121
|
+
- [ ] 页面列出全部缺失附件名称。
|
|
122
|
+
- [ ] 拒绝后保留本次页面已填写内容。
|
|
123
|
+
- [ ] 补齐后再次提交,重新执行附件校验。
|
|
124
|
+
|
|
125
|
+
通过提交接口和申请表单交互验证以上行为。具体命令待从真实工程与实现合同读取,当前没有实现或测试通过证据。
|
|
126
|
+
|
|
127
|
+
当前状态:`ready-for-human`。实现合同 v1 为草案,生命周期批准为 `pending`;必填材料配置切片也未完成。两项阻塞均需闭合,并由生命周期完成全部适用就绪核验后,才可决定是否进入实现。
|
|
128
|
+
|
|
129
|
+
### 保真核对
|
|
130
|
+
|
|
131
|
+
| 输入 | 改写落点 | 保留语义 |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| T1 | 首段 | 保留完整用户行为和跨受影响层范围 |
|
|
134
|
+
| T2 | 范围依据 | 沿用示例版本,不产生真实批准 |
|
|
135
|
+
| T3 | 四条未勾选验收 | 四项均保留,未伪造完成 |
|
|
136
|
+
| T4 | 验证段 | seam 明确,未臆造工程命令 |
|
|
137
|
+
| T5 | 状态段 | 两项阻塞均展示,未只保留一个下一步 |
|
|
138
|
+
| T6 | 范围、验证及状态段 | 状态未提前推进;未扩大范围 |
|
|
@@ -7,17 +7,19 @@ owner: ai
|
|
|
7
7
|
|
|
8
8
|
# 产品研发规格:<功能名称>
|
|
9
9
|
|
|
10
|
+
填写前读取[中文写作规范](../process/document-writing.md)和 [Spec 对照](examples/lifecycle-writing-examples.md#2-spec让规则可以转成验收)。保留原规则、例外和不确定性;输入缺失时记录待确认项。
|
|
11
|
+
|
|
10
12
|
## 功能父 Ticket
|
|
11
13
|
|
|
12
14
|
<Local:`docs/.scratch/<feature>/parent-ticket.md`;GitHub / GitLab:Issue URL / 编号>
|
|
13
15
|
|
|
14
16
|
## 问题陈述
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
(说明哪个角色在什么场景遇到什么问题,给出来源及其限制。)
|
|
17
19
|
|
|
18
20
|
## 解决方案
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
(说明本次改变的用户行为和范围,区分已确认规则与候选方案。)
|
|
21
23
|
|
|
22
24
|
## 用户故事
|
|
23
25
|
|
|
@@ -25,12 +27,16 @@ owner: ai
|
|
|
25
27
|
|
|
26
28
|
## 功能需求
|
|
27
29
|
|
|
30
|
+
需求写明主体、触发条件和可观察结果;关联验收标准。不要用“完善、友好、高效”代替规则。
|
|
31
|
+
|
|
28
32
|
| ID | 需求 | 优先级 | 备注 |
|
|
29
33
|
|---|---|---|---|
|
|
30
34
|
| FR-001 | | P0/P1/P2 | |
|
|
31
35
|
|
|
32
36
|
## 非功能需求
|
|
33
37
|
|
|
38
|
+
命中时填写工作负载或适用条件、目标值及单位、验证方式与依据;尚未确认的目标保留为未决项,不补造性能承诺。
|
|
39
|
+
|
|
34
40
|
| 类别 | 需求 | 目标 |
|
|
35
41
|
|---|---|---|
|
|
36
42
|
| 性能 | | |
|
|
@@ -38,6 +44,8 @@ owner: ai
|
|
|
38
44
|
|
|
39
45
|
## 验收标准
|
|
40
46
|
|
|
47
|
+
关联需求 ID,按实际影响覆盖成功、拒绝、边界和恢复。保留“全部”“仅当”等限定;测试数据不能反向扩展业务规则。
|
|
48
|
+
|
|
41
49
|
```gherkin
|
|
42
50
|
假如 <上下文>
|
|
43
51
|
当 <操作>
|
|
@@ -47,7 +55,8 @@ owner: ai
|
|
|
47
55
|
## 产品总体设计 / 功能架构
|
|
48
56
|
|
|
49
57
|
- 功能域与模块边界:
|
|
50
|
-
- MVP
|
|
58
|
+
- MVP:
|
|
59
|
+
- 非目标:见本文“非目标范围”,此处不重复维护。
|
|
51
60
|
- UI 影响:是 / 否
|
|
52
61
|
- 产品总体设计:`docs/.scratch/<feature>/design/<feature>-product-overview-design.md`
|
|
53
62
|
|
|
@@ -99,4 +108,8 @@ owner: ai
|
|
|
99
108
|
|
|
100
109
|
## 非目标范围
|
|
101
110
|
|
|
111
|
+
明确本次不交付什么及依据;与上游范围保持一致。
|
|
112
|
+
|
|
102
113
|
## 风险
|
|
114
|
+
|
|
115
|
+
记录已知风险和未决项的影响、责任人、解决时点及接收方;尚未明确原因时保留现象和验证方法。
|
|
@@ -4,7 +4,7 @@ status: ready-for-human
|
|
|
4
4
|
|
|
5
5
|
# 垂直切片 Ticket:<标题>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
填写前读取[中文写作规范](../process/document-writing.md)和 [Ticket 对照](examples/lifecycle-writing-examples.md#3-ticket把交付行为与实现就绪区分清楚)。状态只在 frontmatter 维护,正文记录依据。
|
|
8
8
|
|
|
9
9
|
## 父级
|
|
10
10
|
|
|
@@ -14,6 +14,8 @@ Status: ready-for-human
|
|
|
14
14
|
|
|
15
15
|
描述本 Ticket 要交付的窄而完整的端到端行为。它必须贯穿所有受影响层,是可独立验证的垂直切片,不能只是某一层的横向任务。
|
|
16
16
|
|
|
17
|
+
先用一句话写出用户操作及交付结果,再引用对应 Spec 规则、版本和本切片边界;不要重写冻结需求或填入未经确认的范围。
|
|
18
|
+
|
|
17
19
|
## 覆盖的用户故事
|
|
18
20
|
|
|
19
21
|
- <用户故事 ID 或文本>
|
|
@@ -31,6 +33,8 @@ Status: ready-for-human
|
|
|
31
33
|
|
|
32
34
|
## 验收标准
|
|
33
35
|
|
|
36
|
+
每项写条件、操作和可观察结果,关联上游规则;保留必要例外。测试未执行前保持未勾选。
|
|
37
|
+
|
|
34
38
|
- [ ] 标准 1
|
|
35
39
|
- [ ] 标准 2
|
|
36
40
|
- [ ] 标准 3
|
|
@@ -92,7 +96,7 @@ Status: ready-for-human
|
|
|
92
96
|
|
|
93
97
|
## 阻塞关系
|
|
94
98
|
|
|
95
|
-
|
|
99
|
+
列出实际依赖、未决项、责任人和解除条件;尚未核验时写“待核验”。只有确认没有阻塞时才写“无”,无依赖不等于已通过实现就绪核验。
|
|
96
100
|
|
|
97
101
|
## 重路由状态
|
|
98
102
|
|
|
@@ -116,9 +120,9 @@ Status: ready-for-human
|
|
|
116
120
|
|
|
117
121
|
## 状态
|
|
118
122
|
|
|
119
|
-
|
|
123
|
+
状态依据:<当前版本合同、批准和就绪核验记录引用,以及尚未关闭的阻塞>。
|
|
120
124
|
|
|
121
|
-
>
|
|
125
|
+
> 默认 frontmatter 为 `ready-for-human`。仅在生命周期确认合同已批准且当前、阻塞已清除、全部适用门禁及就绪条件通过后更新为 `ready-for-agent`;本节不另维护第二个状态值。
|
|
122
126
|
|
|
123
127
|
## AI / 人工审查点
|
|
124
128
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertApprovalUserDecision } from './user-decision-reuse.mjs';
|
|
1
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { parseDocument } from "../vendor/yaml.mjs";
|
|
@@ -101,7 +102,7 @@ export function validateApprovalRecord(record, { rolesDoc, requireApproved = fal
|
|
|
101
102
|
|
|
102
103
|
function assertRecordUserDecision(record, registry, options) {
|
|
103
104
|
if (!registry.user_decision_policy.gates.includes(record.gate_id) && countersignRuleForGate(registry.gate_policy, record.gate_id)?.bucket !== "biological_human") return;
|
|
104
|
-
const result =
|
|
105
|
+
const result = assertApprovalUserDecision(record, registry, options);
|
|
105
106
|
if (record.actor_kind === "biological-human" && result.validated.some((item) => item.principal_ref !== record.principal_ref)) fail("user-decision-responder-mismatch: 生物人会签者与原始回复者不一致");
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -6,7 +6,7 @@ import { read, safe, ensure, hash, digest, json, files, write, project, schema,
|
|
|
6
6
|
|
|
7
7
|
// Evidence binds the deliverable basis, avoiding a circular hash through its own logs.
|
|
8
8
|
export function backendDeliveryBasis(delivery) {
|
|
9
|
-
return digest(Object.fromEntries(['delivery_id','version','strategic_bundle_digest','scope','openapi','slice_contract','build','environment'].map(key=>[key,delivery[key]])));
|
|
9
|
+
return digest(Object.fromEntries(['delivery_id','version','strategic_bundle_digest','strategic_route_id','scope','openapi','slice_contract','build','environment'].filter(key=>delivery[key]!==undefined).map(key=>[key,delivery[key]])));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
function boundFile(root, binding) {
|
|
@@ -57,6 +57,10 @@ export async function inspectBackendDelivery(root, ref) {
|
|
|
57
57
|
verification(root,delivery.verification.deployment,basis,'backend-deployment');
|
|
58
58
|
return openBundle(safe(root,delivery.strategic_bundle_ref),bundle=>{
|
|
59
59
|
ensure(bundle.manifest.bundle_digest===delivery.strategic_bundle_digest,'后端交付与战略版本不一致');
|
|
60
|
+
if(bundle.handoff.schema_version===4){
|
|
61
|
+
const route=bundle.handoff.consumer_routes.find(item=>item.capability==='backend-technical-design');
|
|
62
|
+
ensure(route&&route.activation!=='not-applicable'&&delivery.strategic_route_id===route.route_id,'后端交付未绑定当前 backend-technical-design route_id');
|
|
63
|
+
}
|
|
60
64
|
const sources=new Set([...bundle.indexes.rules.map(x=>x.rule_id),...bundle.indexes.scenarios.map(x=>x.scenario_id)]);
|
|
61
65
|
ensure(delivery.scope.source_ids.every(id=>sources.has(id)),'后端交付引用未知规则/场景');
|
|
62
66
|
const scenarios=bundle.indexes.scenarios.filter(x=>delivery.scope.source_ids.includes(x.scenario_id));
|
|
@@ -152,14 +156,22 @@ export async function importBackendDelivery({bundle,targetRoot}) {
|
|
|
152
156
|
}
|
|
153
157
|
const strategic=await importBundle({bundle:safe(b.source,b.delivery.strategic_bundle_ref),targetRoot:target});
|
|
154
158
|
const strategicReceipt=read(safe(target,strategic.receipt_ref));
|
|
155
|
-
const
|
|
159
|
+
const strategicBase=path.posix.dirname(strategic.receipt_ref);
|
|
160
|
+
const frontendRoute=strategicReceipt.schema_version===2?strategicReceipt.routes.find(route=>route.capability==='frontend-engineering-design'):null;
|
|
161
|
+
const traceRef=frontendRoute?.artifact_refs.find(item=>item.endsWith('frontend-traceability-draft.json'))||`${strategicBase}/tactical-traceability-draft.json`;
|
|
162
|
+
const trace=read(safe(target,traceRef));
|
|
156
163
|
mkdirSync(path.dirname(destination),{recursive:true});
|
|
157
164
|
const staging=mkdtempSync(path.join(path.dirname(destination),'.backend-import-'));
|
|
158
165
|
try {
|
|
159
166
|
cpSync(b.root,path.join(staging,'package'),{recursive:true,errorOnExist:true,force:false});
|
|
160
167
|
const receipt={schema_version:1,delivery_id:b.delivery.delivery_id,version:b.delivery.version,bundle_digest:b.manifest.bundle_digest,package_ref:`${ref}/package`};
|
|
161
168
|
write(staging,'import-receipt.json',json(receipt));
|
|
162
|
-
|
|
169
|
+
const strategicHandoff={import_receipt_ref:strategic.receipt_ref,bundle_digest:strategicReceipt.bundle_digest,...(trace.route_id?{route_id:trace.route_id}:{}),context_reconciliation_ref:'',rows:trace.rows.map(({tactical_refs,test_seam_refs,...row})=>({...row,frontend_case_refs:[]}))};
|
|
170
|
+
if(strategicReceipt.schema_version===2){
|
|
171
|
+
ensure(frontendRoute,'Handoff v4 Import Receipt 未选择 frontend-engineering-design 能力');
|
|
172
|
+
const preflightRef=frontendRoute.artifact_refs.find(item=>item.endsWith('frontend-strategic-preflight-draft.json'));ensure(preflightRef,'Handoff v4 缺少 Frontend Strategic Preflight 草案');
|
|
173
|
+
write(staging,'frontend-acceptance-draft.json',json({schema_version:2,status:'draft',slice_id:b.delivery.scope.slice_id,strategic_preflight:{ref:preflightRef,digest:hash(readFileSync(safe(target,preflightRef)))},backend_dependency:{mode:'required',route_id:'route.backend'},backend_delivery:{import_receipt_ref:`${ref}/import-receipt.json`,bundle_digest:b.manifest.bundle_digest},strategic_handoff:strategicHandoff,frontend_cases:[]}));
|
|
174
|
+
}else write(staging,'frontend-acceptance-draft.json',json({schema_version:1,status:'draft',slice_id:b.delivery.scope.slice_id,backend_delivery:{import_receipt_ref:`${ref}/import-receipt.json`,bundle_digest:b.manifest.bundle_digest},strategic_handoff:strategicHandoff,frontend_cases:[]}));
|
|
163
175
|
ensure(!existsSync(destination),'后端包导入并发冲突');renameSync(staging,destination);
|
|
164
176
|
return {result:'imported-pending-acceptance',receipt_ref:`${ref}/import-receipt.json`,acceptance_ref:`${ref}/frontend-acceptance-draft.json`};
|
|
165
177
|
} finally { rmSync(staging,{recursive:true,force:true}); }
|
|
@@ -7,14 +7,27 @@ import { ROOT, read, safe, ensure, digest } from './strategic-handoff-io.mjs';
|
|
|
7
7
|
// Shared synchronous adapter for existing compiler, lifecycle and task-package seams.
|
|
8
8
|
// Always re-executes the verifier; a caller-supplied "verified" flag is never evidence.
|
|
9
9
|
export function enforceFrontendDelivery(state={}, {root=ROOT,phase='inputs'}={}) {
|
|
10
|
+
ensure(['preflight','design','contract','inputs','implementation','verification'].includes(phase),`未知前端交付阶段: ${phase}`);
|
|
10
11
|
const profile=loadDeliveryProfile(root);
|
|
11
12
|
let contract;
|
|
12
13
|
const contractRef=state.slice_contract_ref||state.contract?.slice_contract_ref;
|
|
13
|
-
const
|
|
14
|
+
const dedicatedProfile=profile?.profile_id==='harness.frontend-delivery'||profile?.profile_id==='yss-harness-frontend';
|
|
15
|
+
const selected=dedicatedProfile||profile?.frontend_delivery?.required===true||profile?.handoff?.consumer_capabilities?.includes('frontend-engineering-design');
|
|
14
16
|
const identity=selected?read(safe(root,'yss-project.yaml')):null;
|
|
15
17
|
if(selected)ensure(identity.schema_version===1&&['template-source','project-instance'].includes(identity.repository_mode),'前端项目仓库身份无效');
|
|
16
|
-
const dedicated=
|
|
18
|
+
const dedicated=dedicatedProfile&&identity.repository_mode==='project-instance';
|
|
17
19
|
if(dedicated)ensure(state.contract?.kind!=='template-maintenance','前端产品项目不得用模板维护任务绕过输入条件');
|
|
20
|
+
if(['preflight','design'].includes(phase)) {
|
|
21
|
+
const preflight=state.frontend_preflight||state.frontend?.preflight||state.resolution?.frontend_preflight;
|
|
22
|
+
ensure(preflight?.preflight_ref,'frontend-preflight-required: 缺少 Frontend Strategic Preflight');
|
|
23
|
+
const args=[path.join(ROOT,'scripts/verify-frontend-strategic-preflight'),'--root',root];
|
|
24
|
+
if(preflight.digest)args.push('--expected-digest',preflight.digest);
|
|
25
|
+
args.push(preflight.preflight_ref);
|
|
26
|
+
const verified=spawnSync(process.execPath,args,{cwd:root,encoding:'utf8',timeout:60000,maxBuffer:2*1024*1024});
|
|
27
|
+
ensure(verified.status===0,`frontend-preflight-blocked: ${verified.error?.message||verified.stderr||verified.stdout}`);
|
|
28
|
+
const result=JSON.parse(verified.stdout);ensure(result.result==='preflight-verified'&&result.ready_for_agent===false,'前端战略预检返回非法状态');
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
18
31
|
let binding=state.frontend_delivery||state.frontend?.delivery||state.resolution?.frontend_delivery;
|
|
19
32
|
if(contractRef) {
|
|
20
33
|
// Legacy callers may supply an absolute external contract. Discover whether
|
|
@@ -27,17 +40,20 @@ export function enforceFrontendDelivery(state={}, {root=ROOT,phase='inputs'}={})
|
|
|
27
40
|
binding=direct||resolved||binding;
|
|
28
41
|
}
|
|
29
42
|
}
|
|
30
|
-
|
|
43
|
+
const frontendStatus=contract?.frontend?.status||state.frontend?.status;
|
|
44
|
+
const contractRequiresFrontend=typeof frontendStatus==='string'&&!['not-applicable','disabled'].includes(frontendStatus);
|
|
45
|
+
if(!dedicated&&!binding&&!contractRequiresFrontend)return {result:'not-applicable'};
|
|
31
46
|
if(contractRef)safe(root,contractRef);
|
|
32
47
|
ensure(binding?.acceptance_ref,'frontend-delivery-required: 缺少战略与后端联合接收记录');
|
|
33
48
|
const slice=contract?.slice_id||state.slice_id;
|
|
34
49
|
ensure(!contract?.slice_id||!state.slice_id||contract.slice_id===state.slice_id,'前端任务与 Slice Contract 切片不一致');
|
|
35
50
|
ensure(slice,'frontend-delivery-required: 缺少明确切片');
|
|
36
|
-
if(
|
|
51
|
+
if(['implementation','verification'].includes(phase)) {
|
|
37
52
|
ensure(contract?.status==='approved','frontend-delivery-required: 必须读取已持久化的 approved Slice Contract');
|
|
38
53
|
ensure(contract.frontend?.delivery||contract.resolution?.frontend_delivery,'frontend-delivery-required: Slice Contract 未绑定前端交付');
|
|
39
54
|
ensure(binding.digest,'frontend-delivery-required: Slice Contract 未冻结接收记录摘要');
|
|
40
55
|
}
|
|
56
|
+
if(phase==='verification')ensure(state.frontend_implementation_verification_ref||contract?.frontend?.implementation_verification_ref,'frontend-delivery-required: 验证阶段缺少 frontend_implementation_verification 引用');
|
|
41
57
|
const args=[path.join(ROOT,'scripts/verify-frontend-delivery'),'--root',root,'--slice',slice];
|
|
42
58
|
if(binding.digest)args.push('--expected-digest',binding.digest);
|
|
43
59
|
args.push(binding.acceptance_ref);
|
|
@@ -1,9 +1,49 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
3
4
|
import { openBackendDelivery } from './backend-delivery.mjs';
|
|
4
5
|
import { openBundle } from './strategic-handoff.mjs';
|
|
5
6
|
import { verifyConsumption } from './strategic-handoff-consumption.mjs';
|
|
6
|
-
import { read, safe, ensure, hash, schema, project } from './strategic-handoff-io.mjs';
|
|
7
|
+
import { read, safe, ensure, hash, schema, project, ROOT } from './strategic-handoff-io.mjs';
|
|
8
|
+
|
|
9
|
+
const ACCEPTANCE_SCHEMAS=new Map([[1,'docs/process/schemas/frontend-delivery-acceptance-v1.schema.json'],[2,'docs/process/schemas/frontend-delivery-acceptance.schema.json']]);
|
|
10
|
+
|
|
11
|
+
function acceptanceSchema(version) {
|
|
12
|
+
ensure(ACCEPTANCE_SCHEMAS.has(version),`Frontend Delivery Acceptance 未知 schema_version: ${String(version)};支持版本: 1, 2;新接收请迁移到 2`);
|
|
13
|
+
return ACCEPTANCE_SCHEMAS.get(version);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export async function verifyFrontendStrategicPreflight({root=process.cwd(),preflightRef,expectedDigest}={}) {
|
|
17
|
+
project(root);
|
|
18
|
+
const file=safe(root,preflightRef),preflight=read(file);
|
|
19
|
+
schema(preflight,'docs/process/schemas/frontend-strategic-preflight.schema.json');
|
|
20
|
+
const preflightDigest=hash(readFileSync(file));
|
|
21
|
+
if(expectedDigest)ensure(expectedDigest===preflightDigest,'前端战略预检摘要已变化,需重编译合同');
|
|
22
|
+
ensure(preflight.status==='verified','前端战略预检尚未 verified');
|
|
23
|
+
const receipt=read(safe(root,preflight.import_receipt_ref));
|
|
24
|
+
ensure(receipt.schema_version===2,'Frontend Strategic Preflight 仅接受 Import Receipt v2');
|
|
25
|
+
const base=`docs/handoffs/${receipt.bundle_id}/${receipt.version}`;
|
|
26
|
+
ensure(preflight.import_receipt_ref===`${base}/import-receipt.json`&&receipt.package_ref===`${base}/package`,'战略预检收据路径与身份不匹配');
|
|
27
|
+
ensure(preflight.bundle_digest===receipt.bundle_digest,'战略预检与收据摘要不一致');
|
|
28
|
+
const routeReceipt=receipt.routes.find(item=>item.route_id===preflight.route_id&&item.capability==='frontend-engineering-design');
|
|
29
|
+
ensure(routeReceipt&&routeReceipt.activation!=='not-applicable','当前 Handoff 未启用前端工程设计路由');
|
|
30
|
+
const reconciliation=spawnSync(process.execPath,[path.join(ROOT,'scripts/verify-context-reconciliation'),'--root',root,safe(root,preflight.context_reconciliation_ref)],{encoding:'utf8'});
|
|
31
|
+
ensure(reconciliation.status===0,`前端战略预检 Context Reconciliation 未通过: ${reconciliation.error?.message||reconciliation.stderr}`);
|
|
32
|
+
return openBundle(safe(root,receipt.package_ref),bundle=>{
|
|
33
|
+
ensure(bundle.handoff.schema_version===4&&bundle.manifest.bundle_digest===receipt.bundle_digest,'前端战略预检必须绑定 Handoff v4 当前包');
|
|
34
|
+
const frontendRoute=bundle.handoff.consumer_routes.find(item=>item.route_id===preflight.route_id&&item.capability==='frontend-engineering-design');
|
|
35
|
+
const backendRoute=bundle.handoff.consumer_routes.find(item=>item.capability==='backend-technical-design');
|
|
36
|
+
ensure(frontendRoute&&frontendRoute.activation!=='not-applicable','前端路由未启用');
|
|
37
|
+
const known=[...bundle.indexes.rules.map(item=>item.rule_id),...bundle.indexes.scenarios.filter(item=>item.critical).map(item=>item.scenario_id)].sort();
|
|
38
|
+
ensure(JSON.stringify([...preflight.source_rule_refs].sort())===JSON.stringify(known),'前端战略预检未完整绑定源规则/关键场景');
|
|
39
|
+
const expectedVisual=`${base}/package/payload/files/${bundle.handoff.source.visual_baseline_ref.persisted_ref}/${bundle.handoff.source.visual_baseline_ref.manifest_ref}`;
|
|
40
|
+
ensure(preflight.visual_baseline_ref===expectedVisual,'前端战略预检 Visual Baseline 引用不一致');
|
|
41
|
+
const expectedMode=backendRoute.activation==='not-applicable'?'not-applicable':'required';
|
|
42
|
+
ensure(preflight.backend_dependency.mode===expectedMode&&preflight.backend_dependency.route_id===backendRoute.route_id,'前端战略预检后端依赖与消费者路由不一致');
|
|
43
|
+
if(expectedMode==='not-applicable')ensure(preflight.backend_dependency.reason===backendRoute.reason&&JSON.stringify(preflight.backend_dependency.impact_refs)===JSON.stringify(backendRoute.impact_refs)&&JSON.stringify(preflight.backend_dependency.evidence_refs)===JSON.stringify(backendRoute.evidence_refs),'backend-not-applicable 依据与战略路由不一致');
|
|
44
|
+
return {result:'preflight-verified',ready_for_agent:false,preflight_ref:preflightRef,preflight_digest:preflightDigest,strategic_bundle_digest:receipt.bundle_digest,backend_dependency:expectedMode,next_action:'prepare-frontend-engineering-design-draft'};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
7
47
|
|
|
8
48
|
function pointer(value, ref) {
|
|
9
49
|
ensure(ref.startsWith('/')&&!ref.includes('//'),'服务版本 JSON Pointer 无效');
|
|
@@ -35,10 +75,33 @@ export async function probeBackend(delivery) {
|
|
|
35
75
|
export async function verifyFrontendDelivery({root=process.cwd(),acceptanceRef,sliceRef,expectedDigest}) {
|
|
36
76
|
project(root);
|
|
37
77
|
const file=safe(root,acceptanceRef), acceptance=read(file);
|
|
38
|
-
schema(acceptance,
|
|
78
|
+
schema(acceptance,acceptanceSchema(acceptance?.schema_version));
|
|
39
79
|
const acceptanceDigest=hash(readFileSync(file));
|
|
40
80
|
if(expectedDigest)ensure(expectedDigest===acceptanceDigest,'前端接收记录摘要已变化,需重编译合同');
|
|
41
81
|
ensure(sliceRef&&acceptance.slice_id===sliceRef,'前端接收记录与执行切片不匹配');
|
|
82
|
+
if(acceptance.schema_version===2) {
|
|
83
|
+
const preflight=await verifyFrontendStrategicPreflight({root,preflightRef:acceptance.strategic_preflight.ref,expectedDigest:acceptance.strategic_preflight.digest});
|
|
84
|
+
ensure(preflight.strategic_bundle_digest===acceptance.strategic_handoff.bundle_digest,'前端接收与战略预检版本不一致');
|
|
85
|
+
if(acceptance.backend_dependency.mode==='not-applicable') {
|
|
86
|
+
ensure(!acceptance.backend_delivery,'backend-not-applicable 不得绑定后端交付收据');
|
|
87
|
+
const strategic=await verifyConsumption(acceptance,{root,sliceRef,consumer:'frontend'});
|
|
88
|
+
ensure(strategic.result==='verified',`战略承接阻断: ${JSON.stringify(strategic.issues)}`);
|
|
89
|
+
const strategicReceipt=read(safe(root,acceptance.strategic_handoff.import_receipt_ref));
|
|
90
|
+
return openBundle(safe(root,strategicReceipt.package_ref),bundle=>{
|
|
91
|
+
const visualCases=bundle.handoff.source.visual_baseline_ref.case_ids;
|
|
92
|
+
const sourceIds=new Set([...bundle.indexes.rules.map(item=>item.rule_id),...bundle.indexes.scenarios.filter(item=>item.critical).map(item=>item.scenario_id)]);
|
|
93
|
+
const ids=acceptance.frontend_cases.map(item=>item.case_id);ensure(new Set(ids).size===ids.length,'前端验收用例 ID 重复');
|
|
94
|
+
for(const item of acceptance.frontend_cases){
|
|
95
|
+
ensure(item.operation_ids.length===0,'backend-not-applicable 前端用例不得绑定 operation_ids');
|
|
96
|
+
ensure(item.source_ids.every(id=>sourceIds.has(id)),'前端用例引用未知规则/场景');
|
|
97
|
+
ensure(item.visual_case_ids.every(id=>visualCases.includes(id)),'前端用例视觉基线悬空');
|
|
98
|
+
const evidence=readFileSync(safe(root,item.evidence_ref));ensure(evidence.length>0&&hash(evidence)===item.evidence_digest,'前端承接用例说明为空或摘要漂移');
|
|
99
|
+
}
|
|
100
|
+
return {result:'inputs-verified',ready_for_agent:false,slice_id:sliceRef,acceptance_ref:acceptanceRef,acceptance_digest:acceptanceDigest,strategic_bundle_digest:strategic.consumed_bundle_digest,backend_dependency:'not-applicable',next_action:'prepare-or-revalidate-frontend-plan-and-slice-contract'};
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
ensure(acceptance.backend_dependency.mode==='required','frontend backend_dependency.mode 非法');
|
|
104
|
+
}
|
|
42
105
|
const binding=acceptance.backend_delivery, receipt=read(safe(root,binding.import_receipt_ref));
|
|
43
106
|
const base=`docs/backend-deliveries/${receipt.delivery_id}/${receipt.version}`;
|
|
44
107
|
ensure(binding.import_receipt_ref===`${base}/import-receipt.json`&&receipt.package_ref===`${base}/package`,'后端收据路径与身份不匹配');
|
|
@@ -56,6 +119,7 @@ export async function verifyFrontendDelivery({root=process.cwd(),acceptanceRef,s
|
|
|
56
119
|
await openBundle(safe(backend.source,delivery.strategic_bundle_ref),bundle=>{
|
|
57
120
|
const visualCases=bundle.handoff.source.visual_baseline_ref.case_ids;
|
|
58
121
|
for(const item of acceptance.frontend_cases) {
|
|
122
|
+
if(acceptance.schema_version===2)ensure(item.operation_ids.length>0,'有后端依赖时前端用例必须绑定已交付 operation_ids');
|
|
59
123
|
ensure(item.operation_ids.every(id=>delivery.scope.operation_ids.includes(id)),'前端用例依赖未交付接口');
|
|
60
124
|
ensure(item.source_ids.every(id=>delivery.scope.source_ids.includes(id)),'前端用例依赖未交付规则/场景');
|
|
61
125
|
ensure(item.visual_case_ids.every(id=>visualCases.includes(id)),'前端用例视觉基线悬空');
|