create-yss-spec 2.1.3 → 2.1.4
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/code-review/SKILL.md +38 -10
- package/template/.agents/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.agents/skills/yss-design-system/SKILL.md +1 -1
- package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.agents/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.agents/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.agents/skills/yss-router/SKILL.md +2 -2
- package/template/.agents/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.agents/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.claude/skills/code-review/SKILL.md +38 -10
- package/template/.claude/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.claude/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.claude/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.claude/skills/yss-design-system/SKILL.md +1 -1
- package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.claude/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.claude/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.claude/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.claude/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.claude/skills/yss-router/SKILL.md +2 -2
- package/template/.claude/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.claude/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.codex/skills/code-review/SKILL.md +38 -10
- package/template/.codex/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.codex/skills/yss-design-system/SKILL.md +1 -1
- package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.codex/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.codex/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.codex/skills/yss-router/SKILL.md +2 -2
- package/template/.codex/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.codex/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.hermes/skills/code-review/SKILL.md +38 -10
- package/template/.hermes/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.hermes/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.hermes/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.hermes/skills/yss-design-system/SKILL.md +1 -1
- package/template/.hermes/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.hermes/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.hermes/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.hermes/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.hermes/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.hermes/skills/yss-router/SKILL.md +2 -2
- package/template/.hermes/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.hermes/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.pi/skills/code-review/SKILL.md +38 -10
- package/template/.pi/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.pi/skills/yss-design-system/SKILL.md +1 -1
- package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.pi/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.pi/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.pi/skills/yss-router/SKILL.md +2 -2
- package/template/.pi/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.pi/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.qoder/skills/code-review/SKILL.md +38 -10
- package/template/.qoder/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.qoder/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.qoder/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.qoder/skills/yss-design-system/SKILL.md +1 -1
- package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.qoder/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.qoder/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.qoder/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.qoder/skills/yss-router/SKILL.md +2 -2
- package/template/.qoder/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.qoder/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.trae/skills/code-review/SKILL.md +38 -10
- package/template/.trae/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.trae/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.trae/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.trae/skills/yss-design-system/SKILL.md +1 -1
- package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.trae/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.trae/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.trae/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.trae/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.trae/skills/yss-router/SKILL.md +2 -2
- package/template/.trae/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.trae/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/AGENTS.md +6 -4
- package/template/CONTEXT.md +15 -1
- package/template/README.md +2 -1
- package/template/__yss_dotfile__.gitignore +4 -0
- package/template/docs/adr/0003-machine-readable-lifecycle-registry.md +5 -0
- package/template/docs/adr/0004-split-lifecycle-and-router-registry-domains.md +5 -0
- package/template/docs/adr/0005-cross-repository-ecosystem-release-manifest.md +5 -0
- package/template/docs/adr/0006-stable-lifecycle-ids-and-generated-structure.md +5 -0
- package/template/docs/adr/0007-separate-skill-routing-registry-from-integrity-lock.md +5 -0
- package/template/docs/agents/issue-tracker.md +1 -0
- package/template/docs/api/templates/openapi-draft-review-checklist.md +8 -6
- package/template/docs/api/templates/openapi-freeze-record-template.md +8 -2
- package/template/docs/api/templates/openapi-json-export-record-template.md +60 -0
- package/template/docs/architecture/templates/architecture-review-checklist.md +6 -19
- package/template/docs/architecture/templates/functional-architecture-template.md +4 -4
- package/template/docs/architecture/templates/system-overview-design-template.md +10 -5
- package/template/docs/architecture/templates/tech-design-template.md +4 -11
- package/template/docs/discovery/templates/discovery-template.md +0 -1
- package/template/docs/implementation/create-yss-spec-repository-mode-contract.md +2 -2
- package/template/docs/process/harness-process-tailoring.md +2 -0
- package/template/docs/process/harness-work-unit-map.md +14 -10
- package/template/docs/process/lifecycle-artifact-map.md +75 -39
- package/template/docs/process/lifecycle-registry-baseline.json +61 -0
- package/template/docs/process/lifecycle-registry.yaml +255 -0
- package/template/docs/process/schemas/lifecycle-registry.schema.json +35 -0
- package/template/docs/reviews/lifecycle-registry-phase0-1-red-green-2026-08-17.md +61 -0
- package/template/docs/reviews/matt-yss-p0-ticket-review-git-red-green-2026-08-17.md +91 -0
- package/template/docs/reviews/openapi-skill-primary-source-research-2026-08-16.md +76 -0
- package/template/docs/reviews/openapi-yaml-first-independent-review-2026-08-16.md +121 -0
- package/template/docs/reviews/openapi-yaml-first-pressure-scenarios-2026-08-16.md +191 -0
- package/template/docs/reviews/openapi-yaml-first-red-green-2026-08-16.md +76 -0
- package/template/docs/reviews/openapi-yaml-json-output-independent-review-2026-08-16.md +30 -0
- package/template/docs/reviews/openapi-yaml-json-output-scope-red-green-2026-08-16.md +154 -0
- package/template/docs/reviews/research-create-yss-spec-refresh-2026-08-16.md +164 -0
- package/template/docs/reviews/security-permission-lifecycle-simplification-red-green-2026-08-16.md +43 -0
- package/template/docs/reviews/template-release-review-remediation-red-green-2026-08-17.md +41 -0
- package/template/docs/templates/agent-brief-template.md +2 -2
- package/template/docs/templates/build-architecture-checklist-template.md +3 -4
- package/template/docs/templates/implementation-repo-registry-template.md +0 -2
- package/template/docs/templates/implementation-routing-template.md +6 -6
- package/template/docs/templates/openapi-spec-template.yaml +0 -6
- package/template/docs/templates/review-report-template.md +2 -1
- package/template/docs/templates/spec-delta-template.md +1 -1
- package/template/docs/templates/spec-template.md +0 -1
- package/template/docs/templates/vertical-slice-ticket-template.md +2 -2
- 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 +6 -6
- 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 +3 -3
- 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 +1 -1
- 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 +1 -1
- package/template/scripts/generate-lifecycle-artifacts +26 -0
- package/template/scripts/lifecycle-registry.rb +194 -0
- package/template/scripts/sync-skills +1 -0
- package/template/scripts/test-export-yss-skills.rb +8 -6
- package/template/scripts/test-lifecycle-registry.rb +74 -0
- package/template/scripts/update-skill-lock +1 -0
- package/template/scripts/verify-governance-release +39 -0
- package/template/scripts/verify-lifecycle-registry +67 -0
- package/template/scripts/verify-lifecycle-scenarios +114 -17
- package/template/scripts/verify-matt-yss-integration-scenarios +297 -1
- package/template/scripts/verify-openapi-json-handoff-scenarios +270 -0
- package/template/scripts/verify-openapi-yaml-first-scenarios +120 -0
- package/template/scripts/verify-template +27 -3
- package/template/scripts/verify-yss-router-scenarios +42 -14
- package/template/skills-lock.json +9 -24
- package/template/wiki/raw/skills-lock.json +0 -15
- package/template/wiki/wiki/OpenAPI/345/245/221/347/272/246.md +1 -1
- package/template/wiki/wiki/YSS/345/267/245/347/250/213/346/212/200/350/203/275/344/275/223/347/263/273.md +1 -1
- package/template/yss-public-skills.json +3 -5
- package/template.snapshot.json +4 -4
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.agents/skills/yss-openapi/SKILL.md +0 -116
- package/template/.agents/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.agents/skills/yss-openapi/img.png +0 -0
- package/template/.agents/skills/yss-openapi/img_1.png +0 -0
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.claude/skills/yss-openapi/SKILL.md +0 -116
- package/template/.claude/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.claude/skills/yss-openapi/img.png +0 -0
- package/template/.claude/skills/yss-openapi/img_1.png +0 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.codex/skills/yss-openapi/SKILL.md +0 -116
- package/template/.codex/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.codex/skills/yss-openapi/img.png +0 -0
- package/template/.codex/skills/yss-openapi/img_1.png +0 -0
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.hermes/skills/yss-openapi/SKILL.md +0 -116
- package/template/.hermes/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.hermes/skills/yss-openapi/img.png +0 -0
- package/template/.hermes/skills/yss-openapi/img_1.png +0 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.pi/skills/yss-openapi/SKILL.md +0 -116
- package/template/.pi/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.pi/skills/yss-openapi/img.png +0 -0
- package/template/.pi/skills/yss-openapi/img_1.png +0 -0
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.qoder/skills/yss-openapi/SKILL.md +0 -116
- package/template/.qoder/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.qoder/skills/yss-openapi/img.png +0 -0
- package/template/.qoder/skills/yss-openapi/img_1.png +0 -0
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.trae/skills/yss-openapi/SKILL.md +0 -116
- package/template/.trae/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.trae/skills/yss-openapi/img.png +0 -0
- package/template/.trae/skills/yss-openapi/img_1.png +0 -0
|
@@ -175,7 +175,7 @@ skills 是让 AI 按规程工作的“操作手册”,不是关键词装饰。
|
|
|
175
175
|
- 因为是 YSS 项目就一次性加载所有 YSS skills。
|
|
176
176
|
- 把 `需求澄清` 用来重复机会探索,而不是在正式变更中做技术方案。
|
|
177
177
|
- 有 UI 的功能从 Spec 初稿直接跳 OpenAPI,跳过页面、原型、状态矩阵和 `prototype-review`。
|
|
178
|
-
- 在 OpenAPI Freeze
|
|
178
|
+
- 在 OpenAPI Freeze 前将 Draft YAML 或手工 JSON 用作生产客户端输入。
|
|
179
179
|
|
|
180
180
|
### 1.5.4 如何使用 agents
|
|
181
181
|
|
|
@@ -804,7 +804,7 @@ TDD 顺序示例:
|
|
|
804
804
|
| 持久化 | `yss-repository`、需要分页/批量/数据源时加 `yss-mybatis` |
|
|
805
805
|
| Web 接口 | `yss-web-controller`、`yss-dto` |
|
|
806
806
|
| 前端页面 | `yss-ui`、`yss-page-module-development`、`api-integration` |
|
|
807
|
-
| OpenAPI client 刷新 | `yss-openapi
|
|
807
|
+
| OpenAPI client 刷新 | `yss-openapi-governance` 从冻结 YAML 派生 JSON,随后 `api-integration` 运行 Orval;只在 Freeze 后或按实现契约刷新时使用 |
|
|
808
808
|
|
|
809
809
|
阶段门禁:
|
|
810
810
|
|
|
@@ -1071,7 +1071,7 @@ docs/user-guide/
|
|
|
1071
1071
|
使用 yss-router。
|
|
1072
1072
|
输入资产:<Spec 路径>、<交互设计路径>、<OpenAPI Freeze 路径或无 API 影响记录>、<架构设计路径>、<垂直切片路径>。
|
|
1073
1073
|
目标:选择最小 YSS 技能集。
|
|
1074
|
-
请说明每个候选技能需要或不需要的理由,尤其是 yss-domain、yss-repository、yss-mybatis、yss-web-controller、yss-ui、api-integration
|
|
1074
|
+
请说明每个候选技能需要或不需要的理由,尤其是 yss-domain、yss-repository、yss-mybatis、yss-web-controller、yss-ui、yss-openapi-governance、api-integration。
|
|
1075
1075
|
边界:不要实现代码,只输出技能路由、实施顺序、测试 seam 和验证建议。
|
|
1076
1076
|
```
|
|
1077
1077
|
|
|
@@ -114,4 +114,4 @@ YSS_SPEC_TEMPLATE_REF=<pinned-commit> npm test
|
|
|
114
114
|
YSS_SPEC_TEMPLATE_REF=<pinned-commit> npm pack --dry-run
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
发布顺序为:模板修复与验证 → CLI 绑定 commit 并完成跨仓库测试 → 独立审查 → 发布 CLI `2.1.
|
|
117
|
+
发布顺序为:模板修复与验证 → CLI 绑定 commit 并完成跨仓库测试 → 独立审查 → 发布 CLI `2.1.4`。任一仓库未通过共同验证时,不声明整体可发布。
|
|
@@ -258,7 +258,7 @@ Competitive Matrix
|
|
|
258
258
|
|
|
259
259
|
| 场景 | 主技能 | 常见补充 |
|
|
260
260
|
|---|---|---|
|
|
261
|
-
| 新建完整 Vue 业务页面 | `yss-ui` | `yss-page-module-development`、`api-integration
|
|
261
|
+
| 新建完整 Vue 业务页面 | `yss-ui` | `yss-page-module-development`、`yss-openapi-governance`、`api-integration` |
|
|
262
262
|
| YTable / YTree / YssFormily 页面 | `yss-ui` | `yss-use-table-height`、`yss-use-tree-height`、`yss-formily` |
|
|
263
263
|
| 从零创建后端服务 | `yss-ddd-scaffold-generator` | 后续接 `yss-domain`、`yss-repository`、`yss-web-controller` |
|
|
264
264
|
| 领域建模和状态规则 | `yss-domain` | `yss-backend-scaffold-domain` |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "optparse"
|
|
5
|
+
require_relative "lifecycle-registry"
|
|
6
|
+
|
|
7
|
+
options = { check: false, write: false, registry: LifecycleRegistry::DEFAULT_REGISTRY }
|
|
8
|
+
OptionParser.new do |parser|
|
|
9
|
+
parser.on("--check", "仅校验派生文档是否与注册表一致") { options[:check] = true }
|
|
10
|
+
parser.on("--write", "写入派生文档的受管结构区") { options[:write] = true }
|
|
11
|
+
parser.on("--registry PATH", "使用指定注册表") { |path| options[:registry] = Pathname.new(path) }
|
|
12
|
+
end.parse!
|
|
13
|
+
|
|
14
|
+
abort("--check 与 --write 不能同时使用") if options[:check] && options[:write]
|
|
15
|
+
|
|
16
|
+
registry = LifecycleRegistry.validate!(LifecycleRegistry.load_registry(options[:registry]))
|
|
17
|
+
targets = [
|
|
18
|
+
[LifecycleRegistry::ROOT.join("docs/process/lifecycle-artifact-map.md"), "<!-- lifecycle-registry:structure:start -->", "<!-- lifecycle-registry:structure:end -->", LifecycleRegistry.render_lifecycle_structure(registry)],
|
|
19
|
+
[LifecycleRegistry::ROOT.join("docs/process/harness-work-unit-map.md"), "<!-- lifecycle-registry:work-units:start -->", "<!-- lifecycle-registry:work-units:end -->", LifecycleRegistry.render_work_units(registry)]
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
targets.each do |path, start_marker, end_marker, rendered|
|
|
23
|
+
LifecycleRegistry.replace_region!(path, start_marker, end_marker, rendered, check: options[:check])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
puts(options[:check] ? "生命周期派生产物与注册表一致" : "生命周期派生产物已更新")
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "json"
|
|
6
|
+
require "digest"
|
|
7
|
+
require "yaml"
|
|
8
|
+
|
|
9
|
+
module LifecycleRegistry
|
|
10
|
+
ROOT = Pathname.new(__dir__).join("..").realpath
|
|
11
|
+
DEFAULT_REGISTRY = ROOT.join("docs/process/lifecycle-registry.yaml")
|
|
12
|
+
DEFAULT_BASELINE = ROOT.join("docs/process/lifecycle-registry-baseline.json")
|
|
13
|
+
ID_PATTERN = /\A(stage|gate|artifact|work-unit|evidence)\.[a-z0-9][a-z0-9-]*\z/
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def load_registry(path = DEFAULT_REGISTRY)
|
|
18
|
+
YAML.safe_load(Pathname.new(path).read, permitted_classes: [], aliases: false)
|
|
19
|
+
rescue Psych::Exception => error
|
|
20
|
+
raise ArgumentError, "无法解析生命周期注册表: #{error.message}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def validate!(registry, baseline: DEFAULT_BASELINE)
|
|
24
|
+
required_top_level = %w[schema_version registry_id status id_policy stages gates artifacts work_units evidence]
|
|
25
|
+
missing = required_top_level - registry.keys
|
|
26
|
+
raise ArgumentError, "生命周期注册表缺少字段: #{missing.join(', ')}" unless missing.empty?
|
|
27
|
+
raise ArgumentError, "仅支持 lifecycle registry schema_version: 1" unless registry["schema_version"] == 1
|
|
28
|
+
raise ArgumentError, "registry_id 必须为 yss.lifecycle" unless registry["registry_id"] == "yss.lifecycle"
|
|
29
|
+
raise ArgumentError, "status 必须为 shadow 或 active" unless %w[shadow active].include?(registry["status"])
|
|
30
|
+
|
|
31
|
+
policy = registry.fetch("id_policy")
|
|
32
|
+
%w[pattern published_ids_immutable baseline deprecated_ids].each do |key|
|
|
33
|
+
raise ArgumentError, "id_policy 缺少字段: #{key}" unless policy.key?(key)
|
|
34
|
+
end
|
|
35
|
+
raise ArgumentError, "published_ids_immutable 必须为 true" unless policy["published_ids_immutable"] == true
|
|
36
|
+
raise ArgumentError, "id_policy.pattern 不符合固定命名空间" unless policy["pattern"] == "^(stage|gate|artifact|work-unit|evidence)\\.[a-z0-9][a-z0-9-]*$"
|
|
37
|
+
raise ArgumentError, "id_policy.baseline 必须指向发布基线" unless policy["baseline"] == "docs/process/lifecycle-registry-baseline.json"
|
|
38
|
+
raise ArgumentError, "deprecated_ids 必须是数组" unless policy["deprecated_ids"].is_a?(Array)
|
|
39
|
+
|
|
40
|
+
ids = {}
|
|
41
|
+
%w[stages gates artifacts work_units evidence].each do |collection|
|
|
42
|
+
records = registry.fetch(collection)
|
|
43
|
+
raise ArgumentError, "#{collection} 必须是非空数组" unless records.is_a?(Array) && !records.empty?
|
|
44
|
+
records.each do |record|
|
|
45
|
+
id = record["id"]
|
|
46
|
+
raise ArgumentError, "#{collection} 中存在无效 ID: #{id.inspect}" unless id.is_a?(String) && id.match?(ID_PATTERN)
|
|
47
|
+
raise ArgumentError, "生命周期 ID 重复: #{id}" if ids.key?(id)
|
|
48
|
+
expected_prefix = collection == "work_units" ? "work-unit." : collection.delete_suffix("s") + "."
|
|
49
|
+
raise ArgumentError, "#{id} 与 #{collection} 类型不匹配" unless id.start_with?(expected_prefix)
|
|
50
|
+
raise ArgumentError, "#{id} 缺少名称" unless record["name"].is_a?(String) && !record["name"].empty?
|
|
51
|
+
ids[id] = collection
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
registry.fetch("gates").each do |gate|
|
|
56
|
+
require_reference!(ids, gate.fetch("stage"), "#{gate["id"]}.stage")
|
|
57
|
+
unless ids[gate.fetch("stage")] == "stages"
|
|
58
|
+
raise ArgumentError, "#{gate["id"]}.stage 必须引用 stage.*"
|
|
59
|
+
end
|
|
60
|
+
evidence = gate.fetch("evidence")
|
|
61
|
+
raise ArgumentError, "#{gate["id"]}.evidence 必须是非空数组" unless evidence.is_a?(Array) && !evidence.empty?
|
|
62
|
+
evidence.each do |reference|
|
|
63
|
+
require_reference!(ids, reference, "#{gate["id"]}.evidence")
|
|
64
|
+
raise ArgumentError, "#{gate["id"]}.evidence 必须引用 evidence.*" unless ids[reference] == "evidence"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
registry.fetch("artifacts").each do |artifact|
|
|
69
|
+
require_reference!(ids, artifact.fetch("stage"), "#{artifact["id"]}.stage")
|
|
70
|
+
raise ArgumentError, "#{artifact["id"]}.stage 必须引用 stage.*" unless ids[artifact.fetch("stage")] == "stages"
|
|
71
|
+
end
|
|
72
|
+
validate_baseline!(registry, ids, Pathname.new(baseline)) if baseline
|
|
73
|
+
registry
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def require_reference!(ids, reference, field)
|
|
77
|
+
raise ArgumentError, "#{field} 引用了不存在的引用: #{reference}" unless ids.key?(reference)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def semantic_projection(registry)
|
|
81
|
+
%w[stages gates artifacts work_units evidence].flat_map do |collection|
|
|
82
|
+
registry.fetch(collection).map do |record|
|
|
83
|
+
{
|
|
84
|
+
"kind" => collection,
|
|
85
|
+
"record" => canonicalize(record)
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
end.sort_by { |entry| entry.fetch("record").fetch("id") }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def canonicalize(value)
|
|
92
|
+
case value
|
|
93
|
+
when Hash
|
|
94
|
+
value.keys.sort.to_h { |key| [key, canonicalize(value.fetch(key))] }
|
|
95
|
+
when Array
|
|
96
|
+
value.map { |item| canonicalize(item) }
|
|
97
|
+
else
|
|
98
|
+
value
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def semantic_digest(registry)
|
|
103
|
+
Digest::SHA256.hexdigest(JSON.generate(semantic_projection(registry)))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def validate_baseline!(registry, ids, baseline_path)
|
|
107
|
+
raise ArgumentError, "缺少生命周期已发布基线: #{baseline_path.relative_path_from(ROOT)}" unless baseline_path.file?
|
|
108
|
+
baseline = JSON.parse(baseline_path.read)
|
|
109
|
+
unless baseline["schema_version"] == 1 && baseline["registry_id"] == registry["registry_id"]
|
|
110
|
+
raise ArgumentError, "生命周期已发布基线版本或 registry_id 不匹配"
|
|
111
|
+
end
|
|
112
|
+
published_ids = baseline["published_ids"]
|
|
113
|
+
raise ArgumentError, "生命周期已发布基线缺少 published_ids" unless published_ids.is_a?(Array) && published_ids.uniq == published_ids
|
|
114
|
+
published_ids.each do |id|
|
|
115
|
+
raise ArgumentError, "生命周期已发布基线包含无效 ID: #{id.inspect}" unless id.is_a?(String) && id.match?(ID_PATTERN)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
active_ids = ids.keys.sort
|
|
119
|
+
deprecated_ids = registry.fetch("id_policy").fetch("deprecated_ids")
|
|
120
|
+
unless deprecated_ids.uniq == deprecated_ids && deprecated_ids.all? { |id| published_ids.include?(id) } && (deprecated_ids & active_ids).empty?
|
|
121
|
+
raise ArgumentError, "deprecated_ids 必须唯一、来自已发布 ID,且不得仍为活跃对象"
|
|
122
|
+
end
|
|
123
|
+
expected_active_ids = (published_ids - deprecated_ids).sort
|
|
124
|
+
raise ArgumentError, "生命周期活跃 ID 与已发布基线不一致;新增、移除或弃用必须先更新发布基线" unless active_ids == expected_active_ids
|
|
125
|
+
raise ArgumentError, "生命周期稳定 ID 的语义快照已变化;不得复用已发布 ID" unless baseline["semantic_sha256"] == semantic_digest(registry)
|
|
126
|
+
rescue JSON::ParserError => error
|
|
127
|
+
raise ArgumentError, "无法解析生命周期已发布基线: #{error.message}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def render_lifecycle_structure(registry)
|
|
131
|
+
lines = []
|
|
132
|
+
lines << "<!-- lifecycle-registry:structure:start -->"
|
|
133
|
+
lines << "> 此结构区由 `docs/process/lifecycle-registry.yaml` 生成。当前为 `#{registry.fetch("status")}` 模式:它校验结构和派生文档,不改变运行时状态 schema 或人工批准语义。"
|
|
134
|
+
lines << ""
|
|
135
|
+
lines << "## 1. 主阶段"
|
|
136
|
+
lines << ""
|
|
137
|
+
lines << "| 稳定 ID | 阶段 | 目标 | 退出标准 |"
|
|
138
|
+
lines << "|---|---|---|---|"
|
|
139
|
+
registry.fetch("stages").each { |stage| lines << "| `#{stage["id"]}` | #{stage["name"]} | #{stage["goal"]} | #{stage["exit_criteria"]} |" }
|
|
140
|
+
lines << ""
|
|
141
|
+
lines << "## 2. 生命周期对象"
|
|
142
|
+
lines << ""
|
|
143
|
+
lines << "门禁是需要裁决的审查点;产物、工作单元和证据不是门禁的同义词。未命中条件的门禁记录 `not-applicable` 及原因,不生成空文档。"
|
|
144
|
+
lines << ""
|
|
145
|
+
lines << "### 2.1 条件门禁"
|
|
146
|
+
lines << ""
|
|
147
|
+
lines << "| 稳定 ID | 门禁 | 所属阶段 | 触发条件 | 必须留下的证据 |"
|
|
148
|
+
lines << "|---|---|---|---|---|"
|
|
149
|
+
registry.fetch("gates").each do |gate|
|
|
150
|
+
evidence = gate.fetch("evidence").map { |id| "`#{id}`" }.join("、")
|
|
151
|
+
lines << "| `#{gate["id"]}` | #{gate["name"]} | `#{gate["stage"]}` | #{gate["trigger"]} | #{evidence} |"
|
|
152
|
+
end
|
|
153
|
+
lines << ""
|
|
154
|
+
lines << "### 2.2 生命周期产物"
|
|
155
|
+
lines << ""
|
|
156
|
+
lines << "| 稳定 ID | 产物 | 所属阶段 | 触发条件 |"
|
|
157
|
+
lines << "|---|---|---|---|"
|
|
158
|
+
registry.fetch("artifacts").each { |artifact| lines << "| `#{artifact["id"]}` | #{artifact["name"]} | `#{artifact["stage"]}` | #{artifact["trigger"]} |" }
|
|
159
|
+
lines << ""
|
|
160
|
+
lines << "### 2.3 执行证据"
|
|
161
|
+
lines << ""
|
|
162
|
+
lines << "| 稳定 ID | 证据 | 说明 |"
|
|
163
|
+
lines << "|---|---|---|"
|
|
164
|
+
registry.fetch("evidence").each { |evidence| lines << "| `#{evidence["id"]}` | #{evidence["name"]} | #{evidence["description"]} |" }
|
|
165
|
+
lines << "<!-- lifecycle-registry:structure:end -->"
|
|
166
|
+
lines.join("\n") + "\n"
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def render_work_units(registry)
|
|
170
|
+
lines = []
|
|
171
|
+
lines << "<!-- lifecycle-registry:work-units:start -->"
|
|
172
|
+
lines << "> 此表由 `docs/process/lifecycle-registry.yaml` 生成;它只描述 `template-source` 的 Harness 工作单元。"
|
|
173
|
+
lines << ""
|
|
174
|
+
lines << "| 稳定 ID | 工作单元 | 输入 | 输出 | 完成条件 |"
|
|
175
|
+
lines << "|---|---|---|---|---|"
|
|
176
|
+
registry.fetch("work_units").each do |unit|
|
|
177
|
+
lines << "| `#{unit["id"]}` | #{unit["name"]} | #{unit["input"]} | #{unit["output"]} | #{unit["completion"]} |"
|
|
178
|
+
end
|
|
179
|
+
lines << "<!-- lifecycle-registry:work-units:end -->"
|
|
180
|
+
lines.join("\n") + "\n"
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def replace_region!(path, start_marker, end_marker, replacement, check: false)
|
|
184
|
+
body = path.read
|
|
185
|
+
expression = /#{Regexp.escape(start_marker)}.*?#{Regexp.escape(end_marker)}\n?/m
|
|
186
|
+
raise ArgumentError, "派生文档缺少生成区: #{path.relative_path_from(ROOT)}" unless body.match?(expression)
|
|
187
|
+
expected = body.sub(expression, replacement)
|
|
188
|
+
if check
|
|
189
|
+
raise ArgumentError, "派生文档与注册表漂移: #{path.relative_path_from(ROOT)};运行 scripts/generate-lifecycle-artifacts --write" unless expected == body
|
|
190
|
+
else
|
|
191
|
+
path.write(expected)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -18,6 +18,7 @@ REMOVED_SKILLS = %w[
|
|
|
18
18
|
yss-quality
|
|
19
19
|
yss-sql-condition
|
|
20
20
|
yss-sql-tpl
|
|
21
|
+
yss-openapi
|
|
21
22
|
].freeze
|
|
22
23
|
|
|
23
24
|
class ExportYssSkillsTest < Minitest::Test
|
|
@@ -31,19 +32,19 @@ class ExportYssSkillsTest < Minitest::Test
|
|
|
31
32
|
stdout, stderr, result = run_export(output)
|
|
32
33
|
|
|
33
34
|
assert result.success?, "#{stdout}\n#{stderr}"
|
|
34
|
-
assert_equal
|
|
35
|
+
assert_equal 44, Dir.glob(output.join("skills", "*").to_s).count { |path| File.directory?(path) }
|
|
35
36
|
|
|
36
37
|
manifest = JSON.parse(output.join(".yss-export-manifest.json").read)
|
|
37
|
-
assert_equal
|
|
38
|
-
assert_operator manifest.fetch("generated_files_sha256").length, :>,
|
|
38
|
+
assert_equal 44, manifest.fetch("skills").length
|
|
39
|
+
assert_operator manifest.fetch("generated_files_sha256").length, :>, 44
|
|
39
40
|
REMOVED_SKILLS.each do |skill_name|
|
|
40
41
|
refute output.join("skills", skill_name).exist?, "removed skill was exported: #{skill_name}"
|
|
41
42
|
end
|
|
42
43
|
|
|
43
44
|
page = JSON.parse(output.join("skills.sh.json").read)
|
|
44
45
|
grouped = page.fetch("groupings").flat_map { |group| group.fetch("skills") }
|
|
45
|
-
assert_equal
|
|
46
|
-
assert_equal
|
|
46
|
+
assert_equal 44, grouped.uniq.length
|
|
47
|
+
assert_equal 44, grouped.length
|
|
47
48
|
|
|
48
49
|
exported_text = Dir.glob(output.join("skills", "**", "*").to_s)
|
|
49
50
|
.select { |path| File.file?(path) }
|
|
@@ -51,7 +52,8 @@ class ExportYssSkillsTest < Minitest::Test
|
|
|
51
52
|
.select(&:valid_encoding?)
|
|
52
53
|
.join("\n")
|
|
53
54
|
REMOVED_SKILLS.each do |skill_name|
|
|
54
|
-
|
|
55
|
+
pattern = Regexp.new("(?<![a-z0-9-])#{Regexp.escape(skill_name)}(?![a-z0-9-])")
|
|
56
|
+
refute_match(pattern, exported_text, "removed skill is still referenced: #{skill_name}")
|
|
55
57
|
end
|
|
56
58
|
|
|
57
59
|
formily_examples = output.join("skills", "yss-formily", "references", "examples.md").read
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "pathname"
|
|
7
|
+
require "tmpdir"
|
|
8
|
+
require "yaml"
|
|
9
|
+
|
|
10
|
+
ROOT = Pathname.new(__dir__).join("..").realpath
|
|
11
|
+
|
|
12
|
+
class LifecycleRegistryTest < Minitest::Test
|
|
13
|
+
def run_command(*command)
|
|
14
|
+
output, status = Open3.capture2e(*command, chdir: ROOT)
|
|
15
|
+
[output, status]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_registry_verifier_and_generated_views_are_current
|
|
19
|
+
output, status = run_command("scripts/verify-lifecycle-registry")
|
|
20
|
+
assert status.success?, output
|
|
21
|
+
|
|
22
|
+
output, status = run_command("scripts/generate-lifecycle-artifacts", "--check")
|
|
23
|
+
assert status.success?, output
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_verifier_rejects_unknown_cross_reference
|
|
27
|
+
Dir.mktmpdir("yss-lifecycle-registry") do |directory|
|
|
28
|
+
registry_path = Pathname.new(directory).join("broken.yaml")
|
|
29
|
+
registry = YAML.safe_load(ROOT.join("docs/process/lifecycle-registry.yaml").read, aliases: false)
|
|
30
|
+
registry.fetch("gates").first.fetch("evidence") << "evidence.unknown"
|
|
31
|
+
registry_path.write(YAML.dump(registry))
|
|
32
|
+
|
|
33
|
+
output, status = run_command("scripts/verify-lifecycle-registry", "--registry", registry_path.to_s)
|
|
34
|
+
refute status.success?, output
|
|
35
|
+
assert_includes output, "不存在的引用"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_verifier_executes_json_schema_and_stable_id_baseline
|
|
40
|
+
Dir.mktmpdir("yss-lifecycle-registry") do |directory|
|
|
41
|
+
schema_broken = Pathname.new(directory).join("schema-broken.yaml")
|
|
42
|
+
semantic_broken = Pathname.new(directory).join("semantic-broken.yaml")
|
|
43
|
+
registry = YAML.safe_load(ROOT.join("docs/process/lifecycle-registry.yaml").read, aliases: false)
|
|
44
|
+
|
|
45
|
+
registry.fetch("stages").first.delete("goal")
|
|
46
|
+
schema_broken.write(YAML.dump(registry))
|
|
47
|
+
output, status = run_command("scripts/verify-lifecycle-registry", "--registry", schema_broken.to_s)
|
|
48
|
+
refute status.success?, output
|
|
49
|
+
assert_includes output, "JSON Schema 校验失败"
|
|
50
|
+
|
|
51
|
+
registry = YAML.safe_load(ROOT.join("docs/process/lifecycle-registry.yaml").read, aliases: false)
|
|
52
|
+
registry.fetch("gates").first["trigger"] = "被静默改变的语义。"
|
|
53
|
+
semantic_broken.write(YAML.dump(registry))
|
|
54
|
+
output, status = run_command("scripts/verify-lifecycle-registry", "--registry", semantic_broken.to_s)
|
|
55
|
+
refute status.success?, output
|
|
56
|
+
assert_includes output, "语义快照已变化"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_policy_documents_do_not_reintroduce_stale_counts
|
|
61
|
+
forbidden_count = /\d+\s*个(?:主阶段|门禁|工作单元|职责点)/
|
|
62
|
+
assert_match forbidden_count, "必须按 8 个主阶段推进"
|
|
63
|
+
|
|
64
|
+
[
|
|
65
|
+
"AGENTS.md",
|
|
66
|
+
"README.md",
|
|
67
|
+
"docs/user-guide/产品生命周期工作流.md",
|
|
68
|
+
".agents/skills/yss-product-lifecycle/SKILL.md"
|
|
69
|
+
].each do |relative_path|
|
|
70
|
+
body = ROOT.join(relative_path).read
|
|
71
|
+
refute_match(forbidden_count, body, relative_path)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "pathname"
|
|
6
|
+
require "yaml"
|
|
7
|
+
|
|
8
|
+
ROOT = Pathname.new(__dir__).join("..").realpath
|
|
9
|
+
failures = []
|
|
10
|
+
|
|
11
|
+
{
|
|
12
|
+
"docs/architecture/templates/system-overview-design-template.md" => "已明确的认证、授权、租户隔离、敏感数据或合规行为",
|
|
13
|
+
"docs/architecture/templates/tech-design-template.md" => "已明确的认证、授权、租户隔离、敏感数据或合规行为"
|
|
14
|
+
}.each do |relative_path, marker|
|
|
15
|
+
body = ROOT.join(relative_path).read
|
|
16
|
+
failures << "#{relative_path} 缺少条件性安全/权限架构承载" unless body.include?(marker)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
{
|
|
20
|
+
"docs/adr/0003-machine-readable-lifecycle-registry.md" => "状态:部分实施(Phase 1)",
|
|
21
|
+
"docs/adr/0004-split-lifecycle-and-router-registry-domains.md" => "状态:proposed",
|
|
22
|
+
"docs/adr/0005-cross-repository-ecosystem-release-manifest.md" => "状态:proposed",
|
|
23
|
+
"docs/adr/0006-stable-lifecycle-ids-and-generated-structure.md" => "状态:部分实施(Phase 1)",
|
|
24
|
+
"docs/adr/0007-separate-skill-routing-registry-from-integrity-lock.md" => "状态:proposed"
|
|
25
|
+
}.each do |relative_path, marker|
|
|
26
|
+
body = ROOT.join(relative_path).read
|
|
27
|
+
failures << "#{relative_path} 未声明当前实现状态" unless body.include?(marker)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
scenario_verifier = ROOT.join("scripts/verify-lifecycle-scenarios").read
|
|
31
|
+
failures << "生命周期场景未校验稳定 ID 映射" unless scenario_verifier.include?("ROUTE_REGISTRY_IDS")
|
|
32
|
+
|
|
33
|
+
unless failures.empty?
|
|
34
|
+
warn failures.join("\n")
|
|
35
|
+
exit 1
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
warn failures.join("\n") unless failures.empty?
|
|
39
|
+
exit(failures.empty? ? 0 : 1)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
require "open3"
|
|
6
|
+
require "optparse"
|
|
7
|
+
require_relative "lifecycle-registry"
|
|
8
|
+
|
|
9
|
+
options = { registry: LifecycleRegistry::DEFAULT_REGISTRY }
|
|
10
|
+
OptionParser.new do |parser|
|
|
11
|
+
parser.on("--registry PATH", "使用指定注册表") { |path| options[:registry] = Pathname.new(path) }
|
|
12
|
+
end.parse!
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
schema_path = LifecycleRegistry::ROOT.join("docs/process/schemas/lifecycle-registry.schema.json")
|
|
16
|
+
schema = JSON.parse(schema_path.read)
|
|
17
|
+
raise ArgumentError, "生命周期注册表 JSON Schema 缺少 schema_version 约束" unless schema.dig("properties", "schema_version", "const") == 1
|
|
18
|
+
json_schema_program = <<~'PYTHON'
|
|
19
|
+
import json
|
|
20
|
+
import sys
|
|
21
|
+
from jsonschema import Draft202012Validator
|
|
22
|
+
|
|
23
|
+
with open(sys.argv[1], encoding="utf-8") as schema_file:
|
|
24
|
+
schema = json.load(schema_file)
|
|
25
|
+
registry = json.load(sys.stdin)
|
|
26
|
+
errors = sorted(Draft202012Validator(schema).iter_errors(registry), key=lambda error: list(error.absolute_path))
|
|
27
|
+
if errors:
|
|
28
|
+
for error in errors:
|
|
29
|
+
location = ".".join(str(part) for part in error.absolute_path) or "<root>"
|
|
30
|
+
print(f"{location}: {error.message}", file=sys.stderr)
|
|
31
|
+
sys.exit(1)
|
|
32
|
+
PYTHON
|
|
33
|
+
registry_json = JSON.generate(LifecycleRegistry.load_registry(options[:registry]))
|
|
34
|
+
output, status = Open3.capture2e("python3", "-c", json_schema_program, schema_path.to_s, stdin_data: registry_json)
|
|
35
|
+
raise ArgumentError, "JSON Schema 校验失败: #{output}" unless status.success?
|
|
36
|
+
registry = LifecycleRegistry.validate!(LifecycleRegistry.load_registry(options[:registry]))
|
|
37
|
+
|
|
38
|
+
if options[:registry] == LifecycleRegistry::DEFAULT_REGISTRY
|
|
39
|
+
command = [LifecycleRegistry::ROOT.join("scripts/generate-lifecycle-artifacts").to_s, "--check"]
|
|
40
|
+
output, status = Open3.capture2e(*command, chdir: LifecycleRegistry::ROOT)
|
|
41
|
+
raise ArgumentError, output unless status.success?
|
|
42
|
+
|
|
43
|
+
tracked_sources = %w[docs/process/lifecycle-registry.yaml docs/process/lifecycle-registry-baseline.json docs/process/schemas/lifecycle-registry.schema.json]
|
|
44
|
+
tracked_sources.each do |relative_path|
|
|
45
|
+
_output, ignored = Open3.capture2e("git", "check-ignore", "-q", relative_path, chdir: LifecycleRegistry::ROOT)
|
|
46
|
+
raise ArgumentError, "权威注册表资产不得被 Git 忽略: #{relative_path}" if ignored.success?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
stale_count_paths = %w[AGENTS.md README.md docs/user-guide/产品生命周期工作流.md .agents/skills/yss-product-lifecycle/SKILL.md docs/process/lifecycle-artifact-map.md docs/process/harness-work-unit-map.md]
|
|
50
|
+
stale_count_paths.each do |relative_path|
|
|
51
|
+
body = LifecycleRegistry::ROOT.join(relative_path).read
|
|
52
|
+
if body.match?(/\d+\s*个(?:主阶段|门禁|工作单元|职责点)/)
|
|
53
|
+
raise ArgumentError, "#{relative_path} 不得手工声明生命周期对象数量;请引用 lifecycle-registry.yaml"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
public_skills = JSON.parse(LifecycleRegistry::ROOT.join("yss-public-skills.json").read)
|
|
58
|
+
groups = public_skills.fetch("groupings").to_h { |group| [group.fetch("title"), group.fetch("skills")] }
|
|
59
|
+
raise ArgumentError, "yss-web-controller 必须在后端分组" unless groups.fetch("后端").include?("yss-web-controller")
|
|
60
|
+
raise ArgumentError, "yss-web-controller 不得在前端分组" if groups.fetch("前端").include?("yss-web-controller")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
puts "生命周期注册表验证通过(#{registry.fetch("status")})"
|
|
64
|
+
rescue ArgumentError, KeyError, JSON::ParserError => error
|
|
65
|
+
warn "生命周期注册表验证失败: #{error.message}"
|
|
66
|
+
exit 1
|
|
67
|
+
end
|