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.
Files changed (171) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/src/template/instance-runtime.js +8 -2
  4. package/src/validation/snapshot.js +7 -0
  5. package/template/.agents/skills/.strategic-design-skills-manifest.json +7 -5
  6. package/template/.agents/skills/archify/SKILL.md +1 -1
  7. package/template/.agents/skills/code-review/SKILL.md +6 -0
  8. package/template/.agents/skills/i-have-adhd/LICENSE +21 -0
  9. package/template/.agents/skills/i-have-adhd/SKILL.md +26 -0
  10. package/template/.agents/skills/i-have-adhd/agents/openai.yaml +6 -0
  11. package/template/.agents/skills/i-have-adhd/references/yss-adaptation.md +21 -0
  12. package/template/.agents/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
  13. package/template/.agents/skills/prototype-review/SKILL.md +2 -0
  14. package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
  15. package/template/.agents/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
  16. package/template/.agents/skills/yss-openapi-governance/SKILL.md +6 -0
  17. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +3 -1
  18. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
  19. package/template/.agents/skills/yss-prototype-stage/SKILL.md +6 -0
  20. package/template/.agents/skills/yss-research/SKILL.md +6 -0
  21. package/template/.agents/skills/yss-stage-decision/SKILL.md +19 -4
  22. package/template/.agents/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
  23. package/template/.agents/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
  24. package/template/.agents/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
  25. package/template/.agents/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
  26. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
  27. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
  28. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
  29. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
  30. package/template/.agents/skills/yss-stage-decision/references/validation-rules.md +2 -2
  31. package/template/.agents/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
  32. package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
  33. package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
  34. package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
  35. package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
  36. package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
  37. package/template/.agents/skills/yss-technical-design/SKILL.md +6 -0
  38. package/template/.codex/skills/archify/SKILL.md +1 -1
  39. package/template/.codex/skills/code-review/SKILL.md +6 -0
  40. package/template/.codex/skills/i-have-adhd/LICENSE +21 -0
  41. package/template/.codex/skills/i-have-adhd/SKILL.md +26 -0
  42. package/template/.codex/skills/i-have-adhd/agents/openai.yaml +6 -0
  43. package/template/.codex/skills/i-have-adhd/references/yss-adaptation.md +21 -0
  44. package/template/.codex/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
  45. package/template/.codex/skills/prototype-review/SKILL.md +2 -0
  46. package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
  47. package/template/.codex/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
  48. package/template/.codex/skills/yss-openapi-governance/SKILL.md +6 -0
  49. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +3 -1
  50. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
  51. package/template/.codex/skills/yss-prototype-stage/SKILL.md +6 -0
  52. package/template/.codex/skills/yss-research/SKILL.md +6 -0
  53. package/template/.codex/skills/yss-stage-decision/SKILL.md +19 -4
  54. package/template/.codex/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
  55. package/template/.codex/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
  56. package/template/.codex/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
  57. package/template/.codex/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
  58. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
  59. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
  60. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
  61. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
  62. package/template/.codex/skills/yss-stage-decision/references/validation-rules.md +2 -2
  63. package/template/.codex/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
  64. package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
  65. package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
  66. package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
  67. package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
  68. package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
  69. package/template/.codex/skills/yss-technical-design/SKILL.md +6 -0
  70. package/template/.cursor/skills/archify/SKILL.md +1 -1
  71. package/template/.cursor/skills/code-review/SKILL.md +6 -0
  72. package/template/.cursor/skills/i-have-adhd/LICENSE +21 -0
  73. package/template/.cursor/skills/i-have-adhd/SKILL.md +26 -0
  74. package/template/.cursor/skills/i-have-adhd/agents/openai.yaml +6 -0
  75. package/template/.cursor/skills/i-have-adhd/references/yss-adaptation.md +21 -0
  76. package/template/.cursor/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
  77. package/template/.cursor/skills/prototype-review/SKILL.md +2 -0
  78. package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
  79. package/template/.cursor/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
  80. package/template/.cursor/skills/yss-openapi-governance/SKILL.md +6 -0
  81. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +3 -1
  82. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
  83. package/template/.cursor/skills/yss-prototype-stage/SKILL.md +6 -0
  84. package/template/.cursor/skills/yss-research/SKILL.md +6 -0
  85. package/template/.cursor/skills/yss-stage-decision/SKILL.md +19 -4
  86. package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
  87. package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
  88. package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
  89. package/template/.cursor/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
  90. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
  91. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
  92. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
  93. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
  94. package/template/.cursor/skills/yss-stage-decision/references/validation-rules.md +2 -2
  95. package/template/.cursor/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
  96. package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
  97. package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
  98. package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
  99. package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
  100. package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
  101. package/template/.cursor/skills/yss-technical-design/SKILL.md +6 -0
  102. package/template/.pi/skills/archify/SKILL.md +1 -1
  103. package/template/.pi/skills/code-review/SKILL.md +6 -0
  104. package/template/.pi/skills/i-have-adhd/LICENSE +21 -0
  105. package/template/.pi/skills/i-have-adhd/SKILL.md +26 -0
  106. package/template/.pi/skills/i-have-adhd/agents/openai.yaml +6 -0
  107. package/template/.pi/skills/i-have-adhd/references/yss-adaptation.md +21 -0
  108. package/template/.pi/skills/i-have-adhd/tests/verify-integration.mjs +63 -0
  109. package/template/.pi/skills/prototype-review/SKILL.md +2 -0
  110. package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +6 -0
  111. package/template/.pi/skills/yss-implementation-contract-compiler/references/boundaries.md +10 -0
  112. package/template/.pi/skills/yss-openapi-governance/SKILL.md +6 -0
  113. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +3 -1
  114. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +12 -0
  115. package/template/.pi/skills/yss-prototype-stage/SKILL.md +6 -0
  116. package/template/.pi/skills/yss-research/SKILL.md +6 -0
  117. package/template/.pi/skills/yss-stage-decision/SKILL.md +19 -4
  118. package/template/.pi/skills/yss-stage-decision/references/domain-strategy-contract.md +4 -3
  119. package/template/.pi/skills/yss-stage-decision/references/domain-strategy-v2.schema.json +8 -0
  120. package/template/.pi/skills/yss-stage-decision/references/domain-strategy-v3.schema.json +8 -0
  121. package/template/.pi/skills/yss-stage-decision/references/domain-strategy.schema.json +75 -5
  122. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +4 -4
  123. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-v2.schema.json +8 -0
  124. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-v3.schema.json +8 -0
  125. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package.schema.json +59 -9
  126. package/template/.pi/skills/yss-stage-decision/references/validation-rules.md +2 -2
  127. package/template/.pi/skills/yss-stage-decision/scripts/migrate-contract-v3.mjs +143 -0
  128. package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +46 -4
  129. package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +48 -4
  130. package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +42 -13
  131. package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +37 -5
  132. package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +116 -23
  133. package/template/.pi/skills/yss-technical-design/SKILL.md +6 -0
  134. package/template/docs/agents/yss-skill-registry.yaml +22 -0
  135. package/template/docs/plan/templates/plan-template.md +8 -4
  136. package/template/docs/process/document-writing.md +77 -0
  137. package/template/docs/process/frontend-backend-delivery.md +7 -4
  138. package/template/docs/process/schemas/backend-delivery.schema.json +4 -0
  139. package/template/docs/process/schemas/frontend-delivery-acceptance-v1.schema.json +200 -0
  140. package/template/docs/process/schemas/frontend-delivery-acceptance.schema.json +37 -3
  141. package/template/docs/process/schemas/frontend-strategic-preflight.schema.json +32 -0
  142. package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +2 -1
  143. package/template/docs/process/schemas/strategic-consumer-feedback.schema.json +40 -0
  144. package/template/docs/process/schemas/strategic-design-handoff-v3.schema.json +743 -0
  145. package/template/docs/process/schemas/strategic-design-handoff-v4.schema.json +712 -0
  146. package/template/docs/process/schemas/strategic-feedback-adjudication.schema.json +42 -0
  147. package/template/docs/process/schemas/strategic-handoff-domain-strategy-v3.schema.json +216 -0
  148. package/template/docs/process/schemas/strategic-handoff-import-receipt.schema.json +39 -0
  149. package/template/docs/process/schemas/strategic-handoff-stage-decision-package-v3.schema.json +148 -0
  150. package/template/docs/process/strategic-handoff-package.md +37 -4
  151. package/template/docs/process/templates/lifecycle-checkpoint-template.yaml +1 -0
  152. package/template/docs/process/templates/stage-checkpoint-template.md +1 -0
  153. package/template/docs/templates/examples/lifecycle-writing-examples.md +138 -0
  154. package/template/docs/templates/spec-template.md +16 -3
  155. package/template/docs/templates/vertical-slice-ticket-template.md +8 -4
  156. package/template/scripts/lib/approval-record.mjs +2 -1
  157. package/template/scripts/lib/backend-delivery.mjs +15 -3
  158. package/template/scripts/lib/frontend-delivery-boundary.mjs +20 -4
  159. package/template/scripts/lib/frontend-delivery.mjs +66 -2
  160. package/template/scripts/lib/profile-skill-sync.mjs +336 -0
  161. package/template/scripts/lib/strategic-feedback.mjs +33 -0
  162. package/template/scripts/lib/strategic-handoff-consumption.mjs +5 -0
  163. package/template/scripts/lib/strategic-handoff-io.mjs +1 -0
  164. package/template/scripts/lib/strategic-handoff.mjs +101 -10
  165. package/template/scripts/lib/user-decision-reuse.mjs +38 -0
  166. package/template/scripts/strategic-feedback +10 -0
  167. package/template/scripts/sync-profile-skills +43 -0
  168. package/template/scripts/verify-frontend-strategic-preflight +12 -0
  169. package/template/skills-lock.json +38 -20
  170. package/template.manifest.json +1 -0
  171. package/template.snapshot.json +6 -5
@@ -1,16 +1,41 @@
1
- schema_version: 2
1
+ schema_version: 3
2
2
  stage_decision_id: stage-decision.supplier-admission
3
- package_version: v2
3
+ package_version: v3
4
4
  status: approved
5
5
  problem_statement: 合规准入决定分散,采购无法稳定判断当前有效资格。
6
6
  target_users: [采购专员、合规专员]
7
7
  mvp: [提交供应商申请、合规准入决定、采购侧有效性校验]
8
8
  non_goals: [供应商结算、采购付款、通用工作流平台]
9
- success_criteria: [新采购订单 100% 校验当前有效准入决定]
10
- test_seams: [supplier-application-submit, admission-validity-check]
11
- confirmed_decisions: [ComplianceReview 拥有准入规则语义,ProcurementExecution 只消费决定]
12
- assumptions: [供应商已有唯一 subject_ref]
13
- constraints: [保留现有采购订单流程]
9
+ success_criteria:
10
+ - id: success-criterion.current-admission
11
+ statement: 新采购订单 100% 校验当前有效准入决定。
12
+ source_refs: [rule.current-admission-required]
13
+ evidence_refs: [evidence.discovery.compliance]
14
+ status: confirmed
15
+ test_seams:
16
+ - id: test-seam.admission-validity-check
17
+ statement: admission-validity-check
18
+ source_refs: [scenario.admission-expires, invariant.current-admission-required]
19
+ evidence_refs: [evidence.discovery.compliance]
20
+ status: confirmed
21
+ confirmed_decisions:
22
+ - id: decision.compliance-owns-admission-rules
23
+ statement: ComplianceReview 拥有准入规则语义,ProcurementExecution 只消费决定。
24
+ source_refs: [rule.current-admission-required]
25
+ evidence_refs: [evidence.domain-strategy-review.supplier]
26
+ status: confirmed
27
+ assumptions:
28
+ - id: assumption.unique-subject-ref
29
+ statement: 供应商已有唯一 subject_ref。
30
+ source_refs: [scenario.supplier-submits]
31
+ evidence_refs: [evidence.discovery.supplier]
32
+ status: confirmed
33
+ constraints:
34
+ - id: constraint.preserve-procurement-flow
35
+ statement: 保留现有采购订单流程。
36
+ source_refs: [scenario.admission-expires]
37
+ evidence_refs: [evidence.discovery.compliance]
38
+ status: confirmed
14
39
  unresolved_items:
15
40
  - item: 供应商历史资料迁移范围
16
41
  type: deferred
@@ -25,7 +50,7 @@ context_snapshot:
25
50
  term_refs: [Global/Supplier, ComplianceReview/AdmissionDecision]
26
51
  domain_strategy_ref:
27
52
  domain_strategy_id: domain-strategy.supplier-admission
28
- domain_version: v2
53
+ domain_version: v3
29
54
  digest: <domain-strategy-digest>
30
55
  status: approved
31
56
  persisted_ref: domain-strategy.yaml
@@ -38,17 +63,21 @@ impact_assessment:
38
63
  cross_repo: false
39
64
  high_risk: false
40
65
  downstream_mapping:
41
- - domain_change: admission-decision-validity
42
- consumer: spec-synthesis
66
+ - mapping_id: mapping.backend-admission-validity
67
+ source_refs: [rule.current-admission-required, invariant.current-admission-required]
68
+ consumer_capability: backend-technical-design
43
69
  propagation: direct
44
70
  reapproval_condition: 领域策略版本或有效性规则变化
45
- - domain_change: admission-decision-validity
46
- consumer: ticket-decomposition
71
+ evidence_refs: [evidence.domain-strategy-review.supplier]
72
+ - mapping_id: mapping.frontend-admission-validity
73
+ source_refs: [scenario.admission-expires]
74
+ consumer_capability: frontend-engineering-design
47
75
  propagation: transitive
48
76
  reapproval_condition: Spec 基线变更
77
+ evidence_refs: [evidence.domain-strategy-review.supplier]
49
78
  evidence_refs: [evidence.discovery.supplier, evidence.domain-strategy-review.supplier]
50
79
  approval:
51
80
  approval_ref: .agents/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml
52
81
  approver: role.product-manager
53
82
  persisted_ref: docs/.scratch/supplier/stage-decision/stage-decision-package-v1.yaml
54
- current_version: v2
83
+ current_version: v3
@@ -1,7 +1,19 @@
1
- schema_version: 2
1
+ schema_version: 3
2
2
  domain_strategy_id: domain-strategy.supplier-admission
3
- domain_version: v2
3
+ domain_version: v3
4
4
  status: approved
5
+ traceability_version: 1
6
+ rule_catalog:
7
+ - rule_id: rule.application-material-complete
8
+ statement: 申请材料必须完整
9
+ responsible_context: SupplierManagement
10
+ status: confirmed
11
+ evidence_refs: [evidence.discovery.supplier]
12
+ - rule_id: rule.current-admission-required
13
+ statement: 新采购订单必须引用当前有效的准入决定。
14
+ responsible_context: ComplianceReview
15
+ status: confirmed
16
+ evidence_refs: [evidence.discovery.compliance]
5
17
  contexts:
6
18
  - context_id: SupplierManagement
7
19
  name: 供应商管理
@@ -64,6 +76,10 @@ scenarios:
64
76
  preconditions: [供应商资料可编辑]
65
77
  commands: [SubmitSupplierApplication]
66
78
  rules: [申请材料必须完整]
79
+ rule_refs: [rule.application-material-complete]
80
+ critical: true
81
+ success_results: [完整申请进入合规审查]
82
+ evidence_refs: [evidence.discovery.supplier]
67
83
  events: [SupplierApplicationSubmitted]
68
84
  failure_results: [材料不完整时拒绝提交]
69
85
  responsible_context: SupplierManagement
@@ -73,7 +89,11 @@ scenarios:
73
89
  actor: compliance-officer
74
90
  preconditions: [批准决定存在]
75
91
  commands: [EvaluateAdmissionValidity]
76
- rules: [过期决定不得支持新采购订单]
92
+ rules: [新采购订单必须引用当前有效的准入决定。]
93
+ rule_refs: [rule.current-admission-required]
94
+ critical: true
95
+ success_results: [过期准入决定不能支持新采购订单]
96
+ evidence_refs: [evidence.discovery.compliance]
77
97
  events: [SupplierAdmissionExpired]
78
98
  failure_results: [采购下单时资格校验失败]
79
99
  responsible_context: ComplianceReview
@@ -94,6 +114,8 @@ invariants:
94
114
  responsible_context: ComplianceReview
95
115
  scenario_refs: [scenario.admission-expires]
96
116
  verification_method: 领域场景测试和事件版本校验
117
+ rule_ref: rule.current-admission-required
118
+ evidence_refs: [evidence.discovery.compliance]
97
119
  context_snapshot:
98
120
  context_ref: CONTEXT.md
99
121
  context_schema_version: 1
@@ -101,13 +123,23 @@ context_snapshot:
101
123
  referenced_terms_digest: <referenced-terms-digest>
102
124
  term_refs: [Global/Supplier, ComplianceReview/AdmissionDecision]
103
125
  downstream_mapping:
104
- - domain_change: admission-decision-validity
126
+ - mapping_id: mapping.backend-admission-validity
127
+ source_refs: [rule.current-admission-required, invariant.current-admission-required]
128
+ consumer_capability: backend-technical-design
105
129
  impacts: [spec, openapi, procurement-acceptance-tests]
106
130
  propagation: stale
107
131
  reapproval_condition: ComplianceReview 决定和有效期重新批准
132
+ evidence_refs: [evidence.discovery.compliance]
133
+ - mapping_id: mapping.frontend-admission-validity
134
+ source_refs: [scenario.admission-expires]
135
+ consumer_capability: frontend-engineering-design
136
+ impacts: [ui, frontend]
137
+ propagation: direct
138
+ reapproval_condition: 场景结果或视觉基线变化
139
+ evidence_refs: [evidence.discovery.compliance]
108
140
  evidence_refs: [evidence.discovery.supplier, evidence.discovery.compliance]
109
141
  approval:
110
142
  approval_ref: .agents/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml
111
143
  approver: role.product-manager
112
144
  persisted_ref: docs/.scratch/supplier/domain/domain-strategy-v1.yaml
113
- current_version: v2
145
+ current_version: v3
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { buildDecisionFixture } from "../../../../scripts/fixtures/user-decision/build-fixture.mjs";
3
2
  import { createHash } from "node:crypto";
4
3
  import { spawnSync } from "node:child_process";
5
4
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
@@ -14,6 +13,7 @@ const validator = join(testsRoot, "..", "scripts", "validate-domain-strategy.mjs
14
13
  const packageValidator = join(testsRoot, "..", "scripts", "validate-stage-decision-package.mjs");
15
14
  const contextValidator = join(projectRoot, "scripts", "verify-context-contract");
16
15
  const migrationTool = join(testsRoot, "..", "scripts", "migrate-context-references.mjs");
16
+ const v3MigrationTool = join(testsRoot, "..", "scripts", "migrate-contract-v3.mjs");
17
17
  const validTemplate = join(testsRoot, "fixtures", "valid-supplier-domain.yaml");
18
18
  const validPackageTemplate = join(testsRoot, "fixtures", "valid-stage-decision-package.yaml");
19
19
 
@@ -29,6 +29,58 @@ function digestYaml(source) {
29
29
  return `sha256:${createHash("sha256").update(JSON.stringify(canonical(document.toJS({ maxAliasCount: 0 })))).digest("hex")}`;
30
30
  }
31
31
 
32
+ function parseYaml(source) {
33
+ const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
34
+ if (document.errors.length) throw new Error(document.errors[0].message);
35
+ return document.toJS({ maxAliasCount: 0 });
36
+ }
37
+
38
+ function toV2Domain(source) {
39
+ const value = structuredClone(parseYaml(source));
40
+ value.schema_version = 2;
41
+ value.domain_version = "v2";
42
+ delete value.traceability_version;
43
+ delete value.rule_catalog;
44
+ for (const scenario of value.scenarios) {
45
+ delete scenario.rule_refs;
46
+ delete scenario.critical;
47
+ delete scenario.success_results;
48
+ delete scenario.evidence_refs;
49
+ }
50
+ for (const invariant of value.invariants) {
51
+ delete invariant.rule_ref;
52
+ delete invariant.evidence_refs;
53
+ }
54
+ value.downstream_mapping = [{
55
+ domain_change: "admission-decision-validity",
56
+ impacts: ["spec", "openapi", "procurement-acceptance-tests"],
57
+ propagation: "stale",
58
+ reapproval_condition: "ComplianceReview 决定和有效期重新批准"
59
+ }];
60
+ value.approval.current_version = "v2";
61
+ return value;
62
+ }
63
+
64
+ function toV2Stage(source, domainDigest) {
65
+ const value = structuredClone(parseYaml(source));
66
+ value.schema_version = 2;
67
+ value.package_version = "v2";
68
+ for (const field of ["success_criteria", "test_seams", "confirmed_decisions", "assumptions", "constraints"]) {
69
+ value[field] = value[field].map((item) => item.statement);
70
+ }
71
+ value.domain_strategy_ref.domain_version = "v2";
72
+ value.domain_strategy_ref.digest = domainDigest;
73
+ value.domain_strategy_ref.persisted_ref = "domain-strategy-v2.yaml";
74
+ value.downstream_mapping = [{
75
+ domain_change: "admission-decision-validity",
76
+ consumer: "spec-synthesis",
77
+ propagation: "direct",
78
+ reapproval_condition: "领域策略版本或有效性规则变化"
79
+ }];
80
+ value.approval.current_version = "v2";
81
+ return value;
82
+ }
83
+
32
84
  function run(command, file, contextRoot) {
33
85
  return spawnSync(process.execPath, [command, file, "--root", contextRoot], { cwd: projectRoot, encoding: "utf8" });
34
86
  }
@@ -56,34 +108,59 @@ context_schema_version: 1
56
108
  | 准入决定 | 合规审查形成的准入结论。 | AdmissionDecision | ComplianceReview | 避免:\`审批结果\` |
57
109
  `;
58
110
 
59
- const temporaryRoot = await mkdtemp(join(tmpdir(), "yss-stage-decision-v2-"));
111
+ const temporaryRoot = await mkdtemp(join(tmpdir(), "yss-stage-decision-v3-"));
60
112
  try {
61
113
  await writeFile(join(temporaryRoot, "CONTEXT.md"), contextSource);
62
114
  const contextResult = spawnSync(process.execPath, [contextValidator, "--root", temporaryRoot, "--allowed-context", "SupplierManagement", "--allowed-context", "ComplianceReview", "--allowed-context", "ProcurementExecution", "--term-ref", "Global/Supplier", "--term-ref", "ComplianceReview/AdmissionDecision", "--json"], { cwd: projectRoot, encoding: "utf8" });
63
115
  if (contextResult.status !== 0) throw new Error(`context fixture should pass: ${contextResult.stderr}`);
64
116
  const context = JSON.parse(contextResult.stdout);
65
117
 
66
- const domainApprovalRef = join(temporaryRoot, "domain-approval.json");
67
118
  const domainSource = (await readFile(validTemplate, "utf8"))
68
- .replace(".agents/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml", domainApprovalRef)
69
119
  .replace("<document-digest>", context.document_digest)
70
120
  .replace("<referenced-terms-digest>", context.referenced_terms_digest);
71
121
  const domainFile = join(temporaryRoot, "domain-strategy.yaml");
72
122
  await writeFile(domainFile, domainSource);
73
- const domainDecision = buildDecisionFixture(join(temporaryRoot, "domain-decision"), { boundary: "check.domain-strategy-approved", subjectRef: domainFile });
74
- const domainApproval = parseDocument(await readFile(join(testsRoot, "fixtures/domain-strategy-approval.yaml"), "utf8")).toJS();
75
- await writeFile(domainApprovalRef, JSON.stringify({ ...domainApproval, subject_ref: domainFile, approval_scope: domainDecision.requirement.scope, user_decision_ref: domainDecision.ref }));
76
123
  const pass = run(validator, domainFile, temporaryRoot);
77
- if (pass.status !== 0) throw new Error(`valid v2 fixture should pass: ${pass.stderr}`);
124
+ if (pass.status !== 0) throw new Error(`valid v3 fixture should pass: ${pass.stderr}`);
125
+
126
+ const v2Domain = toV2Domain(domainSource);
127
+ const v2DomainSource = JSON.stringify(v2Domain, null, 2);
128
+ const v2DomainFile = join(temporaryRoot, "domain-strategy-v2.yaml");
129
+ await writeFile(v2DomainFile, v2DomainSource);
130
+ const v2Pass = run(validator, v2DomainFile, temporaryRoot);
131
+ if (v2Pass.status !== 0) throw new Error(`read-only v2 fixture should pass: ${v2Pass.stderr}`);
132
+
133
+ const migratedDomainV3 = spawnSync(process.execPath, [v3MigrationTool, v2DomainFile, "--kind", "domain-strategy", "--root", temporaryRoot], { cwd: projectRoot, encoding: "utf8" });
134
+ if (migratedDomainV3.status !== 0) throw new Error(`v2 domain strategy should migrate: ${migratedDomainV3.stderr}`);
135
+ const migratedDomainV3Value = JSON.parse(migratedDomainV3.stdout);
136
+ if (migratedDomainV3Value.schema_version !== 3 || migratedDomainV3Value.status !== "draft" || migratedDomainV3Value.approval.approval_ref !== "migration-required") throw new Error("domain v2 -> v3 migration must reset approval and status");
137
+
138
+ const duplicateRule = join(temporaryRoot, "duplicate-rule.yaml");
139
+ const duplicateRuleValue = parseYaml(domainSource);
140
+ duplicateRuleValue.rule_catalog.push(structuredClone(duplicateRuleValue.rule_catalog[0]));
141
+ await writeFile(duplicateRule, JSON.stringify(duplicateRuleValue, null, 2));
142
+ expectBlocked(run(validator, duplicateRule, temporaryRoot), /rule_id.*重复|重复.*rule_id/, "duplicate v3 rule id");
143
+
144
+ const danglingRule = join(temporaryRoot, "dangling-rule.yaml");
145
+ const danglingRuleValue = parseYaml(domainSource);
146
+ danglingRuleValue.scenarios[0].rule_refs = ["rule.missing"];
147
+ await writeFile(danglingRule, JSON.stringify(danglingRuleValue, null, 2));
148
+ expectBlocked(run(validator, danglingRule, temporaryRoot), /rule_refs.*未声明|悬空/, "dangling v3 rule ref");
149
+
150
+ const missingEvidence = join(temporaryRoot, "missing-rule-evidence.yaml");
151
+ const missingEvidenceValue = parseYaml(domainSource);
152
+ missingEvidenceValue.rule_catalog[0].evidence_refs = [];
153
+ await writeFile(missingEvidence, JSON.stringify(missingEvidenceValue, null, 2));
154
+ expectBlocked(run(validator, missingEvidence, temporaryRoot), /evidence_refs/, "missing v3 evidence");
78
155
 
79
156
  const legacyFile = join(temporaryRoot, "legacy-domain.yaml");
80
- await writeFile(legacyFile, domainSource.replace("schema_version: 2", "schema_version: 1"));
157
+ await writeFile(legacyFile, JSON.stringify({ ...v2Domain, schema_version: 1 }, null, 2));
81
158
  expectBlocked(run(validator, legacyFile, temporaryRoot), /migration-required/, "legacy domain contract");
82
159
 
83
160
  const migratableLegacy = join(temporaryRoot, "migratable-legacy-domain.yaml");
84
- const migratableLegacySource = domainSource
85
- .replace("schema_version: 2", "schema_version: 1")
86
- .replace(/context_snapshot:\n[\s\S]*?\ndownstream_mapping:/, "terminology_refs: [CONTEXT.md#Supplier, contexts/ComplianceReview/CONTEXT.md#AdmissionDecision]\ndownstream_mapping:");
161
+ const migratableLegacyValue = { ...structuredClone(v2Domain), schema_version: 1, terminology_refs: ["CONTEXT.md#Supplier", "contexts/ComplianceReview/CONTEXT.md#AdmissionDecision"] };
162
+ delete migratableLegacyValue.context_snapshot;
163
+ const migratableLegacySource = JSON.stringify(migratableLegacyValue, null, 2);
87
164
  await writeFile(migratableLegacy, migratableLegacySource);
88
165
  const migrated = spawnSync(process.execPath, [migrationTool, migratableLegacy, "--root", temporaryRoot], { cwd: projectRoot, encoding: "utf8" });
89
166
  if (migrated.status !== 0) throw new Error(`migratable v1 contract should migrate: ${migrated.stderr}`);
@@ -91,7 +168,7 @@ try {
91
168
  if (migratedValue.schema_version !== 2 || migratedValue.terminology_refs !== undefined || migratedValue.context_snapshot.context_ref !== "CONTEXT.md" || migratedValue.context_snapshot.term_refs.join(",") !== "ComplianceReview/AdmissionDecision,Global/Supplier") throw new Error("migrated context snapshot is incomplete");
92
169
 
93
170
  const ambiguousLegacy = join(temporaryRoot, "ambiguous-legacy-domain.yaml");
94
- await writeFile(ambiguousLegacy, migratableLegacySource.replace("CONTEXT.md#Supplier, contexts/ComplianceReview/CONTEXT.md#AdmissionDecision", "contexts/ComplianceReview/CONTEXT.md"));
171
+ await writeFile(ambiguousLegacy, JSON.stringify({ ...migratableLegacyValue, terminology_refs: ["contexts/ComplianceReview/CONTEXT.md"] }, null, 2));
95
172
  const ambiguousMigration = spawnSync(process.execPath, [migrationTool, ambiguousLegacy, "--root", temporaryRoot], { cwd: projectRoot, encoding: "utf8" });
96
173
  expectBlocked(ambiguousMigration, /migration-required.*无法唯一定位|无法唯一定位.*migration-required/, "ambiguous legacy reference");
97
174
 
@@ -115,32 +192,48 @@ try {
115
192
  await writeFile(unknownContext, domainSource.replace("to_context: ComplianceReview", "to_context: UnknownContext"));
116
193
  expectBlocked(run(validator, unknownContext, temporaryRoot), /未引用已声明上下文|未在领域战略中登记/, "unknown context");
117
194
 
118
- const packageApprovalRef = join(temporaryRoot, "package-approval.json");
119
195
  const packageSource = (await readFile(validPackageTemplate, "utf8"))
120
- .replace(".agents/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml", packageApprovalRef)
121
196
  .replace("<document-digest>", context.document_digest)
122
197
  .replace("<referenced-terms-digest>", context.referenced_terms_digest)
123
198
  .replace("<domain-strategy-digest>", digestYaml(domainSource));
124
199
  const packageFile = join(temporaryRoot, "stage-decision.yaml");
125
200
  await writeFile(packageFile, packageSource);
126
- const packageDecision = buildDecisionFixture(join(temporaryRoot, "package-decision"), { boundary: "check.stage-decision-package-approved", subjectRef: packageFile });
127
- const packageApproval = parseDocument(await readFile(join(testsRoot, "fixtures/stage-decision-approval.yaml"), "utf8")).toJS();
128
- await writeFile(packageApprovalRef, JSON.stringify({ ...packageApproval, subject_ref: packageFile, approval_scope: packageDecision.requirement.scope, user_decision_ref: packageDecision.ref }));
129
201
  const packagePass = run(packageValidator, packageFile, temporaryRoot);
130
- if (packagePass.status !== 0) throw new Error(`valid v2 stage decision package should pass: ${packagePass.stderr}`);
202
+ if (packagePass.status !== 0) throw new Error(`valid v3 stage decision package should pass: ${packagePass.stderr}`);
203
+
204
+ const v2Stage = toV2Stage(packageSource, digestYaml(v2DomainSource));
205
+ const v2StageFile = join(temporaryRoot, "stage-decision-v2.yaml");
206
+ await writeFile(v2StageFile, JSON.stringify(v2Stage, null, 2));
207
+ const v2StagePass = run(packageValidator, v2StageFile, temporaryRoot);
208
+ if (v2StagePass.status !== 0) throw new Error(`read-only v2 stage decision package should pass: ${v2StagePass.stderr}`);
209
+
210
+ const migratedV3 = spawnSync(process.execPath, [v3MigrationTool, v2StageFile, "--kind", "stage-decision", "--root", temporaryRoot], { cwd: projectRoot, encoding: "utf8" });
211
+ if (migratedV3.status !== 0) throw new Error(`v2 stage decision should migrate: ${migratedV3.stderr}`);
212
+ const migratedV3Value = JSON.parse(migratedV3.stdout);
213
+ if (migratedV3Value.schema_version !== 3 || migratedV3Value.status !== "draft" || migratedV3Value.approval.approval_ref !== "migration-required") throw new Error("v2 -> v3 migration must reset approval and status");
214
+
215
+ const wrongSourceRef = join(temporaryRoot, "stage-decision-wrong-source-ref.yaml");
216
+ const wrongSourceRefValue = parseYaml(packageSource);
217
+ wrongSourceRefValue.success_criteria[0].source_refs = ["rule.missing"];
218
+ await writeFile(wrongSourceRef, JSON.stringify(wrongSourceRefValue, null, 2));
219
+ expectBlocked(run(packageValidator, wrongSourceRef, temporaryRoot), /source_refs.*未在领域战略中声明|悬空/, "stage decision dangling source ref");
131
220
 
132
221
  const packageLegacy = join(temporaryRoot, "legacy-stage-decision.yaml");
133
- await writeFile(packageLegacy, packageSource.replace("schema_version: 2", "schema_version: 1"));
222
+ await writeFile(packageLegacy, JSON.stringify({ ...v2Stage, schema_version: 1 }, null, 2));
134
223
  expectBlocked(run(packageValidator, packageLegacy, temporaryRoot), /migration-required/, "legacy stage decision contract");
135
224
 
136
225
  const packageBlocker = join(temporaryRoot, "stage-decision-blocker.yaml");
137
- await writeFile(packageBlocker, packageSource.replace("type: deferred", "type: blocker"));
226
+ const blockerValue = parseYaml(packageSource);
227
+ blockerValue.unresolved_items[0].type = "blocker";
228
+ await writeFile(packageBlocker, JSON.stringify(blockerValue, null, 2));
138
229
  expectBlocked(run(packageValidator, packageBlocker, temporaryRoot), /blocker/, "blocker package");
139
230
 
140
231
  const packageWrongArray = join(temporaryRoot, "stage-decision-wrong-array.yaml");
141
- await writeFile(packageWrongArray, packageSource.replace("target_users: [采购专员、合规专员]", "target_users: [42]"));
232
+ const wrongArrayValue = parseYaml(packageSource);
233
+ wrongArrayValue.target_users = [42];
234
+ await writeFile(packageWrongArray, JSON.stringify(wrongArrayValue, null, 2));
142
235
  expectBlocked(run(packageValidator, packageWrongArray, temporaryRoot), /target_users\[0\]/, "package non-string array item");
143
236
  } finally {
144
237
  await rm(temporaryRoot, { recursive: true, force: true });
145
238
  }
146
- process.stdout.write("业务边界与规则设计 v2 场景验证通过\n");
239
+ process.stdout.write("业务边界与规则设计 v2/v3 场景验证通过\n");
@@ -7,6 +7,12 @@ description: 在 YSS 技术分析中统一承接需求与战略输入,按已
7
7
 
8
8
  由 `yss-product-lifecycle` 调度,负责 `work-unit.technical-analysis` 的技术设计,不另起生命周期、不生成生产代码。生命周期维护批准和状态;`yss-implementation-contract-compiler` 消费批准且当前的设计,起草实现合同。
9
9
 
10
+ 文档输出时按 `lifecycle-document-output` 条件调用 `i-have-adhd`,读取 `docs/process/document-writing.md`;作用域仅限当前产物,派发时传递条件及引用。
11
+
12
+ ## 文档写作
13
+
14
+ 起草或修订技术设计解释正文前,读取 `docs/process/document-writing.md` 的共用写法及工程契约指引,并在分支派发中传递该引用;结构化合同保持原 schema 和验证要求。
15
+
10
16
  ## 输入与架构选择
11
17
 
12
18
  先读根 `CONTEXT.md`、已批准且当前的 Spec、业务规则、关键场景、适用的 API 契约、ADR 和工程约束。没有 API 或其他专项影响时记录有依据的不适用,不生成占位设计。
@@ -57,6 +57,7 @@ capability_contract:
57
57
  preserve_all_reasons: true
58
58
  deterministic_order: [recipe-declaration, dependency-topology, skill-id]
59
59
  capabilities:
60
+ - { id: writing.lifecycle-document, primary_skill: i-have-adhd, task_modes: [guidance] }
60
61
  - { id: architecture.technical-design, primary_skill: yss-technical-design, task_modes: [guidance, integration, review-input] }
61
62
  - { id: architecture.mvc-design, primary_skill: yss-mvc-design, architecture_family: layered-mvc, task_modes: [guidance, integration, review-input] }
62
63
  - { id: layer.mvc-service, primary_skill: yss-application, architecture_family: layered-mvc, task_modes: [guidance, integration, slice-implementation, troubleshooting, review-input] }
@@ -110,10 +111,24 @@ recipes:
110
111
  - { id: frontend.vue3-scaffold, capabilities: [scaffold.frontend-vue3] }
111
112
  - { id: backend.springboot3-migration, capabilities: [migration.springboot3, quality.java-code-style] }
112
113
  skill_dependencies:
114
+ prototype-review:
115
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
116
+ yss-implementation-contract-compiler:
117
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
118
+ yss-openapi-governance:
119
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
120
+ yss-stage-decision:
121
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
122
+ yss-research:
123
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
124
+ yss-product-lifecycle:
125
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
113
126
  code-review:
127
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
114
128
  - { skill: yss-repository, type: context-conditional, when: backend-persistence-impact }
115
129
  - { skill: yss-mybatis, type: context-conditional, when: backend-persistence-impact }
116
130
  yss-prototype-stage:
131
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
117
132
  - { skill: prototype-review, type: review-only }
118
133
  - { skill: yss-design-system, type: coordination-only }
119
134
  - { skill: yss-antdv-next-design, type: context-conditional, when: h2-vue-antdv-next-default }
@@ -129,6 +144,7 @@ skill_dependencies:
129
144
  - { skill: yss-tactical-design, type: context-conditional, when: tactical-domain }
130
145
  - { skill: lombok, type: context-conditional, when: pojo }
131
146
  yss-technical-design:
147
+ - { skill: i-have-adhd, type: context-conditional, when: lifecycle-document-output }
132
148
  - { skill: yss-tactical-design, type: coordination-only, when: domain-driven }
133
149
  - { skill: yss-mvc-design, type: coordination-only, when: layered-mvc }
134
150
  yss-mvc-design:
@@ -198,6 +214,11 @@ invocation_contract:
198
214
  invocation_mode: user
199
215
  primary_output: maintenance-operation
200
216
  overrides:
217
+ i-have-adhd:
218
+ invocation_mode: model
219
+ trigger_conditions: [lifecycle-document-output]
220
+ exclusion_conditions: [code-only-work, command-only-work, unrelated-conversation, user-disabled]
221
+ primary_output: document-writing-assistance
201
222
  yss-prototype-stage:
202
223
  invocation_mode: both
203
224
  trigger_conditions: [impact:prototype]
@@ -218,6 +239,7 @@ agent_runtime_roots:
218
239
  cursor: .cursor/skills
219
240
  pi: .pi/skills
220
241
  skills:
242
+ - { id: i-have-adhd, layer: core, maturity: supported, instance_default_discoverable: true, aliases: [], impacts: [writing] }
221
243
  - id: alibaba-java-code-style
222
244
  layer: specialist
223
245
  maturity: supported
@@ -9,18 +9,22 @@ owner: <负责人>
9
9
 
10
10
  > 生命周期身份:`stage.plan` / `artifact.plan-record`。按影响面填写,不制造未命中项的空产物。进入 Spec 的退出条件以 `docs/process/lifecycle-registry.yaml` 为准。
11
11
 
12
- ## 1. 输入与复用依据
12
+ 填写前读取[中文写作规范](../../process/document-writing.md)和 [Plan 对照](../../templates/examples/lifecycle-writing-examples.md#1-plan让业务问题和取舍可见)。先说明问题和本期取舍,假设与事实分开;以下各项按实际影响填写。
13
13
 
14
- | 资产 / 证据引用 | 版本 | 本次仍有效的依据 | 需要重新探索的部分 |
15
- |---|---|---|---|
14
+ ## 1. 用户、问题与目标
16
15
 
17
- ## 2. 用户、问题与目标
16
+ 用一段话说明谁在什么情境下遇到什么问题、本期建议改变什么;收益未经验证时保持候选语气。
18
17
 
19
18
  - 目标用户和关键业务故事:
20
19
  - 问题、为什么现在做:
21
20
  - 期望结果、成功标准及验证方式:
22
21
  - 约束、假设及事实证据:
23
22
 
23
+ ## 2. 输入与复用依据
24
+
25
+ | 资产 / 证据引用 | 版本 | 本次仍有效的依据 | 需要重新探索的部分 |
26
+ |---|---|---|---|
27
+
24
28
  ## 3. 战略资产引用
25
29
 
26
30
  | 权威资产 | 当前版本 / 引用 | 确认状态 / 未命中原因 |
@@ -0,0 +1,77 @@
1
+ # 研发文档中文写作规范
2
+
3
+ 起草或修订生命周期文档时,先读本规范的共用写法,再按阶段查阅第 3 节;发送进度与会签提示时读取第 4 节。按当前写入范围应用,正文、摘要和结构化信息应保持同一语义。
4
+
5
+ [Plan、Spec、Ticket 写作对照](../templates/examples/lifecycle-writing-examples.md)提供同一事实输入下的改写样例;示例不构成真实需求或批准。
6
+
7
+ ## 1. 适用范围与保留项
8
+
9
+ 适用于研究结论、Plan、Spec、产品设计说明、工程契约的解释正文、Ticket、审查、发布和复盘。聊天中的进度通知按第 4 节处理。
10
+
11
+ 本文件是生命周期文档的共用写作规范。生命周期身份、门禁、资产所有权、批准和状态由根 `AGENTS.md` 指定的权威资产决定;标准术语消费根 `CONTEXT.md`。本规范约束表达,不新增阶段、审批或业务规则。
12
+
13
+ 写作调整应保留这些内容的原意:主体、触发条件、规则、例外、量词、范围、非目标、数值及单位、证据引用、未决项、责任人、时点和依赖。稳定 ID、API 标识、schema、metadata、版本及批准记录按原合同保存。已经冻结的内容若需要改变行为,应回交资产所有者处理,不作为润色顺手修改。
14
+
15
+ ## 2. 共用写法
16
+
17
+ ### 先回答读者当前需要判断的问题
18
+
19
+ 开头说明业务问题、本次结论或交付行为。必要背景紧接其后,让读者知道结论为什么成立。正式模板要求的 metadata 和身份信息仍保留;表达顺序的建议不能自行覆盖校验器要求的结构。
20
+
21
+ 只在内容较长或需要导航时添加摘要。摘要引用正文,不另写一套范围和状态;维护时检查二者一致。
22
+
23
+ ### 用主体、条件和结果表达需求
24
+
25
+ 把“提升效率”“完善体验”等目标落实到具体场景:谁在什么情况下做什么,系统产生什么可观察结果。保留支持判断的业务动机,不把所有文字都拆成短句或编号。
26
+
27
+ 输入没有规则时,记录待确认问题;不要为了让句子具体而补出时限、阈值、错误码或默认行为。重要缺口交回拥有该决定的工作单元。非阻断细节按既有流程记录责任人、解决时点和接收方。
28
+
29
+ ### 让确定程度与证据一致
30
+
31
+ 事实给出处;推断说明依据;方案使用建议语气;假设写明如何验证。章节开头已明确整段是假设或建议时,无须每句重复标签。
32
+
33
+ 保留表达真实不确定性的“尚未确认”“可能”“取决于”。只有测试失败现象时,报告现象和下一项诊断,不编造原因;只有期望收益时,写目标和验证方法,不写成已实现收益。估算需有执行者、依据、范围和条件;无依据时不填精确工期。
34
+
35
+ ### 让每段承担一项用途
36
+
37
+ 一段解释一个问题、一项规则或一个取舍。顺序动作使用编号;同类规则、状态或选项比较使用表格;因果和取舍使用连贯段落。列表长度、段落数量和总字数按内容决定。
38
+
39
+ 删除只有态度、没有事实或决定的修饰句。技术术语、业务术语和必要限定词保持准确,不使用同义词轮换制造变化。评价文档看它是否明确、可信和可执行,不追求模拟人的口头习惯或降低 AI 检测分数。
40
+
41
+ ### 复用上游事实,交代本阶段新增内容
42
+
43
+ 引用上游规则的可定位位置和必要版本,本阶段写新增细化、适用范围和交接。直接决定本地验收的条件可以在场景中重述,并绑定同一规则 ID;以一致性核验控制漂移。
44
+
45
+ 不要用“详见相关文档”代替必要信息。引用不可读或版本不明时按现有合同处理。条件项只在流程允许时记录带原因的 `not-applicable`;命中的要求和必要异常场景应完整展示。
46
+
47
+ ## 3. 各阶段怎么写
48
+
49
+ | 阶段 | 正文优先回答 | 本阶段需要写具体的内容 |
50
+ |---|---|---|
51
+ | 研究 | 已知什么,证据支持到哪里? | 结论与来源、反证、限制分开;建议与事实区分 |
52
+ | Plan | 谁遇到什么问题,本期为什么这样取舍? | 业务故事、MVP / 非目标、优先级依据、成功标准的确认情况、关键未决项 |
53
+ | Spec | 什么条件下,系统必须怎样表现? | 规则与验收对应;按影响面覆盖成功、拒绝、边界、状态变化和恢复 |
54
+ | 产品设计 | 用户如何完成任务,失败后如何继续? | 入口、操作、反馈、状态和恢复路径;引用 Spec,保留设计待确认项 |
55
+ | 工程契约 | 实现必须遵守什么,哪些地方有取舍? | 精确协议与解释正文配合;标识、版本、范围及约束保持可核验 |
56
+ | Ticket | 本切片交付什么,如何证明完成? | 窄而完整的行为、依赖、验收、公共测试 seam、当前合同及验证证据 |
57
+ | 审查 | 哪个具体条件下存在什么问题? | 定位、触发条件、影响、依据与修复建议;推测和已复现问题分开 |
58
+ | 发布 / 复盘 | 验证了什么,还剩什么风险或决定? | 实际验证范围、未覆盖部分、发布决定或失误机制与改进行动 |
59
+
60
+ 这些指引帮助填写既有模板,不新增必填字段、阶段或门禁。Plan 不提前承诺详细 API 和工程实现;Spec 的例子不代替完整规则;Ticket 不重新设计已冻结行为。
61
+
62
+ ## 4. 进度与会签提示
63
+
64
+ 进度更新说明本轮有意义的变化、当前阻塞和接下来由谁处理。状态没有变化时,无须重述全部计划。已授权且 Agent 可以完成的动作继续执行,避免把操作转交用户。
65
+
66
+ 请求决定时展示当前版本、推荐方案及理由、实质选项和取舍、风险、批准范围与后续动作,遵守既有用户决定协议。可以突出当前最重要的问题,但所有影响决定的阻塞和选项都应可见。一次回复需要多个相互独立的决定时,分别说明各自影响。
67
+
68
+ 示例:“规则说明已补齐。成功标准仍缺统计口径,负责人需在 Plan 进入 Spec 前确认;当前材料尚不能支持流转。”这类表述需要实际资产支持,不能成为固定的完成话术。
69
+
70
+ ## 5. 起草与修订时的检查
71
+
72
+ 1. 确认文档读者、当前阶段、权威输入和允许改动的范围;区分从事实起草与对既有正文作等义改写。
73
+ 2. 起草时按本阶段的问题组织内容;修订时先列出必须保留的规则和约束,再调整文字。
74
+ 3. 对照输入检查有无新增承诺、规则丢失、范围扩大、责任转移或不确定性被抹去。发现源资产冲突时记录并回交,不自行选一个版本。
75
+ 4. 检查正文、摘要、表格和状态是否一致;验证适用的引用、结构和合同。自检结论不代替独立审查或批准。
76
+
77
+ 规则、例外、证据或状态变化属于实质差异,不能被“字数减少”抵消。不要只用禁用词扫描或模型给自己的分数判断效果。
@@ -6,7 +6,7 @@
6
6
 
7
7
  战略方维护业务规则、Spec、页面流程和视觉基线;后端维护 API 及后端交付;前端维护工程设计、页面和验收证据;统一管理方维护基线引用、跨仓切片与业务验收汇总。
8
8
 
9
- 前端消费需求可在上游设计时提前反馈。前端项目在战略和后端交付尚未齐备时,只能验包、诊断和回交缺口。两类输入通过接收核验后,可以准备前端工程设计、实现计划和 Slice Contract;合同获准前不得写代码。
9
+ 前端消费需求可在上游设计时提前反馈。Handoff v4 导入后的 Frontend Strategic Preflight 可在后端交付前完成战略输入、Context、视觉基线和源规则追踪核验,并允许起草前端工程设计与实现计划;它固定返回 `ready_for_agent: false`。仅当 Backend/API/Data 影响命中时,最终接收才等待后端交付;UI-only 路径使用有依据的 `backend-not-applicable`。Slice Contract 获准前均不得写代码。
10
10
 
11
11
  ## 后端导出与前端导入
12
12
 
@@ -28,11 +28,14 @@ scripts/backend-delivery import --bundle <directory-or-zip> --target-root <front
28
28
 
29
29
  ## 接收与启动
30
30
 
31
- 导入只产生 `frontend-acceptance-draft.json`,不会批准资产。接收方完成正式词汇对账并按 `schemas/frontend-delivery-acceptance.schema.json` 准备接收记录:
31
+ Handoff v4 先生成 `frontend-strategic-preflight-draft.json`;补齐正式 Context Reconciliation 后执行 `scripts/verify-frontend-strategic-preflight`。通过仅允许进入前端工程设计草案。
32
32
 
33
- - `backend_delivery` 绑定后端导入收据和包摘要。
33
+ 后端交付导入只新增匹配的 backend binding 并产生 `frontend-acceptance-draft.json`,不会覆盖已填写的前端预检/设计草案,也不会批准资产。最终接收方按当前 `schemas/frontend-delivery-acceptance.schema.json`(v2)准备记录;v1 仅服务历史 Handoff v3,继续要求真实后端交付:
34
+
35
+ - `strategic_preflight` 绑定当前预检文件及字节摘要。
36
+ - `backend_dependency.mode: required` 时,`backend_delivery` 绑定真实后端导入收据和包摘要;`not-applicable` 时必须与 Handoff v4 backend 路由的影响引用、原因和证据一致,且不得绑定后端收据。
34
37
  - `strategic_handoff` 绑定战略导入收据、包摘要、正式 `context_reconciliation_ref` 和全部源规则/关键场景的承接 rows。
35
- - `frontend_cases` 绑定业务规则/场景、成功或失败结果、已交付接口、Visual Baseline `case_id` 和可读取的用例说明。
38
+ - `frontend_cases` 绑定业务规则/场景、成功或失败结果、Visual Baseline `case_id` 和可读取的用例说明;有后端依赖时绑定已交付接口,`backend-not-applicable` 时 `operation_ids` 必须为空。
36
39
  - 已规划的承接使用 `mapped`,表示已映射用例,不声称代码已实现。当前交付范围必须 mapped 到当前切片;其他范围的 pending、conflict、deferred 或 not-applicable 沿用战略逐条承接的理由、证据和依赖阻断规则。
37
40
 
38
41
  完成接收核对后记录 `status: accepted` 并执行:
@@ -25,6 +25,10 @@
25
25
  "type": "string",
26
26
  "pattern": "^sha256:[0-9a-f]{64}$"
27
27
  },
28
+ "strategic_route_id": {
29
+ "type": "string",
30
+ "pattern": "^route\\.[a-z0-9][a-z0-9-]*$"
31
+ },
28
32
  "scope": {
29
33
  "type": "object",
30
34
  "additionalProperties": false,