create-yss-spec 2.2.7 → 2.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/template/.agents/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.agents/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.agents/skills/yss-design-system/SKILL.md +3 -1
- package/template/.agents/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.agents/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.agents/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.agents/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.agents/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.agents/skills/yss-router/references/boundaries.md +1 -1
- package/template/.agents/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.agents/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.agents/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.claude/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.claude/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.claude/skills/yss-design-system/SKILL.md +3 -1
- package/template/.claude/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.claude/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.claude/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.claude/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.claude/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.claude/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.claude/skills/yss-router/references/boundaries.md +1 -1
- package/template/.claude/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.claude/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.claude/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.codex/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.codex/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.codex/skills/yss-design-system/SKILL.md +3 -1
- package/template/.codex/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.codex/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.codex/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.codex/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.codex/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.codex/skills/yss-router/references/boundaries.md +1 -1
- package/template/.codex/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.codex/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.codex/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.cursor/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.cursor/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.cursor/skills/yss-design-system/SKILL.md +3 -1
- package/template/.cursor/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.cursor/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.cursor/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.cursor/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.cursor/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.cursor/skills/yss-router/references/boundaries.md +1 -1
- package/template/.cursor/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.cursor/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.cursor/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.cursor/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.hermes/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.hermes/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.hermes/skills/yss-design-system/SKILL.md +3 -1
- package/template/.hermes/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.hermes/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.hermes/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.hermes/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.hermes/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.hermes/skills/yss-router/references/boundaries.md +1 -1
- package/template/.hermes/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.hermes/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.hermes/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.pi/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.pi/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.pi/skills/yss-design-system/SKILL.md +3 -1
- package/template/.pi/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.pi/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.pi/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.pi/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.pi/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.pi/skills/yss-router/references/boundaries.md +1 -1
- package/template/.pi/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.pi/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.pi/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.qoder/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.qoder/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.qoder/skills/yss-design-system/SKILL.md +3 -1
- package/template/.qoder/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.qoder/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.qoder/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.qoder/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.qoder/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.qoder/skills/yss-router/references/boundaries.md +1 -1
- package/template/.qoder/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.qoder/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.qoder/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/.trae/skills/maintaining-skills/SKILL.md +1 -1
- package/template/.trae/skills/yss-antd-design/references/evidence.md +4 -0
- package/template/.trae/skills/yss-design-system/SKILL.md +3 -1
- package/template/.trae/skills/yss-page-module-development/SKILL.md +1 -1
- package/template/.trae/skills/yss-product-lifecycle/SKILL.md +3 -1
- package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +46 -1
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +6 -0
- package/template/.trae/skills/yss-prototype-stage/SKILL.md +11 -6
- package/template/.trae/skills/yss-prototype-stage/references/product-design-adapter.md +54 -0
- package/template/.trae/skills/yss-prototype-stage/scripts/prototype-contract.mjs +207 -0
- package/template/.trae/skills/yss-prototype-stage/tests/run-scenarios.mjs +154 -0
- package/template/.trae/skills/yss-router/references/boundaries.md +1 -1
- package/template/.trae/skills/yss-router/references/router-contract.yaml +30 -3
- package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +14 -0
- package/template/.trae/skills/yss-router/references/yss-skill-execution-result.md +5 -0
- package/template/.trae/skills/yss-ui/references/antdv-compatibility.md +1 -1
- package/template/AGENTS.md +5 -4
- package/template/CONTEXT.md +2 -2
- package/template/DESIGN.md +203 -0
- package/template/README.md +10 -11
- package/template/__yss_dotfile__.gitignore +1 -0
- package/template/docs/agents/digital-human-roles.md +1 -1
- package/template/docs/agents/digital-human-roles.yaml +17 -21
- package/template/docs/agents/skills-maintenance.md +2 -2
- package/template/docs/agents/yss-plugin-dependency-contract.md +45 -0
- package/template/docs/agents/yss-skill-registry.yaml +30 -1
- package/template/docs/api/templates/openapi-draft-review-checklist.md +2 -2
- package/template/docs/architecture/templates/engineering-baseline-review-template.md +19 -0
- package/template/docs/design/README.md +14 -3
- package/template/docs/design/design-system-sync.yaml +12 -0
- package/template/docs/design/design.md +69 -10
- package/template/docs/design/preview-dark.html +15 -0
- package/template/docs/design/preview.html +20 -0
- package/template/docs/design/templates/interaction-spec-template.md +2 -2
- package/template/docs/design/templates/prototype-confirmation-template.md +1 -1
- package/template/docs/design/templates/prototype-evidence-template.yaml +52 -10
- package/template/docs/design/tokens/.design-md-projection.json +13 -0
- package/template/docs/discovery/reports/agent-governance-options.md +71 -0
- package/template/docs/process/harness-process-tailoring.md +12 -5
- package/template/docs/process/lifecycle-registry-baseline.json +1 -1
- package/template/docs/process/lifecycle-registry.yaml +1 -1
- package/template/docs/process/template-engineering-overview.md +2 -2
- package/template/docs/process/template-verification-profiles.yaml +15 -1
- package/template/docs/process/templates/maintenance-checkpoint-template.yaml +3 -12
- package/template/docs/templates/build-architecture-checklist-template.md +2 -0
- package/template/docs/templates/implementation-routing-template.md +23 -0
- package/template/docs/templates/requirement-freeze-template.md +1 -1
- package/template/docs/user-guide//346/210/230/346/234/257/350/256/276/350/256/241/345/255/220/351/241/271/347/233/256/347/224/250/346/210/267/346/211/213/345/206/214.md +218 -0
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214.md +1014 -0
- package/template/docs/user-guide//347/224/250/346/210/267/346/211/213/345/206/214/347/264/242/345/274/225.md +15 -25
- package/template/scripts/lib/digital-human-roles.mjs +0 -1
- package/template/scripts/lib/maintenance-intensity.mjs +24 -10
- package/template/scripts/lib/skill-governance.mjs +19 -0
- package/template/scripts/lib/skill-registry.mjs +70 -0
- package/template/scripts/node-verify-lifecycle-registry.mjs +1 -1
- package/template/scripts/verify-digital-human-roles-scenarios +1 -1
- package/template/scripts/verify-template-verification-scenarios +5 -0
- package/template/scripts/verify-yss-prototype-contract-scenarios +2 -0
- package/template/skills-lock.json +8 -8
- package/template.manifest.json +1 -0
- package/template.snapshot.json +5 -5
- package/template/docs/user-guide/templates//347/224/250/346/210/267/346/211/213/345/206/214/346/250/241/346/235/277.md +0 -53
- package/template/docs/user-guide//344/272/247/345/223/201/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201.md +0 -223
- package/template/docs/user-guide//344/272/247/345/223/201/347/240/224/345/217/221/345/205/250/347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +0 -1115
- package/template/docs/user-guide//345/244/226/351/203/250/345/221/275/344/273/244/350/241/214/345/267/245/345/205/267/345/256/236/350/267/265/346/214/207/345/215/227.md +0 -117
- package/template/docs/user-guide//347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +0 -584
- package/template/docs/user-guide//350/247/204/346/240/274/344/270/216/344/273/273/345/212/241/350/277/201/347/247/273/346/214/207/345/215/227.md +0 -44
- package/template/docs/user-guide//351/234/200/346/261/202/346/276/204/346/270/205/346/214/207/345/215/227.md +0 -230
- package/template/docs/user-guide//351/234/200/346/261/202/346/276/204/346/270/205/346/234/200/344/275/263/345/256/236/350/267/265.md +0 -275
|
@@ -241,6 +241,10 @@ work_unit_routes:
|
|
|
241
241
|
primary_skill: yss-prototype-stage
|
|
242
242
|
supporting_skills: [prototype-review, yss-design-system, yss-antd-design, product-design:index]
|
|
243
243
|
skills: [prototype-review, yss-design-system, yss-prototype-stage, yss-antd-design, product-design:index]
|
|
244
|
+
execution_order: [yss-design-system, low-fidelity-assets, prototype-review, yss-antd-design-pre-build, product-design-focused-workflow, yss-antd-design-post-build, browser-design-qa-accessibility, user-confirmation]
|
|
245
|
+
prototype_adapter_ref: .agents/skills/yss-prototype-stage/references/product-design-adapter.md
|
|
246
|
+
evidence_schema_version: 2
|
|
247
|
+
version_boundary: {design_standard: ant-design-v6, prototype_components: react-antd-6.x, production_components: yss-ui-ant-design-vue-4.x, production_version_source: implementation-lockfile}
|
|
244
248
|
human_gate: prototype-confirmation
|
|
245
249
|
applies_when: product_design_impact
|
|
246
250
|
not_applicable_reason: no_ui_or_product_design_impact
|
|
@@ -644,8 +648,49 @@ release_readiness:
|
|
|
644
648
|
wayfinder_completion:
|
|
645
649
|
required: [no_open_children, no_open_blocked_or_claimed_children, no_fog, destination_clear]
|
|
646
650
|
|
|
651
|
+
wayfinder_mode:
|
|
652
|
+
optional: true
|
|
653
|
+
enable_when:
|
|
654
|
+
- multi-session-or-multi-agent-work
|
|
655
|
+
- unclear-decision-frontier
|
|
656
|
+
- cross-domain-dependency-map-needed
|
|
657
|
+
lifecycle_position: discovery-to-spec-planning
|
|
658
|
+
completion_route: wayfinder -> handoff -> to-spec
|
|
659
|
+
does_not_replace: [lifecycle-gates, spec-baseline, ticket-formalization]
|
|
660
|
+
forbidden_state_mutations: [ready-for-agent, gate-approval, ticket-role]
|
|
661
|
+
template_source_use: only-when-template-evolution-is-long-running
|
|
662
|
+
|
|
663
|
+
context_engineering:
|
|
664
|
+
contract_field: slice_contract.common.context_plan
|
|
665
|
+
required_context: [CONTEXT.md, approved-spec, current-slice-contract, applicable-adr-or-baseline]
|
|
666
|
+
on_demand_context: [specialist-references, implementation-repository-files, historical-evidence]
|
|
667
|
+
stop_rule: minimal-sufficient-evidence
|
|
668
|
+
missing_context_action: [blocked, reroute]
|
|
669
|
+
numeric_token_budget: not-required
|
|
670
|
+
|
|
671
|
+
doubt_driven_review:
|
|
672
|
+
applies_when:
|
|
673
|
+
- api-schema-impact
|
|
674
|
+
- database-schema-impact
|
|
675
|
+
- cross-repo-contract
|
|
676
|
+
- release-or-rollback
|
|
677
|
+
- authentication-authorization-tenant-or-sensitive-data-behavior
|
|
678
|
+
- lifecycle-or-generation-semantics
|
|
679
|
+
required: [claim, counterclaim, evidence_refs, residual_risks, reviewer_ref]
|
|
680
|
+
record_in: [decision-record, architecture-review, contract-review, release-review]
|
|
681
|
+
blocking_when: [missing-counterclaim, insufficient-evidence, unresolved-residual-risk]
|
|
682
|
+
ordinary-low-risk_changes: not-required
|
|
683
|
+
no_new_lifecycle_stage: true
|
|
684
|
+
|
|
685
|
+
quality_baseline_reuse:
|
|
686
|
+
source: artifact.engineering-baseline
|
|
687
|
+
applies_to: project-instance
|
|
688
|
+
consumers: [slice-implementation-contract, yss-skill-execution-result, code-review, release]
|
|
689
|
+
constraint_results_field: required
|
|
690
|
+
redefinition: forbidden
|
|
691
|
+
|
|
647
692
|
ready_for_agent:
|
|
648
|
-
required: [gates_satisfied, no_stale_artifacts, blockers_closed, implementation_context_ready, implementation_repo, implementation_branch, ci, verification_commands, rollback_point, predecessor_work_unit, ticket_decomposition_result_ref, ticket_decomposition_result_status, vertical_slice_ticket_ref, vertical_slice_ticket_role, vertical_slice_ticket_kind, slice_contract_approved, slice_contract_persisted, slice_contract_current_version, build_architecture_checklist, backend_slice_contract_if_applicable, backend_scaffold_policy_satisfied, frontend_implementation_plan_if_ui_impact]
|
|
693
|
+
required: [gates_satisfied, no_stale_artifacts, blockers_closed, implementation_context_ready, context_plan, quality_baseline_ref, implementation_repo, implementation_branch, ci, verification_commands, rollback_point, predecessor_work_unit, ticket_decomposition_result_ref, ticket_decomposition_result_status, vertical_slice_ticket_ref, vertical_slice_ticket_role, vertical_slice_ticket_kind, slice_contract_approved, slice_contract_persisted, slice_contract_current_version, build_architecture_checklist, backend_slice_contract_if_applicable, backend_scaffold_policy_satisfied, frontend_implementation_plan_if_ui_impact]
|
|
649
694
|
ticket_formalization_validator: scripts/lib/lifecycle-transition.mjs
|
|
650
695
|
requires_vertical_slice_ticket: true
|
|
651
696
|
parent_ticket_as_implementation_ref: forbidden
|
|
@@ -86,6 +86,12 @@ tracker 选择和冲突按 `docs/agents/issue-tracker.md` 裁决:已持久化
|
|
|
86
86
|
|
|
87
87
|
暂停输出:门禁、指定会签 `role_id`、`runtime_id`、会签文件路径、证据、推荐答案、一个问题、恢复动作。
|
|
88
88
|
|
|
89
|
+
## Context Plan 与质量基线
|
|
90
|
+
|
|
91
|
+
实现合同先消费 `common.context_plan`:必需上下文只包含 `CONTEXT.md`、已批准 Spec、当前合同和适用 ADR / 工程基线;专项 references、实现仓库文件和历史证据按影响面按需加载。达到最小充分证据后停止扩展,缺失权威上下文只能 `blocked` 或 `reroute`。
|
|
92
|
+
|
|
93
|
+
质量标准由 `engineering-baseline` 以 `baseline_id` / `baseline_version` 定义一次,Slice Contract、YSS Skill Execution Result、`code-review` 和发布检查只引用它,并将约束结果写入 `constraint_results`。命中 API / 数据迁移、跨仓契约、发布回滚、实际安全行为或生命周期 / 生成语义时,必须在现有决策或审查记录中完成 Doubt-Driven 主张、反证、证据、残余风险和 Reviewer 引用;普通低风险变更不触发该流程。
|
|
94
|
+
|
|
89
95
|
## Wayfinder 完成判定
|
|
90
96
|
|
|
91
97
|
“无 frontier”不等于完成。只有以下条件同时成立,才能 `wayfinder → handoff → to-spec`:
|
|
@@ -15,11 +15,12 @@ description: Use when a YSS feature has product-design impact on a primary flow,
|
|
|
15
15
|
|
|
16
16
|
## 资产与门禁顺序
|
|
17
17
|
|
|
18
|
-
1. 以 Spec
|
|
18
|
+
1. 以 Spec、产品总体设计、`yss-design-system` 和 `docs/design/design.md` 形成交互说明、低保真页面/流程与状态矩阵。
|
|
19
19
|
2. 用 `prototype-review` 形成独立评审结论;未通过不得生成高保真或进入需求冻结。
|
|
20
|
-
3.
|
|
21
|
-
4.
|
|
22
|
-
5.
|
|
20
|
+
3. 用 `yss-antd-design` 固定目标 React `antd@6.x`,先查询 `design.md` 与本功能组件事实。
|
|
21
|
+
4. 通过 `product-design:index` 的 `get-context → ideate → 用户选择 → image-to-code → design-qa` 产出 feature 级 React/Vite 原型;必须套用 `references/product-design-adapter.md`,不能把通用 starter 视为已符合 YSS。
|
|
22
|
+
5. 完成 AntD post-build manifest/lint(按产物类型)、同视口 Design QA、浏览器与无障碍验证,写入 schema v2 `docs/.scratch/<feature>/verification/prototype-evidence.yaml`。
|
|
23
|
+
6. 用户确认后,才可校准 Spec、分析 API 影响或进入 Router readiness。
|
|
23
24
|
|
|
24
25
|
## 设计与 AntD 依据
|
|
25
26
|
|
|
@@ -27,11 +28,13 @@ description: Use when a YSS feature has product-design impact on a primary flow,
|
|
|
27
28
|
|
|
28
29
|
Codex `$design-qa` 仍走官方对比流程;Colors/tokens 与 Fonts/typography 必须以项目覆盖为 source visual truth。对照清单见 `yss-design-system/references/design-qa-theme.md`。仍用官方 `#1677ff`、强制 `Inter` 或历史 8px 品牌圆角当默认主题,视为项目覆盖漂移。
|
|
29
30
|
|
|
30
|
-
Ant Design v6 事实由 `yss-antd-design` 查询并回写证据,不要并列调用官方 `antd` skill,也不要在前端代码落地时继续使用它。进入实现后改走 `yss-ui`。
|
|
31
|
+
主题与视觉标准固定为 `ant-design-v6`;生产运行时固定为 Vue 3 + YSS UI + `ant-design-vue-4.x`,精确生产版本来自实现仓 lockfile。版本号不同本身不是冲突。Ant Design v6 事实由 `yss-antd-design` 查询并回写证据,不要并列调用官方 `antd` skill,也不要在前端代码落地时继续使用它。进入实现后改走 `yss-ui`。
|
|
32
|
+
|
|
33
|
+
标准原型组件存在 Ant Design 实现时必须精确锁定与 CLI 目标一致的 `antd@6.x`,并通过 `ConfigProvider` 消费项目主题 adapter。执行与验证命令见 `references/product-design-adapter.md` 和 `scripts/prototype-contract.mjs`。
|
|
31
34
|
|
|
32
35
|
## 验证与回流
|
|
33
36
|
|
|
34
|
-
`browser_verification`
|
|
37
|
+
`browser_verification` 至少覆盖非空渲染、主流程、一个失败/权限/冲突状态、桌面与窄屏视口和控制台错误;`accessibility_verification` 至少覆盖对比度、键盘/焦点、语义标签与 Dialog、200% zoom、reduced motion、目标尺寸和自动化扫描。优先使用 Browser 或可执行浏览器自动化,Computer Use 只作人工交互补充。把路径、命令、版本、视口、结果和阻塞项写入证据清单。
|
|
35
38
|
|
|
36
39
|
`gate.prototype-reviewed` 的证据是评审记录;`gate.prototype-verified` 的证据是 AntD CLI 与浏览器验证;`gate.user-confirmation` 的证据是确认记录。三者均不是实现授权。
|
|
37
40
|
|
|
@@ -40,3 +43,5 @@ Ant Design v6 事实由 `yss-antd-design` 查询并回写证据,不要并列
|
|
|
40
43
|
- 仅有截图或 HTML,却没有可复现的 CLI、浏览器和确认记录。
|
|
41
44
|
- 把 `product-design:index` 或某个旧技能当作生命周期批准者。
|
|
42
45
|
- 直接复制官方默认颜色、圆角或间距,忽略项目覆盖。
|
|
46
|
+
- 只证明查询过 AntD v6,却没有 v6 semantic role → 项目 Token → YSS/AntDV4 的映射证据。
|
|
47
|
+
- 沿用 Product Design starter 的 npm、根目录 `design-qa.md` 或未安装 `antd` 的通用配置。
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# YSS Product Design Adapter
|
|
2
|
+
|
|
3
|
+
本合同把 Codex Product Design 的通用 React/Vite 产出接入 YSS 原型阶段。它不修改上游 Product Design skill,也不把 React API 带入 Vue 生产实现。
|
|
4
|
+
|
|
5
|
+
## 双轨版本
|
|
6
|
+
|
|
7
|
+
- `design_standard: ant-design-v6`:高保真原型的主题、视觉语义、标准组件和 CLI 事实。
|
|
8
|
+
- `runtime_component_library: ant-design-vue-4.x`:生产 Vue/YSS 组件 API;精确版本只从实现仓 lockfile 读取。
|
|
9
|
+
- 标准原型组件存在 Ant Design 实现时,React 原型必须精确锁定与 CLI 查询一致的 `antd@6.x`。YSS 专有布局可用适配 CSS,但仍消费项目 Token。
|
|
10
|
+
- 禁止把 React hook、props、JSX、静态 API 或事件模型作为 Vue/YSS 实现合同。
|
|
11
|
+
|
|
12
|
+
## 产出前适配
|
|
13
|
+
|
|
14
|
+
1. 目标目录固定为 `docs/.scratch/<feature>/design/prototypes/`。
|
|
15
|
+
2. Product Design 完成 `get-context`、三方案 `ideate` 和用户视觉选择后,进入 `image-to-code` 的 local preflight,只执行官方 bootstrap 创建空 starter;在安装依赖或编写 UI 前立即运行 adapter:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
node .agents/skills/yss-prototype-stage/scripts/prototype-contract.mjs prepare \
|
|
19
|
+
--project-root <project-root> \
|
|
20
|
+
--root <project-root>/docs/.scratch/<feature>/design/prototypes \
|
|
21
|
+
--feature <feature> \
|
|
22
|
+
--target-antd-version <exact-6.x-version> \
|
|
23
|
+
--pnpm-version <actual-pnpm-version>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
3. adapter 只做机械动作:精确写入 `antd` 版本、登记 pnpm、生成 `src/yss-theme.js` 和 `yss-prototype-adapter.json`。随后由 Product Design 将入口包在 `ConfigProvider theme={yssTheme}` 中,并优先使用标准 `antd` 组件。
|
|
27
|
+
4. 执行 `pnpm install`、`pnpm build`,保留 `pnpm-lock.yaml`、源码入口、构建入口、实际命令与退出码。禁止用 npm lockfile 代替受控例外记录。
|
|
28
|
+
5. 校验项目:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
node .agents/skills/yss-prototype-stage/scripts/prototype-contract.mjs validate-project \
|
|
32
|
+
--root <project-root>/docs/.scratch/<feature>/design/prototypes \
|
|
33
|
+
--target-antd-version <exact-6.x-version>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 视觉与实现映射
|
|
37
|
+
|
|
38
|
+
每个关键组件在 `visual_semantic_mapping` 中记录四层映射:Ant Design v6 semantic role、项目 Token、React 原型组件、生产 YSS/Ant Design Vue 目标。映射的是视觉角色、状态和验收行为,不是 React API 表面形状。
|
|
39
|
+
|
|
40
|
+
至少覆盖主操作、表单输入、表格/列表、反馈、弹层和导航中本功能实际出现的类型。每项记录 `default/hover/active/disabled/loading/error` 等适用状态,并把 `react_only_api_not_copied` 设为 `true` 后才能通过。
|
|
41
|
+
|
|
42
|
+
## 视口、QA 与无障碍
|
|
43
|
+
|
|
44
|
+
- 默认视觉目标和同状态 QA 使用 desktop `1440x900`、mobile `390x844`;按影响追加 tablet/laptop/wide,不机械要求九个视口。
|
|
45
|
+
- Design QA 报告固定到 `docs/.scratch/<feature>/verification/design-qa.md`,不得写仓库根共享文件。
|
|
46
|
+
- 项目品牌 Seed `#3371ff` 保持不变;普通文本、按钮及状态组合不满足 WCAG 2.2 AA 时,通过组件 Token 调整实际填充或文字色,并保存对比度证据。
|
|
47
|
+
- 验证至少包含键盘、焦点、语义标签/Dialog、200% zoom、reduced motion、目标尺寸和自动化扫描;工具不可用时记录人工替代与未覆盖缺口,不得空填 passed。
|
|
48
|
+
|
|
49
|
+
## 交互档位
|
|
50
|
+
|
|
51
|
+
- `reviewable-flow`(默认):合同内主路径和关键状态可操作;非范围控件禁用或明确标注,不伪装完整功能。
|
|
52
|
+
- `full-prototype`:brief 明确要求的全部可见范围控件可操作。
|
|
53
|
+
|
|
54
|
+
不得使用含义冲突的 `static` / `mostly-static` 作为 YSS 交付状态。
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
7
|
+
import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
|
|
8
|
+
|
|
9
|
+
const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0;
|
|
10
|
+
const object = (value) => value && typeof value === "object" && !Array.isArray(value);
|
|
11
|
+
const semver = /^6\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
|
|
12
|
+
const pnpmSemver = /^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?$/;
|
|
13
|
+
|
|
14
|
+
function required(data, field, parent, errors) {
|
|
15
|
+
if (!object(data) || data[field] === undefined || data[field] === null) errors.push(`${parent}.${field} 缺失`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function requiredString(data, field, parent, errors) {
|
|
19
|
+
required(data, field, parent, errors);
|
|
20
|
+
if (object(data) && data[field] !== undefined && !nonEmpty(data[field])) errors.push(`${parent}.${field} 必须是非空字符串`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function requiredPassed(data, field, parent, errors) {
|
|
24
|
+
requiredString(data, field, parent, errors);
|
|
25
|
+
if (object(data) && nonEmpty(data[field]) && !["passed", "approved"].includes(data[field])) errors.push(`${parent}.${field} 必须为 passed/approved`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function validatePrototypeEvidence(data, { allowTemplate = false, allowLegacy = false } = {}) {
|
|
29
|
+
const errors = [];
|
|
30
|
+
const warnings = [];
|
|
31
|
+
if (!object(data)) return { errors: ["原型证据必须是对象"], warnings };
|
|
32
|
+
if (data.schema_version === 1) {
|
|
33
|
+
if (!allowLegacy) errors.push("schema_version 1 是旧证据;完成 gate.prototype-verified 前必须迁移到 2,或只读时显式 --allow-legacy");
|
|
34
|
+
else warnings.push("legacy prototype evidence schema v1");
|
|
35
|
+
return { errors, warnings };
|
|
36
|
+
}
|
|
37
|
+
if (data.schema_version !== 2) errors.push("schema_version 必须为 2");
|
|
38
|
+
for (const field of ["feature", "prototype_ref", "prototype_stack", "design_baseline", "visual_semantic_mapping", "antd", "browser_verification", "design_qa", "accessibility_verification", "review", "user_confirmation", "blockers"]) required(data, field, "root", errors);
|
|
39
|
+
|
|
40
|
+
const templateValue = (value) => allowTemplate && nonEmpty(value) && /<[^>]+>/.test(value);
|
|
41
|
+
const stack = data.prototype_stack;
|
|
42
|
+
if (object(stack)) {
|
|
43
|
+
for (const field of ["framework", "package_manager", "package_manifest_ref", "lockfile_ref", "source_entry_ref", "build_entry_ref", "build_command", "build_result", "actual_antd_version"]) requiredString(stack, field, "prototype_stack", errors);
|
|
44
|
+
if (stack.framework !== "react") errors.push("prototype_stack.framework 必须为 react");
|
|
45
|
+
if (stack.package_manager !== "pnpm") errors.push("prototype_stack.package_manager 必须为 pnpm");
|
|
46
|
+
if (nonEmpty(stack.lockfile_ref) && !stack.lockfile_ref.endsWith("pnpm-lock.yaml")) errors.push("prototype_stack.lockfile_ref 必须指向 pnpm-lock.yaml");
|
|
47
|
+
if (!templateValue(stack.actual_antd_version) && nonEmpty(stack.actual_antd_version) && !semver.test(stack.actual_antd_version)) errors.push("prototype_stack.actual_antd_version 必须是明确的 antd 6.x semver");
|
|
48
|
+
if (!allowTemplate) requiredPassed(stack, "build_result", "prototype_stack", errors);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const baseline = data.design_baseline;
|
|
52
|
+
if (object(baseline)) {
|
|
53
|
+
for (const field of ["design_standard", "project_design_ref", "project_token_refs", "theme_adapter_ref", "project_override_reviewed"]) required(baseline, field, "design_baseline", errors);
|
|
54
|
+
if (baseline.design_standard !== "ant-design-v6") errors.push("design_baseline.design_standard 必须为 ant-design-v6");
|
|
55
|
+
if (!Array.isArray(baseline.project_token_refs) || baseline.project_token_refs.length === 0) errors.push("design_baseline.project_token_refs 必须是非空数组");
|
|
56
|
+
if (!allowTemplate && baseline.project_override_reviewed !== true) errors.push("design_baseline.project_override_reviewed 必须为 true");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const mapping = data.visual_semantic_mapping;
|
|
60
|
+
if (object(mapping)) {
|
|
61
|
+
if (mapping.runtime_component_library !== "ant-design-vue-4.x") errors.push("visual_semantic_mapping.runtime_component_library 必须为 ant-design-vue-4.x");
|
|
62
|
+
if (mapping.runtime_version_source !== "implementation-lockfile") errors.push("visual_semantic_mapping.runtime_version_source 必须为 implementation-lockfile");
|
|
63
|
+
if (!Array.isArray(mapping.components) || mapping.components.length === 0) errors.push("visual_semantic_mapping.components 必须是非空数组");
|
|
64
|
+
for (const [index, component] of (mapping.components ?? []).entries()) {
|
|
65
|
+
const parent = `visual_semantic_mapping.components[${index}]`;
|
|
66
|
+
for (const field of ["semantic_role", "antd_v6_component", "project_token_refs", "yss_or_antdv_target", "state_mapping", "react_only_api_not_copied", "verification_ref"]) required(component, field, parent, errors);
|
|
67
|
+
if (!Array.isArray(component?.project_token_refs) || component.project_token_refs.length === 0) errors.push(`${parent}.project_token_refs 必须是非空数组`);
|
|
68
|
+
if (!Array.isArray(component?.state_mapping) || component.state_mapping.length === 0) errors.push(`${parent}.state_mapping 必须是非空数组`);
|
|
69
|
+
if (!allowTemplate && component?.react_only_api_not_copied !== true) errors.push(`${parent}.React-only API 未确认隔离`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (object(data.antd)) {
|
|
74
|
+
requiredString(data.antd, "target_antd_version", "antd", errors);
|
|
75
|
+
if (object(stack) && nonEmpty(data.antd.target_antd_version) && nonEmpty(stack.actual_antd_version) && !templateValue(data.antd.target_antd_version) && data.antd.target_antd_version !== stack.actual_antd_version) errors.push("antd.target_antd_version 必须与 prototype_stack.actual_antd_version 一致");
|
|
76
|
+
}
|
|
77
|
+
if (object(data.design_qa)) {
|
|
78
|
+
requiredString(data.design_qa, "report_ref", "design_qa", errors);
|
|
79
|
+
requiredString(data.design_qa, "result", "design_qa", errors);
|
|
80
|
+
if (nonEmpty(data.design_qa.report_ref) && !/^docs\/\.scratch\/[^/]+\/verification\/design-qa\.md$/.test(data.design_qa.report_ref) && !templateValue(data.design_qa.report_ref)) errors.push("design_qa.report_ref 必须是 feature 级 verification/design-qa.md");
|
|
81
|
+
if (!allowTemplate) requiredPassed(data.design_qa, "result", "design_qa", errors);
|
|
82
|
+
}
|
|
83
|
+
const accessibility = data.accessibility_verification;
|
|
84
|
+
if (object(accessibility)) {
|
|
85
|
+
for (const field of ["contrast_results_ref", "keyboard_navigation_result", "focus_visible_and_order_result", "semantic_label_dialog_result", "zoom_200_result", "reduced_motion_result", "target_size_result", "automated_scan"]) required(accessibility, field, "accessibility_verification", errors);
|
|
86
|
+
requiredString(accessibility, "contrast_results_ref", "accessibility_verification", errors);
|
|
87
|
+
if (!allowTemplate) for (const field of ["keyboard_navigation_result", "focus_visible_and_order_result", "semantic_label_dialog_result", "zoom_200_result", "reduced_motion_result", "target_size_result"]) requiredPassed(accessibility, field, "accessibility_verification", errors);
|
|
88
|
+
if (object(accessibility.automated_scan)) for (const field of ["tool", "version", "result", "ref"]) requiredString(accessibility.automated_scan, field, "accessibility_verification.automated_scan", errors);
|
|
89
|
+
}
|
|
90
|
+
if (!Array.isArray(data.blockers)) errors.push("root.blockers 必须是数组");
|
|
91
|
+
if (!allowTemplate && Array.isArray(data.blockers) && data.blockers.length > 0) errors.push("存在 blockers,不能通过原型验证");
|
|
92
|
+
return { errors, warnings };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function safePrototypeRoot(projectRoot, root, feature) {
|
|
96
|
+
const resolvedProject = path.resolve(projectRoot);
|
|
97
|
+
const resolvedRoot = path.resolve(root);
|
|
98
|
+
const expected = path.resolve(resolvedProject, "docs/.scratch", feature, "design/prototypes");
|
|
99
|
+
if (resolvedRoot !== expected) throw new TypeError(`原型目录必须精确匹配 ${expected}`);
|
|
100
|
+
if (!resolvedRoot.startsWith(`${resolvedProject}${path.sep}`)) throw new TypeError("原型目录越出项目根");
|
|
101
|
+
return { resolvedProject, resolvedRoot };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function preparePrototype({ projectRoot, root, feature, targetAntdVersion, pnpmVersion }) {
|
|
105
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(feature ?? "")) throw new TypeError("feature 必须是小写 kebab-case");
|
|
106
|
+
if (!semver.test(targetAntdVersion ?? "")) throw new TypeError("targetAntdVersion 必须是明确的 antd 6.x semver");
|
|
107
|
+
if (!pnpmSemver.test(pnpmVersion ?? "")) throw new TypeError("pnpmVersion 必须是明确 semver");
|
|
108
|
+
const { resolvedProject, resolvedRoot } = safePrototypeRoot(projectRoot, root, feature);
|
|
109
|
+
const packagePath = path.join(resolvedRoot, "package.json");
|
|
110
|
+
if (!existsSync(packagePath)) throw new TypeError(`缺少 Product Design starter package.json: ${packagePath}`);
|
|
111
|
+
const pkg = JSON.parse(await readFile(packagePath, "utf8"));
|
|
112
|
+
pkg.packageManager = `pnpm@${pnpmVersion}`;
|
|
113
|
+
pkg.dependencies = { ...(pkg.dependencies ?? {}), "@ant-design/icons": "^6.0.0", antd: targetAntdVersion };
|
|
114
|
+
await writeFile(packagePath, `${JSON.stringify(pkg, null, 2)}\n`);
|
|
115
|
+
|
|
116
|
+
const themeSourcePath = path.join(resolvedProject, "docs/design/tokens/theme.json");
|
|
117
|
+
if (!existsSync(themeSourcePath)) throw new TypeError(`缺少项目主题: ${themeSourcePath}`);
|
|
118
|
+
const themeSource = JSON.parse(await readFile(themeSourcePath, "utf8"));
|
|
119
|
+
const generated = [
|
|
120
|
+
'import { theme } from "antd";',
|
|
121
|
+
"",
|
|
122
|
+
`const source = ${JSON.stringify(themeSource, null, 2)};`,
|
|
123
|
+
'const layoutKeys = new Set(["layoutHeaderHeight", "layoutSiderBackground", "layoutBodyBackground"]);',
|
|
124
|
+
"export const yssLayoutTokens = Object.fromEntries(Object.entries(source.token ?? {}).filter(([key]) => layoutKeys.has(key)));",
|
|
125
|
+
"export const yssTheme = {",
|
|
126
|
+
" algorithm: [theme.defaultAlgorithm, theme.compactAlgorithm],",
|
|
127
|
+
" token: Object.fromEntries(Object.entries(source.token ?? {}).filter(([key]) => !layoutKeys.has(key)))",
|
|
128
|
+
"};",
|
|
129
|
+
""
|
|
130
|
+
].join("\n");
|
|
131
|
+
await mkdir(path.join(resolvedRoot, "src"), { recursive: true });
|
|
132
|
+
await writeFile(path.join(resolvedRoot, "src/yss-theme.js"), generated);
|
|
133
|
+
const manifest = {
|
|
134
|
+
schema_version: 1,
|
|
135
|
+
feature,
|
|
136
|
+
design_standard: "ant-design-v6",
|
|
137
|
+
target_antd_version: targetAntdVersion,
|
|
138
|
+
prototype_framework: "react",
|
|
139
|
+
package_manager: `pnpm@${pnpmVersion}`,
|
|
140
|
+
theme_source: "docs/design/tokens/theme.json",
|
|
141
|
+
theme_adapter: `docs/.scratch/${feature}/design/prototypes/src/yss-theme.js`,
|
|
142
|
+
production_runtime: { framework: "vue-3", component_library: "ant-design-vue-4.x", version_source: "implementation-lockfile" },
|
|
143
|
+
next_commands: ["pnpm install", "pnpm build"]
|
|
144
|
+
};
|
|
145
|
+
await writeFile(path.join(resolvedRoot, "yss-prototype-adapter.json"), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
146
|
+
return manifest;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export async function validatePrototypeProject({ root, targetAntdVersion }) {
|
|
150
|
+
const errors = [];
|
|
151
|
+
const packagePath = path.join(root, "package.json");
|
|
152
|
+
if (!existsSync(packagePath)) return { errors: ["缺少 package.json"] };
|
|
153
|
+
const pkg = JSON.parse(await readFile(packagePath, "utf8"));
|
|
154
|
+
if (pkg.dependencies?.antd !== targetAntdVersion) errors.push(`package.json 必须精确锁定 antd ${targetAntdVersion}`);
|
|
155
|
+
if (!String(pkg.packageManager ?? "").startsWith("pnpm@")) errors.push("package.json 必须记录实际 pnpm packageManager");
|
|
156
|
+
if (!existsSync(path.join(root, "pnpm-lock.yaml"))) errors.push("缺少 pnpm-lock.yaml");
|
|
157
|
+
if (!existsSync(path.join(root, "src/yss-theme.js"))) errors.push("缺少 src/yss-theme.js");
|
|
158
|
+
const sourceFiles = ["src/App.jsx", "src/App.tsx", "src/main.jsx", "src/main.tsx"].filter((file) => existsSync(path.join(root, file)));
|
|
159
|
+
const source = (await Promise.all(sourceFiles.map((file) => readFile(path.join(root, file), "utf8")))).join("\n");
|
|
160
|
+
if (!/ConfigProvider/.test(source) || !/yssTheme/.test(source)) errors.push("原型入口必须通过 ConfigProvider 消费 yssTheme");
|
|
161
|
+
if (!existsSync(path.join(root, "yss-prototype-adapter.json"))) errors.push("缺少 yss-prototype-adapter.json");
|
|
162
|
+
return { errors };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function args(argv) {
|
|
166
|
+
const result = { _: [] };
|
|
167
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
168
|
+
const item = argv[index];
|
|
169
|
+
if (!item.startsWith("--")) { result._.push(item); continue; }
|
|
170
|
+
const key = item.slice(2);
|
|
171
|
+
const value = argv[index + 1];
|
|
172
|
+
if (!value || value.startsWith("--")) result[key] = true;
|
|
173
|
+
else { result[key] = value; index += 1; }
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function loadYaml(file) {
|
|
179
|
+
const document = parseDocument(await readFile(file, "utf8"), { uniqueKeys: true });
|
|
180
|
+
if (document.errors.length > 0) throw new TypeError(document.errors[0].message);
|
|
181
|
+
return document.toJS({ maxAliasCount: 0 });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function main(argv) {
|
|
185
|
+
const parsed = args(argv);
|
|
186
|
+
const command = parsed._[0];
|
|
187
|
+
if (command === "prepare") {
|
|
188
|
+
const result = await preparePrototype({ projectRoot: parsed["project-root"], root: parsed.root, feature: parsed.feature, targetAntdVersion: parsed["target-antd-version"], pnpmVersion: parsed["pnpm-version"] });
|
|
189
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (command === "validate-project") {
|
|
193
|
+
const result = await validatePrototypeProject({ root: parsed.root, targetAntdVersion: parsed["target-antd-version"] });
|
|
194
|
+
if (result.errors.length > 0) throw new TypeError(result.errors.join("\n"));
|
|
195
|
+
process.stdout.write("prototype project contract passed\n");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (command === "validate-evidence") {
|
|
199
|
+
const result = validatePrototypeEvidence(await loadYaml(parsed._[1]), { allowTemplate: Boolean(parsed["allow-template"]), allowLegacy: Boolean(parsed["allow-legacy"]) });
|
|
200
|
+
if (result.errors.length > 0) throw new TypeError(result.errors.join("\n"));
|
|
201
|
+
process.stdout.write(`prototype evidence passed${result.warnings.length ? ` with warnings: ${result.warnings.join(", ")}` : ""}\n`);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
throw new TypeError("usage: prototype-contract.mjs prepare|validate-project|validate-evidence ...");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (import.meta.url === pathToFileURL(process.argv[1]).href) main(process.argv.slice(2)).catch((error) => { process.stderr.write(`${error.message}\n`); process.exitCode = 1; });
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtemp, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import {
|
|
7
|
+
preparePrototype,
|
|
8
|
+
validatePrototypeEvidence,
|
|
9
|
+
validatePrototypeProject
|
|
10
|
+
} from "../scripts/prototype-contract.mjs";
|
|
11
|
+
|
|
12
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), "yss-prototype-contract-"));
|
|
13
|
+
const projectRoot = path.join(tempRoot, "project");
|
|
14
|
+
const feature = "order-review";
|
|
15
|
+
const prototypeRoot = path.join(projectRoot, "docs/.scratch", feature, "design/prototypes");
|
|
16
|
+
await mkdir(path.join(prototypeRoot, "src"), { recursive: true });
|
|
17
|
+
await mkdir(path.join(projectRoot, "docs/design/tokens"), { recursive: true });
|
|
18
|
+
await writeFile(path.join(prototypeRoot, "package.json"), JSON.stringify({
|
|
19
|
+
name: "order-review-prototype",
|
|
20
|
+
private: true,
|
|
21
|
+
type: "module",
|
|
22
|
+
scripts: { build: "vite build" },
|
|
23
|
+
dependencies: { react: "19.2.0", "react-dom": "19.2.0", vite: "6.4.2" }
|
|
24
|
+
}, null, 2));
|
|
25
|
+
await writeFile(path.join(projectRoot, "docs/design/tokens/theme.json"), JSON.stringify({
|
|
26
|
+
algorithm: "default",
|
|
27
|
+
token: {
|
|
28
|
+
colorPrimary: "#3371ff",
|
|
29
|
+
borderRadius: 6,
|
|
30
|
+
controlHeight: 32,
|
|
31
|
+
layoutHeaderHeight: 64
|
|
32
|
+
}
|
|
33
|
+
}, null, 2));
|
|
34
|
+
|
|
35
|
+
const before = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.2" });
|
|
36
|
+
assert(before.errors.some((message) => message.includes("antd")), "RED: starter without antd must fail");
|
|
37
|
+
assert(before.errors.some((message) => message.includes("pnpm-lock.yaml")), "RED: missing pnpm lockfile must fail");
|
|
38
|
+
|
|
39
|
+
await preparePrototype({ projectRoot, root: prototypeRoot, feature, targetAntdVersion: "6.6.2", pnpmVersion: "10.15.0" });
|
|
40
|
+
const pkg = JSON.parse(await readFile(path.join(prototypeRoot, "package.json"), "utf8"));
|
|
41
|
+
assert.equal(pkg.dependencies.antd, "6.6.2");
|
|
42
|
+
assert.equal(pkg.packageManager, "pnpm@10.15.0");
|
|
43
|
+
assert.match(await readFile(path.join(prototypeRoot, "src/yss-theme.js"), "utf8"), /compactAlgorithm/);
|
|
44
|
+
|
|
45
|
+
await writeFile(path.join(prototypeRoot, "pnpm-lock.yaml"), "lockfileVersion: '9.0'\n");
|
|
46
|
+
await writeFile(path.join(prototypeRoot, "src/App.jsx"), [
|
|
47
|
+
'import { ConfigProvider, Button } from "antd";',
|
|
48
|
+
'import { yssTheme } from "./yss-theme.js";',
|
|
49
|
+
'export function App() { return <ConfigProvider theme={yssTheme}><Button type="primary">提交</Button></ConfigProvider>; }'
|
|
50
|
+
].join("\n"));
|
|
51
|
+
const after = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.2" });
|
|
52
|
+
assert.deepEqual(after.errors, []);
|
|
53
|
+
|
|
54
|
+
const wrongTarget = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.1" });
|
|
55
|
+
assert(wrongTarget.errors.some((message) => message.includes("精确锁定 antd 6.6.1")), "target 与实际 antd 版本不一致必须失败");
|
|
56
|
+
|
|
57
|
+
const npmPackage = structuredClone(pkg);
|
|
58
|
+
npmPackage.packageManager = "npm@11.0.0";
|
|
59
|
+
await writeFile(path.join(prototypeRoot, "package.json"), JSON.stringify(npmPackage, null, 2));
|
|
60
|
+
const npmProject = await validatePrototypeProject({ root: prototypeRoot, targetAntdVersion: "6.6.2" });
|
|
61
|
+
assert(npmProject.errors.some((message) => message.includes("packageManager")), "原型包管理器漂移到 npm 必须失败");
|
|
62
|
+
await writeFile(path.join(prototypeRoot, "package.json"), JSON.stringify(pkg, null, 2));
|
|
63
|
+
|
|
64
|
+
await assert.rejects(
|
|
65
|
+
preparePrototype({
|
|
66
|
+
projectRoot,
|
|
67
|
+
root: path.join(projectRoot, "prototypes", feature),
|
|
68
|
+
feature,
|
|
69
|
+
targetAntdVersion: "6.6.2",
|
|
70
|
+
pnpmVersion: "10.15.0"
|
|
71
|
+
}),
|
|
72
|
+
/docs\/.scratch/,
|
|
73
|
+
"非标准原型目录必须被拒绝"
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const validEvidence = {
|
|
77
|
+
schema_version: 2,
|
|
78
|
+
feature,
|
|
79
|
+
prototype_ref: `docs/.scratch/${feature}/design/prototypes/index.html`,
|
|
80
|
+
prototype_stack: {
|
|
81
|
+
framework: "react",
|
|
82
|
+
package_manager: "pnpm",
|
|
83
|
+
package_manifest_ref: `docs/.scratch/${feature}/design/prototypes/package.json`,
|
|
84
|
+
lockfile_ref: `docs/.scratch/${feature}/design/prototypes/pnpm-lock.yaml`,
|
|
85
|
+
source_entry_ref: `docs/.scratch/${feature}/design/prototypes/src/App.jsx`,
|
|
86
|
+
build_entry_ref: `docs/.scratch/${feature}/design/prototypes/dist/index.html`,
|
|
87
|
+
build_command: "pnpm build",
|
|
88
|
+
build_result: "passed",
|
|
89
|
+
actual_antd_version: "6.6.2"
|
|
90
|
+
},
|
|
91
|
+
design_baseline: {
|
|
92
|
+
design_standard: "ant-design-v6",
|
|
93
|
+
project_design_ref: "docs/design/design.md",
|
|
94
|
+
project_token_refs: ["docs/design/tokens/theme.json"],
|
|
95
|
+
theme_adapter_ref: `docs/.scratch/${feature}/design/prototypes/src/yss-theme.js`,
|
|
96
|
+
project_override_reviewed: true
|
|
97
|
+
},
|
|
98
|
+
visual_semantic_mapping: {
|
|
99
|
+
runtime_component_library: "ant-design-vue-4.x",
|
|
100
|
+
runtime_version_source: "implementation-lockfile",
|
|
101
|
+
components: [{
|
|
102
|
+
semantic_role: "primary-action",
|
|
103
|
+
antd_v6_component: "Button",
|
|
104
|
+
project_token_refs: ["colorPrimary"],
|
|
105
|
+
yss_or_antdv_target: "YButton",
|
|
106
|
+
state_mapping: ["default", "hover", "active", "disabled", "loading"],
|
|
107
|
+
react_only_api_not_copied: true,
|
|
108
|
+
verification_ref: "verification/button-states.png"
|
|
109
|
+
}]
|
|
110
|
+
},
|
|
111
|
+
antd: { target_antd_version: "6.6.2", queries: { design_md: "verification/antd-design.json", components: [] } },
|
|
112
|
+
browser_verification: { rendered_nonblank: true, viewports: [], main_flow_result: "passed", failure_permission_or_conflict_result: "passed", console_error_ref: "verification/console.txt" },
|
|
113
|
+
design_qa: { report_ref: `docs/.scratch/${feature}/verification/design-qa.md`, result: "passed" },
|
|
114
|
+
accessibility_verification: {
|
|
115
|
+
contrast_results_ref: "verification/contrast.json",
|
|
116
|
+
keyboard_navigation_result: "passed",
|
|
117
|
+
focus_visible_and_order_result: "passed",
|
|
118
|
+
semantic_label_dialog_result: "passed",
|
|
119
|
+
zoom_200_result: "passed",
|
|
120
|
+
reduced_motion_result: "passed",
|
|
121
|
+
target_size_result: "passed",
|
|
122
|
+
automated_scan: { tool: "axe", version: "4", result: "passed", ref: "verification/axe.json" }
|
|
123
|
+
},
|
|
124
|
+
review: { prototype_review_ref: "design/review.md", result: "approved" },
|
|
125
|
+
user_confirmation: { confirmation_ref: "design/confirmation.md", result: "approved" },
|
|
126
|
+
blockers: []
|
|
127
|
+
};
|
|
128
|
+
assert.deepEqual(validatePrototypeEvidence(validEvidence).errors, []);
|
|
129
|
+
|
|
130
|
+
const missingMapping = structuredClone(validEvidence);
|
|
131
|
+
delete missingMapping.visual_semantic_mapping;
|
|
132
|
+
assert(validatePrototypeEvidence(missingMapping).errors.some((message) => message.includes("visual_semantic_mapping")));
|
|
133
|
+
|
|
134
|
+
const copiedReactApi = structuredClone(validEvidence);
|
|
135
|
+
copiedReactApi.visual_semantic_mapping.components[0].react_only_api_not_copied = false;
|
|
136
|
+
assert(validatePrototypeEvidence(copiedReactApi).errors.some((message) => message.includes("React-only")));
|
|
137
|
+
|
|
138
|
+
const inaccessible = structuredClone(validEvidence);
|
|
139
|
+
inaccessible.accessibility_verification.contrast_results_ref = "";
|
|
140
|
+
assert(validatePrototypeEvidence(inaccessible).errors.some((message) => message.includes("contrast_results_ref")));
|
|
141
|
+
|
|
142
|
+
const wrongQaRoot = structuredClone(validEvidence);
|
|
143
|
+
wrongQaRoot.design_qa.report_ref = "docs/design/design-qa.md";
|
|
144
|
+
assert(validatePrototypeEvidence(wrongQaRoot).errors.some((message) => message.includes("design_qa.report_ref")));
|
|
145
|
+
|
|
146
|
+
const versionMismatch = structuredClone(validEvidence);
|
|
147
|
+
versionMismatch.antd.target_antd_version = "6.6.1";
|
|
148
|
+
assert(validatePrototypeEvidence(versionMismatch).errors.some((message) => message.includes("target_antd_version")));
|
|
149
|
+
|
|
150
|
+
const unresolvedBlocker = structuredClone(validEvidence);
|
|
151
|
+
unresolvedBlocker.blockers = ["缺少权限失败态"];
|
|
152
|
+
assert(validatePrototypeEvidence(unresolvedBlocker).errors.some((message) => message.includes("blockers")));
|
|
153
|
+
|
|
154
|
+
process.stdout.write("YSS prototype contract scenarios passed\n");
|
|
@@ -15,7 +15,7 @@ Use this reference when multiple YSS skills seem applicable.
|
|
|
15
15
|
- `yss-use-table-height`: Only table available-height calculation and required container/pagination/toolbar wiring.
|
|
16
16
|
- `yss-use-tree-height`: Only tree available-height calculation, search offset, and virtual scrolling wiring.
|
|
17
17
|
|
|
18
|
-
Default for a new page: first verify the approved product design, state matrix, Ant Design v6 high-fidelity HTML prototype,
|
|
18
|
+
Default for a new page: first verify the approved product design, state matrix, Ant Design v6 theme/visual-standard high-fidelity HTML prototype, schema v2 semantic mapping/browser/accessibility evidence, and user confirmation; then use the implementation lockfile to map into YSS UI + Ant Design Vue 4.x, start with `yss-page-module-development`, and add the narrow skills that match the page controls.
|
|
19
19
|
|
|
20
20
|
中文说明:新建页面默认从页面模块技能开始,只有遇到具体组件、Hook、API、Formily 细节时再加载专项技能。
|
|
21
21
|
|
|
@@ -68,7 +68,7 @@ slice_contract_required:
|
|
|
68
68
|
root: [schema_version, contract_id, contract_version, slice_id, status, lifecycle_refs, readiness, common, frontend, backend, contract, cross_repo, work_units]
|
|
69
69
|
lifecycle_refs: [spec, ticket, requirement_freeze, low_fidelity_review, prototype_review, high_fidelity_html, prototype_verification, antd_cli_evidence, browser_verification_evidence, prototype_confirmation, openapi_freeze_or_no_impact, architecture_review, data_architecture, tactical_design, engineering_baseline, build_architecture_checklist, implementation_repository, frontend_repository, backend_repository, maven_wrapper]
|
|
70
70
|
readiness: [blockers, stale_inputs, not_applicable]
|
|
71
|
-
common: [impacted_areas, implementation_path_policy, project_roots, required_skills, optional_skills, unavailable_skills, allowed_write_paths, forbidden_patterns, expected_evidence_files, verification_commands, human_review_points, full_reroute_triggers]
|
|
71
|
+
common: [impacted_areas, implementation_path_policy, project_roots, required_skills, optional_skills, unavailable_skills, allowed_write_paths, forbidden_patterns, expected_evidence_files, verification_commands, human_review_points, full_reroute_triggers, quality_baseline_ref, context_plan, doubt_driven_review]
|
|
72
72
|
frontend: [status, required_skills, approved_prototype_ref, state_matrix_ref, allowed_write_paths, component_test_seams, e2e_paths]
|
|
73
73
|
backend: [status, affected_layers, component_impacts, required_skills, application_boundary, transaction_boundary, persistence_strategy, allowed_write_paths, forbidden_patterns, expected_evidence_files, seam_deferred, verification_commands, tactical_ddd]
|
|
74
74
|
contract: [api_impact, freeze_ref, no_api_impact_ref, generated_clients, contract_tests, regeneration_commands]
|
|
@@ -100,7 +100,12 @@ work_unit_required: [id, behavior, primary_skill, supporting_skills, tdd_mode, a
|
|
|
100
100
|
work_unit_nonempty_arrays: [allowed_write_paths, expected_evidence, verification_commands]
|
|
101
101
|
slice_contract_nonempty: [contract_id, contract_version, slice_id, status]
|
|
102
102
|
slice_contract_array_fields:
|
|
103
|
-
common: [impacted_areas, implementation_path_policy, project_roots, required_skills, allowed_write_paths, forbidden_patterns, expected_evidence_files, verification_commands, full_reroute_triggers]
|
|
103
|
+
common: [impacted_areas, implementation_path_policy, project_roots, required_skills, allowed_write_paths, forbidden_patterns, expected_evidence_files, verification_commands, full_reroute_triggers, quality_baseline_ref, context_plan, doubt_driven_review]
|
|
104
|
+
|
|
105
|
+
context_plan:
|
|
106
|
+
required: [required_context_refs, on_demand_context_refs, context_stop_rule, missing_context_action]
|
|
107
|
+
context_stop_rule: minimal-sufficient-evidence
|
|
108
|
+
missing_context_action: [blocked, reroute]
|
|
104
109
|
|
|
105
110
|
scaffold_contract_schema:
|
|
106
111
|
schema_version: 1
|
|
@@ -241,6 +246,7 @@ full_reroute_triggers:
|
|
|
241
246
|
- test-seam-changed
|
|
242
247
|
- verification-command-changed
|
|
243
248
|
- delivery-order-changed
|
|
249
|
+
- doubt-review-triggered
|
|
244
250
|
|
|
245
251
|
reroute_destinations:
|
|
246
252
|
scaffold-baseline-drift: stage7-scaffold-revalidation
|
|
@@ -258,9 +264,30 @@ reroute_destinations:
|
|
|
258
264
|
test-seam-changed: spec-ticket-test-seam-review
|
|
259
265
|
verification-command-changed: stage7-contract-recompile
|
|
260
266
|
delivery-order-changed: cross-repo-release-review
|
|
267
|
+
doubt-review-triggered: high-risk-decision-review
|
|
268
|
+
|
|
269
|
+
doubt_driven_review:
|
|
270
|
+
applies_when:
|
|
271
|
+
- api-schema-impact
|
|
272
|
+
- database-schema-impact
|
|
273
|
+
- cross-repo-contract
|
|
274
|
+
- release-or-rollback
|
|
275
|
+
- authentication-authorization-tenant-or-sensitive-data-behavior
|
|
276
|
+
- lifecycle-or-generation-semantics
|
|
277
|
+
required: [claim, counterclaim, evidence_refs, residual_risks, reviewer_ref]
|
|
278
|
+
status_values: [not-applicable, required, completed, blocked]
|
|
279
|
+
blocking_when: [missing-counterclaim, insufficient-evidence, unresolved-residual-risk]
|
|
280
|
+
evidence_owner: decision-or-review-record
|
|
281
|
+
no_new_lifecycle_stage: true
|
|
282
|
+
|
|
283
|
+
quality_baseline:
|
|
284
|
+
source: lifecycle_refs.engineering_baseline
|
|
285
|
+
required_for: [project-instance]
|
|
286
|
+
reused_by: [slice-contract, yss-skill-execution-result, code-review, release]
|
|
287
|
+
redefinition: forbidden
|
|
261
288
|
|
|
262
289
|
execution_result_allowed_statuses: [implemented, seam-deferred, drift, violation, not-applicable]
|
|
263
|
-
execution_blockers: [path-outside-contract, missing-evidence, verification-not-executed, verification-command-mismatch, seam-deferred-without-owner, constraint-failed, unapproved-deviation, drift, violation, new-impacts]
|
|
290
|
+
execution_blockers: [path-outside-contract, missing-evidence, verification-not-executed, verification-command-mismatch, seam-deferred-without-owner, constraint-failed, doubt-review-missing, unapproved-deviation, drift, violation, new-impacts]
|
|
264
291
|
|
|
265
292
|
contract_versioning:
|
|
266
293
|
full_reroute_current_status: stale
|
|
@@ -54,6 +54,20 @@ slice_contract:
|
|
|
54
54
|
verification_commands: []
|
|
55
55
|
human_review_points: []
|
|
56
56
|
full_reroute_triggers: []
|
|
57
|
+
quality_baseline_ref:
|
|
58
|
+
context_plan:
|
|
59
|
+
required_context_refs: []
|
|
60
|
+
on_demand_context_refs: []
|
|
61
|
+
context_stop_rule: minimal-sufficient-evidence
|
|
62
|
+
missing_context_action: blocked # or reroute
|
|
63
|
+
doubt_driven_review:
|
|
64
|
+
status: not-applicable # or required / completed / blocked
|
|
65
|
+
trigger_impacts: []
|
|
66
|
+
claim:
|
|
67
|
+
counterclaim:
|
|
68
|
+
evidence_refs: []
|
|
69
|
+
residual_risks: []
|
|
70
|
+
reviewer_ref:
|
|
57
71
|
frontend:
|
|
58
72
|
status: not-applicable
|
|
59
73
|
required_skills: []
|