create-yss-spec 3.4.1 → 3.4.3
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 +2 -2
- package/template/.agents/skills/.strategic-design-skills-manifest.json +1 -1
- package/template/.agents/skills/archify/SKILL.md +1 -1
- package/template/.agents/skills/code-review/SKILL.md +12 -8
- package/template/.agents/skills/file-export-download/SKILL.md +1 -1
- package/template/.agents/skills/frontend-commit/SKILL.md +1 -1
- package/template/.agents/skills/java-backend-commit/SKILL.md +1 -1
- package/template/.agents/skills/llm-wiki/SKILL.md +1 -6
- package/template/.agents/skills/lombok/SKILL.md +10 -336
- package/template/.agents/skills/lombok/references/annotation-examples.md +307 -0
- package/template/.agents/skills/maintaining-skills/SKILL.md +2 -1
- package/template/.agents/skills/maintaining-skills/references/authoring.md +27 -0
- package/template/.agents/skills/mapstruct/SKILL.md +11 -318
- package/template/.agents/skills/mapstruct/references/annotation-examples.md +300 -0
- package/template/.agents/skills/page-form-module/SKILL.md +1 -1
- package/template/.agents/skills/page-skeleton/SKILL.md +1 -1
- package/template/.agents/skills/theme-token-usage/SKILL.md +1 -1
- package/template/.agents/skills/to-tickets/SKILL.md +1 -1
- package/template/.agents/skills/using-git-worktrees/SKILL.md +1 -1
- package/template/.agents/skills/wayfinder/SKILL.md +1 -1
- package/template/.agents/skills/yedit-table-usage/SKILL.md +1 -1
- package/template/.agents/skills/yss-api-integration/SKILL.md +1 -1
- package/template/.agents/skills/yss-audit-log/SKILL.md +1 -1
- package/template/.agents/skills/yss-cache/SKILL.md +1 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +15 -2
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
- package/template/.agents/skills/yss-distributed-id/SKILL.md +1 -1
- package/template/.agents/skills/yss-dto/SKILL.md +5 -1
- package/template/.agents/skills/yss-excel-mvc/SKILL.md +1 -1
- package/template/.agents/skills/yss-exception/SKILL.md +5 -1
- package/template/.agents/skills/yss-formily-schema-generator/SKILL.md +1 -1
- package/template/.agents/skills/yss-implementation-contract-compiler/SKILL.md +13 -5
- package/template/.agents/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
- package/template/.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
- package/template/.agents/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
- package/template/.agents/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
- package/template/.agents/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
- package/template/.agents/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
- package/template/.agents/skills/yss-mybatis/SKILL.md +4 -0
- package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +1 -1
- package/template/.agents/skills/yss-openapi-governance/SKILL.md +1 -1
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +4 -4
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +7 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +4 -0
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.agents/skills/yss-product-lifecycle/references/user-decisions.md +23 -3
- package/template/.agents/skills/yss-prototype-stage/SKILL.md +1 -1
- package/template/.agents/skills/yss-repository/SKILL.md +4 -0
- package/template/.agents/skills/yss-research/SKILL.md +1 -1
- package/template/.agents/skills/yss-resilience4j/SKILL.md +1 -1
- package/template/.agents/skills/yss-security-algorithm/SKILL.md +1 -1
- package/template/.agents/skills/yss-tactical-design/SKILL.md +4 -0
- package/template/.agents/skills/yss-technical-design/SKILL.md +4 -0
- package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.agents/skills/yss-ui/SKILL.md +1 -1
- package/template/.agents/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.agents/skills/yss-up-springboot3/SKILL.md +1 -1
- package/template/.agents/skills/yss-use-table-height/SKILL.md +1 -1
- package/template/.agents/skills/yss-use-tree-height/SKILL.md +1 -1
- package/template/.agents/skills/yss-userinfo/SKILL.md +1 -1
- package/template/.agents/skills/yss-validation/SKILL.md +5 -1
- package/template/.agents/skills/yss-web-controller/SKILL.md +5 -1
- package/template/.agents/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
- package/template/.agents/skills/ytable-usage/SKILL.md +1 -1
- package/template/.agents/skills/ytree-usage/SKILL.md +1 -1
- package/template/.codex/skills/archify/SKILL.md +1 -1
- package/template/.codex/skills/code-review/SKILL.md +12 -8
- package/template/.codex/skills/data-analytics/skills/analyze-data-quality/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/build-dashboard/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/build-report/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/design-kpis/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/gather-business-context/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/index/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/jupyter-notebooks/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/kpi-reporting/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/market-sizing/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/metric-diagnostics/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/product-business-analysis/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/spreadsheets/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/validate-data/SKILL.md +1 -1
- package/template/.codex/skills/data-analytics/skills/visualize-data/SKILL.md +1 -1
- package/template/.codex/skills/file-export-download/SKILL.md +1 -1
- package/template/.codex/skills/frontend-commit/SKILL.md +1 -1
- package/template/.codex/skills/java-backend-commit/SKILL.md +1 -1
- package/template/.codex/skills/llm-wiki/SKILL.md +1 -6
- package/template/.codex/skills/lombok/SKILL.md +10 -336
- package/template/.codex/skills/lombok/references/annotation-examples.md +307 -0
- package/template/.codex/skills/maintaining-skills/SKILL.md +2 -1
- package/template/.codex/skills/maintaining-skills/references/authoring.md +27 -0
- package/template/.codex/skills/mapstruct/SKILL.md +11 -318
- package/template/.codex/skills/mapstruct/references/annotation-examples.md +300 -0
- package/template/.codex/skills/page-form-module/SKILL.md +1 -1
- package/template/.codex/skills/page-skeleton/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/audit/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/design-qa/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/get-context/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/ideate/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/image-to-code/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/index/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/prototype/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/research/SKILL.md +1 -1
- package/template/.codex/skills/product-design/skills/user-context/SKILL.md +1 -1
- package/template/.codex/skills/theme-token-usage/SKILL.md +1 -1
- package/template/.codex/skills/to-tickets/SKILL.md +1 -1
- package/template/.codex/skills/using-git-worktrees/SKILL.md +1 -1
- package/template/.codex/skills/wayfinder/SKILL.md +1 -1
- package/template/.codex/skills/yedit-table-usage/SKILL.md +1 -1
- package/template/.codex/skills/yss-api-integration/SKILL.md +1 -1
- package/template/.codex/skills/yss-audit-log/SKILL.md +1 -1
- package/template/.codex/skills/yss-cache/SKILL.md +1 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +15 -2
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
- package/template/.codex/skills/yss-distributed-id/SKILL.md +1 -1
- package/template/.codex/skills/yss-dto/SKILL.md +5 -1
- package/template/.codex/skills/yss-excel-mvc/SKILL.md +1 -1
- package/template/.codex/skills/yss-exception/SKILL.md +5 -1
- package/template/.codex/skills/yss-formily-schema-generator/SKILL.md +1 -1
- package/template/.codex/skills/yss-implementation-contract-compiler/SKILL.md +13 -5
- package/template/.codex/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
- package/template/.codex/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
- package/template/.codex/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
- package/template/.codex/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
- package/template/.codex/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
- package/template/.codex/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
- package/template/.codex/skills/yss-mybatis/SKILL.md +4 -0
- package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +1 -1
- package/template/.codex/skills/yss-openapi-governance/SKILL.md +1 -1
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +4 -4
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +7 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +4 -0
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.codex/skills/yss-product-lifecycle/references/user-decisions.md +23 -3
- package/template/.codex/skills/yss-prototype-stage/SKILL.md +1 -1
- package/template/.codex/skills/yss-repository/SKILL.md +4 -0
- package/template/.codex/skills/yss-research/SKILL.md +1 -1
- package/template/.codex/skills/yss-resilience4j/SKILL.md +1 -1
- package/template/.codex/skills/yss-security-algorithm/SKILL.md +1 -1
- package/template/.codex/skills/yss-tactical-design/SKILL.md +4 -0
- package/template/.codex/skills/yss-technical-design/SKILL.md +4 -0
- package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.codex/skills/yss-ui/SKILL.md +1 -1
- package/template/.codex/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.codex/skills/yss-up-springboot3/SKILL.md +1 -1
- package/template/.codex/skills/yss-use-table-height/SKILL.md +1 -1
- package/template/.codex/skills/yss-use-tree-height/SKILL.md +1 -1
- package/template/.codex/skills/yss-userinfo/SKILL.md +1 -1
- package/template/.codex/skills/yss-validation/SKILL.md +5 -1
- package/template/.codex/skills/yss-web-controller/SKILL.md +5 -1
- package/template/.codex/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
- package/template/.codex/skills/ytable-usage/SKILL.md +1 -1
- package/template/.codex/skills/ytree-usage/SKILL.md +1 -1
- package/template/.cursor/skills/archify/SKILL.md +1 -1
- package/template/.cursor/skills/code-review/SKILL.md +12 -8
- package/template/.cursor/skills/file-export-download/SKILL.md +1 -1
- package/template/.cursor/skills/frontend-commit/SKILL.md +1 -1
- package/template/.cursor/skills/java-backend-commit/SKILL.md +1 -1
- package/template/.cursor/skills/llm-wiki/SKILL.md +1 -6
- package/template/.cursor/skills/lombok/SKILL.md +10 -336
- package/template/.cursor/skills/lombok/references/annotation-examples.md +307 -0
- package/template/.cursor/skills/maintaining-skills/SKILL.md +2 -1
- package/template/.cursor/skills/maintaining-skills/references/authoring.md +27 -0
- package/template/.cursor/skills/mapstruct/SKILL.md +11 -318
- package/template/.cursor/skills/mapstruct/references/annotation-examples.md +300 -0
- package/template/.cursor/skills/page-form-module/SKILL.md +1 -1
- package/template/.cursor/skills/page-skeleton/SKILL.md +1 -1
- package/template/.cursor/skills/theme-token-usage/SKILL.md +1 -1
- package/template/.cursor/skills/to-tickets/SKILL.md +1 -1
- package/template/.cursor/skills/using-git-worktrees/SKILL.md +1 -1
- package/template/.cursor/skills/wayfinder/SKILL.md +1 -1
- package/template/.cursor/skills/yedit-table-usage/SKILL.md +1 -1
- package/template/.cursor/skills/yss-api-integration/SKILL.md +1 -1
- package/template/.cursor/skills/yss-audit-log/SKILL.md +1 -1
- package/template/.cursor/skills/yss-cache/SKILL.md +1 -1
- package/template/.cursor/skills/yss-ddd-scaffold-generator/SKILL.md +15 -2
- package/template/.cursor/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
- package/template/.cursor/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
- package/template/.cursor/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
- package/template/.cursor/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
- package/template/.cursor/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
- package/template/.cursor/skills/yss-distributed-id/SKILL.md +1 -1
- package/template/.cursor/skills/yss-dto/SKILL.md +5 -1
- package/template/.cursor/skills/yss-excel-mvc/SKILL.md +1 -1
- package/template/.cursor/skills/yss-exception/SKILL.md +5 -1
- package/template/.cursor/skills/yss-formily-schema-generator/SKILL.md +1 -1
- package/template/.cursor/skills/yss-implementation-contract-compiler/SKILL.md +13 -5
- package/template/.cursor/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
- package/template/.cursor/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
- package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
- package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
- package/template/.cursor/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
- package/template/.cursor/skills/yss-mybatis/SKILL.md +4 -0
- package/template/.cursor/skills/yss-openapi-draft-review/SKILL.md +1 -1
- package/template/.cursor/skills/yss-openapi-governance/SKILL.md +1 -1
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +4 -4
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +7 -2
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +4 -0
- package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.cursor/skills/yss-product-lifecycle/references/user-decisions.md +23 -3
- package/template/.cursor/skills/yss-prototype-stage/SKILL.md +1 -1
- package/template/.cursor/skills/yss-repository/SKILL.md +4 -0
- package/template/.cursor/skills/yss-research/SKILL.md +1 -1
- package/template/.cursor/skills/yss-resilience4j/SKILL.md +1 -1
- package/template/.cursor/skills/yss-security-algorithm/SKILL.md +1 -1
- package/template/.cursor/skills/yss-tactical-design/SKILL.md +4 -0
- package/template/.cursor/skills/yss-technical-design/SKILL.md +4 -0
- package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.cursor/skills/yss-ui/SKILL.md +1 -1
- package/template/.cursor/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.cursor/skills/yss-up-springboot3/SKILL.md +1 -1
- package/template/.cursor/skills/yss-use-table-height/SKILL.md +1 -1
- package/template/.cursor/skills/yss-use-tree-height/SKILL.md +1 -1
- package/template/.cursor/skills/yss-userinfo/SKILL.md +1 -1
- package/template/.cursor/skills/yss-validation/SKILL.md +5 -1
- package/template/.cursor/skills/yss-web-controller/SKILL.md +5 -1
- package/template/.cursor/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
- package/template/.cursor/skills/ytable-usage/SKILL.md +1 -1
- package/template/.cursor/skills/ytree-usage/SKILL.md +1 -1
- package/template/.pi/skills/archify/SKILL.md +1 -1
- package/template/.pi/skills/code-review/SKILL.md +12 -8
- package/template/.pi/skills/file-export-download/SKILL.md +1 -1
- package/template/.pi/skills/frontend-commit/SKILL.md +1 -1
- package/template/.pi/skills/java-backend-commit/SKILL.md +1 -1
- package/template/.pi/skills/llm-wiki/SKILL.md +1 -6
- package/template/.pi/skills/lombok/SKILL.md +10 -336
- package/template/.pi/skills/lombok/references/annotation-examples.md +307 -0
- package/template/.pi/skills/maintaining-skills/SKILL.md +2 -1
- package/template/.pi/skills/maintaining-skills/references/authoring.md +27 -0
- package/template/.pi/skills/mapstruct/SKILL.md +11 -318
- package/template/.pi/skills/mapstruct/references/annotation-examples.md +300 -0
- package/template/.pi/skills/page-form-module/SKILL.md +1 -1
- package/template/.pi/skills/page-skeleton/SKILL.md +1 -1
- package/template/.pi/skills/theme-token-usage/SKILL.md +1 -1
- package/template/.pi/skills/to-tickets/SKILL.md +1 -1
- package/template/.pi/skills/using-git-worktrees/SKILL.md +1 -1
- package/template/.pi/skills/wayfinder/SKILL.md +1 -1
- package/template/.pi/skills/yedit-table-usage/SKILL.md +1 -1
- package/template/.pi/skills/yss-api-integration/SKILL.md +1 -1
- package/template/.pi/skills/yss-audit-log/SKILL.md +1 -1
- package/template/.pi/skills/yss-cache/SKILL.md +1 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +15 -2
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/application-pom.xml.template +1 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/parent-pom.xml.template +15 -10
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/web-pom.xml.template +3 -3
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +3 -3
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/first-slice-compatibility.test.mjs +5 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/first-slice-verification.test.mjs +5 -2
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.mjs +13 -10
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_first_slice_verification.mjs +2 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/run_scaffold_verification.mjs +35 -3
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/scaffold-generator.test.mjs +1 -1
- package/template/.pi/skills/yss-distributed-id/SKILL.md +1 -1
- package/template/.pi/skills/yss-dto/SKILL.md +5 -1
- package/template/.pi/skills/yss-excel-mvc/SKILL.md +1 -1
- package/template/.pi/skills/yss-exception/SKILL.md +5 -1
- package/template/.pi/skills/yss-formily-schema-generator/SKILL.md +1 -1
- package/template/.pi/skills/yss-implementation-contract-compiler/SKILL.md +13 -5
- package/template/.pi/skills/yss-implementation-contract-compiler/agents/openai.yaml +1 -1
- package/template/.pi/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml +16 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/references/slice-implementation-contract-v2.md +214 -0
- package/template/.pi/skills/yss-implementation-contract-compiler/references/slice-implementation-contract.md +66 -204
- package/template/.pi/skills/yss-layered-mvc-scaffold-generator/SKILL.md +15 -2
- package/template/.pi/skills/yss-layered-mvc-scaffold-generator/scripts/generate_scaffold.mjs +28 -19
- package/template/.pi/skills/yss-layered-mvc-scaffold-generator/scripts/scaffold-generator.test.mjs +10 -10
- package/template/.pi/skills/yss-mybatis/SKILL.md +4 -0
- package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +1 -1
- package/template/.pi/skills/yss-openapi-governance/SKILL.md +1 -1
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +4 -4
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +7 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +4 -0
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +2 -0
- package/template/.pi/skills/yss-product-lifecycle/references/user-decisions.md +23 -3
- package/template/.pi/skills/yss-prototype-stage/SKILL.md +1 -1
- package/template/.pi/skills/yss-repository/SKILL.md +4 -0
- package/template/.pi/skills/yss-research/SKILL.md +1 -1
- package/template/.pi/skills/yss-resilience4j/SKILL.md +1 -1
- package/template/.pi/skills/yss-security-algorithm/SKILL.md +1 -1
- package/template/.pi/skills/yss-tactical-design/SKILL.md +4 -0
- package/template/.pi/skills/yss-technical-design/SKILL.md +4 -0
- package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.pi/skills/yss-ui/SKILL.md +1 -1
- package/template/.pi/skills/yss-ui-business-page-generation/SKILL.md +1 -1
- package/template/.pi/skills/yss-up-springboot3/SKILL.md +1 -1
- package/template/.pi/skills/yss-use-table-height/SKILL.md +1 -1
- package/template/.pi/skills/yss-use-tree-height/SKILL.md +1 -1
- package/template/.pi/skills/yss-userinfo/SKILL.md +1 -1
- package/template/.pi/skills/yss-validation/SKILL.md +5 -1
- package/template/.pi/skills/yss-web-controller/SKILL.md +5 -1
- package/template/.pi/skills/yss-web-controller/scripts/generate_controller.mjs +5 -2
- package/template/.pi/skills/ytable-usage/SKILL.md +1 -1
- package/template/.pi/skills/ytree-usage/SKILL.md +1 -1
- package/template/AGENTS.md +1 -0
- package/template/CONTEXT.md +2 -1
- package/template/docs/agents/backend-architecture-profiles.md +1 -1
- package/template/docs/agents/digital-human-roles.yaml +25 -1
- package/template/docs/agents/issue-tracker.md +2 -0
- package/template/docs/engineering/backend-platforms.json +174 -0
- package/template/docs/engineering/backend-platforms.md +77 -0
- package/template/docs/process/MATT-POCOCK-ENGINEERING-SKILLS.md +1 -0
- package/template/docs/process/harness-process-tailoring.md +9 -1
- package/template/docs/process/lifecycle-artifact-map.md +4 -4
- package/template/docs/process/lifecycle-registry-baseline.json +1 -1
- package/template/docs/process/lifecycle-registry.yaml +4 -4
- package/template/docs/process/schemas/backend-architecture-identity.schema.json +91 -0
- package/template/docs/process/schemas/digital-human-task-package.schema.json +2 -1
- package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +4 -0
- package/template/docs/process/schemas/project-scaffold-contract.schema.json +602 -83
- package/template/docs/process/schemas/scaffold-architecture-decisions.schema.json +323 -39
- package/template/docs/process/schemas/slice-implementation-contract-v3.schema.json +925 -0
- package/template/docs/templates/approval-record-template.yaml +2 -0
- package/template/docs/templates/vertical-slice-ticket-template.md +22 -31
- package/template/scripts/backend-platforms +14 -0
- package/template/scripts/lib/approval-record.mjs +32 -6
- package/template/scripts/lib/approved-execution-context.mjs +31 -8
- package/template/scripts/lib/backend-architecture.mjs +6 -0
- package/template/scripts/lib/backend-platform-provenance.mjs +67 -0
- package/template/scripts/lib/backend-platform-verification.mjs +210 -0
- package/template/scripts/lib/backend-platform.mjs +175 -0
- package/template/scripts/lib/backend-scaffold-prerequisites.mjs +1 -1
- package/template/scripts/lib/decision-continuation.mjs +79 -0
- package/template/scripts/lib/delivery-preflight.mjs +6 -5
- package/template/scripts/lib/digital-human-roles.mjs +10 -0
- package/template/scripts/lib/frontend-delivery-boundary.mjs +3 -0
- package/template/scripts/lib/implementation-contract-compiler.mjs +42 -9
- package/template/scripts/lib/lifecycle-controls.mjs +2 -2
- package/template/scripts/lib/lifecycle-transition.mjs +3 -1
- package/template/scripts/lib/plan-spec-entry.mjs +3 -3
- package/template/scripts/lib/scaffold-local-database.mjs +1 -0
- package/template/scripts/lib/slice-applicability.mjs +10 -0
- package/template/scripts/lib/slice-contract-preparation.mjs +257 -0
- package/template/scripts/lib/slice-contract-views.mjs +52 -0
- package/template/scripts/lib/slice-contract.mjs +211 -0
- package/template/scripts/lib/slice-repositories.mjs +49 -0
- package/template/scripts/lib/slice-task-package.mjs +66 -0
- package/template/scripts/lib/strategic-handoff.mjs +12 -1
- package/template/scripts/lib/task-package.mjs +6 -2
- package/template/scripts/lib/technical-design-boundary.mjs +1 -0
- package/template/scripts/lib/user-decision-reuse.mjs +1 -0
- package/template/scripts/lib/user-decision.mjs +4 -1
- package/template/scripts/preflight-delivery +2 -2
- package/template/scripts/slice-contract +30 -0
- package/template/scripts/verify-backend-platform-matrix +69 -0
- package/template/scripts/verify-scaffold-architecture-decisions +5 -0
- package/template/scripts/verify-user-decision +7 -2
- package/template/skills-lock.json +60 -55
- package/template.snapshot.json +3 -3
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { assertSourceFingerprint } from "./backend-platform-provenance.mjs";
|
|
2
|
+
/** Shared, exact backend platform selection. Catalog entries are maintenance-owned. */
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
export const PLATFORM_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
9
|
+
export const PLATFORM_CATALOG_REF = "docs/engineering/backend-platforms.json";
|
|
10
|
+
export const PLATFORM_SKILLS = ["yss-ddd-scaffold-generator", "yss-layered-mvc-scaffold-generator"];
|
|
11
|
+
const fail = (message) => { throw new TypeError(`backend-platform: ${message}`); };
|
|
12
|
+
const stable = (value) => Array.isArray(value) ? value.map(stable) : value && typeof value === "object" ? Object.fromEntries(Object.keys(value).sort().map(key => [key, stable(value[key])])) : value;
|
|
13
|
+
export const platformDigest = value => `sha256:${createHash("sha256").update(typeof value === "string" || Buffer.isBuffer(value) ? value : JSON.stringify(stable(value ?? null))).digest("hex")}`;
|
|
14
|
+
export function loadBackendPlatforms(root = PLATFORM_ROOT) {
|
|
15
|
+
const value = JSON.parse(readFileSync(path.join(root, PLATFORM_CATALOG_REF), "utf8"));
|
|
16
|
+
if (value.schema_version !== 1 || value.kind !== "backend-platform-catalog" || !Array.isArray(value.profiles) || !Array.isArray(value.compatibility)) fail("invalid catalog");
|
|
17
|
+
if (new Set(value.profiles.map(item => `${item.id}:${item.spring_boot_version}:${item.java_version}`)).size !== value.profiles.length || new Set(value.compatibility.map(item => item.id)).size !== value.compatibility.length) fail("duplicate catalog release/id");
|
|
18
|
+
for (const profile of value.profiles) if (!/^\d+\.\d+\.\d+$/.test(profile.spring_boot_version)) fail("catalog requires exact patch versions");
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
export function platformProfile(id, catalog = loadBackendPlatforms(), version) {
|
|
22
|
+
const matches = catalog.profiles.filter(item => item.id === id && (!version || item.spring_boot_version === version));
|
|
23
|
+
if (matches.length > 1) fail("multiple patches: select an exact spring_boot_version");
|
|
24
|
+
const result = matches[0];
|
|
25
|
+
if (!result) fail(`unsupported platform_profile: ${id}`);
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
export function platformRecipeDigest(profile, entry) {
|
|
29
|
+
const { candidate_blockers, recommended, ...recipe } = profile;
|
|
30
|
+
return platformDigest({ profile: recipe, entry: { id: entry.id, profile_id: entry.profile_id, spring_boot_version: entry.spring_boot_version, parent: entry.parent, bom: entry.bom, components: entry.components ?? {} } });
|
|
31
|
+
}
|
|
32
|
+
export function platformBinding(profile, entry) {
|
|
33
|
+
return { schema_version: 2, profile_id: profile.id, spring_boot_version: profile.spring_boot_version, java_version: profile.java_version, parent: entry.parent, bom: entry.bom, compatibility_id: entry.id, compatibility_digest: platformRecipeDigest(profile, entry) };
|
|
34
|
+
}
|
|
35
|
+
export function resolveBackendPlatform(binding, { catalog = loadBackendPlatforms(), requireVerified = true, root = PLATFORM_ROOT } = {}) {
|
|
36
|
+
if (!binding || binding.schema_version !== 2) fail("missing platform_configuration v2 (v1 is historical read-only); 生命周期须展示 Boot/Java/YSS 组合并取得用户确认");
|
|
37
|
+
const profile = platformProfile(binding.profile_id, catalog, binding.spring_boot_version);
|
|
38
|
+
if (binding.spring_boot_version !== profile.spring_boot_version || binding.java_version !== profile.java_version) fail("unsupported exact Boot/Java combination (x/latest and Java 8/11 for Boot 3.5/4.1 are rejected)");
|
|
39
|
+
const entry = catalog.compatibility.find(item => item.id === binding.compatibility_id);
|
|
40
|
+
const evidenceReports = [];
|
|
41
|
+
if (!entry || entry.profile_id !== profile.id || entry.spring_boot_version !== profile.spring_boot_version) fail("YSS compatibility entry missing; parent/BOM/starter verification required");
|
|
42
|
+
if (platformDigest(binding) !== platformDigest(platformBinding(profile, entry))) fail("stale compatibility digest or YSS coordinates");
|
|
43
|
+
if (requireVerified) {
|
|
44
|
+
if (entry.status !== "verified") fail(`YSS combination ${entry.id} is not verified`);
|
|
45
|
+
if (!Array.isArray(entry.evidence) || !entry.evidence.length) fail("verified combination lacks evidence");
|
|
46
|
+
for (const item of entry.evidence) {
|
|
47
|
+
if (!item.ref || !item.digest || path.isAbsolute(item.ref) || item.ref.split(/[\\/]/).includes("..")) fail("invalid portable evidence reference");
|
|
48
|
+
const bytes = readFileSync(path.join(root, item.ref));
|
|
49
|
+
if (platformDigest(bytes) !== item.digest) fail("compatibility evidence drift");
|
|
50
|
+
const report = JSON.parse(bytes);
|
|
51
|
+
if (report.verification_scope !== "empty-scaffold") fail("qualification requires empty-scaffold evidence");
|
|
52
|
+
if (report.recipe_digest !== platformRecipeDigest(profile, entry)) fail("evidence recipe drift");
|
|
53
|
+
assertSourceFingerprint(report.source_fingerprint, report.architecture_family);
|
|
54
|
+
if (!/^sha256:[a-f0-9]{64}$/.test(report.generated_tree_digest ?? "")) fail("missing generated tree digest");
|
|
55
|
+
evidenceReports.push(report);
|
|
56
|
+
if (report.status !== "passed" || report.spring_boot_version !== profile.spring_boot_version || report.java_version !== profile.java_version || report.architecture_family !== item.architecture_family || platformDigest(report.parent) !== platformDigest(entry.parent) || platformDigest(report.bom) !== platformDigest(entry.bom)) fail("compatibility evidence identity mismatch");
|
|
57
|
+
for (const phase of ["validate", "test", "package"]) if (!report.commands?.some(cmd => cmd.command === `./mvnw ${phase}` && cmd.exit_code === 0 && cmd.stdout_ref && cmd.stderr_ref && cmd.executed_at)) fail("missing real Maven evidence");
|
|
58
|
+
if (report.dependency_check !== "passed" || report.startup_check !== "passed" || report.integration_tests?.status !== "passed") fail("missing dependency/startup/integration-test evidence");
|
|
59
|
+
const required = ["effective-pom.xml", "dependency-trees.json", "platform-tests.xml", "boot-bom-effective.xml", "runtime-jar-entries.log", "startup.stdout.log", "startup.stderr.log", ...["validate", "test", "package"].flatMap(phase => [`mvnw-${phase}.stdout.log`, `mvnw-${phase}.stderr.log`])];
|
|
60
|
+
if (!Array.isArray(report.evidence_artifacts) || required.some(ref => !report.evidence_artifacts.some(artifact => artifact.ref === ref))) fail("missing portable evidence artifacts");
|
|
61
|
+
for (const artifact of report.evidence_artifacts) {
|
|
62
|
+
if (!artifact.ref || path.isAbsolute(artifact.ref) || artifact.ref.split(/[\\/]/).includes("..")) fail("invalid evidence artifact path");
|
|
63
|
+
if (platformDigest(readFileSync(path.join(root, path.dirname(item.ref), artifact.ref))) !== artifact.digest) fail("evidence artifact drift");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { profile, entry, evidenceReports };
|
|
68
|
+
}
|
|
69
|
+
export function assertContractPlatform(contract, decision, options = {}) {
|
|
70
|
+
const binding = contract.platform_configuration;
|
|
71
|
+
const resolved = resolveBackendPlatform(binding, options);
|
|
72
|
+
if (contract.profiles?.platform !== resolved.profile.id || contract.profiles?.validation_namespace !== resolved.profile.validation_namespace) fail("platform and validation_namespace are inconsistent");
|
|
73
|
+
if (platformDigest(contract.maven_coordinates?.parent) !== platformDigest(binding.parent) || contract.maven_coordinates?.yss_components_version !== binding.bom.version || binding.bom.group_id !== "com.yss.cloud" || binding.bom.artifact_id !== "yss-components-bom") fail("YSS Maven coordinates mismatch");
|
|
74
|
+
if (decision && platformDigest(decision.platform_configuration) !== platformDigest(binding)) fail("decision/contract platform_configuration mismatch");
|
|
75
|
+
if (options.requireVerified !== false && !resolved.entry.evidence?.some(item => item.architecture_family === contract.architecture_family)) fail("architecture has no compatibility evidence");
|
|
76
|
+
for (const capability of contract.module_profile?.requested_capabilities ?? []) if (!resolved.entry.capabilities?.includes(capability)) fail(`unverified capability: ${capability}`);
|
|
77
|
+
if (options.requireVerified !== false && !resolved.evidenceReports.some(report => report.architecture_family === contract.architecture_family && (contract.module_profile?.requested_capabilities ?? []).every(capability => report.verified_capabilities?.includes(capability)))) fail("architecture/capability combination lacks evidence");
|
|
78
|
+
return resolved;
|
|
79
|
+
}
|
|
80
|
+
export function assertPlatformAgreement(left, right) {
|
|
81
|
+
if (platformDigest(left) !== platformDigest(right)) fail("platform_configuration drift between contract and Manifest");
|
|
82
|
+
}
|
|
83
|
+
export function javaMajor(output) {
|
|
84
|
+
const value = output.match(/(?:java|openjdk) version "(?:1\.)?(\d+)|Java version:\s*(?:1\.)?(\d+)/i);
|
|
85
|
+
return value ? Number(value[1] ?? value[2]) : null;
|
|
86
|
+
}
|
|
87
|
+
export function assertJavaPlatform(output, binding) {
|
|
88
|
+
if (javaMajor(output) !== binding.java_version) fail(`JDK mismatch: expected Java ${binding.java_version}`);
|
|
89
|
+
}
|
|
90
|
+
export function platformTemplateVars(profile) {
|
|
91
|
+
return { boot_version: profile.spring_boot_version, java_version: profile.java_version === 8 ? "1.8" : String(profile.java_version), java_range: profile.java_version === 8 ? "[1.8,1.9)" : `[${profile.java_version},${profile.java_version + 1})`, web_starter: profile.web_starter, web_test_starter: profile.web_test_starter, aop_starter: profile.aop_starter, swagger_artifact: profile.swagger_artifact, ...Object.fromEntries(Object.entries(profile.versions).map(([key, value]) => [`${key}_version`, value])) };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function platformSmokeTest(basePackage, profile, capabilities = []) {
|
|
95
|
+
const mapper = profile.jackson_major === 3 ? "tools.jackson.databind.json.JsonMapper" : "com.fasterxml.jackson.databind.ObjectMapper";
|
|
96
|
+
return `package ${basePackage};
|
|
97
|
+
|
|
98
|
+
import ${profile.validation_namespace}.validation.Validator;
|
|
99
|
+
import ${profile.validation_namespace}.validation.Valid;
|
|
100
|
+
import org.springframework.beans.factory.annotation.Value;
|
|
101
|
+
import org.springframework.context.annotation.Import;
|
|
102
|
+
import org.springframework.web.bind.annotation.RestController;
|
|
103
|
+
import org.springframework.web.bind.annotation.PostMapping;
|
|
104
|
+
import org.springframework.web.bind.annotation.RequestBody;
|
|
105
|
+
import ${profile.validation_namespace}.validation.constraints.NotBlank;
|
|
106
|
+
import ${mapper};
|
|
107
|
+
import org.apache.ibatis.annotations.Select;
|
|
108
|
+
import org.apache.ibatis.session.SqlSession;
|
|
109
|
+
import org.apache.ibatis.session.SqlSessionFactory;
|
|
110
|
+
import org.junit.jupiter.api.Test;
|
|
111
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
112
|
+
import org.springframework.boot.test.context.SpringBootTest;
|
|
113
|
+
import org.springframework.test.context.ActiveProfiles;
|
|
114
|
+
import static org.junit.jupiter.api.Assertions.*;
|
|
115
|
+
|
|
116
|
+
/** Mechanical integration only: no business endpoint or production storage. */
|
|
117
|
+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
|
118
|
+
@Import(PlatformIntegrationTest.ProbeController.class)
|
|
119
|
+
@ActiveProfiles("scaffold-test")
|
|
120
|
+
class PlatformIntegrationTest {
|
|
121
|
+
@Value("\${local.server.port}") int port;
|
|
122
|
+
@Autowired Validator validator;
|
|
123
|
+
public static class ProbePayload {
|
|
124
|
+
@NotBlank private String value;
|
|
125
|
+
public String getValue() { return value; }
|
|
126
|
+
public void setValue(String value) { this.value = value; }
|
|
127
|
+
}
|
|
128
|
+
@RestController
|
|
129
|
+
public static class ProbeController {
|
|
130
|
+
@PostMapping(value = "/__scaffold_probe", consumes = "application/json", produces = "application/json")
|
|
131
|
+
public ProbePayload echo(@Valid @RequestBody ProbePayload body) { return body; }
|
|
132
|
+
}
|
|
133
|
+
@Test void httpJsonRoundTrip() throws Exception { httpProbe("probe", 200); }
|
|
134
|
+
@Test void httpValidationRejectsBlank() throws Exception { httpProbe("", 400); }
|
|
135
|
+
private void httpProbe(String value, int expectedStatus) throws Exception {
|
|
136
|
+
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) new java.net.URL("http://127.0.0.1:" + port + "/__scaffold_probe").openConnection();
|
|
137
|
+
connection.setConnectTimeout(5000); connection.setReadTimeout(5000);
|
|
138
|
+
connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setDoOutput(true);
|
|
139
|
+
ProbePayload request = new ProbePayload(); request.setValue(value);
|
|
140
|
+
try {
|
|
141
|
+
try (java.io.OutputStream stream = connection.getOutputStream()) { stream.write(mapper.writeValueAsBytes(request)); }
|
|
142
|
+
assertEquals(expectedStatus, connection.getResponseCode());
|
|
143
|
+
if (expectedStatus == 200) {
|
|
144
|
+
assertTrue(connection.getContentType().startsWith("application/json"));
|
|
145
|
+
try (java.io.InputStream stream = connection.getInputStream()) { assertEquals(value, mapper.readValue(stream, ProbePayload.class).getValue()); }
|
|
146
|
+
}
|
|
147
|
+
} finally { connection.disconnect(); }
|
|
148
|
+
}
|
|
149
|
+
@Autowired ${mapper.split(".").at(-1)} mapper;
|
|
150
|
+
@Autowired SqlSessionFactory sqlSessionFactory;
|
|
151
|
+
static final class ValidationProbe { @NotBlank String value = ""; }
|
|
152
|
+
@Test void validationAndJsonAutoConfiguration() throws Exception {
|
|
153
|
+
assertFalse(validator.validate(new ValidationProbe()).isEmpty());
|
|
154
|
+
assertEquals("\\\"probe\\\"", mapper.writeValueAsString("probe"));
|
|
155
|
+
}
|
|
156
|
+
interface ProbeMapper { @Select("SELECT 1") int probe(); }
|
|
157
|
+
@Test void mybatisCanMapVerificationQuery() throws Exception {
|
|
158
|
+
try (SqlSession session = sqlSessionFactory.openSession()) {
|
|
159
|
+
if (!session.getConfiguration().hasMapper(ProbeMapper.class)) session.getConfiguration().addMapper(ProbeMapper.class);
|
|
160
|
+
assertEquals(1, session.getMapper(ProbeMapper.class).probe());
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
${capabilities.includes("feign-client") ? ` @Autowired org.springframework.cloud.openfeign.${profile.java_version === 8 ? "FeignContext" : "FeignClientFactory"} feignFactory;
|
|
164
|
+
@Test void feignCanDecodeJson() throws Exception {
|
|
165
|
+
feign.codec.Decoder decoder = feignFactory.getInstance("platform-probe", feign.codec.Decoder.class);
|
|
166
|
+
assertNotNull(decoder);
|
|
167
|
+
feign.Request request = feign.Request.create(feign.Request.HttpMethod.GET, "http://localhost/probe", java.util.Collections.emptyMap(), (byte[]) null, java.nio.charset.StandardCharsets.UTF_8, null);
|
|
168
|
+
feign.Response response = feign.Response.builder().request(request).status(200).reason("OK")
|
|
169
|
+
.headers(java.util.Collections.singletonMap("Content-Type", java.util.Collections.singletonList("application/json")))
|
|
170
|
+
.body("{}", java.nio.charset.StandardCharsets.UTF_8).build();
|
|
171
|
+
assertTrue(decoder.decode(response, java.util.Map.class) instanceof java.util.Map);
|
|
172
|
+
}
|
|
173
|
+
` : ""}}
|
|
174
|
+
`;
|
|
175
|
+
}
|
|
@@ -102,7 +102,7 @@ export async function validateBackendScaffoldPrerequisites(contract, { contractF
|
|
|
102
102
|
const approvalRef = prerequisites.engineering_contract_approval_ref;
|
|
103
103
|
if (approvalRef !== contract.lifecycle_approval_ref || approvalRef !== contract.approval?.approval_ref) fail("工程合同批准引用与脚手架合同不一致");
|
|
104
104
|
const approvalFile = resolveLocalRef(root, approvalRef, "工程合同批准记录");
|
|
105
|
-
const approval = loadApprovalRecord(approvalFile);
|
|
105
|
+
const approval = loadApprovalRecord(approvalFile, 'gate.engineering-contract-approved');
|
|
106
106
|
validateApprovalRecord(approval, { requireApproved: true, root });
|
|
107
107
|
if (approval.gate_id !== "gate.engineering-contract-approved") fail("工程合同批准记录 gate_id 必须为 gate.engineering-contract-approved");
|
|
108
108
|
if (!Array.isArray(approval.approval_scope) || !approval.approval_scope.includes(contract.contract_id) || !approval.approval_scope.includes(contract.project_name)) fail("工程合同批准范围未覆盖当前合同和项目");
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { decisionIO, decisionDigest, decisionError, assertUserDecisionRequirement } from './user-decision.mjs';
|
|
2
|
+
|
|
3
|
+
export const CONTINUATION_CAPABILITY = 'approved-scope-continuation-v1';
|
|
4
|
+
const fail = message => decisionError('user-decision-continuation-invalid', message);
|
|
5
|
+
const strings = value => Array.isArray(value) && value.length > 0 && value.every(x => typeof x === 'string' && x.trim()) && new Set(value).size === value.length;
|
|
6
|
+
const sameSet = (a, b) => strings(a) && strings(b) && a.length === b.length && a.every(x => b.includes(x));
|
|
7
|
+
const basisFields = ['business_scope', 'acceptance', 'contract_commitments', 'authorization', 'risk_acceptance', 'quality', 'external_commitments'];
|
|
8
|
+
|
|
9
|
+
// A continuation validates an explicit human mandate and an independent current
|
|
10
|
+
// review. It never infers semantic equivalence from whitespace or a boolean flag.
|
|
11
|
+
export function assertDecisionContinuation(requirement, roles, options = {}) {
|
|
12
|
+
const io = decisionIO(options);
|
|
13
|
+
const policy = roles.user_decision_policy.continuation;
|
|
14
|
+
if (policy?.capability !== CONTINUATION_CAPABILITY || !policy.boundaries.includes(requirement.boundary)) fail('未授权的延续边界');
|
|
15
|
+
const proof = io.document(requirement.continuation_ref);
|
|
16
|
+
if (proof.schema_version !== 1 || proof.kind !== CONTINUATION_CAPABILITY || proof.boundary !== requirement.boundary || proof.subject?.ref !== requirement.subject_ref || !sameSet(proof.scope, requirement.scope)) fail('当前边界、资产或范围不匹配');
|
|
17
|
+
const current = (asset, parse = true) => {
|
|
18
|
+
if (!asset?.ref || !asset.version || !asset.digest || decisionDigest(io.bytes(asset.ref)) !== asset.digest) fail(`当前证据缺失或过期: ${asset?.ref}`);
|
|
19
|
+
return parse ? io.document(asset.ref) : null;
|
|
20
|
+
};
|
|
21
|
+
if (!proof.source || proof.source.continuation_ref || proof.source.boundary !== 'delivery-scope') fail('必须引用原始交付范围批准,不能链式扩权');
|
|
22
|
+
const sourceResult = assertUserDecisionRequirement(proof.source, { ...options, rolesDoc: roles });
|
|
23
|
+
const mandate = io.document(proof.source.subject_ref);
|
|
24
|
+
if (mandate.schema_version !== 1 || mandate.kind !== 'delivery-authorization' || !Array.isArray(mandate.targets)) fail('缺少已展示并批准的交付授权清单');
|
|
25
|
+
if (!requirement.scope.every(x => proof.source.scope.includes(x))) fail('超出原始批准范围');
|
|
26
|
+
const matches = mandate.targets.filter(x => x.boundary === requirement.boundary && x.subject_ref === requirement.subject_ref && requirement.scope.every(s => x.scope?.includes(s)));
|
|
27
|
+
if (matches.length !== 1) fail('原授权未唯一覆盖当前边界、资产和范围');
|
|
28
|
+
const target = matches[0];
|
|
29
|
+
if (!basisFields.every(key => strings(target.decision_basis?.[key]))) fail('原授权缺少业务、验收、契约、授权、风险、质量或对外承诺依据');
|
|
30
|
+
if (!Array.isArray(mandate.basis) || !mandate.basis.length) fail('原授权缺少可读取的决定依据');
|
|
31
|
+
for (const asset of mandate.basis) {
|
|
32
|
+
if (!asset.ref || !asset.version || decisionDigest(io.bytes(asset.ref)) !== asset.digest) fail('原授权决定依据变化,须重新决定');
|
|
33
|
+
}
|
|
34
|
+
const external = current(mandate.external_policy);
|
|
35
|
+
if (external.status !== 'confirmed' || !Array.isArray(external.requirements)) fail('项目外部审批要求尚未确认,不能自动延续');
|
|
36
|
+
current(proof.subject, false);
|
|
37
|
+
if (requirement.boundary === 'implementation-scope') {
|
|
38
|
+
const manifest = io.document(proof.subject.ref);
|
|
39
|
+
if (manifest.kind !== 'implementation-scope' || !Array.isArray(manifest.slices)) fail('实施范围清单无效');
|
|
40
|
+
for (const ticket of requirement.scope) {
|
|
41
|
+
const slices = manifest.slices.filter(x => x.ticket_ref === ticket);
|
|
42
|
+
const limit = target.implementation_limits?.[ticket];
|
|
43
|
+
if (slices.length !== 1 || !limit || !sameSet(slices[0].repositories, limit.repositories) || !sameSet(slices[0].allowed_write_paths, limit.allowed_write_paths)) fail('实施仓库或写路径超出原授权边界');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (!Array.isArray(proof.basis) || !proof.basis.length) fail('缺少本次实际验证证据');
|
|
47
|
+
for (const asset of proof.basis) {
|
|
48
|
+
if (!asset.ref || !asset.version || decisionDigest(io.bytes(asset.ref)) !== asset.digest) fail('本次验证证据过期');
|
|
49
|
+
}
|
|
50
|
+
const review = current(proof.review);
|
|
51
|
+
const actor = roles.roles.find(x => x.id === review.role_id);
|
|
52
|
+
if (!actor || !roles.runtimes.some(x => x.id === review.runtime_id) || !review.principal_ref || !review.drafter_principal_ref || review.principal_ref === review.drafter_principal_ref) fail('缺少独立专业审查身份');
|
|
53
|
+
const eligible = roles.gate_policy.continuation_reviews?.[requirement.boundary] || roles.gate_policy.dual_digital_human?.find(x => x.gate === requirement.boundary)?.countersigners;
|
|
54
|
+
if (!eligible?.includes(review.role_id)) fail('审查能力不覆盖当前边界');
|
|
55
|
+
if (review.decision !== 'approved' || !['within-approved-scope', 'presentation-only', 'implementation-detail'].includes(review.classification)) fail('未知或实质变化须重新决定');
|
|
56
|
+
if (!Array.isArray(review.material_changes) || review.material_changes.length || !Array.isArray(review.findings)) fail('存在实质变化或未完成影响分析');
|
|
57
|
+
for (const finding of review.findings) {
|
|
58
|
+
if (!finding.id || !finding.reason || !['requirement-violation', 'missing-evidence', 'important-risk', 'suggestion'].includes(finding.kind)) fail('审查发现未分类');
|
|
59
|
+
if (finding.kind === 'suggestion' && !finding.follow_up) fail('非阻断建议缺少待办去向');
|
|
60
|
+
if (finding.kind !== 'suggestion' && finding.status !== 'resolved') fail('未解决的缺陷、证据缺口或重要风险');
|
|
61
|
+
}
|
|
62
|
+
if (review.boundary !== requirement.boundary || !sameSet(review.scope, requirement.scope) || decisionDigest(review.subject) !== decisionDigest(proof.subject) || decisionDigest(review.basis) !== decisionDigest(proof.basis)) fail('审查未绑定当前资产、范围和验证证据');
|
|
63
|
+
if (decisionDigest(review.decision_basis) !== decisionDigest(target.decision_basis)) fail('决定依据有实质变化');
|
|
64
|
+
if (!review.reason?.trim() || !review.comparison?.before || !review.comparison?.after) fail('缺少可审阅的前后差异和等价性说明');
|
|
65
|
+
// Before is an immutable, originally approved snapshot; after is the current candidate.
|
|
66
|
+
const before = review.comparison.before;
|
|
67
|
+
if (!mandate.basis.some(x => decisionDigest(x) === decisionDigest(before)) || decisionDigest(review.comparison.after) !== decisionDigest(proof.subject)) fail('前后差异未绑定原授权快照和当前资产');
|
|
68
|
+
for (const obligation of external.requirements) {
|
|
69
|
+
if (!obligation.id || !strings(obligation.boundaries) || !strings(obligation.principals)) fail('外部审批制度记录不完整');
|
|
70
|
+
if (!obligation.boundaries.includes(requirement.boundary)) continue;
|
|
71
|
+
for (const principal of obligation.principals) {
|
|
72
|
+
const reply = proof.external_decisions?.find(x => x.obligation_id === obligation.id && x.principal_ref === principal);
|
|
73
|
+
if (!reply || reply.requirement?.continuation_ref || reply.requirement?.boundary !== requirement.boundary || reply.requirement?.subject_ref !== requirement.subject_ref || !sameSet(reply.requirement?.scope, requirement.scope)) fail('外部强制审批缺失或范围不符');
|
|
74
|
+
const result = assertUserDecisionRequirement(reply.requirement, { ...options, rolesDoc: roles });
|
|
75
|
+
if (!result.validated.length || result.validated.some(x => x.principal_ref !== principal)) fail('外部审批人与制度要求不符');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { ...sourceResult, continued: true, review_ref: proof.review.ref };
|
|
79
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeSliceContract, sourceSliceContract, parseSliceYaml } from './slice-contract.mjs';
|
|
1
2
|
import { assertExistingSliceStructure, createApprovedExecutionContext, verifySliceContractApproval } from './approved-execution-context.mjs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { readFileSync, existsSync } from 'node:fs';
|
|
@@ -46,7 +47,7 @@ function requireBackendCapability(key) {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
/** Read-only: never executes input commands, starts services, unpacks archives or writes receipts. */
|
|
49
|
-
export async function preflightDelivery(input,{stage,root=process.cwd()}={}) {
|
|
50
|
+
export async function preflightDelivery(input,{stage,root=process.cwd(),work_unit_id}={}) {
|
|
50
51
|
try { ensure(STAGES.includes(stage),'未知阶段;必须是 prepare|build|export|accept');schema(input,'docs/process/schemas/delivery-preflight-input.schema.json'); }
|
|
51
52
|
catch(error) { return invalidPreflightInput(error.message); }
|
|
52
53
|
root=path.resolve(root,input.governance_root||'.');
|
|
@@ -78,7 +79,7 @@ export async function preflightDelivery(input,{stage,root=process.cwd()}={}) {
|
|
|
78
79
|
if(input.architecture_identity.source_kind==='existing-registration')ensure(input.architecture_identity.repository_id===input.scope.repository_id&&input.architecture_identity.project_id===input.scope.project_id,'架构身份与预检目标仓库/项目不一致');
|
|
79
80
|
},{source:'architecture_identity'});
|
|
80
81
|
if(valid.has('architecture.identity'))await run('architecture.profile',()=>{ensure(architecture.validateArchitectureIdentity(input.architecture_identity).maturity==='supported','不支持未达到 supported 的 architecture_profile');},{source:'architecture_profile'});
|
|
81
|
-
if(['build','export','accept'].includes(stage)&&assets.slice_contract)await run('slice_contract.execution',()=>{requireBackendCapability('slice_contract');execution=createApprovedExecutionContext(assets.slice_contract,{root});},{from:'build',source:assets.slice_contract.approval_ref||'slice_contract',evidence:[assets.slice_contract.ref,...(assets.slice_contract.approval_ref?[assets.slice_contract.approval_ref]:[])]});
|
|
82
|
+
if(['build','export','accept'].includes(stage)&&assets.slice_contract)await run('slice_contract.execution',()=>{requireBackendCapability('slice_contract');execution=createApprovedExecutionContext(assets.slice_contract,{root,work_unit_id});},{from:'build',source:assets.slice_contract.approval_ref||'slice_contract',evidence:[assets.slice_contract.ref,...(assets.slice_contract.approval_ref?[assets.slice_contract.approval_ref]:[])]});
|
|
82
83
|
const archDeps=['architecture.identity',...['repository_registration','engineering_baseline','manifest'].map(x=>`architecture.${x}`)];
|
|
83
84
|
if(archDeps.every(x=>valid.has(x)))await run('architecture',()=>{
|
|
84
85
|
ensure(typeof architecture.verifyArchitectureEvidence==='function','不支持既有工程原始证据验证,请同步支持该身份版本的模板运行时');
|
|
@@ -143,12 +144,12 @@ async function verifyAsset(key,data,binding,{root,input,documents,assets,executi
|
|
|
143
144
|
await validateTechnicalDesign(data,{root,sliceRef:input.scope.slice_id,readOnly:true,execution});
|
|
144
145
|
await approved(root,binding,['gate.engineering-contract-approved','gate.technical-design-approved']);
|
|
145
146
|
} else if(key==='slice_contract') {
|
|
146
|
-
const contract=data
|
|
147
|
+
const contract=normalizeSliceContract(data,{root});
|
|
147
148
|
assertExistingSliceStructure(contract);
|
|
148
|
-
ensure(contract.schema_version
|
|
149
|
+
ensure([2,3].includes(contract.schema_version)&&contract.status==='approved'&&contract.slice_id===input.scope.slice_id,'Slice 合同版本、批准状态或切片不匹配');
|
|
149
150
|
ensure(binding.id===contract.contract_id&&binding.version===contract.contract_version,'Slice 合同身份与引用不一致');
|
|
150
151
|
const compiler=read(safe(ROOT,'.agents/skills/yss-implementation-contract-compiler/references/compiler-contract.yaml'));
|
|
151
|
-
for(const [section,fields]of Object.entries(compiler.slice_contract_required))for(const field of fields)ensure(Object.hasOwn(section==='root'?contract:contract[section]||{},field),`合同缺少 ${section}.${field}`);
|
|
152
|
+
if(contract.schema_version===2)for(const [section,fields]of Object.entries(compiler.slice_contract_required))for(const field of fields)ensure(Object.hasOwn(section==='root'?contract:contract[section]||{},field),`合同缺少 ${section}.${field}`);
|
|
152
153
|
ensure(contract.readiness.blockers.length===0&&contract.readiness.stale_inputs.length===0,'Slice 合同仍有 blocker 或 stale input');
|
|
153
154
|
const resolution=contract.resolution;
|
|
154
155
|
ensure(resolution.freshness==='current','Slice resolution 非 current');
|
|
@@ -388,6 +388,16 @@ export function validateDigitalHumanRoles(doc, { skillIds, stageIds, gateIds, ar
|
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
const decisions = doc.user_decision_policy;
|
|
391
|
+
if (decisions?.continuation) {
|
|
392
|
+
const continuation = decisions.continuation;
|
|
393
|
+
if (continuation.capability !== 'approved-scope-continuation-v1' || continuation.source_boundary !== 'delivery-scope' || continuation.unknown_change !== 'blocked' || continuation.external_policy_unconfirmed !== 'no-automatic-continuation') fail('授权延续策略不能省略未知变化或外部制度保护');
|
|
394
|
+
requireStringArray(continuation.boundaries, 'continuation.boundaries');
|
|
395
|
+
for (const boundary of continuation.boundaries) {
|
|
396
|
+
if (!gateIds.has(boundary) && boundary !== 'implementation-scope') fail(`未支持的延续边界: ${boundary}`);
|
|
397
|
+
requireStringArray(policy.continuation_reviews?.[boundary], `${boundary}.continuation_reviews`);
|
|
398
|
+
for (const role of policy.continuation_reviews[boundary]) if (!actors.has(role)) fail(`未知延续审查角色: ${role}`);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
391
401
|
if (decisions?.schema_version !== 1 || decisions.default_responder !== "requester" || decisions.delegate_requires_requester_evidence !== true) fail("缺少统一用户决定策略");
|
|
392
402
|
requireStringArray(decisions.gates, "user_decision_policy.gates");
|
|
393
403
|
for (const gate of decisions.gates) if (!gateIds.has(gate)) fail(`用户决定引用未知门禁: ${gate}`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeSliceContract, sourceSliceContract, parseSliceYaml } from './slice-contract.mjs';
|
|
1
2
|
import { loadDeliveryProfile } from './harness-execution-scope.mjs';
|
|
2
3
|
import { existsSync } from 'node:fs';
|
|
3
4
|
import path from 'node:path';
|
|
@@ -8,6 +9,7 @@ import { ROOT, read, safe, ensure, digest } from './strategic-handoff-io.mjs';
|
|
|
8
9
|
// Always re-executes the verifier; a caller-supplied "verified" flag is never evidence.
|
|
9
10
|
export function enforceFrontendDelivery(state={}, {root=ROOT,phase='inputs'}={}) {
|
|
10
11
|
ensure(['preflight','design','contract','inputs','implementation','verification'].includes(phase),`未知前端交付阶段: ${phase}`);
|
|
12
|
+
if(state.schema_version===3)state=normalizeSliceContract(state,{root});
|
|
11
13
|
const profile=loadDeliveryProfile(root);
|
|
12
14
|
let contract;
|
|
13
15
|
const contractRef=state.slice_contract_ref||state.contract?.slice_contract_ref;
|
|
@@ -35,6 +37,7 @@ export function enforceFrontendDelivery(state={}, {root=ROOT,phase='inputs'}={})
|
|
|
35
37
|
const file=path.resolve(root,contractRef);
|
|
36
38
|
if(existsSync(file)) {
|
|
37
39
|
const document=read(file);contract=document.slice_contract||document;
|
|
40
|
+
if(contract.schema_version===3)contract=normalizeSliceContract(contract,{root});
|
|
38
41
|
const direct=contract.frontend?.delivery, resolved=contract.resolution?.frontend_delivery;
|
|
39
42
|
ensure(!direct||!resolved||digest(direct)===digest(resolved),'Slice Contract 前端交付绑定冲突');
|
|
40
43
|
binding=direct||resolved||binding;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { resolveBackendPlatform } from "./backend-platform.mjs";
|
|
2
|
+
import { safe } from './strategic-handoff-io.mjs';
|
|
3
|
+
import { selectSliceWorkUnit, normalizeSliceContract, withinSlicePath } from './slice-contract.mjs';
|
|
1
4
|
import { createApprovedExecutionContext, createApprovedRecompilationContext, assertApprovedExecutionContext } from './approved-execution-context.mjs';
|
|
2
5
|
import { enforceTechnicalDesign } from './technical-design-boundary.mjs';
|
|
3
6
|
import { enforceHarnessSkillScope } from "./harness-execution-scope.mjs";
|
|
@@ -67,13 +70,15 @@ export function compileImplementationContract({
|
|
|
67
70
|
architecture_identity,
|
|
68
71
|
architecture_evidence,
|
|
69
72
|
approved_slice,
|
|
73
|
+
work_unit_id,
|
|
70
74
|
root = ROOT,
|
|
71
75
|
slice_id,
|
|
72
76
|
frontend_delivery,
|
|
73
|
-
technical_design
|
|
77
|
+
technical_design,
|
|
78
|
+
readOnly = false
|
|
74
79
|
}) {
|
|
75
80
|
assertV2(registry, compilerContract);
|
|
76
|
-
const recompilationExecution=approved_slice?createApprovedRecompilationContext(approved_slice,{root}):undefined;
|
|
81
|
+
const recompilationExecution=approved_slice?createApprovedRecompilationContext(approved_slice,{root,work_unit_id}):undefined;
|
|
77
82
|
const deliveryInput = enforceFrontendDelivery({ slice_id, frontend_delivery }, { root });
|
|
78
83
|
if (!Array.isArray(recipeIds) || !Array.isArray(requiredCapabilities) || !Array.isArray(conditions)) {
|
|
79
84
|
fail("recipeIds、requiredCapabilities 与 conditions 必须是数组");
|
|
@@ -96,7 +101,8 @@ export function compileImplementationContract({
|
|
|
96
101
|
for (const recipe of orderedRecipes) if (recipe.architecture_family && recipe.architecture_family !== architecture_identity.architecture_family) fail(`Recipe ${recipe.id} 与架构族不匹配`);
|
|
97
102
|
}
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
if (architecture_identity?.platform_configuration) resolveBackendPlatform(architecture_identity.platform_configuration);
|
|
105
|
+
enforceTechnicalDesign({ technical_design, conditions, architecture_identity, slice_id }, { root, execution:recompilationExecution, readOnly });
|
|
100
106
|
|
|
101
107
|
const capabilitySources = new Map();
|
|
102
108
|
const orderedCapabilities = [];
|
|
@@ -206,14 +212,17 @@ export function compileDefaultImplementationContract(input = {}) {
|
|
|
206
212
|
});
|
|
207
213
|
}
|
|
208
214
|
|
|
209
|
-
export function evaluateContractFreshness(contract, { registry, compilerContract, root = ROOT, approved_slice, readOnly = false }, execution) {
|
|
215
|
+
export function evaluateContractFreshness(contract, { registry, compilerContract, root = ROOT, approved_slice, readOnly = false, work_unit_id }, execution) {
|
|
210
216
|
assertV2(registry, compilerContract);
|
|
211
|
-
|
|
217
|
+
try { contract=normalizeSliceContract(contract,{root}); } catch(error) { return {freshness:'stale',reasons:[error.message]}; }
|
|
218
|
+
if (![2,3].includes(contract?.schema_version)) fail("Slice Implementation Contract schema v1 已停止支持;必须重新编译 v2 合同");
|
|
219
|
+
const all=contract;
|
|
220
|
+
try {contract=selectSliceWorkUnit(contract,work_unit_id);} catch(error){return {freshness:'stale',reasons:[error.message]};}
|
|
212
221
|
const resolution = contract.resolution ?? contract;
|
|
213
222
|
const reasons = [];
|
|
214
223
|
let trustedExecution;
|
|
215
224
|
try {
|
|
216
|
-
trustedExecution=approved_slice?createApprovedExecutionContext(approved_slice,{root,contract}):execution;
|
|
225
|
+
trustedExecution=approved_slice?createApprovedExecutionContext(approved_slice,{root,contract:all,work_unit_id}):execution;
|
|
217
226
|
if(trustedExecution)assertApprovedExecutionContext(trustedExecution,{root,contract});
|
|
218
227
|
} catch(error) { reasons.push(error.code||'EXECUTION_APPROVAL_INVALID');trustedExecution=undefined; }
|
|
219
228
|
try { enforceTechnicalDesign({ ...resolution, slice_id: contract.slice_id ?? resolution.slice_id }, { root,execution:trustedExecution,readOnly }); }
|
|
@@ -236,11 +245,13 @@ export function evaluateContractFreshness(contract, { registry, compilerContract
|
|
|
236
245
|
|
|
237
246
|
export function validateExecutionResult(result, contract, current) {
|
|
238
247
|
if (result?.schema_version !== 2) fail("YSS Skill Execution Result schema v1 已停止支持;请迁移到 v2");
|
|
239
|
-
|
|
248
|
+
contract=normalizeSliceContract(contract,{root:current?.root || ROOT});
|
|
249
|
+
if (![2,3].includes(contract?.schema_version)) fail("Slice Implementation Contract schema v1 已停止支持;必须重新编译 v2 合同");
|
|
240
250
|
if (!EXECUTION_STATUSES.has(result.status)) fail(`未知 execution result status: ${result.status}`);
|
|
241
|
-
if(contract.resolution?.architecture_identity?.schema_version===2&&!current?.approved_slice)return {status:'stale',blockers:['EXECUTION_APPROVAL_REQUIRED']};
|
|
242
|
-
const freshness = evaluateContractFreshness(contract, current);
|
|
251
|
+
if((contract.schema_version===3||contract.resolution?.architecture_identity?.schema_version===2)&&!current?.approved_slice)return {status:'stale',blockers:['EXECUTION_APPROVAL_REQUIRED']};
|
|
252
|
+
const freshness = evaluateContractFreshness(contract, {...current,work_unit_id:result.work_unit_id});
|
|
243
253
|
if (freshness.freshness === "stale") return { status: "stale", blockers: freshness.reasons };
|
|
254
|
+
contract=selectSliceWorkUnit(contract,result.work_unit_id);
|
|
244
255
|
const consumed = result.consumed_contract ?? {};
|
|
245
256
|
const resolution = contract.resolution ?? contract;
|
|
246
257
|
const blockers = [];
|
|
@@ -253,6 +264,28 @@ export function validateExecutionResult(result, contract, current) {
|
|
|
253
264
|
if (!item?.command || item.exit_code === undefined || !item.executed_at) blockers.push("verification-result-incomplete");
|
|
254
265
|
else if (item.exit_code !== 0) blockers.push("verification-failed");
|
|
255
266
|
}
|
|
267
|
+
if(contract.schema_version===3) {
|
|
268
|
+
const unit=contract.work_units.find(item=>item.id===result.work_unit_id);
|
|
269
|
+
if(!unit)blockers.push('work-unit-mismatch');
|
|
270
|
+
else {
|
|
271
|
+
const checks=unit.work_unit.verification;
|
|
272
|
+
for(const check of checks)if(!result.verification_results?.some(item=>item.command===check.command&&item.exit_code===0&&item.cwd===check.cwd&&(!check.dependency_roots||JSON.stringify(item.dependency_roots)===JSON.stringify(check.dependency_roots))))blockers.push('verification-coverage-or-cwd-missing');
|
|
273
|
+
if(!Array.isArray(result.changed_files))blockers.push('changed-files-missing');
|
|
274
|
+
else for(const item of result.changed_files) {
|
|
275
|
+
const changed=typeof item==='string'?item:item.path;
|
|
276
|
+
if(contract.repositories&&(typeof item==='string'||item.project_root!==unit.project_root))blockers.push('changed-file-repository-mismatch');
|
|
277
|
+
if(!unit.allowed_write_paths.some(parent=>withinSlicePath(changed,parent)))blockers.push('write-scope-violation');
|
|
278
|
+
}
|
|
279
|
+
const evidence=result.evidence_files||[];
|
|
280
|
+
for(const ref of unit.work_unit.expected_evidence) {
|
|
281
|
+
if(!evidence.some(item=>(typeof item==='string'?item:item.path)===ref&&(!contract.repositories||item.project_root===unit.project_root)))blockers.push('expected-evidence-missing');
|
|
282
|
+
else {try {readFileSync(safe(contract.repositories?unit.project_root:(current.root||ROOT),ref));}catch {blockers.push('expected-evidence-unreadable');}}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if(['drift','violation'].includes(result.status))blockers.push(result.status);
|
|
286
|
+
if(result.status==='not-applicable'&&!result.not_applicable_reason?.trim())blockers.push('not-applicable-reason-missing');
|
|
287
|
+
if(result.status==='seam-deferred'&&(!result.seam_deferred?.length||result.seam_deferred.some(item=>['risk','owner','follow_up_ticket','verification_plan','target_version_or_release_date'].some(key=>!item[key]))))blockers.push('seam-deferred-incomplete');
|
|
288
|
+
}
|
|
256
289
|
if (Array.isArray(result.new_impacts) && result.new_impacts.length) blockers.push("new-impacts");
|
|
257
290
|
return { status: blockers.length ? "blocked" : "accepted", blockers: [...new Set(blockers)] };
|
|
258
291
|
}
|
|
@@ -46,7 +46,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
|
|
|
46
46
|
const rule = countersignRuleForGate(rolesDoc.gate_policy, id);
|
|
47
47
|
if (rule) {
|
|
48
48
|
if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${id} 未绑定审查与资产`);
|
|
49
|
-
const record = loadApprovalRecord(path.resolve(root, item.approval_ref));
|
|
49
|
+
const record = loadApprovalRecord(path.resolve(root, item.approval_ref), id);
|
|
50
50
|
if (record.gate_id !== id || record.subject_ref !== item.subject_ref) fail(`${id} 审查对象不匹配`);
|
|
51
51
|
if (!item.approval_scope?.length || JSON.stringify([...item.approval_scope].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) fail(`${id} 审查范围不匹配`);
|
|
52
52
|
const subjectDigest = createHash('sha256').update(readFileSync(path.resolve(root, item.subject_ref))).digest('hex');
|
|
@@ -65,7 +65,7 @@ export function assertGateChecks(gateId, state, { root = ROOT, registry = loadRe
|
|
|
65
65
|
const approvalRequired = countersignRuleForGate(rolesDoc.gate_policy, gateId);
|
|
66
66
|
if (approvalRequired) {
|
|
67
67
|
if (!refs.has(item.approval_ref) || !refs.has(item.subject_ref)) fail(`${gateId} 缺少已绑定批准记录和审阅包`);
|
|
68
|
-
const record = loadApprovalRecord(path.resolve(root, item.approval_ref));
|
|
68
|
+
const record = loadApprovalRecord(path.resolve(root, item.approval_ref), gateId);
|
|
69
69
|
if (!record.drafter_principal_ref || record.drafter_principal_ref === record.principal_ref) fail(`${gateId} 缺少独立审查身份或起草者自签`);
|
|
70
70
|
const bytes = readFileSync(path.resolve(root, item.subject_ref));
|
|
71
71
|
if (record.subject_ref !== item.subject_ref || record.subject_digest !== createHash('sha256').update(bytes).digest('hex')) fail(`${gateId} 批准依据过期`);
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Wire capability marker: profile-local readiness rules are not interchangeable.
|
|
2
|
+
export const SLICE_REPOSITORY_PREPARATION_PROTOCOL = 1;
|
|
1
3
|
import { createHash } from "node:crypto";
|
|
2
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
5
|
import { parseDocument } from "../vendor/yaml.mjs";
|
|
@@ -168,7 +170,7 @@ function backendDesignPrerequisitesReady(prerequisites, exists, root, projectId)
|
|
|
168
170
|
const approvalFile = path.isAbsolute(prerequisites.engineering_contract_approval_ref)
|
|
169
171
|
? prerequisites.engineering_contract_approval_ref
|
|
170
172
|
: path.resolve(root, prerequisites.engineering_contract_approval_ref);
|
|
171
|
-
const approval = loadApprovalRecord(approvalFile);
|
|
173
|
+
const approval = loadApprovalRecord(approvalFile, 'gate.engineering-contract-approved');
|
|
172
174
|
validateApprovalRecord(approval, { requireApproved: true, root });
|
|
173
175
|
if (approval.gate_id !== "gate.engineering-contract-approved" || !approval.approval_scope?.includes(projectId)) return false;
|
|
174
176
|
if (!approvalHasBinding(approval, technical.expected) || !approvalHasBinding(approval, data.expected)) return false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { verifyContextReconciliation } from './context-reconciliation.mjs';
|
|
3
3
|
import { decisionIO, decisionDigest, assertUserDecisionRequirement } from './user-decision.mjs';
|
|
4
|
-
import { validateApprovalRecord } from './approval-record.mjs';
|
|
4
|
+
import { validateApprovalRecord, selectApprovalRecord } from './approval-record.mjs';
|
|
5
5
|
|
|
6
6
|
const fail = message => { throw new TypeError(`plan-spec-entry-blocked: ${message}`); };
|
|
7
7
|
const text = value => typeof value === 'string' && value.trim().length > 0;
|
|
@@ -56,7 +56,7 @@ export function assertPlanSpecEntry(state, options = {}) {
|
|
|
56
56
|
evidence(gate?.evidence_refs);
|
|
57
57
|
if (review.impacts[impact]) {
|
|
58
58
|
if (gate.status !== 'approved' || !basis.has(gate.approval_ref) || !basis.has(gate.subject_ref)) fail(`命中门禁未批准或未绑定依据: ${gateId}`);
|
|
59
|
-
const record = io.document(gate.approval_ref);
|
|
59
|
+
const record = selectApprovalRecord(io.document(gate.approval_ref), gateId);
|
|
60
60
|
if (record.gate_id !== gateId || record.subject_ref !== gate.subject_ref || !gate.approval_scope?.includes(state.feature_id) || JSON.stringify([...(gate.approval_scope || [])].sort()) !== JSON.stringify([...(record.approval_scope || [])].sort())) fail(`会签资产或范围不匹配: ${gateId}`);
|
|
61
61
|
validateApprovalRecord(record, { ...options, requireApproved: true });
|
|
62
62
|
} else if (gate.status !== 'not-applicable' || !text(gate.reason)) fail(`未命中门禁须有原因和依据: ${gateId}`);
|
|
@@ -72,7 +72,7 @@ export function assertPlanSpecEntry(state, options = {}) {
|
|
|
72
72
|
if (reconciliation.status !== 'reconciled' || reconciliation.repository_mode !== 'project-instance') fail('Context 未调和');
|
|
73
73
|
try { verifyContextReconciliation(path.resolve(io.root, review.context_reconciliation_ref), { root: io.root }); }
|
|
74
74
|
catch (error) { fail(`Context reconciliation 验证失败: ${error.message}\n`); }
|
|
75
|
-
assertUserDecisionRequirement({ boundary: 'gate.plan-approved', subject_ref: state.plan_review_ref, scope: [state.feature_id], user_decision_ref: state.plan_user_decision_ref }, options);
|
|
75
|
+
assertUserDecisionRequirement({ boundary: 'gate.plan-approved', subject_ref: state.plan_review_ref, scope: [state.feature_id], user_decision_ref: state.plan_user_decision_ref, continuation_ref: state.plan_continuation_ref }, options);
|
|
76
76
|
return { result: 'allowed', blocking_signals: [], missing_requirements: [], evidence_refs: [state.plan_review_ref, ...basis.keys()], next_work_unit: null };
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -14,6 +14,7 @@ export function localDatabaseConfiguration(name) {
|
|
|
14
14
|
|
|
15
15
|
export function scaffoldArchitectureIdentity(contract, contractDigest) {
|
|
16
16
|
return {
|
|
17
|
+
...(contract.platform_configuration ? { platform_configuration: contract.platform_configuration } : {}),
|
|
17
18
|
architecture_family: contract.architecture_family,
|
|
18
19
|
architecture_profile: contract.architecture_profile,
|
|
19
20
|
generator_skill: contract.generator_skill,
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Interpret the published lifecycle check, without creating a second gate registry.
|
|
2
|
+
export function sliceCheckApplicability(scope,registry) {
|
|
3
|
+
if(!['low','medium','high'].includes(scope.risk_level))throw new TypeError('缺少明确风险等级,不能裁剪材料');
|
|
4
|
+
if(scope.impacted_areas.some(impact=>!['ui','frontend','backend','api','data','persistence','domain','architecture','cross-repo','cross-boundary','high-risk'].includes(impact)))throw new TypeError('未知影响不能裁剪材料,先补影响分析');
|
|
5
|
+
const check=registry.checks?.find(check=>check.id==='check.architecture-reviewed');
|
|
6
|
+
// Unknown source rule revisions need an adapter update, never a local default.
|
|
7
|
+
if(check?.trigger!=='高风险或跨边界变化。')throw new TypeError('不支持当前生命周期架构审查规则');
|
|
8
|
+
const required=scope.risk_level==='high'||scope.impacted_areas.includes('high-risk')||scope.impacted_areas.some(impact=>['architecture','cross-repo','cross-boundary'].includes(impact))||scope.project_roots.length>1;
|
|
9
|
+
return {[check.id]:{status:required?'required':'not-applicable',reason:`${check.trigger} 本切片风险 ${scope.risk_level},影响 ${scope.impacted_areas.join(', ')||'无'},工程数 ${scope.project_roots.length}。`}};
|
|
10
|
+
}
|