create-yss-spec 3.4.1 → 3.4.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 +2 -2
- package/template/.agents/skills/.strategic-design-skills-manifest.json +3 -3
- 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 +16 -3
- 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 +14 -6
- 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 +29 -7
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +6 -2
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.agents/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
- 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-stage-decision/SKILL.md +1 -1
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
- package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
- package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
- package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
- package/template/.agents/skills/yss-tactical-design/SKILL.md +5 -1
- package/template/.agents/skills/yss-technical-design/SKILL.md +5 -1
- package/template/.agents/skills/yss-technical-design/references/technical-design-contract.md +1 -1
- package/template/.agents/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.agents/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
- 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 +16 -3
- 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 +14 -6
- 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 +29 -7
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +6 -2
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.codex/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
- 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-stage-decision/SKILL.md +1 -1
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
- package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
- package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
- package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
- package/template/.codex/skills/yss-tactical-design/SKILL.md +5 -1
- package/template/.codex/skills/yss-technical-design/SKILL.md +5 -1
- package/template/.codex/skills/yss-technical-design/references/technical-design-contract.md +1 -1
- package/template/.codex/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.codex/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
- 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 +16 -3
- 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 +14 -6
- 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 +29 -7
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +6 -2
- package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.cursor/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
- 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-stage-decision/SKILL.md +1 -1
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
- package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
- package/template/.cursor/skills/yss-tactical-design/SKILL.md +5 -1
- package/template/.cursor/skills/yss-technical-design/SKILL.md +5 -1
- package/template/.cursor/skills/yss-technical-design/references/technical-design-contract.md +1 -1
- package/template/.cursor/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.cursor/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
- 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 +16 -3
- 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 +14 -6
- 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 +29 -7
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +6 -2
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +3 -1
- package/template/.pi/skills/yss-product-lifecycle/references/user-decisions.md +24 -4
- 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-stage-decision/SKILL.md +1 -1
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-contract.md +2 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +1 -1
- package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +3 -3
- package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +3 -3
- package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +33 -0
- package/template/.pi/skills/yss-tactical-design/SKILL.md +5 -1
- package/template/.pi/skills/yss-technical-design/SKILL.md +5 -1
- package/template/.pi/skills/yss-technical-design/references/technical-design-contract.md +1 -1
- package/template/.pi/skills/yss-technical-design/scripts/validate-technical-design.mjs +2 -2
- package/template/.pi/skills/yss-technical-design/tests/run-scenarios.mjs +1 -1
- 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 +29 -1
- package/template/docs/agents/issue-tracker.md +2 -0
- package/template/docs/architecture/templates/engineering-baseline-review-template.md +6 -6
- 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/existing-ui-baseline.md +1 -1
- package/template/docs/process/harness-process-tailoring.md +9 -1
- package/template/docs/process/lifecycle-artifact-map.md +6 -5
- package/template/docs/process/lifecycle-registry-baseline.json +2 -1
- package/template/docs/process/lifecycle-registry.yaml +17 -8
- package/template/docs/process/schemas/backend-architecture-identity.schema.json +91 -0
- package/template/docs/process/schemas/digital-human-task-package.schema.json +3 -1
- package/template/docs/process/schemas/lifecycle-checkpoint.schema.json +8 -0
- package/template/docs/process/schemas/project-scaffold-contract.schema.json +602 -83
- package/template/docs/process/schemas/review-bundle.schema.json +42 -0
- 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/process/strategic-handoff-package.md +5 -11
- package/template/docs/templates/approval-record-template.yaml +2 -0
- package/template/docs/templates/build-architecture-checklist-template.md +2 -2
- package/template/docs/templates/implementation-routing-template.md +4 -4
- package/template/docs/templates/review-bundle-template.yaml +26 -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 +52 -7
- 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-io.mjs +7 -0
- package/template/scripts/lib/strategic-handoff.mjs +33 -8
- 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 +17 -3
- 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 +62 -57
- package/template.snapshot.json +3 -3
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import {sliceRepositories} from './slice-repositories.mjs';
|
|
2
|
+
import { sliceCheckApplicability } from './slice-applicability.mjs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { stringify } from '../vendor/yaml.mjs';
|
|
6
|
+
import { safe, hash, digest, write } from './strategic-handoff-io.mjs';
|
|
7
|
+
import { compileDefaultImplementationContract, loadCompilerContract } from './implementation-contract-compiler.mjs';
|
|
8
|
+
import { normalizeSliceContract, parseSliceYaml, readSliceSources, resolveSliceBasis, sourceSliceContract, sliceArchitectureEvidence } from './slice-contract.mjs';
|
|
9
|
+
|
|
10
|
+
const object=value=>value && typeof value==='object' && !Array.isArray(value);
|
|
11
|
+
const same=(a,b)=>digest(a)===digest(b);
|
|
12
|
+
function metadata(text) {
|
|
13
|
+
const front=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(text);
|
|
14
|
+
if(front)return parseSliceYaml(front[1]);
|
|
15
|
+
return (/^\s*[{[]/.test(text)||/^[A-Za-z_][\w-]*:\s/m.test(text)&&!/^#/m.test(text))?parseSliceYaml(text):{};
|
|
16
|
+
}
|
|
17
|
+
function mergeFacts(left,right,path,report) {
|
|
18
|
+
if(left===undefined)return structuredClone(right);
|
|
19
|
+
if(right===undefined)return structuredClone(left);
|
|
20
|
+
if(object(left)&&object(right))return Object.fromEntries([...new Set([...Object.keys(left),...Object.keys(right)])].map(key=>[key,mergeFacts(left[key],right[key],`${path}.${key}`,report)]));
|
|
21
|
+
if(!same(left,right))report.blockers.push({field:path,reason:'conflict',before:left,after:right,recovery:'回到来源确认当前事实,不使用最后覆盖'});
|
|
22
|
+
return structuredClone(left);
|
|
23
|
+
}
|
|
24
|
+
function markdownAcceptance(text) {
|
|
25
|
+
const rows=text.split('\n'),result={};let active=false;
|
|
26
|
+
rows.forEach((line,index)=>{
|
|
27
|
+
if(/^##\s/.test(line))active=/验收/.test(line);
|
|
28
|
+
if(active&&/^\s*-\s+(?:\[[ xX]\]\s*)?\S/.test(line)) {
|
|
29
|
+
const id=/(?:AC|SC|验收)[-_][\w-]+/.exec(line)?.[0] || `acceptance-${Object.keys(result).length+1}`;
|
|
30
|
+
if(result[id])throw new TypeError(`验收 ID 重复: ${id}`);
|
|
31
|
+
result[id]={source:'ticket',locator:`lines:${index+1}-${index+1}`};
|
|
32
|
+
}
|
|
33
|
+
});return result;
|
|
34
|
+
}
|
|
35
|
+
function lifecycleSources(checkpoint,report) {
|
|
36
|
+
const result={};
|
|
37
|
+
for(const [artifact,key]of Object.entries({'artifact.spec':'spec','artifact.engineering-baseline':'engineering_baseline','artifact.architecture-review':'architecture_review','artifact.technical-design':'technical_design','artifact.data-architecture':'data_architecture','artifact.state-matrix':'state_matrix','artifact.prototype-deliverable':'prototype_deliverable','artifact.prototype-review':'prototype_review','artifact.prototype-confirmation':'prototype_confirmation','artifact.openapi-freeze-record':'openapi_freeze'})) {
|
|
38
|
+
const value=checkpoint.artifacts?.[artifact];if(value===undefined)continue;
|
|
39
|
+
if(typeof value==='string')result[key]={ref:value};
|
|
40
|
+
else if(object(value)&&typeof value.ref==='string')result[key]=Object.fromEntries(['ref','version','digest','approval_ref'].filter(k=>value[k]!==undefined).map(k=>[k,value[k]]));
|
|
41
|
+
else report.blockers.push({field:`artifacts.${artifact}`,reason:'上游引用不明确,需选择当前绑定'});
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
/** sources select existing assets; refinements contain ONLY new slice facts, never an approved contract. */
|
|
46
|
+
export function prepareSliceImplementationContract({root=process.cwd(),ticket_ref,checkpoint_ref,sources={},refinements={},approved_slice}={}) {
|
|
47
|
+
const started=performance.now();
|
|
48
|
+
const report={read_only:true,blockers:[],sources:{},provenance:[],reason_chains:{},checks:[]};
|
|
49
|
+
const snapshots=new Map();
|
|
50
|
+
const read=ref=>{if(!snapshots.has(ref))snapshots.set(ref,fs.readFileSync(safe(root,ref)));return snapshots.get(ref);};
|
|
51
|
+
let contract={schema_version:3,status:'blocked'};
|
|
52
|
+
try {
|
|
53
|
+
let ticketText='',ticket={},saved={};
|
|
54
|
+
try {ticketText=read(ticket_ref).toString('utf8');ticket=metadata(ticketText);}catch(error){report.blockers.push({code:'SLICE_SOURCE_UNREADABLE',field:'basis.ticket',source_ref:ticket_ref,reason:error.message});}
|
|
55
|
+
if(checkpoint_ref)try {saved=parseSliceYaml(read(checkpoint_ref));}catch(error){report.blockers.push({code:'SLICE_SOURCE_UNREADABLE',field:'checkpoint',source_ref:checkpoint_ref,reason:error.message});}
|
|
56
|
+
const fromTicket=ticket.slice_implementation || {};
|
|
57
|
+
const facts=mergeFacts(saved.slice_implementation || {},fromTicket,'slice',report);
|
|
58
|
+
const input=mergeFacts(facts,refinements,'slice',report);
|
|
59
|
+
for(const field of ['status','resolution','schema_version','readiness'])if(Object.hasOwn(input,field))report.blockers.push({field,reason:'由编译器生成,不接受调用方指定'});
|
|
60
|
+
const inputKeys=['contract_id','contract_version','slice_id','sources','scope','applicability','recipe_ids','required_capabilities','conditions','acceptance','verification','work_units','extensions'];
|
|
61
|
+
for(const field of Object.keys(input))if(!inputKeys.includes(field))report.blockers.push({field,reason:'未知输入字段,禁止静默丢弃'});
|
|
62
|
+
contract={schema_version:3,contract_id:input.contract_id,contract_version:input.contract_version,slice_id:input.slice_id,status:'blocked'};
|
|
63
|
+
for(const field of ['contract_id','contract_version','slice_id','scope','applicability','verification','work_units'])if(input[field]===undefined)report.blockers.push({code:'SLICE_INPUT_MISSING',field:`slice.${field}`,reason:'缺少切片必要输入',recovery:'优先从 Ticket / checkpoint 整理;只补缺失的切片细化'});
|
|
64
|
+
for(const field of ['impacted_areas','allowed_write_paths'])if(input.scope?.[field]===undefined)report.blockers.push({code:'SLICE_INPUT_MISSING',field:`scope.${field}`,reason:'影响与授权范围未确定',responsibility:field==='allowed_write_paths'?'user-decision':'professional-review',recovery:'先确认影响与既有授权范围;不能从目录猜测'});
|
|
65
|
+
|
|
66
|
+
const selected=mergeFacts(lifecycleSources(saved,report),mergeFacts(input.sources || {},sources,'sources',report),'sources',report);
|
|
67
|
+
if(selected.ticket && (typeof selected.ticket==='string'?selected.ticket:selected.ticket.ref)!==ticket_ref)throw new TypeError('Ticket 来源冲突');
|
|
68
|
+
selected.ticket=selected.ticket || {ref:ticket_ref};
|
|
69
|
+
if(input.scope?.risk_level){selected.lifecycle_registry??={ref:'docs/process/lifecycle-registry.yaml'};selected.process_tailoring??={ref:'docs/process/harness-process-tailoring.md'};}
|
|
70
|
+
if(!selected.context&&fs.existsSync(safe(root,'CONTEXT.md',{missing:true})))selected.context={ref:'CONTEXT.md'};
|
|
71
|
+
const basis={},seen=new Map();
|
|
72
|
+
for(const [key,value] of Object.entries(selected)) {
|
|
73
|
+
try {
|
|
74
|
+
if(typeof value==='string' && Object.hasOwn(selected,value)) {basis[key]=value;continue;}
|
|
75
|
+
const binding=typeof value==='string'?{ref:value}:value;
|
|
76
|
+
const bytes=read(binding.ref),rawDigest=hash(bytes);
|
|
77
|
+
if(binding.digest&&binding.digest!==rawDigest)throw new TypeError(`stale: 来源 ${key}`);
|
|
78
|
+
const data=metadata(bytes.toString('utf8'));
|
|
79
|
+
const sourceVersion=data.requirement_version??data.version??data.contract_version;
|
|
80
|
+
if(binding.version!==undefined&&sourceVersion!==undefined&&String(binding.version)!==String(sourceVersion))throw new TypeError(`来源版本冲突: ${key}`);
|
|
81
|
+
const version=binding.version||data.requirement_version||data.version||data.contract_version;
|
|
82
|
+
basis[key]={ref:binding.ref,digest:rawDigest,...(version?{version:String(version)}:{}),...(binding.approval_ref?{approval_ref:binding.approval_ref}:{})};
|
|
83
|
+
if(seen.has(binding.ref)) {
|
|
84
|
+
const previous=seen.get(binding.ref);
|
|
85
|
+
if(!same(basis[key],basis[previous]))throw new TypeError(`来源绑定冲突: ${key}/${previous}`);
|
|
86
|
+
basis[key]=previous;
|
|
87
|
+
}else seen.set(binding.ref,key);
|
|
88
|
+
report.provenance.push({target:`basis.${key}`,source_ref:binding.ref,digest:rawDigest,rule:'original-bytes'});
|
|
89
|
+
}catch(error){report.blockers.push({code:(error.code==='ENOENT'||/文件不可读/.test(error.message))?'SLICE_SOURCE_UNREADABLE':/冲突/.test(error.message)?'SLICE_SOURCE_CONFLICT':'SLICE_SOURCE_INVALID',field:`basis.${key}`,source_ref:typeof value==='string'?value:value?.ref,reason:error.message,responsibility:'agent',recovery:'补齐当前来源或纠正绑定后重新准备'});}
|
|
90
|
+
}
|
|
91
|
+
const extraRequired=[...(input.applicability?.backend?.status==='required'?['technical_design','repository_registration','manifest','backend_repository','maven_wrapper']:[]),...(input.applicability?.frontend?.status==='required'?(input.applicability.frontend.baseline_kind==='existing-ui-baseline'?['existing_ui_baseline','frontend_delivery']:['requirement_freeze','low_fidelity_review','prototype_review','prototype_profile_decision','prototype_deliverable','prototype_deliverable_verification','prototype_confirmation','visual_baseline','state_matrix']):[]),...(input.applicability?.api?[input.applicability.api.status==='required'?'openapi_freeze':'no_api_impact_record']:[])];
|
|
92
|
+
for(const key of ['spec','ticket','engineering_baseline','implementation_repository','build_architecture_checklist',...extraRequired,...(!input.scope?.risk_level?['architecture_review']:[])])if(!selected[key])report.blockers.push({code:'SLICE_SOURCE_MISSING',field:`basis.${key}`,reason:'缺少必要来源',responsibility:'agent',recovery:'绑定已有当前资产;不能用空文档替代'});
|
|
93
|
+
contract.basis=basis;
|
|
94
|
+
if(report.blockers.length){report.checks.push({check:'dependent-compilation',result:'not-executed',reason:'来源或输入存在独立阻断'});throw Object.assign(new Error('依赖未就绪'),{code:'SLICE_DEPENDENCIES_UNAVAILABLE'});}
|
|
95
|
+
const sourceDoc=key=>basis[key]?metadata(read(resolveSliceBasis({basis},key).ref).toString('utf8')):{};
|
|
96
|
+
const registration=sourceDoc('implementation_repository'),baseline=sourceDoc('engineering_baseline');
|
|
97
|
+
const registeredRoot=registration.local_worktree?(registration.project_root&®istration.project_root!=='.'?path.resolve(registration.local_worktree,registration.project_root):registration.local_worktree):undefined;
|
|
98
|
+
const scope={...(registeredRoot?{project_roots:[registeredRoot]}:{}),...input.scope};
|
|
99
|
+
// Registration is an upper bound. Never use its allowed_write_paths as slice authorization.
|
|
100
|
+
if(!input.extensions?.cross_repo?.repository_bindings&®isteredRoot&&scope.project_roots?.some(p=>p!==registeredRoot))throw new TypeError('实施仓库与登记冲突');
|
|
101
|
+
if(!input.extensions?.cross_repo?.repository_bindings&®istration.allowed_write_paths && scope.allowed_write_paths) {
|
|
102
|
+
const {withinSlicePath}=helpers;
|
|
103
|
+
if(scope.allowed_write_paths.some(p=>!registration.allowed_write_paths.some(parent=>withinSlicePath(p,parent))))throw new TypeError('Slice 写范围超出登记');
|
|
104
|
+
}
|
|
105
|
+
const applicability=structuredClone(input.applicability);
|
|
106
|
+
if(scope.risk_level){const calculated=sliceCheckApplicability(scope,sourceDoc('lifecycle_registry'));if(applicability.checks&&!same(applicability.checks,calculated))throw new TypeError('材料适用性与生命周期规则冲突');applicability.checks=calculated;}
|
|
107
|
+
const architecture_identity=baseline.architecture_identity || registration.architecture_identity;
|
|
108
|
+
if(baseline.architecture_identity&®istration.architecture_identity&&!same(baseline.architecture_identity,registration.architecture_identity))throw new TypeError('工程基线与登记架构冲突');
|
|
109
|
+
const bound=key=>basis[key]?resolveSliceBasis({basis},key):undefined;
|
|
110
|
+
const architecture_evidence=architecture_identity?sliceArchitectureEvidence({basis,resolution:{architecture_identity}},readSliceSources({basis},{root})):undefined;
|
|
111
|
+
const compilerRules=loadCompilerContract();
|
|
112
|
+
scope.full_reroute_triggers=[...new Set([...(compilerRules.full_reroute_triggers||[]),...(scope.full_reroute_triggers||[])])];
|
|
113
|
+
for(const impact of input.extensions?.backend?.component_impacts||[])if(!compilerRules.impact_to_capabilities[impact])throw new TypeError(`未知组件影响: ${impact}`);
|
|
114
|
+
const componentCapabilities=(input.extensions?.backend?.component_impacts||[]).flatMap(impact=>compilerRules.impact_to_capabilities[impact]||[]);
|
|
115
|
+
const compileBase={root,slice_id:input.slice_id,conditions:input.conditions||[]};
|
|
116
|
+
let compiled;
|
|
117
|
+
if(input.extensions?.cross_repo?.repository_bindings) {
|
|
118
|
+
const repositories=sliceRepositories({basis,scope,extensions:input.extensions,work_units:input.work_units,resolution:{}},readSliceSources({basis},{root}),{root});
|
|
119
|
+
const results=Object.entries(repositories).map(([projectRoot,repo])=>{
|
|
120
|
+
const recipeIds=repo.recipe_refs||(input.recipe_ids||[]).filter(id=>!id.startsWith('backend.')&&!id.startsWith('frontend.')||id.startsWith(`${repo.project.delivery_role}.`));
|
|
121
|
+
const requiredCapabilities=repo.capability_refs||input.required_capabilities||[];
|
|
122
|
+
if(recipeIds.some(id=>!(input.recipe_ids||[]).includes(id))||requiredCapabilities.some(id=>!(input.required_capabilities||[]).includes(id)))throw new TypeError('逐仓编译引用不属于切片新增输入');
|
|
123
|
+
return compileDefaultImplementationContract({...compileBase,recipeIds,requiredCapabilities:[...requiredCapabilities,...(repo.project.delivery_role==='backend'?componentCapabilities:[])],architecture_identity:repo.resolution.architecture_identity,architecture_evidence:repo.resolution.architecture_evidence,technical_design:repo.resolution.technical_design,...(repo.resolution.frontend_delivery?{frontend_delivery:repo.resolution.frontend_delivery}:{}),...(approved_slice?{approved_slice,work_unit_id:input.work_units.find(u=>u.project_root===projectRoot)?.id}:{})});
|
|
124
|
+
});
|
|
125
|
+
if(results.some(r=>r.registry_digest!==results[0].registry_digest||r.compiler_contract_digest!==results[0].compiler_contract_digest))throw new TypeError('逐仓编译依据冲突:准备期间来源发生变化');
|
|
126
|
+
compiled={...results[0],required_capabilities:[...new Set(results.flatMap(r=>r.required_capabilities))],required_skills:[...new Set(results.flatMap(r=>r.required_skills))],recipe_ids:[...new Set(results.flatMap(r=>r.recipe_ids))],readiness_blockers:results.flatMap(r=>r.readiness_blockers||[]),reason_chains:Object.fromEntries(Object.keys(repositories).map((p,i)=>[p,results[i].reason_chains]))};
|
|
127
|
+
delete compiled.architecture_identity;
|
|
128
|
+
} else compiled=compileDefaultImplementationContract({...compileBase,recipeIds:input.recipe_ids||[],requiredCapabilities:[...new Set([...(input.required_capabilities||[]),...componentCapabilities])],architecture_identity,architecture_evidence,technical_design:bound('technical_design'),...(bound('frontend_delivery')?{frontend_delivery:{acceptance_ref:bound('frontend_delivery').ref,digest:bound('frontend_delivery').digest}}:{}),...(approved_slice?{approved_slice}:{})});
|
|
129
|
+
if(compiled.compiler_contract_digest!==digest(compilerRules).slice(7))throw new TypeError('编译规则来源冲突:准备期间发生变化');
|
|
130
|
+
const resolution=Object.fromEntries(['required_capabilities','required_skills','recipe_ids','conditions','registry_digest','compiler_contract_digest','architecture_identity'].filter(key=>compiled[key]!==undefined).map(key=>[key,compiled[key]]));
|
|
131
|
+
contract={schema_version:3,ticket_policy:{mode:'frozen-requirements',state_owner:'tracker-or-task-package'},contract_id:input.contract_id,contract_version:input.contract_version,slice_id:input.slice_id,status:'draft',basis,scope,applicability,resolution,acceptance:input.acceptance||markdownAcceptance(ticketText),verification:input.verification,work_units:input.work_units,...(input.extensions?{extensions:input.extensions}:{})};
|
|
132
|
+
report.reason_chains=compiled.reason_chains;
|
|
133
|
+
for(const reason of compiled.readiness_blockers||[])report.blockers.push({reason});
|
|
134
|
+
normalizeSliceContract(contract,{root});
|
|
135
|
+
report.checks.push({check:'structure-sources-scope-acceptance',result:'pass'});
|
|
136
|
+
report.provenance.push({target:'resolution',source_ref:'docs/agents/yss-skill-registry.yaml',digest:compiled.registry_digest,rule:'existing-capability-compiler'});
|
|
137
|
+
for(const field of ['scope','acceptance','verification','work_units','applicability','extensions'])if(contract[field]) {
|
|
138
|
+
const origins=[];
|
|
139
|
+
if(saved.slice_implementation?.[field]!==undefined)origins.push({kind:'checkpoint',ref:checkpoint_ref});
|
|
140
|
+
if(fromTicket[field]!==undefined)origins.push({kind:'ticket-metadata',ref:ticket_ref});
|
|
141
|
+
if(refinements[field]!==undefined)origins.push({kind:'agent-refinement'});
|
|
142
|
+
if(field==='scope'&®isteredRoot&&!input.scope?.project_roots)origins.push({kind:'repository-registration',ref:resolveSliceBasis({basis},'implementation_repository').ref});
|
|
143
|
+
if(field==='scope'&&input.extensions?.cross_repo?.repository_bindings)for(const keys of Object.values(input.extensions.cross_repo.repository_bindings))origins.push({kind:'repository-registration',ref:resolveSliceBasis({basis},keys.implementation_repository).ref});
|
|
144
|
+
if(field==='acceptance'&&!input.acceptance)origins.push({kind:'ticket-acceptance',ref:ticket_ref});
|
|
145
|
+
if(field==='applicability'&&scope.risk_level)origins.push({kind:'lifecycle-rule',ref:resolveSliceBasis({basis},'lifecycle_registry').ref});
|
|
146
|
+
report.provenance.push({target:field,origins,requires_professional_review:true});
|
|
147
|
+
}
|
|
148
|
+
}catch(error){if(error.code!=='SLICE_DEPENDENCIES_UNAVAILABLE')report.blockers.push({reason:error.message,recovery:'补齐已确认输入后重新准备;草案不授予执行权限'});report.checks.push({check:'assembly',result:'not-executed',reason:'前置检查未通过'});}
|
|
149
|
+
for(const [ref,bytes] of snapshots) {
|
|
150
|
+
try {if(hash(fs.readFileSync(safe(root,ref)))!==hash(bytes))report.blockers.push({field:ref,reason:'生成期间来源变化'});}catch(error){report.blockers.push({field:ref,reason:error.message});}
|
|
151
|
+
report.sources[ref]=hash(bytes);
|
|
152
|
+
}
|
|
153
|
+
report.blockers=report.blockers.map(b=>({code:b.code||(/conflict|冲突/.test(b.reason)?'SLICE_INPUT_CONFLICT':'SLICE_INPUT_INVALID'),field:b.field||'slice',source_ref:b.source_ref||null,responsibility:b.responsibility||(/user.decision|用户决定|实施授权/.test(b.reason)?'user-decision':/conflict|冲突|技术设计|架构/.test(b.reason)?'professional-review':'agent'),recovery:b.recovery||'核对所列来源并补齐细化后重新准备',...b}));
|
|
154
|
+
report.blockers=report.blockers.filter((b,i,all)=>all.findIndex(x=>x.code===b.code&&x.field===b.field&&x.source_ref===b.source_ref)===i);
|
|
155
|
+
contract.status=report.blockers.length?'blocked':'ready-for-lifecycle-review';
|
|
156
|
+
report.metrics={elapsed_ms:Math.round(performance.now()-started),preparation_round:null,additional_human_confirmations:null,reapproval_reasons:[],measurement:'observed-preparation-only; interaction counts not recorded',unique_source_files:snapshots.size,refinement_fields:Object.keys(refinements).length,contract_bytes:Buffer.byteLength(stringify({slice_contract:contract}))};
|
|
157
|
+
return {slice_contract:contract,report};
|
|
158
|
+
}
|
|
159
|
+
import * as helpers from './slice-contract.mjs';
|
|
160
|
+
|
|
161
|
+
export function persistSliceDraft(result,ref,{root=process.cwd()}={}) {
|
|
162
|
+
if(!['draft','blocked','ready-for-lifecycle-review'].includes(result.slice_contract?.status))throw new TypeError('只能保存编译器草案');
|
|
163
|
+
for(const [source,expected]of Object.entries(result.report?.sources||{}))if(hash(fs.readFileSync(safe(root,source)))!==expected)throw new TypeError(`stale: 保存前来源变化 ${source}`);
|
|
164
|
+
if(result.slice_contract.status!=='blocked')normalizeSliceContract(result.slice_contract,{root});
|
|
165
|
+
const bytes=stringify({slice_contract:result.slice_contract});
|
|
166
|
+
const reportRef=`${ref}.preparation.json`;
|
|
167
|
+
if(fs.existsSync(safe(root,reportRef,{missing:true})))throw Object.assign(new TypeError('EEXIST: 准备报告目标已存在'),{code:'EEXIST'});
|
|
168
|
+
write(root,ref,bytes); // wx: never overwrite a draft or approval.
|
|
169
|
+
write(root,reportRef,JSON.stringify({binding:{ref,digest:hash(bytes)},...result.report},null,2)+'\n');
|
|
170
|
+
return ref;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Explicit, non-destructive migration; no new authorization is inferred. */
|
|
174
|
+
export function migrateSliceContractV2(document,{root=process.cwd(),ticket_ref,sources={},refinements={},...rest}={}) {
|
|
175
|
+
const old=sourceSliceContract(document);
|
|
176
|
+
if(old?.schema_version!==2)throw new TypeError('显式迁移只接受 Slice v2');
|
|
177
|
+
const conflicts=[];
|
|
178
|
+
const meaningful=value=>value!==undefined&&value!==null&&value!==''&&(!Array.isArray(value)||value.length>0);
|
|
179
|
+
const compare=(a,b,label)=>{if(meaningful(a)&&meaningful(b)&&!same(a,b))conflicts.push({field:label,reason:'conflict',before:a,after:b});};
|
|
180
|
+
for(const key of ['required_skills','required_capabilities'])compare(old.common?.[key],old.resolution?.[key],key);
|
|
181
|
+
compare(old.frontend?.delivery,old.resolution?.frontend_delivery,'frontend_delivery');
|
|
182
|
+
const constraintKeys=['application_boundary','transaction_boundary','persistence_strategy','aggregate_refs','invariant_refs','state_behavior_refs','gateway_boundary_ref','domain_test_seams','application_test_seams'];
|
|
183
|
+
for(const key of constraintKeys)compare(old.backend?.[key],old.backend?.tactical_ddd?.[key],`backend.${key}`);
|
|
184
|
+
if(refinements.contract_version===undefined||refinements.contract_version===String(old.contract_version))conflicts.push({field:'contract_version',reason:'迁移必须指定新版本'});
|
|
185
|
+
if(old.readiness?.blockers?.length||old.readiness?.stale_inputs?.length)conflicts.push({field:'readiness',reason:'旧合同仍有阻断或过期输入'});
|
|
186
|
+
const sourceMap=Object.fromEntries(Object.entries(old.lifecycle_refs||{}).filter(([,v])=>typeof v==='string'&&v).map(([k,v])=>[k,{ref:v}]));
|
|
187
|
+
for(const [key,binding]of Object.entries({...old.resolution?.architecture_evidence,...(old.resolution?.technical_design?{technical_design:old.resolution.technical_design}:{})})) {
|
|
188
|
+
if(!binding?.ref)continue;
|
|
189
|
+
if(sourceMap[key]&&sourceMap[key].ref!==binding.ref)conflicts.push({field:`basis.${key}`,reason:'阅读引用与冻结绑定冲突'});
|
|
190
|
+
sourceMap[key]=binding;
|
|
191
|
+
}
|
|
192
|
+
if(sourceMap.openapi_freeze_or_no_impact){sourceMap[old.contract?.api_impact?'openapi_freeze':'no_api_impact_record']=sourceMap.openapi_freeze_or_no_impact;delete sourceMap.openapi_freeze_or_no_impact;}
|
|
193
|
+
const frontendBinding=old.frontend?.delivery||old.resolution?.frontend_delivery;
|
|
194
|
+
if(frontendBinding)sourceMap.frontend_delivery={ref:frontendBinding.acceptance_ref,digest:frontendBinding.digest};
|
|
195
|
+
if(sourceMap.tactical_design&&!sourceMap.technical_design)sourceMap.technical_design=sourceMap.tactical_design;
|
|
196
|
+
const applicability=Object.fromEntries(['frontend','backend','api','cross_repo'].map(key=>{
|
|
197
|
+
const required=key==='api'?old.contract?.api_impact:key==='cross_repo'?old.cross_repo?.repositories?.length>1:old[key]?.status==='required';
|
|
198
|
+
const reason=old.readiness?.not_applicable?.find(x=>x.item===key)?.reason;
|
|
199
|
+
return [key,required?{status:'required'}:{status:'not-applicable',reason:reason||refinements.applicability?.[key]?.reason}];
|
|
200
|
+
}));
|
|
201
|
+
const scopeKeys=['impacted_areas','implementation_path_policy','project_roots','allowed_write_paths','forbidden_patterns','context_plan','doubt_driven_review','human_review_points','full_reroute_triggers','optional_skills','unavailable_skills'];
|
|
202
|
+
const scope=Object.fromEntries(scopeKeys.filter(k=>old.common?.[k]!==undefined).map(k=>[k,old.common[k]]));
|
|
203
|
+
const checkUnknown=(value,known,prefix)=>{for(const [key,item]of Object.entries(value||{}))if(meaningful(item)&&!known.includes(key))conflicts.push({field:`${prefix}.${key}`,reason:'未映射约束,禁止静默丢弃'});};
|
|
204
|
+
checkUnknown(old,['schema_version','contract_id','contract_version','slice_id','status','suggested_owner_role_id','lifecycle_refs','readiness','resolution','common','frontend','backend','contract','cross_repo','work_units'],'root');
|
|
205
|
+
checkUnknown(old.common,[...scopeKeys,'required_capabilities','required_skills','verification_commands','expected_evidence_files','quality_baseline_ref'],'common');
|
|
206
|
+
checkUnknown(old.resolution,['schema_version','status','slice_id','architecture_identity','architecture_identity_digest','architecture_evidence','technical_design','frontend_delivery','profile_maturity','readiness_blockers','skill_profiles','recipe_ids','conditions','required_capabilities','required_skills','reason_chains','non_expanding_dependencies','excluded_conditional_dependencies','registry_digest','compiler_contract_digest','compiled_at','freshness'],'resolution');
|
|
207
|
+
const ticketRef=ticket_ref||old.lifecycle_refs?.ticket;
|
|
208
|
+
let acceptance=refinements.acceptance;
|
|
209
|
+
if(!acceptance){try{acceptance=markdownAcceptance(fs.readFileSync(safe(root,ticketRef),'utf8'));}catch(error){conflicts.push({field:'acceptance',reason:error.message});acceptance={};}}
|
|
210
|
+
const verification={},work_units=[],extensions={};
|
|
211
|
+
for(const entry of old.work_units||[]) {
|
|
212
|
+
const unit=entry.work_unit||entry;
|
|
213
|
+
for(const key of ['allowed_write_paths','verification_commands','expected_evidence'])compare(entry[key],unit[key],`work_units.${entry.id}.${key}`);
|
|
214
|
+
const projectRoot=unit.project_root||entry.project_root||(scope.project_roots?.length===1?scope.project_roots[0]:undefined);
|
|
215
|
+
const acceptanceRefs=unit.acceptance_refs||(Object.keys(acceptance).length===1?Object.keys(acceptance):[]);
|
|
216
|
+
const seams=[...(old.frontend?.component_test_seams||[]),...(old.frontend?.e2e_paths||[]),...(old.backend?.domain_test_seams||old.backend?.tactical_ddd?.domain_test_seams||[]),...(old.backend?.application_test_seams||old.backend?.tactical_ddd?.application_test_seams||[])];
|
|
217
|
+
const evidence=[...new Set([...(old.common?.expected_evidence_files||[]),...(unit.expected_evidence||[])])];
|
|
218
|
+
const refs=[];
|
|
219
|
+
for(const command of new Set([...(old.common?.verification_commands||[]),...(unit.verification_commands||[])])) {
|
|
220
|
+
const check={command,cwd:projectRoot,expected_evidence:evidence,test_seams:seams,acceptance_refs:acceptanceRefs};
|
|
221
|
+
const existing=Object.entries(verification).find(([,v])=>same(v,check));
|
|
222
|
+
const id=existing?.[0]||`verify-${Object.keys(verification).length+1}`;verification[id]=check;refs.push(id);
|
|
223
|
+
}
|
|
224
|
+
const allowed=unit.allowed_write_paths||entry.allowed_write_paths;
|
|
225
|
+
const next={id:entry.id||unit.id,role_id:entry.role_id||unit.role_id,behavior:unit.behavior,primary_skill:unit.primary_skill,tdd_mode:unit.tdd_mode,verification_refs:refs,acceptance_refs:acceptanceRefs};
|
|
226
|
+
for(const key of ['supporting_skills','controlled_generation','downstream_consumers','convergence_ref','forbidden_patterns'])if(meaningful(unit[key]||entry[key]))next[key]=unit[key]||entry[key];
|
|
227
|
+
if(allowed&&!same(allowed,scope.allowed_write_paths))next.allowed_write_paths=allowed;
|
|
228
|
+
if(scope.project_roots?.length>1)next.project_root=projectRoot;
|
|
229
|
+
work_units.push(next);
|
|
230
|
+
checkUnknown(unit,['id','behavior','role_id','runtime_id','execution_state','workflow_status','task_package_ref','contract_id','contract_version','architecture_identity','project_root','primary_skill','supporting_skills','tdd_mode','allowed_write_paths','expected_evidence','verification_commands','controlled_generation','acceptance_refs','downstream_consumers','convergence_ref','forbidden_patterns'],'work_unit');
|
|
231
|
+
}
|
|
232
|
+
const subset=(value,keys)=>Object.fromEntries(keys.filter(k=>meaningful(value?.[k])).map(k=>[k,value[k]]));
|
|
233
|
+
if(applicability.frontend.status==='required')extensions.frontend=subset(old.frontend,['visual_baseline_case_ids','component_test_seams','e2e_paths','generated_api_client_ref','implementation_verification_ref']);
|
|
234
|
+
if(applicability.backend.status==='required') {
|
|
235
|
+
const constraints={...subset(old.backend,constraintKeys),...subset(old.backend?.tactical_ddd,constraintKeys)};
|
|
236
|
+
extensions.backend={...subset(old.backend,['affected_layers','component_impacts','seam_deferred']),design_refs:['pointer:/design'],...(Object.keys(constraints).length?{constraints}:{})};
|
|
237
|
+
}
|
|
238
|
+
if(applicability.api.status==='required')extensions.api=subset(old.contract,['generated_clients','contract_tests','regeneration_commands']);
|
|
239
|
+
if(applicability.cross_repo.status==='required')extensions.cross_repo=subset(old.cross_repo,['delivery_order','integration_verification','rollback_order']);
|
|
240
|
+
for(const [section,data]of Object.entries({frontend:old.frontend,backend:old.backend})) {
|
|
241
|
+
if(data?.status!=='required')continue;
|
|
242
|
+
for(const key of ['allowed_write_paths','forbidden_patterns','verification_commands','expected_evidence_files'])if(meaningful(data[key])&&!same(data[key],old.common?.[key]))conflicts.push({field:`${section}.${key}`,reason:'独有约束须显式映射至对应工作单元'});
|
|
243
|
+
}
|
|
244
|
+
const knownSub=['status','required_skills','allowed_write_paths','forbidden_patterns','verification_commands','expected_evidence_files'];
|
|
245
|
+
checkUnknown(old.frontend,[...knownSub,'approved_prototype_ref','state_matrix_ref','visual_baseline_ref','visual_baseline_case_ids','component_test_seams','e2e_paths','generated_api_client_ref','implementation_verification_ref','delivery'],'frontend');
|
|
246
|
+
checkUnknown(old.backend,[...knownSub,...constraintKeys,'affected_layers','component_impacts','tactical_design_ref','tactical_design_version','tactical_ddd','seam_deferred'],'backend');
|
|
247
|
+
checkUnknown(old.contract,['api_impact','freeze_ref','no_api_impact_ref','generated_clients','contract_tests','regeneration_commands'],'contract');
|
|
248
|
+
checkUnknown(old.cross_repo,['repositories','delivery_order','integration_verification','rollback_order'],'cross_repo');
|
|
249
|
+
const base={contract_id:old.contract_id,slice_id:old.slice_id,scope,applicability,recipe_ids:old.resolution?.recipe_ids,required_capabilities:old.resolution?.required_capabilities,conditions:old.resolution?.conditions,acceptance,verification,work_units,...(Object.keys(extensions).length?{extensions}:{})};
|
|
250
|
+
const migrated=mergeFacts(base,refinements,'migration', {blockers:conflicts});
|
|
251
|
+
migrated.contract_version=refinements.contract_version;
|
|
252
|
+
const result=prepareSliceImplementationContract({root,ticket_ref:ticketRef,sources:mergeFacts(sourceMap,sources,'sources',{blockers:conflicts}),refinements:migrated,...rest});
|
|
253
|
+
result.report.blockers.push(...conflicts);
|
|
254
|
+
result.report.migration={from_schema:2,to_schema:3,approval_inherited:false};
|
|
255
|
+
if(result.report.blockers.length)result.slice_contract.status='blocked';
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { safe, hash, digest } from './strategic-handoff-io.mjs';
|
|
3
|
+
import { selectSliceWorkUnit, readSliceContract, readSliceSources, sliceAcceptanceText, parseSliceYaml, sourceSliceContract } from './slice-contract.mjs';
|
|
4
|
+
|
|
5
|
+
function sections(text) {
|
|
6
|
+
const result={};let name='正文';
|
|
7
|
+
for(const line of text.split('\n')) {
|
|
8
|
+
const heading=/^#{1,3}\s+(.+)/.exec(line);
|
|
9
|
+
if(heading)name=heading[1];
|
|
10
|
+
else (result[name]??=[]).push(line);
|
|
11
|
+
}
|
|
12
|
+
return Object.fromEntries(Object.entries(result).filter(([name])=>!/验收/.test(name)).map(([name,lines])=>[name,lines.join('\n').trim()]));
|
|
13
|
+
}
|
|
14
|
+
export function renderSliceContractView(ref,{root=process.cwd(),unit_id}={}) {
|
|
15
|
+
const {contract,raw,binding,sources}=readSliceContract(ref,{root,diagnostic:true});
|
|
16
|
+
if(raw.status==='blocked') {
|
|
17
|
+
let report;try{report=JSON.parse(fs.readFileSync(safe(root,`${ref}.preparation.json`),'utf8'));if(report.binding.digest!==binding.digest)report=undefined;}catch{}
|
|
18
|
+
const blockers=report?.blockers||[{code:'SLICE_DIAGNOSTICS_UNAVAILABLE',reason:'未找到绑定当前字节的准备报告,需重新准备'}];
|
|
19
|
+
return {read_only:true,diagnostic_only:true,binding,status:'blocked',approval_validity:'阻断草案不可批准或执行',blockers,markdown:`# Slice 诊断\n\n${ref} · ${binding.digest}\n\n阻断草案不可批准或执行。\n\n`+blockers.map(b=>`- ${b.code} · ${b.field||'slice'}:${b.reason};${b.recovery||'重新准备'}`).join('\n')};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const displayed=unit_id?selectSliceWorkUnit(contract,unit_id):contract;
|
|
23
|
+
const task=unit_id?contract.work_units?.filter(u=>u.id===unit_id):null;
|
|
24
|
+
if(task&&task.length!==1)throw new TypeError(`工作单元缺失或不唯一: ${unit_id}`);
|
|
25
|
+
const view={ticket_state:raw.ticket_policy?{owner:raw.ticket_policy.state_owner,frozen_status:/^---\r?\n([\s\S]*?)\r?\n---/.test(sources.ticket.text)?parseSliceYaml(/^---\r?\n([\s\S]*?)\r?\n---/.exec(sources.ticket.text)[1]).status||'未记录':'未记录',current_status:'请读取主 tracker 或当前任务包',requirement_version:sources.ticket.version}:{owner:'legacy-ticket'},read_only:true,view_kind:unit_id?'work-unit':'review',binding,status:raw.status,approval_validity:'未核验;本视图不授予执行权限',sources:Object.fromEntries(Object.entries(sources).map(([k,{text,...b}])=>[k,b])),acceptance:raw.schema_version===3?sliceAcceptanceText(raw,sources):{},summary:sources.ticket?sections(sources.ticket.text.replace(/^---\n[\s\S]*?\n---\n/,'')):{说明:'v2 原合同未提供统一摘要来源'},constraints:displayed.common,extensions:{frontend:displayed.frontend,backend:displayed.backend,api:displayed.contract,cross_repo:displayed.cross_repo},...(task?{task:task[0].work_unit||task[0]}:{})};
|
|
26
|
+
const lines=[`# Slice ${raw.slice_id}`,`权威合同:${ref} · ${raw.contract_version} · ${binding.digest}`,`状态:${raw.status};${view.approval_validity}`];
|
|
27
|
+
for(const [name,pattern]of [['交付目标',/目标|构建/],['关键取舍',/取舍/],['风险',/风险/],['待决定事项',/待|决定/]]) { const rows=Object.entries(view.summary).filter(([key])=>pattern.test(key)&&!/^非目标/.test(key));lines.push(`## ${name}`,rows.map(([,text])=>text).filter(Boolean).join('\n')||'未提供说明,需在审查时核实。'); }
|
|
28
|
+
lines.push('## 实施范围',Object.entries(view.summary).filter(([name])=>/范围|非目标/.test(name)).map(([name,text])=>`${name}:${text}`).join('\n')||'未提供业务范围说明,需核对目标、工作单元与写边界。',`工程:${displayed.common?.project_roots?.join(', ') || '见原合同'}`,`允许写入:${displayed.common?.allowed_write_paths?.join(', ') || '见原合同'}`);
|
|
29
|
+
lines.push('## 验收',...Object.entries(view.acceptance).map(([id,text])=>`- ${id}: ${text}`));
|
|
30
|
+
if(raw.ticket_policy)lines.push('## 状态来源',`需求版本:${view.ticket_state.requirement_version};冻结时状态:${view.ticket_state.frozen_status}。当前执行状态:${view.ticket_state.current_status}。`);
|
|
31
|
+
if(view.task)lines.push('## 当前任务',`行为:${view.task.behavior}`,`写范围:${view.task.allowed_write_paths.join(', ')}`,`验证:${view.task.verification_commands.join('; ')}`);
|
|
32
|
+
lines.push('## 执行停止条件','来源或批准过期、越界、缺少证据、验证失败、drift / violation / new_impacts 时停止并回交。','<details><summary>完整工程约束与来源</summary>','', '```json',JSON.stringify({constraints:view.constraints,extensions:view.extensions,task:view.task,sources:view.sources},null,2),'```','</details>');
|
|
33
|
+
view.markdown=lines.join('\n\n');
|
|
34
|
+
return view;
|
|
35
|
+
}
|
|
36
|
+
export function diffSliceContracts(beforeRef,afterRef,{root=process.cwd(),beforeRoot=root}={}) {
|
|
37
|
+
const read=(base,ref)=>{const bytes=fs.readFileSync(safe(base,ref));return{raw:sourceSliceContract(parseSliceYaml(bytes)),binding:{ref,digest:hash(bytes)}};};
|
|
38
|
+
const before=read(beforeRoot,beforeRef),after=read(root,afterRef),changes=[];
|
|
39
|
+
function walk(a,b,p) {
|
|
40
|
+
if(digest(a??null)===digest(b??null)&&((a===undefined)===(b===undefined)))return;
|
|
41
|
+
if(a&&b&&typeof a==='object'&&typeof b==='object'&&!Array.isArray(a)&&!Array.isArray(b)) {
|
|
42
|
+
for(const key of new Set([...Object.keys(a),...Object.keys(b)]))walk(a[key],b[key],p?`${p}.${key}`:key);
|
|
43
|
+
}else changes.push({path:p,before:a??null,after:b??null,category:/^(scope\.(allowed_write_paths|project_roots)|work_units)/.test(p)?'scope':/^acceptance/.test(p)?'acceptance':/^(ticket_policy|basis\.ticket|contract_version|status)/.test(p)?'authorization':'engineering-detail',evidence:{before:before.binding,after:after.binding},decision_impact:'待独立专业审查判定'});
|
|
44
|
+
}
|
|
45
|
+
walk(before.raw,after.raw,'');
|
|
46
|
+
const sourceChecks=[];
|
|
47
|
+
for(const [label,entry,base]of [['before',before,beforeRoot],['after',after,root]]) {
|
|
48
|
+
try {if(entry.raw.schema_version!==3)throw new Error('v2 未冻结统一来源快照');readSliceSources(entry.raw,{root:base});sourceChecks.push({side:label,result:'current'});}
|
|
49
|
+
catch(error){sourceChecks.push({side:label,result:'unknown-or-stale',reason:error.message});}
|
|
50
|
+
}
|
|
51
|
+
return {read_only:true,before:before.binding,after:after.binding,bytes_changed:before.binding.digest!==after.binding.digest,category:changes.length?'requires-review':sourceChecks.some(x=>x.result!=='current')?'unknown-or-stale':before.binding.digest===after.binding.digest?'unchanged':'presentation-only',changes,source_checks:sourceChecks,approval_reusable:false,explanation:'字节变化后须重新绑定;用户确认是否延续由现有协议和独立专业审查裁决。'};
|
|
52
|
+
}
|