create-yss-spec 2.1.3 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/template/.agents/skills/code-review/SKILL.md +38 -10
- package/template/.agents/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.agents/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.agents/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.agents/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.agents/skills/yss-design-system/SKILL.md +1 -1
- package/template/.agents/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.agents/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.agents/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.agents/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.agents/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.agents/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.agents/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.agents/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.agents/skills/yss-router/SKILL.md +2 -2
- package/template/.agents/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.agents/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.agents/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.claude/skills/code-review/SKILL.md +38 -10
- package/template/.claude/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.claude/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.claude/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.claude/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.claude/skills/yss-design-system/SKILL.md +1 -1
- package/template/.claude/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.claude/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.claude/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.claude/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.claude/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.claude/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.claude/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.claude/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.claude/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.claude/skills/yss-router/SKILL.md +2 -2
- package/template/.claude/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.claude/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.claude/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.codex/skills/code-review/SKILL.md +38 -10
- package/template/.codex/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.codex/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.codex/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.codex/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.codex/skills/yss-design-system/SKILL.md +1 -1
- package/template/.codex/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.codex/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.codex/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.codex/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.codex/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.codex/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.codex/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.codex/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.codex/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.codex/skills/yss-router/SKILL.md +2 -2
- package/template/.codex/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.codex/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.codex/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.hermes/skills/code-review/SKILL.md +38 -10
- package/template/.hermes/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.hermes/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.hermes/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.hermes/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.hermes/skills/yss-design-system/SKILL.md +1 -1
- package/template/.hermes/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.hermes/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.hermes/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.hermes/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.hermes/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.hermes/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.hermes/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.hermes/skills/yss-router/SKILL.md +2 -2
- package/template/.hermes/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.hermes/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.hermes/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.pi/skills/code-review/SKILL.md +38 -10
- package/template/.pi/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.pi/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.pi/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.pi/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.pi/skills/yss-design-system/SKILL.md +1 -1
- package/template/.pi/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.pi/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.pi/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.pi/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.pi/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.pi/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.pi/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.pi/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.pi/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.pi/skills/yss-router/SKILL.md +2 -2
- package/template/.pi/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.pi/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.pi/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.qoder/skills/code-review/SKILL.md +38 -10
- package/template/.qoder/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.qoder/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.qoder/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.qoder/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.qoder/skills/yss-design-system/SKILL.md +1 -1
- package/template/.qoder/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.qoder/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.qoder/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.qoder/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.qoder/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.qoder/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.qoder/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.qoder/skills/yss-router/SKILL.md +2 -2
- package/template/.qoder/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.qoder/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.qoder/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/.trae/skills/code-review/SKILL.md +38 -10
- package/template/.trae/skills/yss-api-integration/SKILL.md +25 -7
- package/template/.trae/skills/yss-ddd-scaffold-generator/SKILL.md +3 -17
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/pom/bootstrap-pom.xml.template +0 -30
- package/template/.trae/skills/yss-ddd-scaffold-generator/references/yss-backend-scaffold-parent/SKILL.md +1 -1
- package/template/.trae/skills/yss-ddd-scaffold-generator/scripts/generate_scaffold.py +1 -21
- package/template/.trae/skills/yss-design-system/SKILL.md +1 -1
- package/template/.trae/skills/yss-frontend-scaffold-generator/SKILL.md +12 -6
- package/template/.trae/skills/yss-openapi-draft-review/SKILL.md +13 -17
- package/template/.trae/skills/yss-openapi-governance/SKILL.md +89 -114
- package/template/.trae/skills/yss-openapi-governance/agents/openai.yaml +2 -2
- package/template/.trae/skills/yss-product-lifecycle/SKILL.md +11 -5
- package/template/.trae/skills/yss-product-lifecycle/references/artifact-dependencies.md +2 -2
- package/template/.trae/skills/yss-product-lifecycle/references/matt-yss-adapter.md +8 -2
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration-contract.yaml +75 -28
- package/template/.trae/skills/yss-product-lifecycle/references/orchestration.md +7 -2
- package/template/.trae/skills/yss-product-lifecycle/references/state-model.md +8 -0
- package/template/.trae/skills/yss-router/SKILL.md +2 -2
- package/template/.trae/skills/yss-router/references/router-contract.yaml +4 -6
- package/template/.trae/skills/yss-router/references/slice-implementation-contract.md +1 -1
- package/template/.trae/skills/yss-router/references/yss-skill-execution-result.md +2 -1
- package/template/AGENTS.md +6 -4
- package/template/CONTEXT.md +15 -1
- package/template/README.md +2 -1
- package/template/__yss_dotfile__.gitignore +4 -0
- package/template/docs/adr/0003-machine-readable-lifecycle-registry.md +5 -0
- package/template/docs/adr/0004-split-lifecycle-and-router-registry-domains.md +5 -0
- package/template/docs/adr/0005-cross-repository-ecosystem-release-manifest.md +5 -0
- package/template/docs/adr/0006-stable-lifecycle-ids-and-generated-structure.md +5 -0
- package/template/docs/adr/0007-separate-skill-routing-registry-from-integrity-lock.md +5 -0
- package/template/docs/agents/issue-tracker.md +1 -0
- package/template/docs/api/templates/openapi-draft-review-checklist.md +8 -6
- package/template/docs/api/templates/openapi-freeze-record-template.md +8 -2
- package/template/docs/api/templates/openapi-json-export-record-template.md +60 -0
- package/template/docs/architecture/templates/architecture-review-checklist.md +6 -19
- package/template/docs/architecture/templates/functional-architecture-template.md +4 -4
- package/template/docs/architecture/templates/system-overview-design-template.md +10 -5
- package/template/docs/architecture/templates/tech-design-template.md +4 -11
- package/template/docs/discovery/templates/discovery-template.md +0 -1
- package/template/docs/implementation/create-yss-spec-repository-mode-contract.md +2 -2
- package/template/docs/process/harness-process-tailoring.md +2 -0
- package/template/docs/process/harness-work-unit-map.md +14 -10
- package/template/docs/process/lifecycle-artifact-map.md +75 -39
- package/template/docs/process/lifecycle-registry-baseline.json +61 -0
- package/template/docs/process/lifecycle-registry.yaml +255 -0
- package/template/docs/process/schemas/lifecycle-registry.schema.json +35 -0
- package/template/docs/reviews/lifecycle-registry-phase0-1-red-green-2026-08-17.md +61 -0
- package/template/docs/reviews/matt-yss-p0-ticket-review-git-red-green-2026-08-17.md +91 -0
- package/template/docs/reviews/openapi-skill-primary-source-research-2026-08-16.md +76 -0
- package/template/docs/reviews/openapi-yaml-first-independent-review-2026-08-16.md +121 -0
- package/template/docs/reviews/openapi-yaml-first-pressure-scenarios-2026-08-16.md +191 -0
- package/template/docs/reviews/openapi-yaml-first-red-green-2026-08-16.md +76 -0
- package/template/docs/reviews/openapi-yaml-json-output-independent-review-2026-08-16.md +30 -0
- package/template/docs/reviews/openapi-yaml-json-output-scope-red-green-2026-08-16.md +154 -0
- package/template/docs/reviews/research-create-yss-spec-refresh-2026-08-16.md +164 -0
- package/template/docs/reviews/security-permission-lifecycle-simplification-red-green-2026-08-16.md +43 -0
- package/template/docs/reviews/template-release-review-remediation-red-green-2026-08-17.md +41 -0
- package/template/docs/templates/agent-brief-template.md +2 -2
- package/template/docs/templates/build-architecture-checklist-template.md +3 -4
- package/template/docs/templates/implementation-repo-registry-template.md +0 -2
- package/template/docs/templates/implementation-routing-template.md +6 -6
- package/template/docs/templates/openapi-spec-template.yaml +0 -6
- package/template/docs/templates/review-report-template.md +2 -1
- package/template/docs/templates/spec-delta-template.md +1 -1
- package/template/docs/templates/spec-template.md +0 -1
- package/template/docs/templates/vertical-slice-ticket-template.md +2 -2
- package/template/docs/user-guide//344/272/247/345/223/201/347/224/237/345/221/275/345/221/250/346/234/237/345/267/245/344/275/234/346/265/201.md +6 -6
- package/template/docs/user-guide//344/272/247/345/223/201/347/240/224/345/217/221/345/205/250/347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
- package/template/docs/user-guide//345/244/226/351/203/250/345/221/275/344/273/244/350/241/214/345/267/245/345/205/267/345/256/236/350/267/265/346/214/207/345/215/227.md +1 -1
- package/template/docs/user-guide//347/224/237/345/221/275/345/221/250/346/234/237/346/234/200/344/275/263/345/256/236/350/267/265.md +1 -1
- package/template/scripts/generate-lifecycle-artifacts +26 -0
- package/template/scripts/lifecycle-registry.rb +194 -0
- package/template/scripts/sync-skills +1 -0
- package/template/scripts/test-export-yss-skills.rb +8 -6
- package/template/scripts/test-lifecycle-registry.rb +74 -0
- package/template/scripts/update-skill-lock +1 -0
- package/template/scripts/verify-governance-release +39 -0
- package/template/scripts/verify-lifecycle-registry +67 -0
- package/template/scripts/verify-lifecycle-scenarios +114 -17
- package/template/scripts/verify-matt-yss-integration-scenarios +297 -1
- package/template/scripts/verify-openapi-json-handoff-scenarios +270 -0
- package/template/scripts/verify-openapi-yaml-first-scenarios +120 -0
- package/template/scripts/verify-template +27 -3
- package/template/scripts/verify-yss-router-scenarios +42 -14
- package/template/skills-lock.json +9 -24
- package/template/wiki/raw/skills-lock.json +0 -15
- package/template/wiki/wiki/OpenAPI/345/245/221/347/272/246.md +1 -1
- package/template/wiki/wiki/YSS/345/267/245/347/250/213/346/212/200/350/203/275/344/275/223/347/263/273.md +1 -1
- package/template/yss-public-skills.json +3 -5
- package/template.snapshot.json +4 -4
- package/template/.agents/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.agents/skills/yss-openapi/SKILL.md +0 -116
- package/template/.agents/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.agents/skills/yss-openapi/img.png +0 -0
- package/template/.agents/skills/yss-openapi/img_1.png +0 -0
- package/template/.claude/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.claude/skills/yss-openapi/SKILL.md +0 -116
- package/template/.claude/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.claude/skills/yss-openapi/img.png +0 -0
- package/template/.claude/skills/yss-openapi/img_1.png +0 -0
- package/template/.codex/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.codex/skills/yss-openapi/SKILL.md +0 -116
- package/template/.codex/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.codex/skills/yss-openapi/img.png +0 -0
- package/template/.codex/skills/yss-openapi/img_1.png +0 -0
- package/template/.hermes/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.hermes/skills/yss-openapi/SKILL.md +0 -116
- package/template/.hermes/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.hermes/skills/yss-openapi/img.png +0 -0
- package/template/.hermes/skills/yss-openapi/img_1.png +0 -0
- package/template/.pi/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.pi/skills/yss-openapi/SKILL.md +0 -116
- package/template/.pi/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.pi/skills/yss-openapi/img.png +0 -0
- package/template/.pi/skills/yss-openapi/img_1.png +0 -0
- package/template/.qoder/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.qoder/skills/yss-openapi/SKILL.md +0 -116
- package/template/.qoder/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.qoder/skills/yss-openapi/img.png +0 -0
- package/template/.qoder/skills/yss-openapi/img_1.png +0 -0
- package/template/.trae/skills/yss-ddd-scaffold-generator/assets/templates/config/smart-doc.json.template +0 -17
- package/template/.trae/skills/yss-openapi/SKILL.md +0 -116
- package/template/.trae/skills/yss-openapi/agents/openai.yaml +0 -4
- package/template/.trae/skills/yss-openapi/img.png +0 -0
- package/template/.trae/skills/yss-openapi/img_1.png +0 -0
|
@@ -2,9 +2,44 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "pathname"
|
|
5
|
+
require "set"
|
|
5
6
|
require "yaml"
|
|
6
7
|
|
|
7
8
|
ROOT = Pathname.new(__dir__).join("..").realpath
|
|
9
|
+
REGISTRY = YAML.safe_load(
|
|
10
|
+
ROOT.join("docs/process/lifecycle-registry.yaml").read,
|
|
11
|
+
permitted_classes: [],
|
|
12
|
+
aliases: false
|
|
13
|
+
)
|
|
14
|
+
REGISTRY_IDS = %w[stages gates artifacts work_units evidence].flat_map do |collection|
|
|
15
|
+
REGISTRY.fetch(collection).map { |record| record.fetch("id") }
|
|
16
|
+
end.to_set
|
|
17
|
+
ROUTE_REGISTRY_IDS = {
|
|
18
|
+
"impact-assessment" => "artifact.impact-assessment",
|
|
19
|
+
"ssot-update" => "work-unit.ssot-update",
|
|
20
|
+
"skill-projection-sync" => "work-unit.skill-projection-sync",
|
|
21
|
+
"pressure-scenarios" => "evidence.fresh-verification",
|
|
22
|
+
"fresh-verification" => "work-unit.fresh-verification",
|
|
23
|
+
"independent-review" => "work-unit.independent-review",
|
|
24
|
+
"tracker-sync" => "evidence.checkpoint-and-rollback",
|
|
25
|
+
"spec" => "artifact.spec",
|
|
26
|
+
"product-overview" => "artifact.product-overview",
|
|
27
|
+
"functional-architecture" => "artifact.functional-architecture",
|
|
28
|
+
"low-fidelity-prototype" => "artifact.low-fidelity-prototype",
|
|
29
|
+
"state-matrix" => "artifact.state-matrix",
|
|
30
|
+
"high-fidelity-html-prototype" => "artifact.high-fidelity-html-prototype",
|
|
31
|
+
"user-confirmation" => "gate.user-confirmation",
|
|
32
|
+
"openapi-draft" => "artifact.openapi-draft",
|
|
33
|
+
"draft-review" => "gate.openapi-draft-reviewed",
|
|
34
|
+
"design-review" => "gate.design-reviewed",
|
|
35
|
+
"openapi-freeze" => "gate.openapi-frozen",
|
|
36
|
+
"engineering-baseline" => "artifact.engineering-baseline",
|
|
37
|
+
"architecture-review" => "artifact.architecture-review",
|
|
38
|
+
"data-architecture" => "artifact.data-architecture",
|
|
39
|
+
"spec-delta" => "artifact.spec-delta",
|
|
40
|
+
"parent-ticket" => "artifact.parent-ticket",
|
|
41
|
+
"vertical-slice-tickets" => "artifact.vertical-slice-ticket"
|
|
42
|
+
}.freeze
|
|
8
43
|
|
|
9
44
|
def route(facts)
|
|
10
45
|
if facts.fetch(:repository_mode) == "template-source"
|
|
@@ -19,7 +54,10 @@ def route(facts)
|
|
|
19
54
|
end
|
|
20
55
|
|
|
21
56
|
gates = %w[impact-assessment tracker-sync fresh-verification]
|
|
22
|
-
|
|
57
|
+
small_change = facts.fetch(:scale) == :small && !facts.fetch(:high_risk) &&
|
|
58
|
+
!facts.fetch(:ui_impact) && !facts.fetch(:api_impact) &&
|
|
59
|
+
!facts.fetch(:backend_impact) && !facts.fetch(:data_impact)
|
|
60
|
+
return gates if small_change
|
|
23
61
|
|
|
24
62
|
gates.concat(%w[spec product-overview functional-architecture])
|
|
25
63
|
|
|
@@ -32,7 +70,7 @@ def route(facts)
|
|
|
32
70
|
])
|
|
33
71
|
end
|
|
34
72
|
|
|
35
|
-
gates.concat(%w[openapi-draft design-review openapi-freeze]) if facts.fetch(:api_impact)
|
|
73
|
+
gates.concat(%w[openapi-draft draft-review design-review openapi-freeze]) if facts.fetch(:api_impact)
|
|
36
74
|
|
|
37
75
|
if facts.fetch(:backend_impact) || facts.fetch(:high_risk)
|
|
38
76
|
gates.concat(%w[engineering-baseline architecture-review])
|
|
@@ -65,6 +103,16 @@ scenarios = [
|
|
|
65
103
|
required: %w[spec product-overview functional-architecture openapi-draft engineering-baseline parent-ticket vertical-slice-tickets],
|
|
66
104
|
forbidden: %w[low-fidelity-prototype state-matrix high-fidelity-html-prototype user-confirmation spec-delta]
|
|
67
105
|
},
|
|
106
|
+
{
|
|
107
|
+
name: "普通 API 功能无需专项输入",
|
|
108
|
+
facts: {
|
|
109
|
+
repository_mode: "project-instance", scale: :small, high_risk: false,
|
|
110
|
+
ui_impact: false, api_impact: true, backend_impact: true,
|
|
111
|
+
data_impact: false, existing_frozen_baseline: false
|
|
112
|
+
},
|
|
113
|
+
required: %w[spec product-overview functional-architecture openapi-draft draft-review openapi-freeze engineering-baseline parent-ticket vertical-slice-tickets],
|
|
114
|
+
forbidden: %w[low-fidelity-prototype state-matrix high-fidelity-html-prototype user-confirmation spec-delta]
|
|
115
|
+
},
|
|
68
116
|
{
|
|
69
117
|
name: "有 UI 的新功能",
|
|
70
118
|
facts: {
|
|
@@ -107,12 +155,22 @@ scenarios.each do |scenario|
|
|
|
107
155
|
failures << "#{scenario.fetch(:name)} 错误触发: #{unexpected.join(', ')}" unless unexpected.empty?
|
|
108
156
|
end
|
|
109
157
|
|
|
158
|
+
route_keys = scenarios.flat_map { |scenario| scenario.fetch(:required) + scenario.fetch(:forbidden) }.uniq
|
|
159
|
+
route_keys.each do |route_key|
|
|
160
|
+
registry_id = ROUTE_REGISTRY_IDS[route_key]
|
|
161
|
+
failures << "生命周期场景 route key 未映射稳定 ID: #{route_key}" unless registry_id
|
|
162
|
+
failures << "生命周期场景 route key 映射到不存在的稳定 ID: #{route_key} -> #{registry_id}" if registry_id && !REGISTRY_IDS.include?(registry_id)
|
|
163
|
+
end
|
|
164
|
+
|
|
110
165
|
semantic_markers = {
|
|
111
166
|
"AGENTS.md" => [
|
|
112
|
-
"
|
|
167
|
+
"生命周期注册表中的条件门禁全部按影响面强制",
|
|
113
168
|
"只要进入 Spec 基线",
|
|
114
169
|
"才构成产品设计影响",
|
|
115
170
|
"Spec Delta 只记录相对既有冻结 Spec 基线",
|
|
171
|
+
"安全 / 权限不设独立生命周期资料或专属门禁",
|
|
172
|
+
"普通 action 注册",
|
|
173
|
+
"SQL / DDL / 迁移和上传 / 下载本身不构成安全 / 权限专项",
|
|
116
174
|
"template-source",
|
|
117
175
|
"apps/backend/<project>/",
|
|
118
176
|
"apps/frontend/<project>/",
|
|
@@ -126,7 +184,17 @@ semantic_markers = {
|
|
|
126
184
|
"不生成空文档",
|
|
127
185
|
"最近可信阶段",
|
|
128
186
|
"同一独立执行者",
|
|
129
|
-
"集中 checkpoint"
|
|
187
|
+
"集中 checkpoint",
|
|
188
|
+
"安全 / 权限不单独分诊",
|
|
189
|
+
"不自动升级为安全专项"
|
|
190
|
+
],
|
|
191
|
+
"docs/process/lifecycle-artifact-map.md" => [
|
|
192
|
+
"安全 / 权限不形成独立门禁",
|
|
193
|
+
"按实际 UI、API、Backend、Data、High-risk 影响"
|
|
194
|
+
],
|
|
195
|
+
".agents/skills/yss-product-lifecycle/references/artifact-dependencies.md" => [
|
|
196
|
+
"不使用独立影响类型",
|
|
197
|
+
"不增加安全 / 权限传播"
|
|
130
198
|
],
|
|
131
199
|
"docs/process/implementation-repo-integration.md" => [
|
|
132
200
|
"apps/backend/<project>/",
|
|
@@ -171,7 +239,7 @@ unless failures.empty?
|
|
|
171
239
|
exit 1
|
|
172
240
|
end
|
|
173
241
|
|
|
174
|
-
puts "
|
|
242
|
+
puts "六类生命周期压力场景验证通过"
|
|
175
243
|
|
|
176
244
|
skill_root = ROOT.join(".agents/skills/yss-product-lifecycle")
|
|
177
245
|
skill = skill_root.join("SKILL.md").read
|
|
@@ -235,7 +303,7 @@ reference_markers = {
|
|
|
235
303
|
]
|
|
236
304
|
}.freeze
|
|
237
305
|
|
|
238
|
-
removed_skills = %w[code-review-process yss-domain-modeling]
|
|
306
|
+
removed_skills = %w[code-review-process yss-domain-modeling yss-openapi]
|
|
239
307
|
removed_skills.each do |skill_name|
|
|
240
308
|
failures << "已移除 skill 仍存在: #{skill_name}" if ROOT.join(".agents/skills", skill_name).exist?
|
|
241
309
|
end
|
|
@@ -250,7 +318,8 @@ tracked_policy_files = [
|
|
|
250
318
|
tracked_policy_files.each do |relative_path|
|
|
251
319
|
body = ROOT.join(relative_path).read
|
|
252
320
|
removed_skills.each do |skill_name|
|
|
253
|
-
|
|
321
|
+
pattern = Regexp.new("(?<![a-z0-9-])#{Regexp.escape(skill_name)}(?![a-z0-9-])")
|
|
322
|
+
failures << "#{relative_path} 仍引用已移除 skill: #{skill_name}" if body.match?(pattern)
|
|
254
323
|
end
|
|
255
324
|
end
|
|
256
325
|
|
|
@@ -421,8 +490,9 @@ ready_required.each do |condition|
|
|
|
421
490
|
end
|
|
422
491
|
|
|
423
492
|
propagation = contract.fetch("impact_propagation")
|
|
424
|
-
expected_types = %w[wording ui-state
|
|
493
|
+
expected_types = %w[wording ui-state api-schema state-machine data-model service-boundary nfr deployment]
|
|
425
494
|
failures << "影响类型不完整" unless (expected_types - propagation.keys).empty?
|
|
495
|
+
failures << "安全 / 权限仍作为独立传播类型" unless (propagation.keys & %w[permission security]).empty?
|
|
426
496
|
|
|
427
497
|
allowed_conditions = %w[always existing_frozen_baseline ui_impact api_impact data_impact backend_impact]
|
|
428
498
|
propagation.each do |impact_type, definition|
|
|
@@ -464,14 +534,41 @@ expected_types.each do |impact_type|
|
|
|
464
534
|
failures << "#{impact_type} 可执行传播结果为空" if targets.nil? || targets.empty?
|
|
465
535
|
end
|
|
466
536
|
|
|
467
|
-
|
|
537
|
+
new_module_api = propagated_targets(
|
|
468
538
|
propagation,
|
|
469
|
-
"
|
|
539
|
+
"api-schema",
|
|
470
540
|
all_impacts_context.merge("existing_frozen_baseline" => false)
|
|
471
541
|
)
|
|
472
|
-
failures << "新模块错误激活 spec-delta" if
|
|
473
|
-
unless
|
|
474
|
-
failures << "
|
|
542
|
+
failures << "新模块错误激活 spec-delta" if new_module_api.any? { |target| target["name"] == "spec-delta" }
|
|
543
|
+
unless new_module_api.any? { |target| target["kind"] == "gate" && target["name"] == "openapi-freeze" }
|
|
544
|
+
failures << "普通 API 影响未使 openapi-freeze gate stale"
|
|
545
|
+
end
|
|
546
|
+
|
|
547
|
+
legacy_posture_key = %w[security permission posture].join("_")
|
|
548
|
+
failures << "生命周期合同仍要求已废弃的专项输入" if contract.key?(legacy_posture_key)
|
|
549
|
+
ordinary_route = route(
|
|
550
|
+
repository_mode: "project-instance", scale: :medium, high_risk: false,
|
|
551
|
+
ui_impact: true, api_impact: true, backend_impact: true,
|
|
552
|
+
data_impact: false, existing_frozen_baseline: false
|
|
553
|
+
)
|
|
554
|
+
%w[openapi-draft openapi-freeze engineering-baseline].each do |gate|
|
|
555
|
+
failures << "普通功能错误移除 #{gate} 门禁" unless ordinary_route.include?(gate)
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
data_targets = propagated_targets(propagation, "data-model", all_impacts_context)
|
|
559
|
+
failures << "SQL / DDL 未按普通数据影响传播" unless data_targets.any? { |target| target["name"] == "data-architecture" }
|
|
560
|
+
api_targets = propagated_targets(propagation, "api-schema", all_impacts_context)
|
|
561
|
+
failures << "下载接口未按普通 API 影响传播" unless api_targets.any? { |target| target["name"] == "openapi-draft" }
|
|
562
|
+
|
|
563
|
+
seam_required = contract.fetch("seam_deferred_required")
|
|
564
|
+
def seam_field_filled?(value)
|
|
565
|
+
value.is_a?(Array) ? !value.empty? : !value.to_s.empty?
|
|
566
|
+
end
|
|
567
|
+
valid_seam = seam_required.to_h { |field| [field, "value"] }
|
|
568
|
+
failures << "完整 seam-deferred 证据被错误阻断" unless seam_required.all? { |field| seam_field_filled?(valid_seam[field]) }
|
|
569
|
+
%w[owner follow_up_ticket target_version_or_release_date].each do |field|
|
|
570
|
+
mutation = valid_seam.reject { |key, _| key == field }
|
|
571
|
+
failures << "seam-deferred 缺少 #{field} 时未阻断" if seam_required.all? { |required_field| seam_field_filled?(mutation[required_field]) }
|
|
475
572
|
end
|
|
476
573
|
|
|
477
574
|
no_api_ui = propagated_targets(
|
|
@@ -488,11 +585,11 @@ unless unknown_decision == {"action" => "pause", "reason_code" => "impact-classi
|
|
|
488
585
|
failures << "未知 impact type 未返回结构化暂停"
|
|
489
586
|
end
|
|
490
587
|
|
|
491
|
-
|
|
492
|
-
|
|
588
|
+
api_gate_stale = new_module_api.any? { |target| target["kind"] == "gate" }
|
|
589
|
+
api_artifact_stale = new_module_api.any? { |target| target["kind"] == "artifact" }
|
|
493
590
|
linked_ready_facts = ready_slice.merge(
|
|
494
|
-
"gates_satisfied" => !
|
|
495
|
-
"no_stale_artifacts" => !
|
|
591
|
+
"gates_satisfied" => !api_gate_stale,
|
|
592
|
+
"no_stale_artifacts" => !api_artifact_stale
|
|
496
593
|
)
|
|
497
594
|
failures << "传播后未撤销 ready-for-agent" if ready_for_agent?(ready_required, linked_ready_facts)
|
|
498
595
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require "pathname"
|
|
5
5
|
require "yaml"
|
|
6
|
+
require "digest"
|
|
6
7
|
|
|
7
8
|
ROOT = Pathname.new(__dir__).join("..").realpath
|
|
8
9
|
|
|
@@ -76,6 +77,46 @@ def flow_decision(definition, repository_mode:, flow:)
|
|
|
76
77
|
{"result" => "allowed", "reason" => nil}
|
|
77
78
|
end
|
|
78
79
|
|
|
80
|
+
def git_operation_authorized?(definition, facts)
|
|
81
|
+
return false unless definition["requires_explicit_user_authorization"] == true
|
|
82
|
+
return false unless definition["authorized_value"] == true
|
|
83
|
+
|
|
84
|
+
required = definition.fetch("required", [])
|
|
85
|
+
return false unless required.all? { |field| facts.key?(field) }
|
|
86
|
+
|
|
87
|
+
authorization_fields = required.grep(/_authorized\z/)
|
|
88
|
+
return false unless authorization_fields.all? { |field| facts[field] == definition["authorized_value"] }
|
|
89
|
+
|
|
90
|
+
definition.fetch("non_empty", []).all? { |field| !facts.fetch(field, "").to_s.empty? }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def uint64be(value)
|
|
94
|
+
[value].pack("Q>")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def uint32be(value)
|
|
98
|
+
[value].pack("N")
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def canonical_worktree_candidate_stream(snapshot, tracked_diff:, untracked:)
|
|
102
|
+
header = snapshot.fetch("header_ascii").b + [Integer(snapshot.fetch("terminator_byte"))].pack("C")
|
|
103
|
+
tracked = snapshot.fetch("tracked_record")
|
|
104
|
+
stream = header + [Integer(tracked.fetch("type_byte"))].pack("C") + uint64be(tracked_diff.bytesize) + tracked_diff
|
|
105
|
+
kinds = snapshot.fetch("untracked_record").fetch("entry_kinds")
|
|
106
|
+
|
|
107
|
+
untracked.sort_by { |entry| entry.fetch(:path).b }.each do |entry|
|
|
108
|
+
path = entry.fetch(:path).b
|
|
109
|
+
content = entry.fetch(:content).b
|
|
110
|
+
kind = entry.fetch(:kind).to_s
|
|
111
|
+
stream << [Integer(snapshot.fetch("untracked_record").fetch("type_byte"))].pack("C")
|
|
112
|
+
stream << uint64be(path.bytesize) << path
|
|
113
|
+
stream << uint32be(entry.fetch(:mode))
|
|
114
|
+
stream << [Integer(kinds.fetch(kind))].pack("C")
|
|
115
|
+
stream << uint64be(content.bytesize) << content
|
|
116
|
+
end
|
|
117
|
+
stream
|
|
118
|
+
end
|
|
119
|
+
|
|
79
120
|
entry = contract.fetch("entry_routing", {})
|
|
80
121
|
require_equal(failures, "entry manifest", entry["manifest"], "yss-project.yaml")
|
|
81
122
|
require_equal(failures, "entry valid modes", entry["valid_modes"], %w[template-source project-instance])
|
|
@@ -196,6 +237,222 @@ ready_required = contract.dig("ready_for_agent", "required") || []
|
|
|
196
237
|
(preconditions.dig("implement", "required") || []).reject { |field| field == "ready_for_agent" }.each do |field|
|
|
197
238
|
require_include(failures, "ready-for-agent 与 implement 前置条件", ready_required, field)
|
|
198
239
|
end
|
|
240
|
+
|
|
241
|
+
ticket_role_transition = contract.fetch("ticket_role_transition", {})
|
|
242
|
+
require_equal(
|
|
243
|
+
failures,
|
|
244
|
+
"YSS to-tickets initial role",
|
|
245
|
+
ticket_role_transition.dig("yss_active", "to_tickets_initial_role"),
|
|
246
|
+
"ready-for-human"
|
|
247
|
+
)
|
|
248
|
+
require_equal(
|
|
249
|
+
failures,
|
|
250
|
+
"YSS ticket promotion owner",
|
|
251
|
+
ticket_role_transition.dig("yss_active", "promotion_owner"),
|
|
252
|
+
"yss-product-lifecycle"
|
|
253
|
+
)
|
|
254
|
+
require_equal(
|
|
255
|
+
failures,
|
|
256
|
+
"YSS ticket promoted role",
|
|
257
|
+
ticket_role_transition.dig("yss_active", "promoted_role"),
|
|
258
|
+
"ready-for-agent"
|
|
259
|
+
)
|
|
260
|
+
require_equal(
|
|
261
|
+
failures,
|
|
262
|
+
"YSS ticket promotion condition",
|
|
263
|
+
ticket_role_transition.dig("yss_active", "promotion_requires"),
|
|
264
|
+
"ready_for_agent"
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
review_input = contract.fetch("review_input", {})
|
|
268
|
+
require_equal(failures, "review input schema", review_input["schema_version"], 1)
|
|
269
|
+
%w[
|
|
270
|
+
review_mode
|
|
271
|
+
review_base_ref
|
|
272
|
+
implementation_candidate_ref
|
|
273
|
+
candidate_snapshot_ref
|
|
274
|
+
candidate_digest
|
|
275
|
+
spec_ref
|
|
276
|
+
ticket_ref
|
|
277
|
+
slice_contract_ref
|
|
278
|
+
build_architecture_checklist_ref
|
|
279
|
+
yss_execution_result_refs
|
|
280
|
+
].each do |field|
|
|
281
|
+
require_include(failures, "review input required fields", review_input["required"] || [], field)
|
|
282
|
+
end
|
|
283
|
+
%w[committed worktree].each do |mode|
|
|
284
|
+
require_include(failures, "review modes", review_input["modes"] || [], mode)
|
|
285
|
+
end
|
|
286
|
+
%w[committed staged unstaged untracked].each do |candidate_part|
|
|
287
|
+
require_include(
|
|
288
|
+
failures,
|
|
289
|
+
"worktree review coverage",
|
|
290
|
+
review_input.dig("worktree", "required_coverage") || [],
|
|
291
|
+
candidate_part
|
|
292
|
+
)
|
|
293
|
+
end
|
|
294
|
+
require_equal(
|
|
295
|
+
failures,
|
|
296
|
+
"worktree untracked inventory",
|
|
297
|
+
review_input.dig("worktree", "untracked_inventory_command"),
|
|
298
|
+
"git ls-files -z --others --exclude-standard"
|
|
299
|
+
)
|
|
300
|
+
require_equal(
|
|
301
|
+
failures,
|
|
302
|
+
"worktree tracked binary diff",
|
|
303
|
+
review_input.dig("worktree", "tracked_diff_command"),
|
|
304
|
+
"git diff --no-ext-diff --binary --full-index <merge-base>"
|
|
305
|
+
)
|
|
306
|
+
require_equal(
|
|
307
|
+
failures,
|
|
308
|
+
"worktree untracked binary diff",
|
|
309
|
+
review_input.dig("worktree", "untracked_diff_command"),
|
|
310
|
+
"git diff --no-index --no-ext-diff --binary --full-index -- /dev/null <path>"
|
|
311
|
+
)
|
|
312
|
+
require_equal(failures, "worktree capture once", review_input.dig("worktree", "capture_once"), true)
|
|
313
|
+
require_equal(failures, "worktree verify unchanged", review_input.dig("worktree", "verify_unchanged_after_review"), true)
|
|
314
|
+
require_equal(failures, "review snapshot immutable", review_input.dig("snapshot", "immutable"), true)
|
|
315
|
+
require_equal(failures, "review digest algorithm", review_input.dig("snapshot", "digest_algorithm"), "sha256")
|
|
316
|
+
require_equal(
|
|
317
|
+
failures,
|
|
318
|
+
"review digest framing",
|
|
319
|
+
review_input.dig("snapshot", "digest_framing"),
|
|
320
|
+
"length-prefixed-path-and-bytes"
|
|
321
|
+
)
|
|
322
|
+
require_equal(failures, "review digest path order", review_input.dig("snapshot", "path_order"), "bytewise")
|
|
323
|
+
require_equal(failures, "review digest change action", review_input.dig("snapshot", "on_digest_change"), "blocked")
|
|
324
|
+
require_equal(failures, "review completion digest guard", review_input.dig("snapshot", "completion_requires_current_digest"), true)
|
|
325
|
+
require_equal(failures, "review snapshot protocol", review_input.dig("snapshot", "protocol"), "yss-worktree-candidate-v1")
|
|
326
|
+
require_equal(failures, "review snapshot path encoding", review_input.dig("snapshot", "path_encoding"), "raw-bytes")
|
|
327
|
+
require_equal(failures, "review snapshot length encoding", review_input.dig("snapshot", "length_encoding"), "uint64-big-endian")
|
|
328
|
+
require_equal(failures, "review snapshot header", review_input.dig("snapshot", "header_ascii"), "YSS-WORKTREE-CANDIDATE-V1")
|
|
329
|
+
require_equal(failures, "review snapshot terminator", review_input.dig("snapshot", "terminator_byte"), "0x00")
|
|
330
|
+
require_equal(failures, "review snapshot tracked record", review_input.dig("snapshot", "tracked_record", "type_byte"), "0x54")
|
|
331
|
+
require_equal(failures, "review snapshot untracked record", review_input.dig("snapshot", "untracked_record", "type_byte"), "0x55")
|
|
332
|
+
require_equal(failures, "review snapshot unsupported entry action", review_input.dig("snapshot", "unsupported_entry_action"), "blocked")
|
|
333
|
+
require_equal(
|
|
334
|
+
failures,
|
|
335
|
+
"review snapshot tracked fields",
|
|
336
|
+
review_input.dig("snapshot", "tracked_record", "fields"),
|
|
337
|
+
%w[type_byte uint64be_content_length binary_diff_bytes]
|
|
338
|
+
)
|
|
339
|
+
require_equal(
|
|
340
|
+
failures,
|
|
341
|
+
"review snapshot untracked fields",
|
|
342
|
+
review_input.dig("snapshot", "untracked_record", "fields"),
|
|
343
|
+
%w[type_byte uint64be_path_length raw_path_bytes uint32be_file_mode entry_kind_byte uint64be_content_length content_bytes]
|
|
344
|
+
)
|
|
345
|
+
require_equal(
|
|
346
|
+
failures,
|
|
347
|
+
"review snapshot entry kinds",
|
|
348
|
+
review_input.dig("snapshot", "untracked_record", "entry_kinds"),
|
|
349
|
+
{"regular" => "0x52", "symlink" => "0x4c"}
|
|
350
|
+
)
|
|
351
|
+
fixture_tracked_diff = "COMMITTED\\nSTAGED\\nUNSTAGED\\nDELETE\\nMODE-CHANGE\\n".b
|
|
352
|
+
fixture_untracked = [
|
|
353
|
+
{path: "z\\nname".b, mode: 0o100644, kind: :regular, content: "untracked-bytes\\n".b},
|
|
354
|
+
{path: "a-link".b, mode: 0o120777, kind: :symlink, content: "target\\nname".b}
|
|
355
|
+
]
|
|
356
|
+
fixture_stream = canonical_worktree_candidate_stream(
|
|
357
|
+
review_input.fetch("snapshot"),
|
|
358
|
+
tracked_diff: fixture_tracked_diff,
|
|
359
|
+
untracked: fixture_untracked
|
|
360
|
+
)
|
|
361
|
+
require_equal(
|
|
362
|
+
failures,
|
|
363
|
+
"review snapshot canonical digest",
|
|
364
|
+
Digest::SHA256.hexdigest(fixture_stream),
|
|
365
|
+
"cc1b30990cc0d2a11721140cd94cb92a275f9dd24c6663e21ad7e5ea47898b7d"
|
|
366
|
+
)
|
|
367
|
+
reordered_stream = canonical_worktree_candidate_stream(
|
|
368
|
+
review_input.fetch("snapshot"),
|
|
369
|
+
tracked_diff: fixture_tracked_diff,
|
|
370
|
+
untracked: fixture_untracked.reverse
|
|
371
|
+
)
|
|
372
|
+
require_equal(failures, "review snapshot bytewise ordering", reordered_stream, fixture_stream)
|
|
373
|
+
review_return_digest = Digest::SHA256.hexdigest(fixture_stream)
|
|
374
|
+
completion_digest = Digest::SHA256.hexdigest(fixture_stream)
|
|
375
|
+
require_equal(failures, "review return digest guard", review_return_digest, Digest::SHA256.hexdigest(fixture_stream))
|
|
376
|
+
require_equal(failures, "review completion digest guard behavior", completion_digest, Digest::SHA256.hexdigest(fixture_stream))
|
|
377
|
+
drift_stream = canonical_worktree_candidate_stream(
|
|
378
|
+
review_input.fetch("snapshot"),
|
|
379
|
+
tracked_diff: fixture_tracked_diff,
|
|
380
|
+
untracked: fixture_untracked.map { |entry| entry.merge(content: entry[:content] + "changed".b) }
|
|
381
|
+
)
|
|
382
|
+
failures << "review return digest drift 未阻断" if Digest::SHA256.hexdigest(drift_stream) == review_return_digest
|
|
383
|
+
failures << "review completion digest drift 未阻断" if Digest::SHA256.hexdigest(drift_stream) == completion_digest
|
|
384
|
+
%w[merge_base tracked_diff_command untracked_inventory_command untracked_diff_command untracked_files commit_list_command].each do |field|
|
|
385
|
+
require_include(
|
|
386
|
+
failures,
|
|
387
|
+
"worktree manifest required fields",
|
|
388
|
+
review_input.dig("manifest_required_by_mode", "worktree") || [],
|
|
389
|
+
field
|
|
390
|
+
)
|
|
391
|
+
end
|
|
392
|
+
%w[merge_base tracked_diff_command commit_list_command].each do |field|
|
|
393
|
+
require_include(
|
|
394
|
+
failures,
|
|
395
|
+
"committed manifest required fields",
|
|
396
|
+
review_input.dig("manifest_required_by_mode", "committed") || [],
|
|
397
|
+
field
|
|
398
|
+
)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
git_authorization = contract.fetch("git_authorization", {})
|
|
402
|
+
{
|
|
403
|
+
"commit" => %w[commit_authorized commit_scope commit_authorization_ref],
|
|
404
|
+
"push" => %w[push_authorized push_scope push_authorization_ref]
|
|
405
|
+
}.each do |operation, required_fields|
|
|
406
|
+
require_equal(
|
|
407
|
+
failures,
|
|
408
|
+
"#{operation} explicit authorization",
|
|
409
|
+
git_authorization.dig(operation, "requires_explicit_user_authorization"),
|
|
410
|
+
true
|
|
411
|
+
)
|
|
412
|
+
required_fields.each do |field|
|
|
413
|
+
require_include(failures, "#{operation} authorization fields", git_authorization.dig(operation, "required") || [], field)
|
|
414
|
+
end
|
|
415
|
+
require_equal(
|
|
416
|
+
failures,
|
|
417
|
+
"#{operation} authorization value",
|
|
418
|
+
git_authorization.dig(operation, "authorized_value"),
|
|
419
|
+
true
|
|
420
|
+
)
|
|
421
|
+
required_fields.reject { |field| field.end_with?("_authorized") }.each do |field|
|
|
422
|
+
require_include(
|
|
423
|
+
failures,
|
|
424
|
+
"#{operation} non-empty authorization fields",
|
|
425
|
+
git_authorization.dig(operation, "non_empty") || [],
|
|
426
|
+
field
|
|
427
|
+
)
|
|
428
|
+
end
|
|
429
|
+
require_equal(
|
|
430
|
+
failures,
|
|
431
|
+
"#{operation} unauthorized action",
|
|
432
|
+
git_authorization.dig(operation, "unauthorized_action"),
|
|
433
|
+
"checkpoint-only"
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
definition = git_authorization.fetch(operation, {})
|
|
437
|
+
valid_facts = required_fields.to_h do |field|
|
|
438
|
+
[field, field.end_with?("_authorized") ? true : "explicit-value"]
|
|
439
|
+
end
|
|
440
|
+
allowed = git_operation_authorized?(definition, valid_facts)
|
|
441
|
+
failures << "#{operation} 完整显式授权被错误阻断" unless allowed
|
|
442
|
+
|
|
443
|
+
false_authorization = valid_facts.merge("#{operation}_authorized" => false)
|
|
444
|
+
false_allowed = git_operation_authorized?(definition, false_authorization)
|
|
445
|
+
failures << "#{operation} authorized=false 未阻断" if false_allowed
|
|
446
|
+
|
|
447
|
+
required_fields.reject { |field| field.end_with?("_authorized") }.each do |field|
|
|
448
|
+
blank = valid_facts.merge(field => "")
|
|
449
|
+
blank_allowed = git_operation_authorized?(definition, blank)
|
|
450
|
+
failures << "#{operation} #{field} 为空时未阻断" if blank_allowed
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
false_contract = definition.merge("authorized_value" => false)
|
|
454
|
+
failures << "#{operation} authorized_value=false 未阻断" if git_operation_authorized?(false_contract, valid_facts)
|
|
455
|
+
end
|
|
199
456
|
{
|
|
200
457
|
"to-spec" => %w[user_problem mvp_and_non_goals success_criteria test_seam terminology_review]
|
|
201
458
|
}.each do |flow, required|
|
|
@@ -447,6 +704,7 @@ end
|
|
|
447
704
|
|
|
448
705
|
adapter = read(ROOT, ".agents/skills/yss-product-lifecycle/references/matt-yss-adapter.md")
|
|
449
706
|
to_spec = read(ROOT, ".agents/skills/to-spec/SKILL.md")
|
|
707
|
+
code_review = read(ROOT, ".agents/skills/code-review/SKILL.md")
|
|
450
708
|
require_markers(
|
|
451
709
|
failures,
|
|
452
710
|
"Matt to-spec core contract",
|
|
@@ -466,17 +724,55 @@ require_markers(
|
|
|
466
724
|
"发布提示由本适配层覆盖为 `ready-for-human`",
|
|
467
725
|
"to-spec",
|
|
468
726
|
"to-tickets",
|
|
727
|
+
"YSS active 的 `to-tickets`",
|
|
728
|
+
"`review_mode`",
|
|
729
|
+
"`commit_authorized`",
|
|
730
|
+
"`push_authorized`",
|
|
469
731
|
"Release",
|
|
470
732
|
"Retrospective"
|
|
471
733
|
]
|
|
472
734
|
)
|
|
735
|
+
require_markers(
|
|
736
|
+
failures,
|
|
737
|
+
"Matt code-review candidate modes",
|
|
738
|
+
code_review,
|
|
739
|
+
[
|
|
740
|
+
"Committed candidate",
|
|
741
|
+
"Worktree candidate",
|
|
742
|
+
"git diff --no-ext-diff --binary --full-index <merge-base>",
|
|
743
|
+
"git diff --no-index --no-ext-diff --binary --full-index -- /dev/null <path>",
|
|
744
|
+
"git ls-files -z --others --exclude-standard",
|
|
745
|
+
"staged",
|
|
746
|
+
"unstaged",
|
|
747
|
+
"untracked",
|
|
748
|
+
"candidate manifest",
|
|
749
|
+
"captured candidate",
|
|
750
|
+
"yss-worktree-candidate-v1",
|
|
751
|
+
"unsigned 64-bit big-endian",
|
|
752
|
+
"candidate_digest",
|
|
753
|
+
"stale candidate",
|
|
754
|
+
"immutable",
|
|
755
|
+
"length-prefixed",
|
|
756
|
+
"bytewise path order",
|
|
757
|
+
"return `blocked`"
|
|
758
|
+
]
|
|
759
|
+
)
|
|
473
760
|
|
|
474
761
|
lifecycle_skill = read(ROOT, ".agents/skills/yss-product-lifecycle/SKILL.md")
|
|
475
762
|
require_markers(
|
|
476
763
|
failures,
|
|
477
764
|
"lifecycle template-source guard",
|
|
478
765
|
lifecycle_skill,
|
|
479
|
-
[
|
|
766
|
+
[
|
|
767
|
+
"template-source",
|
|
768
|
+
"必须返回 `blocked`",
|
|
769
|
+
"template-source-product-artifact-forbidden",
|
|
770
|
+
"YSS active 调用 `to-spec` 时",
|
|
771
|
+
"ready-for-agent` 发布提示归一化为 Spec `ready-for-human`",
|
|
772
|
+
"YSS active 调用 `to-tickets` 时",
|
|
773
|
+
"`commit_authorized`",
|
|
774
|
+
"`push_authorized`"
|
|
775
|
+
]
|
|
480
776
|
)
|
|
481
777
|
orchestration = read(ROOT, ".agents/skills/yss-product-lifecycle/references/orchestration.md")
|
|
482
778
|
require_markers(
|