@ccoalm/ccl-skills 0.1.0
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/LICENSE +201 -0
- package/README.md +49 -0
- package/dist/assets/marketplace/.agents/plugins/marketplace.json +12 -0
- package/dist/assets/marketplace/.claude-plugin/marketplace.json +13 -0
- package/dist/assets/marketplace/marketplace-manifest.json +12 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.claude-plugin/marketplace.json +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.claude-plugin/plugin.json +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.codex-plugin/plugin.json +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/.worktree-only +3 -0
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/session-start.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/agent-context/subagent-start.md +12 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/AGENTS.md +19 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-delegation-owner.sh +125 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-edit-isolation.sh +102 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/guard-merge-authorization.sh +1156 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/hooks.json +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/merge-authorization-prompt.sh +142 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-guard.sh +12 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/owner-dispatch-stop.sh +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/remind-post-merge-cleanup.sh +144 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-context.sh +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/session-start.sh +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/skill-extraction-gate-stop.sh +69 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/subagent-start.sh +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_delegation_owner.sh +329 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_edit_isolation.sh +322 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_guard_merge_authorization.sh +902 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_merge_authorization_prompt.sh +178 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_remind_post_merge_cleanup.sh +121 -0
- package/dist/assets/marketplace/plugins/ccl-skills/hooks/test_session_start.sh +170 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/AGENTS.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/ccl-skills.ts +564 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-install-skills.md +14 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-update-skills.md +44 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-verify-skills.md +109 -0
- package/dist/assets/marketplace/plugins/ccl-skills/packages/opencode-plugin/commands/ccl-worktree-check.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/AGENTS.md +28 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/README.md +276 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.example.json +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/owner-dispatch.sh +1307 -0
- package/dist/assets/marketplace/plugins/ccl-skills/scripts/owner-dispatch/test.sh +941 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/agents-file-coverage-gate/SKILL.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/agents-file-coverage-gate/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/SKILL.md +188 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/android-dev.md +92 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/flutter-dev.md +80 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/ios-dev.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/kotlin-multiplatform.md +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-platform-boundaries.md +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/mobile-quality-release.md +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/app-cross-platform-dev/references/source-evidence-map.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +353 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/client-routing.md +419 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/manual-invocation-and-prompts.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +197 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/timeout-auth-and-capabilities.md +179 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +98 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_envelope.py +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/classify_timeout_exit.sh +15 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +1438 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/codex_review.sh +324 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/concern_excerpt.py +295 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/egress_schema.py +214 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/init_policy_matrix.py +642 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_packet_mcp.py +181 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/kimi_review.sh +1165 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/opencode_review.sh +1190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_cli_review.py +946 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_opencode_review.py +474 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_probe_result.py +1899 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_review_json.py +200 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +2845 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.sh +6 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/run_claude_capture.py +71 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/runtime-surface-verification-design.md +53 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_classify_envelope.sh +68 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +2311 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_cli_review_wrappers.sh +1832 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_code_review_identity.sh +73 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_concern_excerpt.sh +245 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_egress_schema.sh +177 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_init_policy_matrix.sh +272 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_kimi_packet_mcp.py +195 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_opencode_review_concurrency.sh +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_opencode_review_retry.sh +1005 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_opencode_review.sh +258 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_probe_result.sh +574 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_review_json.sh +349 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_compat.py +434 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_client_order.sh +264 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_review_gate.sh +2412 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/verify_native_skill_binding.py +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +153 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/references/diagnosis-playbook.md +54 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/references/prevention-routing.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/SKILL.md +69 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/feature-risk-router/references/security-review-gate.md +41 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/SKILL.md +165 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/api-security-boundaries.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/architecture-playbook.md +160 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/artifact-generation-architecture.md +37 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/audit-history-architecture.md +29 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/bulk-workflow-architecture.md +33 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/config-rule-routing-architecture.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/cross-cutting-concerns.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/data-modeling-and-migrations.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/data-platform-architecture.md +210 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/dependency-platform.md +105 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/developer-tooling-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/error-contract-architecture.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/event-driven-architecture.md +260 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/http-gateway-architecture.md +74 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/mq-consumer-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/multi-tenant-isolation.md +275 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/notification-architecture.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/ops-checklist.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/performance-capacity-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/protobuf-contract-architecture.md +119 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/redis-cache-coordination.md +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/release-runtime-readiness.md +65 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/replay-comparison-architecture.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/runtime-observability.md +94 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/service-scaffold.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/source-evidence-map.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-architecture/references/workflow-state-architecture.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/SKILL.md +159 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/artifact-generation-patterns.md +37 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/audit-history-patterns.md +28 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/bulk-import-export-patterns.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/config-rule-routing-patterns.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/data-access-patterns.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/db-schema-and-dal-patterns.md +109 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/dependency-client-patterns.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/developer-tooling-patterns.md +70 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/domain-feature-patterns.md +78 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/engineering-patterns.md +119 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/error-contract-patterns.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/feature-playbook.md +61 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/http-gateway-client-patterns.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/mq-consumer-patterns.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/notification-patterns.md +42 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/observability-implementation-patterns.md +101 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/performance-capacity-patterns.md +44 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/protobuf-contract-patterns.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/public-api-integration-patterns.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/quality-and-testing-patterns.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/redis-cache-lock-patterns.md +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/release-ops-patterns.md +112 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/reliability-patterns.md +83 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/replay-comparison-patterns.md +32 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/scaffold-and-codegen.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/source-evidence-map.md +54 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/go-microservice-dev/references/state-machine-task-patterns.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/SKILL.md +80 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/SKILL.md +117 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-approval-auto-reviewer.md +106 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-command-sandbox.md +441 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-context-freshness.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-credentials-auth.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-extensions-skills.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-file-edit-protocol.md +129 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-ide-integration.md +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-input-ingestion.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-instruction-composition.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-lifecycle-hooks.md +92 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-messaging.md +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-runtime-bootstrap.md +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-session-persistence.md +448 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-task-orchestration.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-tool-dispatch.md +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/agent-turn-lifecycle.md +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/inference-capacity-operations.md +162 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/llm-client-gateway.md +156 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/model-prompt-evaluation.md +146 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/llm-inference-integration/references/retrieval-agent-safety.md +273 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +202 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/contracts-and-state.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/cross-stack-alignment.md +94 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/framework-choice.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/online-practice-uptake.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/platform-capabilities.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/product-page-checklist.md +40 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/qa-release.md +72 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/references/source-evidence-map.md +82 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/SKILL.md +103 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/agents/openai.yaml +5 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-agent-delegation/references/multi-agent-delegation-playbook.md +100 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/SKILL.md +70 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-data-acquisition.md +549 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/public-disclosure-channels.md +97 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/references/research-prompts.md +66 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/scripts/AGENTS.md +32 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/multi-perspective-research/scripts/test-public-data-acquisition-recipes.sh +379 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +244 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/alerting-and-on-call.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/framework-middleware-checklist.md +142 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/infra-component-deployment.md +268 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/log-correlation-recipe.md +124 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/log-schema-canonical.md +208 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/metrics-conventions.md +105 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/obs-stack-architecture.md +107 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/sli-slo-design.md +95 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/references/source-register.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/SKILL.md +303 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/canary-and-rollout-strategy.md +163 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/config-center-via-etcd.md +245 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/custom-control-plane-boundary.md +298 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/deploy-cli-concrete-recipe.md +312 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/deploy-pipeline.md +165 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/env-and-lane-matrix.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/lane-orchestration-control-plane.md +383 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/multi-region-and-cluster.md +135 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/promotion-gate-and-review.md +149 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/python-package-registry-release.md +462 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/rollback-playbook.md +123 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/secret-and-config-management.md +231 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/references/version-authority-and-deprecation.md +21 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/SKILL.md +276 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/dual-sidecar-and-traffic-config-center.md +127 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/framework-middleware.md +143 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/grpc-authority-workaround.md +90 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/http-response-envelope-contract.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/mesh-architecture.md +127 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/multi-env-routing.md +192 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/protobuf-http-contract-signals.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/retry-timeout-circuit-breaker.md +124 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/rpc-framework-recipe.md +494 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-choice.md +113 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-migration-playbook.md +231 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-service-connectivity/references/service-discovery-recipe.md +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +235 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/adr-convention.md +146 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-checklist.md +30 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-evaluation-report-template.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-execution-spec.md +108 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-sop.md +457 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/algorithm-launch-templates.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/artifact-egress-confidentiality.md +58 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/code-review-checklist.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/cross-repo-coordination.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/delivery-lifecycle.md +192 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-review-gate-mechanics.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/design-routing-and-readiness.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/diagnostic-spec-match-gate.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/dispatch-owner-skills.md +35 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/dormant-code-activation.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/existing-project-assessment-report.md +223 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/external-skill-augmentation.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/feature-deprecation-cascade.md +15 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/high-risk-resilience-gates.md +73 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/implementation-completeness-and-minimality.md +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/implementation-entry-reentry-gate.md +122 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/modular-monolith-heuristic.md +105 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/pre-final-continuation-gate.md +115 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/problem-resolution-and-learning.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/quality-attributes.md +112 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/quality-remediation-program.md +88 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/rd-standards-doc-family-checklist.md +27 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/refactoring-discipline.md +52 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/review-reception.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/shared-gate-artifact-classification.md +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/source-evidence-map.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/status-tracker-sync.md +77 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/sync-spec-repo-contract.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/verify-developer-experience.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/worktree-mechanics.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/scripts/AGENTS.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/scripts/check-agent-contract-coverage.sh +213 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/SKILL.md +136 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/agents/openai.yaml +9 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/analytics-visualization-interactions.md +206 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/behavioral-aesthetic-logic.md +108 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/complex-creation-interactions.md +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-execution-checklist.md +214 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-impl-naming-and-versioning.md +53 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-intake-and-acceptance.md +129 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/design-system-source-of-truth.md +97 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/external-ui-ux-quality-benchmarks.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/frontend-code-evidence-map.md +63 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/interaction-design-patterns.md +146 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/layout-recipes-and-screenshot-acceptance.md +250 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-project-token-consistency.md +237 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/multi-stack-strategy.md +65 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/operational-processing-workflows.md +237 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-mobile-patterns.md +324 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/platform-web-desktop-patterns.md +456 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-lifecycle-acceptance-and-iteration.md +114 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/product-surface-patterns.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/resource-management-interactions.md +113 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/scenario-community-patterns.md +133 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/source-map.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/tokens-and-components.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/trust-sensitive-ai-and-data-patterns.md +96 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-audit.md +106 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/ui-ux-design-development.md +176 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-ui-ux-design/references/visual-craft.md +111 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/SKILL.md +157 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/ai-service-integration-boundaries.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/api-contract-and-schema.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/api-security-boundaries.md +39 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/architecture-playbook.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/async-execution-model.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/background-jobs-and-scheduling.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/batch-and-pipeline-architecture.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/config-secrets-runtime.md +22 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/data-modeling-and-migrations.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/data-platform-architecture.md +211 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/event-driven-architecture.md +263 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/multi-tenant-isolation.md +281 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/observability-and-ops.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/packaging-runtime-readiness.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/redis-cache-coordination.md +41 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/reliability-and-error-contract.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/source-evidence-map.md +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-architecture/references/web-framework-boundaries.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/SKILL.md +143 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/ai-service-wiring-patterns.md +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/async-and-worker-patterns.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/background-job-patterns.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/batch-and-artifact-patterns.md +13 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/dependency-client-patterns.md +39 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/error-handling-patterns.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/feature-playbook.md +43 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/observability-implementation-patterns.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/project-structure-and-tooling.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/public-api-security-patterns.md +52 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/redis-cache-lock-patterns.md +78 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/schema-and-validation-patterns.md +23 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/source-evidence-map.md +56 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/sqlalchemy-and-migrations-patterns.md +99 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/testing-and-quality-patterns.md +61 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/python-service-dev/references/web-framework-patterns.md +35 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/SKILL.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/config-runtime-readback.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/mr-merge-authorization.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/post-release-env-reset.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/release-closeout-evidence.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/release-scope-confirmation.md +21 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/tag-and-prod-pipeline-gate.md +20 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/test-scope-prompt.md +24 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-coordination/references/watcher-discipline.md +14 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/SKILL.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/comment-safe-release-doc.md +19 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/release-evidence-workflow.md +23 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/release-doc-writer/references/release-testing-scope-section.md +15 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/SKILL.md +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/SKILL.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/prd-composition-contract.md +35 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/requirement-closure-contract.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/references/security-four-questions.md +38 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-intent/SKILL.md +91 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-intent/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/SKILL.md +88 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +337 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/analysis-parse-fix-test-challenge-replay.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/attribution-verification.md +69 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/bootstrap-slim-c3-obligation-table.md +112 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/coverage-exhaustion-traps.md +45 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/description-authoring.md +162 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +507 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/evidence-card-template.md +51 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/example-domain-preselect.md +79 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-lifecycle-handoff.md +65 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/firing-point-placement.md +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/harness-patterns-and-eval.md +286 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/incident-postmortem-extraction.md +190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/l0-l1-l2-routing.md +114 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/online-skill-review.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/parallel-stack-references-pattern.md +164 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/r0-leakage-audit.md +90 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/recurring-anti-patterns-checklist.md +320 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/resume-paused-delivery.md +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-feedback-mining.md +33 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-finding-standards.md +57 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/review-rubric.md +40 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/rule-consolidation.md +118 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/skill-listing-budget.md +19 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +254 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-to-skill-extraction.md +658 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/two-source-extraction-pattern.md +167 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-judgment-extraction.md +179 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-routing-map.md +51 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +180 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/AGENTS.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-ccl-skills.sh +1452 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-evidence-card-leak.sh +491 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-mr-target-freshness.sh +173 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-size-budget.sh +488 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/check-sync-pointers.sh +419 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-golden-trace.rb +197 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-health.rb +327 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing-bank.rb +401 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing.rb +248 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/generic-r0-leak-scan.sh +282 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/governing-chain-diff.py +321 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +964 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/register-firing-path-resolution.rb +708 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/skill-behavior-eval.py +540 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/source-register-lifecycle.rb +51 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/source-register-pending-status.rb +55 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_ai_coding_implementation_gates.sh +829 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +1203 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_r0_status.sh +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_register_pending_exclusion.sh +137 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +173 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_route_drift.sh +377 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_size_budget.sh +833 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_skill_catalog.sh +491 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_source_register_lifecycle.sh +114 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_mr_target_freshness.sh +261 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_sync_pointers.sh +538 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_controlled_escalation_pins.sh +154 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_grader_diagnostics.sh +190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_surface_binding.sh +178 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_prose_target.sh +86 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_generic_r0_leak_scan.sh +131 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_git_identity_predicate_gate.sh +243 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_governing_chain_diff.sh +419 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_dateless_host.sh +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_resolution.sh +724 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_register_firing_path_wiring.sh +414 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_regression_runner_registration.sh +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_bank_integrity.sh +205 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_routing_pointer_integrity.sh +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_credential_cwd.sh +61 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_cross_refs.sh +111 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_validate_skill_root_depth.sh +53 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/validate-skill.sh +257 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/SKILL.md +98 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/input-state-machines.md +36 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/streaming-rich-output.md +130 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/terminal-cli-dev/references/terminal-side-channels.md +96 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/SKILL.md +408 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/AGENTS.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/bitable-setup.md +573 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/README.md +120 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/github-actions.yml +119 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/gitlab-ci.yml +76 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/ci_templates/jenkins.Jenkinsfile +106 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/classical-test-design-techniques.md +279 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/gen_report.py +2807 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/makefile-template.md +200 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/report-config-schema.md +272 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/run_pytestless.py +475 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/source-to-case-workflows.md +258 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-marker-conventions.md +316 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc-review-and-prioritization.md +145 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/AGENTS.md +16 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.dart +129 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.go +197 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.py +135 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/tc_helpers/tc.ts +285 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/test_gen_report.py +2144 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/test-artifact-management/references/update-lifecycle.md +62 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/SKILL.md +212 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/ci-fixtures-and-flake-control.md +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/client-runtime-test-matrices.md +50 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/data-and-workflow-testing.md +34 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/design-closed-contract-oracles.md +31 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/e2e-real-flow-testing.md +71 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/fitness-functions.md +240 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/integration-contract-testing.md +235 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/non-functional-specialized-scenarios.md +296 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/rd-testing-standard-template.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/run-killing-mutation-walk.md +43 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/scenario-testing.md +136 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/source-evidence-map.md +59 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/structured-tc-input-translation.md +67 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-code-authoring-patterns.md +392 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-data-and-determinism.md +39 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/test-topology-and-commands.md +92 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/unit-testing.md +46 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/vendored-contract-drift-checklist.md +64 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/references/verify-enforcement-mechanisms.md +18 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/AGENTS.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/client-terminal-ansi-check.py +140 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/client-terminal-ansi-check.test.sh +75 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-ast-check.py +170 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-ast-check.test.sh +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-go-check.go +198 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/lang-basics-go-check.test.sh +109 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/testing-strategy/scripts/test_mutation_backup_recipe.sh +237 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/SKILL.md +184 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/comment-safe-feishu.md +93 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/cross-model-co-review.md +3 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/delivery-face-closeout.md +60 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/doc-charter-first.md +17 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/tighten-doc/references/session-vantage-leakage.md +58 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/SKILL.md +126 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/complex-workspace-patterns.md +47 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/embedded-h5-in-host.md +87 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/react-architecture.md +194 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/source-evidence-map.md +60 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-quality-release.md +190 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/web-react-dev/references/web-ui-quality.md +83 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/SKILL.md +179 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/agents/openai.yaml +4 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/references/shared-branch-rebase.md +25 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/AGENTS.md +23 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/test_worktree_status.sh +207 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/test_worktree_sweep.sh +481 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/worktree-status.sh +325 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/worktree-isolation/scripts/worktree-sweep.sh +245 -0
- package/dist/assets/release.json +2797 -0
- package/dist/claude-adapter.d.ts +9 -0
- package/dist/claude-adapter.js +240 -0
- package/dist/cli-worker.d.ts +1 -0
- package/dist/cli-worker.js +32 -0
- package/dist/cli.d.ts +22 -0
- package/dist/cli.js +214 -0
- package/dist/codex-host.d.ts +30 -0
- package/dist/codex-host.js +162 -0
- package/dist/fs-safe.d.ts +21 -0
- package/dist/fs-safe.js +241 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/manifest.d.ts +8 -0
- package/dist/manifest.js +135 -0
- package/dist/opencode-adapter.d.ts +10 -0
- package/dist/opencode-adapter.js +416 -0
- package/dist/operations.d.ts +3 -0
- package/dist/operations.js +956 -0
- package/dist/paths.d.ts +20 -0
- package/dist/paths.js +4 -0
- package/dist/types.d.ts +58 -0
- package/dist/types.js +1 -0
- package/dist/unified.d.ts +4 -0
- package/dist/unified.js +64 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +5 -0
- package/package.json +35 -0
|
@@ -0,0 +1,964 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
#
|
|
4
|
+
# Impact-chain firing gate: every added source-register row for a changed
|
|
5
|
+
# upstream-owner skill must declare a behavioral-evidence status and an
|
|
6
|
+
# observed-failure state, and (for non-wording changes) name an owner-scoped
|
|
7
|
+
# FIRING PATH that resolves to this diff — an anchor on a changed normative
|
|
8
|
+
# rule line, or a changed owner executable. The statuses are required author
|
|
9
|
+
# declarations; the firing path and the wording-only classification are the
|
|
10
|
+
# machine-verified core. Extracted from the former inline `ruby -e` block in
|
|
11
|
+
# check-ccl-skills.sh so the program gets normal Ruby tooling and no
|
|
12
|
+
# single-quote embedding constraint. Invoked by check-ccl-skills.sh (same
|
|
13
|
+
# scripts/ directory) with the target repo root as ARGV[0]; exits 1 on gate
|
|
14
|
+
# failure, 0 otherwise.
|
|
15
|
+
|
|
16
|
+
require "yaml"
|
|
17
|
+
# `description_is_scalar` passes Date to safe_load's permitted_classes; psych
|
|
18
|
+
# only sometimes loads date transitively (<=5.1 lazily, 5.2.0-5.2.5 never,
|
|
19
|
+
# 5.2.6+ eagerly), so declare the dependency instead of riding on that.
|
|
20
|
+
require "date"
|
|
21
|
+
|
|
22
|
+
root = ARGV.fetch(0)
|
|
23
|
+
# Diff reads FAIL CLOSED: a git failure that returned empty output would
|
|
24
|
+
# otherwise make the gate see no changed owners and silently pass.
|
|
25
|
+
git_read = lambda do |*args|
|
|
26
|
+
out = IO.popen(["git", "-C", root, *args], &:read)
|
|
27
|
+
unless $?.success?
|
|
28
|
+
warn "impact_chain_git_failed: git #{args.join(" ")} exited #{$?.exitstatus}"
|
|
29
|
+
exit 1
|
|
30
|
+
end
|
|
31
|
+
out
|
|
32
|
+
end
|
|
33
|
+
base = ENV["CCL_SKILL_BASE_REF"].to_s.strip
|
|
34
|
+
if base.empty?
|
|
35
|
+
upstream_ref = IO.popen(["git", "-C", root, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}", err: File::NULL], &:read).strip
|
|
36
|
+
base = upstream_ref.empty? ? "origin/main" : upstream_ref
|
|
37
|
+
end
|
|
38
|
+
merge_base = IO.popen(["git", "-C", root, "merge-base", base, "HEAD"], &:read).strip
|
|
39
|
+
if merge_base.empty?
|
|
40
|
+
warn "impact_chain_merge_base_missing: #{base}"
|
|
41
|
+
exit 1
|
|
42
|
+
end
|
|
43
|
+
base_ref = merge_base
|
|
44
|
+
LEDGER_PATH = "skills/skill-extraction-workflow/references/source-register.md"
|
|
45
|
+
# ROUND SCOPING. An evidence row is authored against ONE round's diff, but every
|
|
46
|
+
# classifier below used to read the whole base..HEAD range. The two are different
|
|
47
|
+
# units, so a row's verdict moved after it landed: an already-gated row turned red
|
|
48
|
+
# once a LATER round touched the same owner, and a description-only round lost its
|
|
49
|
+
# locator because an EARLIER round had edited that owner's body. Both are the same
|
|
50
|
+
# defect — the predicate was scoped to the RANGE instead of to the round the row
|
|
51
|
+
# belongs to — and patching the symptoms one at a time (the retarget tolerance in
|
|
52
|
+
# the routing-surface class below was one such patch) only re-instantiates it on
|
|
53
|
+
# the next input. The predicate now reads the round.
|
|
54
|
+
#
|
|
55
|
+
# Rounds are cut at the commits that touch the ledger itself, walked first-parent
|
|
56
|
+
# so one merged worktree round collapses to one boundary. The partition comes from
|
|
57
|
+
# git alone: an author cannot widen, move, or nominate their own scope.
|
|
58
|
+
round_heads = git_read.call("rev-list", "--first-parent", "--reverse", "#{base_ref}..HEAD", "--", LEDGER_PATH)
|
|
59
|
+
.split("\n").map(&:strip).reject(&:empty?)
|
|
60
|
+
# Each round spans (previous ledger boundary, this one] so the work commits that
|
|
61
|
+
# precede a ledger append are inside the round they belong to — landing the change
|
|
62
|
+
# and appending the row in separate commits is the normal shape, not an evasion.
|
|
63
|
+
round_bounds = ([base_ref] + round_heads).each_cons(2).to_a
|
|
64
|
+
# The trailing span — owner changes committed after the last ledger append — is a
|
|
65
|
+
# round too. It holds no rows, so its owners fall through to the presence check
|
|
66
|
+
# and the gate still fails closed on undeclared work.
|
|
67
|
+
round_bounds << [round_heads.last || base_ref, "HEAD"]
|
|
68
|
+
# Everything a predicate needs to judge one span. Built lazily per span and
|
|
69
|
+
# memoized: a round whose rows are all RED-baseline never pays for the rename
|
|
70
|
+
# derivation.
|
|
71
|
+
scope_struct = Struct.new(:base, :head, :changed_paths, :rename_pairs, :rename_pattern)
|
|
72
|
+
scope_cache = {}
|
|
73
|
+
scope_at = lambda do |span_base, span_head|
|
|
74
|
+
scope_cache[[span_base, span_head]] ||= begin
|
|
75
|
+
# --no-renames so a moved-out/renamed upstream reference or script surfaces its
|
|
76
|
+
# OLD path (as a delete) instead of collapsing to a destination outside skills/;
|
|
77
|
+
# otherwise `git mv skills/<owner>/references/x.md docs/x.md` would drop the
|
|
78
|
+
# owner entirely and slip past the row requirement.
|
|
79
|
+
# -z + NUL split so a path containing newline/tab bytes cannot hide from the
|
|
80
|
+
# owner and subject-set enumeration behind Git's line-oriented quoting.
|
|
81
|
+
paths = git_read.call("diff", "--no-renames", "-z", span_base, span_head, "--name-only")
|
|
82
|
+
.split("\0").reject(&:empty?)
|
|
83
|
+
# Rename pairs come from git's own tree state — which owner packages disappeared
|
|
84
|
+
# and which appeared — never from an author declaration. How the pairs are derived
|
|
85
|
+
# does not have to be trustworthy: every consumer below only ever gets stricter
|
|
86
|
+
# when a pair is wrong, and nothing here lets a diff be measured against a
|
|
87
|
+
# DIFFERENT file.
|
|
88
|
+
pairs = git_read.call("diff", "--find-renames", "--diff-filter=R", "-z", "--name-status",
|
|
89
|
+
span_base, span_head, "--", "skills/*/SKILL.md")
|
|
90
|
+
.split("\0").reject(&:empty?).each_slice(3).filter_map do |_status, from, to|
|
|
91
|
+
from_owner = from.to_s[%r{\Askills/([^/]+)/SKILL\.md\z}, 1]
|
|
92
|
+
to_owner = to.to_s[%r{\Askills/([^/]+)/SKILL\.md\z}, 1]
|
|
93
|
+
[from_owner, to_owner] if from_owner && to_owner && from_owner != to_owner
|
|
94
|
+
end.to_h
|
|
95
|
+
# Single-pass alternation so one pair's output can never be re-matched by another
|
|
96
|
+
# pair (a chained gsub would let old -> new -> newer cascade).
|
|
97
|
+
pattern = pairs.empty? ? nil : Regexp.union(pairs.keys.sort_by { |k| -k.length }.map { |k| k.dup.force_encoding(Encoding::BINARY) })
|
|
98
|
+
scope_struct.new(span_base, span_head, paths, pairs, pattern)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
# The CUMULATIVE scope still owns everything that asks "was this owner touched at
|
|
102
|
+
# all between base and HEAD" — subject selection and the presence check. Narrowing
|
|
103
|
+
# those to a round would let an owner changed in one round be declared in another,
|
|
104
|
+
# so they deliberately keep reading the whole range.
|
|
105
|
+
cumulative = scope_at.call(base_ref, "HEAD")
|
|
106
|
+
changed_paths = cumulative.changed_paths
|
|
107
|
+
# Normalize every changed path to the owning "<skill>/SKILL.md" identity (the
|
|
108
|
+
# prefix-free form the select rules and source-register evidence convention both
|
|
109
|
+
# use). ANY path inside an owner package maps to the owner — SKILL.md,
|
|
110
|
+
# references/, scripts/, and every other shipped file (agents/ overlays,
|
|
111
|
+
# templates, assets): the whole package is behavior-bearing, and enumerating
|
|
112
|
+
# "behavioral" subdirectories is how the agents/ overlay slipped through.
|
|
113
|
+
# Scoping to exactly one path segment under skills/ (via [^/]+) is what makes
|
|
114
|
+
# the gate fire without letting stray paths like docs/<x>-architecture/SKILL.md
|
|
115
|
+
# trip it.
|
|
116
|
+
# The source-register itself is the impact-chain LEDGER; appending rows to it is a
|
|
117
|
+
# routine, self-referential operation, so it never counts as an upstream change
|
|
118
|
+
# (otherwise every ledger append would demand a row about editing the ledger).
|
|
119
|
+
changed = changed_paths.map do |path|
|
|
120
|
+
next nil if path == "skills/skill-extraction-workflow/references/source-register.md"
|
|
121
|
+
if (m = path.match(%r{\Askills/([^/]+)/.+\z}m))
|
|
122
|
+
"#{m[1]}/SKILL.md"
|
|
123
|
+
end
|
|
124
|
+
end.compact.uniq
|
|
125
|
+
# Curated upstream-owner list for the automated impact-chain gate.
|
|
126
|
+
# When a new skill becomes an upstream decision owner, add it here in the same
|
|
127
|
+
# change that introduces that responsibility.
|
|
128
|
+
upstream_owner_skills = %w[
|
|
129
|
+
code-review
|
|
130
|
+
defect-diagnosis
|
|
131
|
+
feature-risk-router
|
|
132
|
+
llm-inference-integration
|
|
133
|
+
multi-agent-delegation
|
|
134
|
+
multi-perspective-research
|
|
135
|
+
platform-observability
|
|
136
|
+
platform-release-engineering
|
|
137
|
+
platform-service-connectivity
|
|
138
|
+
product-rd-workflow
|
|
139
|
+
product-ui-ux-design
|
|
140
|
+
skill-extraction-workflow
|
|
141
|
+
test-artifact-management
|
|
142
|
+
testing-strategy
|
|
143
|
+
tighten-doc
|
|
144
|
+
]
|
|
145
|
+
# Name-level selection predicate, shared by the cumulative subject filter and
|
|
146
|
+
# the per-round rename-away suppression below: whether a NAME is a decision
|
|
147
|
+
# owner is a property of the name, independent of whether it exists at the
|
|
148
|
+
# range endpoints.
|
|
149
|
+
selectable_path = lambda do |path|
|
|
150
|
+
path.end_with?("-architecture/SKILL.md") ||
|
|
151
|
+
path.start_with?("platform-") && path.end_with?("/SKILL.md") ||
|
|
152
|
+
upstream_owner_skills.any? { |skill| path == "#{skill}/SKILL.md" }
|
|
153
|
+
end
|
|
154
|
+
upstream = changed.select { |path| selectable_path.call(path) }
|
|
155
|
+
# Subject selection reasons about the whole range, so it reads the cumulative
|
|
156
|
+
# pairs; the per-round classifiers take their pairs from their own scope.
|
|
157
|
+
rename_pairs = cumulative.rename_pairs
|
|
158
|
+
rename_pattern = cumulative.rename_pattern
|
|
159
|
+
# Blob and package readers, hoisted because BOTH the subject filter below and the
|
|
160
|
+
# no-behaviour classifier need them. Binary, because a package may legitimately
|
|
161
|
+
# track a blob that is not valid UTF-8 and comparing bytes must not depend on
|
|
162
|
+
# decoding them; slugs are ASCII so the substitution is unaffected.
|
|
163
|
+
raw_blob_at = lambda do |ref, relative|
|
|
164
|
+
out = IO.popen(["git", "-C", root, "show", "#{ref}:#{relative}", err: File::NULL], &:read)
|
|
165
|
+
$?.success? ? out.force_encoding(Encoding::BINARY) : nil
|
|
166
|
+
end
|
|
167
|
+
# Existence at a ref must mean A REGULAR FILE. `git show ref:path` also succeeds
|
|
168
|
+
# for a TREE, so a directory named SKILL.md would read as "present" and let a
|
|
169
|
+
# row vouch for an owner whose entrypoint was effectively deleted (the
|
|
170
|
+
# extension-challenge P1). ls-tree exposes the entry's mode; only a regular
|
|
171
|
+
# blob counts, so symlinks, submodules, and directories all read as absent and
|
|
172
|
+
# fall through to the deletion fail-closed path.
|
|
173
|
+
regular_blob_at = lambda do |ref, relative|
|
|
174
|
+
out = IO.popen(["git", "-C", root, "ls-tree", "-z", ref, "--", relative], err: File::NULL, &:read)
|
|
175
|
+
next false unless $?.success?
|
|
176
|
+
entry = out.split("\0").reject(&:empty?).first
|
|
177
|
+
next false unless entry
|
|
178
|
+
mode = entry.split(/\s+/, 2).first
|
|
179
|
+
mode == "100644" || mode == "100755"
|
|
180
|
+
end
|
|
181
|
+
# Every tracked entry in an owner package at one ref, as "<mode> <path>". The MODE
|
|
182
|
+
# is part of the identity: names and contents alone would let a diff drop the
|
|
183
|
+
# executable bit from a script and still reproduce byte-for-byte.
|
|
184
|
+
package_files = lambda do |ref, owner|
|
|
185
|
+
out = IO.popen(["git", "-C", root, "ls-tree", "-r", "-z", ref, "--", "skills/#{owner}/"],
|
|
186
|
+
err: File::NULL, &:read)
|
|
187
|
+
next nil unless $?.success?
|
|
188
|
+
out.split("\0").reject(&:empty?).map do |entry|
|
|
189
|
+
meta, path = entry.split("\t", 2)
|
|
190
|
+
"#{meta.to_s.split(/\s+/, 2).first} #{path}"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
# Canonical form of a package path for comparison. The directory moves, and the
|
|
194
|
+
# substitution is applied to BOTH sides so a FILENAME carrying the old slug — a
|
|
195
|
+
# renamed skill's own playbook reference is exactly that case — compares equal
|
|
196
|
+
# whether or not the author also renamed the file. Normalizing rather than
|
|
197
|
+
# rewriting one side keeps the gate from quietly demanding filename renames it has
|
|
198
|
+
# no business requiring.
|
|
199
|
+
canonical_package_path = lambda do |scope, path, base_owner, owner|
|
|
200
|
+
moved = path.sub("skills/#{base_owner}/", "skills/#{owner}/")
|
|
201
|
+
scope.rename_pattern ? moved.gsub(scope.rename_pattern) { |hit| scope.rename_pairs.fetch(hit) } : moved
|
|
202
|
+
end
|
|
203
|
+
# True when HEAD's `owner` package is base's `base_owner` package MOVED: the same
|
|
204
|
+
# file set, one-to-one. Deliberately structural and content-blind, because a real
|
|
205
|
+
# rename normally also edits a heading or a display name — requiring byte equality
|
|
206
|
+
# here would reject every honest rename. It is still far harder to satisfy than
|
|
207
|
+
# git's similarity score, which pairs two SKILL.md files and can therefore mistake
|
|
208
|
+
# "delete one skill, add a similar one" for a move.
|
|
209
|
+
package_moved = lambda do |scope, base_owner, owner|
|
|
210
|
+
base_files = package_files.call(scope.base, base_owner)
|
|
211
|
+
head_files = package_files.call(scope.head, owner)
|
|
212
|
+
return false if base_files.nil? || head_files.nil? || base_files.empty?
|
|
213
|
+
strip = ->(entries) { entries.map { |e| e.split(" ", 2).last } }
|
|
214
|
+
expected = strip.call(base_files).map { |f| canonical_package_path.call(scope, f, base_owner, owner) }
|
|
215
|
+
actual = strip.call(head_files).map { |f| canonical_package_path.call(scope, f, owner, owner) }
|
|
216
|
+
expected.sort == actual.sort
|
|
217
|
+
end
|
|
218
|
+
# True when HEAD's `owner` package is exactly base's `base_owner` package with the
|
|
219
|
+
# identifiers rewritten: one-to-one entries including mode, and byte-exact content
|
|
220
|
+
# under the substitution.
|
|
221
|
+
package_reproduces = lambda do |scope, base_owner, owner|
|
|
222
|
+
return false if scope.rename_pattern.nil?
|
|
223
|
+
base_files = package_files.call(scope.base, base_owner)
|
|
224
|
+
head_files = package_files.call(scope.head, owner)
|
|
225
|
+
return false if base_files.nil? || head_files.nil? || base_files.empty?
|
|
226
|
+
expected = base_files.map do |entry|
|
|
227
|
+
mode, path = entry.split(" ", 2)
|
|
228
|
+
"#{mode} #{canonical_package_path.call(scope, path, base_owner, owner)}"
|
|
229
|
+
end
|
|
230
|
+
return false unless expected.sort == head_files.sort
|
|
231
|
+
base_lookup = base_files.to_h do |entry|
|
|
232
|
+
path = entry.split(" ", 2).last
|
|
233
|
+
[canonical_package_path.call(scope, path, base_owner, owner), path]
|
|
234
|
+
end
|
|
235
|
+
head_files.map { |entry| entry.split(" ", 2).last }
|
|
236
|
+
.reject { |f| f == LEDGER_PATH }
|
|
237
|
+
.all? do |changed|
|
|
238
|
+
base_path = base_lookup.fetch(canonical_package_path.call(scope, changed, owner, owner))
|
|
239
|
+
base_bytes = raw_blob_at.call(scope.base, base_path)
|
|
240
|
+
head_bytes = raw_blob_at.call(scope.head, changed)
|
|
241
|
+
!base_bytes.nil? && !head_bytes.nil? &&
|
|
242
|
+
base_bytes.gsub(scope.rename_pattern) { |hit| scope.rename_pairs.fetch(hit) } == head_bytes
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
# A RENAMED-AWAY owner is excused from the CUMULATIVE subject set: for the
|
|
246
|
+
# rename round itself its successor is in `changed` and carries the declaration,
|
|
247
|
+
# so the rename is declared once, against the surviving name. The excuse is
|
|
248
|
+
# cumulative only — a round BEFORE the rename that substantively changed the
|
|
249
|
+
# owner still owes a row under the old name, and the evidence check reads each
|
|
250
|
+
# row against its own round head, so that row is writable and stays valid after
|
|
251
|
+
# the rename. The per-round subject set below re-admits the excused owner for
|
|
252
|
+
# exactly those rounds.
|
|
253
|
+
#
|
|
254
|
+
# A DELETED owner is not that case and stays a subject. Excluding every missing
|
|
255
|
+
# path would let removing a decision owner outright — the larger change of the
|
|
256
|
+
# two — pass with no declaration at all, which is a hole the pre-existing
|
|
257
|
+
# contradiction did not have (it failed closed). Deletions therefore keep failing
|
|
258
|
+
# until the ledger accounts for them, and only a git-confirmed rename whose
|
|
259
|
+
# destination actually survives is dropped here.
|
|
260
|
+
# --no-renames deliberately surfaces the OLD path so a reference or script moved
|
|
261
|
+
# out of a still-live owner cannot slip past; that intent is untouched, because a
|
|
262
|
+
# live owner still has its SKILL.md.
|
|
263
|
+
# Dropping the old path is only sound when the SUCCESSOR is itself a selected
|
|
264
|
+
# subject. Rename a curated owner to a slug nobody added to the list above and
|
|
265
|
+
# neither name is selected: the old one is dropped here and the new one was never
|
|
266
|
+
# picked, so the rename of a decision owner escapes entirely — worse than the
|
|
267
|
+
# contradiction this replaced, which at least failed closed. The destination must
|
|
268
|
+
# already be in the selected set for the declaration to have somewhere to land.
|
|
269
|
+
selected_paths = upstream.to_h { |path| [path, true] }
|
|
270
|
+
# Owners dropped here are remembered: the per-round subject set and the row
|
|
271
|
+
# recognition below re-admit them for the rounds where their SKILL.md still
|
|
272
|
+
# existed, so the cumulative excuse cannot leak backwards onto pre-rename work.
|
|
273
|
+
rename_excused = {}
|
|
274
|
+
upstream = upstream.reject do |path|
|
|
275
|
+
owner = path.sub(%r{/SKILL\.md\z}, "")
|
|
276
|
+
destination = rename_pairs[owner]
|
|
277
|
+
# git --find-renames is a SIMILARITY heuristic: it can pair a deleted SKILL.md
|
|
278
|
+
# with an unrelated new one. For the classifier a wrong pair is harmless — it
|
|
279
|
+
# only makes reproduction fail — but dropping a subject on a wrong pair is the
|
|
280
|
+
# opposite, so this drop is tied to hard evidence instead: the destination
|
|
281
|
+
# package must actually be the source package with the identifiers rewritten.
|
|
282
|
+
excused = !File.file?(File.join(root, "skills", path)) &&
|
|
283
|
+
destination && File.file?(File.join(root, "skills", destination, "SKILL.md")) &&
|
|
284
|
+
selected_paths["#{destination}/SKILL.md"] &&
|
|
285
|
+
package_moved.call(cumulative, owner, destination) &&
|
|
286
|
+
# The cumulative endpoints also pair a round-A DELETE with a round-B ADD of
|
|
287
|
+
# a lookalike — a laundering shape, not a rename. An honest rename is atomic
|
|
288
|
+
# inside one round, so the excuse additionally requires some single round's
|
|
289
|
+
# OWN pairs to contain the source; a cross-round delete/recreate split has
|
|
290
|
+
# no such pair and stays a deletion, which fails closed.
|
|
291
|
+
round_bounds.any? { |span_base, span_head| scope_at.call(span_base, span_head).rename_pairs.key?(owner) }
|
|
292
|
+
rename_excused[path] = true if excused
|
|
293
|
+
excused
|
|
294
|
+
end
|
|
295
|
+
if upstream.any?
|
|
296
|
+
# Rows are collected PER ROUND and carry the scope they were authored against,
|
|
297
|
+
# so the classifiers below judge a row against its own round's diff. Reading the
|
|
298
|
+
# cumulative register diff instead would re-judge every earlier round's rows
|
|
299
|
+
# against a range that keeps growing — the defect this partition removes.
|
|
300
|
+
rows = []
|
|
301
|
+
round_bounds.each do |span_base, span_head|
|
|
302
|
+
round_scope = scope_at.call(span_base, span_head)
|
|
303
|
+
register_diff = git_read.call("diff", span_base, span_head, "--", LEDGER_PATH)
|
|
304
|
+
register_diff.lines.each do |line|
|
|
305
|
+
next unless line.start_with?("+")
|
|
306
|
+
# Strip the diff "+" and any surrounding whitespace so an indented markdown row
|
|
307
|
+
# (up to 3 leading spaces is valid Markdown) parses the same as a column-0 row;
|
|
308
|
+
# the pending-status scan below normalizes identically, keeping the two
|
|
309
|
+
# consistent (previously "+|" alone falsely blocked a valid indented row).
|
|
310
|
+
stripped = line.sub(/\A\+/, "").strip
|
|
311
|
+
next unless stripped.start_with?("|") && stripped.end_with?("|")
|
|
312
|
+
raw = stripped[1..-2]
|
|
313
|
+
# Honor markdown-escaped pipes (\|) so a literal | inside a cell does not
|
|
314
|
+
# split into spurious columns and silently drop the whole row (which would
|
|
315
|
+
# later surface as a misleading "missing evidence path" for a row that is
|
|
316
|
+
# actually present). Split only on UNescaped |, then unescape each cell.
|
|
317
|
+
# Split on column delimiters with correct backslash parity: protect escaped
|
|
318
|
+
# backslashes (\\) then escaped pipes (\|) behind control-char sentinels,
|
|
319
|
+
# split on the remaining bare |, then restore. This way a | escaped by an ODD
|
|
320
|
+
# number of backslashes is literal, but an even count (e.g. \\ before |) is a
|
|
321
|
+
# real delimiter — so a structurally-malformed row is not silently accepted.
|
|
322
|
+
esc_bs = "\u0001"; esc_pipe = "\u0002"
|
|
323
|
+
cells = raw.gsub("\\\\", esc_bs).gsub("\\|", esc_pipe).split("|").map { |c| c.gsub(esc_pipe, "|").gsub(esc_bs, "\\\\").strip }
|
|
324
|
+
if cells.length != 5
|
|
325
|
+
# A line that otherwise looks like an impact-chain data row (cites a
|
|
326
|
+
# SKILL.md and a valid status word) but has the wrong column count is
|
|
327
|
+
# almost always an unescaped literal | inside a cell. Warn (advisory; does
|
|
328
|
+
# not change exit code): the register carries many OTHER legitimate table
|
|
329
|
+
# shapes whose prose can contain a status word and a SKILL.md citation,
|
|
330
|
+
# so hard-blocking here would false-positive on unrelated ledger rows.
|
|
331
|
+
# A deliberately mangled row evading per-row completeness is dishonest
|
|
332
|
+
# authorship — outside this gate's trust model; the warning plus the
|
|
333
|
+
# mandatory independent review own that residual.
|
|
334
|
+
if raw.include?("SKILL.md") && raw.match?(/(updated|unchanged|routed|not-applicable)/)
|
|
335
|
+
warn "impact_chain_row_malformed: likely an unescaped pipe inside a cell (escape it as backslash-pipe): #{line.strip}"
|
|
336
|
+
end
|
|
337
|
+
next
|
|
338
|
+
end
|
|
339
|
+
next unless !cells.any?(&:empty?) && cells[4] != "---" && cells[1] != "Downstream owner"
|
|
340
|
+
status = cells[3].delete("`").strip
|
|
341
|
+
next unless status.match?(/\A(updated|unchanged|routed|not-applicable)\z/)
|
|
342
|
+
rows << { line: line, status: status, evidence: cells[4], behavior: cells[2], scope: round_scope }
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
# A row counts only if it SURVIVES at HEAD. Round scoping alone would accept a
|
|
346
|
+
# row added in one round and deleted in a later one: the cumulative read this
|
|
347
|
+
# replaces saw that as a net zero and failed closed, and losing it would make
|
|
348
|
+
# "append the row, drop it next round" a laundering route. The ledger is
|
|
349
|
+
# append-only, so requiring survival costs an honest author nothing. A missing or
|
|
350
|
+
# undecodable register leaves the set empty and every subject falls through to
|
|
351
|
+
# the presence check, which fails closed.
|
|
352
|
+
# Survival is counted as a MULTISET, not a set. A boolean "this text exists at
|
|
353
|
+
# HEAD" is forgeable when the text ALREADY existed at base: append a duplicate in
|
|
354
|
+
# the round that needs a row, drop one copy in a later ledger-only round, and the
|
|
355
|
+
# ledger ends byte-identical while the transient row still reads as surviving.
|
|
356
|
+
# The budget is therefore how many occurrences the round span ADDED — HEAD's count
|
|
357
|
+
# minus base's — and each accepted row consumes one. That also subsumes the
|
|
358
|
+
# first-round-wins rule: a text re-added by a later round finds the budget spent,
|
|
359
|
+
# so an old row's verdict is never re-litigated against a newer round.
|
|
360
|
+
register_row_counts = lambda do |ref|
|
|
361
|
+
bytes = raw_blob_at.call(ref, LEDGER_PATH).to_s.dup.force_encoding(Encoding::UTF_8)
|
|
362
|
+
next Hash.new(0) unless bytes.valid_encoding?
|
|
363
|
+
bytes.lines.each_with_object(Hash.new(0)) { |l, counts| counts[l.strip] += 1 }
|
|
364
|
+
end
|
|
365
|
+
base_row_counts = register_row_counts.call(base_ref)
|
|
366
|
+
head_row_counts = register_row_counts.call("HEAD")
|
|
367
|
+
row_budget = Hash.new(0)
|
|
368
|
+
head_row_counts.each { |text, count| row_budget[text] = count - base_row_counts[text] }
|
|
369
|
+
rows.select! do |row|
|
|
370
|
+
key = row[:line].sub(/\A\+/, "").strip
|
|
371
|
+
next false unless row_budget[key].positive?
|
|
372
|
+
row_budget[key] -= 1
|
|
373
|
+
true
|
|
374
|
+
end
|
|
375
|
+
bad_evidence_files = []
|
|
376
|
+
ambiguous_evidence_rows = []
|
|
377
|
+
evidence_rows_by_upstream_path = Hash.new(0)
|
|
378
|
+
rows_by_upstream_path = Hash.new { |h, k| h[k] = [] }
|
|
379
|
+
declared_in_round = {}
|
|
380
|
+
upstream_set = upstream.to_h { |path| [path, true] }
|
|
381
|
+
# Selected-owner rename LINEAGE. A transient intermediate name — X renamed to
|
|
382
|
+
# Y in one round, Y to Z in a later one — appears in neither the cumulative
|
|
383
|
+
# diff (which pairs X with Z directly) nor the excused set, yet a round that
|
|
384
|
+
# substantively changed Y owes its row like any other selected owner (both
|
|
385
|
+
# review lanes independently found this laundering path). Walk the rounds in
|
|
386
|
+
# order and propagate selection through each round's OWN rename pairs; every
|
|
387
|
+
# name reached this way is treated exactly like the directly-excused source
|
|
388
|
+
# name: demanded and recognized wherever it exists at a round head. Pairs come
|
|
389
|
+
# from git per span, never from an author declaration, and a name outside the
|
|
390
|
+
# selected lineage can never join, so this only ever adds obligations.
|
|
391
|
+
lineage_extra = rename_excused.dup
|
|
392
|
+
round_bounds.each do |span_base, span_head|
|
|
393
|
+
scope_at.call(span_base, span_head).rename_pairs.each do |from_owner, to_owner|
|
|
394
|
+
from_path = "#{from_owner}/SKILL.md"
|
|
395
|
+
to_path = "#{to_owner}/SKILL.md"
|
|
396
|
+
next unless upstream_set[from_path] || lineage_extra[from_path]
|
|
397
|
+
lineage_extra[to_path] = true unless upstream_set[to_path]
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
# One round's subject set: the same normalization the cumulative pass uses,
|
|
401
|
+
# intersected with the cumulative selection — so a round can never demand a row
|
|
402
|
+
# for an owner the curated-list filter never picked. A lineage name (the
|
|
403
|
+
# rename-excused source or a transient intermediate hop) is admitted for
|
|
404
|
+
# exactly the rounds where its SKILL.md still exists at the round head: those
|
|
405
|
+
# rounds' rows cite a name that was real when the round landed and stays
|
|
406
|
+
# checkable against that round's head. In the round that renames it away the
|
|
407
|
+
# SKILL.md is gone at the head, so the old name is not demanded there and the
|
|
408
|
+
# successor carries that round's declaration — which is the whole cumulative
|
|
409
|
+
# excuse, now scoped to the one round it is sound for. A DELETED owner was
|
|
410
|
+
# never excused and is unaffected.
|
|
411
|
+
upstream_for_round = lambda do |scope|
|
|
412
|
+
scope.changed_paths.filter_map do |path|
|
|
413
|
+
next nil if path == LEDGER_PATH
|
|
414
|
+
m = path.match(%r{\Askills/([^/]+)/.+\z}m)
|
|
415
|
+
"#{m[1]}/SKILL.md" if m
|
|
416
|
+
end.uniq.select do |candidate|
|
|
417
|
+
next false unless upstream_set[candidate] || lineage_extra[candidate]
|
|
418
|
+
next true if regular_blob_at.call(scope.head, "skills/#{candidate}")
|
|
419
|
+
# Absent at this round's head. The demand is suppressed ONLY when this
|
|
420
|
+
# round's own git-verified pairs rename the name to a SELECTED successor —
|
|
421
|
+
# that successor carries this round's declaration, and a rename CYCLE
|
|
422
|
+
# (A to B, then B back to A) stays fully declarable without ever asking
|
|
423
|
+
# for a row the evidence check must refuse. Everything else stays
|
|
424
|
+
# demanded: a deletion has no pair and fails closed, and a rename to an
|
|
425
|
+
# unselected slug keeps the curated source bound as the named subject.
|
|
426
|
+
owner = candidate.sub(%r{/SKILL\.md\z}, "")
|
|
427
|
+
destination = scope.rename_pairs[owner]
|
|
428
|
+
!(destination && selectable_path.call("#{destination}/SKILL.md"))
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
rows.each do |row|
|
|
432
|
+
paths = row[:evidence].scan(/(?<![\w\/.-])([a-z][a-z0-9_-]+\/SKILL\.md)(?![\w\/.-])/).flatten.uniq
|
|
433
|
+
# A lineage name's rows are recognized as declarations, matching the
|
|
434
|
+
# per-round subject set above — demanding a row the mapping then ignored
|
|
435
|
+
# would be the same contradiction the excuse used to justify.
|
|
436
|
+
upstream_paths_in_row = paths.select { |path| upstream_set[path] || lineage_extra[path] }
|
|
437
|
+
if upstream_paths_in_row.length > 1
|
|
438
|
+
ambiguous_evidence_rows << { line: row[:line].sub(/^\+/, "").strip, paths: upstream_paths_in_row }
|
|
439
|
+
end
|
|
440
|
+
if upstream_paths_in_row.length == 1
|
|
441
|
+
evidence_rows_by_upstream_path[upstream_paths_in_row.first] += 1
|
|
442
|
+
rows_by_upstream_path[upstream_paths_in_row.first] << row
|
|
443
|
+
declared_in_round[[row[:scope].base, row[:scope].head, upstream_paths_in_row.first]] = true
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
unless ambiguous_evidence_rows.empty?
|
|
447
|
+
warn "impact_chain_row_ambiguous: source-register evidence row cites multiple changed upstream SKILL.md paths; split into one row per changed upstream SKILL.md"
|
|
448
|
+
ambiguous_evidence_rows.each do |row|
|
|
449
|
+
warn " paths: #{row[:paths].join(", ")}"
|
|
450
|
+
warn " row: #{row[:line]}"
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
# Existence is checked against the ROW'S OWN ROUND HEAD, not the working tree.
|
|
454
|
+
# A row is authored against one round's diff, so the name it cites only has to
|
|
455
|
+
# be real when that round landed: reading the working tree instead made a later
|
|
456
|
+
# rename retroactively invalidate honest pre-rename rows — and that impossible
|
|
457
|
+
# row was the stated excuse for dropping renamed-away owners from every round's
|
|
458
|
+
# subject set, which let their pre-rename work escape undeclared. A row citing
|
|
459
|
+
# a name its own round never had stays rejected.
|
|
460
|
+
rows.each do |row|
|
|
461
|
+
row[:evidence].scan(/(?<![\w\/.-])([a-z][a-z0-9_-]+\/SKILL\.md)(?![\w\/.-])/).flatten.each do |path|
|
|
462
|
+
bad_evidence_files << path unless regular_blob_at.call(row[:scope].head, "skills/#{path}")
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
if bad_evidence_files.any?
|
|
466
|
+
warn "impact_chain_evidence_missing_file: evidence cites a SKILL.md missing at its round head"
|
|
467
|
+
bad_evidence_files.uniq.each { |path| warn " missing: #{path}" }
|
|
468
|
+
exit 1
|
|
469
|
+
end
|
|
470
|
+
# Presence is checked PER ROUND, not across the range. Cumulative presence let
|
|
471
|
+
# owner work committed after a ledger append ride on an EARLIER round's row —
|
|
472
|
+
# the row said nothing about those bytes. Now that classification is round-scoped
|
|
473
|
+
# this is the matching obligation on the other side: the round that changed an
|
|
474
|
+
# owner is the round that owes the row. Work and its ledger append land in the
|
|
475
|
+
# same round whenever no other append separates them, so the ordinary
|
|
476
|
+
# "commit the change, then append the row" shape is unaffected.
|
|
477
|
+
missing_paths = round_bounds.flat_map do |span_base, span_head|
|
|
478
|
+
round_scope = scope_at.call(span_base, span_head)
|
|
479
|
+
upstream_for_round.call(round_scope).reject do |path|
|
|
480
|
+
declared_in_round[[span_base, span_head, path]]
|
|
481
|
+
end
|
|
482
|
+
end.uniq
|
|
483
|
+
unless missing_paths.empty?
|
|
484
|
+
warn "impact_chain_gate_missing: upstream-owner skill changed without a matching source-register impact-chain row"
|
|
485
|
+
warn " note: for an upstream owner, its references/ and scripts/ count as a change too (they ship decision-surface/operational behavior); cite the owning <skill>/SKILL.md in the row evidence cell"
|
|
486
|
+
warn " fix: add one row per changed upstream owner in skill-extraction-workflow/references/source-register.md"
|
|
487
|
+
warn " row shape: | <upstream rule> | `<downstream owner>` | <expected executable behavior> | `updated|unchanged|routed|not-applicable` | <owning `<skill>/SKILL.md` is the machine key; add any changed reference/script path as supporting evidence> | (escape any literal pipe inside a cell as backslash-pipe)"
|
|
488
|
+
upstream.each { |path| warn " changed: #{path}" }
|
|
489
|
+
missing_paths.each { |path| warn " missing evidence path: #{path}" }
|
|
490
|
+
exit 1
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# A matching owner path proves only that a ledger row exists. It does not
|
|
494
|
+
# prove the changed rule can fire, or that an observed failure now has a
|
|
495
|
+
# firing path. Require the behavioral-evidence declaration and firing path in
|
|
496
|
+
# the SAME added row so a content-only "already covered" disposition cannot
|
|
497
|
+
# satisfy the impact-chain gate. Intentionally diff-scoped: historical rows
|
|
498
|
+
# are not retrofitted.
|
|
499
|
+
behavior_failures = []
|
|
500
|
+
firing_path_failures = []
|
|
501
|
+
# Lazily computed and memoized per owner: most rows are RED-baseline /
|
|
502
|
+
# semantic-control and never consult the wording-only classification, so the
|
|
503
|
+
# per-owner diff subprocess only runs when a row actually declares
|
|
504
|
+
# `not-required wording-only` (or the owner-level RED floor needs it).
|
|
505
|
+
wording_only_diff_cache = {}
|
|
506
|
+
wording_only_diff_for = lambda do |scope, path|
|
|
507
|
+
cache_key = [scope.base, scope.head, path]
|
|
508
|
+
return wording_only_diff_cache[cache_key] if wording_only_diff_cache.key?(cache_key)
|
|
509
|
+
owner = path.sub(%r{/SKILL\.md\z}, "")
|
|
510
|
+
# The letters/digits bar is a PROSE heuristic: in runnable content,
|
|
511
|
+
# punctuation-only edits (`:` -> `! :`, a deleted `)`) change behavior.
|
|
512
|
+
# The class therefore applies only when EVERY changed owner file is
|
|
513
|
+
# Markdown prose; any non-.md file (script, runnable reference, overlay)
|
|
514
|
+
# disqualifies it outright.
|
|
515
|
+
non_prose_changed = scope.changed_paths.any? do |changed|
|
|
516
|
+
next false unless changed.start_with?("skills/#{owner}/")
|
|
517
|
+
next false if changed == LEDGER_PATH
|
|
518
|
+
changed.start_with?("skills/#{owner}/scripts/") || !changed.end_with?(".md")
|
|
519
|
+
end
|
|
520
|
+
owner_diff = git_read.call("diff", "--no-ext-diff", "--unified=0", scope.base, scope.head, "--",
|
|
521
|
+
"skills/#{owner}", ":(exclude)#{LEDGER_PATH}")
|
|
522
|
+
changed_content = owner_diff.lines.filter_map do |line|
|
|
523
|
+
next if line.start_with?("+++", "---")
|
|
524
|
+
line[1..] if line.start_with?("+", "-")
|
|
525
|
+
end
|
|
526
|
+
wording_only_diff_cache[cache_key] = !non_prose_changed && !changed_content.empty? && changed_content.none? { |line| line.match?(/[\p{L}\p{N}]/) }
|
|
527
|
+
end
|
|
528
|
+
# Rename pairs come from git's own tree state — which owner packages
|
|
529
|
+
# disappeared and which appeared — never from an author declaration. How the
|
|
530
|
+
# pairs are derived does not have to be trustworthy, because a wrong pair can
|
|
531
|
+
# only make the reproduction below fail: the class is granted solely when
|
|
532
|
+
# rewriting the BASE bytes with the pairs reproduces the HEAD bytes exactly,
|
|
533
|
+
# so smuggled content of any size breaks equality and falls back to the normal
|
|
534
|
+
# evidence bar. Every derivation error is therefore strictly conservative.
|
|
535
|
+
# This is not the baseline-nomination mechanism removed from the size budget:
|
|
536
|
+
# nothing here lets a diff be measured against a DIFFERENT file — the
|
|
537
|
+
# comparison is always the same path against a mechanical transform of itself.
|
|
538
|
+
# `rename_pairs` / `rename_pattern` are computed before the subject filter above,
|
|
539
|
+
# which needs them to tell a rename apart from a deletion.
|
|
540
|
+
# Named apart from the `blob_at` defined further down: that one returns entry
|
|
541
|
+
# metadata for the firing-path anchors, and sharing the name would silently
|
|
542
|
+
# rebind this closure to it.
|
|
543
|
+
identifier_rename_cache = {}
|
|
544
|
+
identifier_rename_diff_for = lambda do |scope, path|
|
|
545
|
+
cache_key = [scope.base, scope.head, path]
|
|
546
|
+
return identifier_rename_cache[cache_key] if identifier_rename_cache.key?(cache_key)
|
|
547
|
+
owner = path.sub(%r{/SKILL\.md\z}, "")
|
|
548
|
+
identifier_rename_cache[cache_key] = begin
|
|
549
|
+
# The class is for owners that merely RETARGET a pointer. The renamed owner
|
|
550
|
+
# itself never qualifies: its package bytes may reproduce, but the name is
|
|
551
|
+
# how hosts and callers resolve it, so changing it IS the behaviour change —
|
|
552
|
+
# every caller still saying the old name now resolves to nothing. A
|
|
553
|
+
# destination therefore owes the normal RED evidence and firing path, the
|
|
554
|
+
# same bar its own rename record has to meet.
|
|
555
|
+
if scope.rename_pattern.nil? || scope.rename_pairs.value?(owner)
|
|
556
|
+
false
|
|
557
|
+
else
|
|
558
|
+
owner_changed = scope.changed_paths.select do |changed|
|
|
559
|
+
changed.start_with?("skills/#{owner}/") && changed != LEDGER_PATH
|
|
560
|
+
end
|
|
561
|
+
source_owner = scope.rename_pairs.key(owner)
|
|
562
|
+
!owner_changed.empty? && package_reproduces.call(scope, source_owner || owner, owner)
|
|
563
|
+
end
|
|
564
|
+
end
|
|
565
|
+
end
|
|
566
|
+
# A routing-surface-only change edits the frontmatter `description` and nothing
|
|
567
|
+
# else. The firing path must anchor on a CHANGED numbered/list rule carrying a
|
|
568
|
+
# normative verb; a one-line YAML scalar is neither, so such an owner has no
|
|
569
|
+
# anchor to point at and would otherwise be forced to pad its body with a
|
|
570
|
+
# restatement purely to satisfy the anchor — on entrypoints that a separate
|
|
571
|
+
# zero-growth budget forbids from growing at all.
|
|
572
|
+
#
|
|
573
|
+
# The safety argument is the INVERSE of the identifier-rename class and has to
|
|
574
|
+
# be, because a wrong judgement here is LOOSER than the normal bar rather than
|
|
575
|
+
# stricter: nothing is derived or guessed, so there is no derivation that could
|
|
576
|
+
# err conservatively. Instead the class is granted only when the owner's whole
|
|
577
|
+
# change is accounted for byte-for-byte — one changed file, identical body,
|
|
578
|
+
# identical frontmatter apart from the single description entry. Every shape the
|
|
579
|
+
# split cannot fully account for refuses the class.
|
|
580
|
+
routing_surface_cache = {}
|
|
581
|
+
# The file MODE is part of the entrypoint's identity, exactly as it is for the
|
|
582
|
+
# package comparison above: bytes alone would let `chmod +x` on SKILL.md ride
|
|
583
|
+
# along with a description edit and still read as description-only.
|
|
584
|
+
entry_mode = lambda do |ref, relative|
|
|
585
|
+
out = IO.popen(["git", "-C", root, "ls-tree", "-z", ref, "--", relative], err: File::NULL, &:read)
|
|
586
|
+
next nil unless $?.success?
|
|
587
|
+
entry = out.split("\0").reject(&:empty?).first
|
|
588
|
+
entry && entry.split(/\s+/, 2).first
|
|
589
|
+
end
|
|
590
|
+
# "---\n<frontmatter>\n---\n<body>" -> [frontmatter, body] as BYTES, or nil when
|
|
591
|
+
# the delimiters are not exactly where the format requires.
|
|
592
|
+
split_frontmatter = lambda do |bytes|
|
|
593
|
+
m = bytes.match(/\A---\n(.*?\n)---\n/m)
|
|
594
|
+
next nil unless m
|
|
595
|
+
[m[1], m.post_match]
|
|
596
|
+
end
|
|
597
|
+
# Split the frontmatter into [everything that is not the description entry, the
|
|
598
|
+
# description entry itself]. The entry is its `description:` line plus any
|
|
599
|
+
# indented continuation lines, so a block or folded scalar is one entry rather
|
|
600
|
+
# than a first line and some orphans. Absent or repeated keys return nil, which
|
|
601
|
+
# refuses the class rather than picking one.
|
|
602
|
+
split_description_entry = lambda do |frontmatter|
|
|
603
|
+
lines = frontmatter.lines
|
|
604
|
+
# YAML allows the key quoted or spaced before the colon; refusing those forms
|
|
605
|
+
# would block a legitimate description-only change with no satisfiable anchor.
|
|
606
|
+
key = /\A(?:"description"|'description'|description)[ \t]*:/
|
|
607
|
+
starts = lines.each_index.select { |i| lines[i].match?(key) }
|
|
608
|
+
next nil unless starts.length == 1
|
|
609
|
+
first = starts.first
|
|
610
|
+
# The entry runs to the next TOP-LEVEL key, not to the first unindented line:
|
|
611
|
+
# a folded scalar may contain blank lines between paragraphs, and stopping at
|
|
612
|
+
# one would move the later paragraphs into the "other keys" set and refuse a
|
|
613
|
+
# perfectly ordinary description edit. Indentation is a shape proxy; "where the
|
|
614
|
+
# next top-level key starts" is the structure YAML itself uses.
|
|
615
|
+
last = first + 1
|
|
616
|
+
last += 1 while last < lines.length && !lines[last].match?(/\A\S/)
|
|
617
|
+
[lines[0...first] + lines[last..], lines[first...last]]
|
|
618
|
+
end
|
|
619
|
+
# Whatever the line split decides, the value must still BE a description: a
|
|
620
|
+
# string. Widening the entry to the next top-level key means a nested mapping
|
|
621
|
+
# (`description:` followed by indented `key: value` pairs) would otherwise ride
|
|
622
|
+
# inside the entry, letting arbitrary frontmatter through and even carrying the
|
|
623
|
+
# anchor. Parsing settles it with the format's own rules rather than another
|
|
624
|
+
# shape heuristic; anything that fails to parse, or whose description is not a
|
|
625
|
+
# string, refuses the class.
|
|
626
|
+
# Whatever the line split decides, the value must still BE a description: a
|
|
627
|
+
# string. Widening the entry to the next top-level key means a nested mapping
|
|
628
|
+
# (`description:` followed by indented `key: value` pairs) would otherwise ride
|
|
629
|
+
# inside the entry, letting arbitrary frontmatter through and even carrying the
|
|
630
|
+
# locator. Parse ONLY the entry, never the whole frontmatter: a sibling key that
|
|
631
|
+
# deserializes to a Date or uses an alias makes `safe_load` raise, and rescuing
|
|
632
|
+
# that to nil would refuse a legitimate owner for a key this class does not care
|
|
633
|
+
# about. Anything that still fails to parse, or whose description is not a
|
|
634
|
+
# string, refuses the class.
|
|
635
|
+
description_is_scalar = lambda do |frontmatter|
|
|
636
|
+
text = frontmatter.dup.force_encoding(Encoding::UTF_8)
|
|
637
|
+
next false unless text.valid_encoding?
|
|
638
|
+
parsed = begin
|
|
639
|
+
YAML.safe_load(text, permitted_classes: [Date, Time], aliases: true)
|
|
640
|
+
rescue StandardError
|
|
641
|
+
nil
|
|
642
|
+
end
|
|
643
|
+
parsed.is_a?(Hash) && parsed["description"].is_a?(String)
|
|
644
|
+
end
|
|
645
|
+
routing_surface_diff_for = lambda do |scope, path|
|
|
646
|
+
cache_key = [scope.base, scope.head, path]
|
|
647
|
+
return routing_surface_cache[cache_key] if routing_surface_cache.key?(cache_key)
|
|
648
|
+
owner = path.sub(%r{/SKILL\.md\z}, "")
|
|
649
|
+
routing_surface_cache[cache_key] = begin
|
|
650
|
+
# NO register exclusion here, unlike the classifiers above. The ledger lives
|
|
651
|
+
# inside one owner's package, and for that owner "the entire change is the
|
|
652
|
+
# description" would otherwise be satisfiable while arbitrary normative
|
|
653
|
+
# ledger content rode along. Dropping the exclusion costs the other owners
|
|
654
|
+
# nothing (the ledger is not under their package) and correctly makes the
|
|
655
|
+
# class unavailable to the owner that ships it.
|
|
656
|
+
owner_changed = scope.changed_paths.select { |changed| changed.start_with?("skills/#{owner}/") }
|
|
657
|
+
entrypoint = "skills/#{owner}/SKILL.md"
|
|
658
|
+
# The rest of the package may differ ONLY by a rename retarget — the same
|
|
659
|
+
# class the gate already machine-proves carries no obligation. This tolerance
|
|
660
|
+
# was added when the classifier still read the whole accumulating range and an
|
|
661
|
+
# owner whose only behaviour was its description got refused for retargets
|
|
662
|
+
# already declared no-behaviour; the round scoping now removes that pressure
|
|
663
|
+
# at the source, and the tolerance stays only because a retarget landing in
|
|
664
|
+
# the SAME round is still genuinely no-behaviour. The bound is the identical
|
|
665
|
+
# byte-exact reproduction used there: apply git's own rename pairs to the base
|
|
666
|
+
# bytes and require the head bytes exactly, mode included. A file that cannot
|
|
667
|
+
# be accounted for that way — one real byte of content — takes the locator away.
|
|
668
|
+
# One normalizer for both halves: the entrypoint's own body and non-description
|
|
669
|
+
# keys mention renamed slugs too, so comparing them raw would refuse the very
|
|
670
|
+
# shape this composition exists for. The description entry is exempt because
|
|
671
|
+
# it is the change being evidenced.
|
|
672
|
+
retarget = lambda do |bytes|
|
|
673
|
+
next bytes unless scope.rename_pattern
|
|
674
|
+
bytes.gsub(scope.rename_pattern) { |hit| scope.rename_pairs.fetch(hit).dup.force_encoding(Encoding::BINARY) }
|
|
675
|
+
end
|
|
676
|
+
others_reproduce = (owner_changed - [entrypoint]).all? do |other|
|
|
677
|
+
# Prose only, for the same reason the wording-only class refuses non-.md
|
|
678
|
+
# files: a substitution reproducing a SCRIPT's bytes says nothing about
|
|
679
|
+
# whether rewriting that identifier was safe there. Some occurrences of an
|
|
680
|
+
# old slug are deliberately kept — a persisted key, an uninstall manifest —
|
|
681
|
+
# and rewriting one is a behaviour change the normalizer would wave through.
|
|
682
|
+
next false if other.start_with?("skills/#{owner}/scripts/") || !other.end_with?(".md")
|
|
683
|
+
# Regular files only, on BOTH sides. A symlink's blob is its TARGET, so a
|
|
684
|
+
# `.md` symlink whose target carries an old slug reproduces under the
|
|
685
|
+
# substitution while what the path resolves to changes — a filesystem
|
|
686
|
+
# behaviour the normalizer has no business clearing. Same for a mode flip.
|
|
687
|
+
next false unless entry_mode.call(scope.base, other) == "100644"
|
|
688
|
+
next false unless entry_mode.call(scope.head, other) == "100644"
|
|
689
|
+
base_bytes = raw_blob_at.call(scope.base, other)
|
|
690
|
+
head_bytes = raw_blob_at.call(scope.head, other)
|
|
691
|
+
next false if base_bytes.nil? || head_bytes.nil?
|
|
692
|
+
retarget.call(base_bytes) == head_bytes
|
|
693
|
+
end
|
|
694
|
+
if !owner_changed.include?(entrypoint) || !others_reproduce
|
|
695
|
+
false
|
|
696
|
+
else
|
|
697
|
+
# `path` is owner-relative in this loop; blob reads need the repo path.
|
|
698
|
+
base_bytes = raw_blob_at.call(scope.base, entrypoint)
|
|
699
|
+
head_bytes = raw_blob_at.call(scope.head, entrypoint)
|
|
700
|
+
base_parts = base_bytes && split_frontmatter.call(base_bytes)
|
|
701
|
+
head_parts = head_bytes && split_frontmatter.call(head_bytes)
|
|
702
|
+
if base_parts.nil? || head_parts.nil?
|
|
703
|
+
false
|
|
704
|
+
else
|
|
705
|
+
base_split = split_description_entry.call(base_parts[0])
|
|
706
|
+
head_split = split_description_entry.call(head_parts[0])
|
|
707
|
+
!base_split.nil? && !head_split.nil? &&
|
|
708
|
+
base_split[0].map { |l| retarget.call(l) } == head_split[0] &&
|
|
709
|
+
retarget.call(base_parts[1]) == head_parts[1] &&
|
|
710
|
+
base_split[1].map { |l| retarget.call(l) } != head_split[1] &&
|
|
711
|
+
description_is_scalar.call(base_parts[0]) && description_is_scalar.call(head_parts[0]) &&
|
|
712
|
+
entry_mode.call(scope.base, entrypoint) == entry_mode.call(scope.head, entrypoint) &&
|
|
713
|
+
!entry_mode.call(scope.head, entrypoint).nil?
|
|
714
|
+
end
|
|
715
|
+
end
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
added_lines_cache = {}
|
|
719
|
+
added_lines_for = lambda do |scope, relative|
|
|
720
|
+
rel = relative.to_s.strip
|
|
721
|
+
added_lines_cache[[scope.base, scope.head, rel]] ||=
|
|
722
|
+
git_read.call("diff", "--no-ext-diff", "--unified=0", scope.base, scope.head, "--", rel).lines.filter_map do |line|
|
|
723
|
+
next if line.start_with?("+++")
|
|
724
|
+
line[1..]&.chomp if line.start_with?("+")
|
|
725
|
+
end
|
|
726
|
+
end
|
|
727
|
+
# Raw tree entry at a path (memoized, including nil): `mode type oid\tpath`,
|
|
728
|
+
# or nil when no entry of ANY type exists. `-z` keeps the path raw so entries
|
|
729
|
+
# for paths with unusual bytes still compare equal to the requested rel
|
|
730
|
+
# instead of failing on git's line-oriented quoting.
|
|
731
|
+
tree_entry_cache = {}
|
|
732
|
+
tree_entry_at = lambda do |treeish, relative|
|
|
733
|
+
rel = relative.to_s.strip
|
|
734
|
+
next nil if rel.empty? || rel.start_with?("/") || rel.include?(":") || rel.split("/").include?("..")
|
|
735
|
+
key = [treeish, rel]
|
|
736
|
+
next tree_entry_cache[key] if tree_entry_cache.key?(key)
|
|
737
|
+
entry = IO.popen(["git", "-C", root, "ls-tree", "-z", treeish, "--", rel], &:read).split("\0").first.to_s
|
|
738
|
+
tree_entry_cache[key] = entry.empty? ? nil : entry
|
|
739
|
+
end
|
|
740
|
+
# Memoized (including nil results): the same (treeish, path) blob can be
|
|
741
|
+
# fetched by several locator checks; without the cache each fetch costs git
|
|
742
|
+
# subprocesses. Only a regular blob (100644/100755) resolves; symlinks,
|
|
743
|
+
# submodules, and trees return nil.
|
|
744
|
+
blob_cache = {}
|
|
745
|
+
blob_at = lambda do |treeish, relative|
|
|
746
|
+
rel = relative.to_s.strip
|
|
747
|
+
key = [treeish, rel]
|
|
748
|
+
next blob_cache[key] if blob_cache.key?(key)
|
|
749
|
+
entry = tree_entry_at.call(treeish, rel)
|
|
750
|
+
blob_cache[key] = if entry
|
|
751
|
+
meta, listed = entry.split("\t", 2)
|
|
752
|
+
mode, type, _oid = meta.to_s.split(/\s+/, 3)
|
|
753
|
+
if %w[100644 100755].include?(mode) && type == "blob" && listed == rel
|
|
754
|
+
content = IO.popen(["git", "-C", root, "show", "#{treeish}:#{rel}"], &:read)
|
|
755
|
+
{ path: rel, mode: mode, content: content }
|
|
756
|
+
end
|
|
757
|
+
end
|
|
758
|
+
end
|
|
759
|
+
# The locator must resolve in the round's own head, not the branch tip: a later
|
|
760
|
+
# round that deletes or rewrites the anchored file must not retroactively
|
|
761
|
+
# invalidate — or silently re-validate — an earlier round's locator.
|
|
762
|
+
head_blob = ->(scope, relative) { blob_at.call(scope.head, relative) }
|
|
763
|
+
locator_parts = lambda do |raw|
|
|
764
|
+
locator = raw.to_s.strip
|
|
765
|
+
if (m = locator.match(/\Acommand:([^\s;]+)\z/))
|
|
766
|
+
{ kind: "command", path: m[1] }
|
|
767
|
+
elsif (m = locator.match(/\Afile:([^#\s;]+)#(.+)\z/))
|
|
768
|
+
anchor = m[2].strip
|
|
769
|
+
{ kind: "file", path: m[1], anchor: anchor } unless anchor.empty?
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
locator_valid = lambda do |scope, raw|
|
|
773
|
+
parts = locator_parts.call(raw)
|
|
774
|
+
next false unless parts
|
|
775
|
+
blob = head_blob.call(scope, parts[:path])
|
|
776
|
+
added = added_lines_for.call(scope, parts[:path])
|
|
777
|
+
next false unless blob && !added.empty?
|
|
778
|
+
if parts[:kind] == "command"
|
|
779
|
+
# An executable firing surface must actually be a script: mode 100755
|
|
780
|
+
# AND a shebang. Without this, any changed file with the executable bit
|
|
781
|
+
# (even a chmod'ed Markdown file) satisfies a command locator.
|
|
782
|
+
blob[:mode] == "100755" && blob[:content].start_with?("#!")
|
|
783
|
+
else
|
|
784
|
+
anchor = parts[:anchor]
|
|
785
|
+
anchor.length >= 16 &&
|
|
786
|
+
added.count { |line| line.include?(anchor) } == 1 &&
|
|
787
|
+
blob[:content].scan(Regexp.new(Regexp.escape(anchor))).length == 1
|
|
788
|
+
end
|
|
789
|
+
end
|
|
790
|
+
enforcing_file_locator_valid = lambda do |scope, parts|
|
|
791
|
+
next false unless parts && parts[:kind] == "file"
|
|
792
|
+
next false unless parts[:path].end_with?(".md")
|
|
793
|
+
next false unless locator_valid.call(scope, "file:#{parts[:path]}##{parts[:anchor]}")
|
|
794
|
+
line = added_lines_for.call(scope, parts[:path]).find { |added| added.include?(parts[:anchor]) }
|
|
795
|
+
next false unless line
|
|
796
|
+
# A non-rendered HTML comment can smuggle normative vocabulary past the
|
|
797
|
+
# heuristic (`- <!-- must ... -->`); an anchor line carrying a comment
|
|
798
|
+
# marker is never an enforcing rule surface.
|
|
799
|
+
next false if line.include?("<!--")
|
|
800
|
+
list_rule = line.lstrip.match?(/\A(?:[-*+]\s+|\d+[.)]\s+)/)
|
|
801
|
+
# Normative-action vocabulary. This is a recall heuristic, not a semantic
|
|
802
|
+
# parser: it accepts common imperative/prohibitive phrasings in English and
|
|
803
|
+
# Chinese (never/do not/应当/务必/不能 included so a genuinely normative
|
|
804
|
+
# rule is not rejected for its verb choice) while still refusing anchors on
|
|
805
|
+
# purely descriptive prose. Deliberately excluded for precision: "always"
|
|
806
|
+
# and "does not" (dominant descriptive uses — "the host always exposes",
|
|
807
|
+
# "the adapter does not support"), and single characters with broad
|
|
808
|
+
# compounds (应/只/别 — 应用/只是/区别).
|
|
809
|
+
normative = line.match?(/(?:\b(?:must|shall|never|do\s+not|don'?t|required?|requires?|block(?:s|ed)?|reject(?:s|ed)?|deny|denied|invalidates?|forbid(?:s|den)?|cannot|enforcement)\b|必须|不得|禁止|拒绝|作废|仅限|只能|应当|应该|务必|不能|不允许|不可)/i)
|
|
810
|
+
list_rule && normative
|
|
811
|
+
end
|
|
812
|
+
# A routing-surface-only owner has no changed rule line to anchor on: its whole
|
|
813
|
+
# change is one YAML scalar. The answer is NOT to exempt it — a description edit
|
|
814
|
+
# IS a routing behaviour change (it decides which requests reach the skill), so
|
|
815
|
+
# exempting it would drop the evidence requirement from the class that carries
|
|
816
|
+
# the most behaviour, and its evidence exists anyway as a measured routing delta.
|
|
817
|
+
# Instead the anchor may land on the changed description entry itself. Every other
|
|
818
|
+
# requirement is unchanged — owner-scoped path, minimum length, unique in the
|
|
819
|
+
# file, present in this diff's added lines — and only the "numbered/list rule with
|
|
820
|
+
# a normative verb" SHAPE is lifted, because a YAML scalar can never take it.
|
|
821
|
+
# The widening is bounded by the same byte-exact predicate: an owner that changed
|
|
822
|
+
# anything besides the description keeps the ordinary anchor bar.
|
|
823
|
+
routing_surface_anchor_valid = lambda do |scope, parts, owner|
|
|
824
|
+
next false unless parts[:kind] == "file"
|
|
825
|
+
next false unless parts[:path] == "skills/#{owner}/SKILL.md"
|
|
826
|
+
# A CANONICAL FIELD LOCATOR, not a text search. Three designs tried to make a
|
|
827
|
+
# substring anchor prove which bytes changed — a numbered/list rule shape, then
|
|
828
|
+
# the `description:` line, then any line of the entry — and each was refuted in
|
|
829
|
+
# turn, the last because a substring that merely SURVIVES the edit identifies
|
|
830
|
+
# nothing. Same class three times is the signal to drop the proxy rather than
|
|
831
|
+
# patch it again: the predicate below already proves the entire owner diff IS
|
|
832
|
+
# the description entry, so the locator's only job is to name that field. The
|
|
833
|
+
# length/uniqueness rules that guard a free-text anchor have nothing to guard
|
|
834
|
+
# here, and applying them to a constant would be ceremony dressed as evidence.
|
|
835
|
+
next false unless parts[:anchor] == "description"
|
|
836
|
+
routing_surface_diff_for.call(scope, "#{owner}/SKILL.md")
|
|
837
|
+
end
|
|
838
|
+
firing_locator_valid = lambda do |scope, parts, owner|
|
|
839
|
+
next false unless parts && parts[:path].start_with?("skills/#{owner}/")
|
|
840
|
+
if parts[:kind] == "command"
|
|
841
|
+
locator_valid.call(scope, "command:#{parts[:path]}")
|
|
842
|
+
else
|
|
843
|
+
routing_surface_anchor_valid.call(scope, parts, owner) ||
|
|
844
|
+
enforcing_file_locator_valid.call(scope, parts)
|
|
845
|
+
end
|
|
846
|
+
end
|
|
847
|
+
# Lineage names join the walk: their recognized rows must clear the same
|
|
848
|
+
# behavior-evidence and firing-path bar as everyone else's (each row judged
|
|
849
|
+
# against its own round, where its anchors resolve), or the admission above
|
|
850
|
+
# would accept rows it never validates.
|
|
851
|
+
(upstream + lineage_extra.keys).each do |path|
|
|
852
|
+
owner_rows = rows_by_upstream_path[path]
|
|
853
|
+
next if owner_rows.empty? # reported by impact_chain_gate_missing above
|
|
854
|
+
owner = path.sub(%r{/SKILL\.md\z}, "")
|
|
855
|
+
|
|
856
|
+
# Parse and validate each row exactly once; both the pass/fail decision and
|
|
857
|
+
# the failure-bucket classification below consume these structs, so the row
|
|
858
|
+
# grammar lives in one place and a failing owner does not pay a second full
|
|
859
|
+
# validation walk (each walk costs git subprocesses via the blob lookups).
|
|
860
|
+
evaluated = owner_rows.map do |row|
|
|
861
|
+
# Every predicate below reads the row's OWN round. This is what makes a
|
|
862
|
+
# verdict stable: the span it is judged against is fixed when the row lands
|
|
863
|
+
# and cannot grow afterwards.
|
|
864
|
+
row_scope = row[:scope]
|
|
865
|
+
text = row[:behavior]
|
|
866
|
+
# Declarations parse from semicolon-delimited fragments, each field
|
|
867
|
+
# anchored at its fragment start: a key embedded mid-prose ("no
|
|
868
|
+
# behavioral-evidence: ...") or carrying a suffixed value never counts.
|
|
869
|
+
declarations = {}
|
|
870
|
+
text.split(";").each do |fragment|
|
|
871
|
+
if (m = fragment.match(/\A\s*(behavioral-evidence|observed-failure|firing-path):\s*(.+?)\s*\z/i))
|
|
872
|
+
declarations[m[1].downcase] ||= m[2]
|
|
873
|
+
end
|
|
874
|
+
end
|
|
875
|
+
status = declarations["behavioral-evidence"]&.[](/\A(RED-baseline|semantic-control|not-required\s+wording-only|not-required\s+identifier-rename)\z/i, 1)
|
|
876
|
+
normalized_status = status&.downcase&.gsub(/\s+/, " ")
|
|
877
|
+
declared_wording_only = normalized_status == "not-required wording-only"
|
|
878
|
+
wording_only = declared_wording_only && wording_only_diff_for.call(row_scope, path)
|
|
879
|
+
declared_identifier_rename = normalized_status == "not-required identifier-rename"
|
|
880
|
+
identifier_rename = declared_identifier_rename && identifier_rename_diff_for.call(row_scope, path)
|
|
881
|
+
# Both no-behavior classes are machine-verified, so they share a branch. A
|
|
882
|
+
# routing-surface-only change is NOT one of them: it carries behaviour, so it
|
|
883
|
+
# keeps the RED-baseline bar and only gains a place its anchor can bind.
|
|
884
|
+
no_behavior_class = wording_only || identifier_rename
|
|
885
|
+
observed = declarations["observed-failure"]&.[](/\A(yes|no)\z/i, 1)&.downcase
|
|
886
|
+
semantic_control = normalized_status == "semantic-control" && observed == "no"
|
|
887
|
+
status_allowed = no_behavior_class || normalized_status == "red-baseline" || semantic_control
|
|
888
|
+
firing_path = declarations["firing-path"]&.[](/\A((?:command|file):.+)\z/i, 1)&.strip
|
|
889
|
+
firing_parts = locator_parts.call(firing_path)
|
|
890
|
+
firing_path_valid = firing_locator_valid.call(row_scope, firing_parts, owner)
|
|
891
|
+
# The machine-checked core is the FIRING PATH (an owner-scoped anchor on a
|
|
892
|
+
# changed normative rule, or a changed owner executable) plus the
|
|
893
|
+
# deterministic wording-only classification. The behavioral-evidence
|
|
894
|
+
# status and observed-failure fields are required author declarations —
|
|
895
|
+
# honest labels, not digest-verified artifacts: a digest-bound evidence
|
|
896
|
+
# apparatus was evaluated here and removed because its per-iteration
|
|
897
|
+
# regeneration cost (full-suite reruns on every owner-script byte change)
|
|
898
|
+
# far outweighed the staleness detection it added under the
|
|
899
|
+
# unsigned-repository-local trust model.
|
|
900
|
+
row_valid = if no_behavior_class
|
|
901
|
+
# Neither `not-required` class is an author-controlled waiver: each is
|
|
902
|
+
# accepted only when the owner diff itself passes the matching
|
|
903
|
+
# deterministic classifier — letters/digits-free for wording-only,
|
|
904
|
+
# byte-exact reproduction under the git-derived rename pairs for
|
|
905
|
+
# identifier-rename. Both record no observed failure, and neither can
|
|
906
|
+
# carry a firing path, because a retarget changes no normative rule to
|
|
907
|
+
# anchor one on.
|
|
908
|
+
status_allowed && observed == "no"
|
|
909
|
+
else
|
|
910
|
+
status_allowed && firing_path_valid &&
|
|
911
|
+
(observed == "no" || (observed == "yes" && status&.casecmp?("RED-baseline")))
|
|
912
|
+
end
|
|
913
|
+
{
|
|
914
|
+
red_declared: normalized_status == "red-baseline",
|
|
915
|
+
row_valid: row_valid,
|
|
916
|
+
firing_path_valid: firing_path_valid
|
|
917
|
+
}
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
# A stable-control label can say one named behavior did not change, but it
|
|
921
|
+
# cannot vouch for the rest of a non-wording owner diff. Require at least
|
|
922
|
+
# one RED-baseline row per non-wording owner so a package cannot self-clear
|
|
923
|
+
# on semantic-control labels alone. The floor is lifted only for the two
|
|
924
|
+
# machine-verified no-behavior classes, whose whole point is that there is
|
|
925
|
+
# nothing left for a label to hide: an owner whose bytes are reproduced by
|
|
926
|
+
# rewriting identifiers has no unvouched-for remainder, so demanding an
|
|
927
|
+
# observed delta there would only be satisfiable by inventing one.
|
|
928
|
+
# The floor deliberately reads the CUMULATIVE diff, not a round. It asks
|
|
929
|
+
# whether anything in this owner's whole change is left unvouched-for, so
|
|
930
|
+
# narrowing it to one round would let a package self-clear on the one round
|
|
931
|
+
# that happened to be punctuation-only. Cumulative is the strictly stricter
|
|
932
|
+
# reading of the two, so the round scoping cannot loosen this floor.
|
|
933
|
+
valid = evaluated.all? { |entry| entry[:row_valid] }
|
|
934
|
+
valid &&= evaluated.any? { |entry| entry[:red_declared] } ||
|
|
935
|
+
wording_only_diff_for.call(cumulative, path) ||
|
|
936
|
+
identifier_rename_diff_for.call(cumulative, path)
|
|
937
|
+
next if valid
|
|
938
|
+
|
|
939
|
+
# Bucket the failure for the diagnostic: a declared RED row whose firing
|
|
940
|
+
# path is broken gets the firing-path message; every other failure shape
|
|
941
|
+
# gets the behavior-evidence message. (A declared wording-only row can
|
|
942
|
+
# never be a RED row, so no exclusion is needed here.)
|
|
943
|
+
firing_path_incomplete = evaluated.any? do |entry|
|
|
944
|
+
entry[:red_declared] && !entry[:firing_path_valid]
|
|
945
|
+
end
|
|
946
|
+
if firing_path_incomplete
|
|
947
|
+
firing_path_failures << path
|
|
948
|
+
else
|
|
949
|
+
behavior_failures << path
|
|
950
|
+
end
|
|
951
|
+
end
|
|
952
|
+
unless firing_path_failures.empty?
|
|
953
|
+
warn "impact_chain_firing_path_missing: RED-baseline row has no owner-scoped firing path in this committed diff"
|
|
954
|
+
warn " fix: point to this owner with `firing-path: command:<changed repo executable>` or `firing-path: file:<changed markdown>#<unique token on a changed numbered/list rule with a normative action>`"
|
|
955
|
+
firing_path_failures.each { |path| warn " incomplete: #{path}" }
|
|
956
|
+
exit 1
|
|
957
|
+
end
|
|
958
|
+
unless behavior_failures.empty?
|
|
959
|
+
warn "impact_chain_behavior_evidence_missing: at least one added upstream-owner row lacks a complete behavioral-evidence declaration"
|
|
960
|
+
warn " fix: every added row for a changed upstream owner needs `behavioral-evidence: RED-baseline` (observed deltas; observed-failure: yes requires it) or `semantic-control` (only with observed-failure: no), plus `observed-failure: yes/no` and an owner-scoped `firing-path:`; a non-wording owner package needs at least one RED-baseline row; only deterministically wording-only diffs (no letters or digits changed) may use `not-required wording-only`, and only diffs whose base bytes are reproduced exactly by applying git-derived skill-rename pairs may use `not-required identifier-rename` (both drop the firing-path requirement and require observed-failure: no); an owner whose ENTIRE change is the SKILL.md frontmatter description entry keeps the RED-baseline bar and may anchor its firing path on that changed description line"
|
|
961
|
+
behavior_failures.each { |path| warn " incomplete: #{path}" }
|
|
962
|
+
exit 1
|
|
963
|
+
end
|
|
964
|
+
end
|