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,169 @@
|
|
|
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
|
+
import { loadApprovalRecord, resolveApprovalRef, validateApprovalRecordFile } from "../../../../scripts/lib/approval-record.mjs";
|
|
6
|
+
|
|
7
|
+
const required = ["schema_version", "domain_strategy_id", "domain_version", "status", "contexts", "subdomains", "relationships", "scenarios", "concept_candidates", "invariants", "terminology_refs", "downstream_mapping", "evidence_refs", "approval"];
|
|
8
|
+
const idPatterns = {
|
|
9
|
+
context_id: /^[A-Z][A-Za-z0-9]+$/,
|
|
10
|
+
domain_strategy_id: /^domain-strategy\.[a-z0-9][a-z0-9-]*$/,
|
|
11
|
+
subdomain_id: /^subdomain\.[a-z0-9][a-z0-9-]*$/,
|
|
12
|
+
relationship_id: /^relationship\.[a-z0-9][a-z0-9-]*$/,
|
|
13
|
+
scenario_id: /^scenario\.[a-z0-9][a-z0-9-]*$/,
|
|
14
|
+
concept_id: /^domain-concept\.[a-z0-9][a-z0-9-]*$/,
|
|
15
|
+
invariant_id: /^invariant\.[a-z0-9][a-z0-9-]*$/
|
|
16
|
+
};
|
|
17
|
+
const relationshipPatterns = new Set(["Partnership", "Customer/Supplier", "Conformist", "Anti-Corruption Layer", "Open Host Service", "Published Language", "Shared Kernel", "Separate Ways"]);
|
|
18
|
+
|
|
19
|
+
function fail(errors) {
|
|
20
|
+
process.stderr.write(`${JSON.stringify({ result: "blocked", errors }, null, 2)}\n`);
|
|
21
|
+
process.exitCode = 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function nonEmpty(value) { return typeof value === "string" && value.trim().length > 0; }
|
|
25
|
+
function list(value) { return Array.isArray(value); }
|
|
26
|
+
function unique(items, label, errors) {
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
for (const item of items) {
|
|
29
|
+
if (seen.has(item)) errors.push(`${label} 重复: ${item}`);
|
|
30
|
+
seen.add(item);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function requireField(object, field, path, errors) {
|
|
34
|
+
if (!(field in object) || object[field] === null || object[field] === undefined) errors.push(`${path}.${field} 缺失`);
|
|
35
|
+
}
|
|
36
|
+
function requireString(object, field, path, errors) {
|
|
37
|
+
requireField(object, field, path, errors);
|
|
38
|
+
if (field in object && !nonEmpty(object[field])) errors.push(`${path}.${field} 必须是非空字符串`);
|
|
39
|
+
}
|
|
40
|
+
function requireArray(object, field, path, errors, min = 0, itemKind = "string") {
|
|
41
|
+
requireField(object, field, path, errors);
|
|
42
|
+
if (field in object && (!list(object[field]) || object[field].length < min)) errors.push(`${path}.${field} 必须是至少 ${min} 项的数组`);
|
|
43
|
+
if (field in object && list(object[field]) && itemKind === "string") object[field].forEach((item, index) => { if (!nonEmpty(item)) errors.push(`${path}.${field}[${index}] 必须是非空字符串`); });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validate(data) {
|
|
47
|
+
const errors = [];
|
|
48
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return ["合同必须是对象"];
|
|
49
|
+
for (const field of required) requireField(data, field, "root", errors);
|
|
50
|
+
if (data.schema_version !== 1) errors.push("schema_version 必须为 1");
|
|
51
|
+
if (!idPatterns.domain_strategy_id.test(String(data.domain_strategy_id ?? ""))) errors.push("domain_strategy_id 格式非法");
|
|
52
|
+
if (!/^v[0-9]+$/.test(String(data.domain_version ?? ""))) errors.push("domain_version 必须形如 v1");
|
|
53
|
+
if (!["draft", "ready-for-human", "approved", "stale", "blocked"].includes(data.status)) errors.push("status 非法");
|
|
54
|
+
|
|
55
|
+
requireArray(data, "contexts", "root", errors, 1, "object");
|
|
56
|
+
const contexts = list(data.contexts) ? data.contexts : [];
|
|
57
|
+
const contextIds = contexts.map((item) => item?.context_id).filter(Boolean);
|
|
58
|
+
unique(contextIds, "context_id", errors);
|
|
59
|
+
for (const [index, context] of contexts.entries()) {
|
|
60
|
+
const path = `contexts[${index}]`;
|
|
61
|
+
for (const field of ["context_id", "name", "owner", "status", "subdomain_type"]) requireString(context ?? {}, field, path, errors);
|
|
62
|
+
for (const field of ["responsibilities", "non_responsibilities"]) requireArray(context ?? {}, field, path, errors, field === "responsibilities" ? 1 : 0);
|
|
63
|
+
if (context?.context_id && !idPatterns.context_id.test(context.context_id)) errors.push(`${path}.context_id 格式非法`);
|
|
64
|
+
if (context?.status && !["candidate", "confirmed", "stale"].includes(context.status)) errors.push(`${path}.status 非法`);
|
|
65
|
+
if (context?.subdomain_type && !["Core Domain", "Supporting Subdomain", "Generic Subdomain"].includes(context.subdomain_type)) errors.push(`${path}.subdomain_type 非法`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
requireArray(data, "subdomains", "root", errors, 1, "object");
|
|
69
|
+
const subdomains = list(data.subdomains) ? data.subdomains : [];
|
|
70
|
+
unique(subdomains.map((item) => item?.subdomain_id).filter(Boolean), "subdomain_id", errors);
|
|
71
|
+
for (const [index, item] of subdomains.entries()) {
|
|
72
|
+
const path = `subdomains[${index}]`;
|
|
73
|
+
for (const field of ["subdomain_id", "name", "type", "rationale"]) requireString(item ?? {}, field, path, errors);
|
|
74
|
+
requireArray(item ?? {}, "evidence_refs", path, errors, 1);
|
|
75
|
+
if (item?.subdomain_id && !idPatterns.subdomain_id.test(item.subdomain_id)) errors.push(`${path}.subdomain_id 格式非法`);
|
|
76
|
+
if (item?.type && !["Core Domain", "Supporting Subdomain", "Generic Subdomain"].includes(item.type)) errors.push(`${path}.type 非法`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const relationships = list(data.relationships) ? data.relationships : [];
|
|
80
|
+
unique(relationships.map((item) => item?.relationship_id).filter(Boolean), "relationship_id", errors);
|
|
81
|
+
for (const [index, relationship] of relationships.entries()) {
|
|
82
|
+
const path = `relationships[${index}]`;
|
|
83
|
+
for (const field of ["relationship_id", "from_context", "to_context", "relationship_pattern", "semantic_upstream", "semantic_downstream", "business_authority", "model_change_impact", "transport_direction", "translation_responsibility", "direction_explanation"]) requireString(relationship ?? {}, field, path, errors);
|
|
84
|
+
if (relationship?.relationship_id && !idPatterns.relationship_id.test(relationship.relationship_id)) errors.push(`${path}.relationship_id 格式非法`);
|
|
85
|
+
for (const field of ["from_context", "to_context", "semantic_upstream", "semantic_downstream"]) {
|
|
86
|
+
if (relationship?.[field] && !contextIds.includes(relationship[field])) errors.push(`${path}.${field} 未引用已声明上下文`);
|
|
87
|
+
}
|
|
88
|
+
if (relationship?.from_context === relationship?.to_context) errors.push(`${path} 不允许上下文自环`);
|
|
89
|
+
if (relationship?.semantic_upstream && ![relationship.from_context, relationship.to_context].includes(relationship.semantic_upstream)) errors.push(`${path}.semantic_upstream 必须是关系端点`);
|
|
90
|
+
if (relationship?.semantic_downstream && ![relationship.from_context, relationship.to_context].includes(relationship.semantic_downstream)) errors.push(`${path}.semantic_downstream 必须是关系端点`);
|
|
91
|
+
if (relationship?.relationship_pattern && !relationshipPatterns.has(relationship.relationship_pattern)) errors.push(`${path}.relationship_pattern 非法`);
|
|
92
|
+
if (relationship?.relationship_pattern === "Shared Kernel" && !nonEmpty(relationship.shared_kernel_approval_ref)) errors.push(`${path} Shared Kernel 必须有 shared_kernel_approval_ref`);
|
|
93
|
+
if (relationship?.semantic_upstream && relationship?.semantic_downstream && relationship.semantic_upstream === relationship.semantic_downstream) errors.push(`${path} semantic_upstream 与 semantic_downstream 不能相同`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
requireArray(data, "scenarios", "root", errors, 1, "object");
|
|
97
|
+
const scenarios = list(data.scenarios) ? data.scenarios : [];
|
|
98
|
+
const scenarioIds = scenarios.map((item) => item?.scenario_id).filter(Boolean);
|
|
99
|
+
unique(scenarioIds, "scenario_id", errors);
|
|
100
|
+
for (const [index, scenario] of scenarios.entries()) {
|
|
101
|
+
const path = `scenarios[${index}]`;
|
|
102
|
+
for (const field of ["scenario_id", "actor", "responsible_context", "status"]) requireString(scenario ?? {}, field, path, errors);
|
|
103
|
+
for (const field of ["preconditions", "commands", "rules", "events", "failure_results", "consumers"]) requireArray(scenario ?? {}, field, path, errors, field === "commands" || field === "rules" || field === "failure_results" ? 1 : 0);
|
|
104
|
+
if (scenario?.scenario_id && !idPatterns.scenario_id.test(scenario.scenario_id)) errors.push(`${path}.scenario_id 格式非法`);
|
|
105
|
+
if (scenario?.responsible_context && !contextIds.includes(scenario.responsible_context)) errors.push(`${path}.responsible_context 未声明`);
|
|
106
|
+
for (const consumer of scenario?.consumers ?? []) if (!contextIds.includes(consumer)) errors.push(`${path}.consumers 引用了未声明上下文: ${consumer}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const concepts = list(data.concept_candidates) ? data.concept_candidates : [];
|
|
110
|
+
unique(concepts.map((item) => item?.concept_id).filter(Boolean), "concept_id", errors);
|
|
111
|
+
for (const [index, concept] of concepts.entries()) {
|
|
112
|
+
const path = `concept_candidates[${index}]`;
|
|
113
|
+
for (const field of ["concept_id", "name", "context_id", "confidence", "status"]) requireString(concept ?? {}, field, path, errors);
|
|
114
|
+
for (const field of ["identity_features", "lifecycle"]) requireArray(concept ?? {}, field, path, errors, 1);
|
|
115
|
+
if (concept?.concept_id && !idPatterns.concept_id.test(concept.concept_id)) errors.push(`${path}.concept_id 格式非法`);
|
|
116
|
+
if (concept?.context_id && !contextIds.includes(concept.context_id)) errors.push(`${path}.context_id 未声明`);
|
|
117
|
+
if (concept?.confidence && !["low", "medium", "high"].includes(concept.confidence)) errors.push(`${path}.confidence 非法`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const invariants = list(data.invariants) ? data.invariants : [];
|
|
121
|
+
unique(invariants.map((item) => item?.invariant_id).filter(Boolean), "invariant_id", errors);
|
|
122
|
+
for (const [index, invariant] of invariants.entries()) {
|
|
123
|
+
const path = `invariants[${index}]`;
|
|
124
|
+
for (const field of ["invariant_id", "statement", "responsible_context", "verification_method"]) requireString(invariant ?? {}, field, path, errors);
|
|
125
|
+
requireArray(invariant ?? {}, "scenario_refs", path, errors, 1);
|
|
126
|
+
if (invariant?.invariant_id && !idPatterns.invariant_id.test(invariant.invariant_id)) errors.push(`${path}.invariant_id 格式非法`);
|
|
127
|
+
if (invariant?.responsible_context && !contextIds.includes(invariant.responsible_context)) errors.push(`${path}.responsible_context 未声明`);
|
|
128
|
+
for (const reference of invariant?.scenario_refs ?? []) if (!scenarioIds.includes(reference)) errors.push(`${path}.scenario_refs 引用了未声明场景: ${reference}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
requireArray(data, "terminology_refs", "root", errors, 0);
|
|
132
|
+
requireArray(data, "evidence_refs", "root", errors, 1);
|
|
133
|
+
const mappings = list(data.downstream_mapping) ? data.downstream_mapping : [];
|
|
134
|
+
for (const [index, mapping] of mappings.entries()) {
|
|
135
|
+
const path = `downstream_mapping[${index}]`;
|
|
136
|
+
for (const field of ["domain_change", "propagation", "reapproval_condition"]) requireString(mapping ?? {}, field, path, errors);
|
|
137
|
+
requireArray(mapping ?? {}, "impacts", path, errors, 1);
|
|
138
|
+
if (mapping?.propagation && !["direct", "transitive", "stale"].includes(mapping.propagation)) errors.push(`${path}.propagation 非法`);
|
|
139
|
+
}
|
|
140
|
+
const approval = data.approval ?? {};
|
|
141
|
+
for (const field of ["approval_ref", "approver", "persisted_ref", "current_version"]) requireString(approval, field, "approval", errors);
|
|
142
|
+
if (data.status === "approved") {
|
|
143
|
+
if (contexts.some((context) => context.status !== "confirmed")) errors.push("approved 合同要求所有上下文 status=confirmed");
|
|
144
|
+
if (approval.current_version !== data.domain_version) errors.push("approval.current_version 必须等于 domain_version");
|
|
145
|
+
try {
|
|
146
|
+
const approvalPath = resolveApprovalRef(approval.approval_ref);
|
|
147
|
+
validateApprovalRecordFile(approvalPath, { requireApproved: true });
|
|
148
|
+
const record = loadApprovalRecord(approvalPath);
|
|
149
|
+
if (record.gate_id !== "gate.domain-strategy-approved") errors.push("approval.approval_ref 的 gate_id 必须为 gate.domain-strategy-approved");
|
|
150
|
+
if (record.role_id !== approval.approver) errors.push("approval.approver 必须与会签记录 role_id 一致");
|
|
151
|
+
} catch (error) { errors.push(`approval.approval_ref 会签记录无效: ${error.message}`); }
|
|
152
|
+
}
|
|
153
|
+
return errors;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const file = process.argv[2];
|
|
157
|
+
if (!file) fail(["用法: validate-domain-strategy.mjs <contract.yaml>"]);
|
|
158
|
+
else {
|
|
159
|
+
try {
|
|
160
|
+
const source = await readFile(file, "utf8");
|
|
161
|
+
const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
|
|
162
|
+
if (document.errors.length) fail([document.errors[0].message]);
|
|
163
|
+
else {
|
|
164
|
+
const errors = validate(document.toJS({ maxAliasCount: 0 }));
|
|
165
|
+
if (errors.length) fail(errors);
|
|
166
|
+
else process.stdout.write(JSON.stringify({ result: "completed", contract: file }, null, 2) + "\n");
|
|
167
|
+
}
|
|
168
|
+
} catch (error) { fail([error.message]); }
|
|
169
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import { parseDocument } from "../../../../scripts/vendor/yaml.mjs";
|
|
7
|
+
import { loadApprovalRecord, resolveApprovalRef, validateApprovalRecordFile } from "../../../../scripts/lib/approval-record.mjs";
|
|
8
|
+
|
|
9
|
+
const required = ["schema_version", "stage_decision_id", "package_version", "status", "problem_statement", "target_users", "mvp", "non_goals", "success_criteria", "test_seams", "confirmed_decisions", "assumptions", "constraints", "unresolved_items", "terminology_refs", "domain_strategy_ref", "impact_assessment", "downstream_mapping", "evidence_refs", "approval"];
|
|
10
|
+
const idPattern = /^stage-decision\.[a-z0-9][a-z0-9-]*$/;
|
|
11
|
+
|
|
12
|
+
function fail(errors) {
|
|
13
|
+
process.stderr.write(`${JSON.stringify({ result: "blocked", errors }, null, 2)}\n`);
|
|
14
|
+
process.exitCode = 1;
|
|
15
|
+
}
|
|
16
|
+
function nonEmpty(value) { return typeof value === "string" && value.trim().length > 0; }
|
|
17
|
+
function requireField(object, field, path, errors) { if (!(field in object) || object[field] === null || object[field] === undefined) errors.push(`${path}.${field} 缺失`); }
|
|
18
|
+
function requireString(object, field, path, errors) { requireField(object, field, path, errors); if (field in object && !nonEmpty(object[field])) errors.push(`${path}.${field} 必须是非空字符串`); }
|
|
19
|
+
function requireArray(object, field, path, errors, min = 0) { requireField(object, field, path, errors); if (field in object && (!Array.isArray(object[field]) || object[field].length < min)) errors.push(`${path}.${field} 必须是至少 ${min} 项的数组`); if (field in object && Array.isArray(object[field])) object[field].forEach((item, index) => { if (!nonEmpty(item)) errors.push(`${path}.${field}[${index}] 必须是非空字符串`); }); }
|
|
20
|
+
function canonical(value) { if (Array.isArray(value)) return value.map(canonical); if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonical(value[key])])); return value; }
|
|
21
|
+
function digest(value) { return `sha256:${createHash("sha256").update(JSON.stringify(canonical(value))).digest("hex")}`; }
|
|
22
|
+
|
|
23
|
+
async function validate(data) {
|
|
24
|
+
const errors = [];
|
|
25
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return ["合同必须是对象"];
|
|
26
|
+
for (const field of required) requireField(data, field, "root", errors);
|
|
27
|
+
if (data.schema_version !== 1) errors.push("schema_version 必须为 1");
|
|
28
|
+
if (!idPattern.test(String(data.stage_decision_id ?? ""))) errors.push("stage_decision_id 格式非法");
|
|
29
|
+
if (!/^v[0-9]+$/.test(String(data.package_version ?? ""))) errors.push("package_version 必须形如 v1");
|
|
30
|
+
if (!["draft", "ready-for-human", "approved", "stale", "blocked"].includes(data.status)) errors.push("status 非法");
|
|
31
|
+
for (const field of ["problem_statement"]) requireString(data, field, "root", errors);
|
|
32
|
+
for (const field of ["target_users", "mvp", "non_goals", "success_criteria", "test_seams", "confirmed_decisions", "assumptions", "constraints", "terminology_refs", "evidence_refs"]) requireArray(data, field, "root", errors, ["target_users", "mvp", "success_criteria", "test_seams", "confirmed_decisions", "evidence_refs"].includes(field) ? 1 : 0);
|
|
33
|
+
|
|
34
|
+
const unresolved = Array.isArray(data.unresolved_items) ? data.unresolved_items : [];
|
|
35
|
+
for (const [index, item] of unresolved.entries()) {
|
|
36
|
+
const path = `unresolved_items[${index}]`;
|
|
37
|
+
for (const field of ["item", "type", "owner", "next_action", "target_version"]) requireString(item ?? {}, field, path, errors);
|
|
38
|
+
if (item?.type && !["blocker", "deferred"].includes(item.type)) errors.push(`${path}.type 非法`);
|
|
39
|
+
}
|
|
40
|
+
const domainRef = data.domain_strategy_ref ?? {};
|
|
41
|
+
for (const field of ["domain_strategy_id", "domain_version", "digest", "status", "persisted_ref"]) requireString(domainRef, field, "domain_strategy_ref", errors);
|
|
42
|
+
if (domainRef.status && !["approved", "stale", "blocked"].includes(domainRef.status)) errors.push("domain_strategy_ref.status 非法");
|
|
43
|
+
if (data.status === "approved" && domainRef.status !== "approved") errors.push("approved 阶段包必须引用 approved 的 domain strategy");
|
|
44
|
+
if (nonEmpty(domainRef.persisted_ref)) {
|
|
45
|
+
try {
|
|
46
|
+
const strategySource = await readFile(resolve(process.cwd(), domainRef.persisted_ref), "utf8");
|
|
47
|
+
const strategyDocument = parseDocument(strategySource, { maxAliasCount: 0, uniqueKeys: true });
|
|
48
|
+
if (strategyDocument.errors.length) errors.push(`domain_strategy_ref.persisted_ref YAML 非法: ${strategyDocument.errors[0].message}`);
|
|
49
|
+
else {
|
|
50
|
+
const strategy = strategyDocument.toJS({ maxAliasCount: 0 });
|
|
51
|
+
if (strategy.domain_strategy_id !== domainRef.domain_strategy_id) errors.push("domain_strategy_ref.domain_strategy_id 与实际文件不一致");
|
|
52
|
+
if (strategy.domain_version !== domainRef.domain_version) errors.push("domain_strategy_ref.domain_version 与实际文件不一致");
|
|
53
|
+
if (strategy.status !== domainRef.status) errors.push("domain_strategy_ref.status 与实际文件不一致");
|
|
54
|
+
if (domainRef.digest !== digest(strategy)) errors.push("domain_strategy_ref.digest 与实际领域战略内容不一致");
|
|
55
|
+
}
|
|
56
|
+
} catch (error) { errors.push(`domain_strategy_ref.persisted_ref 无法读取: ${error.message}`); }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const impact = data.impact_assessment ?? {};
|
|
60
|
+
for (const field of ["ui", "api", "data", "backend", "frontend", "cross_repo", "high_risk"]) {
|
|
61
|
+
requireField(impact, field, "impact_assessment", errors);
|
|
62
|
+
if (field in impact && typeof impact[field] !== "boolean") errors.push(`impact_assessment.${field} 必须是 boolean`);
|
|
63
|
+
}
|
|
64
|
+
const mappings = Array.isArray(data.downstream_mapping) ? data.downstream_mapping : [];
|
|
65
|
+
if (mappings.length < 1) errors.push("downstream_mapping 至少需要一项");
|
|
66
|
+
for (const [index, mapping] of mappings.entries()) {
|
|
67
|
+
const path = `downstream_mapping[${index}]`;
|
|
68
|
+
for (const field of ["domain_change", "consumer", "propagation", "reapproval_condition"]) requireString(mapping ?? {}, field, path, errors);
|
|
69
|
+
if (mapping?.propagation && !["direct", "transitive", "not-applicable", "stale"].includes(mapping.propagation)) errors.push(`${path}.propagation 非法`);
|
|
70
|
+
}
|
|
71
|
+
const approval = data.approval ?? {};
|
|
72
|
+
for (const field of ["approval_ref", "approver", "persisted_ref", "current_version"]) requireString(approval, field, "approval", errors);
|
|
73
|
+
if (data.status === "approved" && approval.current_version !== data.package_version) errors.push("approval.current_version 必须等于 package_version");
|
|
74
|
+
if (unresolved.some((item) => item?.type === "blocker") && data.status === "approved") errors.push("存在 blocker 未决项时不得 approved");
|
|
75
|
+
if (data.status === "approved" && nonEmpty(approval.approval_ref)) {
|
|
76
|
+
try {
|
|
77
|
+
const approvalPath = resolveApprovalRef(approval.approval_ref);
|
|
78
|
+
validateApprovalRecordFile(approvalPath, { requireApproved: true });
|
|
79
|
+
const record = loadApprovalRecord(approvalPath);
|
|
80
|
+
if (record.gate_id !== "gate.stage-decision-package-approved") errors.push("approval_ref 的 gate_id 必须为 gate.stage-decision-package-approved");
|
|
81
|
+
if (record.role_id !== approval.approver) errors.push("approval.approver 必须与会签记录 role_id 一致");
|
|
82
|
+
} catch (error) { errors.push(`approval_ref 会签记录无效: ${error.message}`); }
|
|
83
|
+
}
|
|
84
|
+
return errors;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const file = process.argv[2];
|
|
88
|
+
if (!file) fail(["用法: validate-stage-decision-package.mjs <package.yaml>"]);
|
|
89
|
+
else {
|
|
90
|
+
try {
|
|
91
|
+
const source = await readFile(file, "utf8");
|
|
92
|
+
const document = parseDocument(source, { maxAliasCount: 0, uniqueKeys: true });
|
|
93
|
+
if (document.errors.length) fail([document.errors[0].message]);
|
|
94
|
+
else {
|
|
95
|
+
const errors = await validate(document.toJS({ maxAliasCount: 0 }));
|
|
96
|
+
if (errors.length) fail(errors);
|
|
97
|
+
else process.stdout.write(JSON.stringify({ result: "completed", contract: file }, null, 2) + "\n");
|
|
98
|
+
}
|
|
99
|
+
} catch (error) { fail([error.message]); }
|
|
100
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
gate_id: gate.domain-strategy-approved
|
|
3
|
+
decision: approved
|
|
4
|
+
actor_kind: digital-human
|
|
5
|
+
role_id: role.product-manager
|
|
6
|
+
runtime_id: runtime.generic
|
|
7
|
+
runtime_instance_ref: "runtime.generic:role.product-manager"
|
|
8
|
+
principal_ref: "instance:role.product-manager"
|
|
9
|
+
drafter_role_id: role.requirements-manager
|
|
10
|
+
countersigner_role_ids:
|
|
11
|
+
- role.product-manager
|
|
12
|
+
evidence_refs:
|
|
13
|
+
- evidence.domain-strategy-review.supplier
|
|
14
|
+
biological_veto: false
|
|
15
|
+
notes: DDD 战略设计由需求经理起草,产品经理独立会签。
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
domain_strategy_id: domain-strategy.invalid-direction
|
|
3
|
+
domain_version: v1
|
|
4
|
+
status: ready-for-human
|
|
5
|
+
contexts:
|
|
6
|
+
- context_id: A
|
|
7
|
+
name: A
|
|
8
|
+
responsibilities: [rule]
|
|
9
|
+
non_responsibilities: []
|
|
10
|
+
subdomain_type: Supporting Subdomain
|
|
11
|
+
owner: owner
|
|
12
|
+
status: confirmed
|
|
13
|
+
- context_id: B
|
|
14
|
+
name: B
|
|
15
|
+
responsibilities: [consume]
|
|
16
|
+
non_responsibilities: []
|
|
17
|
+
subdomain_type: Supporting Subdomain
|
|
18
|
+
owner: owner
|
|
19
|
+
status: confirmed
|
|
20
|
+
subdomains:
|
|
21
|
+
- subdomain_id: subdomain.a
|
|
22
|
+
name: A
|
|
23
|
+
type: Supporting Subdomain
|
|
24
|
+
rationale: test
|
|
25
|
+
evidence_refs: [e]
|
|
26
|
+
relationships:
|
|
27
|
+
- relationship_id: relationship.a-b
|
|
28
|
+
from_context: A
|
|
29
|
+
to_context: B
|
|
30
|
+
relationship_pattern: Published Language
|
|
31
|
+
semantic_upstream: A
|
|
32
|
+
semantic_downstream: B
|
|
33
|
+
business_authority: A
|
|
34
|
+
model_change_impact: B adapts
|
|
35
|
+
transport_direction: B calls A
|
|
36
|
+
translation_responsibility: B
|
|
37
|
+
direction_explanation: ""
|
|
38
|
+
scenarios:
|
|
39
|
+
- scenario_id: scenario.test
|
|
40
|
+
actor: actor
|
|
41
|
+
preconditions: []
|
|
42
|
+
commands: [command]
|
|
43
|
+
rules: [rule]
|
|
44
|
+
events: []
|
|
45
|
+
failure_results: [failure]
|
|
46
|
+
responsible_context: A
|
|
47
|
+
consumers: [B]
|
|
48
|
+
status: confirmed
|
|
49
|
+
concept_candidates: []
|
|
50
|
+
invariants: []
|
|
51
|
+
terminology_refs: [t]
|
|
52
|
+
downstream_mapping: []
|
|
53
|
+
evidence_refs: [e]
|
|
54
|
+
approval:
|
|
55
|
+
approval_ref: a
|
|
56
|
+
approver: a
|
|
57
|
+
persisted_ref: p
|
|
58
|
+
current_version: v1
|
package/template/.trae/skills/yss-stage-decision/tests/fixtures/invalid-stage-decision-blocker.yaml
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
stage_decision_id: stage-decision.invalid-blocker
|
|
3
|
+
package_version: v1
|
|
4
|
+
status: approved
|
|
5
|
+
problem_statement: 示例
|
|
6
|
+
target_users: [用户]
|
|
7
|
+
mvp: [功能]
|
|
8
|
+
non_goals: []
|
|
9
|
+
success_criteria: [标准]
|
|
10
|
+
test_seams: [seam]
|
|
11
|
+
confirmed_decisions: [决定]
|
|
12
|
+
assumptions: []
|
|
13
|
+
constraints: []
|
|
14
|
+
unresolved_items:
|
|
15
|
+
- item: 规则所有权未确认
|
|
16
|
+
type: blocker
|
|
17
|
+
owner: role.product-manager
|
|
18
|
+
next_action: 召开领域评审
|
|
19
|
+
target_version: 2026-Q4
|
|
20
|
+
terminology_refs: [CONTEXT.md#Example]
|
|
21
|
+
domain_strategy_ref:
|
|
22
|
+
domain_strategy_id: domain-strategy.invalid
|
|
23
|
+
domain_version: v1
|
|
24
|
+
digest: sha256:invalid
|
|
25
|
+
status: approved
|
|
26
|
+
impact_assessment:
|
|
27
|
+
ui: false
|
|
28
|
+
api: false
|
|
29
|
+
data: false
|
|
30
|
+
backend: true
|
|
31
|
+
frontend: false
|
|
32
|
+
cross_repo: false
|
|
33
|
+
high_risk: false
|
|
34
|
+
downstream_mapping:
|
|
35
|
+
- domain_change: example
|
|
36
|
+
consumer: spec-synthesis
|
|
37
|
+
propagation: direct
|
|
38
|
+
reapproval_condition: 规则确认
|
|
39
|
+
evidence_refs: [evidence.invalid]
|
|
40
|
+
approval:
|
|
41
|
+
approval_ref: docs/.scratch/invalid/gate.yaml
|
|
42
|
+
approver: role.lifecycle-orchestrator
|
|
43
|
+
persisted_ref: docs/.scratch/invalid/package.yaml
|
|
44
|
+
current_version: v1
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
gate_id: gate.stage-decision-package-approved
|
|
3
|
+
decision: approved
|
|
4
|
+
actor_kind: digital-human
|
|
5
|
+
role_id: role.product-manager
|
|
6
|
+
runtime_id: runtime.generic
|
|
7
|
+
runtime_instance_ref: "runtime.generic:role.product-manager"
|
|
8
|
+
principal_ref: "instance:role.product-manager"
|
|
9
|
+
drafter_role_id: role.requirements-manager
|
|
10
|
+
countersigner_role_ids:
|
|
11
|
+
- role.product-manager
|
|
12
|
+
evidence_refs:
|
|
13
|
+
- evidence.stage-decision-package.supplier
|
|
14
|
+
biological_veto: false
|
|
15
|
+
notes: 阶段决策包由需求经理起草,产品经理独立会签。
|
package/template/.trae/skills/yss-stage-decision/tests/fixtures/valid-stage-decision-package.yaml
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
schema_version: 1
|
|
2
|
+
stage_decision_id: stage-decision.supplier-admission
|
|
3
|
+
package_version: v1
|
|
4
|
+
status: approved
|
|
5
|
+
problem_statement: 合规准入决定分散,采购无法稳定判断当前有效资格。
|
|
6
|
+
target_users: [采购专员、合规专员]
|
|
7
|
+
mvp: [提交供应商申请、合规准入决定、采购侧有效性校验]
|
|
8
|
+
non_goals: [供应商结算、采购付款、通用工作流平台]
|
|
9
|
+
success_criteria: [新采购订单 100% 校验当前有效准入决定]
|
|
10
|
+
test_seams: [supplier-application-submit, admission-validity-check]
|
|
11
|
+
confirmed_decisions: [ComplianceReview 拥有准入规则语义,ProcurementExecution 只消费决定]
|
|
12
|
+
assumptions: [供应商已有唯一 subject_ref]
|
|
13
|
+
constraints: [保留现有采购订单流程]
|
|
14
|
+
unresolved_items:
|
|
15
|
+
- item: 供应商历史资料迁移范围
|
|
16
|
+
type: deferred
|
|
17
|
+
owner: role.product-manager
|
|
18
|
+
next_action: 在 Spec synthesis 前完成数据盘点
|
|
19
|
+
target_version: 2026-Q4
|
|
20
|
+
terminology_refs: [CONTEXT.md#SupplierAdmission]
|
|
21
|
+
domain_strategy_ref:
|
|
22
|
+
domain_strategy_id: domain-strategy.supplier-admission
|
|
23
|
+
domain_version: v1
|
|
24
|
+
digest: sha256:a1a4df23fdb59ab8b4433cedba8271c8a7f11bc8a38abe675d3c7b645d51d7a1
|
|
25
|
+
status: approved
|
|
26
|
+
persisted_ref: .agents/skills/yss-stage-decision/tests/fixtures/valid-supplier-domain.yaml
|
|
27
|
+
impact_assessment:
|
|
28
|
+
ui: true
|
|
29
|
+
api: true
|
|
30
|
+
data: true
|
|
31
|
+
backend: true
|
|
32
|
+
frontend: true
|
|
33
|
+
cross_repo: false
|
|
34
|
+
high_risk: false
|
|
35
|
+
downstream_mapping:
|
|
36
|
+
- domain_change: admission-decision-validity
|
|
37
|
+
consumer: spec-synthesis
|
|
38
|
+
propagation: direct
|
|
39
|
+
reapproval_condition: 领域策略版本或有效性规则变化
|
|
40
|
+
- domain_change: admission-decision-validity
|
|
41
|
+
consumer: ticket-decomposition
|
|
42
|
+
propagation: transitive
|
|
43
|
+
reapproval_condition: Spec 基线变更
|
|
44
|
+
evidence_refs: [evidence.discovery.supplier, evidence.domain-strategy-review.supplier]
|
|
45
|
+
approval:
|
|
46
|
+
approval_ref: .agents/skills/yss-stage-decision/tests/fixtures/stage-decision-approval.yaml
|
|
47
|
+
approver: role.product-manager
|
|
48
|
+
persisted_ref: docs/.scratch/supplier/stage-decision/stage-decision-package-v1.yaml
|
|
49
|
+
current_version: v1
|
|
@@ -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");
|