create-yss-spec 2.2.3 → 2.2.5
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 +17 -1
- package/package.json +1 -1
- package/src/cli.js +15 -1
- package/src/self-update.js +277 -0
- package/template/.agents/skills/yss-domain/SKILL.md +5 -4
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.agents/skills/yss-router/SKILL.md +4 -2
- package/template/.agents/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.agents/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.agents/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.agents/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.agents/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.agents/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.agents/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.agents/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.agents/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.agents/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.agents/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.agents/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.agents/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.agents/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.agents/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.agents/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.agents/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.agents/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.agents/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.agents/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.agents/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.agents/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.agents/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.claude/skills/yss-domain/SKILL.md +5 -4
- package/template/.claude/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.claude/skills/yss-router/SKILL.md +4 -2
- package/template/.claude/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.claude/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.claude/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.claude/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.claude/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.claude/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.claude/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.claude/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.claude/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.claude/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.claude/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.claude/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.claude/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.claude/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.claude/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.claude/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.claude/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.claude/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.claude/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.claude/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.claude/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.claude/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.claude/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.claude/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.claude/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.claude/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.claude/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.claude/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.claude/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.claude/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.codex/skills/yss-domain/SKILL.md +5 -4
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.codex/skills/yss-router/SKILL.md +4 -2
- package/template/.codex/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.codex/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.codex/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.codex/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.codex/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.codex/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.codex/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.codex/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.codex/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.codex/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.codex/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.codex/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.codex/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.codex/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.codex/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.codex/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.codex/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.codex/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.codex/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.codex/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.codex/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.codex/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.codex/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.cursor/skills/yss-domain/SKILL.md +5 -4
- package/template/.cursor/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.cursor/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.cursor/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.cursor/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.cursor/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.cursor/skills/yss-router/SKILL.md +4 -2
- package/template/.cursor/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.cursor/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.cursor/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.cursor/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.cursor/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.cursor/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.cursor/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.cursor/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.cursor/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.cursor/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.cursor/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.cursor/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.cursor/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.cursor/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.cursor/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.cursor/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.cursor/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.cursor/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.cursor/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.cursor/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.cursor/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.cursor/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.cursor/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.hermes/skills/yss-domain/SKILL.md +5 -4
- package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.hermes/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.hermes/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.hermes/skills/yss-router/SKILL.md +4 -2
- package/template/.hermes/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.hermes/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.hermes/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.hermes/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.hermes/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.hermes/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.hermes/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.hermes/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.hermes/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.hermes/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.hermes/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.hermes/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.hermes/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.hermes/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.hermes/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.hermes/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.hermes/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.hermes/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.hermes/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.hermes/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.hermes/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.hermes/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.hermes/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.hermes/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.hermes/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.hermes/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.hermes/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.hermes/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.hermes/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.hermes/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.pi/skills/yss-domain/SKILL.md +5 -4
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.pi/skills/yss-router/SKILL.md +4 -2
- package/template/.pi/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.pi/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.pi/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.pi/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.pi/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.pi/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.pi/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.pi/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.pi/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.pi/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.pi/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.pi/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.pi/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.pi/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.pi/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.pi/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.pi/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.pi/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.pi/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.pi/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.pi/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.pi/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.pi/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.qoder/skills/yss-domain/SKILL.md +5 -4
- package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.qoder/skills/yss-router/SKILL.md +4 -2
- package/template/.qoder/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.qoder/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.qoder/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.qoder/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.qoder/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.qoder/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.qoder/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.qoder/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.qoder/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.qoder/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.qoder/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.qoder/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.qoder/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.qoder/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.qoder/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.qoder/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.qoder/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.qoder/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.qoder/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.qoder/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.qoder/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.qoder/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.qoder/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.qoder/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.qoder/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/.trae/skills/yss-domain/SKILL.md +5 -4
- package/template/.trae/skills/yss-product-lifecycle/SKILL.md +15 -14
- package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +4 -0
- package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +2 -2
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +139 -4
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +6 -3
- package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +7 -2
- package/template/.trae/skills/yss-router/SKILL.md +4 -2
- package/template/.trae/skills/yss-router/references/router-contract.yaml +18 -3
- package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +58 -1
- package/template/.trae/skills/yss-stage-decision/SKILL.md +50 -0
- package/template/.trae/skills/yss-stage-decision/references/domain-strategy-contract.md +26 -0
- package/template/.trae/skills/yss-stage-decision/references/domain-strategy.schema.json +128 -0
- package/template/.trae/skills/yss-stage-decision/references/stage-decision-package-contract.md +19 -0
- package/template/.trae/skills/yss-stage-decision/references/stage-decision-package.schema.json +86 -0
- package/template/.trae/skills/yss-stage-decision/references/validation-rules.md +18 -0
- package/template/.trae/skills/yss-stage-decision/scripts/validate-domain-strategy.mjs +169 -0
- package/template/.trae/skills/yss-stage-decision/scripts/validate-stage-decision-package.mjs +100 -0
- package/template/.trae/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml +15 -0
- package/template/.trae/skills/yss-stage-decision/tests/fixtures/invalid-direction.yaml +58 -0
- package/template/.trae/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml +44 -0
- package/template/.trae/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml +15 -0
- package/template/.trae/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml +49 -0
- package/template/.trae/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml +108 -0
- package/template/.trae/skills/yss-stage-decision/tests/run-scenarios.mjs +68 -0
- package/template/.trae/skills/yss-tactical-design/SKILL.md +33 -0
- package/template/.trae/skills/yss-tactical-design/agents/openai.yaml +4 -0
- package/template/.trae/skills/yss-tactical-design/references/output-template.md +28 -0
- package/template/.trae/skills/yss-tactical-design/references/tactical-design-contract.md +41 -0
- package/template/.trae/skills/yss-tactical-design/references/tactical-design.schema.json +31 -0
- package/template/.trae/skills/yss-tactical-design/references/validation-rules.md +13 -0
- package/template/.trae/skills/yss-tactical-design/scripts/validate-tactical-design.mjs +213 -0
- package/template/.trae/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml +21 -0
- package/template/.trae/skills/yss-tactical-design/tests/fixtures/invalid-missing-consistency-policy.yaml +21 -0
- package/template/.trae/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml +21 -0
- package/template/.trae/skills/yss-tactical-design/tests/fixtures/invalid-stale-upstream-ref.yaml +21 -0
- package/template/.trae/skills/yss-tactical-design/tests/fixtures/invalid-strategic-as-tactical.yaml +21 -0
- package/template/.trae/skills/yss-tactical-design/tests/fixtures/valid-tactical-design.yaml +80 -0
- package/template/.trae/skills/yss-tactical-design/tests/run-scenarios.mjs +47 -0
- package/template/AGENTS.md +22 -5
- package/template/CONTEXT.md +1 -1
- package/template/docs/agents/README.md +1 -1
- package/template/docs/agents/digital-human-roles.md +2 -2
- package/template/docs/agents/digital-human-roles.yaml +7 -1
- package/template/docs/agents/yss-skill-registry.yaml +12 -0
- package/template/docs/architecture/templates/system-overview-design-template.md +1 -0
- package/template/docs/process/lifecycle-artifact-map.md +8 -0
- package/template/docs/process/lifecycle-registry-baseline.json +11 -1
- package/template/docs/process/lifecycle-registry.yaml +46 -2
- package/template/docs/process/schemas/digital-human-task-package.schema.json +107 -0
- package/template/docs/process/schemas/subagent-task-package.schema.json +6 -0
- package/template/docs/process/subagent-collaboration.md +2 -2
- package/template/docs/templates/subagent-task-package-template.md +39 -1
- package/template/scripts/lib/lifecycle-transition.mjs +259 -0
- package/template/scripts/lib/scenario-checks.mjs +96 -2
- package/template/scripts/lib/task-package.mjs +214 -0
- package/template/scripts/verify-digital-human-task-package +14 -0
- package/template/scripts/verify-digital-human-task-package-scenarios +8 -0
- package/template/scripts/verify-lifecycle-transition-scenarios +105 -0
- package/template/scripts/verify-subagent-task-package +8 -0
- package/template/scripts/verify-subagent-task-package-scenarios +196 -0
- package/template/scripts/verify-template +13 -2
- package/template/skills-lock.json +36 -4
- package/template.snapshot.json +4 -4
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
domain_strategy_id: domain-strategy.supplier-admission
|
|
3
|
+
domain_version: v1
|
|
4
|
+
status: approved
|
|
5
|
+
contexts:
|
|
6
|
+
- context_id: SupplierManagement
|
|
7
|
+
name: 供应商管理
|
|
8
|
+
responsibilities: [供应商申请、资料生命周期]
|
|
9
|
+
non_responsibilities: [合规决定、采购订单]
|
|
10
|
+
subdomain_type: Supporting Subdomain
|
|
11
|
+
owner: requirements-manager
|
|
12
|
+
status: confirmed
|
|
13
|
+
- context_id: ComplianceReview
|
|
14
|
+
name: 合规审查
|
|
15
|
+
responsibilities: [资质审查、准入决定、有效期]
|
|
16
|
+
non_responsibilities: [供应商主档、采购订单]
|
|
17
|
+
subdomain_type: Core Domain
|
|
18
|
+
owner: product-manager
|
|
19
|
+
status: confirmed
|
|
20
|
+
- context_id: ProcurementExecution
|
|
21
|
+
name: 采购执行
|
|
22
|
+
responsibilities: [采购选择、采购订单履行]
|
|
23
|
+
non_responsibilities: [合规规则、供应商申请]
|
|
24
|
+
subdomain_type: Supporting Subdomain
|
|
25
|
+
owner: project-manager
|
|
26
|
+
status: confirmed
|
|
27
|
+
subdomains:
|
|
28
|
+
- subdomain_id: subdomain.supplier-management
|
|
29
|
+
name: Supplier Management
|
|
30
|
+
type: Supporting Subdomain
|
|
31
|
+
rationale: 管理申请与资料生命周期,不承载差异化合规决策。
|
|
32
|
+
evidence_refs: [evidence.discovery.supplier]
|
|
33
|
+
- subdomain_id: subdomain.compliance-review
|
|
34
|
+
name: Compliance Review
|
|
35
|
+
type: Core Domain
|
|
36
|
+
rationale: 核心价值候选是企业自有的合规判断和风险规则。
|
|
37
|
+
evidence_refs: [evidence.discovery.compliance]
|
|
38
|
+
relationships:
|
|
39
|
+
- relationship_id: relationship.supplier-to-compliance
|
|
40
|
+
from_context: SupplierManagement
|
|
41
|
+
to_context: ComplianceReview
|
|
42
|
+
relationship_pattern: Customer/Supplier
|
|
43
|
+
semantic_upstream: SupplierManagement
|
|
44
|
+
semantic_downstream: ComplianceReview
|
|
45
|
+
business_authority: SupplierManagement owns applicant facts
|
|
46
|
+
model_change_impact: applicant schema changes require review adaptation
|
|
47
|
+
transport_direction: SubmitSupplierForComplianceReview command
|
|
48
|
+
translation_responsibility: ComplianceReview ACL
|
|
49
|
+
direction_explanation: 申请资料由 SupplierManagement 拥有,但技术请求方向不代表合规规则所有权。
|
|
50
|
+
- relationship_id: relationship.compliance-to-procurement
|
|
51
|
+
from_context: ComplianceReview
|
|
52
|
+
to_context: ProcurementExecution
|
|
53
|
+
relationship_pattern: Published Language
|
|
54
|
+
semantic_upstream: ComplianceReview
|
|
55
|
+
semantic_downstream: ProcurementExecution
|
|
56
|
+
business_authority: ComplianceReview owns admission validity
|
|
57
|
+
model_change_impact: decision validity changes invalidate procurement acceptance
|
|
58
|
+
transport_direction: admission decision events
|
|
59
|
+
translation_responsibility: ProcurementExecution local projection
|
|
60
|
+
direction_explanation: 合规决定是语义上游;采购侧可通过事件接收并在下单时实时校验。
|
|
61
|
+
scenarios:
|
|
62
|
+
- scenario_id: scenario.supplier-submits
|
|
63
|
+
actor: supplier
|
|
64
|
+
preconditions: [供应商资料可编辑]
|
|
65
|
+
commands: [SubmitSupplierApplication]
|
|
66
|
+
rules: [申请材料必须完整]
|
|
67
|
+
events: [SupplierApplicationSubmitted]
|
|
68
|
+
failure_results: [材料不完整时拒绝提交]
|
|
69
|
+
responsible_context: SupplierManagement
|
|
70
|
+
consumers: [ComplianceReview]
|
|
71
|
+
status: confirmed
|
|
72
|
+
- scenario_id: scenario.admission-expires
|
|
73
|
+
actor: compliance-officer
|
|
74
|
+
preconditions: [批准决定存在]
|
|
75
|
+
commands: [EvaluateAdmissionValidity]
|
|
76
|
+
rules: [过期决定不得支持新采购订单]
|
|
77
|
+
events: [SupplierAdmissionExpired]
|
|
78
|
+
failure_results: [采购下单时资格校验失败]
|
|
79
|
+
responsible_context: ComplianceReview
|
|
80
|
+
consumers: [SupplierManagement, ProcurementExecution]
|
|
81
|
+
status: confirmed
|
|
82
|
+
concept_candidates:
|
|
83
|
+
- concept_id: domain-concept.admission-decision
|
|
84
|
+
name: AdmissionDecision
|
|
85
|
+
context_id: ComplianceReview
|
|
86
|
+
identity_features: [decision_id、subject_ref、rule_version]
|
|
87
|
+
lifecycle: [proposed、approved、rejected、expired、revoked]
|
|
88
|
+
possible_tactical_role: Entity candidate
|
|
89
|
+
confidence: high
|
|
90
|
+
status: confirmed
|
|
91
|
+
invariants:
|
|
92
|
+
- invariant_id: invariant.current-admission-required
|
|
93
|
+
statement: 新采购订单必须引用当前有效的准入决定。
|
|
94
|
+
responsible_context: ComplianceReview
|
|
95
|
+
scenario_refs: [scenario.admission-expires]
|
|
96
|
+
verification_method: 领域场景测试和事件版本校验
|
|
97
|
+
terminology_refs: [contexts/SupplierManagement/CONTEXT.md, contexts/ComplianceReview/CONTEXT.md]
|
|
98
|
+
downstream_mapping:
|
|
99
|
+
- domain_change: admission-decision-validity
|
|
100
|
+
impacts: [spec, openapi, procurement-acceptance-tests]
|
|
101
|
+
propagation: stale
|
|
102
|
+
reapproval_condition: ComplianceReview 决定和有效期重新批准
|
|
103
|
+
evidence_refs: [evidence.discovery.supplier, evidence.discovery.compliance]
|
|
104
|
+
approval:
|
|
105
|
+
approval_ref: .agents/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml
|
|
106
|
+
approver: role.product-manager
|
|
107
|
+
persisted_ref: docs/.scratch/supplier/domain/domain-strategy-v1.yaml
|
|
108
|
+
current_version: v1
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
|
|
8
|
+
const root = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const validator = join(root, "..", "scripts", "validate-domain-strategy.mjs");
|
|
10
|
+
const packageValidator = join(root, "..", "scripts", "validate-stage-decision-package.mjs");
|
|
11
|
+
const valid = join(root, "fixtures", "valid-supplier-domain.yaml");
|
|
12
|
+
const invalid = join(root, "fixtures", "invalid-direction.yaml");
|
|
13
|
+
const validPackage = join(root, "fixtures", "valid-stage-decision-package.yaml");
|
|
14
|
+
const invalidPackage = join(root, "fixtures", "invalid-stage-decision-blocker.yaml");
|
|
15
|
+
const run = (file) => spawnSync(process.execPath, [validator, file], { encoding: "utf8" });
|
|
16
|
+
const pass = run(valid);
|
|
17
|
+
if (pass.status !== 0) throw new Error(`valid fixture should pass: ${pass.stderr}`);
|
|
18
|
+
const fail = run(invalid);
|
|
19
|
+
if (fail.status === 0 || !fail.stderr.includes("direction_explanation")) throw new Error("invalid direction fixture should be blocked");
|
|
20
|
+
const packagePass = spawnSync(process.execPath, [packageValidator, validPackage], { encoding: "utf8" });
|
|
21
|
+
if (packagePass.status !== 0) throw new Error(`valid stage decision package should pass: ${packagePass.stderr}`);
|
|
22
|
+
const packageFail = spawnSync(process.execPath, [packageValidator, invalidPackage], { encoding: "utf8" });
|
|
23
|
+
if (packageFail.status === 0 || !packageFail.stderr.includes("blocker")) throw new Error("blocker package should be blocked");
|
|
24
|
+
|
|
25
|
+
const temporaryRoot = await mkdtemp(join(tmpdir(), "yss-stage-decision-pressure-"));
|
|
26
|
+
try {
|
|
27
|
+
const validSource = await readFile(valid, "utf8");
|
|
28
|
+
const sharedKernel = join(temporaryRoot, "shared-kernel.yaml");
|
|
29
|
+
await writeFile(sharedKernel, validSource.replace("relationship_pattern: Customer/Supplier", "relationship_pattern: Shared Kernel"));
|
|
30
|
+
const sharedKernelResult = run(sharedKernel);
|
|
31
|
+
if (sharedKernelResult.status === 0 || !sharedKernelResult.stderr.includes("shared_kernel_approval_ref")) throw new Error("unapproved Shared Kernel should be blocked");
|
|
32
|
+
const unknownContext = join(temporaryRoot, "unknown-context.yaml");
|
|
33
|
+
await writeFile(unknownContext, validSource.replace("to_context: ComplianceReview", "to_context: UnknownContext"));
|
|
34
|
+
const unknownContextResult = run(unknownContext);
|
|
35
|
+
if (unknownContextResult.status === 0 || !unknownContextResult.stderr.includes("未引用已声明上下文")) throw new Error("unknown context should be blocked");
|
|
36
|
+
const wrongArrayType = join(temporaryRoot, "wrong-array-type.yaml");
|
|
37
|
+
await writeFile(wrongArrayType, validSource.replace("responsibilities: [供应商申请、资料生命周期]", "responsibilities: [42]"));
|
|
38
|
+
const wrongArrayTypeResult = run(wrongArrayType);
|
|
39
|
+
if (wrongArrayTypeResult.status === 0 || !wrongArrayTypeResult.stderr.includes("responsibilities[0]")) throw new Error("non-string array item should be blocked");
|
|
40
|
+
const missingSubdomainType = join(temporaryRoot, "missing-subdomain-type.yaml");
|
|
41
|
+
await writeFile(missingSubdomainType, validSource.replace(" subdomain_type: Supporting Subdomain\n", ""));
|
|
42
|
+
const missingSubdomainTypeResult = run(missingSubdomainType);
|
|
43
|
+
if (missingSubdomainTypeResult.status === 0 || !missingSubdomainTypeResult.stderr.includes("subdomain_type 缺失")) throw new Error("missing subdomain type should be blocked");
|
|
44
|
+
const wrongReferenceType = join(temporaryRoot, "wrong-reference-type.yaml");
|
|
45
|
+
await writeFile(wrongReferenceType, validSource.replace("terminology_refs: [contexts/SupplierManagement/CONTEXT.md, contexts/ComplianceReview/CONTEXT.md]", "terminology_refs: [42]"));
|
|
46
|
+
const wrongReferenceTypeResult = run(wrongReferenceType);
|
|
47
|
+
if (wrongReferenceTypeResult.status === 0 || !wrongReferenceTypeResult.stderr.includes("terminology_refs[0]")) throw new Error("non-string terminology reference should be blocked");
|
|
48
|
+
const emptyDomainCollections = join(temporaryRoot, "empty-domain-collections.yaml");
|
|
49
|
+
await writeFile(emptyDomainCollections, validSource.replace(/contexts:\n[\s\S]*?subdomains:/, "contexts: []\nsubdomains:").replace(/subdomains:\n[\s\S]*?relationships:/, "subdomains: []\nrelationships:").replace(/scenarios:\n[\s\S]*?concept_candidates:/, "scenarios: []\nconcept_candidates:"));
|
|
50
|
+
const emptyDomainCollectionsResult = run(emptyDomainCollections);
|
|
51
|
+
if (emptyDomainCollectionsResult.status === 0 || !emptyDomainCollectionsResult.stderr.includes("contexts 必须是至少 1 项的数组")) throw new Error("empty DDD collections should be blocked");
|
|
52
|
+
const wrongDomainApproval = join(temporaryRoot, "wrong-domain-approval.yaml");
|
|
53
|
+
await writeFile(wrongDomainApproval, validSource.replace("approval_ref: .agents/skills/yss-stage-decision/tests/fixtures/domain-strategy-approval.yaml", "approval_ref: docs/.scratch/does-not-exist.yaml"));
|
|
54
|
+
const wrongDomainApprovalResult = run(wrongDomainApproval);
|
|
55
|
+
if (wrongDomainApprovalResult.status === 0 || !wrongDomainApprovalResult.stderr.includes("approval.approval_ref")) throw new Error("unreadable domain approval ref should be blocked");
|
|
56
|
+
const packageSource = await readFile(validPackage, "utf8");
|
|
57
|
+
const packageWrongArrayType = join(temporaryRoot, "package-wrong-array-type.yaml");
|
|
58
|
+
await writeFile(packageWrongArrayType, packageSource.replace("target_users: [采购专员、合规专员]", "target_users: [42]"));
|
|
59
|
+
const packageWrongArrayTypeResult = spawnSync(process.execPath, [packageValidator, packageWrongArrayType], { encoding: "utf8" });
|
|
60
|
+
if (packageWrongArrayTypeResult.status === 0 || !packageWrongArrayTypeResult.stderr.includes("target_users[0]")) throw new Error("package non-string array item should be blocked");
|
|
61
|
+
const packageWrongApproval = join(temporaryRoot, "package-wrong-approval.yaml");
|
|
62
|
+
await writeFile(packageWrongApproval, packageSource.replace("approval_ref: .agents/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml", "approval_ref: docs/.scratch/does-not-exist.yaml"));
|
|
63
|
+
const packageWrongApprovalResult = spawnSync(process.execPath, [packageValidator, packageWrongApproval], { encoding: "utf8" });
|
|
64
|
+
if (packageWrongApprovalResult.status === 0 || !packageWrongApprovalResult.stderr.includes("approval_ref")) throw new Error("unreadable approval ref should be blocked");
|
|
65
|
+
} finally {
|
|
66
|
+
await rm(temporaryRoot, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
process.stdout.write("DDD strategic design scenarios passed\n");
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: yss-tactical-design
|
|
3
|
+
description: 在 YSS 技术分析阶段将批准的战略领域输入细化为可审查的聚合、行为、一致性和 Gateway 设计;不生成生产代码。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# yss-tactical-design
|
|
7
|
+
|
|
8
|
+
本 skill 负责 DDD 战术设计,不新增生命周期主阶段,也不替代 `yss-stage-decision` 或 `yss-domain`。
|
|
9
|
+
|
|
10
|
+
## 适用边界
|
|
11
|
+
|
|
12
|
+
- 由 `yss-product-lifecycle` 在 `work-unit.technical-analysis` 中按领域影响条件调度。
|
|
13
|
+
- 输入必须是版本当前的 Spec、功能架构、战略 DDD、状态矩阵、OpenAPI Draft / Freeze、ADR 和工程约束。
|
|
14
|
+
- 默认将结果写入系统概要设计 / 数据架构中的 Tactical DDD Check;聚合、状态机、一致性或持久化映射复杂到无法清楚表达时,才升级为独立战术设计文档。
|
|
15
|
+
- 没有聚合、状态、不变量、一致性或领域边界影响时返回 `not-applicable` 及原因,不生成空设计。
|
|
16
|
+
|
|
17
|
+
## 设计内容
|
|
18
|
+
|
|
19
|
+
必须明确 Aggregate Root、Entity、Value Object、领域行为、状态转换、不变量、一致性 / 事务、幂等 / 并发、Domain Event、Gateway、持久化映射和 Domain / Application 测试 seam。
|
|
20
|
+
|
|
21
|
+
数据库表、HTTP 调用链或菜单结构不能单独决定聚合边界;OpenAPI 不得暴露内部聚合、Repository 或持久化表结构。
|
|
22
|
+
|
|
23
|
+
## 输出与状态
|
|
24
|
+
|
|
25
|
+
输出结构化 tactical-design contract、验证结果、评审引用和影响标记。状态使用 `draft`、`ready-for-human`、`approved`、`blocked`、`stale`、`drift`、`new_impacts`。
|
|
26
|
+
|
|
27
|
+
本 skill 不能自行批准资产、设置 `ready-for-agent`、创建 Ticket 或修改生命周期状态。批准由 `yss-product-lifecycle` 维护;独立架构评审使用 `evidence.tactical-design-review`。
|
|
28
|
+
|
|
29
|
+
## 与实现交接
|
|
30
|
+
|
|
31
|
+
批准且版本当前的战术设计合同由 `Slice Implementation Contract` 引用,再由 `yss-domain` 使用 `behavior-tdd` 实现。`yss-domain` 不得静默重新定义聚合或不变量;发现新的 API、状态、数据或架构影响时必须返回 `new_impacts` / `drift` 并重新路由。
|
|
32
|
+
|
|
33
|
+
合同、Schema、校验规则和示例见 `references/`;使用 `scripts/validate-tactical-design.mjs` 做只读验证。该 skill 不生成 Java、Repository、Controller、DTO、OpenAPI Freeze、实现 Ticket 或生产代码。
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
pipeline: <feature-id>
|
|
2
|
+
stage: system-data-engineering
|
|
3
|
+
status: draft
|
|
4
|
+
owner: ai
|
|
5
|
+
|
|
6
|
+
# <功能名称> Tactical DDD Design
|
|
7
|
+
|
|
8
|
+
## 上游引用
|
|
9
|
+
|
|
10
|
+
| 资产 | ref | version / digest | 状态 |
|
|
11
|
+
|---|---|---|---|
|
|
12
|
+
| Spec | | | |
|
|
13
|
+
| Strategic DDD | | | |
|
|
14
|
+
| 状态矩阵 | | | |
|
|
15
|
+
| OpenAPI / 无 API 影响记录 | | | |
|
|
16
|
+
|
|
17
|
+
## Tactical DDD Check
|
|
18
|
+
|
|
19
|
+
| 限界上下文 | 聚合根 | Entity / Value Object | 行为与不变量 | 一致性边界 | Gateway | 测试 seam |
|
|
20
|
+
|---|---|---|---|---|---|---|
|
|
21
|
+
| | | | | | | |
|
|
22
|
+
|
|
23
|
+
## 结论
|
|
24
|
+
|
|
25
|
+
- 复杂度升级:是 / 否
|
|
26
|
+
- API / 数据 / 状态新增影响:是 / 否
|
|
27
|
+
- 评审结论:Approved / Blocked
|
|
28
|
+
- 下一步:
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Tactical DDD Design Contract
|
|
2
|
+
|
|
3
|
+
## 输入
|
|
4
|
+
|
|
5
|
+
必须引用批准且版本当前的 Spec、功能架构、战略 DDD、原型状态矩阵、OpenAPI Draft / Freeze(或无 API 影响记录)、ADR 和工程约束。所有引用都必须带版本或 digest;不可读或过期引用返回 `blocked` / `stale`。
|
|
6
|
+
|
|
7
|
+
## 输出
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
schema_version: 1
|
|
11
|
+
tactical_design_id: tactical-design.<feature>
|
|
12
|
+
tactical_version: v1
|
|
13
|
+
status: draft | ready-for-human | approved | blocked | stale | drift | new_impacts | not-applicable
|
|
14
|
+
context_ref: <限界上下文引用>
|
|
15
|
+
aggregate_catalog: []
|
|
16
|
+
entity_catalog: []
|
|
17
|
+
value_object_catalog: []
|
|
18
|
+
behavior_catalog: []
|
|
19
|
+
invariant_catalog: []
|
|
20
|
+
state_transition_catalog: []
|
|
21
|
+
consistency_policy: {}
|
|
22
|
+
domain_event_catalog: []
|
|
23
|
+
gateway_catalog: []
|
|
24
|
+
persistence_mapping: []
|
|
25
|
+
test_seams: []
|
|
26
|
+
adr_candidates: []
|
|
27
|
+
upstream_impact: {}
|
|
28
|
+
version: v1
|
|
29
|
+
digest: sha256:<digest>
|
|
30
|
+
evidence_refs: []
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 设计规则
|
|
34
|
+
|
|
35
|
+
1. 聚合边界由业务行为和不变量决定,不由数据库表或外键自动推导。
|
|
36
|
+
2. 每个聚合根必须列出行为、不变量和一致性边界。
|
|
37
|
+
3. 状态转换必须绑定领域行为,禁止只有状态字段而没有行为语义。
|
|
38
|
+
4. Gateway 接口属于 Domain,Repository / Mapper / GatewayImpl 属于 Infrastructure。
|
|
39
|
+
5. OpenAPI schema 使用上下文公开语言,不泄漏内部聚合或持久化结构。
|
|
40
|
+
6. 复杂跨聚合一致性、并发、幂等、事件补偿或持久化错位必须写明策略,必要时升级独立文档。
|
|
41
|
+
7. 实现发现新影响时必须阻断并回到生命周期重新路由。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://yss.dev/schemas/tactical-design.schema.json",
|
|
4
|
+
"title": "YSS Tactical DDD Design Contract",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["schema_version", "tactical_design_id", "tactical_version", "status", "context_ref", "aggregate_catalog", "entity_catalog", "value_object_catalog", "behavior_catalog", "invariant_catalog", "state_transition_catalog", "consistency_policy", "domain_event_catalog", "gateway_catalog", "persistence_mapping", "test_seams", "adr_candidates", "upstream_impact", "version", "digest", "evidence_refs"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schema_version": {"const": 1},
|
|
9
|
+
"tactical_design_id": {"type": "string", "pattern": "^tactical-design\\.[a-z0-9][a-z0-9-]*$"},
|
|
10
|
+
"tactical_version": {"type": "string", "pattern": "^v[0-9]+$"},
|
|
11
|
+
"status": {"enum": ["draft", "ready-for-human", "approved", "blocked", "stale", "drift", "new_impacts", "not-applicable"]},
|
|
12
|
+
"context_ref": {"type": "string", "minLength": 1},
|
|
13
|
+
"aggregate_catalog": {"type": "array", "minItems": 1},
|
|
14
|
+
"entity_catalog": {"type": "array", "minItems": 1},
|
|
15
|
+
"value_object_catalog": {"type": "array"},
|
|
16
|
+
"behavior_catalog": {"type": "array", "minItems": 1},
|
|
17
|
+
"invariant_catalog": {"type": "array", "minItems": 1},
|
|
18
|
+
"state_transition_catalog": {"type": "array", "minItems": 1},
|
|
19
|
+
"consistency_policy": {"type": "object", "minProperties": 1},
|
|
20
|
+
"domain_event_catalog": {"type": "array"},
|
|
21
|
+
"gateway_catalog": {"type": "array", "minItems": 1},
|
|
22
|
+
"persistence_mapping": {"type": "array", "minItems": 1},
|
|
23
|
+
"test_seams": {"type": "array", "minItems": 1},
|
|
24
|
+
"adr_candidates": {"type": "array"},
|
|
25
|
+
"upstream_impact": {"type": "object", "minProperties": 1},
|
|
26
|
+
"version": {"type": "string", "pattern": "^v[0-9]+$"},
|
|
27
|
+
"digest": {"type": "string", "pattern": "^sha256:[A-Fa-f0-9]{64}$"},
|
|
28
|
+
"evidence_refs": {"type": "array", "items": {"type": "string"}}
|
|
29
|
+
},
|
|
30
|
+
"additionalProperties": true
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Tactical DDD Validation Rules
|
|
2
|
+
|
|
3
|
+
- 根对象必须包含合同要求的字段,状态只能使用生命周期状态集合。
|
|
4
|
+
- `aggregate_catalog`、`behavior_catalog`、`invariant_catalog`、`state_transition_catalog`、`consistency_policy` 和 `test_seams` 不能为空。
|
|
5
|
+
- 聚合、Entity、Value Object、行为、不变量、状态转换、事件和 Gateway ID 必须唯一且引用已声明对象。
|
|
6
|
+
- 聚合根必须是 Entity;Entity 和 Value Object 不得跨聚合隐式共享身份。
|
|
7
|
+
- 每个行为至少引用一个聚合和一个不变量;每个状态转换必须引用已声明行为。
|
|
8
|
+
- `api_exposure: internal-only` 是内部聚合的唯一允许值;其他值需要回到 API 影响分析。
|
|
9
|
+
- Gateway 的 `layer` 必须为 `Domain`,持久化实现不得出现在 Domain 目录。
|
|
10
|
+
- `consistency_policy` 必须说明事务边界、并发、幂等和跨聚合策略。
|
|
11
|
+
- 上游引用发生版本变化时,设计标记为 `stale`,不得进入 `approved` 或 `ready-for-agent`。
|
|
12
|
+
- 若合同标记 `model_origin: strategic-concept`,必须阻断并要求完成战术细化。
|
|
13
|
+
- 当 `complexity.escalate_to_standalone` 为真时,必须提供独立文档引用;否则仅允许作为嵌入式 Tactical DDD Check 消费。
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
|
|
5
|
+
|
|
6
|
+
const required = [
|
|
7
|
+
"schema_version", "tactical_design_id", "tactical_version", "status", "context_ref",
|
|
8
|
+
"aggregate_catalog", "entity_catalog", "value_object_catalog", "behavior_catalog",
|
|
9
|
+
"invariant_catalog", "state_transition_catalog", "consistency_policy", "domain_event_catalog",
|
|
10
|
+
"gateway_catalog", "persistence_mapping", "test_seams", "adr_candidates", "upstream_impact",
|
|
11
|
+
"version", "digest", "evidence_refs"
|
|
12
|
+
];
|
|
13
|
+
const statuses = new Set(["draft", "ready-for-human", "approved", "blocked", "stale", "drift", "new_impacts", "not-applicable"]);
|
|
14
|
+
const idPatterns = {
|
|
15
|
+
tactical_design_id: /^tactical-design\.[a-z0-9][a-z0-9-]*$/,
|
|
16
|
+
aggregate_id: /^aggregate\.[a-z0-9][a-z0-9-]*$/,
|
|
17
|
+
entity_id: /^entity\.[a-z0-9][a-z0-9-]*$/,
|
|
18
|
+
value_object_id: /^value-object\.[a-z0-9][a-z0-9-]*$/,
|
|
19
|
+
behavior_id: /^behavior\.[a-z0-9][a-z0-9-]*$/,
|
|
20
|
+
invariant_id: /^invariant\.[a-z0-9][a-z0-9-]*$/,
|
|
21
|
+
transition_id: /^transition\.[a-z0-9][a-z0-9-]*$/,
|
|
22
|
+
event_id: /^domain-event\.[a-z0-9][a-z0-9-]*$/,
|
|
23
|
+
gateway_id: /^gateway\.[a-z0-9][a-z0-9-]*$/,
|
|
24
|
+
seam_id: /^test-seam\.[a-z0-9][a-z0-9-]*$/,
|
|
25
|
+
version: /^v[0-9]+$/
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const isObject = (value) => value && typeof value === "object" && !Array.isArray(value);
|
|
29
|
+
const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0;
|
|
30
|
+
const list = (value) => Array.isArray(value);
|
|
31
|
+
|
|
32
|
+
function unique(items, label, errors) {
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
for (const item of items) {
|
|
35
|
+
if (seen.has(item)) errors.push(`${label} 重复: ${item}`);
|
|
36
|
+
seen.add(item);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function requireField(object, field, path, errors) {
|
|
41
|
+
if (!Object.prototype.hasOwnProperty.call(object ?? {}, field) || object[field] === null || object[field] === undefined) {
|
|
42
|
+
errors.push(`${path}.${field} 缺失`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function requireString(object, field, path, errors) {
|
|
47
|
+
requireField(object, field, path, errors);
|
|
48
|
+
if (Object.prototype.hasOwnProperty.call(object ?? {}, field) && !nonEmpty(object[field])) errors.push(`${path}.${field} 必须是非空字符串`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function requireArray(object, field, path, errors, minimum = 0) {
|
|
52
|
+
requireField(object, field, path, errors);
|
|
53
|
+
if (Object.prototype.hasOwnProperty.call(object ?? {}, field) && (!list(object[field]) || object[field].length < minimum)) {
|
|
54
|
+
errors.push(`${path}.${field} 必须是至少 ${minimum} 项的数组`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function requireId(value, kind, path, errors) {
|
|
59
|
+
if (value !== undefined && value !== null && !idPatterns[kind].test(String(value))) errors.push(`${path} 格式非法`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function refsExist(values, known, path, errors) {
|
|
63
|
+
for (const [index, value] of (values ?? []).entries()) {
|
|
64
|
+
if (!known.has(value)) errors.push(`${path}[${index}] 引用了未声明对象: ${value}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function validate(data) {
|
|
69
|
+
const errors = [];
|
|
70
|
+
if (!isObject(data)) return ["合同必须是对象"];
|
|
71
|
+
for (const field of required) requireField(data, field, "root", errors);
|
|
72
|
+
if (data.schema_version !== 1) errors.push("schema_version 必须为 1");
|
|
73
|
+
requireId(data.tactical_design_id, "tactical_design_id", "tactical_design_id", errors);
|
|
74
|
+
for (const field of ["tactical_version", "version"]) if (data[field] !== undefined && !idPatterns.version.test(String(data[field]))) errors.push(`${field} 必须形如 v1`);
|
|
75
|
+
if (data.status !== undefined && !statuses.has(data.status)) errors.push(`status 非法: ${data.status}`);
|
|
76
|
+
if (data.digest !== undefined && !/^sha256:[A-Fa-f0-9]{64}$/.test(String(data.digest))) errors.push("digest 必须为 sha256 加 64 位十六进制");
|
|
77
|
+
|
|
78
|
+
for (const field of ["aggregate_catalog", "entity_catalog", "behavior_catalog", "invariant_catalog", "state_transition_catalog", "gateway_catalog", "persistence_mapping", "test_seams"]) {
|
|
79
|
+
requireArray(data, field, "root", errors, 1);
|
|
80
|
+
}
|
|
81
|
+
for (const field of ["value_object_catalog", "domain_event_catalog", "adr_candidates", "evidence_refs"]) requireArray(data, field, "root", errors);
|
|
82
|
+
if (!isObject(data.consistency_policy)) errors.push("consistency_policy 必须是对象");
|
|
83
|
+
if (!isObject(data.upstream_impact)) errors.push("upstream_impact 必须是对象");
|
|
84
|
+
if (isObject(data.consistency_policy)) {
|
|
85
|
+
for (const field of ["transaction_boundary", "concurrency", "idempotency", "cross_aggregate_strategy"]) requireString(data.consistency_policy, field, "consistency_policy", errors);
|
|
86
|
+
}
|
|
87
|
+
if (isObject(data.upstream_impact)) {
|
|
88
|
+
for (const field of ["spec_ref", "strategic_ref", "api_ref", "data_ref"]) requireString(data.upstream_impact, field, "upstream_impact", errors);
|
|
89
|
+
if (data.upstream_impact.upstream_current === false && data.status !== "stale") errors.push("上游已过期时 status 必须为 stale");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const aggregates = list(data.aggregate_catalog) ? data.aggregate_catalog : [];
|
|
93
|
+
const entities = list(data.entity_catalog) ? data.entity_catalog : [];
|
|
94
|
+
const values = list(data.value_object_catalog) ? data.value_object_catalog : [];
|
|
95
|
+
const behaviors = list(data.behavior_catalog) ? data.behavior_catalog : [];
|
|
96
|
+
const invariants = list(data.invariant_catalog) ? data.invariant_catalog : [];
|
|
97
|
+
const transitions = list(data.state_transition_catalog) ? data.state_transition_catalog : [];
|
|
98
|
+
const events = list(data.domain_event_catalog) ? data.domain_event_catalog : [];
|
|
99
|
+
const gateways = list(data.gateway_catalog) ? data.gateway_catalog : [];
|
|
100
|
+
const mappings = list(data.persistence_mapping) ? data.persistence_mapping : [];
|
|
101
|
+
const seams = list(data.test_seams) ? data.test_seams : [];
|
|
102
|
+
const ids = (items, field, kind, label) => {
|
|
103
|
+
const result = new Set();
|
|
104
|
+
unique(items.map((item) => item?.[field]).filter(Boolean), label, errors);
|
|
105
|
+
for (const [index, item] of items.entries()) {
|
|
106
|
+
if (item?.[field]) { requireId(item[field], kind, `${label}[${index}].${field}`, errors); result.add(item[field]); }
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
};
|
|
110
|
+
const aggregateIds = ids(aggregates, "aggregate_id", "aggregate_id", "aggregate_id");
|
|
111
|
+
const entityIds = ids(entities, "entity_id", "entity_id", "entity_id");
|
|
112
|
+
const valueIds = ids(values, "value_object_id", "value_object_id", "value_object_id");
|
|
113
|
+
const behaviorIds = ids(behaviors, "behavior_id", "behavior_id", "behavior_id");
|
|
114
|
+
const invariantIds = ids(invariants, "invariant_id", "invariant_id", "invariant_id");
|
|
115
|
+
const transitionIds = ids(transitions, "transition_id", "transition_id", "transition_id");
|
|
116
|
+
const eventIds = ids(events, "event_id", "event_id", "event_id");
|
|
117
|
+
const gatewayIds = ids(gateways, "gateway_id", "gateway_id", "gateway_id");
|
|
118
|
+
ids(seams, "seam_id", "seam_id", "seam_id");
|
|
119
|
+
|
|
120
|
+
for (const [index, aggregate] of aggregates.entries()) {
|
|
121
|
+
const path = `aggregate_catalog[${index}]`;
|
|
122
|
+
if (!isObject(aggregate)) { errors.push(`${path} 必须是对象`); continue; }
|
|
123
|
+
for (const field of ["aggregate_id", "name", "context_ref", "root_entity", "consistency_boundary"]) requireString(aggregate, field, path, errors);
|
|
124
|
+
requireArray(aggregate, "invariant_refs", path, errors, 1); requireArray(aggregate, "behavior_refs", path, errors, 1);
|
|
125
|
+
if (aggregate.model_origin === "strategic-concept") errors.push(`${path}.model_origin 不得直接把战略概念当作 Aggregate`);
|
|
126
|
+
if (aggregate.api_exposure !== "internal-only") errors.push(`${path}.api_exposure 必须为 internal-only`);
|
|
127
|
+
if (aggregate.root_entity && !entityIds.has(aggregate.root_entity)) errors.push(`${path}.root_entity 未引用 Entity`);
|
|
128
|
+
const rootEntity = entities.find((entity) => entity?.entity_id === aggregate.root_entity);
|
|
129
|
+
if (rootEntity && rootEntity.aggregate_id !== aggregate.aggregate_id) errors.push(`${path}.root_entity 的 aggregate_id 必须与当前 Aggregate 一致`);
|
|
130
|
+
refsExist(aggregate.invariant_refs, invariantIds, `${path}.invariant_refs`, errors);
|
|
131
|
+
refsExist(aggregate.behavior_refs, behaviorIds, `${path}.behavior_refs`, errors);
|
|
132
|
+
}
|
|
133
|
+
for (const [index, entity] of entities.entries()) {
|
|
134
|
+
const path = `entity_catalog[${index}]`;
|
|
135
|
+
if (!isObject(entity)) { errors.push(`${path} 必须是对象`); continue; }
|
|
136
|
+
for (const field of ["entity_id", "name", "aggregate_id", "identity", "lifecycle"]) requireString(entity, field, path, errors);
|
|
137
|
+
if (entity.aggregate_id && !aggregateIds.has(entity.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
138
|
+
}
|
|
139
|
+
for (const [index, value] of values.entries()) {
|
|
140
|
+
const path = `value_object_catalog[${index}]`;
|
|
141
|
+
if (!isObject(value)) { errors.push(`${path} 必须是对象`); continue; }
|
|
142
|
+
for (const field of ["value_object_id", "name", "aggregate_id", "immutable"]) requireField(value, field, path, errors);
|
|
143
|
+
if (typeof value.immutable !== "boolean" || value.immutable !== true) errors.push(`${path}.immutable 必须为 true`);
|
|
144
|
+
if (value.aggregate_id && !aggregateIds.has(value.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
145
|
+
}
|
|
146
|
+
for (const [index, behavior] of behaviors.entries()) {
|
|
147
|
+
const path = `behavior_catalog[${index}]`;
|
|
148
|
+
if (!isObject(behavior)) { errors.push(`${path} 必须是对象`); continue; }
|
|
149
|
+
for (const field of ["behavior_id", "name", "aggregate_id", "command"]) requireString(behavior, field, path, errors);
|
|
150
|
+
for (const field of ["preconditions", "invariant_refs", "postconditions", "event_refs"]) requireArray(behavior, field, path, errors, field === "invariant_refs" ? 1 : 0);
|
|
151
|
+
if (behavior.aggregate_id && !aggregateIds.has(behavior.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
152
|
+
refsExist(behavior.invariant_refs, invariantIds, `${path}.invariant_refs`, errors);
|
|
153
|
+
refsExist(behavior.event_refs, eventIds, `${path}.event_refs`, errors);
|
|
154
|
+
}
|
|
155
|
+
for (const [index, invariant] of invariants.entries()) {
|
|
156
|
+
const path = `invariant_catalog[${index}]`;
|
|
157
|
+
if (!isObject(invariant)) { errors.push(`${path} 必须是对象`); continue; }
|
|
158
|
+
for (const field of ["invariant_id", "aggregate_id", "statement"]) requireString(invariant, field, path, errors);
|
|
159
|
+
if (invariant.aggregate_id && !aggregateIds.has(invariant.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
160
|
+
}
|
|
161
|
+
for (const [index, transition] of transitions.entries()) {
|
|
162
|
+
const path = `state_transition_catalog[${index}]`;
|
|
163
|
+
if (!isObject(transition)) { errors.push(`${path} 必须是对象`); continue; }
|
|
164
|
+
for (const field of ["transition_id", "aggregate_id", "from", "to", "behavior_id"]) requireString(transition, field, path, errors);
|
|
165
|
+
if (transition.aggregate_id && !aggregateIds.has(transition.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
166
|
+
if (transition.behavior_id && !behaviorIds.has(transition.behavior_id)) errors.push(`${path}.behavior_id 未引用行为`);
|
|
167
|
+
}
|
|
168
|
+
for (const [index, event] of events.entries()) {
|
|
169
|
+
const path = `domain_event_catalog[${index}]`;
|
|
170
|
+
if (!isObject(event)) { errors.push(`${path} 必须是对象`); continue; }
|
|
171
|
+
for (const field of ["event_id", "name", "aggregate_id", "delivery"]) requireString(event, field, path, errors);
|
|
172
|
+
requireArray(event, "consumers", path, errors, 0);
|
|
173
|
+
if (event.aggregate_id && !aggregateIds.has(event.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
174
|
+
}
|
|
175
|
+
for (const [index, gateway] of gateways.entries()) {
|
|
176
|
+
const path = `gateway_catalog[${index}]`;
|
|
177
|
+
if (!isObject(gateway)) { errors.push(`${path} 必须是对象`); continue; }
|
|
178
|
+
for (const field of ["gateway_id", "name", "context_ref", "layer"]) requireString(gateway, field, path, errors);
|
|
179
|
+
requireArray(gateway, "capabilities", path, errors, 1);
|
|
180
|
+
if (gateway.layer !== "Domain") errors.push(`${path}.layer 必须为 Domain,Infrastructure 只实现 Gateway`);
|
|
181
|
+
}
|
|
182
|
+
for (const [index, mapping] of mappings.entries()) {
|
|
183
|
+
const path = `persistence_mapping[${index}]`;
|
|
184
|
+
if (!isObject(mapping)) { errors.push(`${path} 必须是对象`); continue; }
|
|
185
|
+
for (const field of ["aggregate_id", "storage_model", "notes"]) requireString(mapping, field, path, errors);
|
|
186
|
+
if (mapping.aggregate_id && !aggregateIds.has(mapping.aggregate_id)) errors.push(`${path}.aggregate_id 未引用 Aggregate`);
|
|
187
|
+
}
|
|
188
|
+
for (const [index, seam] of seams.entries()) {
|
|
189
|
+
const path = `test_seams[${index}]`;
|
|
190
|
+
if (!isObject(seam)) { errors.push(`${path} 必须是对象`); continue; }
|
|
191
|
+
for (const field of ["seam_id", "kind", "subject_ref", "assertion"]) requireString(seam, field, path, errors);
|
|
192
|
+
if (seam.subject_ref && !new Set([...aggregateIds, ...entityIds, ...valueIds, ...behaviorIds, ...invariantIds, ...transitionIds, ...gatewayIds]).has(seam.subject_ref)) errors.push(`${path}.subject_ref 未引用已声明领域对象`);
|
|
193
|
+
}
|
|
194
|
+
if (isObject(data.complexity) && data.complexity.escalate_to_standalone === true && !nonEmpty(data.complexity.standalone_ref)) errors.push("complexity.escalate_to_standalone 为 true 时必须提供 standalone_ref");
|
|
195
|
+
return errors;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function main() {
|
|
199
|
+
const file = process.argv[2];
|
|
200
|
+
if (!file) throw new Error("用法: validate-tactical-design.mjs <contract.yaml>");
|
|
201
|
+
const source = await readFile(file, "utf8");
|
|
202
|
+
const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
|
|
203
|
+
if (document.errors.length) throw new Error(`无法解析合同: ${document.errors[0].message}`);
|
|
204
|
+
const errors = validate(document.toJS({ maxAliasCount: 0 }));
|
|
205
|
+
if (errors.length) {
|
|
206
|
+
process.stderr.write(`${JSON.stringify({ result: "blocked", errors }, null, 2)}\n`);
|
|
207
|
+
process.exitCode = 1;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
process.stdout.write(`${JSON.stringify({ result: "ready-for-lifecycle-review", tactical_design_id: document.get("tactical_design_id"), status: document.get("status") }, null, 2)}\n`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
main().catch((error) => { process.stderr.write(`${error.message}\n`); process.exitCode = 1; });
|
package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-api-leaks-aggregate.yaml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
tactical_design_id: tactical-design.invalid-api
|
|
3
|
+
tactical_version: v1
|
|
4
|
+
status: ready-for-human
|
|
5
|
+
context_ref: context.example
|
|
6
|
+
aggregate_catalog: [{aggregate_id: aggregate.example, name: Example, context_ref: context.example, root_entity: entity.example-root, invariant_refs: [invariant.example], behavior_refs: [behavior.example], consistency_boundary: single, api_exposure: public-aggregate}]
|
|
7
|
+
entity_catalog: [{entity_id: entity.example-root, name: Root, aggregate_id: aggregate.example, identity: id, lifecycle: active}]
|
|
8
|
+
value_object_catalog: []
|
|
9
|
+
behavior_catalog: [{behavior_id: behavior.example, name: Do, aggregate_id: aggregate.example, command: do, preconditions: [ready], invariant_refs: [invariant.example], postconditions: [done], event_refs: []}]
|
|
10
|
+
invariant_catalog: [{invariant_id: invariant.example, aggregate_id: aggregate.example, statement: required}]
|
|
11
|
+
state_transition_catalog: [{transition_id: transition.example, aggregate_id: aggregate.example, from: draft, to: done, behavior_id: behavior.example}]
|
|
12
|
+
consistency_policy: {transaction_boundary: single, concurrency: optimistic, idempotency: guarded, cross_aggregate_strategy: none}
|
|
13
|
+
domain_event_catalog: []
|
|
14
|
+
gateway_catalog: [{gateway_id: gateway.example, name: Gateway, context_ref: context.example, layer: Domain, capabilities: [load]}]
|
|
15
|
+
persistence_mapping: [{aggregate_id: aggregate.example, storage_model: example, notes: mapping}]
|
|
16
|
+
test_seams: [{seam_id: test-seam.example, kind: domain, subject_ref: invariant.example, assertion: behavior}]
|
|
17
|
+
adr_candidates: []
|
|
18
|
+
upstream_impact: {spec_ref: spec@v1, strategic_ref: strategy@v1, api_ref: api@draft, data_ref: data@v1, upstream_current: true}
|
|
19
|
+
version: v1
|
|
20
|
+
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
|
|
21
|
+
evidence_refs: []
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
tactical_design_id: tactical-design.invalid-consistency
|
|
3
|
+
tactical_version: v1
|
|
4
|
+
status: ready-for-human
|
|
5
|
+
context_ref: context.example
|
|
6
|
+
aggregate_catalog: [{aggregate_id: aggregate.example, name: Example, context_ref: context.example, root_entity: entity.example-root, invariant_refs: [invariant.example], behavior_refs: [behavior.example], consistency_boundary: single, api_exposure: internal-only}]
|
|
7
|
+
entity_catalog: [{entity_id: entity.example-root, name: Root, aggregate_id: aggregate.example, identity: id, lifecycle: active}]
|
|
8
|
+
value_object_catalog: []
|
|
9
|
+
behavior_catalog: [{behavior_id: behavior.example, name: Do, aggregate_id: aggregate.example, command: do, preconditions: [ready], invariant_refs: [invariant.example], postconditions: [done], event_refs: []}]
|
|
10
|
+
invariant_catalog: [{invariant_id: invariant.example, aggregate_id: aggregate.example, statement: required}]
|
|
11
|
+
state_transition_catalog: [{transition_id: transition.example, aggregate_id: aggregate.example, from: draft, to: done, behavior_id: behavior.example}]
|
|
12
|
+
consistency_policy: {}
|
|
13
|
+
domain_event_catalog: []
|
|
14
|
+
gateway_catalog: [{gateway_id: gateway.example, name: Gateway, context_ref: context.example, layer: Domain, capabilities: [load]}]
|
|
15
|
+
persistence_mapping: [{aggregate_id: aggregate.example, storage_model: example, notes: mapping}]
|
|
16
|
+
test_seams: [{seam_id: test-seam.example, kind: domain, subject_ref: invariant.example, assertion: behavior}]
|
|
17
|
+
adr_candidates: []
|
|
18
|
+
upstream_impact: {spec_ref: spec@v1, strategic_ref: strategy@v1, api_ref: api@draft, data_ref: data@v1, upstream_current: true}
|
|
19
|
+
version: v1
|
|
20
|
+
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
|
|
21
|
+
evidence_refs: []
|
package/template/.qoder/skills/yss-tactical-design/tests/fixtures/invalid-missing-invariant.yaml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
tactical_design_id: tactical-design.invalid-missing-invariant
|
|
3
|
+
tactical_version: v1
|
|
4
|
+
status: ready-for-human
|
|
5
|
+
context_ref: context.example
|
|
6
|
+
aggregate_catalog: [{aggregate_id: aggregate.example, name: Example, context_ref: context.example, root_entity: entity.example-root, invariant_refs: [], behavior_refs: [behavior.example], consistency_boundary: single, api_exposure: internal-only}]
|
|
7
|
+
entity_catalog: [{entity_id: entity.example-root, name: Root, aggregate_id: aggregate.example, identity: id, lifecycle: active}]
|
|
8
|
+
value_object_catalog: []
|
|
9
|
+
behavior_catalog: [{behavior_id: behavior.example, name: Do, aggregate_id: aggregate.example, command: do, preconditions: [], invariant_refs: [], postconditions: [], event_refs: []}]
|
|
10
|
+
invariant_catalog: []
|
|
11
|
+
state_transition_catalog: [{transition_id: transition.example, aggregate_id: aggregate.example, from: draft, to: done, behavior_id: behavior.example}]
|
|
12
|
+
consistency_policy: {transaction_boundary: single, concurrency: optimistic, idempotency: guarded, cross_aggregate_strategy: none}
|
|
13
|
+
domain_event_catalog: []
|
|
14
|
+
gateway_catalog: [{gateway_id: gateway.example, name: Gateway, context_ref: context.example, layer: Domain, capabilities: [load]}]
|
|
15
|
+
persistence_mapping: [{aggregate_id: aggregate.example, storage_model: example, notes: mapping}]
|
|
16
|
+
test_seams: [{seam_id: test-seam.example, kind: domain, subject_ref: aggregate.example, assertion: behavior}]
|
|
17
|
+
adr_candidates: []
|
|
18
|
+
upstream_impact: {spec_ref: spec@v1, strategic_ref: strategy@v1, api_ref: api@draft, data_ref: data@v1, upstream_current: true}
|
|
19
|
+
version: v1
|
|
20
|
+
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
|
|
21
|
+
evidence_refs: []
|