create-yss-spec 3.3.0 → 3.3.1

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 (197) hide show
  1. package/package.json +3 -2
  2. package/src/command-runner.mjs +107 -0
  3. package/src/self-update.js +7 -4
  4. package/src/template/instance-runtime.js +1 -1
  5. package/template/.agents/skills/.strategic-design-skills-manifest.json +2 -2
  6. package/template/.agents/skills/competitive-intelligence/SKILL.md +4 -4
  7. package/template/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  8. package/template/.agents/skills/grill-with-docs/SKILL.md +1 -1
  9. package/template/.agents/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  10. package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  11. package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  12. package/template/.agents/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  13. package/template/.agents/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  14. package/template/.agents/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  15. package/template/.agents/skills/yss-product-lifecycle/SKILL.md +7 -4
  16. package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  17. package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  18. package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  19. package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  20. package/template/.agents/skills/yss-research/SKILL.md +1 -1
  21. package/template/.agents/skills/yss-stage-decision/SKILL.md +5 -3
  22. package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  23. package/template/.claude/skills/competitive-intelligence/SKILL.md +4 -4
  24. package/template/.claude/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  25. package/template/.claude/skills/grill-with-docs/SKILL.md +1 -1
  26. package/template/.claude/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  27. package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  28. package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  29. package/template/.claude/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  30. package/template/.claude/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  31. package/template/.claude/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  32. package/template/.claude/skills/yss-product-lifecycle/SKILL.md +7 -4
  33. package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  34. package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  35. package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  36. package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  37. package/template/.claude/skills/yss-research/SKILL.md +1 -1
  38. package/template/.claude/skills/yss-stage-decision/SKILL.md +5 -3
  39. package/template/.claude/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  40. package/template/.codex/skills/competitive-intelligence/SKILL.md +4 -4
  41. package/template/.codex/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  42. package/template/.codex/skills/grill-with-docs/SKILL.md +1 -1
  43. package/template/.codex/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  44. package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  45. package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  46. package/template/.codex/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  47. package/template/.codex/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  48. package/template/.codex/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  49. package/template/.codex/skills/yss-product-lifecycle/SKILL.md +7 -4
  50. package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  51. package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  52. package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  53. package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  54. package/template/.codex/skills/yss-research/SKILL.md +1 -1
  55. package/template/.codex/skills/yss-stage-decision/SKILL.md +5 -3
  56. package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  57. package/template/.cursor/skills/competitive-intelligence/SKILL.md +4 -4
  58. package/template/.cursor/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  59. package/template/.cursor/skills/grill-with-docs/SKILL.md +1 -1
  60. package/template/.cursor/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  61. package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  62. package/template/.cursor/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  63. package/template/.cursor/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  64. package/template/.cursor/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  65. package/template/.cursor/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  66. package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +7 -4
  67. package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  68. package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  69. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  70. package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  71. package/template/.cursor/skills/yss-research/SKILL.md +1 -1
  72. package/template/.cursor/skills/yss-stage-decision/SKILL.md +5 -3
  73. package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  74. package/template/.pi/skills/competitive-intelligence/SKILL.md +4 -4
  75. package/template/.pi/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  76. package/template/.pi/skills/grill-with-docs/SKILL.md +1 -1
  77. package/template/.pi/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  78. package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  79. package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  80. package/template/.pi/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  81. package/template/.pi/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  82. package/template/.pi/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  83. package/template/.pi/skills/yss-product-lifecycle/SKILL.md +7 -4
  84. package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  85. package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  86. package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  87. package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  88. package/template/.pi/skills/yss-research/SKILL.md +1 -1
  89. package/template/.pi/skills/yss-stage-decision/SKILL.md +5 -3
  90. package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  91. package/template/.qoder/skills/competitive-intelligence/SKILL.md +4 -4
  92. package/template/.qoder/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  93. package/template/.qoder/skills/grill-with-docs/SKILL.md +1 -1
  94. package/template/.qoder/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  95. package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  96. package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  97. package/template/.qoder/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  98. package/template/.qoder/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  99. package/template/.qoder/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  100. package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +7 -4
  101. package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  102. package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  103. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  104. package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  105. package/template/.qoder/skills/yss-research/SKILL.md +1 -1
  106. package/template/.qoder/skills/yss-stage-decision/SKILL.md +5 -3
  107. package/template/.qoder/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  108. package/template/.trae/skills/competitive-intelligence/SKILL.md +4 -4
  109. package/template/.trae/skills/domain-modeling/CONTEXT-FORMAT.md +1 -1
  110. package/template/.trae/skills/grill-with-docs/SKILL.md +1 -1
  111. package/template/.trae/skills/setup-matt-pocock-skills/issue-tracker-local.md +1 -1
  112. package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +7 -7
  113. package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +1 -1
  114. package/template/.trae/skills/yss-frontend-scaffold-generator/scripts/generate_scaffold.mjs +22 -8
  115. package/template/.trae/skills/yss-frontend-scaffold-generator/scripts/run_scaffold_verification.mjs +5 -6
  116. package/template/.trae/skills/yss-frontend-scaffold-generator/scripts/scaffold-generator.test.mjs +19 -1
  117. package/template/.trae/skills/yss-product-lifecycle/SKILL.md +7 -4
  118. package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +1 -1
  119. package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +3 -3
  120. package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +57 -6
  121. package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +11 -1
  122. package/template/.trae/skills/yss-research/SKILL.md +1 -1
  123. package/template/.trae/skills/yss-stage-decision/SKILL.md +5 -3
  124. package/template/.trae/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
  125. package/template/AGENTS.md +2 -2
  126. package/template/CONTEXT.md +3 -2
  127. package/template/README.md +3 -3
  128. package/template/docs/agents/digital-human-roles.md +1 -1
  129. package/template/docs/agents/digital-human-roles.yaml +11 -11
  130. package/template/docs/agents/issue-tracker.md +1 -1
  131. package/template/docs/agents/strategic-design-skills-integration.md +2 -0
  132. package/template/docs/architecture/README.md +1 -1
  133. package/template/docs/architecture/templates/business-architecture-template.md +1 -1
  134. package/template/docs/architecture/templates/functional-architecture-template.md +1 -1
  135. package/template/docs/design/README.md +1 -1
  136. package/template/docs/design/templates/interaction-spec-template.md +1 -1
  137. package/template/docs/design/templates/product-overview-design-template.md +1 -1
  138. package/template/docs/{discovery → plan}/IDEATION.md +5 -5
  139. package/template/docs/plan/README.md +9 -0
  140. package/template/docs/plan/entry-review.md +23 -0
  141. package/template/docs/plan/templates/plan-template.md +58 -0
  142. package/template/docs/process/harness-process-tailoring.md +1 -1
  143. package/template/docs/process/lifecycle-artifact-map.md +6 -6
  144. package/template/docs/process/lifecycle-registry-baseline.json +5 -1
  145. package/template/docs/process/lifecycle-registry.yaml +25 -20
  146. package/template/docs/process/plan-migration.md +13 -0
  147. package/template/docs/process/schemas/digital-human-task-package.schema.json +2 -0
  148. package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +3 -0
  149. package/template/docs/process/schemas/lifecycle-registry.schema.json +1 -1
  150. package/template/docs/process/template-engineering-overview.md +2 -2
  151. package/template/docs/process/template-verification-profiles.yaml +2 -0
  152. package/template/docs/process/templates/context-reconciliation-template.yaml +2 -2
  153. package/template/docs/process/templates/lifecycle-checkpoint-template.yaml +1 -1
  154. package/template/docs/requirements/README.md +2 -2
  155. package/template/docs/templates/local-parent-ticket-template.md +1 -1
  156. package/template/docs/templates/subagent-task-package-template.md +1 -1
  157. package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +1 -1
  158. package/template/scripts/cache-template-commit +2 -2
  159. package/template/scripts/fixtures/strategic-handoff/source-roles.json +7 -7
  160. package/template/scripts/fixtures/user-decision/plan-fixture.mjs +30 -0
  161. package/template/scripts/lib/backend-delivery.mjs +5 -2
  162. package/template/scripts/lib/command-runner.mjs +107 -0
  163. package/template/scripts/lib/context-reconciliation.mjs +34 -0
  164. package/template/scripts/lib/json-schema.mjs +42 -13
  165. package/template/scripts/lib/lifecycle-context-query.mjs +7 -3
  166. package/template/scripts/lib/lifecycle-transition.mjs +9 -3
  167. package/template/scripts/lib/plan-spec-entry.mjs +87 -0
  168. package/template/scripts/lib/scenario-checks.mjs +15 -12
  169. package/template/scripts/lib/skill-supply-chain.mjs +18 -2
  170. package/template/scripts/lib/strategic-handoff-io.mjs +5 -4
  171. package/template/scripts/lib/strategic-handoff.mjs +10 -9
  172. package/template/scripts/lib/task-package.mjs +2 -0
  173. package/template/scripts/lib/template-commit-cache.mjs +7 -5
  174. package/template/scripts/run-template-verification +9 -3
  175. package/template/scripts/sync-strategic-handoff-tools +9 -0
  176. package/template/scripts/verify-context-reconciliation +2 -48
  177. package/template/scripts/verify-context-reconciliation-scenarios +1 -1
  178. package/template/scripts/verify-lifecycle-checkpoint +2 -0
  179. package/template/scripts/verify-lifecycle-context-query-scenarios +28 -8
  180. package/template/scripts/verify-plan-spec-entry +11 -0
  181. package/template/scripts/verify-plan-spec-entry-scenarios +79 -0
  182. package/template/scripts/verify-script-performance-scenarios +56 -0
  183. package/template/scripts/verify-subagent-task-package-scenarios +9 -8
  184. package/template/scripts/verify-template-cache-scenarios +11 -1
  185. package/template/scripts/verify-user-decision-scenarios +4 -4
  186. package/template/skills-lock.json +17 -17
  187. package/template.manifest.json +2 -1
  188. package/template.snapshot.json +5 -5
  189. package/template/docs/discovery/README.md +0 -87
  190. package/template/docs/discovery/reports/.gitkeep +0 -0
  191. package/template/docs/discovery/reports/agent-governance-options.md +0 -71
  192. package/template/docs/discovery/reports/competitor-deep-dive/.gitkeep +0 -0
  193. package/template/docs/discovery/templates/discovery-template.md +0 -94
  194. /package/template/docs/{discovery → plan}/templates/competitive-analysis-template.md +0 -0
  195. /package/template/docs/{discovery → plan}/templates/competitive-matrix-template.md +0 -0
  196. /package/template/docs/{discovery → plan}/templates/market-analysis-template.md +0 -0
  197. /package/template/docs/{discovery → plan}/templates/user-pain-points-template.md +0 -0
@@ -48,6 +48,34 @@ modes:
48
48
  orchestrate: bounded_write
49
49
  resume: rebuild_then_bounded_write
50
50
 
51
+ execution_efficiency:
52
+ context_query:
53
+ strategy: combine-mode-stage-work-unit-and-required-includes
54
+ read_scope: current-work-unit-and-triggered-impacts
55
+ reuse: already-read-unchanged-sources-within-current-task
56
+ refresh_on: [source-changed, new-impact, evidence-conflict, resume, handoff]
57
+ verification:
58
+ scope: current-artifacts-and-triggered-contracts
59
+ timing: after-artifact-write-before-approval-or-transition
60
+ duplicate_check: reuse-only-within-same-boundary-and-unchanged-inputs
61
+ unchanged_inputs: [artifact-bytes, upstream-bytes, validator-and-schema, command-and-options, repository-root]
62
+ freshness_unknown: rerun
63
+ always_revalidate_on: [resume, handoff, implementation-entry, merge, release]
64
+ template_regression_suite: template-maintenance-or-explicit-regression-task
65
+ per_work_unit_context_reconciliation: required
66
+ skip_triggered_gates: forbidden
67
+ interaction:
68
+ questions: batch-independent-current-stage-questions
69
+ user_decision_policy_ref: docs/agents/digital-human-roles.yaml#user_decision_policy
70
+ decision_evidence_ref: references/user-decisions.md
71
+ dependent_future_approvals: forbidden
72
+ checkpoint_policy_ref: checkpoint_policy
73
+ timing_evidence:
74
+ location: existing-checkpoint-verification-evidence
75
+ script_fields: [command, duration_ms, exit_code]
76
+ distinguish: [script-execution, agent-orchestration, human-wait]
77
+ unmeasured_duration: unknown
78
+
51
79
  # 有效的 YSS 仓库必须先由生命周期编排器接管入口;Matt flow 只负责选择工作方式。
52
80
  entry_routing:
53
81
  manifest: yss-project.yaml
@@ -210,7 +238,7 @@ lifecycle_native_entries:
210
238
  implement: lifecycle-validate-and-accept
211
239
 
212
240
  work_unit_routes:
213
- work-unit.discovery-opportunity:
241
+ work-unit.plan-opportunity:
214
242
  native: {source: yss-product-lifecycle, skill: yss-product-lifecycle, invocation_mode: model-invoked}
215
243
  primary_skill: yss-product-lifecycle
216
244
  supporting_skills: [competitive-intelligence, yss-research]
@@ -218,7 +246,7 @@ work_unit_routes:
218
246
  route_by: {market_or_competitor_fact: competitive-intelligence, technical_or_standard_fact: yss-research:technical-evidence, strategy_fact: yss-research:strategy-evidence, no_external_fact: yss-product-lifecycle}
219
247
  applies_when: opportunity_or_external_fact_requires_validation
220
248
  not_applicable_reason: no_external_fact
221
- work-unit.discovery-requirements:
249
+ work-unit.plan-requirements:
222
250
  native: {source: yss-product-lifecycle, skill: yss-product-lifecycle, invocation_mode: model-invoked}
223
251
  primary_skill: yss-product-lifecycle
224
252
  supporting_skills: [grilling, domain-modeling]
@@ -241,7 +269,7 @@ work_unit_routes:
241
269
  skills: [yss-stage-decision, domain-modeling, yss-research]
242
270
  research_contract: {profile: strategy-evidence, mode_before_gate: evidence-audited, artifact_owner: yss-research, downstream_owner: yss-stage-decision}
243
271
  human_gate: stage-decision-package-approved
244
- applies_when: discovery_to_spec_requires_stable_decision_package
272
+ applies_when: plan_to_spec_requires_stable_decision_package
245
273
  not_applicable_reason: existing_approved_stage_decision_current
246
274
  work-unit.spec-synthesis:
247
275
  native: {source: yss-product-lifecycle, skill: yss-product-lifecycle, invocation_mode: model-invoked}
@@ -484,6 +512,10 @@ transition_graph:
484
512
  work-unit.intensity-aware-verification: [work-unit.intensity-aware-review]
485
513
  work-unit.intensity-aware-review: [work-unit.release-and-rollback]
486
514
  work-unit.release-and-rollback: []
515
+ work-unit.plan-opportunity: [work-unit.plan-requirements, work-unit.domain-strategy-design, work-unit.stage-decision, work-unit.spec-synthesis]
516
+ work-unit.plan-requirements: [work-unit.domain-strategy-design, work-unit.stage-decision, work-unit.spec-synthesis]
517
+ work-unit.domain-strategy-design: [work-unit.stage-decision, work-unit.spec-synthesis]
518
+ work-unit.stage-decision: [work-unit.spec-synthesis]
487
519
  work-unit.spec-synthesis: [work-unit.prototype-design, work-unit.technical-analysis, work-unit.implementation-repository-preparation]
488
520
  work-unit.prototype-design: [work-unit.technical-analysis, work-unit.implementation-repository-preparation]
489
521
  work-unit.technical-analysis: [work-unit.implementation-repository-preparation]
@@ -495,6 +527,25 @@ transition_graph:
495
527
  - {from: work-unit.technical-analysis, to: work-unit.slice-implementation}
496
528
  - {from: work-unit.technical-analysis, to: work-unit.ticket-decomposition}
497
529
 
530
+ planning:
531
+ entry_validator: scripts/verify-plan-spec-entry
532
+ review_contract: docs/plan/entry-review.md
533
+ check_policy: docs/process/lifecycle-registry.yaml
534
+ default_check_status: pending
535
+ formal_spec_draft_requires_passed_entry: true
536
+ stage: stage.plan
537
+ record: artifact.plan-record
538
+ template: docs/plan/templates/plan-template.md
539
+ exit_policy: docs/process/lifecycle-registry.yaml
540
+ migration_policy: docs/process/plan-migration.md
541
+ critical_open_questions: block-before-spec
542
+ deferred_details_require: [noncritical_reason, owner, resolution_point, downstream_recipient]
543
+ reuse_requires: [source_ref, current_version, applicable_scope, reason]
544
+ downstream: work-unit.spec-synthesis
545
+ implementation_authorized: false
546
+ frontier_scope: current-plan-decisions
547
+ deferred_details: excluded-from-frontier-only-after-user-confirms-deferral
548
+
498
549
  grill_exit:
499
550
  required: [frontier_empty, facts_resolved_or_routed, decisions_confirmed, shared_understanding_confirmed, no_unresolved_runnable_blocker]
500
551
  facts_resolved_or_routed:
@@ -502,7 +553,7 @@ grill_exit:
502
553
  runnable_question: handoff-prototype-handoff
503
554
  external_decision: external-input-required
504
555
  user_confirmation_required: true
505
- output: discovery-evidence
556
+ output: plan-evidence
506
557
 
507
558
  ticket_role_transition:
508
559
  yss_active:
@@ -761,7 +812,7 @@ tracker:
761
812
  local_markdown:
762
813
  root: docs/.scratch
763
814
  legacy_roots: [.scratch, docs/requirements/tickets]
764
- feature_layout: [map.md, discovery, spec.md, spec-delta, parent-ticket.md, design, api, architecture, gates, verification, issues]
815
+ feature_layout: [map.md, plan, spec.md, spec-delta, parent-ticket.md, design, api, architecture, gates, verification, issues]
765
816
  primary_sync: local
766
817
  remote_ticket_required: false
767
818
  remote_mirror: optional
@@ -817,7 +868,7 @@ wayfinder_mode:
817
868
  - multi-session-or-multi-agent-work
818
869
  - unclear-decision-frontier
819
870
  - cross-domain-dependency-map-needed
820
- lifecycle_position: discovery-to-spec-planning
871
+ lifecycle_position: plan-to-spec-planning
821
872
  completion_route: wayfinder -> handoff -> to-spec
822
873
  does_not_replace: [lifecycle-gates, spec-baseline, ticket-formalization]
823
874
  forbidden_state_mutations: [ready-for-agent, gate-approval, ticket-role]
@@ -13,6 +13,16 @@
13
13
 
14
14
  连续阶段自动推进时累积 Ticket 同步和 Git 判断证据,在人工暂停、handoff、进入实现、合并或发布边界集中 checkpoint。发生阻塞、责任人变化或资产需要单独批准时立即落 checkpoint,不因合并记录而丢失阶段因果关系。
15
15
 
16
+ ## 执行成本
17
+
18
+ 执行策略以 `orchestration-contract.yaml.execution_efficiency` 为准,通过同一次 `query-lifecycle-context` 查询取得。Plan → Spec → Ticket 的耗时应分清脚本执行、Agent 读取与编排、人工等待;没有计时记录时不把总时长归因于摘要计算。
19
+
20
+ 同一工作单元把 mode、stage、work-unit 和必要 include 放进一次查询。查询已给出的内容不再整份读取;已读资料在当前任务内未变化时复用,变化、新影响或恢复时重新加载。只问当前阶段尚缺且会影响判断的问题,独立问题可合并;依赖尚未形成资产的后续批准仍按用户决定协议逐边界取得。
21
+
22
+ 资产写入稳定后、批准或流转前执行当前合同要求的验证。同一边界内,只有输入字节、上游、验证器/schema、参数和仓库根均已确认未变化且实际结果可读时,才引用已执行结果;不确定就重跑。每个工作单元仍生成并校验自己的 context reconciliation;恢复、交接、实现、合并和发布边界重新执行适用验证。`verify-*-scenarios` 与模板全量核验用于模板维护或明确的回归任务,不因产品阶段切换而重复执行;实例合同显式要求的检查仍须执行。
23
+
24
+ 脚本命令、实际退出码和 duration_ms 记入已有 checkpoint 的验证证据;Agent 编排和人工等待仅在有计时来源时记录,否则标为 unknown。无需为耗时再建一套阶段产物。
25
+
16
26
  ## 阶段边界
17
27
 
18
28
  Matt phase boundary 是工作阶段之间的上下文决策,不是新的生命周期状态。按以下顺序判断,第一项适用即停止判断:
@@ -59,7 +69,7 @@ tracker 选择和冲突按 `docs/agents/issue-tracker.md` 裁决:已持久化
59
69
 
60
70
  - `work-unit.technical-analysis` 由 `yss-technical-design` 组织后端技术设计,先按项目确认架构,再调用 DDD `yss-tactical-design` 或传统 MVC `yss-mvc-design`。状态、规则、一致性、持久化影响本身不意味着选择 DDD。无后端技术设计影响记录带原因的 `not-applicable`,其他 API / 前端技术分析继续各自路由。新合同使用 `artifact.technical-design`,通过 `evidence.technical-design-review` 回交现有架构审查;旧 DDD 稳定 ID 只读兼容。批准仍由生命周期维护,编译器消费批准且当前的设计起草实现合同;`stale`、`drift` 或 `new_impacts` 时不得继续 Ticket 正式化。
61
71
 
62
- - `work-unit.discovery-requirements` 实际调用 `grilling` 和 `domain-modeling`;`work-unit.discovery-opportunity` 按事实类型路由 `competitive-intelligence` 或 `yss-research`。`yss-research:quick` 只用于探索;外部证据进入领域战略、阶段决策或其他生命周期批准输入前必须升级为 `evidence-audited`。生命周期原生工作单元默认负责 Spec、Ticket 和实现资产;`to-spec`、`to-tickets`、`implement` 仅保留为显式兼容入口,结果必须回交生命周期验收。
72
+ - `work-unit.plan-requirements` 实际调用 `grilling` 和 `domain-modeling`;`work-unit.plan-opportunity` 按事实类型路由 `competitive-intelligence` 或 `yss-research`。`yss-research:quick` 只用于探索;外部证据进入领域战略、阶段决策或其他生命周期批准输入前必须升级为 `evidence-audited`。生命周期原生工作单元默认负责 Spec、Ticket 和实现资产;`to-spec`、`to-tickets`、`implement` 仅保留为显式兼容入口,结果必须回交生命周期验收。
63
73
  - 原生 `work-unit.ticket-decomposition` 只能在 OpenAPI Freeze 或无 API 影响记录后创建垂直切片,初始 Ticket 状态统一为 `ready-for-human`;生命周期复算完整公式后才能提升 `ready-for-agent`。该工作单元必须返回 `ticket_decomposition_result_ref` 和垂直切片引用,并作为实现的必经前置证据。
64
74
  - 原生 `work-unit.slice-implementation` 必须在生命周期批准并持久化 Slice Implementation Contract 和 Build Architecture Checklist 后执行;用户显式 `implement` 仍走兼容入口,不得绕过生命周期。
65
75
  - `Workflow Execution Result.next_route` 必须通过生命周期转换校验;Spec、原型和技术分析不得直接跳转到 Ticket 正式化或实现,必须先完成 `work-unit.implementation-repository-preparation`,再进入 `work-unit.ticket-decomposition`。
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yss-research
3
- description: Research technical or product-strategy questions with traceable evidence before YSS Discovery, Spec, domain-strategy, API, architecture, or implementation decisions. Use for current facts, standards, third-party APIs, business constraints, user problems, domain-boundary evidence, or when the deprecated `research` alias is invoked.
3
+ description: Research technical or product-strategy questions with traceable evidence before YSS Plan, Spec, domain-strategy, API, architecture, or implementation decisions. Use for current facts, standards, third-party APIs, business constraints, user problems, domain-boundary evidence, or when the deprecated `research` alias is invoked.
4
4
  ---
5
5
 
6
6
  # YSS Research
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: yss-stage-decision
3
- description: 编排 Discovery 到 Spec 入口的方案决策与业务边界、协作和规则设计;当需求、业务责任区、统一业务词汇或下游影响尚未稳定时使用。
3
+ description: 编排 Plan 到 Spec 入口的方案决策与业务边界、协作和规则设计;当需求、业务责任区、统一业务词汇或下游影响尚未稳定时使用。
4
4
  ---
5
5
 
6
6
  # YSS Stage Decision
@@ -9,14 +9,16 @@ description: 编排 Discovery 到 Spec 入口的方案决策与业务边界、
9
9
 
10
10
  ## 适用边界
11
11
 
12
- - 适用于 `project-instance` 的 Discovery → Spec 入口。
12
+ - 适用于 `project-instance` 的 Plan → Spec 入口。
13
13
  - `template-source` 只维护本技能、Schema、验证器和合成 Fixture,不生成具体产品领域资产。
14
14
  - 业务边界与协作工作单元只回答:有哪些业务板块、每个业务责任区负责什么、不同责任区如何交接、使用哪些统一业务词汇、发生哪些业务事实、有哪些待确认的关键业务对象和不可违反的业务规则。
15
15
  - Entity、Aggregate、Repository、Java 类、数据库表和 OpenAPI Freeze 留给下游工作单元。
16
16
 
17
17
  ## 执行顺序
18
18
 
19
- 1. 读取 `yss-project.yaml`、`CONTEXT.md`、既有 Discovery/Spec、ADR 和父 Ticket/checkpoint。
19
+ Plan 的目标与退出条件由 `docs/process/lifecycle-registry.yaml` 持有;从 `docs/plan/templates/plan-template.md` 汇总输入。旧资产按 `docs/process/plan-migration.md` 重新整理并核查,关键未决项不得延期到 Spec,非关键项记录责任人、解决时点与接收方。
20
+
21
+ 1. 读取 `yss-project.yaml`、`CONTEXT.md`、既有 Plan/Spec、ADR 和父 Ticket/checkpoint。
20
22
  2. 分离事实、决策、假设、约束和未决项;技术事实走 `yss-research` 的 `technical-evidence`,领域边界、业务规则、MVP、非目标、成功标准或阶段推进依据等决策证据走 `strategy-evidence`,市场/竞品事实走 `competitive-intelligence`。
21
23
  3. 从业务故事、已发生的事实、规则、责任人和失败路径识别业务板块与业务责任区,不从数据库表或调用链直接反推边界。
22
24
  4. 为每个业务责任区建立统一业务词汇;对跨责任区协作记录规则提供方、规则使用方、业务决策权、信息传递方向和口径转换负责人。
@@ -1,6 +1,6 @@
1
1
  # 方案决策包合同
2
2
 
3
- 内部对象 `stage_decision_package` 是 Discovery、需求/产品/商务决策与业务边界和规则设计之间的冻结入口。它记录“做什么、为什么做、范围是什么、哪些仍未决”,不复制业务边界与规则事实。
3
+ 内部对象 `stage_decision_package` 是 Plan、需求/产品/商务决策与业务边界和规则设计之间的冻结入口。它记录“做什么、为什么做、范围是什么、哪些仍未决”,不复制业务边界与规则事实。
4
4
 
5
5
  ## 必须包含
6
6
 
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: competitive-intelligence
3
- description: Use when researching competitors, market positioning, pricing, feature gaps, customer sentiment, or category trends before Discovery, Spec, product strategy, or roadmap decisions.
3
+ description: Use when researching competitors, market positioning, pricing, feature gaps, customer sentiment, or category trends before Plan, Spec, product strategy, or roadmap decisions.
4
4
  ---
5
5
 
6
6
  # Competitive Intelligence
7
7
 
8
8
  Source requested for this project: `anthropics/knowledge-work-plugins`, `sales/skills/competitive-intelligence`.
9
9
 
10
- Use this skill when competitive or market facts are needed to shape product Discovery, Spec scope, positioning, differentiation, pricing assumptions, or roadmap tradeoffs.
10
+ Use this skill when competitive or market facts are needed to shape product Plan, Spec scope, positioning, differentiation, pricing assumptions, or roadmap tradeoffs.
11
11
 
12
12
  ## Core Rules
13
13
 
@@ -45,8 +45,8 @@ Use this skill when competitive or market facts are needed to shape product Disc
45
45
  - Risks if we copy the competitor too closely.
46
46
  - Product opportunities for Spec or roadmap.
47
47
  5. Hand off to lifecycle assets:
48
- - Update Discovery findings in `docs/.scratch/<feature>/discovery/`.
49
- - Create or update a competitor matrix in `docs/.scratch/<feature>/discovery/reports/`.
48
+ - Update Plan findings in `docs/.scratch/<feature>/plan/`.
49
+ - Create or update a competitor matrix in `docs/.scratch/<feature>/plan/reports/`.
50
50
  - Feed stable user, pain, MVP, non-goal, and success criteria into `grill-with-docs` and `to-spec`.
51
51
  - Record uncertain claims as assumptions, not requirements.
52
52
 
@@ -45,7 +45,7 @@ context_schema_version: 1
45
45
 
46
46
  ## 内容边界
47
47
 
48
- - 只写已经确认、稳定且未来资产需要复用的业务语言。候选、猜测和未决术语保留在 Discovery、业务边界与规则设计或 `context_delta`。
48
+ - 只写已经确认、稳定且未来资产需要复用的业务语言。候选、猜测和未决术语保留在 Plan、业务边界与规则设计或 `context_delta`。
49
49
  - 定义保持一到两句,说明概念是什么;不要写类全名、表名、接口路径、实现步骤或计划。
50
50
  - 禁用别名使用 `避免:别名一、别名二`;需要补充说明时追加 `;备注:...`。
51
51
  - 术语稳定时立即回写。工作单元完成、门禁批准或阶段转换前仍须执行 context reconciliation。
@@ -11,7 +11,7 @@ Call the Skill tool with `grilling`, then call it separately with `domain-modeli
11
11
  1. Read `yss-project.yaml` and the root glossary before the first round, then run `scripts/verify-context-contract --root . --json`. Missing or lowercase root files, nested `CONTEXT.md`, `CONTEXT-MAP.md`, unsupported schema, absolute/cross-repository references, and Markdown pseudo-anchors are `blocked` or `migration-required`.
12
12
  2. Separate discoverable facts from user decisions; investigate facts instead of asking the user.
13
13
  3. Ask the entire current decision frontier, with a recommendation for every question, then wait.
14
- 4. Keep candidate or disputed terms in the Discovery decision frontier. Only after confirmation, use `domain-modeling` to record true stable glossary entries in the repository root's single, case-sensitive `CONTEXT.md`; business rows use the five-column format and `<ContextId>/<EnglishIdentifier>` identity. Non-`Global` Context IDs must come from the approved business responsibility areas in the business-boundary asset.
14
+ 4. Keep candidate or disputed terms in the Plan decision frontier. Only after confirmation, use `domain-modeling` to record true stable glossary entries in the repository root's single, case-sensitive `CONTEXT.md`; business rows use the five-column format and `<ContextId>/<EnglishIdentifier>` identity. Non-`Global` Context IDs must come from the approved business responsibility areas in the business-boundary asset.
15
15
  5. Create an ADR only when the decision is hard to reverse, surprising without context, and a real trade-off.
16
16
  6. Persist factual research/validation records in the repository's existing review or research convention.
17
17
  7. For `project-instance`, before requesting approval or returning a next work unit, generate and validate `context_reconciliation` with a readable ref, `document_digest`, `referenced_terms_digest`, and `term_refs`. Unresolved candidates, scope conflicts, aliases, or digest drift are `blocked`; reconciliation does not create another gate. For `template-source`, do not add fictional business terms and return a reasoned `not-applicable` after validating the template contract.
@@ -31,7 +31,7 @@ When `yss-product-lifecycle` is active, the same `docs/.scratch/<feature-slug>/`
31
31
  ```text
32
32
  docs/.scratch/<feature-slug>/
33
33
  ├── map.md
34
- ├── discovery/
34
+ ├── plan/
35
35
  ├── spec.md
36
36
  ├── spec-delta/
37
37
  ├── parent-ticket.md
@@ -3,7 +3,7 @@
3
3
  import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import process from "node:process";
6
- import { spawn } from "node:child_process";
6
+ import { runCommand } from "../../../../scripts/lib/command-runner.mjs";
7
7
  import { assertArchitectureAgreement } from "../../../../scripts/lib/backend-architecture.mjs";
8
8
  import { assertLocalDatabaseProfile, scaffoldArchitectureIdentity } from "../../../../scripts/lib/scaffold-local-database.mjs";
9
9
 
@@ -37,7 +37,7 @@ function classifyFailure(phase, outcome) {
37
37
  if (phase === "package") return "packaging";
38
38
  return "maven-execution";
39
39
  }
40
- function parseArgs(argv) { const result = {}; for (let index = 0; index < argv.length; index += 1) { let token = argv[index]; if (token === "--help" || token === "-h") { result.help = true; continue; } const equals = token.indexOf("="); let value; if (equals !== -1) { value = token.slice(equals + 1); token = token.slice(0, equals); } if (!["--project-root", "--evidence-dir"].includes(token)) throw new Error(`不支持的参数: ${token}`); if (value === undefined) value = argv[++index]; if (!value || value.startsWith("--")) throw new Error(`参数 ${token} 缺少值`); result[token === "--project-root" ? "projectRoot" : "evidenceDir"] = path.resolve(value); } if (result.help) return result; if (!result.projectRoot || !result.evidenceDir) throw new Error("必须提供 --project-root 和 --evidence-dir"); return result; }
40
+ function parseArgs(argv) { const result = {}; for (let index = 0; index < argv.length; index += 1) { let token = argv[index]; if (token === "--help" || token === "-h") { result.help = true; continue; } const equals = token.indexOf("="); let value; if (equals !== -1) { value = token.slice(equals + 1); token = token.slice(0, equals); } if (!["--project-root", "--evidence-dir", "--timeout-ms"].includes(token)) throw new Error(`不支持的参数: ${token}`); if (value === undefined) value = argv[++index]; if (!value || value.startsWith("--")) throw new Error(`参数 ${token} 缺少值`); if (token === "--timeout-ms") result.timeoutMs = Number(value); else result[token === "--project-root" ? "projectRoot" : "evidenceDir"] = path.resolve(value); } if (result.help) return result; if (!result.projectRoot || !result.evidenceDir) throw new Error("必须提供 --project-root 和 --evidence-dir"); return result; }
41
41
  function validateManifest(manifest) {
42
42
  if (![2, 3, 4].includes(manifest.schema_version)) throw new Error(`unsupported: scaffold Manifest schema_version=${manifest.schema_version};只读兼容 v2,并验证当前 v3/v4`);
43
43
  const required = ["schema_version", "contract_id", "contract_version", "scaffold_request_id", "contract_digest", "profiles", "ownership", "readiness", "generation_policy", "completion_level", "approval_ref", "approver", "lifecycle_approval_ref", "compiler_draft_ref", "persisted_ref", "contract_file_ref", "current_version", "allowed_write_paths", "expected_evidence_files", "verification_commands", "generation_mode"];
@@ -57,8 +57,7 @@ function validateManifest(manifest) {
57
57
  if (manifest.current_version !== manifest.contract_version) throw new Error("脚手架生成元数据清单不是当前合同版本");
58
58
  if (JSON.stringify(manifest.verification_commands) !== JSON.stringify(COMMANDS)) throw new Error("脚手架生成元数据清单验证命令不符合固定合同");
59
59
  }
60
- function execute(wrapper, phase, cwd, environment) { return new Promise((resolve) => { const child = spawn(wrapper, [phase], { cwd, env: environment, stdio: ["ignore", "pipe", "pipe"] }); let stdout = "", stderr = ""; child.stdout.on("data", (chunk) => { stdout += chunk; }); child.stderr.on("data", (chunk) => { stderr += chunk; }); child.on("error", (error) => resolve({ exitCode: 127, stdout: "", stderr: String(error) })); child.on("close", (code) => resolve({ exitCode: code ?? 1, stdout, stderr })); }); }
61
- export async function run(projectRoot, evidenceDir, environment = process.env) {
60
+ export async function run(projectRoot, evidenceDir, environment = process.env, { timeoutMs = 0, signal } = {}) {
62
61
  const wrapper = path.join(projectRoot, "mvnw"), manifestPath = path.join(projectRoot, ".yss", "scaffold-generation.json");
63
62
  if (!await isFile(wrapper)) throw new Error(`项目根目录缺少 Maven wrapper: ${wrapper}`);
64
63
  if (!await isFile(manifestPath)) throw new Error(`项目根目录缺少脚手架生成元数据清单: ${manifestPath}`);
@@ -91,7 +90,8 @@ export async function run(projectRoot, evidenceDir, environment = process.env) {
91
90
  const stderrPath = path.join(evidenceDir, `mvnw-${phase}.stderr.log`);
92
91
  const startedAt = isoNow();
93
92
  const started = process.hrtime.bigint();
94
- const outcome = await execute(wrapper, phase, projectRoot, environment);
93
+ const execution = await runCommand(wrapper, [phase], { cwd: projectRoot, env: environment, timeoutMs, signal, stdoutFile: stdoutPath, stderrFile: stderrPath, secrets: [environment.MAVEN_REPO_USERNAME, environment.MAVEN_REPO_PASSWORD], progress: true });
94
+ const outcome = { ...execution, exitCode: execution.status };
95
95
  const durationMs = Number(process.hrtime.bigint() - started) / 1e6;
96
96
  await writeText(stdoutPath, redactSecrets(outcome.stdout, environment));
97
97
  await writeText(stderrPath, redactSecrets(outcome.stderr, environment));
@@ -99,7 +99,7 @@ export async function run(projectRoot, evidenceDir, environment = process.env) {
99
99
  command: `./mvnw ${phase}`,
100
100
  phase,
101
101
  exit_code: outcome.exitCode,
102
- failure_category: classifyFailure(phase, outcome),
102
+ failure_category: outcome.termination || classifyFailure(phase, outcome),
103
103
  duration_ms: Number(durationMs.toFixed(3)),
104
104
  started_at: startedAt,
105
105
  executed_at: isoNow(),
@@ -120,5 +120,5 @@ export async function run(projectRoot, evidenceDir, environment = process.env) {
120
120
  commands
121
121
  };
122
122
  }
123
- async function main() { let args; try { args = parseArgs(process.argv.slice(2)); if (args.help) { console.log("运行 YSS 脚手架真实验证命令\n用法: node scripts/run_scaffold_verification.mjs --project-root <dir> --evidence-dir <dir>"); return 0; } const reportPath = path.join(args.evidenceDir, "scaffold-verification.json"); try { const report = await run(args.projectRoot, args.evidenceDir); await writeText(reportPath, `${JSON.stringify(report, null, 2)}\n`); console.log(`${report.status}: ${reportPath}`); return report.status === "passed" ? 0 : 1; } catch (error) { const report = { verification_mode: "controlled-generation", project_root: args.projectRoot, generated_at: isoNow(), status: "failed", failure_category: "verification-preflight", error: error.message, commands: [] }; await writeText(reportPath, `${JSON.stringify(report, null, 2)}\n`); process.stderr.write(`❌ 脚手架验证无法执行: ${error.message}\n`); return 1; } } catch (error) { process.stderr.write(`❌ 脚手架验证无法执行: ${error.message}\n`); return 1; } }
123
+ async function main() { let args; try { args = parseArgs(process.argv.slice(2)); if (args.help) { console.log("运行 YSS 脚手架真实验证命令\n用法: node scripts/run_scaffold_verification.mjs --project-root <dir> --evidence-dir <dir>"); return 0; } const reportPath = path.join(args.evidenceDir, "scaffold-verification.json"); try { const report = await run(args.projectRoot, args.evidenceDir, process.env, { timeoutMs: args.timeoutMs ?? 0 }); await writeText(reportPath, `${JSON.stringify(report, null, 2)}\n`); console.log(`${report.status}: ${reportPath}`); return report.status === "passed" ? 0 : 1; } catch (error) { const report = { verification_mode: "controlled-generation", project_root: args.projectRoot, generated_at: isoNow(), status: "failed", failure_category: "verification-preflight", error: error.message, commands: [] }; await writeText(reportPath, `${JSON.stringify(report, null, 2)}\n`); process.stderr.write(`❌ 脚手架验证无法执行: ${error.message}\n`); return 1; } } catch (error) { process.stderr.write(`❌ 脚手架验证无法执行: ${error.message}\n`); return 1; } }
124
124
  if (process.argv[1] && import.meta.url === new URL(`file://${process.argv[1]}`).href) process.exitCode = await main();
@@ -36,7 +36,7 @@ branch: template
36
36
  1. 确认当前任务已经通过 Harness 入口分诊、逐项目脚手架决定已由真实用户确认,且 schema v4 合同已由生命周期批准、持久化并保持当前。
37
37
  2. 确认目标是外部实现仓库;只有用户明确选择时才输出到 Harness 仓库的 `apps/frontend/<project>/`。`apps/frontend/` 只能作为项目容器,`app/frontend/`、`app/backend/` 及其子路径禁止作为输出位置。`git-submodule` 只能在已初始化且附加分支的子仓工作树生成;空 gitlink、detached HEAD、`--force` 覆盖挂载点不得当成普通目录。
38
38
  3. 只读检查模板分支和合同锁定的 40 位 commit 是否可访问;生成时使用精确 commit,不跟随浮动分支。
39
- 4. 使用 `scripts/generate_and_verify_scaffold.mjs` 从已核验 checkout 复制工作树,排除模板 `.git`;目标必须不存在或为空。不得默认写入 Harness、不得 `--force`。仅合同 `init_git=true` 时初始化目标 Git。
39
+ 4. 使用 `scripts/generate_and_verify_scaffold.mjs` 从已核验 checkout 的批准 commit 导出模板,排除模板 `.git` 及未提交的工作树内容;目标必须不存在或为空。不得默认写入 Harness、不得 `--force`。仅合同 `init_git=true` 时初始化目标 Git。
40
40
  5. 替换应用名、微应用名、路由、`micro-config.json`、环境变量和 README 中的模板占位。
41
41
  6. 有 API 影响时核验 OpenAPI Freeze 记录和 JSON 派生记录,将摘要一致的 JSON 原样物化到 `<frontend>/openapi/openapi.json`;`openapi_impact=not-applicable` 时必须有原因并禁止生成 API client。
42
42
  7. 保持模板既有的前端代码生成配置不变;本 Harness 只将 SHA-256 一致的 JSON 原样交给既有前端代码生成流程,不修改该配置、不在此仓库执行生成,也不设置生成 CI 门禁。目标前端项目在需要时手动运行其既有命令。
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createHash } from "node:crypto";
3
- import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
3
+ import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
4
4
  import path from "node:path";
5
+ import { tmpdir } from "node:os";
5
6
  import { spawnSync } from "node:child_process";
6
7
  import { fileURLToPath } from "node:url";
7
8
  import { validateJsonSchema } from "../../../../scripts/lib/json-schema.mjs";
@@ -22,7 +23,7 @@ function git(cwd, ...args) {
22
23
  function walk(root) {
23
24
  return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
24
25
  const item = path.join(root, entry.name);
25
- return entry.isDirectory() ? walk(item) : entry.isFile() ? [item] : [];
26
+ return entry.isDirectory() ? walk(item) : entry.isFile() || entry.isSymbolicLink() ? [item] : [];
26
27
  });
27
28
  }
28
29
  function validate(contract, outputDir) {
@@ -47,7 +48,15 @@ export function generate({ contractFile, templateCheckout, outputDir }) {
47
48
  if (git(templateCheckout, "config", "--get", "remote.origin.url") !== contract.frontend.template.repository) fail("template repository differs from approved source");
48
49
  if (existsSync(outputDir) && readdirSync(outputDir).length > 0) fail("target directory must not exist or must be empty");
49
50
  mkdirSync(outputDir, { recursive: true });
50
- cpSync(templateCheckout, outputDir, { recursive: true, filter: (source) => path.basename(source) !== ".git" });
51
+ const scratch = mkdtempSync(path.join(tmpdir(), "yss-frontend-source-"));
52
+ try {
53
+ // Read the approved Git tree, never dependency caches or edits in the checkout.
54
+ const archive = spawnSync("git", ["archive", contract.frontend.template.commit], { cwd: templateCheckout, maxBuffer: 256 * 1024 * 1024 });
55
+ if (archive.error || archive.status !== 0) fail(archive.error?.message || String(archive.stderr));
56
+ const unpack = spawnSync("tar", ["-xf", "-", "-C", scratch], { input: archive.stdout });
57
+ if (unpack.error || unpack.status !== 0) fail(unpack.error?.message || String(unpack.stderr));
58
+ cpSync(scratch, outputDir, { recursive: true, verbatimSymlinks: true });
59
+ } finally { rmSync(scratch, { recursive: true, force: true }); }
51
60
 
52
61
  const replacements = {
53
62
  "__APP_NAME__": contract.frontend.app_name,
@@ -55,10 +64,14 @@ export function generate({ contractFile, templateCheckout, outputDir }) {
55
64
  "__BASE_ROUTE__": contract.frontend.base_route,
56
65
  ...(contract.frontend.replacements || {}),
57
66
  };
58
- for (const file of walk(outputDir)) {
59
- if (statSync(file).size > 2_000_000) continue;
60
- let text;
61
- try { text = readFileSync(file, "utf8"); } catch { continue; }
67
+ const generatedFiles = walk(outputDir).map(file => path.relative(outputDir, file));
68
+ for (const ref of generatedFiles) {
69
+ const file = path.join(outputDir, ref);
70
+ const info = lstatSync(file);
71
+ if (info.isSymbolicLink() || info.size > 2_000_000) continue;
72
+ const bytes = readFileSync(file);
73
+ if (bytes.includes(0) || !Buffer.from(bytes.toString("utf8")).equals(bytes)) continue;
74
+ const text = bytes.toString("utf8");
62
75
  const replaced = Object.entries(replacements).reduce((value, [from, to]) => value.split(from).join(to), text);
63
76
  if (replaced !== text) writeFileSync(file, replaced);
64
77
  }
@@ -67,9 +80,10 @@ export function generate({ contractFile, templateCheckout, outputDir }) {
67
80
  if (sha256(bytes) !== contract.frontend.openapi_json_digest) fail("OpenAPI JSON digest mismatch");
68
81
  mkdirSync(path.join(outputDir, "openapi"), { recursive: true });
69
82
  writeFileSync(path.join(outputDir, "openapi", "openapi.json"), bytes);
83
+ if (!generatedFiles.includes("openapi/openapi.json")) generatedFiles.push("openapi/openapi.json");
70
84
  }
71
85
  if (contract.init_git === true) git(outputDir, "init");
72
- const generatedFiles = walk(outputDir).map((file) => path.relative(outputDir, file)).filter((file) => file !== ".yss/scaffold-generation.json").sort();
86
+ generatedFiles.sort();
73
87
  const manifest = {
74
88
  schema_version: 4,
75
89
  kind: "frontend-scaffold",
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import path from "node:path";
4
- import { spawnSync } from "node:child_process";
4
+ import { runCommandSync } from "../../../../scripts/lib/command-runner.mjs";
5
5
 
6
6
  const ALLOWED = new Map([
7
7
  ["pnpm install --frozen-lockfile", ["install", "--frozen-lockfile"]],
@@ -10,7 +10,7 @@ const ALLOWED = new Map([
10
10
  ["pnpm build", ["build"]],
11
11
  ]);
12
12
  function argsOf(argv) { const args = {}; for (let i = 0; i < argv.length; i += 2) args[argv[i].replace(/^--/, "")] = argv[i + 1]; return args; }
13
- export function verify(projectRoot, evidenceDir) {
13
+ export function verify(projectRoot, evidenceDir, { timeoutMs = 0 } = {}) {
14
14
  projectRoot = path.resolve(projectRoot); evidenceDir = path.resolve(evidenceDir);
15
15
  const manifestPath = path.join(projectRoot, ".yss", "scaffold-generation.json");
16
16
  const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
@@ -23,10 +23,9 @@ export function verify(projectRoot, evidenceDir) {
23
23
  const argv = ALLOWED.get(command);
24
24
  if (!argv) throw new TypeError(`unsupported verification command: ${command}`);
25
25
  const started = Date.now();
26
- const result = spawnSync("pnpm", argv, { cwd: projectRoot, encoding: "utf8" });
27
26
  const stdoutRef = path.join(evidenceDir, `${index + 1}-stdout.log`), stderrRef = path.join(evidenceDir, `${index + 1}-stderr.log`);
28
- writeFileSync(stdoutRef, result.stdout || ""); writeFileSync(stderrRef, result.stderr || "");
29
- return { command, exit_code: result.status ?? 1, duration_ms: Date.now() - started, stdout_ref: stdoutRef, stderr_ref: stderrRef, executed_at: new Date().toISOString() };
27
+ const result = runCommandSync("pnpm", argv, { cwd: projectRoot, timeoutMs, stdoutFile: stdoutRef, stderrFile: stderrRef, progress: true });
28
+ return { command, exit_code: result.status ?? 1, duration_ms: Date.now() - started, ...(result.termination ? { termination: result.termination } : {}), stdout_ref: stdoutRef, stderr_ref: stderrRef, executed_at: new Date().toISOString() };
30
29
  });
31
30
  const passed = results.every((item) => item.exit_code === 0);
32
31
  const report = { schema_version: 1, kind: "frontend-scaffold-verification", status: passed ? "passed" : "failed", project_root: projectRoot, scaffold_manifest_ref: manifestPath, commands: results };
@@ -36,6 +35,6 @@ export function verify(projectRoot, evidenceDir) {
36
35
  return report;
37
36
  }
38
37
  if (import.meta.url === `file://${process.argv[1]}`) {
39
- try { const args = argsOf(process.argv.slice(2)); const report = verify(args["project-root"], args["evidence-dir"]); process.stdout.write(`${report.status}\n`); if (report.status !== "passed") process.exitCode = 1; }
38
+ try { const args = argsOf(process.argv.slice(2)); const report = verify(args["project-root"], args["evidence-dir"], { timeoutMs: Number(args["timeout-ms"] || 0) }); process.stdout.write(`${report.status}\n`); if (report.status !== "passed") process.exitCode = 1; }
40
39
  catch (error) { process.stderr.write(`${error.message}\n`); process.exitCode = 1; }
41
40
  }
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import assert from "node:assert/strict";
3
- import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
+ import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, readlinkSync, rmSync, statSync, symlinkSync, writeFileSync } from "node:fs";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
  import { spawnSync } from "node:child_process";
@@ -12,10 +12,19 @@ mkdirSync(template); mkdirSync(bin);
12
12
  writeFileSync(path.join(template, "package.json"), JSON.stringify({ name: "__APP_NAME__", scripts: { lint: "noop", "type-check": "noop", build: "noop" } }));
13
13
  writeFileSync(path.join(template, "pnpm-lock.yaml"), "lockfileVersion: '9.0'\n");
14
14
  writeFileSync(path.join(template, "micro-config.json"), JSON.stringify({ name: "__MICROAPP_NAME__", route: "__BASE_ROUTE__" }));
15
+ mkdirSync(path.join(template, "assets"));
16
+ writeFileSync(path.join(template, "assets/binary.bin"), Buffer.from([0, 255, 95, 95, 65, 80, 80, 95, 78, 65, 77, 69, 95, 95]));
17
+ writeFileSync(path.join(template, "assets/large.txt"), "__APP_NAME__".repeat(200_000));
18
+ writeFileSync(path.join(template, "assets/run.sh"), "#!/bin/sh\necho __APP_NAME__\n");
19
+ chmodSync(path.join(template, "assets/run.sh"), 0o755);
20
+ symlinkSync("run.sh", path.join(template, "assets/current"));
15
21
  for (const args of [["init"], ["config", "user.email", "test@example.com"], ["config", "user.name", "test"], ["remote", "add", "origin", template], ["add", "."], ["commit", "-m", "fixture"]]) {
16
22
  const result = spawnSync("git", args, { cwd: template, encoding: "utf8" }); assert.equal(result.status, 0, result.stderr);
17
23
  }
18
24
  const commit = spawnSync("git", ["rev-parse", "HEAD"], { cwd: template, encoding: "utf8" }).stdout.trim();
25
+ mkdirSync(path.join(template, "node_modules"));
26
+ writeFileSync(path.join(template, "node_modules/cache.txt"), "not approved");
27
+ writeFileSync(path.join(template, "micro-config.json"), "uncommitted edit");
19
28
  const contract = {
20
29
  schema_version: 4, kind: "project-scaffold-contract", contract_id: "frontend.demo.v1", contract_version: "1", status: "approved", persisted_ref: "docs/.scratch/demo/scaffold-contract.json", current_version: true,
21
30
  delivery_role: "frontend", scaffold_kind: "frontend-yss-vue3", generator_skill: "yss-frontend-scaffold-generator", implementation_repository: output, target_output_dir: output, repository_scope: "external-repository", init_git: false,
@@ -31,6 +40,15 @@ assert.equal(existsSync(path.join(output, ".git")), false);
31
40
  assert.equal(JSON.parse(readFileSync(path.join(output, "package.json"))).name, "demo-app");
32
41
  assert.equal(JSON.parse(readFileSync(path.join(output, ".yss", "scaffold-generation.json"))).completion_level, "empty-scaffold-verified");
33
42
  assert.equal(JSON.parse(readFileSync(path.join(evidence, "scaffold-verification.json"))).commands.length, 4);
43
+ assert.equal(existsSync(path.join(output, "node_modules")), false);
44
+ assert.equal(JSON.parse(readFileSync(path.join(output, "micro-config.json"))).name, "demo");
45
+ assert.deepEqual(readFileSync(path.join(output, "assets/binary.bin")), readFileSync(path.join(template, "assets/binary.bin")));
46
+ assert.deepEqual(readFileSync(path.join(output, "assets/large.txt")), readFileSync(path.join(template, "assets/large.txt")));
47
+ assert.equal(readlinkSync(path.join(output, "assets/current")), "run.sh");
48
+ assert.equal(statSync(path.join(output, "assets/run.sh")).mode & 0o777, 0o755);
49
+ assert.match(readFileSync(path.join(output, "assets/current"), "utf8"), /echo demo-app/);
50
+ const generated = JSON.parse(readFileSync(path.join(output, ".yss/scaffold-generation.json"))).generated_files;
51
+ assert.deepEqual(generated, ["assets/binary.bin", "assets/current", "assets/large.txt", "assets/run.sh", "micro-config.json", "package.json", "pnpm-lock.yaml"]);
34
52
  const second = spawnSync(process.execPath, [runner, "--contract-file", contractFile, "--template-checkout", template, "--output-dir", output, "--evidence-dir", evidence], { encoding: "utf8", env: { ...process.env, PATH: `${bin}:${process.env.PATH}` } });
35
53
  assert.notEqual(second.status, 0);
36
54
  assert.match(second.stderr, /must not exist or must be empty/);
@@ -22,14 +22,13 @@ description: 编排 YSS 产品或模块从机会调研到 Spec、原型、技术
22
22
  使用 `scripts/query-lifecycle-context` 获取确定性 JSON 投影,不要为普通路由整份读取编排合同:
23
23
 
24
24
  ```bash
25
- scripts/query-lifecycle-context --mode route
26
- scripts/query-lifecycle-context --stage stage.discovery
27
- scripts/query-lifecycle-context --work-unit work-unit.discovery-requirements
28
- scripts/query-lifecycle-context --work-unit work-unit.slice-implementation --include ready_for_agent --include ticket_formalization
25
+ scripts/query-lifecycle-context --mode route --stage stage.plan --work-unit work-unit.plan-requirements --include execution_efficiency
29
26
  ```
30
27
 
31
28
  `--include` 接受编排合同的顶层键;非法模式、ID 或合同键必须失败。查询结果只是带摘要的权威事实投影,不成为新的事实源。解释性细节按需读取 `references/orchestration.md`、`references/state-model.md`、`references/artifact-dependencies.md`、`references/user-decisions.md` 和 `references/matt-yss-adapter.md`,达到最小充分证据后停止扩展上下文。
32
29
 
30
+ 按 `execution_efficiency` 合并查询、复用未变资料并验证当前资产;产品流转不重跑模板套件。词汇对账、恢复核验及门禁不变,执行细节见 `references/orchestration.md`。
31
+
33
32
  ## 入口与模式
34
33
 
35
34
  1. 严格解析 `yss-project.yaml`,不得按目录、Git remote 或占位符猜仓库身份。
@@ -37,6 +36,8 @@ scripts/query-lifecycle-context --work-unit work-unit.slice-implementation --inc
37
36
  3. 模式为 `route`、`orchestrate`、`resume`、`audit`;未明确时使用只读 `route`。具体写入边界从编排合同的 `modes` 子树读取。
38
37
  4. `project-instance` 按生命周期注册表推进;`template-source` 只走模板维护流程。
39
38
 
39
+ Plan 入口读取 `docs/plan/README.md` 和 `docs/process/plan-migration.md`,按注册表的退出条件核查战略输入。关键未决项阻断进入 Spec;非关键细节须有责任人、解决时点和下游接收方。只使用 Plan 标识;旧阶段不提供兼容解析,历史批准不自动成为 Plan 批准。
40
+
40
41
  ## 不可越过的边界
41
42
 
42
43
  ### 仓库身份
@@ -74,6 +75,8 @@ scripts/query-lifecycle-context --work-unit work-unit.slice-implementation --inc
74
75
 
75
76
  先问清用户与结果、通常流程、责任交接、规则与例外、可独立交付的最小范围、证明结果正确的例子和证据。每轮可生成一页“业务方案总览”,只引用权威资产并显示状态、未决问题、责任人和下一步;不复制正文、不成为新的事实源、不新增门禁。
76
77
 
78
+ Plan → Spec(含正式草稿、恢复与显式 `to-spec`)写入前,按 `docs/plan/entry-review.md` 持久化审阅包并运行 `node scripts/verify-plan-spec-entry <state.yaml>`。检查默认 pending,缺项、过期或无真实回复即阻断;独立调研可继续。
79
+
77
80
  ## 结果与暂停
78
81
 
79
82
  输出至少包含:模式、仓库身份、当前阶段和工作单元、影响面、资产与门禁状态、证据、新鲜度、Ticket/垂直切片/合同状态、`ready-for-agent` 结论、阻塞项、本轮动作、下一工作单元、暂停或继续理由、Ticket 同步和 Git checkpoint 判断。
@@ -3,7 +3,7 @@
3
3
  ## 基础依赖
4
4
 
5
5
  ```text
6
- Discovery → Spec → Product Overview / Functional Architecture
6
+ Plan → Spec → Product Overview / Functional Architecture
7
7
  Root CONTEXT.md + current work-unit changes → Context Reconciliation → approval / next work unit
8
8
  Spec + Product Overview → Product Design / Requirement Freeze
9
9
  Spec + Product Overview → API Impact / OpenAPI Draft
@@ -10,7 +10,7 @@ Matt skills 决定如何工作;YSS 生命周期决定是否允许推进;YSS
10
10
  - **直接调用生命周期管理的 Matt user-invoked skill**(`setup-matt-pocock-skills`、`grill-with-docs`、`to-spec`、`to-tickets`、`implement`)时,用户仍是正式资产的创建者;生命周期先校验前置条件,再接受结果并重新计算阶段、门禁和状态。其他 user-invoked skill 同样不得由生命周期自动调用;只有在其专属适配合同存在时才进入 YSS 流程。
11
11
  - **直接调用 `yss-product-lifecycle`** 时,不机械嵌套调用任何 Matt user-invoked skill;编排器直接使用原生工作单元和允许的 model-invoked 原语。Matt user-invoked skill 保持显式兼容入口,生命周期负责准备、校验并验收其结果。
12
12
  - `template-source` 只允许进入模板维护流程。命中 `to-spec`、`to-tickets`、`implement`、Release 或 Retrospective 时返回 `blocked`,原因是 `template-source-product-artifact-forbidden`;`setup-matt-pocock-skills` 不得为具体产品生成 Spec、prototype、OpenAPI 或垂直切片 Ticket。
13
- - `project-instance` 才允许进入产品 Discovery → Spec → 设计 → 契约 → Ticket → 实现 → Release / Retrospective 链路。
13
+ - `project-instance` 才允许进入产品 Plan → Spec → 设计 → 契约 → Ticket → 实现 → Release / Retrospective 链路。
14
14
 
15
15
  | 情形 | Matt flow | 生命周期验收 |
16
16
  |---|---|---|
@@ -66,7 +66,7 @@ blocking_signals: []
66
66
 
67
67
  | Matt flow | 进入条件 | 生命周期结果 |
68
68
  |---|---|---|
69
- | `to-spec`(用户显式) | Discovery work unit 或 `grill-with-docs` 已满足退出条件,且不存在未回流 runnable blocker;用户问题、MVP/非目标、成功标准、测试 seam 和术语审查均有证据 | 生命周期只准备/验收;Spec 初稿为 `ready-for-human`,不等于批准 |
69
+ | `to-spec`(用户显式) | Plan work unit 或 `grill-with-docs` 已满足退出条件,且不存在未回流 runnable blocker;用户问题、MVP/非目标、成功标准、测试 seam 和术语审查均有证据 | 生命周期只准备/验收;Spec 初稿为 `ready-for-human`,不等于批准 |
70
70
  | `to-tickets`(用户显式) | OpenAPI Freeze 或 `no-api-impact` 记录、必要门禁、垂直切片范围和阻塞边均已明确 | 生命周期只准备/验收;只能生成垂直切片 Ticket,初始统一为 `ready-for-human`;必须留下 `ticket_decomposition_result_ref` 和 `vertical_slice_ticket_ref` |
71
71
  | `implement`(用户显式) | `ready-for-agent` 公式、Ticket 正式化结果、垂直切片引用/类型/状态、Contract 已批准/持久化/版本一致、Build Architecture Checklist、实现仓库/分支/CI/验证命令/回滚点,以及后端 Contract(适用时)均满足 | 生命周期只准备/验收;单会话实现同样适用,不得绕过门禁;父 Ticket、`ready-for-human` 切片或跳过 Ticket 正式化的 `next_route` 必须 `blocked` |
72
72
 
@@ -100,7 +100,7 @@ Matt `implement` 的通用提交指令不构成 YSS Git 授权。只有用户明
100
100
 
101
101
  | Matt 产物 | Local 载体 |
102
102
  |---|---|
103
- | Discovery | `docs/.scratch/<feature>/discovery/` |
103
+ | Plan | `docs/.scratch/<feature>/plan/` |
104
104
  | Spec | `docs/.scratch/<feature>/spec.md` |
105
105
  | Spec Delta | `docs/.scratch/<feature>/spec-delta/` |
106
106
  | 功能父 Ticket | `docs/.scratch/<feature>/parent-ticket.md` |