@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,1452 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="${1:-.}"
|
|
5
|
+
|
|
6
|
+
if [[ ! -d "$root" ]]; then
|
|
7
|
+
echo "ccl_skill_root_not_found: $root" >&2
|
|
8
|
+
exit 2
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
if [[ ! -x "$root/skills/skill-extraction-workflow/scripts/validate-skill.sh" ]]; then
|
|
12
|
+
echo "missing_validate_script: $root/skills/skill-extraction-workflow/scripts/validate-skill.sh" >&2
|
|
13
|
+
exit 2
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
for required_cmd in ruby rg git; do
|
|
17
|
+
if ! command -v "$required_cmd" >/dev/null 2>&1; then
|
|
18
|
+
echo "missing_required_command: $required_cmd" >&2
|
|
19
|
+
exit 2
|
|
20
|
+
fi
|
|
21
|
+
done
|
|
22
|
+
|
|
23
|
+
resolve_checker_scripts_dir() {
|
|
24
|
+
local checker_source="$1"
|
|
25
|
+
local checker_target
|
|
26
|
+
local checker_hops=0
|
|
27
|
+
|
|
28
|
+
while [[ -L "$checker_source" ]]; do
|
|
29
|
+
checker_hops=$((checker_hops + 1))
|
|
30
|
+
if (( checker_hops > 8 )); then
|
|
31
|
+
return 1
|
|
32
|
+
fi
|
|
33
|
+
checker_target="$(readlink "$checker_source")"
|
|
34
|
+
if [[ "$checker_target" == /* ]]; then
|
|
35
|
+
checker_source="$checker_target"
|
|
36
|
+
else
|
|
37
|
+
checker_source="$(dirname "$checker_source")/$checker_target"
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
|
|
41
|
+
cd "$(dirname "$checker_source")" && pwd -P
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
"$root/skills/skill-extraction-workflow/scripts/validate-skill.sh" "$root/skills"
|
|
45
|
+
|
|
46
|
+
ruby -ryaml -e '
|
|
47
|
+
root = ARGV.fetch(0)
|
|
48
|
+
skill_files = Dir[File.join(root, "skills", "*", "SKILL.md")].sort
|
|
49
|
+
skills = skill_files.map { |path| File.basename(File.dirname(path)) }
|
|
50
|
+
abort "no_ccl_skills_found: #{root}" if skills.empty?
|
|
51
|
+
|
|
52
|
+
changed_entrypoints = []
|
|
53
|
+
begin
|
|
54
|
+
if system("git", "-C", root, "rev-parse", "--is-inside-work-tree", out: File::NULL, err: File::NULL)
|
|
55
|
+
base = ENV.fetch("CCL_SKILL_BASE_REF", "").strip
|
|
56
|
+
if base.empty?
|
|
57
|
+
upstream_ref = IO.popen(["git", "-C", root, "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{upstream}", err: File::NULL], &:read).strip
|
|
58
|
+
base = upstream_ref.empty? ? "origin/main" : upstream_ref
|
|
59
|
+
end
|
|
60
|
+
merge_base = IO.popen(["git", "-C", root, "merge-base", base, "HEAD"], &:read).strip
|
|
61
|
+
changed_paths = []
|
|
62
|
+
changed_paths.concat(IO.popen(["git", "-C", root, "diff", "--name-only", merge_base, "HEAD"], &:read).lines.map(&:strip)) unless merge_base.empty?
|
|
63
|
+
changed_paths.concat(IO.popen(["git", "-C", root, "diff", "--name-only"], &:read).lines.map(&:strip))
|
|
64
|
+
changed_paths.concat(IO.popen(["git", "-C", root, "diff", "--cached", "--name-only"], &:read).lines.map(&:strip))
|
|
65
|
+
changed_paths.concat(IO.popen(["git", "-C", root, "ls-files", "--others", "--exclude-standard", "--", "skills/*/SKILL.md"], &:read).lines.map(&:strip))
|
|
66
|
+
changed_entrypoints = changed_paths.map { |path| path[%r{\Askills/[^/]+/SKILL\.md\z}] }.compact.uniq
|
|
67
|
+
end
|
|
68
|
+
rescue StandardError => e
|
|
69
|
+
warn "entrypoint_recommended_size_changed_file_scan_skipped: #{e.class.name} #{e.message.lines.first.to_s.strip}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Catalog contract. docs/SKILLS.md is the single authoritative human catalog and
|
|
73
|
+
# agent-context/session-start.md is the always-on entry routing layer; without a
|
|
74
|
+
# gate binding them they drift apart on the next skill added, and a drifting
|
|
75
|
+
# hand-maintained skill index is the one artifact this workflow tells you not to
|
|
76
|
+
# build. Rows are anchored on their own header (- `name` `entry|leaf` — ...), not
|
|
77
|
+
# on a loose backtick scan: a loose scan counts a name mentioned in some OTHER
|
|
78
|
+
# entry redirect as coverage, so deleting a skill row went undetected.
|
|
79
|
+
catalog = File.join(root, "docs", "SKILLS.md")
|
|
80
|
+
catalog = File.join(root, "README.md") unless File.file?(catalog)
|
|
81
|
+
bootstrap_path = File.join(root, "agent-context", "session-start.md")
|
|
82
|
+
skill_token = /\A[a-z0-9]+(?:-[a-z0-9]+)+\z/
|
|
83
|
+
catalog_bad = []
|
|
84
|
+
if File.file?(catalog)
|
|
85
|
+
catalog_lines = File.readlines(catalog)
|
|
86
|
+
rows = []
|
|
87
|
+
catalog_lines.each_with_index do |line, idx|
|
|
88
|
+
header = line.match(/\A- `([a-z0-9-]+)` `(entry|leaf)` /)
|
|
89
|
+
next unless header
|
|
90
|
+
rows << { name: header[1], kind: header[2], use: line, skip: catalog_lines[idx + 1].to_s }
|
|
91
|
+
end
|
|
92
|
+
# One format, no compatibility branch. The old loose backtick scan counted a name
|
|
93
|
+
# mentioned in some OTHER row as coverage, so it could not see a deleted row --
|
|
94
|
+
# keeping it alongside the contract would just preserve the hole it created.
|
|
95
|
+
if rows.empty?
|
|
96
|
+
catalog_bad << "skill_catalog_missing_markers: #{catalog} carries no `name` `entry|leaf` rows"
|
|
97
|
+
catalog_bad << " the catalog format is the contract: each skill needs one row plus a 不用 line beneath it"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Initialize on every path. The routing block below lives in the else-branch, so
|
|
101
|
+
# today nothing reads these when rows is empty -- but only because catalog_bad is
|
|
102
|
+
# non-empty there and short-circuits the reader. That is one edit away from a
|
|
103
|
+
# NameError, so do not leave it resting on an unrelated branch staying non-empty.
|
|
104
|
+
names = []
|
|
105
|
+
entry_names = []
|
|
106
|
+
entry_coverage_unevaluated = false
|
|
107
|
+
unless rows.empty?
|
|
108
|
+
names = rows.map { |row| row[:name] }
|
|
109
|
+
missing = skills - names
|
|
110
|
+
extra = names - skills
|
|
111
|
+
duplicated = names.select { |name| names.count(name) > 1 }.uniq
|
|
112
|
+
unless missing.empty? && extra.empty? && duplicated.empty?
|
|
113
|
+
catalog_bad << "skill_catalog_map_mismatch"
|
|
114
|
+
catalog_bad << " missing_in_catalog=#{missing.join(",")}" unless missing.empty?
|
|
115
|
+
# Live check now: the previous one filtered candidates down to real skills
|
|
116
|
+
# first, so this could never fire.
|
|
117
|
+
catalog_bad << " extra_in_catalog=#{extra.join(",")}" unless extra.empty?
|
|
118
|
+
catalog_bad << " duplicated_in_catalog=#{duplicated.join(",")}" unless duplicated.empty?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
rows.each do |row|
|
|
122
|
+
# Two lines per skill: when to use it, and when to use something else. The
|
|
123
|
+
# second one is the part that only ever existed inside a description Skip
|
|
124
|
+
# clause, invisible to a human reading the catalog.
|
|
125
|
+
# Anchor on the dash-introduced clause: a bare include?("用:") is satisfied by
|
|
126
|
+
# 不用:, so a row whose only clause is a redirect would pass the two-line
|
|
127
|
+
# contract while never saying when to USE the skill.
|
|
128
|
+
unless row[:use].match?(/—\s*用:/)
|
|
129
|
+
catalog_bad << "skill_catalog_missing_use_line: #{row[:name]}"
|
|
130
|
+
end
|
|
131
|
+
unless row[:skip].match?(/\A\s+- 不用:/)
|
|
132
|
+
catalog_bad << "skill_catalog_missing_skip_line: #{row[:name]}"
|
|
133
|
+
next
|
|
134
|
+
end
|
|
135
|
+
row[:skip].scan(/`([a-z0-9-]+)`/) do |match|
|
|
136
|
+
target = match[0]
|
|
137
|
+
next unless target.match?(skill_token)
|
|
138
|
+
next if skills.include?(target)
|
|
139
|
+
catalog_bad << "skill_catalog_dangling_pointer: #{row[:name]} redirects to #{target}"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
entry_names = rows.select { |row| row[:kind] == "entry" }.map { |row| row[:name] }
|
|
144
|
+
# The routing layer covers the entry set only. Leaf skills are reached through
|
|
145
|
+
# their owner, so putting them in an every-session injection is pure token cost.
|
|
146
|
+
# Fail closed. Marking a skill entry is a claim that the always-on layer routes to
|
|
147
|
+
# it, so a missing layer file means that claim was never evaluated -- skipping here
|
|
148
|
+
# would print contract_ok over an unverified assertion. Other checks in this script
|
|
149
|
+
# degrade to skipped-missing for the same file; this one cannot, because it is the
|
|
150
|
+
# one that asserts the coverage.
|
|
151
|
+
# Do not fail, and do not abort. This script only runs against this repository
|
|
152
|
+
# (Makefile, AGENTS.md, .githooks/pre-push, the opencode commands; install-gates.sh
|
|
153
|
+
# does not ship it), so a checkout without the layer is a fixture, not a deployment.
|
|
154
|
+
# The reason to keep going is that consumers read the later sections *_done markers
|
|
155
|
+
# to tell "checked and clean" from "never ran", and an early exit masks all of them.
|
|
156
|
+
# What this must not do is read as clean:
|
|
157
|
+
# marking a skill entry claims the always-on layer routes to it, and with no layer
|
|
158
|
+
# that claim was never evaluated. Same honesty shape as the size-gate
|
|
159
|
+
# *_unevaluated token and sync_pointer_skipped -- skip is not a pass.
|
|
160
|
+
entry_coverage_unevaluated = !entry_names.empty? && !File.file?(bootstrap_path)
|
|
161
|
+
if entry_coverage_unevaluated
|
|
162
|
+
puts "skill_catalog_entry_coverage_unevaluated: #{bootstrap_path} is absent, so entry coverage for #{entry_names.length} entry skills was NOT evaluated — this is not a pass"
|
|
163
|
+
end
|
|
164
|
+
if File.file?(bootstrap_path)
|
|
165
|
+
region = File.read(bootstrap_path)[/ccl:entry-routing:start -->(.*?)<!-- ccl:entry-routing:end/m, 1]
|
|
166
|
+
if region.nil?
|
|
167
|
+
catalog_bad << "skill_bootstrap_region_missing: agent-context/session-start.md has no ccl:entry-routing markers"
|
|
168
|
+
else
|
|
169
|
+
routed = region.scan(/\*\*([a-z0-9-]+)\*\*/).flatten.select { |name| name.match?(skill_token) }.uniq
|
|
170
|
+
uncovered = entry_names - routed
|
|
171
|
+
dangling = routed - skills
|
|
172
|
+
catalog_bad << "skill_bootstrap_entry_uncovered: #{uncovered.join(",")}" unless uncovered.empty?
|
|
173
|
+
catalog_bad << "skill_bootstrap_dangling_pointer: #{dangling.join(",")}" unless dangling.empty?
|
|
174
|
+
# entry means: this skill has a routing rule in the resident layer. A leaf named
|
|
175
|
+
# there contradicts its own mark, and the mark is what the catalog tells readers.
|
|
176
|
+
leaf_in_region = routed & (names - entry_names)
|
|
177
|
+
catalog_bad << "skill_bootstrap_leaf_in_region: #{leaf_in_region.join(",")} — routed in the always-on layer but marked leaf; mark them entry or remove the routing rule" unless leaf_in_region.empty?
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Do NOT exit here. A catalog failure must fail the gate, but aborting the program
|
|
184
|
+
# masks every later section and its *_done marker -- consumers read those markers to
|
|
185
|
+
# tell "checked and clean" from "never ran", so a masked section reports as neither.
|
|
186
|
+
# The findings ride the terminal bad list below instead.
|
|
187
|
+
if catalog_bad.empty?
|
|
188
|
+
puts "skill_catalog_map_ok"
|
|
189
|
+
unless entry_coverage_unevaluated
|
|
190
|
+
puts "skill_catalog_contract_ok entries=#{rows.length} entry=#{entry_names.length} leaf=#{rows.length - entry_names.length}"
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
else
|
|
194
|
+
puts "skill_catalog_map_skipped"
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
bad = catalog_bad.dup
|
|
198
|
+
warns = []
|
|
199
|
+
overlay_keys = %w[display_name short_description default_prompt]
|
|
200
|
+
skill_files.each do |path|
|
|
201
|
+
text = File.read(path)
|
|
202
|
+
body = text.sub(/\A---\n.*?\n---\n/m, "")
|
|
203
|
+
frontmatter_raw = text[/\A---\n(.*?)\n---\n/m, 1].to_s
|
|
204
|
+
dir = File.basename(File.dirname(path))
|
|
205
|
+
begin
|
|
206
|
+
fm = YAML.safe_load(frontmatter_raw, aliases: false) || {}
|
|
207
|
+
rescue Psych::Exception => e
|
|
208
|
+
bad << "#{dir}: yaml_parse_error #{e.class.name.split("::").last} #{e.message.lines.first.to_s.strip}"
|
|
209
|
+
next
|
|
210
|
+
end
|
|
211
|
+
name = fm["name"].to_s.strip
|
|
212
|
+
desc = fm["description"].to_s.strip
|
|
213
|
+
rel_path = path.start_with?(root + "/") ? path[(root.length + 1)..] : path.sub(%r{\A\./}, "")
|
|
214
|
+
changed_entrypoint = changed_entrypoints.include?(rel_path)
|
|
215
|
+
bad << "#{dir}: name_mismatch frontmatter=#{name}" unless name == dir
|
|
216
|
+
bad << "#{dir}: empty_description" if desc.empty?
|
|
217
|
+
# OpenCode skill routing relies heavily on the frontmatter description. Long
|
|
218
|
+
# or multi-line descriptions dilute the trigger signal and can be truncated in
|
|
219
|
+
# the host skill listing, so keep detailed routing rules in the body instead.
|
|
220
|
+
bad << "#{dir}: description_too_long_for_opencode #{desc.length}/800" if desc.length > 800
|
|
221
|
+
bad << "#{dir}: description_multiline_for_opencode" if frontmatter_raw.match?(/^description:\s*[>|]/)
|
|
222
|
+
warns << "#{dir}: description_long_for_opencode #{desc.length}/800" if desc.length > 600 && desc.length <= 800
|
|
223
|
+
|
|
224
|
+
long_lines = body.lines.each_with_index.map do |line, idx|
|
|
225
|
+
line_length = line.chomp.length
|
|
226
|
+
[idx + 1, line_length] if line_length > 600
|
|
227
|
+
end.compact
|
|
228
|
+
# Report the true largest hotspots; line number is a deterministic tie-breaker.
|
|
229
|
+
longest_lines = long_lines.sort_by { |line_number, line_length| [-line_length, line_number] }.first(5).map do |line_number, line_length|
|
|
230
|
+
"L#{line_number}:#{line_length}"
|
|
231
|
+
end
|
|
232
|
+
warns << "#{dir}: entrypoint_body_large #{body.length}/50000" if body.length > 50000
|
|
233
|
+
if changed_entrypoint
|
|
234
|
+
warns << "#{dir}: entrypoint_body_below_recommended_for_changed_file #{body.length}/1000 verify_trigger_owner_hard-stop_pointer_do_not_pad" if body.length < 1000
|
|
235
|
+
warns << "#{dir}: entrypoint_body_above_recommended_for_changed_file #{body.length}/5000" if body.length > 5000
|
|
236
|
+
end
|
|
237
|
+
warns << "#{dir}: entrypoint_long_lines #{longest_lines.join(",")}" unless long_lines.empty?
|
|
238
|
+
|
|
239
|
+
# Codex overlay parity: every skill ships agents/openai.yaml so the Codex side
|
|
240
|
+
# gets a $skill interface (display_name / short_description / default_prompt),
|
|
241
|
+
# matching the Claude side. Missing or incomplete overlay = two-end drift.
|
|
242
|
+
overlay = File.join(File.dirname(path), "agents", "openai.yaml")
|
|
243
|
+
if !File.file?(overlay)
|
|
244
|
+
bad << "#{dir}: missing_codex_overlay agents/openai.yaml"
|
|
245
|
+
else
|
|
246
|
+
begin
|
|
247
|
+
oy = YAML.safe_load(File.read(overlay), aliases: false) || {}
|
|
248
|
+
iface = oy["interface"]
|
|
249
|
+
if !iface.is_a?(Hash)
|
|
250
|
+
bad << "#{dir}: codex_overlay_missing_interface"
|
|
251
|
+
else
|
|
252
|
+
missing = overlay_keys.reject { |k| !iface[k].to_s.strip.empty? }
|
|
253
|
+
bad << "#{dir}: codex_overlay_incomplete missing=#{missing.join(",")}" unless missing.empty?
|
|
254
|
+
end
|
|
255
|
+
rescue Psych::Exception => e
|
|
256
|
+
bad << "#{dir}: codex_overlay_yaml_error #{e.message.lines.first.to_s.strip}"
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
warns.each { |item| warn " WARN #{item}" } unless warns.empty?
|
|
262
|
+
|
|
263
|
+
if bad.empty?
|
|
264
|
+
puts "frontmatter_name_description_ok"
|
|
265
|
+
puts "codex_overlay_ok"
|
|
266
|
+
else
|
|
267
|
+
warn "frontmatter_name_description_failed"
|
|
268
|
+
bad.each { |item| warn " #{item}" }
|
|
269
|
+
exit 1
|
|
270
|
+
end
|
|
271
|
+
' "$root"
|
|
272
|
+
|
|
273
|
+
if leak_output="$(rg -n 'code\.[[:alnum:].-]+|figma\.com/files|[0-9]{8,}|\x{6559}\x{5e08}|\x{5b66}\x{751f}|\x{8003}\x{8bd5}|\x{5b66}\x{6821}|\x{9605}\x{5377}|\x{51fa}\x{5377}|\x{626b}\x{63cf}|\x{5b66}\x{60c5}' "$root"/skills/*/SKILL.md "$root"/skills/*/references/*.md 2>/dev/null)"; then
|
|
274
|
+
echo "$leak_output"
|
|
275
|
+
echo "entrypoint_or_reference_domain_scan_failed" >&2
|
|
276
|
+
exit 1
|
|
277
|
+
else
|
|
278
|
+
rg_status=$?
|
|
279
|
+
if [[ "$rg_status" -ne 1 ]]; then
|
|
280
|
+
echo "entrypoint_scan_error: rg exited $rg_status" >&2
|
|
281
|
+
exit 1
|
|
282
|
+
fi
|
|
283
|
+
fi
|
|
284
|
+
echo "entrypoint_and_reference_domain_scan_ok"
|
|
285
|
+
|
|
286
|
+
# Recurring anti-pattern scan: a TARGETED mechanical backstop (NOT a comprehensive
|
|
287
|
+
# detector) for the grep panel in
|
|
288
|
+
# skill-extraction-workflow/references/recurring-anti-patterns-checklist.md, which is
|
|
289
|
+
# otherwise only run from memory. It catches the one high-signal class with a written
|
|
290
|
+
# architectural rule and zero legitimate occurrences in product-agnostic skills:
|
|
291
|
+
# a framework's reserved envelope/base field NUMBER (the byted/Kitex base is always
|
|
292
|
+
# field 255) presented as a contract convention, plus bare `Base{...}` struct literals.
|
|
293
|
+
# The rule it enforces:
|
|
294
|
+
# "Do not inherit a framework's reserved envelope/base field number as a contract
|
|
295
|
+
# convention. New products should choose an explicit envelope field and document it."
|
|
296
|
+
# (go-microservice-architecture/references/protobuf-contract-architecture.md)
|
|
297
|
+
# The comprehensive net stays the human/agent checklist + the dual-track challenge;
|
|
298
|
+
# this gate is the fast deterministic catch for the exact shape that has leaked before.
|
|
299
|
+
# Additional per-class mechanical gates may be added as a symptom recurs across 2+
|
|
300
|
+
# skills, mirroring the checklist's growth rule; do NOT bulk-copy the checklist here.
|
|
301
|
+
#
|
|
302
|
+
# `platform-service-connectivity` legitimately owns the canonical base struct (it frames
|
|
303
|
+
# these as named examples of a generic concept) and the checklist file defines the
|
|
304
|
+
# symptom — both are allowlisted by repo-relative PATH (not by match text, and not via
|
|
305
|
+
# any runtime env override: a security backstop must not be skippable from the caller's
|
|
306
|
+
# environment). Bare `base.Request` mentions are NOT flagged (legitimate routing-pointer
|
|
307
|
+
# uses exist). Scan surface includes SKILL.md, references, the Codex overlays, and README.
|
|
308
|
+
# Allowlist by ANCHORED repo-relative path: a trailing-slash entry is a directory
|
|
309
|
+
# prefix; any other entry is an exact file path (a bare basename would wrongly exempt
|
|
310
|
+
# a same-named file under another skill).
|
|
311
|
+
antipattern_allow_paths=( "skills/platform-service-connectivity/" "skills/skill-extraction-workflow/references/recurring-anti-patterns-checklist.md" )
|
|
312
|
+
antipattern_files=( "$root"/skills/*/SKILL.md "$root"/skills/*/references/*.md "$root"/skills/*/agents/*.yaml )
|
|
313
|
+
[[ -f "$root/README.md" ]] && antipattern_files+=( "$root/README.md" )
|
|
314
|
+
# rg stage-1 is a CANDIDATE net (lines with a base-token near `=`/`{`); the bash stage-2
|
|
315
|
+
# below confirms precisely. The gate is HIGH-PRECISION by design: it flags only the
|
|
316
|
+
# base-NAMED field bound to the reserved field number 255 — the byted/Kitex base
|
|
317
|
+
# convention that actually leaked (`base = 255`, `base.Request base = 255`,
|
|
318
|
+
# `baseResp = 255`), incl. case variants — plus a bare `Base {` struct literal.
|
|
319
|
+
# It deliberately does NOT flag:
|
|
320
|
+
# - a bare reserved number `= 255` on a non-base field (exit codes, uint8/varchar 255);
|
|
321
|
+
# - a base-named field bound to OTHER numbers (`base = 2 seconds` backoff math, etc);
|
|
322
|
+
# - a base var holding 255 as a VALUE with a unit/decimal (`base = 255 ms`, `255.0`,
|
|
323
|
+
# `255-byte`): the 255 must be terminated by a proto-ish boundary (closing backtick,
|
|
324
|
+
# `;`, `,`, `)`, `]`, `}`) — exactly how every real leak appeared (inline-code
|
|
325
|
+
# `` `…base = 255` `` or a `… = 255;` proto field decl) — not by a space+unit/decimal;
|
|
326
|
+
# - `baseline = 3`/`database = 255` (the base token must be exactly `base`, `baseResp`,
|
|
327
|
+
# or `base.<Word>`, never an arbitrary `base*` word).
|
|
328
|
+
# Renamed-field, non-255, non-terminated, and pure-prose variants are the accepted recall
|
|
329
|
+
# limit; the comprehensive net is the human/agent checklist + the dual-track challenge.
|
|
330
|
+
antipattern_candidate='\bbase[a-z0-9._]*[[:space:]]*[={]'
|
|
331
|
+
# Note: bash [[ =~ ]] is POSIX ERE — no `\b`. The trailing group is the proto-terminator
|
|
332
|
+
# set ( ` ; , ) ] } ); `)` is escaped so it does not close the group.
|
|
333
|
+
re_base_assign='(^|[^a-z0-9_])base(resp|\.[a-z0-9_]+)?[[:space:]]*=[[:space:]]*255(`|;|,|\)|]|})'
|
|
334
|
+
re_base_struct='(^|[^a-z0-9_])base[[:space:]]*\{'
|
|
335
|
+
if antipattern_raw="$(rg -ni "$antipattern_candidate" "${antipattern_files[@]}" 2>/dev/null)"; then
|
|
336
|
+
antipattern_hits=""
|
|
337
|
+
shopt -s nocasematch
|
|
338
|
+
while IFS= read -r line; do
|
|
339
|
+
[[ -z "$line" ]] && continue
|
|
340
|
+
# Strip the known "$root/" prefix first so the path field is repo-relative and
|
|
341
|
+
# colon-safe even if $root itself contains a colon; then split path:lineno:text.
|
|
342
|
+
rel="${line#"$root"/}"
|
|
343
|
+
hitpath="${rel%%:*}"
|
|
344
|
+
rest="${rel#*:}"; linetext="${rest#*:}"
|
|
345
|
+
skip=0
|
|
346
|
+
for sub in "${antipattern_allow_paths[@]}"; do
|
|
347
|
+
if [[ "$sub" == */ ]]; then
|
|
348
|
+
[[ "$hitpath" == "$sub"* ]] && { skip=1; break; }
|
|
349
|
+
else
|
|
350
|
+
[[ "$hitpath" == "$sub" ]] && { skip=1; break; }
|
|
351
|
+
fi
|
|
352
|
+
done
|
|
353
|
+
[[ "$skip" -eq 1 ]] && continue
|
|
354
|
+
if [[ "$linetext" =~ $re_base_assign ]] || [[ "$linetext" =~ $re_base_struct ]]; then
|
|
355
|
+
antipattern_hits+="$line"$'\n'
|
|
356
|
+
fi
|
|
357
|
+
done <<< "$antipattern_raw"
|
|
358
|
+
shopt -u nocasematch
|
|
359
|
+
if [[ -n "${antipattern_hits//[$'\n']/}" ]]; then
|
|
360
|
+
printf '%s\n' "$antipattern_hits"
|
|
361
|
+
echo "recurring_antipattern_scan_failed: one-organization reserved-field/base-struct convention above appears outside platform-service-connectivity; generalize it (name the platform's documented field without a hardcoded number) or route to that owner — see skill-extraction-workflow/references/recurring-anti-patterns-checklist.md" >&2
|
|
362
|
+
exit 1
|
|
363
|
+
fi
|
|
364
|
+
else
|
|
365
|
+
antipattern_status=$?
|
|
366
|
+
if [[ "$antipattern_status" -ne 1 ]]; then
|
|
367
|
+
echo "recurring_antipattern_scan_error: rg exited $antipattern_status" >&2
|
|
368
|
+
exit 1
|
|
369
|
+
fi
|
|
370
|
+
fi
|
|
371
|
+
echo "recurring_antipattern_scan_ok"
|
|
372
|
+
|
|
373
|
+
# A variable expansion immediately followed by a multibyte character: bash folds
|
|
374
|
+
# those bytes into the NAME, so `$arg(可用…)` reads a variable literally called
|
|
375
|
+
# `arg(可用…)`. Under `set -u` the script aborts with an unbound-variable error;
|
|
376
|
+
# without it the value AND the punctuation silently vanish. It hides in error
|
|
377
|
+
# branches and summary lines nobody exercises by hand, so only a static scan finds
|
|
378
|
+
# it. This class was already mechanized in the repo — but only over the ```bash
|
|
379
|
+
# blocks of one reference doc, so the repo's OWN scripts were never covered and
|
|
380
|
+
# both live instances survived (scripts/install.sh usage error: aborts instead of
|
|
381
|
+
# printing usage; Makefile prune-cache summary: prints mojibake instead of the
|
|
382
|
+
# version). Widened here to every tracked shell script plus the Makefile.
|
|
383
|
+
fullwidth_var_exempt="skills/multi-perspective-research/scripts/test-public-data-acquisition-recipes.sh"
|
|
384
|
+
fullwidth_files=()
|
|
385
|
+
while IFS= read -r f; do
|
|
386
|
+
[ "$f" = "$fullwidth_var_exempt" ] && continue
|
|
387
|
+
fullwidth_files+=("$f")
|
|
388
|
+
done < <(git -C "$root" ls-files '*.sh' 2>/dev/null)
|
|
389
|
+
[ -f "$root/Makefile" ] && fullwidth_files+=("Makefile")
|
|
390
|
+
if [ "${#fullwidth_files[@]}" -gt 0 ]; then
|
|
391
|
+
fullwidth_hits="$(cd "$root" && ruby -e '
|
|
392
|
+
ARGV.each do |path|
|
|
393
|
+
next unless File.file?(path)
|
|
394
|
+
File.readlines(path, chomp: true).each_with_index do |line, idx|
|
|
395
|
+
next if line.lstrip.start_with?("#")
|
|
396
|
+
next unless line.match?(/\$[A-Za-z_][A-Za-z0-9_]*(?![A-Za-z0-9_])[^[:ascii:]]/)
|
|
397
|
+
puts "#{path}:#{idx + 1}: #{line.strip}"
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
' "${fullwidth_files[@]}" 2>&1)" || {
|
|
401
|
+
echo "fullwidth_var_scan_error: scanner exited non-zero (fail-closed)" >&2
|
|
402
|
+
exit 1
|
|
403
|
+
}
|
|
404
|
+
if [ -n "$fullwidth_hits" ]; then
|
|
405
|
+
printf '%s\n' "$fullwidth_hits"
|
|
406
|
+
echo "fullwidth_var_scan_failed: a variable expansion above is immediately followed by a multibyte character, so the shell reads it as part of the NAME; brace it as \${var}. Exempt by path only for deliberate negative fixtures." >&2
|
|
407
|
+
exit 1
|
|
408
|
+
fi
|
|
409
|
+
fi
|
|
410
|
+
echo "fullwidth_var_scan_ok (${#fullwidth_files[@]} files)"
|
|
411
|
+
|
|
412
|
+
# Anti-pattern 27 — repo/worktree identity decided by PATH SHAPE (see
|
|
413
|
+
# references/recurring-anti-patterns-checklist.md). A control that matches a git-dir
|
|
414
|
+
# against `*/worktrees/*` is predicating on the USER'S directory naming, not on git
|
|
415
|
+
# structure: a primary checkout living under a directory called `worktrees/` is misread
|
|
416
|
+
# as already-isolated, so an isolation/deny gate silently fails open. This promoted the
|
|
417
|
+
# checklist row to a gate because the class recurred twice (owner-dispatch state key,
|
|
418
|
+
# guard-edit-isolation deny bypass) within one day.
|
|
419
|
+
# Scope: executable shell under hooks/ and scripts/ — the surface where such a predicate
|
|
420
|
+
# makes a control decision. Excluded on purpose: `test_*.sh` / `test.sh` (a fixture
|
|
421
|
+
# legitimately asserts a git-dir CONTAINS the component, which is not a control
|
|
422
|
+
# decision), and WHOLE-LINE comments (the fix itself documents the banned spelling).
|
|
423
|
+
# A trailing comment or a string literal carrying the pattern IS flagged, deliberately:
|
|
424
|
+
# deciding "is this `#` a comment or part of a glob/string" needs a shell parser, and a
|
|
425
|
+
# half-parser is the kind of thing a later maintainer loosens after one false positive —
|
|
426
|
+
# which silently re-blinds the gate. The contract is therefore the simple checkable one:
|
|
427
|
+
# outside a whole-line comment, this literal must not appear in non-test shell here; put
|
|
428
|
+
# explanatory mentions on their own comment line (as these very lines do).
|
|
429
|
+
# The predicate requires a glob star on BOTH sides of the component, optionally quoted
|
|
430
|
+
# (`*/worktrees/*`, `*"/worktrees/"*`, `*'/worktrees/'*`) — that shape is a MATCH pattern,
|
|
431
|
+
# never an ordinary path, so a legitimate `rm -rf .work/worktrees/*` cleanup glob does not
|
|
432
|
+
# trip it. Matching bare `worktrees` + `*` instead would flag exactly such cleanup code.
|
|
433
|
+
# Recall limits — three, all deliberate and all stated so the contract is not overclaimed:
|
|
434
|
+
# 1. a fully dynamic pattern (`*"/$seg/"*`);
|
|
435
|
+
# 2. a pattern split across physical lines by a backslash continuation (the match is
|
|
436
|
+
# per physical line; joining continuations first would move every reported line
|
|
437
|
+
# number off the real source line, for a spelling nobody writes by accident);
|
|
438
|
+
# 3. `--absolute-git-dir` used as an identity key — the same call legitimately locates
|
|
439
|
+
# the CURRENT worktree, so grepping it is false-positive-prone.
|
|
440
|
+
# Those stay checklist/challenge checks. This gate catches the literal spellings a
|
|
441
|
+
# developer writes by hand; it is not an obfuscation-proof barrier and does not claim to be.
|
|
442
|
+
# Traversal hardening — every leg here exists because the failure it prevents makes the
|
|
443
|
+
# gate print "ok" for a scan that did not happen, which is worse than no gate at all:
|
|
444
|
+
# -print0/read -d '' a newline in a file name would split into two non-existent paths
|
|
445
|
+
# and silently drop the real file
|
|
446
|
+
# -L a symlinked hooks//scripts/ dir, or a symlinked .sh, is otherwise
|
|
447
|
+
# skipped entirely (`-type f` alone excludes symlinks)
|
|
448
|
+
# find status check a failed traversal (unreadable dir; a symlink loop where the find
|
|
449
|
+
# implementation reports one) must not read as "clean". Loop
|
|
450
|
+
# reporting is implementation-dependent — bfs was measured to be
|
|
451
|
+
# nondeterministic about it — so the pinned case is the unreadable
|
|
452
|
+
# dir; loops are caught only when find says so.
|
|
453
|
+
# Ordering is applied to the collected HITS, not the file list, so there is no `sort -z`
|
|
454
|
+
# portability assumption.
|
|
455
|
+
gid_hits=""
|
|
456
|
+
if [[ -d "$root/hooks" || -d "$root/scripts" ]]; then
|
|
457
|
+
gid_list=$(mktemp "${TMPDIR:-/tmp}/ccl-skills-gid.XXXXXX") || { echo "git_identity_predicate_scan_error: mktemp failed" >&2; exit 1; }
|
|
458
|
+
# Every normal and error path below removes this explicitly; the trap only covers a
|
|
459
|
+
# signal or an unrelated `set -e` abort further down the checker.
|
|
460
|
+
trap 'rm -f "${gid_list:-/dev/null}"' EXIT
|
|
461
|
+
# Pass ONLY the roots that exist, so a non-zero find status always means a genuine walk
|
|
462
|
+
# failure (symlink loop, unreadable dir) and never merely "one of the two is absent".
|
|
463
|
+
# Gating the error on "both dirs exist" instead would silently accept a failed walk in
|
|
464
|
+
# the common single-root repo — the same fail-open shape this gate exists to stop.
|
|
465
|
+
gid_roots=()
|
|
466
|
+
[[ -d "$root/hooks" ]] && gid_roots+=( "$root/hooks" )
|
|
467
|
+
[[ -d "$root/scripts" ]] && gid_roots+=( "$root/scripts" )
|
|
468
|
+
# if-guarded: under this script's `set -e`, a bare `find ...; rc=$?` would exit the
|
|
469
|
+
# whole checker before the status is ever inspected (verified, not assumed).
|
|
470
|
+
if find -L "${gid_roots[@]}" -name '*.sh' -type f -print0 > "$gid_list" 2>/dev/null; then
|
|
471
|
+
gid_find_rc=0
|
|
472
|
+
else
|
|
473
|
+
gid_find_rc=$?
|
|
474
|
+
fi
|
|
475
|
+
if [[ "$gid_find_rc" -ne 0 ]]; then
|
|
476
|
+
rm -f "$gid_list"
|
|
477
|
+
echo "git_identity_predicate_scan_error: find exited $gid_find_rc walking ${gid_roots[*]#"$root"/} — the walk is INCOMPLETE, which is not the same as clean" >&2
|
|
478
|
+
exit 1
|
|
479
|
+
fi
|
|
480
|
+
while IFS= read -r -d '' gid_file; do
|
|
481
|
+
[[ -n "$gid_file" ]] || continue
|
|
482
|
+
case "${gid_file##*/}" in test_*.sh|test.sh) continue ;; esac
|
|
483
|
+
# A no-match is grep status 1; anything above that is a real scan error (file vanished
|
|
484
|
+
# after find, unreadable, I/O). Swallowing those with `|| true` would print the ok
|
|
485
|
+
# token for a scan that never happened — a clean result that means nothing.
|
|
486
|
+
# Same `set -e` hazard: a plain `gid_out=$(grep ...)` exits the checker on the FIRST
|
|
487
|
+
# no-match file (status 1), i.e. on virtually every run — the gate would never be
|
|
488
|
+
# reached in production while every extracted-section probe stayed green.
|
|
489
|
+
if gid_out="$(grep -nE '\*['"'"'"]?/worktrees/['"'"'"]?\*' "$gid_file" 2>/dev/null)"; then
|
|
490
|
+
gid_rc=0
|
|
491
|
+
else
|
|
492
|
+
gid_rc=$?
|
|
493
|
+
fi
|
|
494
|
+
if [[ "$gid_rc" -gt 1 ]]; then
|
|
495
|
+
rm -f "$gid_list"
|
|
496
|
+
echo "git_identity_predicate_scan_error: grep exited $gid_rc while scanning ${gid_file#"$root"/} — unreadable or I/O failure means the result is UNKNOWN, not clean" >&2
|
|
497
|
+
exit 1
|
|
498
|
+
fi
|
|
499
|
+
[[ "$gid_rc" -eq 0 ]] || continue
|
|
500
|
+
while IFS= read -r gid_line; do
|
|
501
|
+
[[ -n "$gid_line" ]] || continue
|
|
502
|
+
gid_text="${gid_line#*:}"
|
|
503
|
+
[[ "$gid_text" =~ ^[[:space:]]*# ]] && continue
|
|
504
|
+
gid_hits+="${gid_file#"$root"/}:$gid_line"$'\n'
|
|
505
|
+
done <<< "$gid_out"
|
|
506
|
+
done < "$gid_list"
|
|
507
|
+
rm -f "$gid_list"
|
|
508
|
+
[[ -n "${gid_hits//[$'\n']/}" ]] && gid_hits="$(printf '%s' "$gid_hits" | sort)"$'\n'
|
|
509
|
+
fi
|
|
510
|
+
if [[ -n "${gid_hits//[$'\n']/}" ]]; then
|
|
511
|
+
printf '%s' "$gid_hits"
|
|
512
|
+
echo "git_identity_predicate_scan_failed: the lines above decide repo/worktree identity from a PATH NAME (\`*/worktrees/*\`), which the user's directory layout controls — a primary checkout under a \`worktrees/\`-named path is misread as isolated and the control fails open silently. Use git structure instead: identity => \`rev-parse --path-format=absolute --git-common-dir\`; is-linked-worktree => absolute-git-dir != common dir. See skill-extraction-workflow/references/recurring-anti-patterns-checklist.md (Anti-pattern 27)." >&2
|
|
513
|
+
exit 1
|
|
514
|
+
fi
|
|
515
|
+
echo "git_identity_predicate_scan_ok"
|
|
516
|
+
|
|
517
|
+
# Evidence-card leak PREFLIGHT (best-effort, NOT the gate of record): catches obvious
|
|
518
|
+
# card-shaped markdown accidentally committed under skills/** (L0 storage rule, see
|
|
519
|
+
# l0-l1-l2-routing.md). Delegated to a dedicated, self-tested detector. The gate runs the
|
|
520
|
+
# detector's --self-test FIRST (fixture regression: the detector's own logic must be green
|
|
521
|
+
# before we trust its verdict), then the real scan. Scope is CHANGED markdown *.md under
|
|
522
|
+
# skills/** (integration base..worktree plus untracked / intent-to-add; base-less runs
|
|
523
|
+
# report a degraded warning); it does not re-police unchanged historical docs and does
|
|
524
|
+
# not enforce the L0 rule. R0 (actually run, not skipped) is the comprehensive
|
|
525
|
+
# L0-storage / leakage gate of record.
|
|
526
|
+
evidence_card_script="$root/skills/skill-extraction-workflow/scripts/check-evidence-card-leak.sh"
|
|
527
|
+
if [[ ! -f "$evidence_card_script" ]]; then
|
|
528
|
+
echo "missing_evidence_card_leak_script: $evidence_card_script" >&2
|
|
529
|
+
exit 2
|
|
530
|
+
fi
|
|
531
|
+
# Invoke via `bash` so a missing +x bit (common after checkout / on CI) is not a false miss.
|
|
532
|
+
# The --self-test is a fixture regression for the detector's own logic. A self-test FAILURE
|
|
533
|
+
# (a pure-shape assertion failed, or CCL_SKILL_EVIDENCE_CARD_STRICT_SELFTEST=1 flagged
|
|
534
|
+
# missing fixture infra) is BLOCKING — a broken detector must not be silently trusted. By
|
|
535
|
+
# default, missing git fixture infra SKIPS the changed-scope sub-tests inside the self-test
|
|
536
|
+
# (returning success with a printed warning), so unrelated authors on minimal images are not
|
|
537
|
+
# blocked. The changed-file scan below blocks on a real offender; a base-less degraded scan is
|
|
538
|
+
# warning-pass by default (set CCL_SKILL_EVIDENCE_CARD_STRICT_BASE=1 to enforce coverage).
|
|
539
|
+
if ! bash "$evidence_card_script" --self-test; then
|
|
540
|
+
echo "evidence_card_leak_self_test_failed: detector self-test failed — blocking. (Set CCL_SKILL_EVIDENCE_CARD_STRICT_SELFTEST only to make missing fixture infra fail; it is not needed to pass normally.)" >&2
|
|
541
|
+
exit 1
|
|
542
|
+
fi
|
|
543
|
+
if ! bash "$evidence_card_script" "$root"; then
|
|
544
|
+
exit 1
|
|
545
|
+
fi
|
|
546
|
+
|
|
547
|
+
# Label-discovery: list every <angle-bracket-token> introduced anywhere under the
|
|
548
|
+
# skill tree. The script does NOT have access to the maintainer's private alias
|
|
549
|
+
# YAML (that file lives outside the repo), so it cannot verify each label maps to
|
|
550
|
+
# a sanitized capability. It prints the inventory so the maintainer can confirm
|
|
551
|
+
# every label is registered in the alias YAML before committing.
|
|
552
|
+
label_inventory="$(rg -o --no-filename '<[a-z][a-z0-9-]+>' "$root"/skills/*/SKILL.md "$root"/skills/*/references/*.md 2>/dev/null | sort -u)"
|
|
553
|
+
label_rg_status=$?
|
|
554
|
+
if [[ "$label_rg_status" -ne 0 && "$label_rg_status" -ne 1 ]]; then
|
|
555
|
+
echo "label_inventory_scan_error: rg exited $label_rg_status" >&2
|
|
556
|
+
exit 1
|
|
557
|
+
fi
|
|
558
|
+
if printf '%s\n' "$label_inventory" | rg -q '^(USAGE:|ripgrep | -| --)'; then
|
|
559
|
+
echo "label_inventory_scan_error: rg help text captured instead of labels" >&2
|
|
560
|
+
exit 1
|
|
561
|
+
fi
|
|
562
|
+
if [[ -n "$label_inventory" ]]; then
|
|
563
|
+
echo "label_inventory_discovered (verify each exists in private alias YAML):"
|
|
564
|
+
echo "$label_inventory" | sed 's/^/ /'
|
|
565
|
+
fi
|
|
566
|
+
|
|
567
|
+
# R0 clean-landing status, consumed by the final machine-distinguishable token.
|
|
568
|
+
# "private-ok" => the private alias audit ran clean (clean-landing R0 evidence).
|
|
569
|
+
# "public-fallback" => no ALIAS_AUDIT_CMD; only the public diff-scoped fallback ran
|
|
570
|
+
# (interim evidence only — private R0 has NOT run).
|
|
571
|
+
# It defaults to interim/public-fallback so a missing/short-circuited assignment can
|
|
572
|
+
# never silently upgrade a run to clean.
|
|
573
|
+
r0_clean_landing_status="public-fallback"
|
|
574
|
+
|
|
575
|
+
# Fail-closed hook: if the maintainer has exported ALIAS_AUDIT_CMD, run it.
|
|
576
|
+
# The command is sourced from the maintainer's environment (typically pointing
|
|
577
|
+
# at a script that opens the private alias YAML and verifies every label and
|
|
578
|
+
# pattern). A non-zero exit blocks the check.
|
|
579
|
+
#
|
|
580
|
+
# The value is split on whitespace and exec'd directly — NOT passed to a shell —
|
|
581
|
+
# so a polluted environment variable cannot inject `;`/`&&`/pipes/substitutions.
|
|
582
|
+
# Use "<script-path> <args>" form; anything needing shell features belongs in a
|
|
583
|
+
# wrapper script the variable points at.
|
|
584
|
+
if [[ -n "${ALIAS_AUDIT_CMD:-}" ]]; then
|
|
585
|
+
echo "alias_audit_cmd_running: $ALIAS_AUDIT_CMD"
|
|
586
|
+
read -r -a alias_audit_argv <<<"$ALIAS_AUDIT_CMD"
|
|
587
|
+
# No shell means no tilde expansion; expand a leading ~/ per word so the
|
|
588
|
+
# documented `bash ~/.../run-r0-audit.sh` form keeps working.
|
|
589
|
+
for i in "${!alias_audit_argv[@]}"; do
|
|
590
|
+
[[ "${alias_audit_argv[$i]}" == "~/"* ]] && alias_audit_argv[$i]="$HOME/${alias_audit_argv[$i]:2}"
|
|
591
|
+
done
|
|
592
|
+
if ! "${alias_audit_argv[@]}"; then
|
|
593
|
+
echo "alias_audit_failed" >&2
|
|
594
|
+
exit 1
|
|
595
|
+
fi
|
|
596
|
+
echo "alias_audit_ok"
|
|
597
|
+
r0_clean_landing_status="private-ok"
|
|
598
|
+
echo "r0_status=private-ok"
|
|
599
|
+
else
|
|
600
|
+
# No private alias profile on this host (a normal local machine). Instead of
|
|
601
|
+
# leaving only an "audit skipped" notice, run the deterministic PUBLIC fallback:
|
|
602
|
+
# a high-signal leak scan over the ADDED lines of the current diff (shared-skill
|
|
603
|
+
# markdown only). The private audit, when present above, stays the strongest /
|
|
604
|
+
# clean-landing R0 evidence; this fallback is public interim evidence only.
|
|
605
|
+
generic_r0_scan="$root/skills/skill-extraction-workflow/scripts/generic-r0-leak-scan.sh"
|
|
606
|
+
if [[ ! -f "$generic_r0_scan" ]]; then
|
|
607
|
+
echo "missing_generic_r0_leak_scan_script: $generic_r0_scan" >&2
|
|
608
|
+
exit 2
|
|
609
|
+
fi
|
|
610
|
+
# Run the matcher's own fixture self-test first (a broken detector must not be
|
|
611
|
+
# silently trusted), then the real diff scan. A leak hit blocks (exit 1).
|
|
612
|
+
if ! bash "$generic_r0_scan" --self-test >/dev/null; then
|
|
613
|
+
echo "generic_r0_leak_scan_self_test_failed: matcher self-test failed — blocking" >&2
|
|
614
|
+
exit 1
|
|
615
|
+
fi
|
|
616
|
+
if ! bash "$generic_r0_scan" "$root"; then
|
|
617
|
+
exit 1
|
|
618
|
+
fi
|
|
619
|
+
echo "alias_audit_unavailable: ALIAS_AUDIT_CMD unset; ran the generic public leak scan over added diff lines as the public R0 fallback. This permits interim commit/push/Draft MR, but is NOT private-alias clean-landing evidence — clean landing still requires alias_audit_ok, a named private profile, or an explicit risk-owner waiver (see skill-extraction-workflow/references/r0-leakage-audit.md)."
|
|
620
|
+
r0_clean_landing_status="public-fallback"
|
|
621
|
+
echo "r0_status=public-fallback"
|
|
622
|
+
fi
|
|
623
|
+
|
|
624
|
+
# Routing-skill existence check: when a route-like line points at another skill
|
|
625
|
+
# by name, verify the named skill directory exists at the top level of the skill
|
|
626
|
+
# tree. External skills must be allowed explicitly by the caller, not hard-coded
|
|
627
|
+
# here, so organization validation does not silently depend on one developer's local
|
|
628
|
+
# skill set. BLOCKING since 2026-08-02 (was warn-only advisory): a stale route
|
|
629
|
+
# fails the gate — a renamed/removed skill must never leave a live routing chain
|
|
630
|
+
# behind under a green CI.
|
|
631
|
+
route_check_rc=0
|
|
632
|
+
ruby -rset -rdigest -e '
|
|
633
|
+
begin
|
|
634
|
+
root = ARGV.fetch(0)
|
|
635
|
+
skills = Dir[File.join(root, "skills", "*", "SKILL.md")].map { |path| File.basename(File.dirname(path)) }.to_set
|
|
636
|
+
allowed_external = ENV.fetch("CCL_SKILL_ROUTE_ALLOWLIST", "").split(/[,\s]+/).reject(&:empty?).to_set
|
|
637
|
+
# Repo-internal vocabulary that is NOT a skill route: feature-risk-router risk
|
|
638
|
+
# tags. Only tags matching skillish_suffix can ever trip the check, but the
|
|
639
|
+
# whole tag set is listed so a future tag rename stays a one-line edit here.
|
|
640
|
+
# These are repo-wide vocabulary, so the exemption is unscoped.
|
|
641
|
+
# MUST stay in sync with the canonical tag list in
|
|
642
|
+
# skills/feature-risk-router/SKILL.md (the route-word saturation case in
|
|
643
|
+
# test_check_ccl_route_drift.sh fails when a mentioned tag is missing here).
|
|
644
|
+
risk_tags = %w[
|
|
645
|
+
visible-ui client-plumbing api-contract permission-access money-quota
|
|
646
|
+
write-finality ai-output ai-action genai-compliance data-migration
|
|
647
|
+
external-integration release-ops shared-gate security-review
|
|
648
|
+
verification-scope-unclear docs-only
|
|
649
|
+
].to_set
|
|
650
|
+
# Identifiers owned by ANOTHER namespace that happen to be route-shaped. Unlike
|
|
651
|
+
# risk tags these are only non-routes where their owning integration is being
|
|
652
|
+
# described, so each is scoped to the skill package that documents it: the same
|
|
653
|
+
# token elsewhere in the tree most likely IS someone routing to a skill that does
|
|
654
|
+
# not exist, which is exactly what this check exists to report.
|
|
655
|
+
# `ccl-review` is the agent OpenCode invokes (`agent.<name>.model`), so it is
|
|
656
|
+
# a non-route only inside the package that documents the OpenCode lane.
|
|
657
|
+
# `targeted-workflow` is one enum value of the source-map `coverage` column, so
|
|
658
|
+
# it is a non-route only inside the package that defines that column.
|
|
659
|
+
scoped_non_route_vocab = {
|
|
660
|
+
"ccl-review" => "skills/code-review/",
|
|
661
|
+
"targeted-workflow" => "skills/product-ui-ux-design/",
|
|
662
|
+
}
|
|
663
|
+
# Append-only ledger rows may legitimately name a renamed/removed skill as
|
|
664
|
+
# historical provenance: the ledger must never be edited, so a stale mention
|
|
665
|
+
# there has no legal fix and would otherwise hard-red the gate forever (same
|
|
666
|
+
# shape as register-firing-path-resolution EXEMPT). Keyed by [repo-relative
|
|
667
|
+
# path, token] with a per-key OCCURRENCE CAP: only the first N recorded
|
|
668
|
+
# historical mentions are exempt (the ledger is append-only, so the known
|
|
669
|
+
# mentions are always the earliest lines); any FURTHER occurrence of the same
|
|
670
|
+
# token in the same path — a NEW row routing to the dead name — blocks like
|
|
671
|
+
# any other stale route. The same token anywhere else also still blocks.
|
|
672
|
+
# Every entry needs a reason; applied exemptions are printed, never silent.
|
|
673
|
+
# Trust model: this table catches ACCIDENTAL drift (renames, dangling history,
|
|
674
|
+
# cap/count mismatch). A deliberate cap bump paired with a new mention is the
|
|
675
|
+
# same shape as the legitimate bump workflow — distinguishing them is intent,
|
|
676
|
+
# which no table inside the gated repo can adjudicate. Adversarial authorship
|
|
677
|
+
# is owned by the mandatory independent review (dual-track), with the printed
|
|
678
|
+
# exempt lines and the diff of this table itself as the reviewer-visible
|
|
679
|
+
# artifacts; machinery defending against the gated-repo author would defend
|
|
680
|
+
# against an adversary the trust model of this gate already excludes.
|
|
681
|
+
# Each entry pins the SHA-256 of every ledger LINE the waiver was written for, not
|
|
682
|
+
# a bare occurrence count. A count alone says "one row", never "WHICH row": delete
|
|
683
|
+
# the waived historical row and let a different row gain the same token and the
|
|
684
|
+
# count is still one, so the waiver silently transfers onto a brand-new stale route
|
|
685
|
+
# under a green gate (observed by applying that exact mutation — the exemption moved
|
|
686
|
+
# from register row 70 to a row appended 1100 lines later, rc=0, no block). Digests
|
|
687
|
+
# are stable under the append-only rule of the ledger (rows added elsewhere do not change
|
|
688
|
+
# a pinned line) and red on a rewrite with nobody having to touch code, which is what
|
|
689
|
+
# makes them worth having: the realistic failure is an accidental reflow or a
|
|
690
|
+
# repurposed row, not an author who edits both this table and the row to match. Same
|
|
691
|
+
# shape as EXEMPT_ROW_DIGESTS in register-firing-path-resolution.rb. Regenerate a
|
|
692
|
+
# digest only when the row itself legitimately changes, and say why in that commit.
|
|
693
|
+
exempt_historical_routes = {
|
|
694
|
+
["skills/skill-extraction-workflow/references/source-register.md", "claude-code-review"] =>
|
|
695
|
+
["legacy installed skill directory name recorded in append-only ledger history (register rows 959, 1153, and 1154); the live skill is code-review",
|
|
696
|
+
%w[
|
|
697
|
+
4099584cc48babbfbda07b828e42a8066cf4f1f3f7b4fe9898bc37fa872685df
|
|
698
|
+
9379f50564f42671e0f0a41fed83a2ab21d8ed64c73979fa0941da42b92d02eb
|
|
699
|
+
ed78f65c3a3e5fbfc185931eac40b2cbf06f71de7ead851dcf1ecaa1fb187f56
|
|
700
|
+
]],
|
|
701
|
+
["skills/skill-extraction-workflow/references/source-register.md", "resume-fit-evaluator"] =>
|
|
702
|
+
["recruitment-domain skill split out of this repo into common/hr-skills; the append-only ledger row (register row 70) records the org-screening-policy extraction that landed while it still lived here",
|
|
703
|
+
%w[88111b77874de4bb63822288861be00bd7a78beb51801946136c06dec1266a37]],
|
|
704
|
+
["skills/skill-extraction-workflow/references/source-register.md", "jd-writer"] =>
|
|
705
|
+
["recruitment-domain skill split out of this repo into common/hr-skills; the append-only ledger row (register row 808) is a provenance note recording why the artifact-egress gate scopes recruitment JDs out",
|
|
706
|
+
%w[dc4e874f9e430e711eb7c6909d2a3d876f650d1736a5d0100e09e91ced3750b0]],
|
|
707
|
+
}
|
|
708
|
+
exemption_seen = Hash.new { |h, k| h[k] = Hash.new(0) }
|
|
709
|
+
root_prefix = root.chomp("/") + "/"
|
|
710
|
+
repo_relative = lambda do |path|
|
|
711
|
+
path.start_with?(root_prefix) ? path[root_prefix.length..] : path
|
|
712
|
+
end
|
|
713
|
+
files = [File.join(root, "README.md")] + Dir[File.join(root, "skills", "*", "SKILL.md")] + Dir[File.join(root, "skills", "*", "references", "*.md")]
|
|
714
|
+
# The always-on routing layer is itself a routing surface: a renamed/removed
|
|
715
|
+
# skill otherwise leaves stale backticked routes in agent-context/session-start.md invisible to
|
|
716
|
+
# this check (observed gap: the layer had prose-only sync while README and
|
|
717
|
+
# SKILL.md/references were scanned).
|
|
718
|
+
files << File.join(root, "agent-context/session-start.md") if File.file?(File.join(root, "agent-context/session-start.md"))
|
|
719
|
+
route_words = /\b(route|routes|routing|owner|owners|ownership|belong|belongs|belonging|skill|skills|use|uses)\b|路由|负责|用|走|先|再|回到|实现|设计|→|->/i
|
|
720
|
+
skillish_suffix = /-(dev|workflow|strategy|design|architecture|diagnosis|router|review|rollout|observability|connectivity|integration|execution|evaluator|writer|doc)\z/
|
|
721
|
+
stale = []
|
|
722
|
+
exempted = []
|
|
723
|
+
allowlisted = []
|
|
724
|
+
cap_drift = false
|
|
725
|
+
files.each do |path|
|
|
726
|
+
next unless File.file?(path)
|
|
727
|
+
File.readlines(path, chomp: true).each_with_index do |line, idx|
|
|
728
|
+
next unless line.match?(route_words)
|
|
729
|
+
candidates = {}
|
|
730
|
+
# A skill route reference is recognized ONLY when the skill name is wrapped in
|
|
731
|
+
# backticks (the repo convention: skills are always written in backticks).
|
|
732
|
+
# Bare hyphenated prose, even beside an arrow (e.g. review then fix then
|
|
733
|
+
# re-review), is NOT treated as a route, so English compounds that happen to
|
|
734
|
+
# end in a skillish suffix do not produce false positives. A genuine stale
|
|
735
|
+
# route stays detectable because real route references are backtick-wrapped,
|
|
736
|
+
# including a mistyped or renamed name such as cross-platform-dev.
|
|
737
|
+
# (Keep this block apostrophe-free: it runs inside a single-quoted ruby -e.)
|
|
738
|
+
line.scan(/`([^`]+)`/).flatten.each { |token| candidates[token] ||= :backtick }
|
|
739
|
+
candidates.each do |candidate, source|
|
|
740
|
+
next if candidate.end_with?(".md") || candidate.include?("/")
|
|
741
|
+
next if candidate == "unresolved"
|
|
742
|
+
next if risk_tags.include?(candidate)
|
|
743
|
+
scope = scoped_non_route_vocab[candidate]
|
|
744
|
+
# Containment against the repo-relative path, never a substring of the
|
|
745
|
+
# absolute one: a checkout living under a directory that happens to spell
|
|
746
|
+
# the scope would otherwise exempt the token tree-wide.
|
|
747
|
+
next if scope && repo_relative.call(path).start_with?(scope)
|
|
748
|
+
looks_like_skill = candidate.match?(/\A[a-z][a-z0-9_-]*\z/) && candidate.include?("-")
|
|
749
|
+
next unless looks_like_skill
|
|
750
|
+
next if skills.include?(candidate)
|
|
751
|
+
next unless candidate.match?(skillish_suffix)
|
|
752
|
+
# The caller-controlled allowlist suppresses a block — so every genuine
|
|
753
|
+
# suppression is printed (an installed skill or a non-skill-shaped value
|
|
754
|
+
# in the allowlist prints nothing: it suppressed nothing). An invisible
|
|
755
|
+
# escape hatch on a blocking gate would let a one-line CI/env edit reach
|
|
756
|
+
# green while skipping the gate with no reviewer-visible artifact.
|
|
757
|
+
if allowed_external.include?(candidate)
|
|
758
|
+
allowlisted << [path, idx + 1, candidate]
|
|
759
|
+
next
|
|
760
|
+
end
|
|
761
|
+
exempt_key = [repo_relative.call(path), candidate]
|
|
762
|
+
exempt_entry = exempt_historical_routes[exempt_key]
|
|
763
|
+
# Identity AND multiplicity. Identity: the waiver applies to THIS line only
|
|
764
|
+
# when its digest is one the table pinned, so a different line carrying the
|
|
765
|
+
# same token is a live stale route no matter how many waived lines exist.
|
|
766
|
+
# Multiplicity: a digest is spent as many times as the table pins it and no
|
|
767
|
+
# more, because a byte-identical COPY of a waived line hashes the same and
|
|
768
|
+
# would otherwise ride the same pin for free.
|
|
769
|
+
line_digest = Digest::SHA256.hexdigest(line)
|
|
770
|
+
allowance = exempt_entry ? exempt_entry[1].count(line_digest) : 0
|
|
771
|
+
if allowance.positive? && (exemption_seen[exempt_key][line_digest] += 1) <= allowance
|
|
772
|
+
exempted << [path, idx + 1, candidate, exempt_entry[0]]
|
|
773
|
+
else
|
|
774
|
+
stale << [path, idx + 1, candidate]
|
|
775
|
+
end
|
|
776
|
+
end
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
# Digest-drift fail-closed: a pinned digest that no line matches means the RECORDED
|
|
780
|
+
# historical row was edited or removed (the append-only ledger forbids both) or a
|
|
781
|
+
# digest was added without a real row. A dead pin is a slot nothing occupies, and
|
|
782
|
+
# leaving it unreported would let the table claim coverage it no longer has.
|
|
783
|
+
# Zero observed mentions for an entry is NOT drift, unchanged from the count era:
|
|
784
|
+
# with nothing observed there is nothing being wrongly exempted, and a synthetic or
|
|
785
|
+
# foreign register (the fixtures several suites build) is outside a table that
|
|
786
|
+
# describes THIS ledger. KNOWN RESIDUAL, deliberately not closed here: delete the
|
|
787
|
+
# sole waived row outright and nothing is observed, nothing is stale, so an
|
|
788
|
+
# append-only deletion passes. Closing it needs the declared injection seam the
|
|
789
|
+
# sibling gate uses (production forces the built-in table, a fixture injects its
|
|
790
|
+
# own, injection is announced and downgrades the clean token) — that is ledger
|
|
791
|
+
# INTEGRITY work, a scope this repo already deferred when it mechanized only the
|
|
792
|
+
# waived rows, and it does not belong to a skill-package removal. What IS closed
|
|
793
|
+
# here is every axis the waiver entries themselves widen: a line whose digest is
|
|
794
|
+
# not pinned is a live stale route, never a free slot, and a copy beyond the
|
|
795
|
+
# pinned multiplicity lands there too.
|
|
796
|
+
exempt_historical_routes.each do |(exempt_path, token), (_reason, digests)|
|
|
797
|
+
seen = exemption_seen[[exempt_path, token]]
|
|
798
|
+
next if seen.empty?
|
|
799
|
+
missing = digests.tally.reject { |digest, count| seen[digest] >= count }
|
|
800
|
+
next if missing.empty?
|
|
801
|
+
next unless File.file?(File.join(root, exempt_path))
|
|
802
|
+
warn "route_existence_block: #{exempt_path} no longer contains the pinned historical line(s) for #{token.inspect} (unmatched digest(s): #{missing.keys.join(", ")}) — a recorded ledger row was edited/removed (append-only forbids both) or a digest was pinned without a real row; restore the history or regenerate the digest with a reason"
|
|
803
|
+
cap_drift = true
|
|
804
|
+
end
|
|
805
|
+
stale.each do |path, lineno, candidate|
|
|
806
|
+
warn "route_existence_block: #{path}:#{lineno} references #{candidate.inspect} but #{root}/#{candidate} is not a directory at the skill root"
|
|
807
|
+
end
|
|
808
|
+
exempted.each do |path, lineno, candidate, reason|
|
|
809
|
+
puts "route_existence_exempt: #{path}:#{lineno} references #{candidate.inspect} — exempt: #{reason}"
|
|
810
|
+
end
|
|
811
|
+
allowlisted.each do |path, lineno, candidate|
|
|
812
|
+
puts "route_existence_allowlisted: #{path}:#{lineno} references #{candidate.inspect} — suppressed via CCL_SKILL_ROUTE_ALLOWLIST (visible, never silent)"
|
|
813
|
+
end
|
|
814
|
+
if stale.any?
|
|
815
|
+
puts "route_existence_check: #{stale.length} stale route reference(s) above — blocking; update the reference, restore the renamed skill, or allowlist a genuine external skill via CCL_SKILL_ROUTE_ALLOWLIST"
|
|
816
|
+
end
|
|
817
|
+
exit(stale.empty? && !cap_drift ? 0 : 1)
|
|
818
|
+
rescue StandardError, ScriptError => e
|
|
819
|
+
warn "route_existence_check_error: #{e.class.name}: #{e.message.lines.first.to_s.strip}"
|
|
820
|
+
exit 2
|
|
821
|
+
end
|
|
822
|
+
' "$root" || route_check_rc=$?
|
|
823
|
+
case "$route_check_rc" in
|
|
824
|
+
0|1) : ;;
|
|
825
|
+
*) echo "route_existence_check_infra_failed rc=$route_check_rc (route-drift scan could not run — fail-closed)" >&2; exit 2 ;;
|
|
826
|
+
esac
|
|
827
|
+
echo "route_existence_check_done"
|
|
828
|
+
echo "bootstrap_route_scan: $([ -f "$root/agent-context/session-start.md" ] && echo covered || echo skipped-missing)"
|
|
829
|
+
|
|
830
|
+
# Cross-skill .md reference existence check: when a reference points at
|
|
831
|
+
# another .md file (e.g. `../product-ui-ux-design/references/foo.md`,
|
|
832
|
+
# `product-ui-ux-design/references/foo.md`, or `references/foo.md`), verify
|
|
833
|
+
# the target file actually exists. A rename or removal of the target file
|
|
834
|
+
# otherwise breaks the routing chain silently. BLOCKING since 2026-08-02 (was
|
|
835
|
+
# warn-only advisory): a broken reference fails the gate.
|
|
836
|
+
# Append-only ledger rows may legitimately cite a renamed/removed references
|
|
837
|
+
# file as historical provenance (the ledger must never be edited, so a stale
|
|
838
|
+
# citation there has no legal fix). Exemptions key on "<repo-relative path>
|
|
839
|
+
# <cited ref>": anything else still blocks. Empty today — add an entry with a
|
|
840
|
+
# reason only when a real rename creates the collision; applied exemptions
|
|
841
|
+
# are printed, never silent.
|
|
842
|
+
md_ref_exempt() {
|
|
843
|
+
case "$1" in
|
|
844
|
+
*) return 1 ;;
|
|
845
|
+
esac
|
|
846
|
+
}
|
|
847
|
+
md_ref_broken=0
|
|
848
|
+
bootstrap_arg=()
|
|
849
|
+
if [ -f "$root/agent-context/session-start.md" ]; then
|
|
850
|
+
bootstrap_arg=("$root/agent-context/session-start.md")
|
|
851
|
+
bootstrap_scan_state="covered"
|
|
852
|
+
else
|
|
853
|
+
bootstrap_scan_state="skipped-missing"
|
|
854
|
+
fi
|
|
855
|
+
rg_err_tmp="$(mktemp "${TMPDIR:-/tmp}/mdref-rg-err.XXXXXX")" || { echo "md_reference_scan_error: mktemp failed" >&2; exit 1; }
|
|
856
|
+
rg_rc=0
|
|
857
|
+
rg_out="$(rg -n '`(\.\./)?[a-z][a-z0-9_-]*(/references)?/[a-z][a-z0-9_./-]+\.md`' "$root"/skills/*/references/*.md "$root"/skills/*/SKILL.md "${bootstrap_arg[@]+"${bootstrap_arg[@]}"}" 2>"$rg_err_tmp")" || rg_rc=$?
|
|
858
|
+
if [ "$rg_rc" -gt 1 ] && [ -z "$rg_out" ]; then
|
|
859
|
+
cat "$rg_err_tmp" >&2
|
|
860
|
+
echo "md_reference_scan_error: rg exited $rg_rc with no usable output" >&2
|
|
861
|
+
rm -f "$rg_err_tmp"
|
|
862
|
+
exit 1
|
|
863
|
+
fi
|
|
864
|
+
if [ -z "$rg_out" ]; then
|
|
865
|
+
# Zero candidates: this repo always carries at least one <pkg>/references/*.md
|
|
866
|
+
# citation, so an empty stream means the scan broke (glob/pattern/path
|
|
867
|
+
# regression), not that there is nothing to check.
|
|
868
|
+
echo "md_reference_scan_error: zero candidate lines" >&2
|
|
869
|
+
rm -f "$rg_err_tmp"
|
|
870
|
+
exit 1
|
|
871
|
+
fi
|
|
872
|
+
if [ "$rg_rc" -gt 1 ]; then
|
|
873
|
+
# rg exits 2 on hard errors AND on partial failures (an unreadable file or a
|
|
874
|
+
# broken glob): with partial failures it still prints usable matches, so only
|
|
875
|
+
# an EMPTY result is a scan failure worth blocking every downstream gate for.
|
|
876
|
+
echo "md_reference_scan_partial: rg exited $rg_rc; continuing with the matched subset:" >&2
|
|
877
|
+
cat "$rg_err_tmp" >&2
|
|
878
|
+
bootstrap_scan_state="partial-unverified"
|
|
879
|
+
fi
|
|
880
|
+
rm -f "$rg_err_tmp"
|
|
881
|
+
while IFS=: read -r path lineno match; do
|
|
882
|
+
[[ -z "$match" ]] && continue
|
|
883
|
+
ref=$(echo "$match" | sed -nE 's|.*`((\.\./)?([a-z][a-z0-9_-]+/)?references/[a-z][a-z0-9_./-]+\.md)`.*|\1|p')
|
|
884
|
+
[[ -z "$ref" ]] && continue
|
|
885
|
+
if [[ "$ref" == ../* ]]; then
|
|
886
|
+
candidate="$root/skills/${ref#../}"
|
|
887
|
+
elif [[ "$ref" == */references/* && "$ref" != references/* ]]; then
|
|
888
|
+
candidate="$root/skills/$ref"
|
|
889
|
+
else
|
|
890
|
+
calling_skill=$(echo "$path" | sed -nE "s|^$root/skills/([^/]+)/.*|\1|p")
|
|
891
|
+
candidate="$root/skills/$calling_skill/$ref"
|
|
892
|
+
fi
|
|
893
|
+
if [[ ! -f "$candidate" ]]; then
|
|
894
|
+
# Normalize to the repo-relative key form the exemption table uses: strip
|
|
895
|
+
# the root prefix, then a defensive leading "./" (root="." CI shape).
|
|
896
|
+
path_rel="${path#"${root%/}/"}"
|
|
897
|
+
path_rel="${path_rel#./}"
|
|
898
|
+
if md_ref_exempt "$path_rel $ref"; then
|
|
899
|
+
echo "md_reference_exempt: $path:$lineno cites \`$ref\` — exempt (append-only historical citation)"
|
|
900
|
+
else
|
|
901
|
+
echo "md_reference_block: $path:$lineno cites \`$ref\` but $candidate does not exist" >&2
|
|
902
|
+
md_ref_broken=$((md_ref_broken + 1))
|
|
903
|
+
fi
|
|
904
|
+
fi
|
|
905
|
+
done <<< "$rg_out"
|
|
906
|
+
if [[ "$md_ref_broken" -gt 0 ]]; then
|
|
907
|
+
echo "md_reference_check: $md_ref_broken broken .md reference(s) above — blocking; a routed-to file was renamed or removed, update the citation or restore the target"
|
|
908
|
+
fi
|
|
909
|
+
echo "md_reference_check_done"
|
|
910
|
+
if [ "$bootstrap_scan_state" = "covered" ]; then
|
|
911
|
+
bootstrap_ref_hits="$(printf '%s\n' "$rg_out" | grep -cF "$root/agent-context/session-start.md:" || true)"
|
|
912
|
+
echo "bootstrap_scan: covered refs=$bootstrap_ref_hits"
|
|
913
|
+
else
|
|
914
|
+
echo "bootstrap_scan: $bootstrap_scan_state"
|
|
915
|
+
fi
|
|
916
|
+
# The two sync checks above are BLOCKING but their exit verdict is deferred to
|
|
917
|
+
# just after the impact-chain / register gates (search: sync_reference_blocking_failed)
|
|
918
|
+
# so one run shows THOSE gates' diagnostics alongside the sync violations. Later
|
|
919
|
+
# sections (eval-routing, size gate, final tokens) keep the script's fail-fast
|
|
920
|
+
# per-section shape: a sync failure exits before them by design.
|
|
921
|
+
# Structural guard for the deferral: no earlier exit path (including a future
|
|
922
|
+
# early-return added to an intervening section) may drop a pending sync
|
|
923
|
+
# verdict. The guard fires ONLY when the process is exiting 0 with violations
|
|
924
|
+
# pending — the explicit verdict below and every non-zero exit pass through
|
|
925
|
+
# silently with their original status.
|
|
926
|
+
sync_verdict_guard() {
|
|
927
|
+
_guard_rc=$?
|
|
928
|
+
if [ "$_guard_rc" -eq 0 ] && { [ "$route_check_rc" -eq 1 ] || [ "$md_ref_broken" -gt 0 ] || [ "${sync_pointer_rc:-0}" -eq 1 ]; }; then
|
|
929
|
+
echo "sync_reference_blocking_failed: stale route reference(s) and/or broken .md reference(s) and/or semantic sync registry violation(s) above block the gate (reached via an early-exit path; blocking since 2026-08-02)" >&2
|
|
930
|
+
exit 1
|
|
931
|
+
fi
|
|
932
|
+
exit "$_guard_rc"
|
|
933
|
+
}
|
|
934
|
+
trap sync_verdict_guard EXIT
|
|
935
|
+
|
|
936
|
+
# Semantic tier of the sync family (C-1): declared pinned pairs (always-on
|
|
937
|
+
# pointer literals AND their canonical anchors) plus the security-four-questions
|
|
938
|
+
# predicate-subset registry. Same blocking strength as the syntactic tier; its
|
|
939
|
+
# verdict joins the deferred combined verdict below. The gate program resolves
|
|
940
|
+
# NEXT TO THIS VALIDATOR (never from the judged tree — an in-tree copy could be
|
|
941
|
+
# doctored to `exit 0`), following the impact-chain gate's one-versioned-unit
|
|
942
|
+
# rule. The output is captured so a marked skip (missing agent-context/session-start.md /
|
|
943
|
+
# package) downgrades the final clean token — a skip must never read as a
|
|
944
|
+
# clean full evaluation.
|
|
945
|
+
sync_pointer_rc=0
|
|
946
|
+
sync_pointer_out=""
|
|
947
|
+
sync_pointer_err=""
|
|
948
|
+
sync_pointer_skipped=0
|
|
949
|
+
if [[ -z "${checker_scripts_dir:-}" ]]; then
|
|
950
|
+
if ! checker_scripts_dir="$(resolve_checker_scripts_dir "${BASH_SOURCE[0]}")"; then
|
|
951
|
+
checker_scripts_dir=""
|
|
952
|
+
echo "sync_pointer_infra_failed: could not resolve the validator script directory from ${BASH_SOURCE[0]}" >&2
|
|
953
|
+
exit 2
|
|
954
|
+
fi
|
|
955
|
+
fi
|
|
956
|
+
sync_pointer_script="$checker_scripts_dir/check-sync-pointers.sh"
|
|
957
|
+
if [[ -L "$sync_pointer_script" || ! -f "$sync_pointer_script" ]]; then
|
|
958
|
+
echo "sync_pointer_infra_failed: check-sync-pointers.sh missing or not a regular file beside the validator: $sync_pointer_script" >&2
|
|
959
|
+
exit 2
|
|
960
|
+
fi
|
|
961
|
+
sync_pointer_err_tmp="$(mktemp "${TMPDIR:-/tmp}/sync-pointer-err.XXXXXX")" || { echo "sync_pointer_infra_failed: mktemp failed" >&2; exit 2; }
|
|
962
|
+
sync_pointer_out="$(bash "$sync_pointer_script" "$root" 2>"$sync_pointer_err_tmp")" || sync_pointer_rc=$?
|
|
963
|
+
sync_pointer_err="$(cat "$sync_pointer_err_tmp")"
|
|
964
|
+
rm -f "$sync_pointer_err_tmp"
|
|
965
|
+
# Replay on the original channels: markers to stdout, diagnostics to stderr.
|
|
966
|
+
printf '%s\n' "$sync_pointer_out"
|
|
967
|
+
[ -n "$sync_pointer_err" ] && printf '%s\n' "$sync_pointer_err" >&2
|
|
968
|
+
if [ "$sync_pointer_rc" -ne 0 ] && [ "$sync_pointer_rc" -ne 1 ]; then
|
|
969
|
+
echo "sync_pointer_infra_failed rc=$sync_pointer_rc (semantic sync gate could not run — fail-closed)" >&2
|
|
970
|
+
exit 2
|
|
971
|
+
fi
|
|
972
|
+
case "$sync_pointer_out" in
|
|
973
|
+
*check_skipped*) sync_pointer_skipped=1 ;;
|
|
974
|
+
esac
|
|
975
|
+
|
|
976
|
+
# Shared process gates that are easy to weaken by updating only an entrypoint
|
|
977
|
+
# while leaving the default template or retrospective reference with old exits.
|
|
978
|
+
project_assessment_template="$root/skills/product-rd-workflow/references/existing-project-assessment-report.md"
|
|
979
|
+
if [[ ! -f "$project_assessment_template" ]]; then
|
|
980
|
+
echo "project_assessment_template_missing: $project_assessment_template" >&2
|
|
981
|
+
exit 1
|
|
982
|
+
fi
|
|
983
|
+
for required_phrase in \
|
|
984
|
+
"Assessment launch checklist" \
|
|
985
|
+
"product/user paths" \
|
|
986
|
+
"architecture/implementation owners" \
|
|
987
|
+
"test-layer matrix owner" \
|
|
988
|
+
"UI/UX surfaces" \
|
|
989
|
+
"runtime/host evidence surface" \
|
|
990
|
+
"unavailable/live/manual boundaries" \
|
|
991
|
+
"extraction/learning trigger" \
|
|
992
|
+
"Closeout outputs" \
|
|
993
|
+
"project findings or fixes" \
|
|
994
|
+
"verification evidence by layer" \
|
|
995
|
+
"issue/risk registration" \
|
|
996
|
+
"reusable-process disposition"; do
|
|
997
|
+
if ! rg -qF "$required_phrase" "$project_assessment_template"; then
|
|
998
|
+
echo "project_assessment_template_gate_missing: $required_phrase" >&2
|
|
999
|
+
exit 1
|
|
1000
|
+
fi
|
|
1001
|
+
done
|
|
1002
|
+
echo "project_assessment_template_gate_ok"
|
|
1003
|
+
|
|
1004
|
+
skill_extraction_entry="$root/skills/skill-extraction-workflow/SKILL.md"
|
|
1005
|
+
task_retro_reference="$root/skills/skill-extraction-workflow/references/source-to-skill-extraction.md"
|
|
1006
|
+
if [[ ! -f "$skill_extraction_entry" ]]; then
|
|
1007
|
+
echo "skill_extraction_entry_missing: $skill_extraction_entry" >&2
|
|
1008
|
+
exit 1
|
|
1009
|
+
fi
|
|
1010
|
+
if [[ ! -f "$task_retro_reference" ]]; then
|
|
1011
|
+
echo "task_retro_reference_missing: $task_retro_reference" >&2
|
|
1012
|
+
exit 1
|
|
1013
|
+
fi
|
|
1014
|
+
for required_phrase in \
|
|
1015
|
+
"would other teammates hit this" \
|
|
1016
|
+
"will we forget next time" \
|
|
1017
|
+
"teamwide recurrence" \
|
|
1018
|
+
"reusable routing/process/team failure" \
|
|
1019
|
+
"memory-only landing as insufficient"; do
|
|
1020
|
+
if ! rg -qF "$required_phrase" "$skill_extraction_entry"; then
|
|
1021
|
+
echo "skill_extraction_teammate_trigger_gate_missing: $required_phrase" >&2
|
|
1022
|
+
exit 1
|
|
1023
|
+
fi
|
|
1024
|
+
done
|
|
1025
|
+
for required_phrase in \
|
|
1026
|
+
"shared-skill vs memory-only boundary" \
|
|
1027
|
+
"not a reusable process, routing, testing, design, review, or teamwide failure" \
|
|
1028
|
+
"Do not classify reusable process defects" \
|
|
1029
|
+
"others will hit this too" \
|
|
1030
|
+
"shared skill/reference/validator/checklist/project-template landing"; do
|
|
1031
|
+
if ! rg -qF "$required_phrase" "$task_retro_reference"; then
|
|
1032
|
+
echo "task_retro_memory_escape_gate_missing: $required_phrase" >&2
|
|
1033
|
+
exit 1
|
|
1034
|
+
fi
|
|
1035
|
+
done
|
|
1036
|
+
echo "task_retro_memory_escape_gate_ok"
|
|
1037
|
+
|
|
1038
|
+
testing_strategy_entry="$root/skills/testing-strategy/SKILL.md"
|
|
1039
|
+
product_rd_entry="$root/skills/product-rd-workflow/SKILL.md"
|
|
1040
|
+
if [[ ! -f "$testing_strategy_entry" ]]; then
|
|
1041
|
+
echo "testing_strategy_entry_missing: $testing_strategy_entry" >&2
|
|
1042
|
+
exit 1
|
|
1043
|
+
fi
|
|
1044
|
+
if [[ ! -f "$product_rd_entry" ]]; then
|
|
1045
|
+
echo "product_rd_entry_missing: $product_rd_entry" >&2
|
|
1046
|
+
exit 1
|
|
1047
|
+
fi
|
|
1048
|
+
for required_phrase in \
|
|
1049
|
+
"先写测试用例" \
|
|
1050
|
+
"test cases first" \
|
|
1051
|
+
"test-case register first" \
|
|
1052
|
+
"expected current result" \
|
|
1053
|
+
"RED-before-implementation rule" \
|
|
1054
|
+
"run RED before implementation" \
|
|
1055
|
+
"Do not answer \"tests are complete\" from command output alone"; do
|
|
1056
|
+
if ! rg -qF "$required_phrase" "$testing_strategy_entry"; then
|
|
1057
|
+
echo "testing_strategy_test_case_first_gate_missing: $required_phrase" >&2
|
|
1058
|
+
exit 1
|
|
1059
|
+
fi
|
|
1060
|
+
done
|
|
1061
|
+
for required_phrase in \
|
|
1062
|
+
"test-case register" \
|
|
1063
|
+
"test-case-first is the default gate" \
|
|
1064
|
+
"run it RED before coding" \
|
|
1065
|
+
"not applicable: behavior-neutral/docs/config-only" \
|
|
1066
|
+
"do not claim TDD"; do
|
|
1067
|
+
if ! rg -qF "$required_phrase" "$product_rd_entry"; then
|
|
1068
|
+
echo "product_rd_test_case_first_gate_missing: $required_phrase" >&2
|
|
1069
|
+
exit 1
|
|
1070
|
+
fi
|
|
1071
|
+
done
|
|
1072
|
+
# Product-rd entrypoint semantic-anchor gate: a targeted, non-comprehensive
|
|
1073
|
+
# backstop for B0 entrypoint slimming. It protects high-risk semantic phrases and
|
|
1074
|
+
# section anchors; full semantic-control still requires the B0 checklist,
|
|
1075
|
+
# behavioral evidence, and dual-track review. Intentional replacements should
|
|
1076
|
+
# update this list in the same MR.
|
|
1077
|
+
for required_phrase in \
|
|
1078
|
+
"Implementation entry / re-entry gate" \
|
|
1079
|
+
"context summaries, compacted memory, and previous-response residue are not establishment" \
|
|
1080
|
+
"Reaching the first implementation edit without this boundary record is a process defect" \
|
|
1081
|
+
"High-risk resilience gating: when a feature touches money" \
|
|
1082
|
+
"Diagnostic spec-match baseline gate" \
|
|
1083
|
+
"do NOT treat the user's single-utterance description as the authoritative spec" \
|
|
1084
|
+
"Owner-dispatch firing gate" \
|
|
1085
|
+
"START of design-substance production, not only design completion" \
|
|
1086
|
+
"this workflow classifies the artifact before implementation" \
|
|
1087
|
+
"### Pre-Final Continuation Gate" \
|
|
1088
|
+
"Run this gate before finalizing a product R&D turn after any delivery slice lands" \
|
|
1089
|
+
"fetch/update the target ref from its remote immediately before classifying the slice landed" \
|
|
1090
|
+
'Deferred-evidence continuation check (`DFE-CONT`)' \
|
|
1091
|
+
"Report deferred real evidence as" \
|
|
1092
|
+
"Stop only for an explicit stop/pause instruction" \
|
|
1093
|
+
"Do not send a completion-only, solved, fixed, or fully-closed final response" \
|
|
1094
|
+
"### Feature Deprecation" \
|
|
1095
|
+
'A deprecation slice is `complete` only when steps'; do
|
|
1096
|
+
if rg -qF "$required_phrase" "$product_rd_entry"; then
|
|
1097
|
+
continue
|
|
1098
|
+
else
|
|
1099
|
+
rg_status=$?
|
|
1100
|
+
if [[ "$rg_status" -eq 1 ]]; then
|
|
1101
|
+
echo "product_rd_entrypoint_anchor_gate_missing: $required_phrase" >&2
|
|
1102
|
+
echo "fix: keep the stable anchor in product-rd-workflow/SKILL.md, or update this gate in the same MR when intentionally replacing the anchor" >&2
|
|
1103
|
+
exit 1
|
|
1104
|
+
fi
|
|
1105
|
+
echo "product_rd_entrypoint_anchor_gate_scan_error: rg exited $rg_status while checking $required_phrase" >&2
|
|
1106
|
+
exit 1
|
|
1107
|
+
fi
|
|
1108
|
+
done
|
|
1109
|
+
echo "product_rd_entrypoint_anchor_gate_ok"
|
|
1110
|
+
for required_phrase in \
|
|
1111
|
+
"Test-case register before fixes/tests" \
|
|
1112
|
+
"RED/pass-existing/blocked/gap status" \
|
|
1113
|
+
"Running test commands before writing the test-case register"; do
|
|
1114
|
+
if ! rg -qF "$required_phrase" "$project_assessment_template"; then
|
|
1115
|
+
echo "project_assessment_test_case_first_gate_missing: $required_phrase" >&2
|
|
1116
|
+
exit 1
|
|
1117
|
+
fi
|
|
1118
|
+
done
|
|
1119
|
+
for required_phrase in \
|
|
1120
|
+
"tests were run before test cases" \
|
|
1121
|
+
'target-output map must include `testing-strategy`' \
|
|
1122
|
+
'coordinating workflow such as `product-rd-workflow`' \
|
|
1123
|
+
"durable test-case-first prevention rule"; do
|
|
1124
|
+
if ! rg -qF "$required_phrase" "$skill_extraction_entry"; then
|
|
1125
|
+
echo "skill_extraction_test_case_first_gate_missing: $required_phrase" >&2
|
|
1126
|
+
exit 1
|
|
1127
|
+
fi
|
|
1128
|
+
done
|
|
1129
|
+
echo "test_case_first_gate_ok"
|
|
1130
|
+
|
|
1131
|
+
# Post-cleanup register check: after a project-specific extraction batch is
|
|
1132
|
+
# migrated out of the shared skill tree, the source-register.md template must
|
|
1133
|
+
# not silently grow new project-specific dated entries. The rule in
|
|
1134
|
+
# skill-extraction-workflow/SKILL.md (Extraction lifecycle handoff) forbids
|
|
1135
|
+
# adding new project-specific provenance to that file. This check enforces it.
|
|
1136
|
+
if [[ -f "$root/skills/skill-extraction-workflow/references/source-register.md" ]]; then
|
|
1137
|
+
ct_count=$(rg -c "^## Current Task:" "$root/skills/skill-extraction-workflow/references/source-register.md" 2>/dev/null || echo 0)
|
|
1138
|
+
if [[ "$ct_count" -gt 0 ]]; then
|
|
1139
|
+
echo "warn_project_specific_register_entries: skill-extraction-workflow/references/source-register.md contains $ct_count '## Current Task:' section(s); per the Extraction lifecycle handoff rule, project-specific dated entries must live in the private alias archive, not in the shared skill tree" >&2
|
|
1140
|
+
echo "post_cleanup_register_pattern_failed"
|
|
1141
|
+
exit 1
|
|
1142
|
+
fi
|
|
1143
|
+
echo "post_cleanup_register_pattern_ok"
|
|
1144
|
+
fi
|
|
1145
|
+
|
|
1146
|
+
# `--is-inside-work-tree` alone is not the right predicate: an exported copy
|
|
1147
|
+
# unpacked INSIDE some other checkout answers `true`, and every gate below would
|
|
1148
|
+
# then adjudicate that enclosing repository's git state while reading $root's
|
|
1149
|
+
# files — the wrong tree, reported as a clean landing. Require $root to be the
|
|
1150
|
+
# work tree's own top level, so a nested export takes the interim branch with a
|
|
1151
|
+
# real non-git export.
|
|
1152
|
+
root_worktree_toplevel=""
|
|
1153
|
+
if git -C "$root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
1154
|
+
if git_toplevel_raw="$(git -C "$root" rev-parse --show-toplevel 2>/dev/null)" \
|
|
1155
|
+
&& [ -n "$git_toplevel_raw" ] && [ -d "$git_toplevel_raw" ]; then
|
|
1156
|
+
# Normalize both sides: $root may be given with symlinked or relative
|
|
1157
|
+
# components, and a textual comparison against git's physical path would
|
|
1158
|
+
# false-negative a legitimate repository root.
|
|
1159
|
+
root_physical="$(cd "$root" 2>/dev/null && pwd -P)" || root_physical=""
|
|
1160
|
+
toplevel_physical="$(cd "$git_toplevel_raw" 2>/dev/null && pwd -P)" || toplevel_physical=""
|
|
1161
|
+
if [ -n "$root_physical" ] && [ "$root_physical" = "$toplevel_physical" ]; then
|
|
1162
|
+
root_worktree_toplevel="$toplevel_physical"
|
|
1163
|
+
fi
|
|
1164
|
+
fi
|
|
1165
|
+
fi
|
|
1166
|
+
|
|
1167
|
+
if [ -n "$root_worktree_toplevel" ]; then
|
|
1168
|
+
# The gate program lives beside this checker (impact-chain-gate.rb) and is
|
|
1169
|
+
# resolved from THIS script's directory, not from $root: the checker and the
|
|
1170
|
+
# gate are one versioned unit, and a harness pointing CHECK_SCRIPT_UNDER_TEST
|
|
1171
|
+
# at a working-tree checker must exercise the same working-tree gate rather
|
|
1172
|
+
# than a stale committed copy inside the target repo.
|
|
1173
|
+
# Resolve file- and directory-level symlinks once so every checker-adjacent
|
|
1174
|
+
# helper comes from the same versioned script directory.
|
|
1175
|
+
if ! checker_scripts_dir="$(resolve_checker_scripts_dir "${BASH_SOURCE[0]}")"; then
|
|
1176
|
+
echo "missing_impact_chain_gate: could not resolve checker script directory from ${BASH_SOURCE[0]}" >&2
|
|
1177
|
+
exit 2
|
|
1178
|
+
fi
|
|
1179
|
+
impact_chain_gate="$checker_scripts_dir/impact-chain-gate.rb"
|
|
1180
|
+
if [[ -L "$impact_chain_gate" || ! -f "$impact_chain_gate" ]]; then
|
|
1181
|
+
echo "missing_impact_chain_gate: $impact_chain_gate (must be a regular file beside the checker, not a symlink)" >&2
|
|
1182
|
+
exit 2
|
|
1183
|
+
fi
|
|
1184
|
+
ruby "$impact_chain_gate" "$root"
|
|
1185
|
+
|
|
1186
|
+
# Whole-ledger firing-path resolution. The impact-chain gate above is
|
|
1187
|
+
# diff-scoped by design, so a row's firing path is machine-checked exactly once
|
|
1188
|
+
# — at the commit that added it. Nothing re-checks it afterwards, while the
|
|
1189
|
+
# prose it anchors into stays living text, so a later move/reword of an
|
|
1190
|
+
# anchored rule silently voids that row's firing evidence with every gate
|
|
1191
|
+
# green. This one re-resolves every locator in the ledger, historical rows
|
|
1192
|
+
# included.
|
|
1193
|
+
firing_path_gate="$checker_scripts_dir/register-firing-path-resolution.rb"
|
|
1194
|
+
if [[ -L "$firing_path_gate" || ! -f "$firing_path_gate" ]]; then
|
|
1195
|
+
echo "missing_register_firing_path_gate: $firing_path_gate (must be a regular file beside the checker, not a symlink)" >&2
|
|
1196
|
+
exit 2
|
|
1197
|
+
fi
|
|
1198
|
+
# Consumption is a symmetric contract: a clean rc must pair with the gate's
|
|
1199
|
+
# clean terminal line. A bare call site cannot tell a real clean run from a
|
|
1200
|
+
# gate that died quietly (a crash where `set -e` is disarmed, a reworded
|
|
1201
|
+
# token, an early `exit 0`) — both arrive as rc=0, and the checker would
|
|
1202
|
+
# certify a gate that adjudicated nothing. The rc is captured without early
|
|
1203
|
+
# exit so the gate's own diagnostics still reach the log on every tier.
|
|
1204
|
+
# stdout and stderr are captured SEPARATELY. Merging them makes the terminal
|
|
1205
|
+
# line unlocatable: with `2>&1` any stderr write can land after the gate's
|
|
1206
|
+
# final puts, so the check can only ask "does some line carry the token",
|
|
1207
|
+
# which a gate that printed its token and then died silently also satisfies.
|
|
1208
|
+
# Split streams let the contract be "the LAST non-empty stdout line is the
|
|
1209
|
+
# token", which that failure cannot meet.
|
|
1210
|
+
# One checked directory plus a trap, not two bare `mktemp`s: an unchecked
|
|
1211
|
+
# mktemp failure exits with whatever rc it happened to have (typically 1,
|
|
1212
|
+
# indistinguishable from an adjudicated ledger violation) and a second failure
|
|
1213
|
+
# would leak the first file. A signal mid-run would leak both.
|
|
1214
|
+
if ! fp_tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/firingpath.XXXXXX")"; then
|
|
1215
|
+
echo "register_firing_path_gate_failed: could not create a temporary directory for the gate's output (infrastructure failure, not an adjudicated ledger violation)" >&2
|
|
1216
|
+
exit 2
|
|
1217
|
+
fi
|
|
1218
|
+
# COMPOSE with the script-level EXIT trap, never replace it: `sync_verdict_guard`
|
|
1219
|
+
# is armed above and converts a would-be rc=0 early exit into the deferred sync
|
|
1220
|
+
# verdict. A bare `trap ... EXIT` here would silently disarm it for the rest of
|
|
1221
|
+
# the checker, and a bare `trap - EXIT` afterwards would leave it disarmed all
|
|
1222
|
+
# the way to its own teardown — harmless only for as long as every exit in that
|
|
1223
|
+
# span happens to be non-zero, which is not a property anyone editing later
|
|
1224
|
+
# would know they have to preserve.
|
|
1225
|
+
# Capture `$?` FIRST and restore it before delegating: `rm -rf` succeeds and
|
|
1226
|
+
# overwrites the pending status with 0, so a naive `rm; sync_verdict_guard`
|
|
1227
|
+
# makes the guard read 0 and `exit 0` — turning this block's `exit 2` for a
|
|
1228
|
+
# failed output read into a silent success while the trap is armed.
|
|
1229
|
+
trap 'fp_trap_rc=$?; rm -rf "${fp_tmp_dir:-}"; (exit "$fp_trap_rc"); sync_verdict_guard' EXIT
|
|
1230
|
+
ruby "$firing_path_gate" "$root" >"$fp_tmp_dir/out" 2>"$fp_tmp_dir/err" && fp_rc=0 || fp_rc=$?
|
|
1231
|
+
if ! firing_path_out="$(cat "$fp_tmp_dir/out")" || ! firing_path_err="$(cat "$fp_tmp_dir/err")"; then
|
|
1232
|
+
echo "register_firing_path_gate_failed: could not read back the gate's captured output (infrastructure failure, not an adjudicated ledger violation)" >&2
|
|
1233
|
+
exit 2
|
|
1234
|
+
fi
|
|
1235
|
+
rm -rf "$fp_tmp_dir"
|
|
1236
|
+
trap sync_verdict_guard EXIT
|
|
1237
|
+
# Not a bare AND-list: under `set -e` an empty-success print would abort the
|
|
1238
|
+
# checker unexplained. Diagnostics always replay to stderr (CI scrapes stderr
|
|
1239
|
+
# for causes); the contract checks below read the captured strings.
|
|
1240
|
+
[ -n "$firing_path_err" ] && printf '%s\n' "$firing_path_err" >&2
|
|
1241
|
+
if [ -n "$firing_path_out" ]; then
|
|
1242
|
+
if [ "$fp_rc" -eq 0 ]; then
|
|
1243
|
+
printf '%s\n' "$firing_path_out"
|
|
1244
|
+
else
|
|
1245
|
+
printf '%s\n' "$firing_path_out" >&2
|
|
1246
|
+
fi
|
|
1247
|
+
fi
|
|
1248
|
+
if [ "$fp_rc" -ne 0 ]; then
|
|
1249
|
+
# A non-zero rc alone does not say WHICH tier failed. The gate reports a
|
|
1250
|
+
# ledger violation by naming it; a Ruby syntax error, an uncaught exception,
|
|
1251
|
+
# or a silent `exit 1` also arrive as rc=1 with no such diagnostic, and
|
|
1252
|
+
# forwarding that as rc=1 tells CI "the ledger is wrong" when the truth is
|
|
1253
|
+
# "the gate did not run". Only a diagnosed rc=1 stays a rule failure.
|
|
1254
|
+
if [ "$fp_rc" -eq 1 ] \
|
|
1255
|
+
&& grep -qE '^register_firing_path_(malformed|unresolved)' <<<"$firing_path_err"; then
|
|
1256
|
+
exit 1
|
|
1257
|
+
fi
|
|
1258
|
+
echo "register_firing_path_gate_failed: gate exited $fp_rc without a register_firing_path_malformed/unresolved diagnostic (gate malfunction or infrastructure failure, not an adjudicated ledger violation)" >&2
|
|
1259
|
+
exit 2
|
|
1260
|
+
fi
|
|
1261
|
+
# The token must be the LAST non-empty stdout line and be complete.
|
|
1262
|
+
# - last line, not any line: a gate that prints its token and then dies on a
|
|
1263
|
+
# later path would otherwise still read as clean.
|
|
1264
|
+
# - whole-line anchored: an unanchored fragment also accepts the truncated
|
|
1265
|
+
# line a gate crashing mid-print emits.
|
|
1266
|
+
# - the COUNT is not constrained here. Zero is only suspicious when the
|
|
1267
|
+
# ledger actually carries declarations, and only the gate can see that;
|
|
1268
|
+
# it owns the scanner-failure verdict (a checker-side non-zero floor
|
|
1269
|
+
# false-reds a legitimately declaration-free register).
|
|
1270
|
+
# Here-string, NOT `printf | grep -q`: under this script's `pipefail`, `grep -q`
|
|
1271
|
+
# exits at the first match while the writer still has data queued, the writer
|
|
1272
|
+
# takes SIGPIPE, and the pipeline reports 141 — inverting the check into a
|
|
1273
|
+
# false RED on any sufficiently chatty gate (the failure this repository
|
|
1274
|
+
# already hit once in the review-gate CLI wrappers).
|
|
1275
|
+
# awk, not `grep -v ... | tail`: on empty gate output grep matches nothing and
|
|
1276
|
+
# exits 1, which under `pipefail` fails the assignment and aborts the whole
|
|
1277
|
+
# checker with rc=1 — turning the "gate printed nothing" case into an
|
|
1278
|
+
# unexplained checker crash instead of the rc=2 malfunction verdict below.
|
|
1279
|
+
# awk exits 0 whether or not it saw a non-empty line.
|
|
1280
|
+
# The gate's waiver-row bindings can be replaced through an injected table so
|
|
1281
|
+
# fixtures can describe their own synthetic ledger. That seam must never yield
|
|
1282
|
+
# a clean landing — an inherited test environment would otherwise silently
|
|
1283
|
+
# disable the digest and missing-row layers on a real run.
|
|
1284
|
+
if grep -q '^register_firing_path_exempt_digests_injected:' <<<"$firing_path_out"; then
|
|
1285
|
+
echo "ccl_skill_check_interim_notice: the firing-path gate ran with an injected EXEMPT digest table, so the built-in waiver-row bindings were not enforced; this run is interim, not clean-landing"
|
|
1286
|
+
firing_path_digests_injected=1
|
|
1287
|
+
fi
|
|
1288
|
+
firing_path_last_line="$(awk 'NF { last = $0 } END { print last }' <<<"$firing_path_out")"
|
|
1289
|
+
if ! grep -qE '^register_firing_path_resolution_ok \([0-9]+ locators resolved\)$' <<<"$firing_path_last_line"; then
|
|
1290
|
+
echo "register_firing_path_terminal_missing: gate exited 0 but its last non-empty stdout line is not a complete ok terminal line (gate malfunction, not a clean run)" >&2
|
|
1291
|
+
exit 2
|
|
1292
|
+
fi
|
|
1293
|
+
|
|
1294
|
+
# Register pending/interim status <-> clean-landing mutual exclusion.
|
|
1295
|
+
# The prose rule ("any `pending` row blocks a complete/final claim", and an
|
|
1296
|
+
# `interim` checkpoint is not complete either) had no machine firing point, so
|
|
1297
|
+
# the dual-track challenge had to catch "claimed clean/complete while a changed
|
|
1298
|
+
# register row is still pending/interim" by hand across rounds. This wires the
|
|
1299
|
+
# two together: if the ADDED source-register diff introduces any row whose
|
|
1300
|
+
# status cell is a non-terminal `pending`/`interim`, the run is forced to
|
|
1301
|
+
# interim (clean_ok is suppressed at the final token below). It is a downgrade,
|
|
1302
|
+
# NOT a hard block — committing an interim/pending checkpoint is legitimate;
|
|
1303
|
+
# calling it a clean landing is not. Scoped to the ADDED diff (not the whole
|
|
1304
|
+
# historical ledger) so pre-existing pending/interim rows never block a fresh
|
|
1305
|
+
# commit. A WHOLE-cell match (`pending`/`interim` after stripping backticks)
|
|
1306
|
+
# targets the status column only: prose cells are sentences, never a lone
|
|
1307
|
+
# status word, and impact-chain rows can only be updated/unchanged/routed/
|
|
1308
|
+
# not-applicable, so this fires only on the non-impact-chain row families that
|
|
1309
|
+
# legitimately use pending/interim.
|
|
1310
|
+
pending_status_gate="$checker_scripts_dir/source-register-pending-status.rb"
|
|
1311
|
+
if [[ -L "$pending_status_gate" || ! -f "$pending_status_gate" ]]; then
|
|
1312
|
+
echo "missing_source_register_pending_status_gate: $pending_status_gate (must be a regular file beside the checker, not a symlink)" >&2
|
|
1313
|
+
exit 2
|
|
1314
|
+
fi
|
|
1315
|
+
register_nonterminal_status="$(ruby "$pending_status_gate" "$root")"
|
|
1316
|
+
case "$register_nonterminal_status" in
|
|
1317
|
+
0|1) ;;
|
|
1318
|
+
*)
|
|
1319
|
+
echo "register_pending_status_gate_failed: expected 0 or 1 from $pending_status_gate" >&2
|
|
1320
|
+
exit 2
|
|
1321
|
+
;;
|
|
1322
|
+
esac
|
|
1323
|
+
|
|
1324
|
+
git -C "$root" diff --check
|
|
1325
|
+
echo "diff_check_ok"
|
|
1326
|
+
else
|
|
1327
|
+
# $root is not a work tree's own top level — either no git at all (exported
|
|
1328
|
+
# copy, build artifact directory, unpacked package) or an export nested inside
|
|
1329
|
+
# some other checkout, where running the gates would adjudicate the enclosing
|
|
1330
|
+
# repository instead. Either way the four git-dependent gates below did not
|
|
1331
|
+
# run against $root. Silence would let the run reach the clean-landing token
|
|
1332
|
+
# with all four skipped, so mark it interim — skip must never read as clean.
|
|
1333
|
+
echo "ccl_skill_check_interim_notice: $root is not a git work tree root — git-dependent gates (impact-chain, firing-path resolution, register pending-status, diff --check) not run; this run is interim, not clean-landing"
|
|
1334
|
+
git_dependent_gates_skipped=1
|
|
1335
|
+
fi
|
|
1336
|
+
|
|
1337
|
+
# Combined blocking verdict for the two sync checks (route existence +
|
|
1338
|
+
# cross-skill .md reference, diagnostics printed in their own sections above).
|
|
1339
|
+
# Deferred to exactly here so the impact-chain / register gates above still
|
|
1340
|
+
# report their diagnostics in the same run; the sections BELOW (lifecycle
|
|
1341
|
+
# report, eval-routing, size gate) keep the script's fail-fast per-section
|
|
1342
|
+
# shape and are not accumulated — each failure class exits at its own section.
|
|
1343
|
+
# Either violation class fails the gate.
|
|
1344
|
+
if [ "$route_check_rc" -eq 1 ] || [ "$md_ref_broken" -gt 0 ] || [ "$sync_pointer_rc" -eq 1 ]; then
|
|
1345
|
+
echo "sync_reference_blocking_failed: stale route reference(s) and/or broken .md reference(s) and/or semantic sync registry violation(s) above block the gate (blocking since 2026-08-02); fix the citation, restore the renamed/removed target, reword both sides of a registered sync pair together, or allowlist a genuine external skill via CCL_SKILL_ROUTE_ALLOWLIST" >&2
|
|
1346
|
+
exit 1
|
|
1347
|
+
fi
|
|
1348
|
+
# Verdict evaluated: disarm the early-exit guard so the clean path continues.
|
|
1349
|
+
trap - EXIT
|
|
1350
|
+
|
|
1351
|
+
# Source-register lifecycle report (advisory — NEVER blocks, NEVER changes exit code).
|
|
1352
|
+
# Scans only shared-ledger table rows (lines beginning with `|`) so methodology prose
|
|
1353
|
+
# and examples do not inflate counts. Reports machine-visible cue counts for
|
|
1354
|
+
# `supersedes:` and `revalidate-when:` without judging stale state or event truth.
|
|
1355
|
+
# Names any `revalidate-by: <date>` marker whose date has passed (local calendar day),
|
|
1356
|
+
# so a stale externally-anchored rule (per the "Row lifecycle" convention) gets
|
|
1357
|
+
# re-checked instead of trusted blind. Uses Ruby (already a hard dependency for
|
|
1358
|
+
# eval-routing.rb): Date.strptime validates a REAL calendar date, so the `<date>`
|
|
1359
|
+
# placeholder, ISO timestamps (`...T..`), and invalid dates (e.g. 2020-99-99) do NOT
|
|
1360
|
+
# match; Date.today avoids any external `date` command. The whole call is guarded
|
|
1361
|
+
# with `|| true` so nothing here — even a Ruby error — can change the exit code.
|
|
1362
|
+
# One-shot scan, not a prune/telemetry/event-monitoring job.
|
|
1363
|
+
register="$root/skills/skill-extraction-workflow/references/source-register.md"
|
|
1364
|
+
if [ -f "$register" ]; then
|
|
1365
|
+
if [[ -z "${checker_scripts_dir:-}" ]]; then
|
|
1366
|
+
if ! checker_scripts_dir="$(resolve_checker_scripts_dir "${BASH_SOURCE[0]}")"; then
|
|
1367
|
+
checker_scripts_dir=""
|
|
1368
|
+
echo "revalidate_check_skipped: could not resolve checker script directory from ${BASH_SOURCE[0]}" >&2
|
|
1369
|
+
fi
|
|
1370
|
+
fi
|
|
1371
|
+
if [[ -n "$checker_scripts_dir" ]]; then
|
|
1372
|
+
lifecycle_gate="$checker_scripts_dir/source-register-lifecycle.rb"
|
|
1373
|
+
if [[ -L "$lifecycle_gate" || ! -f "$lifecycle_gate" ]]; then
|
|
1374
|
+
echo "revalidate_check_skipped: missing lifecycle helper beside checker: $lifecycle_gate" >&2
|
|
1375
|
+
else
|
|
1376
|
+
ruby "$lifecycle_gate" "$register" || true
|
|
1377
|
+
fi
|
|
1378
|
+
fi
|
|
1379
|
+
fi
|
|
1380
|
+
|
|
1381
|
+
# F4 Tier-1 static routing analyzer: block on objective routing-surface defects
|
|
1382
|
+
# (dangling backticked redirects, exact trigger collisions without disambiguation).
|
|
1383
|
+
# Advisory findings (fuzzy/possible-dangling) print but never block.
|
|
1384
|
+
eval_routing_rc=0
|
|
1385
|
+
ruby "$root/skills/skill-extraction-workflow/scripts/eval-routing.rb" "$root" || eval_routing_rc=$?
|
|
1386
|
+
if [ "$eval_routing_rc" -eq 0 ]; then
|
|
1387
|
+
echo "eval_routing_ok"
|
|
1388
|
+
elif [ "$eval_routing_rc" -eq 2 ]; then
|
|
1389
|
+
# parse/usage error (bad or absent SKILL.md frontmatter) — distinct from a routing defect
|
|
1390
|
+
echo "eval_routing_error: analyzer parse/usage error (see above)" >&2
|
|
1391
|
+
exit 2
|
|
1392
|
+
else
|
|
1393
|
+
echo "eval_routing_blocking: objective routing-surface defects (see above; run: make eval-routing)" >&2
|
|
1394
|
+
exit 1
|
|
1395
|
+
fi
|
|
1396
|
+
|
|
1397
|
+
# Entrypoint size gate (delta-blocking since 2026-07-30): gives the "consolidate; a rule
|
|
1398
|
+
# set must not grow monotonically" Core Rule a mechanical firing path. Delta-scoped — a
|
|
1399
|
+
# changed entrypoint that is new/crossing over
|
|
1400
|
+
# 50KB, or an already-severe entrypoint that grew, fails the gate; the debt counters
|
|
1401
|
+
# and recommended-band tokens stay visibility/debt-management only (not a
|
|
1402
|
+
# clean-landing waiver and not authorization to keep growing entrypoints). The
|
|
1403
|
+
# legacy markers (size_budget_advisory_ok|partial, size_budget_info:) are preserved.
|
|
1404
|
+
# Since 2026-08-02 the same delta shape gates agent-context/session-start.md: a changed agent-context/session-start.md
|
|
1405
|
+
# that grew fails the gate (the 13000B band stays advisory visibility only).
|
|
1406
|
+
size_budget_script="$root/skills/skill-extraction-workflow/scripts/check-size-budget.sh"
|
|
1407
|
+
if [[ -f "$size_budget_script" ]]; then
|
|
1408
|
+
size_budget_rc=0
|
|
1409
|
+
bash "$size_budget_script" "$root" || size_budget_rc=$?
|
|
1410
|
+
if [[ "$size_budget_rc" -eq 1 ]]; then
|
|
1411
|
+
echo "entrypoint_size_budget_blocking_failed (block or partial: see entrypoint_size_block lines above)" >&2
|
|
1412
|
+
exit 1
|
|
1413
|
+
elif [[ "$size_budget_rc" -ne 0 ]]; then
|
|
1414
|
+
echo "entrypoint_size_budget_infra_failed rc=$size_budget_rc (size gate could not run — ruby missing/crash; fail-closed)" >&2
|
|
1415
|
+
exit 1
|
|
1416
|
+
fi
|
|
1417
|
+
else
|
|
1418
|
+
# The size gate is part of this gate's contract — a missing script is a broken
|
|
1419
|
+
# checkout, not a skippable advisory.
|
|
1420
|
+
echo "entrypoint_size_budget_blocking_failed: check-size-budget.sh missing" >&2
|
|
1421
|
+
exit 1
|
|
1422
|
+
fi
|
|
1423
|
+
|
|
1424
|
+
# Final status token. The legacy `ccl_skill_check_ok` is still printed for
|
|
1425
|
+
# backward-compatible consumers, but it is NO LONGER the last line and NO LONGER
|
|
1426
|
+
# the sole success signal: a machine (or human) MUST read the final
|
|
1427
|
+
# `ccl_skill_check_(clean|interim)_ok` token to tell a clean-landing R0 pass
|
|
1428
|
+
# (private alias audit ran clean) from an interim pass (only the public fallback
|
|
1429
|
+
# ran — private R0 NOT run). Never treat the legacy token, or the interim token,
|
|
1430
|
+
# as clean-landing R0 evidence (see skill-extraction-workflow/references/r0-leakage-audit.md).
|
|
1431
|
+
# Clean landing requires BOTH a private-ok R0 audit AND no pending/interim register
|
|
1432
|
+
# rows added in this diff: a changed ledger row that is still `pending`/`interim`
|
|
1433
|
+
# is by definition not-yet-complete work, which cannot be a clean landing.
|
|
1434
|
+
# Likewise a partially-SKIPPED semantic sync tier (missing agent-context/session-start.md or a
|
|
1435
|
+
# missing package) is not a full evaluation: the run keeps rc 0 for the legal
|
|
1436
|
+
# skip states, but skip must never read as clean (same honesty shape as the
|
|
1437
|
+
# size gate's `*_unevaluated` token).
|
|
1438
|
+
echo "ccl_skill_check_ok"
|
|
1439
|
+
if [[ "$r0_clean_landing_status" == "private-ok" && "${register_nonterminal_status:-0}" != "1" && "${sync_pointer_skipped:-0}" != "1" && "${git_dependent_gates_skipped:-0}" != "1" && "${firing_path_digests_injected:-0}" != "1" ]]; then
|
|
1440
|
+
echo "ccl_skill_check_clean_ok"
|
|
1441
|
+
else
|
|
1442
|
+
if [[ "$r0_clean_landing_status" != "private-ok" ]]; then
|
|
1443
|
+
echo "ccl_skill_check_interim_notice: private R0 alias audit did not run (r0_status=${r0_clean_landing_status}); this is interim, NOT clean-landing — do not merge or mark R0-clean without alias_audit_ok, a named private profile, or a risk-owner waiver"
|
|
1444
|
+
fi
|
|
1445
|
+
if [[ "${register_nonterminal_status:-0}" == "1" ]]; then
|
|
1446
|
+
echo "ccl_skill_check_interim_notice: the changed source-register diff adds pending/interim status row(s) (see register_nonterminal_status_added above); a pending/interim ledger row blocks a clean-landing/complete claim — resolve or supersede those rows before marking this landing clean/complete"
|
|
1447
|
+
fi
|
|
1448
|
+
if [[ "${sync_pointer_skipped:-0}" == "1" ]]; then
|
|
1449
|
+
echo "ccl_skill_check_interim_notice: semantic sync checks were partially skipped (missing agent-context/session-start.md or package) — skip is NOT a full evaluation (sync_semantic_check_unevaluated semantics); this run is interim, not clean-landing"
|
|
1450
|
+
fi
|
|
1451
|
+
echo "ccl_skill_check_interim_ok"
|
|
1452
|
+
fi
|