@soleur/opencode 0.0.0-stage → 1.0.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/.claude-plugin/agents.manifest.json +476 -0
- package/.claude-plugin/plugin.json +42 -0
- package/README.md +44 -2
- package/agents/community/.gitkeep +0 -0
- package/agents/engineering/cto.md +87 -0
- package/agents/engineering/design/ddd-architect.md +95 -0
- package/agents/engineering/discovery/agent-finder.md +214 -0
- package/agents/engineering/discovery/functional-discovery.md +182 -0
- package/agents/engineering/infra/infra-security.md +151 -0
- package/agents/engineering/infra/platform-strategist.md +109 -0
- package/agents/engineering/infra/terraform-architect.md +171 -0
- package/agents/engineering/prompt-engineer.md +37 -0
- package/agents/engineering/research/best-practices-researcher.md +115 -0
- package/agents/engineering/research/framework-docs-researcher.md +93 -0
- package/agents/engineering/research/git-history-analyzer.md +53 -0
- package/agents/engineering/research/learnings-researcher.md +285 -0
- package/agents/engineering/research/repo-research-analyst.md +118 -0
- package/agents/engineering/review/agent-native-reviewer.md +279 -0
- package/agents/engineering/review/architecture-strategist.md +61 -0
- package/agents/engineering/review/code-quality-analyst.md +92 -0
- package/agents/engineering/review/code-simplicity-reviewer.md +109 -0
- package/agents/engineering/review/data-integrity-guardian.md +82 -0
- package/agents/engineering/review/data-migration-expert.md +98 -0
- package/agents/engineering/review/deployment-verification-agent.md +183 -0
- package/agents/engineering/review/dhh-rails-reviewer.md +46 -0
- package/agents/engineering/review/kieran-rails-reviewer.md +87 -0
- package/agents/engineering/review/legacy-code-expert.md +55 -0
- package/agents/engineering/review/observability-coverage-reviewer.md +147 -0
- package/agents/engineering/review/pattern-recognition-specialist.md +59 -0
- package/agents/engineering/review/performance-oracle.md +130 -0
- package/agents/engineering/review/security-sentinel.md +167 -0
- package/agents/engineering/review/semgrep-sast.md +36 -0
- package/agents/engineering/review/test-design-reviewer.md +150 -0
- package/agents/engineering/review/user-impact-reviewer.md +70 -0
- package/agents/engineering/workflow/pr-comment-resolver.md +69 -0
- package/agents/finance/budget-analyst.md +29 -0
- package/agents/finance/cfo.md +44 -0
- package/agents/finance/financial-reporter.md +30 -0
- package/agents/finance/revenue-analyst.md +30 -0
- package/agents/legal/clo.md +115 -0
- package/agents/legal/legal-compliance-auditor.md +110 -0
- package/agents/legal/legal-document-generator.md +134 -0
- package/agents/marketing/analytics-analyst.md +25 -0
- package/agents/marketing/brand-architect.md +181 -0
- package/agents/marketing/cmo.md +76 -0
- package/agents/marketing/conversion-optimizer.md +19 -0
- package/agents/marketing/copywriter.md +20 -0
- package/agents/marketing/fact-checker.md +70 -0
- package/agents/marketing/growth-strategist.md +145 -0
- package/agents/marketing/paid-media-strategist.md +28 -0
- package/agents/marketing/pricing-strategist.md +17 -0
- package/agents/marketing/programmatic-seo-specialist.md +25 -0
- package/agents/marketing/retention-strategist.md +23 -0
- package/agents/marketing/seo-aeo-analyst.md +164 -0
- package/agents/operations/coo.md +50 -0
- package/agents/operations/ops-advisor.md +78 -0
- package/agents/operations/ops-provisioner.md +101 -0
- package/agents/operations/ops-research.md +52 -0
- package/agents/operations/service-automator.md +278 -0
- package/agents/product/business-validator.md +206 -0
- package/agents/product/competitive-intelligence.md +89 -0
- package/agents/product/cpo.md +63 -0
- package/agents/product/design/ux-design-lead.md +209 -0
- package/agents/product/spec-flow-analyzer.md +122 -0
- package/agents/sales/cro.md +44 -0
- package/agents/sales/deal-architect.md +29 -0
- package/agents/sales/outbound-strategist.md +29 -0
- package/agents/sales/pipeline-analyst.md +29 -0
- package/agents/support/cco.md +48 -0
- package/agents/support/community-manager.md +570 -0
- package/agents/support/ticket-triage.md +70 -0
- package/bin/soleur-opencode.js +29 -0
- package/commands/go.md +659 -0
- package/commands/help.md +273 -0
- package/commands/sync.md +977 -0
- package/commands/version.md +103 -0
- package/hooks/antigravity-hooks.json +84 -0
- package/hooks/antigravity-session-start.sh +15 -0
- package/hooks/bare-root-cwd-guard.sh +131 -0
- package/hooks/browser-snapshot-credential-guard.sh +200 -0
- package/hooks/codex-session-start.sh +9 -0
- package/hooks/compaction-state.sh +525 -0
- package/hooks/destructive-command-guard.sh +1387 -0
- package/hooks/devin-session-start.sh +90 -0
- package/hooks/ext-filter-detect.sh +171 -0
- package/hooks/hooks.json +133 -0
- package/hooks/lib/hook-tool-kind.sh +24 -0
- package/hooks/lib/log-rotation.sh +176 -0
- package/hooks/lib/shell-argv.pl +576 -0
- package/hooks/memory-backstop.sh +1114 -0
- package/hooks/operator-stage-approval.sh +391 -0
- package/hooks/stop-hook.sh +367 -0
- package/hooks/unkept-promise-hook.sh +383 -0
- package/hooks/version-banner.sh +127 -0
- package/hooks/welcome-hook.sh +50 -0
- package/install.js +108 -0
- package/lib/agent-registry.ts +154 -0
- package/lib/c4-canonical-cli.mjs +34 -0
- package/lib/c4-canonical.mjs +46 -0
- package/lib/c4-from-components.ts +554 -0
- package/lib/go-routing.ts +81 -0
- package/lib/grok-inspect-contract.ts +311 -0
- package/lib/harness-model-map.ts +101 -0
- package/lib/harness-parity.ts +726 -0
- package/lib/harness-tool-map.ts +180 -0
- package/lib/harness.ts +716 -0
- package/lib/heartbeat-live-reconcile.ts +1153 -0
- package/lib/heartbeat-manifest.ts +342 -0
- package/lib/kb-coverage.ts +252 -0
- package/lib/pr-merge-poll.ts +103 -0
- package/lib/workflow-fidelity.ts +388 -0
- package/opencode/INSTRUCTIONS.md +152 -0
- package/opencode/agents/engineering/cto.md +10 -0
- package/opencode/agents/engineering/design/ddd-architect.md +10 -0
- package/opencode/agents/engineering/discovery/agent-finder.md +10 -0
- package/opencode/agents/engineering/discovery/functional-discovery.md +10 -0
- package/opencode/agents/engineering/infra/infra-security.md +10 -0
- package/opencode/agents/engineering/infra/platform-strategist.md +10 -0
- package/opencode/agents/engineering/infra/terraform-architect.md +10 -0
- package/opencode/agents/engineering/prompt-engineer.md +10 -0
- package/opencode/agents/engineering/research/best-practices-researcher.md +10 -0
- package/opencode/agents/engineering/research/framework-docs-researcher.md +10 -0
- package/opencode/agents/engineering/research/git-history-analyzer.md +10 -0
- package/opencode/agents/engineering/research/learnings-researcher.md +10 -0
- package/opencode/agents/engineering/research/repo-research-analyst.md +10 -0
- package/opencode/agents/engineering/review/agent-native-reviewer.md +10 -0
- package/opencode/agents/engineering/review/architecture-strategist.md +10 -0
- package/opencode/agents/engineering/review/code-quality-analyst.md +10 -0
- package/opencode/agents/engineering/review/code-simplicity-reviewer.md +10 -0
- package/opencode/agents/engineering/review/data-integrity-guardian.md +10 -0
- package/opencode/agents/engineering/review/data-migration-expert.md +10 -0
- package/opencode/agents/engineering/review/deployment-verification-agent.md +10 -0
- package/opencode/agents/engineering/review/dhh-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/kieran-rails-reviewer.md +10 -0
- package/opencode/agents/engineering/review/legacy-code-expert.md +10 -0
- package/opencode/agents/engineering/review/observability-coverage-reviewer.md +10 -0
- package/opencode/agents/engineering/review/pattern-recognition-specialist.md +10 -0
- package/opencode/agents/engineering/review/performance-oracle.md +10 -0
- package/opencode/agents/engineering/review/security-sentinel.md +10 -0
- package/opencode/agents/engineering/review/semgrep-sast.md +10 -0
- package/opencode/agents/engineering/review/test-design-reviewer.md +10 -0
- package/opencode/agents/engineering/review/user-impact-reviewer.md +10 -0
- package/opencode/agents/engineering/workflow/pr-comment-resolver.md +10 -0
- package/opencode/agents/finance/budget-analyst.md +10 -0
- package/opencode/agents/finance/cfo.md +10 -0
- package/opencode/agents/finance/financial-reporter.md +10 -0
- package/opencode/agents/finance/revenue-analyst.md +10 -0
- package/opencode/agents/legal/clo.md +10 -0
- package/opencode/agents/legal/legal-compliance-auditor.md +10 -0
- package/opencode/agents/legal/legal-document-generator.md +10 -0
- package/opencode/agents/marketing/analytics-analyst.md +10 -0
- package/opencode/agents/marketing/brand-architect.md +10 -0
- package/opencode/agents/marketing/cmo.md +10 -0
- package/opencode/agents/marketing/conversion-optimizer.md +10 -0
- package/opencode/agents/marketing/copywriter.md +10 -0
- package/opencode/agents/marketing/fact-checker.md +10 -0
- package/opencode/agents/marketing/growth-strategist.md +10 -0
- package/opencode/agents/marketing/paid-media-strategist.md +10 -0
- package/opencode/agents/marketing/pricing-strategist.md +10 -0
- package/opencode/agents/marketing/programmatic-seo-specialist.md +10 -0
- package/opencode/agents/marketing/retention-strategist.md +10 -0
- package/opencode/agents/marketing/seo-aeo-analyst.md +10 -0
- package/opencode/agents/operations/coo.md +10 -0
- package/opencode/agents/operations/ops-advisor.md +10 -0
- package/opencode/agents/operations/ops-provisioner.md +10 -0
- package/opencode/agents/operations/ops-research.md +10 -0
- package/opencode/agents/operations/service-automator.md +10 -0
- package/opencode/agents/product/business-validator.md +10 -0
- package/opencode/agents/product/competitive-intelligence.md +10 -0
- package/opencode/agents/product/cpo.md +10 -0
- package/opencode/agents/product/design/ux-design-lead.md +10 -0
- package/opencode/agents/product/spec-flow-analyzer.md +10 -0
- package/opencode/agents/sales/cro.md +10 -0
- package/opencode/agents/sales/deal-architect.md +10 -0
- package/opencode/agents/sales/outbound-strategist.md +10 -0
- package/opencode/agents/sales/pipeline-analyst.md +10 -0
- package/opencode/agents/support/cco.md +10 -0
- package/opencode/agents/support/community-manager.md +10 -0
- package/opencode/agents/support/ticket-triage.md +10 -0
- package/opencode/commands/go.md +10 -0
- package/opencode/commands/help.md +10 -0
- package/opencode/commands/sync.md +10 -0
- package/opencode/commands/version.md +11 -0
- package/opencode/opencode.json +8 -0
- package/opencode/plugin.ts +493 -0
- package/package.json +36 -4
- package/scripts/admin-merge-ready.sh +545 -0
- package/scripts/admin-merge-ready.test.sh +753 -0
- package/scripts/affected-tests.sh +908 -0
- package/scripts/affected-tests.test.sh +1797 -0
- package/scripts/alpha-metrics.sh +78 -0
- package/scripts/alpha-metrics.test.sh +115 -0
- package/scripts/ancestor-signal-helpers.baseline.txt +16 -0
- package/scripts/audit-flag-flip.sh +107 -0
- package/scripts/check-red-on-main.sh +316 -0
- package/scripts/ci-head-verdict.sh +363 -0
- package/scripts/cloud-detect.sh +193 -0
- package/scripts/delegation-verify.sh +657 -0
- package/scripts/delegation-verify.test.sh +1424 -0
- package/scripts/deploy-arm.sh +475 -0
- package/scripts/domain-model-drift.sh +419 -0
- package/scripts/emit-decision.sh +144 -0
- package/scripts/emit-decision.test.sh +144 -0
- package/scripts/ext-filter-divergence-corpus.txt +15 -0
- package/scripts/ext-filter-divergence.sh +189 -0
- package/scripts/generate-c4-from-components.ts +442 -0
- package/scripts/grok-fidelity-gate.sh +68 -0
- package/scripts/grok-pre-push-gate.sh +232 -0
- package/scripts/harness-discovery-smoke.ts +906 -0
- package/scripts/harness-parity-census.ts +92 -0
- package/scripts/inngest-luks-alert-armed-probe.ts +29 -0
- package/scripts/install-opencode-adapter.ts +520 -0
- package/scripts/lib/affected-tests/common.sh +365 -0
- package/scripts/lib/affected-tests/go.sh +157 -0
- package/scripts/lib/affected-tests/js.sh +188 -0
- package/scripts/lib/affected-tests/nx-turbo.sh +98 -0
- package/scripts/lib/affected-tests/python.sh +185 -0
- package/scripts/lib/context-sanitize.sh +49 -0
- package/scripts/lib/domain-model-lib.sh +180 -0
- package/scripts/lib/ext-filter-grammar.tsv +34 -0
- package/scripts/lib/operator-script.sh +1236 -0
- package/scripts/lib/proc.sh +580 -0
- package/scripts/lib/session-state.sh +748 -0
- package/scripts/lib/tmp-classify.sh +843 -0
- package/scripts/lib/wrapper-boundary.sh +47 -0
- package/scripts/lint-ratchet.py +1547 -0
- package/scripts/monitor-pr-checks.sh +441 -0
- package/scripts/pipeline-tally.sh +756 -0
- package/scripts/pipeline-tally.test.sh +740 -0
- package/scripts/plugin-version.sh +528 -0
- package/scripts/precommit-guard.sh +113 -0
- package/scripts/precommit-guard.test.sh +254 -0
- package/scripts/reconcile-live-heartbeats.ts +705 -0
- package/scripts/render-c4-model.sh +217 -0
- package/scripts/resolve-git-root.sh +55 -0
- package/scripts/resolve-regenerable-conflicts.sh +363 -0
- package/scripts/resolve-regenerable-conflicts.test.sh +780 -0
- package/scripts/ruff-requirements.txt +22 -0
- package/scripts/run-in-pid-namespace.sh +98 -0
- package/scripts/run-in-pid-namespace.test.sh +290 -0
- package/scripts/scan-ancestor-signal-helpers.py +556 -0
- package/scripts/scan-ancestor-signal-helpers.test.sh +670 -0
- package/scripts/setup-ralph-loop.sh +238 -0
- package/scripts/sync-cursor-name-map.ts +316 -0
- package/scripts/sync-grok-agent-compat.ts +188 -0
- package/scripts/sync-npm-package.ts +178 -0
- package/scripts/sync-opencode-adapter.ts +479 -0
- package/scripts/sync-pr-behind.sh +534 -0
- package/scripts/sync-pr-behind.test.sh +252 -0
- package/scripts/taste-profile-update.sh +180 -0
- package/scripts/taste-profile-update.test.sh +167 -0
- package/scripts/write-budget-marker.sh +23 -0
- package/scripts/write-kb-coverage.ts +113 -0
- package/skills/admin-ip-refresh/SKILL.md +81 -0
- package/skills/admin-ip-refresh/references/admin-ip-refresh-procedure.md +201 -0
- package/skills/agent-browser/SKILL.md +698 -0
- package/skills/agent-browser/scripts/playwright-mcp-profile-slot.sh +304 -0
- package/skills/agent-browser/scripts/playwright-mcp-redact-proxy.py +964 -0
- package/skills/agent-browser/scripts/redact-a11y-snapshot.py +443 -0
- package/skills/agent-browser/test/fixtures/capture-playwright-mcp-fixtures.py +217 -0
- package/skills/agent-browser/test/fixtures/fake-passthrough-proxy.py +24 -0
- package/skills/agent-browser/test/fixtures/fake-playwright-mcp.py +131 -0
- package/skills/agent-browser/test/fixtures/make-proxy-mutant.py +48 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/dialog-link-injection.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/empty-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-and-result.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-bool.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-code-string.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-message-tree.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-no-data.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-string.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/error-with-data.json +9 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/evaluate-escaped-object.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/invalid-utf8.json +4 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/link-result.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/list-two-results.json +6 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/meta-in-result.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/no-content.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/quoted-key.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/resource-block.json +18 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-and-method.json +11 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/result-string.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped-one-row.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/run-code-escaped.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/structured-content.json +13 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tools-list-no-tools.json +5 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/tree-no-credential.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/two-text-blocks.json +14 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/unparsable-line.json +3 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-brace.json +10 -0
- package/skills/agent-browser/test/fixtures/odd-shapes/value-contains-link-substring.json +10 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/close.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/evaluate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/find.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/framing.json +6 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/initialize.json +14 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate-link.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/navigate.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/roots-list-request.json +5 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/screenshot.json +17 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-filename.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-json.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot-meta-raw.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/snapshot.json +12 -0
- package/skills/agent-browser/test/fixtures/playwright-mcp-0.0.78/tools-list.json +827 -0
- package/skills/agent-browser/test/fixtures/proxy-session-driver.py +138 -0
- package/skills/agent-browser/test/fixtures/session-facts.py +102 -0
- package/skills/agent-browser/test/playwright-mcp-lifetime.test.sh +1620 -0
- package/skills/agent-browser/test/playwright-mcp-redact-proxy.test.sh +1599 -0
- package/skills/agent-browser/test/redact-a11y-snapshot.test.sh +527 -0
- package/skills/agent-native-architecture/SKILL.md +479 -0
- package/skills/agent-native-architecture/references/action-parity-discipline.md +430 -0
- package/skills/agent-native-architecture/references/agent-execution-patterns.md +483 -0
- package/skills/agent-native-architecture/references/agent-native-testing.md +605 -0
- package/skills/agent-native-architecture/references/architecture-patterns.md +493 -0
- package/skills/agent-native-architecture/references/dynamic-context-injection.md +358 -0
- package/skills/agent-native-architecture/references/files-universal-interface.md +314 -0
- package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +381 -0
- package/skills/agent-native-architecture/references/mcp-tool-design.md +524 -0
- package/skills/agent-native-architecture/references/mobile-patterns.md +897 -0
- package/skills/agent-native-architecture/references/product-implications.md +478 -0
- package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +342 -0
- package/skills/agent-native-architecture/references/self-modification.md +294 -0
- package/skills/agent-native-architecture/references/shared-workspace-architecture.md +700 -0
- package/skills/agent-native-architecture/references/system-prompt-design.md +263 -0
- package/skills/agent-native-audit/SKILL.md +300 -0
- package/skills/agent-native-audit/workflows/agent-native-audit.workflow.js +423 -0
- package/skills/andrew-kane-gem-writer/SKILL.md +189 -0
- package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/skills/andrew-kane-gem-writer/references/resources.md +126 -0
- package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/skills/architecture/SKILL.md +436 -0
- package/skills/architecture/references/adr-template.md +154 -0
- package/skills/architecture/references/likec4-reference.md +136 -0
- package/skills/architecture/references/nfr-reference.md +126 -0
- package/skills/archive-kb/SKILL.md +86 -0
- package/skills/archive-kb/scripts/archive-kb.sh +300 -0
- package/skills/archive-kb/test/archive-kb-partial-run.test.sh +276 -0
- package/skills/atdd-developer/SKILL.md +65 -0
- package/skills/brainstorm/SKILL.md +701 -0
- package/skills/brainstorm/references/brainstorm-brand-workshop.md +153 -0
- package/skills/brainstorm/references/brainstorm-domain-config.md +63 -0
- package/skills/brainstorm/references/brainstorm-validation-workshop.md +65 -0
- package/skills/brainstorm/references/ui-surface-terms.md +42 -0
- package/skills/brainstorm-techniques/SKILL.md +231 -0
- package/skills/brainstorm-techniques/references/decision-principles.md +150 -0
- package/skills/brainstorm-techniques/references/phase-boundaries.md +103 -0
- package/skills/brainstorm-techniques/references/standing-delegation.md +407 -0
- package/skills/brainstorm-techniques/references/technical-ruling-delegation.md +174 -0
- package/skills/campaign-calendar/SKILL.md +145 -0
- package/skills/cf-token-scope/SKILL.md +164 -0
- package/skills/cf-token-scope/references/widen-playbook.md +114 -0
- package/skills/cf-token-scope/scripts/cf-token-scope.sh +253 -0
- package/skills/changelog/SKILL.md +142 -0
- package/skills/code-to-prd/SKILL.md +66 -0
- package/skills/code-to-prd/references/banner-template.md +12 -0
- package/skills/code-to-prd/references/prd-template.md +41 -0
- package/skills/code-to-prd/scripts/code-to-prd.sh +634 -0
- package/skills/code-to-prd/test/code-to-prd.test.sh +447 -0
- package/skills/code-to-prd/test/fixture/.env.example +7 -0
- package/skills/code-to-prd/test/fixture/app/about/page.tsx +11 -0
- package/skills/code-to-prd/test/fixture/app/api/health/route.ts +10 -0
- package/skills/code-to-prd/test/fixture/app/page.tsx +14 -0
- package/skills/code-to-prd/test/fixture/next.config.mjs +3 -0
- package/skills/code-to-prd/test/fixture/package.json +6 -0
- package/skills/cohort-status/SKILL.md +62 -0
- package/skills/community/SKILL.md +210 -0
- package/skills/community/scripts/bsky-community.sh +644 -0
- package/skills/community/scripts/bsky-setup.sh +631 -0
- package/skills/community/scripts/community-router.sh +93 -0
- package/skills/community/scripts/discord-community.sh +487 -0
- package/skills/community/scripts/discord-setup.sh +784 -0
- package/skills/community/scripts/github-community.sh +706 -0
- package/skills/community/scripts/hn-community.sh +233 -0
- package/skills/community/scripts/lib/hmac-sha1-b64.sh +126 -0
- package/skills/community/scripts/linkedin-community.sh +750 -0
- package/skills/community/scripts/linkedin-setup.sh +758 -0
- package/skills/community/scripts/x-community.sh +890 -0
- package/skills/community/scripts/x-setup.sh +713 -0
- package/skills/community/test/community-argv.test.sh +2922 -0
- package/skills/community/test/github-community.test.sh +981 -0
- package/skills/competitive-analysis/SKILL.md +69 -0
- package/skills/competitive-analysis/references/peer-plugin-audit.md +218 -0
- package/skills/compound/SKILL.md +673 -0
- package/skills/compound/scripts/token-efficiency-report.sh +334 -0
- package/skills/compound/test/phase-16.test.sh +379 -0
- package/skills/compound-capture/SKILL.md +791 -0
- package/skills/compound-capture/assets/critical-pattern-template.md +37 -0
- package/skills/compound-capture/assets/resolution-template.md +116 -0
- package/skills/compound-capture/references/yaml-schema.md +67 -0
- package/skills/compound-capture/schema.yaml +181 -0
- package/skills/constraint-scaffold/SKILL.md +175 -0
- package/skills/constraint-scaffold/references/boundary-readme.template +35 -0
- package/skills/constraint-scaffold/references/constraint-gates-workflow.template +69 -0
- package/skills/constraint-scaffold/references/depcruise-config.template +230 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-a.template +240 -0
- package/skills/constraint-scaffold/references/fix-constraints-stage-b.template +313 -0
- package/skills/constraint-scaffold/references/shared-runner.template +135 -0
- package/skills/constraint-scaffold/scripts/constraint-scaffold.sh +589 -0
- package/skills/constraint-scaffold/test/bite-proof.test.sh +1338 -0
- package/skills/constraint-scaffold/test/boundary.test.sh +734 -0
- package/skills/constraint-scaffold/test/emit-fix-constraints.test.sh +193 -0
- package/skills/constraint-scaffold/test/generator.test.sh +93 -0
- package/skills/constraint-scaffold/test/parity.test.sh +285 -0
- package/skills/content-writer/SKILL.md +242 -0
- package/skills/content-writer/scripts/blog-jargon-scan.sh +42 -0
- package/skills/cron-delete/SKILL.md +56 -0
- package/skills/cron-list/SKILL.md +54 -0
- package/skills/deepen-plan/SKILL.md +937 -0
- package/skills/deepen-plan/workflows/deepen-plan.workflow.js +488 -0
- package/skills/deploy/SKILL.md +115 -0
- package/skills/deploy/references/hetzner-setup.md +65 -0
- package/skills/deploy/scripts/deploy.sh +37 -0
- package/skills/deploy-docs/SKILL.md +95 -0
- package/skills/dhh-rails-style/SKILL.md +203 -0
- package/skills/dhh-rails-style/references/architecture.md +717 -0
- package/skills/dhh-rails-style/references/controllers.md +323 -0
- package/skills/dhh-rails-style/references/frontend.md +556 -0
- package/skills/dhh-rails-style/references/gems.md +316 -0
- package/skills/dhh-rails-style/references/models.md +388 -0
- package/skills/dhh-rails-style/references/testing.md +354 -0
- package/skills/discord-content/SKILL.md +126 -0
- package/skills/docs-site/SKILL.md +214 -0
- package/skills/drain-labeled-backlog/SKILL.md +203 -0
- package/skills/drain-labeled-backlog/scripts/group-by-area.sh +208 -0
- package/skills/drain-labeled-backlog/workflows/drain-labeled-backlog.workflow.js +433 -0
- package/skills/drain-prs/SKILL.md +142 -0
- package/skills/drain-prs/scripts/triage-prs.sh +192 -0
- package/skills/drain-prs/test/argv-ceiling.test.sh +183 -0
- package/skills/dspy-ruby/SKILL.md +634 -0
- package/skills/dspy-ruby/assets/config-template.rb +359 -0
- package/skills/dspy-ruby/assets/module-template.rb +326 -0
- package/skills/dspy-ruby/assets/signature-template.rb +143 -0
- package/skills/dspy-ruby/references/core-concepts.md +268 -0
- package/skills/dspy-ruby/references/optimization.md +623 -0
- package/skills/dspy-ruby/references/providers.md +335 -0
- package/skills/eval-harness/README.md +194 -0
- package/skills/eval-harness/SKILL.md +157 -0
- package/skills/eval-harness/enums/go-routes.json +13 -0
- package/skills/eval-harness/enums/incident-threshold.json +5 -0
- package/skills/eval-harness/enums/lane.json +5 -0
- package/skills/eval-harness/enums/tool-selection.json +20 -0
- package/skills/eval-harness/enums/triage-levels.json +5 -0
- package/skills/eval-harness/gated-skills.json +34 -0
- package/skills/eval-harness/models.generated.json +5 -0
- package/skills/eval-harness/promptfooconfig-go-routing.yaml +35 -0
- package/skills/eval-harness/promptfooconfig-incident-threshold.yaml +32 -0
- package/skills/eval-harness/promptfooconfig-lane-inference.yaml +33 -0
- package/skills/eval-harness/promptfooconfig-ticket-triage.yaml +34 -0
- package/skills/eval-harness/promptfooconfig-tool-selection.yaml +33 -0
- package/skills/eval-harness/prompts/go-baseline.txt +6 -0
- package/skills/eval-harness/prompts/go-skill.txt +21 -0
- package/skills/eval-harness/prompts/incident-threshold-baseline.txt +6 -0
- package/skills/eval-harness/prompts/incident-threshold-skill.txt +12 -0
- package/skills/eval-harness/prompts/lane-inference-baseline.txt +6 -0
- package/skills/eval-harness/prompts/lane-inference-skill.txt +15 -0
- package/skills/eval-harness/prompts/tool-selection-baseline.txt +19 -0
- package/skills/eval-harness/prompts/tool-selection-skill.txt +22 -0
- package/skills/eval-harness/prompts/triage-baseline.txt +7 -0
- package/skills/eval-harness/prompts/triage-skill.txt +10 -0
- package/skills/eval-harness/scripts/eval-gate.cjs +318 -0
- package/skills/eval-harness/scripts/extract-block.cjs +87 -0
- package/skills/eval-harness/scripts/gate-classification.cjs +28 -0
- package/skills/eval-harness/scripts/gen-models.sh +41 -0
- package/skills/eval-harness/scripts/gen-skill-prompt.cjs +177 -0
- package/skills/eval-harness/scripts/measure-classification.cjs +30 -0
- package/skills/eval-harness/scripts/parse-label.cjs +93 -0
- package/skills/eval-harness/scripts/verdict.cjs +132 -0
- package/skills/eval-harness/tasks/go-routing.jsonl +8 -0
- package/skills/eval-harness/tasks/incident-threshold.jsonl +7 -0
- package/skills/eval-harness/tasks/lane-inference.jsonl +7 -0
- package/skills/eval-harness/tasks/ticket-triage.jsonl +6 -0
- package/skills/eval-harness/tasks/tool-selection.jsonl +15 -0
- package/skills/eval-harness/test/eval-gate.test.sh +132 -0
- package/skills/eval-harness/test/extract-block.test.sh +87 -0
- package/skills/eval-harness/test/gate-classification.test.sh +77 -0
- package/skills/eval-harness/test/gen-models.test.sh +75 -0
- package/skills/eval-harness/test/measure-classification.test.sh +74 -0
- package/skills/eval-harness/test/parse-label.test.sh +129 -0
- package/skills/eval-harness/test/registry-completeness.test.sh +109 -0
- package/skills/eval-harness/test/verdict.test.sh +123 -0
- package/skills/every-style-editor/SKILL.md +142 -0
- package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/skills/feature-tweet/SKILL.md +199 -0
- package/skills/feature-video/SKILL.md +412 -0
- package/skills/feature-video/scripts/check_deps.sh +281 -0
- package/skills/file-todos/SKILL.md +267 -0
- package/skills/file-todos/assets/todo-template.md +166 -0
- package/skills/fix-issue/SKILL.md +278 -0
- package/skills/fix-issue/references/agent-authored-exclusion.md +118 -0
- package/skills/fix-issue/references/exclude-label-jq-snippet.md +96 -0
- package/skills/flag-bootstrap/SETUP.md +142 -0
- package/skills/flag-create/SKILL.md +145 -0
- package/skills/flag-create/scripts/create.sh +273 -0
- package/skills/flag-delete/SKILL.md +167 -0
- package/skills/flag-delete/scripts/delete.sh +288 -0
- package/skills/flag-list/SKILL.md +99 -0
- package/skills/flag-list/scripts/list.sh +275 -0
- package/skills/flag-set-role/SKILL.md +229 -0
- package/skills/flag-set-role/scripts/flip.sh +774 -0
- package/skills/frontend-anti-slop/SKILL.md +106 -0
- package/skills/frontend-anti-slop/references/anti-patterns.md +199 -0
- package/skills/frontend-anti-slop/references/slop-rules.md +65 -0
- package/skills/frontend-anti-slop/scripts/tier1-scan.ts +525 -0
- package/skills/frontend-design/SKILL.md +77 -0
- package/skills/gdpr-gate/NOTICE +136 -0
- package/skills/gdpr-gate/SKILL.md +341 -0
- package/skills/gdpr-gate/references/fields.md +160 -0
- package/skills/gdpr-gate/references/layers/api-layer.md +355 -0
- package/skills/gdpr-gate/references/layers/auth-sessions.md +290 -0
- package/skills/gdpr-gate/references/layers/data-in-transit.md +331 -0
- package/skills/gdpr-gate/references/layers/data-lifecycle.md +341 -0
- package/skills/gdpr-gate/references/layers/frontend.md +249 -0
- package/skills/gdpr-gate/references/layers/testing-seeding.md +256 -0
- package/skills/gdpr-gate/references/leakage-vectors.md +248 -0
- package/skills/gdpr-gate/references/legacy/legal-consent-v1-prose.md +48 -0
- package/skills/gdpr-gate/references/legal-consent.md +140 -0
- package/skills/gdpr-gate/references/non-negotiables.md +60 -0
- package/skills/gdpr-gate/scripts/gdpr-gate.sh +271 -0
- package/skills/gdpr-gate/scripts/notice-frontmatter.sh +337 -0
- package/skills/gdpr-gate/scripts/path-denylist.txt +39 -0
- package/skills/gdpr-gate/scripts/repo-scan.sh +158 -0
- package/skills/gdpr-gate/scripts/vendor-drift-classify.sh +120 -0
- package/skills/gdpr-gate/scripts/vendor-pin-integrity.sh +237 -0
- package/skills/gemini-imagegen/SKILL.md +283 -0
- package/skills/gemini-imagegen/requirements.txt +5 -0
- package/skills/gemini-imagegen/scripts/_error_handling.py +146 -0
- package/skills/gemini-imagegen/scripts/compose_images.py +150 -0
- package/skills/gemini-imagegen/scripts/edit_image.py +137 -0
- package/skills/gemini-imagegen/scripts/gemini_images.py +256 -0
- package/skills/gemini-imagegen/scripts/generate_image.py +147 -0
- package/skills/gemini-imagegen/scripts/multi_turn_chat.py +223 -0
- package/skills/gemini-imagegen/scripts/test_error_handling.py +179 -0
- package/skills/git-worktree/SKILL.md +534 -0
- package/skills/git-worktree/scripts/git-repo-readiness-diag.sh +98 -0
- package/skills/git-worktree/scripts/worktree-manager.sh +4773 -0
- package/skills/git-worktree/test/create-from-origin-main.test.sh +116 -0
- package/skills/git-worktree/test/lease-protects-active.test.sh +1056 -0
- package/skills/git-worktree/test/no-repo-fail-loud.test.sh +88 -0
- package/skills/git-worktree/test/orphan-reaper-honest-count.test.sh +379 -0
- package/skills/git-worktree/test/reap-archive-persistence.test.sh +725 -0
- package/skills/git-worktree/test/stale-lock-sweep.test.sh +176 -0
- package/skills/go/SKILL.md +54 -0
- package/skills/growth/SKILL.md +164 -0
- package/skills/harvest-debt/SKILL.md +78 -0
- package/skills/harvest-debt/scripts/harvest-debt.sh +114 -0
- package/skills/heal-skill/SKILL.md +173 -0
- package/skills/help/SKILL.md +46 -0
- package/skills/incident/NOTICE +39 -0
- package/skills/incident/SKILL.md +395 -0
- package/skills/incident/scripts/dry-run.sh +448 -0
- package/skills/incident/scripts/redact-engine.py +412 -0
- package/skills/incident/scripts/redact-sentinel.sh +44 -0
- package/skills/incident/templates/pir.md +139 -0
- package/skills/incident/test/fixtures/dry-run-incident.json +26 -0
- package/skills/incident/test/fixtures/dry-run-secret-leak.json +26 -0
- package/skills/incident/test/fixtures/legacy-bash-scanner.sh +82 -0
- package/skills/incident/test/fixtures/positive-corpus.md +87 -0
- package/skills/incident/test/redact-sentinel.test.sh +1420 -0
- package/skills/invoice/SKILL.md +206 -0
- package/skills/kb-glossary/SKILL.md +71 -0
- package/skills/kb-glossary/references/glossary-format.md +111 -0
- package/skills/kb-glossary/references/rejected-request-register.md +115 -0
- package/skills/kb-search/SKILL.md +276 -0
- package/skills/kb-search/scripts/kb-search-cache.sh +123 -0
- package/skills/legal-audit/SKILL.md +161 -0
- package/skills/legal-generate/NOTICE +242 -0
- package/skills/legal-generate/SKILL.md +244 -0
- package/skills/legal-generate/references/templates/advisor-agreement/template.md +12 -0
- package/skills/legal-generate/references/templates/business-associate-agreement/template.md +112 -0
- package/skills/legal-generate/references/templates/cookie-notice/template.md +82 -0
- package/skills/legal-generate/references/templates/dpa-global/template.md +439 -0
- package/skills/legal-generate/references/templates/dpa-us/template.md +222 -0
- package/skills/legal-generate/references/templates/employee-offer-letter/template.md +75 -0
- package/skills/legal-generate/references/templates/master-services-agreement/template.md +252 -0
- package/skills/legal-generate/references/templates/mutual-nda/template.md +66 -0
- package/skills/legal-generate/references/templates/one-way-nda/template.md +38 -0
- package/skills/legal-generate/references/templates/privacy-policy-gdpr/template.md +427 -0
- package/skills/legal-generate/references/templates/privacy-policy-us/template.md +313 -0
- package/skills/legal-generate/references/templates/terms-of-use/template.md +75 -0
- package/skills/legal-generate/scripts/strip-vendor-credit.sh +96 -0
- package/skills/linear-fetch/SKILL.md +247 -0
- package/skills/linear-fetch/scripts/assert-no-linear-telemetry.sh +66 -0
- package/skills/linear-fetch/scripts/redact-linear-urls.sh +51 -0
- package/skills/linear-fetch/scripts/render-caller-template.sh +36 -0
- package/skills/linear-fetch/test/assert-no-linear-telemetry.test.sh +113 -0
- package/skills/linear-fetch/test/parity.test.sh +112 -0
- package/skills/linear-fetch/test/persist-safe-integration.test.sh +191 -0
- package/skills/linear-fetch/test/redact-linear-urls.test.sh +226 -0
- package/skills/merge-pr/SKILL.md +668 -0
- package/skills/model-launch-review/SKILL.md +255 -0
- package/skills/model-launch-review/scripts/audit-models.sh +501 -0
- package/skills/one-shot/SKILL.md +316 -0
- package/skills/one-shot/references/token-discipline.md +74 -0
- package/skills/operator-bootstrap/SKILL.md +412 -0
- package/skills/operator-bootstrap/template.sh +439 -0
- package/skills/operator-digest/SKILL.md +287 -0
- package/skills/operator-digest/assets/operator-digest.workflow.yml +175 -0
- package/skills/operator-digest/scripts/digest-scrub.sh +119 -0
- package/skills/operator-digest/scripts/provision-operator-digest-repo.sh +147 -0
- package/skills/operator-rephrase/SKILL.md +98 -0
- package/skills/pencil-setup/SKILL.md +201 -0
- package/skills/pencil-setup/scripts/check_deps.sh +556 -0
- package/skills/pencil-setup/scripts/copy_adapter.sh +80 -0
- package/skills/pencil-setup/scripts/package-lock.json +1172 -0
- package/skills/pencil-setup/scripts/package.json +14 -0
- package/skills/pencil-setup/scripts/pencil-error-enrichment.mjs +21 -0
- package/skills/pencil-setup/scripts/pencil-mcp-adapter.mjs +733 -0
- package/skills/pencil-setup/scripts/pencil-response-classify.mjs +38 -0
- package/skills/pencil-setup/scripts/pencil-save-gate.mjs +26 -0
- package/skills/pencil-setup/scripts/sanitize-filename.mjs +25 -0
- package/skills/plan/SKILL.md +1140 -0
- package/skills/plan/references/differential-migration-testing.md +185 -0
- package/skills/plan/references/plan-community-discovery.md +42 -0
- package/skills/plan/references/plan-founder-check.md +137 -0
- package/skills/plan/references/plan-functional-overlap.md +25 -0
- package/skills/plan/references/plan-host-fanout.md +51 -0
- package/skills/plan/references/plan-issue-templates.md +779 -0
- package/skills/plan/references/plan-network-outage-checklist.md +131 -0
- package/skills/plan/references/plan-scope-check.md +126 -0
- package/skills/plan/references/plan-sharp-edges.md +325 -0
- package/skills/plan/references/plan-signoff-lifecycle.md +12 -0
- package/skills/plan/references/webapp-cwv-observability.md +143 -0
- package/skills/plan-review/SKILL.md +91 -0
- package/skills/plan-review/lib/named-panel.mjs +58 -0
- package/skills/plan-review/workflows/plan-review.workflow.js +477 -0
- package/skills/postmerge/SKILL.md +642 -0
- package/skills/postmerge/references/deploy-status-debugging.md +138 -0
- package/skills/postmerge/references/graceful-degradation.md +20 -0
- package/skills/postmerge/references/sentry-error-count-delta.md +137 -0
- package/skills/preflight/SKILL.md +1553 -0
- package/skills/preflight/references/check-13-founder-check.md +286 -0
- package/skills/preflight/scripts/founder-check.py +1640 -0
- package/skills/preflight/scripts/parse-form-a.awk +107 -0
- package/skills/preflight/scripts/probe-verb-gate.sh +108 -0
- package/skills/product-roadmap/SKILL.md +357 -0
- package/skills/product-roadmap/scripts/roadmap-reconcile.sh +327 -0
- package/skills/provision-cloudflare/SKILL.md +67 -0
- package/skills/provision-cloudflare/scripts/provision-cloudflare.sh +271 -0
- package/skills/provision-doppler/SKILL.md +58 -0
- package/skills/provision-doppler/scripts/provision-doppler.sh +358 -0
- package/skills/provision-github/SKILL.md +59 -0
- package/skills/provision-github/scripts/provision-github.sh +300 -0
- package/skills/provision-hetzner/SKILL.md +76 -0
- package/skills/provision-hetzner/scripts/provision-hetzner.sh +262 -0
- package/skills/provision-hetzner/test/fixture/knowledge-base/legal/tenant-dpa-register.md +26 -0
- package/skills/provision-hetzner/test/fixture/provision-hetzner-dry-run.golden +34 -0
- package/skills/provision-hetzner/test/provision-hetzner-characterization.test.sh +227 -0
- package/skills/qa/SKILL.md +263 -0
- package/skills/qa/references/browser-preflight.md +22 -0
- package/skills/questionnaire-generate/SKILL.md +328 -0
- package/skills/questionnaire-generate/references/questionnaire.template +60 -0
- package/skills/rclone/SKILL.md +162 -0
- package/skills/rclone/scripts/check_setup.sh +63 -0
- package/skills/release-announce/SKILL.md +65 -0
- package/skills/release-docs/SKILL.md +92 -0
- package/skills/reproduce-bug/SKILL.md +358 -0
- package/skills/resolve-debt/SKILL.md +85 -0
- package/skills/resolve-debt/scripts/resolve-debt.py +584 -0
- package/skills/resolve-parallel/SKILL.md +45 -0
- package/skills/resolve-parallel/workflows/resolve-parallel.workflow.js +415 -0
- package/skills/resolve-pr-parallel/SKILL.md +68 -0
- package/skills/resolve-pr-parallel/workflows/resolve-pr-parallel.workflow.js +419 -0
- package/skills/resolve-todo-parallel/SKILL.md +57 -0
- package/skills/resolve-todo-parallel/workflows/resolve-todo-parallel.workflow.js +398 -0
- package/skills/review/SKILL.md +1621 -0
- package/skills/review/references/anti-slop-scanner-hook.md +40 -0
- package/skills/review/references/defect-classes-migrations.md +9 -0
- package/skills/review/references/generated-input-oracle-surfaces.md +15 -0
- package/skills/review/references/review-e2e-testing.md +116 -0
- package/skills/review/references/review-todo-structure.md +165 -0
- package/skills/review/references/risk-tier-and-fix-rounds.md +95 -0
- package/skills/review/references/semgrep-custom-rules.yaml +174 -0
- package/skills/review/references/ultrathink-phases.md +98 -0
- package/skills/review/references/wfs.md +6 -0
- package/skills/review/scripts/emit-review-trailer.sh +499 -0
- package/skills/review/scripts/ensure-semgrep.sh +99 -0
- package/skills/review/scripts/fix-round-seats.sh +197 -0
- package/skills/review/test/emit-review-trailer.test.sh +387 -0
- package/skills/review/test/ensure-semgrep.test.sh +111 -0
- package/skills/review/test/fix-round-seats.test.sh +237 -0
- package/skills/review/workflows/README.md +147 -0
- package/skills/review/workflows/review.workflow.js +667 -0
- package/skills/schedule/SKILL.md +796 -0
- package/skills/seo-aeo/SKILL.md +139 -0
- package/skills/seo-aeo/scripts/validate-csp.sh +233 -0
- package/skills/seo-aeo/scripts/validate-seo.sh +262 -0
- package/skills/ship/SKILL.md +3022 -0
- package/skills/ship/references/adr-ordinal-collision.md +47 -0
- package/skills/ship/references/affected-gate-contract.md +115 -0
- package/skills/ship/references/ci-run-diagnosis.md +29 -0
- package/skills/ship/references/ci-workflow-authoring.md +68 -0
- package/skills/ship/references/counsel-review-clo-attestation.md +38 -0
- package/skills/ship/references/cto-ruling-armed-push.md +5 -0
- package/skills/ship/references/decision-challenges-render.md +71 -0
- package/skills/ship/references/detached-battery-verdict.md +13 -0
- package/skills/ship/references/feature-tweet-draft.md +42 -0
- package/skills/ship/references/followthrough-issue-body-template.md +47 -0
- package/skills/ship/references/followthrough-stub-template.sh +92 -0
- package/skills/ship/references/merge-queue-dequeue.md +39 -0
- package/skills/ship/references/operator-holds.md +149 -0
- package/skills/ship/references/pipeline-tally-render.md +43 -0
- package/skills/ship/references/pr-overlap.md +153 -0
- package/skills/ship/references/queue-mode.md +7 -0
- package/skills/ship/references/ready-run-wait.md +36 -0
- package/skills/ship/references/red-on-main-quarantine.md +110 -0
- package/skills/ship/references/register-update-pr-pattern.md +88 -0
- package/skills/ship/references/settle-then-admin-merge.md +130 -0
- package/skills/ship/references/supabase-column-probe.md +13 -0
- package/skills/ship/scripts/auto-close-scan.sh +76 -0
- package/skills/ship/scripts/battery-owed.sh +403 -0
- package/skills/ship/scripts/hold-gate-eval.sh +410 -0
- package/skills/ship/scripts/net-issue-flow.sh +665 -0
- package/skills/ship/scripts/pr-overlap-preflight.sh +483 -0
- package/skills/ship/scripts/ship-pir-action-items-gate.sh +246 -0
- package/skills/ship/scripts/technical-ruling-gate.sh +444 -0
- package/skills/skill-creator/SKILL.md +299 -0
- package/skills/skill-creator/references/api-security.md +248 -0
- package/skills/skill-creator/references/authoring-levers.md +110 -0
- package/skills/skill-creator/references/be-clear-and-direct.md +587 -0
- package/skills/skill-creator/references/best-practices.md +431 -0
- package/skills/skill-creator/references/common-patterns.md +639 -0
- package/skills/skill-creator/references/core-principles.md +193 -0
- package/skills/skill-creator/references/executable-code.md +188 -0
- package/skills/skill-creator/references/iteration-and-testing.md +509 -0
- package/skills/skill-creator/references/official-spec.md +193 -0
- package/skills/skill-creator/references/recommended-structure.md +180 -0
- package/skills/skill-creator/references/skill-structure.md +396 -0
- package/skills/skill-creator/references/using-scripts.md +122 -0
- package/skills/skill-creator/references/using-templates.md +120 -0
- package/skills/skill-creator/references/workflows-and-validation.md +541 -0
- package/skills/skill-creator/scripts/init_skill.py +322 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +64 -0
- package/skills/skill-creator/templates/router-skill.md +73 -0
- package/skills/skill-creator/templates/simple-skill.md +34 -0
- package/skills/skill-creator/workflows/add-reference.md +96 -0
- package/skills/skill-creator/workflows/add-script.md +104 -0
- package/skills/skill-creator/workflows/add-template.md +83 -0
- package/skills/skill-creator/workflows/add-workflow.md +128 -0
- package/skills/skill-creator/workflows/audit-skill.md +159 -0
- package/skills/skill-creator/workflows/create-domain-expertise-skill.md +623 -0
- package/skills/skill-creator/workflows/create-new-skill.md +207 -0
- package/skills/skill-creator/workflows/get-guidance.md +134 -0
- package/skills/skill-creator/workflows/upgrade-to-router.md +170 -0
- package/skills/skill-creator/workflows/verify-skill.md +226 -0
- package/skills/skill-security-scan/SKILL.md +145 -0
- package/skills/skill-security-scan/references/disclaimer.md +21 -0
- package/skills/skill-security-scan/references/first-party-allowlist.yaml +38 -0
- package/skills/skill-security-scan/references/override-artifact-schema.json +68 -0
- package/skills/skill-security-scan/references/override-mechanism.md +171 -0
- package/skills/skill-security-scan/references/redirect-domains.yaml +27 -0
- package/skills/skill-security-scan/references/regex-patterns.md +136 -0
- package/skills/skill-security-scan/references/rules/code-exec.yaml +70 -0
- package/skills/skill-security-scan/references/rules/filesystem-boundary.yaml +29 -0
- package/skills/skill-security-scan/references/rules/manifest.yaml +44 -0
- package/skills/skill-security-scan/references/rules/supply-chain.yaml +36 -0
- package/skills/skill-security-scan/references/scan-meta-schema.json +63 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-soleur-style.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/clean-third-party.skill.md +26 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-codeexec.skill.md +23 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-curl-pipe-bash.skill.md +69 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-prompt-injection.skill.md +17 -0
- package/skills/skill-security-scan/references/test-fixtures/malicious-telemetry-beacon.skill.md +23 -0
- package/skills/skill-security-scan/references/typosquat-targets.yaml +65 -0
- package/skills/skill-security-scan/scripts/check-codeexec.sh +41 -0
- package/skills/skill-security-scan/scripts/check-filesystem-boundary.sh +19 -0
- package/skills/skill-security-scan/scripts/check-prompt-injection.sh +95 -0
- package/skills/skill-security-scan/scripts/check-supply-chain.sh +219 -0
- package/skills/skill-security-scan/scripts/check-telemetry-surface.sh +126 -0
- package/skills/skill-security-scan/scripts/lib.sh +197 -0
- package/skills/skill-security-scan/scripts/parse-override.sh +231 -0
- package/skills/skill-security-scan/scripts/run-scan.sh +342 -0
- package/skills/skill-security-scan/scripts/run-self-test.sh +95 -0
- package/skills/skill-security-scan/test/argv-ceiling.test.sh +180 -0
- package/skills/skill-security-scan/test/meta-dir-reap.test.sh +411 -0
- package/skills/skill-security-scan/test/parse-override.test.sh +607 -0
- package/skills/skill-security-scan/test/redact-pii-ghs-shape.test.sh +251 -0
- package/skills/social-distribute/SKILL.md +485 -0
- package/skills/spec-templates/SKILL.md +274 -0
- package/skills/sync/SKILL.md +49 -0
- package/skills/test-browser/SKILL.md +464 -0
- package/skills/test-browser/references/feature-map.md +161 -0
- package/skills/test-fix-loop/SKILL.md +159 -0
- package/skills/test-fix-loop/references/determinism-checklist.md +154 -0
- package/skills/triage/SKILL.md +402 -0
- package/skills/trigger-cron/SKILL.md +136 -0
- package/skills/trigger-cron/scripts/trigger.sh +198 -0
- package/skills/user-set-role/SKILL.md +147 -0
- package/skills/user-set-role/scripts/set-role.sh +218 -0
- package/skills/user-story-writer/SKILL.md +77 -0
- package/skills/ux-audit/SKILL.md +251 -0
- package/skills/ux-audit/references/finding.schema.json +62 -0
- package/skills/ux-audit/references/route-list.yaml +95 -0
- package/skills/ux-audit/scripts/bot-fixture.ts +270 -0
- package/skills/ux-audit/scripts/bot-signin.ts +135 -0
- package/skills/ux-audit/scripts/dedup-hash.ts +46 -0
- package/skills/work/SKILL.md +1479 -0
- package/skills/work/references/end-of-work-resume.md +7 -0
- package/skills/work/references/hook-test-main-cwd.md +24 -0
- package/skills/work/references/key-principles.md +83 -0
- package/skills/work/references/property-testing.md +122 -0
- package/skills/work/references/sql-security-definer-rpc-scaffold.sql +78 -0
- package/skills/work/references/work-agent-teams.md +97 -0
- package/skills/work/references/work-lifecycle-parallel.md +147 -0
- package/skills/work/references/work-lockfile-bumps.md +97 -0
- package/skills/work/references/work-scratch-sandboxes.md +212 -0
- package/skills/work/references/work-subagent-fanout.md +61 -0
- package/skills/work/references/work-test-harness-sharp-edges.md +73 -0
- package/skills/xcode-test/SKILL.md +360 -0
|
@@ -0,0 +1,753 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# shellcheck disable=SC2329,SC2015,SC2016 # row/mutation functions are dispatched indirectly; A && B || why is the assertion idiom; jq programs are single-quoted on purpose
|
|
3
|
+
# Suite for plugins/soleur/scripts/admin-merge-ready.sh (#8500) -- Guard 1 of the plan's Guard
|
|
4
|
+
# Contract (knowledge-base/project/plans/archive/20260922-120349-2026-09-22-feat-admin-merge-ready-script-plan.md).
|
|
5
|
+
#
|
|
6
|
+
# ── THE SEAM ─────────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
# `gh` is a PATH stub that answers ONLY the four requests the SUT is expected to make, keyed on
|
|
8
|
+
# the FULL argv (including --paginate/--slurp and the query string), and refuses anything else
|
|
9
|
+
# with exit 64 after logging `STUB-MISS <argv>`. Every row asserts the log holds no STUB-MISS, so
|
|
10
|
+
# a SUT querying the wrong endpoint cannot turn a stub refusal into the exit 3 an error row wants.
|
|
11
|
+
# `sleep` is a PATH stub too: it logs its argument, so the --wait cadence is observable.
|
|
12
|
+
#
|
|
13
|
+
# ── THE FIXTURES ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
# Every row is a jq edit of ONE real-shape base captured read-only from GitHub
|
|
15
|
+
# (test/fixtures/admin-merge-ready/, provenance in its README): 26 required contexts across two
|
|
16
|
+
# rulesets, 77 check runs, all required contexts green. No hand-written required set exists.
|
|
17
|
+
#
|
|
18
|
+
# ── MUTATION ROWS ────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
# M-rows copy the SUT, apply one edit (asserted to have landed), and require BOTH that the named
|
|
20
|
+
# row FAILS against the mutant AND that the mutant exhibits the specific defect the row exists to
|
|
21
|
+
# catch (e.g. R2: the #8458 fixture now reads ready). A mutant that merely crashes is not a kill.
|
|
22
|
+
export TMPDIR="${TMPDIR:-/var/tmp}"
|
|
23
|
+
set -uo pipefail
|
|
24
|
+
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
26
|
+
REAL_SUT="$SCRIPT_DIR/admin-merge-ready.sh"
|
|
27
|
+
BASE_FX="$SCRIPT_DIR/../test/fixtures/admin-merge-ready"
|
|
28
|
+
|
|
29
|
+
passes=0; fails=0; CASES_RUN=0; FAILED=()
|
|
30
|
+
pass() { passes=$((passes + 1)); echo " PASS: $1"; }
|
|
31
|
+
fail() { fails=$((fails + 1)); FAILED+=("$1"); echo " FAIL: $1" >&2; }
|
|
32
|
+
|
|
33
|
+
_iv_p="$passes"; _iv_f="$fails"; _iv_n="${#FAILED[@]}"
|
|
34
|
+
{ pass "self-test"; fail "self-test"; } >/dev/null 2>&1
|
|
35
|
+
if [[ "$passes" -ne $((_iv_p + 1)) || "$fails" -ne $((_iv_f + 1)) || "${#FAILED[@]}" -ne $((_iv_n + 1)) ]]; then
|
|
36
|
+
printf '[FATAL] instrument self-test: the verdict helpers did not both record\n' >&2; exit 1
|
|
37
|
+
fi
|
|
38
|
+
passes=0; fails=0; FAILED=(); CASES_RUN=0
|
|
39
|
+
|
|
40
|
+
[[ -f "$REAL_SUT" ]] || { echo "[FATAL] SUT not found at $REAL_SUT" >&2; exit 1; }
|
|
41
|
+
[[ -f "$BASE_FX/rules-branches-main.json" && -f "$BASE_FX/check-runs.json" ]] \
|
|
42
|
+
|| { echo "[FATAL] base fixtures missing under $BASE_FX" >&2; exit 1; }
|
|
43
|
+
command -v jq >/dev/null || { echo "[FATAL] jq required" >&2; exit 1; }
|
|
44
|
+
command -v python3 >/dev/null || { echo "[FATAL] python3 required (mutation rows)" >&2; exit 1; }
|
|
45
|
+
|
|
46
|
+
assert_fixture_dir() {
|
|
47
|
+
case "${1-}" in
|
|
48
|
+
"") printf 'FATAL: fixture dir is EMPTY; git -C "" would operate on %s\n' "$PWD" >&2; exit 2 ;;
|
|
49
|
+
*/../*|*/..) printf 'FATAL: fixture dir %s contains ..; refusing\n' "$1" >&2; exit 2 ;;
|
|
50
|
+
/proc/*|/sys/*|/dev/*) printf 'FATAL: fixture dir %s is a synthetic-fs path; refusing\n' "$1" >&2; exit 2 ;;
|
|
51
|
+
/|//|/.) printf 'FATAL: fixture dir resolves to the filesystem root; refusing\n' >&2; exit 2 ;;
|
|
52
|
+
/*) : ;;
|
|
53
|
+
*) printf 'FATAL: fixture dir %s is RELATIVE; refusing\n' "$1" >&2; exit 2 ;;
|
|
54
|
+
esac
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
SANDBOX="$(mktemp -d)"; assert_fixture_dir "$SANDBOX"
|
|
58
|
+
trap 'rm -rf "$SANDBOX"' EXIT
|
|
59
|
+
|
|
60
|
+
SHA=319c22bffa4c1785da52dd9af9471a9d8eef1310
|
|
61
|
+
# --green-sha carryover fixtures: GREEN is the certified prior head, P1 is the base-side
|
|
62
|
+
# parent the merge commit carries. Both are arbitrary-but-valid 40-hex.
|
|
63
|
+
GREEN=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
|
64
|
+
P1=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
|
65
|
+
PR=8534
|
|
66
|
+
SUT="$REAL_SUT"
|
|
67
|
+
TIMEOUT_BIN="$(command -v timeout)" || { echo "[FATAL] timeout(1) required" >&2; exit 1; }
|
|
68
|
+
|
|
69
|
+
# ── H6: fixture preconditions every row depends on ──────────────────────────────────────────
|
|
70
|
+
pre() { jq -e "$1" "$2" >/dev/null || { echo "[FATAL] H6 fixture precondition failed: $3 -- recapture the base (see README)" >&2; exit 1; }; }
|
|
71
|
+
pre '[.[0][] | select(.type=="required_status_checks") | .parameters.required_status_checks[]] | length >= 26' \
|
|
72
|
+
"$BASE_FX/rules-branches-main.json" ">=26 required entries"
|
|
73
|
+
pre '[.[0][] | select(.ruleset_id==13304872) | .parameters.required_status_checks[]?.context] | index("cla-evidence") != null' \
|
|
74
|
+
"$BASE_FX/rules-branches-main.json" "cla-evidence in ruleset 13304872"
|
|
75
|
+
pre '[.[0][] | select(.ruleset_id!=13304872) | .parameters.required_status_checks[]?.context] | index("cla-evidence") == null' \
|
|
76
|
+
"$BASE_FX/rules-branches-main.json" "cla-evidence ONLY in ruleset 13304872"
|
|
77
|
+
pre '[.[0][] | .type] | index("deletion") != null' "$BASE_FX/rules-branches-main.json" "a non-check rule type is present"
|
|
78
|
+
pre '[.[0].check_runs[] | select(.name=="test" and .app.id==15368 and .status=="completed" and .conclusion=="success")] | length == 1' \
|
|
79
|
+
"$BASE_FX/check-runs.json" "test present and green"
|
|
80
|
+
pre '[.[0].check_runs[] | select(.name=="CodeQL")] | all(.app.id == 57789) and length >= 1' \
|
|
81
|
+
"$BASE_FX/check-runs.json" "CodeQL run carries app 57789"
|
|
82
|
+
pre "[.[0].check_runs[].head_sha] | unique == [\"$SHA\"]" "$BASE_FX/check-runs.json" "every run carries the fixture head_sha"
|
|
83
|
+
[[ "$(grep -c -e 'https://' -e '@' "$BASE_FX"/*.json | awk -F: '{s+=$2} END {print s}')" == 0 ]] \
|
|
84
|
+
|| { echo "[FATAL] H6: base fixtures carry URLs or emails" >&2; exit 1; }
|
|
85
|
+
|
|
86
|
+
# ── the stubs ───────────────────────────────────────────────────────────────────────────────
|
|
87
|
+
BIN="$SANDBOX/bin"; mkdir -p "$BIN"
|
|
88
|
+
cat > "$BIN/gh" <<'GH'
|
|
89
|
+
#!/usr/bin/env bash
|
|
90
|
+
# Per-poll files: <name>.<poll>.json wins over <name>.json; the poll counter advances on `pr view`.
|
|
91
|
+
args="$*"
|
|
92
|
+
printf '%s\n' "$args" >> "$STUB_LOG"
|
|
93
|
+
poll=$(cat "$FX/.polls" 2>/dev/null || echo 0)
|
|
94
|
+
pick() { if [[ -f "$FX/$1.$poll.json" ]]; then cat "$FX/$1.$poll.json"; else cat "$FX/$1.json"; fi; }
|
|
95
|
+
failing() { [[ -f "$FX/$1.fail" || -f "$FX/$1.fail.$poll" ]]; }
|
|
96
|
+
enc=$(cat "$FX/expect_base_enc" 2>/dev/null || echo main)
|
|
97
|
+
runs_url="repos/{owner}/{repo}/commits/$STUB_SHA/check-runs?per_page=100&filter=all"
|
|
98
|
+
green_url="repos/{owner}/{repo}/commits/$STUB_GREEN/check-runs?per_page=100&filter=all"
|
|
99
|
+
case "$args" in
|
|
100
|
+
"pr view $STUB_PR --json state,headRefOid,baseRefName,changedFiles")
|
|
101
|
+
poll=$((poll + 1)); echo "$poll" > "$FX/.polls"
|
|
102
|
+
failing pr && exit 1
|
|
103
|
+
pick pr ;;
|
|
104
|
+
"api --paginate --slurp repos/{owner}/{repo}/pulls/$STUB_PR/files?per_page=100")
|
|
105
|
+
failing files && exit 1
|
|
106
|
+
pick files ;;
|
|
107
|
+
"api repos/{owner}/{repo}/commits/$STUB_SHA")
|
|
108
|
+
failing head && exit 1
|
|
109
|
+
pick head ;;
|
|
110
|
+
"api repos/{owner}/{repo}/compare/"*"...main")
|
|
111
|
+
failing compare && exit 1
|
|
112
|
+
pick compare ;;
|
|
113
|
+
"api repos/{owner}/{repo}/compare/$STUB_GREEN...$STUB_SHA")
|
|
114
|
+
failing cmp_added && exit 1
|
|
115
|
+
pick cmp_added ;;
|
|
116
|
+
"api repos/{owner}/{repo}/compare/$STUB_GREEN...$STUB_P1")
|
|
117
|
+
failing cmp_base && exit 1
|
|
118
|
+
pick cmp_base ;;
|
|
119
|
+
"api --paginate --slurp repos/{owner}/{repo}/rules/branches/$enc")
|
|
120
|
+
failing rules && exit 1
|
|
121
|
+
pick rules ;;
|
|
122
|
+
"api --paginate --slurp $runs_url"|"api --paginate --slurp $green_url")
|
|
123
|
+
if failing runs; then pick runs | jq -c '[.[0]]'; exit 1; fi # page 1 printed, page 2 failed
|
|
124
|
+
pick runs ;;
|
|
125
|
+
"api --slurp $runs_url") # the no---paginate mutant: only the first page is ever read
|
|
126
|
+
pick runs | jq -c '[.[0]]' ;;
|
|
127
|
+
*) printf 'STUB-MISS %s\n' "$args" >> "$STUB_LOG"; echo "stub: unexpected gh argv: $args" >&2; exit 64 ;;
|
|
128
|
+
esac
|
|
129
|
+
GH
|
|
130
|
+
cat > "$BIN/sleep" <<'SLP'
|
|
131
|
+
#!/usr/bin/env bash
|
|
132
|
+
printf '%s\n' "$*" >> "$FX/sleeps"
|
|
133
|
+
SLP
|
|
134
|
+
# The head-verdict resolver (ADR-276 S3, #9728) is stubbed through the CI_HEAD_VERDICT_BIN seam: <dir>/vstate holds
|
|
135
|
+
# "<state> [run-id] [sha]" (default n/a), <dir>/vstate.fail makes it exit 3, <dir>/vlog logs each call. The real
|
|
136
|
+
# resolver has its own suite (plugins/soleur/test/ci-head-verdict.test.sh); the wiring suite pins that this script calls it.
|
|
137
|
+
cat > "$BIN/verdict.sh" <<'VS'
|
|
138
|
+
#!/usr/bin/env bash
|
|
139
|
+
printf '%s\n' "$*" >> "$FX/vlog"
|
|
140
|
+
# The REAL error shape: a state=error marker (outside the six-state set) AND exit 3, carrying the real sha like the resolver does.
|
|
141
|
+
[[ -f "$FX/vstate.fail" ]] && { printf 'SOLEUR_CI_HEAD_VERDICT state=error pr=%s sha=%s run=none reason=api-error\n' "$STUB_PR" "$STUB_SHA"; exit 3; }
|
|
142
|
+
st=n/a; rn=none; sh="$STUB_SHA"
|
|
143
|
+
[[ -f "$FX/vstate" ]] && read -r st rn sh < "$FX/vstate"
|
|
144
|
+
printf 'SOLEUR_CI_HEAD_VERDICT state=%s pr=%s sha=%s run=%s reason=stub\n' "${st:-n/a}" "$STUB_PR" "${sh:-$STUB_SHA}" "${rn:-none}"
|
|
145
|
+
VS
|
|
146
|
+
chmod +x "$BIN/gh" "$BIN/sleep" "$BIN/verdict.sh"
|
|
147
|
+
# A PATH with jq but no gh, for the missing-tool row.
|
|
148
|
+
NOGH="$SANDBOX/nogh"; mkdir -p "$NOGH"; ln -s "$(command -v jq)" "$NOGH/jq"
|
|
149
|
+
|
|
150
|
+
# ── row plumbing ────────────────────────────────────────────────────────────────────────────
|
|
151
|
+
mkrow() { # <name> -> prints dir; fresh copy of the base
|
|
152
|
+
local d="$SANDBOX/rows/$1"; assert_fixture_dir "$d"
|
|
153
|
+
rm -rf "$d"; mkdir -p "$d"
|
|
154
|
+
cp "$BASE_FX/rules-branches-main.json" "$d/rules.json"
|
|
155
|
+
cp "$BASE_FX/check-runs.json" "$d/runs.json"
|
|
156
|
+
printf '{"state":"OPEN","headRefOid":"%s","baseRefName":"main","changedFiles":1}\n' "$SHA" > "$d/pr.json"
|
|
157
|
+
echo '[[{"filename":"plugins/soleur/x.md"}]]' > "$d/files.json"
|
|
158
|
+
# --green-sha fixtures (only read by carryover rows): head SHA is a GitHub-verified
|
|
159
|
+
# merge of GREEN (first parent) and P1 (base side), and P1 is an ancestor of main.
|
|
160
|
+
printf '{"commit":{"verification":{"verified":true}},"parents":[{"sha":"%s"},{"sha":"%s"}]}\n' \
|
|
161
|
+
"$GREEN" "$P1" > "$d/head.json"
|
|
162
|
+
echo '{"status":"ahead"}' > "$d/compare.json"
|
|
163
|
+
# --allow-local-merge fixtures (only read by the L rows): the merge's added
|
|
164
|
+
# delta is ONE docs file (disjoint from the PR's plugins/soleur/x.md) that is
|
|
165
|
+
# a byte-identical replay of the base-side delta — the proof's PASS shape.
|
|
166
|
+
jq -nc '{status:"ahead", merge_base_commit:{sha:"dddddddddddddddddddddddddddddddddddddddd"},
|
|
167
|
+
files:[{filename:"docs/notes.md", status:"added", patch:"@@ -0,0 +1 @@\n+doc"}]}' \
|
|
168
|
+
> "$d/cmp_added.json"
|
|
169
|
+
cp "$d/cmp_added.json" "$d/cmp_base.json"
|
|
170
|
+
printf '%s' "$d"
|
|
171
|
+
}
|
|
172
|
+
# jqf <dir> <file> <filter> : edit a fixture file in place
|
|
173
|
+
jqf() {
|
|
174
|
+
assert_fixture_dir "$1"
|
|
175
|
+
local t; t=$(mktemp "$SANDBOX/jqf.XXXXXX")
|
|
176
|
+
jq "$3" "$1/$2" > "$t" && mv "$t" "$1/$2" || { echo "[FATAL] jq edit failed: $3" >&2; exit 1; }
|
|
177
|
+
}
|
|
178
|
+
# setfiles <dir> <json-pages> : set the PR file list and keep changedFiles consistent with it
|
|
179
|
+
setfiles() {
|
|
180
|
+
assert_fixture_dir "$1"
|
|
181
|
+
printf '%s\n' "$2" > "$1/files.json"
|
|
182
|
+
jqf "$1" pr.json ".changedFiles = $(jq '[.[][]] | length' <<<"$2")"
|
|
183
|
+
}
|
|
184
|
+
# runs <dir> <filter-over-check_runs-array> [outfile]
|
|
185
|
+
runs() {
|
|
186
|
+
assert_fixture_dir "$1"
|
|
187
|
+
local out="${3:-runs.json}"; [[ "$out" == runs.json ]] || cp "$1/runs.json" "$1/$out"
|
|
188
|
+
jqf "$1" "$out" "map(.check_runs |= ($2))"
|
|
189
|
+
}
|
|
190
|
+
drop() { runs "$1" "map(select(.name != \"$2\"))" "${3:-runs.json}"; }
|
|
191
|
+
setrun() { runs "$1" "map(if .name == \"$2\" then $3 else . end)" "${4:-runs.json}"; }
|
|
192
|
+
|
|
193
|
+
run() { # <dir> <sut-args...> ; RUN_PATH / RUN_UNSET_POLL / RUN_POLL override the environment
|
|
194
|
+
local d="$1"; shift
|
|
195
|
+
assert_fixture_dir "$d"
|
|
196
|
+
: > "$d/log"; rm -f "$d/.polls" "$d/sleeps" "$d/vlog"
|
|
197
|
+
local -a envv=(FX="$d" STUB_LOG="$d/log" STUB_PR="$PR" STUB_SHA="$SHA" STUB_GREEN="$GREEN" STUB_P1="$P1" PATH="${RUN_PATH:-$BIN:$PATH}" CI_HEAD_VERDICT_BIN="$BIN/verdict.sh")
|
|
198
|
+
if [[ -z "${RUN_UNSET_POLL:-}" ]]; then envv+=(ADMIN_MERGE_READY_POLL_SECONDS="${RUN_POLL:-0}"); fi
|
|
199
|
+
env -u ADMIN_MERGE_READY_POLL_SECONDS "${envv[@]}" "$TIMEOUT_BIN" 30 "$BASH" "$SUT" "$@" > "$d/out" 2> "$d/err"
|
|
200
|
+
echo $? > "$d/rc"
|
|
201
|
+
}
|
|
202
|
+
why() { echo " why: $*" >&2; return 1; }
|
|
203
|
+
rc_is() { [[ "$(cat "$1/rc")" == "$2" ]] || why "rc=$(cat "$1/rc"), want $2; out: $(tail -3 "$1/out" | tr '\n' '|') err: $(tail -2 "$1/err" | tr '\n' '|')"; }
|
|
204
|
+
line() { grep -Fxq -- "$2" "$1/out" || why "missing stdout line: $2"; }
|
|
205
|
+
noline() { ! grep -Fq -- "$2" "$1/out" || why "unexpected stdout text: $2"; }
|
|
206
|
+
tailis() { local l; l=$(tail -1 "$1/out"); [[ "$l" == *" $2" ]] || why "marker tail is '$l', want '* $2'"; }
|
|
207
|
+
verdict() { tail -1 "$1/out" | grep -c >/dev/null "^SOLEUR_ADMIN_MERGE_READY verdict=$2 " || why "last line is not verdict=$2: $(tail -1 "$1/out")"; }
|
|
208
|
+
reason() { tail -1 "$1/out" | grep -c >/dev/null " reason=$2 " || why "last line lacks reason=$2: $(tail -1 "$1/out")"; }
|
|
209
|
+
nomiss() { ! grep -q '^STUB-MISS' "$1/log" || why "stub refused: $(grep '^STUB-MISS' "$1/log" | head -1)"; }
|
|
210
|
+
polls() { [[ "$(cat "$1/.polls" 2>/dev/null || echo 0)" == "$2" ]] || why "polls=$(cat "$1/.polls" 2>/dev/null), want $2"; }
|
|
211
|
+
sleeps() { [[ "$(cat "$1/sleeps" 2>/dev/null | wc -l)" == "$2" ]] || why "sleeps=$(cat "$1/sleeps" 2>/dev/null | wc -l), want $2"; }
|
|
212
|
+
count() { [[ "$(grep -c -- "$2" "$1/out")" == "$3" ]] || why "count of '$2' = $(grep -c -- "$2" "$1/out"), want $3"; }
|
|
213
|
+
logs() { grep -Fq -- "$2" "$1/log" || why "stub log lacks request: $2"; }
|
|
214
|
+
nocall() { [[ ! -s "$1/log" ]] || why "gh was called: $(head -1 "$1/log")"; }
|
|
215
|
+
|
|
216
|
+
setv() { printf '%s\n' "${*:2}" > "$1/vstate"; } # setv <dir> <state> [run-id] [sha]
|
|
217
|
+
vcalls() { [[ -f "$1/vlog" ]] && wc -l < "$1/vlog" || echo 0; }
|
|
218
|
+
vcalled() { [[ "$(vcalls "$1")" == "$2" ]] || why "resolver calls=$(vcalls "$1"), want $2"; }
|
|
219
|
+
TEST_URL_RUN8='https://example.invalid/o/r/actions/runs/8/job/1'
|
|
220
|
+
TEST_URL_RUN6='https://example.invalid/o/r/actions/runs/6/job/2'
|
|
221
|
+
|
|
222
|
+
case_ok() { CASES_RUN=$((CASES_RUN + 1)); if "$2"; then pass "$1"; else fail "$1"; fi; }
|
|
223
|
+
# case_mutant <id> <row-fn> <defect-fn> <python-old> <python-new>
|
|
224
|
+
# The row must FAIL against the mutant AND <defect-fn> must confirm the mutant shows the defect.
|
|
225
|
+
case_mutant() {
|
|
226
|
+
CASES_RUN=$((CASES_RUN + 1))
|
|
227
|
+
local id="$1" fn="$2" defect="$3" m="$SANDBOX/mut-$1.sh"
|
|
228
|
+
cp "$REAL_SUT" "$m"
|
|
229
|
+
OLD="$4" NEW="$5" python3 - "$m" <<'PY' || { fail "$id (mutation did not land)"; return; }
|
|
230
|
+
import os, sys
|
|
231
|
+
p = sys.argv[1]; s = open(p).read(); o = os.environ["OLD"]
|
|
232
|
+
if s.count(o) != 1: sys.exit(1)
|
|
233
|
+
open(p, "w").write(s.replace(o, os.environ["NEW"]))
|
|
234
|
+
PY
|
|
235
|
+
cmp -s "$m" "$REAL_SUT" && { fail "$id (mutant identical to SUT)"; return; }
|
|
236
|
+
if ( SUT="$m"; "$fn" ) 2>/dev/null; then fail "$id (row $fn still passes against the mutant)"; return; fi
|
|
237
|
+
if "$defect"; then pass "$id (row $fn reds, mutant shows the defect)"
|
|
238
|
+
else fail "$id (row $fn reds, but the mutant did not show the defect -- a crash is not a kill)"; fi
|
|
239
|
+
}
|
|
240
|
+
rowdir() { printf '%s' "$SANDBOX/rows/$1"; }
|
|
241
|
+
rc_of() { cat "$(rowdir "$1")/rc"; }
|
|
242
|
+
|
|
243
|
+
READY_TAIL="required=26 absent=[] pending=[] failed=[]"
|
|
244
|
+
|
|
245
|
+
# ── rows ────────────────────────────────────────────────────────────────────────────────────
|
|
246
|
+
row_H1() { local d; d=$(mkrow H1); assert_fixture_dir "$d"; run "$d" "$PR" "$SHA"
|
|
247
|
+
rc_is "$d" 0 && nomiss "$d" && [[ "$(cat "$d/out")" == "SOLEUR_ADMIN_MERGE_READY verdict=ready pr=$PR sha=$SHA base=main reason=all-green $READY_TAIL" ]] \
|
|
248
|
+
|| why "H1 stdout is not exactly the ready marker: $(cat "$d/out")"; }
|
|
249
|
+
row_H2() { local d; d=$(mkrow H2); assert_fixture_dir "$d"
|
|
250
|
+
setrun "$d" "e2e" '.conclusion = "skipped"'
|
|
251
|
+
setrun "$d" "markdown-lint" '.conclusion = "neutral"'
|
|
252
|
+
runs "$d" '. + [(.[] | select(.name == "lockfile-sync") | .id = (.id - 5) | .conclusion = "failure")]'
|
|
253
|
+
runs "$d" ". + [range(0;50) as \$i | {id: (9000000000 + \$i), name: \"extra-\\(\$i)\", head_sha: \"$SHA\", status: \"completed\", conclusion: \"failure\", started_at: null, app: {id: 15368}, check_suite: {id: 1}}]"
|
|
254
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 0 && nomiss "$d" && tailis "$d" "$READY_TAIL"; }
|
|
255
|
+
row_R1() { local d; d=$(mkrow R1); assert_fixture_dir "$d"; drop "$d" test; run "$d" "$PR" "$SHA"
|
|
256
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT test" && verdict "$d" not-ready && reason "$d" not-green \
|
|
257
|
+
&& tailis "$d" 'required=26 absent=["test"] pending=[] failed=[]'; }
|
|
258
|
+
row_R3() { local d; d=$(mkrow R3); assert_fixture_dir "$d"; drop "$d" tenant-integration-required; drop "$d" cla-evidence; run "$d" "$PR" "$SHA"
|
|
259
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT tenant-integration-required" && line "$d" "ABSENT cla-evidence" \
|
|
260
|
+
&& noline "$d" " enforce" && tailis "$d" 'required=26 absent=["tenant-integration-required","cla-evidence"] pending=[] failed=[]'; }
|
|
261
|
+
row_R4() { local d; d=$(mkrow R4); assert_fixture_dir "$d"
|
|
262
|
+
setrun "$d" enforce '.id = 99999999999'
|
|
263
|
+
runs "$d" '. + [(.[] | select(.name == "enforce") | .id = 100000000000 | .status = "queued" | .conclusion = null | .started_at = null)]'
|
|
264
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "PENDING enforce (queued)" \
|
|
265
|
+
&& tailis "$d" 'required=26 absent=[] pending=["enforce"] failed=[]'; }
|
|
266
|
+
row_R5() { local d; d=$(mkrow R5); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; run "$d" "$PR" "$SHA"
|
|
267
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)" && tailis "$d" 'required=26 absent=[] pending=[] failed=["test"]'; }
|
|
268
|
+
row_R6() { local c d; for c in stale cancelled bogus-conclusion; do d=$(mkrow "R6-$c"); assert_fixture_dir "$d"
|
|
269
|
+
setrun "$d" test ".conclusion = \"$c\""; run "$d" "$PR" "$SHA"
|
|
270
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test ($c)" || return 1; done; }
|
|
271
|
+
row_R7() { local d; d=$(mkrow R7); assert_fixture_dir "$d"; drop "$d" cla-evidence; run "$d" "$PR" "$SHA"
|
|
272
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT cla-evidence"; }
|
|
273
|
+
row_R8() { local d; d=$(mkrow R8); assert_fixture_dir "$d"; setrun "$d" CodeQL '.app.id = 15368'; run "$d" "$PR" "$SHA"
|
|
274
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT CodeQL"; }
|
|
275
|
+
row_R9() { local d
|
|
276
|
+
d=$(mkrow R9a); assert_fixture_dir "$d"; touch "$d/rules.fail"; run "$d" "$PR" "$SHA"
|
|
277
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && logs "$d" "rules/branches/main" || return 1
|
|
278
|
+
d=$(mkrow R9b); assert_fixture_dir "$d"; echo '[[]]' > "$d/rules.json"; run "$d" "$PR" "$SHA"
|
|
279
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && reason "$d" empty-required || return 1
|
|
280
|
+
d=$(mkrow R9c); assert_fixture_dir "$d"; jqf "$d" runs.json '[.[0] | .check_runs |= map(select(.name != "test"))] + [{total_count: 1, check_runs: [(.[0].check_runs[] | select(.name == "test"))]}]'
|
|
281
|
+
touch "$d/runs.fail"; run "$d" "$PR" "$SHA"
|
|
282
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && logs "$d" "check-runs" || return 1
|
|
283
|
+
d=$(mkrow R9d); assert_fixture_dir "$d"; setfiles "$d" '[[{"filename":".github/workflows/x.yml"}]]'; touch "$d/files.fail"; run "$d" "$PR" "$SHA"
|
|
284
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && logs "$d" "pulls/$PR/files" || return 1
|
|
285
|
+
d=$(mkrow R9e); assert_fixture_dir "$d"; touch "$d/pr.fail"; run "$d" "$PR" "$SHA"
|
|
286
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error || return 1
|
|
287
|
+
d=$(mkrow R9f); assert_fixture_dir "$d"; echo '<html>502 Bad Gateway</html>' > "$d/runs.json"; run "$d" "$PR" "$SHA"
|
|
288
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error || return 1
|
|
289
|
+
d=$(mkrow R9g); assert_fixture_dir "$d"; : > "$d/runs.json"; run "$d" "$PR" "$SHA"
|
|
290
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error || return 1
|
|
291
|
+
d=$(mkrow R9h); assert_fixture_dir "$d"; : > "$d/files.json"; run "$d" "$PR" "$SHA"
|
|
292
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error; }
|
|
293
|
+
row_R10() { local d; d=$(mkrow R10); assert_fixture_dir "$d"; jqf "$d" pr.json '.headRefOid = "0000000000000000000000000000000000000000"'; run "$d" "$PR" "$SHA"
|
|
294
|
+
rc_is "$d" 4 && nomiss "$d" && verdict "$d" stale && reason "$d" head-moved; }
|
|
295
|
+
row_R11() { local d; d=$(mkrow R11); assert_fixture_dir "$d"
|
|
296
|
+
jqf "$d" runs.json '[.[0] | .check_runs |= map(select(.name != "test"))] + [{total_count: 1, check_runs: [(.[0].check_runs[] | select(.name == "test"))]}]'
|
|
297
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 0 && nomiss "$d" && tailis "$d" "$READY_TAIL"; }
|
|
298
|
+
row_R12() { local d; d=$(mkrow R12); assert_fixture_dir "$d"; jqf "$d" rules.json '.[0][0].parameters.required_status_checks[0].integration_id = null'
|
|
299
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && reason "$d" unpinned && grep -q 'unpinned required context(s) \["enforce"\]' "$d/err" \
|
|
300
|
+
|| why "R12 does not name the unpinned context: $(cat "$d/err")"; }
|
|
301
|
+
row_R13() { local d; d=$(mkrow R13); assert_fixture_dir "$d"; jqf "$d" pr.json '.state = "MERGED"'; run "$d" "$PR" "$SHA"
|
|
302
|
+
rc_is "$d" 4 && nomiss "$d" && verdict "$d" stale && line "$d" "NOT-OPEN: PR is not open"; }
|
|
303
|
+
row_R14() { local d a; d=$(mkrow R14); assert_fixture_dir "$d"
|
|
304
|
+
for a in "" "abc $SHA" "$PR ${SHA:0:7}" "$PR $SHA --timeout 0" "$PR $SHA --bogus" "$PR $SHA --base bad;name"; do
|
|
305
|
+
# shellcheck disable=SC2086
|
|
306
|
+
run "$d" $a; rc_is "$d" 2 && verdict "$d" error && nocall "$d" || return 1
|
|
307
|
+
done
|
|
308
|
+
RUN_POLL=abc run "$d" "$PR" "$SHA" --wait; rc_is "$d" 2 && verdict "$d" error && nocall "$d"; }
|
|
309
|
+
row_R15() { local d; d=$(mkrow R15); assert_fixture_dir "$d"; jqf "$d" pr.json '.baseRefName = "feat/x"'; echo 'feat%2Fx' > "$d/expect_base_enc"
|
|
310
|
+
run "$d" "$PR" "$SHA" --base feat/x; rc_is "$d" 0 && nomiss "$d" && logs "$d" "rules/branches/feat%2Fx"; }
|
|
311
|
+
row_R16() { local d; d=$(mkrow R16); assert_fixture_dir "$d"
|
|
312
|
+
drop "$d" test runs.1.json; setrun "$d" test '.status = "in_progress" | .conclusion = null' runs.2.json
|
|
313
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 0 && nomiss "$d" && polls "$d" 3 && count "$d" '^WAIT ' 2 && verdict "$d" ready \
|
|
314
|
+
&& line "$d" 'WAIT poll=1/60 absent=["test"] pending=[]' && line "$d" 'WAIT poll=2/60 absent=[] pending=["test"]' && sleeps "$d" 2; }
|
|
315
|
+
row_R17() { local d; d=$(mkrow R17); assert_fixture_dir "$d"
|
|
316
|
+
drop "$d" test runs.1.json; setrun "$d" test '.conclusion = "failure"' runs.2.json; setrun "$d" test '.conclusion = "success"' runs.3.json
|
|
317
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && nomiss "$d" && polls "$d" 2 && verdict "$d" not-ready && line "$d" "FAILED test (failure)"; }
|
|
318
|
+
row_R18() { local d; d=$(mkrow R18); assert_fixture_dir "$d"; drop "$d" test runs.1.json
|
|
319
|
+
jq '.headRefOid = "1111111111111111111111111111111111111111"' "$d/pr.json" > "$d/pr.2.json"
|
|
320
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 4 && nomiss "$d" && polls "$d" 2 && verdict "$d" stale; }
|
|
321
|
+
row_R19() { local d; d=$(mkrow R19); assert_fixture_dir "$d"; drop "$d" test
|
|
322
|
+
run "$d" "$PR" "$SHA" --wait --timeout 180; rc_is "$d" 1 && nomiss "$d" && polls "$d" 3 && sleeps "$d" 2 && verdict "$d" timeout \
|
|
323
|
+
&& tailis "$d" 'required=26 absent=["test"] pending=[] failed=[]' || return 1
|
|
324
|
+
# A timeout that is not a multiple of 60 rounds UP: 90 s is two polls, never one or zero.
|
|
325
|
+
run "$d" "$PR" "$SHA" --wait --timeout 90; rc_is "$d" 1 && polls "$d" 2 && verdict "$d" timeout; }
|
|
326
|
+
row_R20() { local d; d=$(mkrow R20); assert_fixture_dir "$d"; drop "$d" test runs.1.json; touch "$d/rules.fail.2"
|
|
327
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 3 && nomiss "$d" && polls "$d" 2 && verdict "$d" error; }
|
|
328
|
+
row_R21() { local d; d=$(mkrow R21); assert_fixture_dir "$d"
|
|
329
|
+
runs "$d" '. + [(.[] | select(.name == "CodeQL") | .id = (.id + 1000) | .app.id = 15368 | .conclusion = "failure")]'
|
|
330
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 0 && nomiss "$d"; }
|
|
331
|
+
row_R22() { local d; d=$(mkrow R22); assert_fixture_dir "$d"; setrun "$d" CodeQL '.conclusion = "failure"'
|
|
332
|
+
runs "$d" '. + [(.[] | select(.name == "CodeQL") | .id = (.id + 1000) | .app.id = 15368 | .conclusion = "success")]'
|
|
333
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED CodeQL (failure)"; }
|
|
334
|
+
row_R23() { local d; d=$(mkrow R23); assert_fixture_dir "$d"; drop "$d" test
|
|
335
|
+
jqf "$d" rules.json '.[0] |= map(if .ruleset_id == 13304872 and .type == "required_status_checks" then .parameters.required_status_checks += [{context: "test", integration_id: 15368}] else . end)'
|
|
336
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && count "$d" '^ABSENT test$' 1 && tailis "$d" 'required=26 absent=["test"] pending=[] failed=[]'; }
|
|
337
|
+
row_R24() { local d; d=$(mkrow R24); assert_fixture_dir "$d"; setrun "$d" test '.status = "mystery" | .conclusion = null'; run "$d" "$PR" "$SHA"
|
|
338
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (unknown status mystery)"; }
|
|
339
|
+
row_R25() { local d i; d=$(mkrow R25); assert_fixture_dir "$d"
|
|
340
|
+
for i in 1 2 3 4 5 6 7; do setrun "$d" test '.status = "in_progress" | .conclusion = null' "runs.$i.json"; done
|
|
341
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 0 && nomiss "$d" && polls "$d" 8 && count "$d" '^HEARTBEAT ' 1 \
|
|
342
|
+
&& count "$d" '^HEARTBEAT poll=5/' 1 && count "$d" '^WAIT ' 1; }
|
|
343
|
+
row_R26() { local d p
|
|
344
|
+
for p in '[[{"filename":"README.md"}],[{"filename":".github/workflows/new.yml"}]]' \
|
|
345
|
+
'[[{"filename":".github/actions/setup/action.yml"}],[{"filename":"README.md"}]]' \
|
|
346
|
+
'[[{"filename":"ci/renamed.yml","previous_filename":".github/workflows/ci.yml"}]]'; do
|
|
347
|
+
d=$(mkrow R26); assert_fixture_dir "$d"; setfiles "$d" "$p"; run "$d" "$PR" "$SHA"
|
|
348
|
+
rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready && reason "$d" untrusted-ci && grep -q '^UNTRUSTED-CI' "$d/out" \
|
|
349
|
+
&& noline "$d" ".yml" || return 1
|
|
350
|
+
done
|
|
351
|
+
# Terminal under --wait: one poll, no waiting out the budget.
|
|
352
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && polls "$d" 1 && verdict "$d" not-ready && reason "$d" untrusted-ci; }
|
|
353
|
+
row_R27() { local c d suite
|
|
354
|
+
for c in skipped neutral; do
|
|
355
|
+
d=$(mkrow "R27-$c"); assert_fixture_dir "$d"
|
|
356
|
+
suite=$(jq '.[0].check_runs[] | select(.name == "tenant-integration-required") | .check_suite.id' "$d/runs.json")
|
|
357
|
+
setrun "$d" tenant-integration-required ".conclusion = \"$c\""
|
|
358
|
+
runs "$d" ". + [{id: 8000000000, name: \"some-shard\", head_sha: \"$SHA\", status: \"completed\", conclusion: \"failure\", started_at: null, app: {id: 15368}, check_suite: {id: $suite}}]"
|
|
359
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED tenant-integration-required ($c-after-failure)" || return 1
|
|
360
|
+
# The dependency is being RE-RUN: its latest run is in progress, the skip is not yet recreated.
|
|
361
|
+
d=$(mkrow "R27-$c-rerun"); assert_fixture_dir "$d"
|
|
362
|
+
setrun "$d" tenant-integration-required ".conclusion = \"$c\""
|
|
363
|
+
runs "$d" ". + [{id: 8000000000, name: \"some-shard\", head_sha: \"$SHA\", status: \"completed\", conclusion: \"failure\", started_at: null, app: {id: 15368}, check_suite: {id: $suite}}, {id: 999999999999, name: \"some-shard\", head_sha: \"$SHA\", status: \"in_progress\", conclusion: null, started_at: null, app: {id: 15368}, check_suite: {id: $suite}}]"
|
|
364
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "PENDING tenant-integration-required ($c-while-suite-running)" || return 1
|
|
365
|
+
d=$(mkrow "R27-$c-clean"); assert_fixture_dir "$d"; setrun "$d" tenant-integration-required ".conclusion = \"$c\""
|
|
366
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 0 && nomiss "$d" || return 1
|
|
367
|
+
done; }
|
|
368
|
+
row_R28() { local d; d=$(mkrow R28); assert_fixture_dir "$d"; drop "$d" cla-evidence
|
|
369
|
+
# Rules split over two pages, the CLA ruleset on page 2 only.
|
|
370
|
+
jqf "$d" rules.json '[[.[0][] | select(.ruleset_id != 13304872)], [.[0][] | select(.ruleset_id == 13304872)]]'
|
|
371
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT cla-evidence"; }
|
|
372
|
+
row_R29() { local d; d=$(mkrow R29); assert_fixture_dir "$d"; jqf "$d" rules.json '.[0] += [{type: "workflows", ruleset_id: 1}]'
|
|
373
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && reason "$d" unsupported-rule; }
|
|
374
|
+
row_R30() { local d; d=$(mkrow R30); assert_fixture_dir "$d"; jqf "$d" pr.json '.changedFiles = 2'
|
|
375
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 3 && nomiss "$d" && reason "$d" incomplete-files || return 1
|
|
376
|
+
d=$(mkrow R30b); assert_fixture_dir "$d"; setfiles "$d" "[[$(jq -nc '[range(0;3000) | {filename: "f\(.)"}] | .[]' | paste -sd,)]]"
|
|
377
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 3 && nomiss "$d" && reason "$d" incomplete-files; }
|
|
378
|
+
row_R31() { local d; d=$(mkrow R31); assert_fixture_dir "$d"; jqf "$d" pr.json '.baseRefName = "develop"'
|
|
379
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready && reason "$d" base-mismatch; }
|
|
380
|
+
row_R32() { local d; d=$(mkrow R32); assert_fixture_dir "$d"; setrun "$d" test '.head_sha = "2222222222222222222222222222222222222222"'
|
|
381
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT test"; }
|
|
382
|
+
row_R33() { local d; d=$(mkrow R33); assert_fixture_dir "$d"
|
|
383
|
+
RUN_PATH="$NOGH" run "$d" "$PR" "$SHA"; rc_is "$d" 3 && verdict "$d" error && reason "$d" missing-tool; }
|
|
384
|
+
row_R34() { local d; d=$(mkrow R34); assert_fixture_dir "$d"; drop "$d" test runs.1.json
|
|
385
|
+
RUN_UNSET_POLL=1 run "$d" "$PR" "$SHA" --wait; rc_is "$d" 0 && [[ "$(cat "$d/sleeps")" == "60" ]] || why "default poll interval is not 60: $(cat "$d/sleeps" 2>/dev/null)"; }
|
|
386
|
+
row_R35() { local d; d=$(mkrow R35); assert_fixture_dir "$d"
|
|
387
|
+
# The same context required from two different apps: both entries must be satisfied.
|
|
388
|
+
jqf "$d" rules.json '.[0] |= map(if .ruleset_id == 13304872 and .type == "required_status_checks" then .parameters.required_status_checks += [{context: "CodeQL", integration_id: 15368}] else . end)'
|
|
389
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT CodeQL" && tailis "$d" 'required=27 absent=["CodeQL"] pending=[] failed=[]'; }
|
|
390
|
+
# R36/R37 (#9454): the POST-ADOPTION live rule shape -- the CI Required ruleset gains a
|
|
391
|
+
# `merge_queue` rule and LOSES its `CodeQL` required context (CodeQL is advisory: it cannot report on
|
|
392
|
+
# `merge_group`). The base capture above is the PRE-adoption shape (26 contexts incl. CodeQL/57789), so
|
|
393
|
+
# these rows derive the new shape from it rather than hand-writing a required set.
|
|
394
|
+
# R36: merge_queue present + CodeQL not required -> READY with required=25 (24 CI Required minus
|
|
395
|
+
# CodeQL = 23, plus the 2 CLA contexts); a FAILED advisory CodeQL run must not block.
|
|
396
|
+
# Before the fix the script errored `unsupported-rule` on the `merge_queue` type, so every
|
|
397
|
+
# admin-merge gate would have failed closed the moment the queue went live.
|
|
398
|
+
# R37: the allowlist stayed SPECIFIC -- merge_queue present alongside an unevaluated type
|
|
399
|
+
# (`workflows`) is still an `unsupported-rule` error.
|
|
400
|
+
_mq_rule='{type: "merge_queue", ruleset_id: 14145388, parameters: {merge_method: "SQUASH", grouping_strategy: "ALLGREEN", max_entries_to_merge: 1, min_entries_to_merge: 1, min_entries_to_merge_wait_minutes: 0, max_entries_to_build: 2, check_response_timeout_minutes: 60}}'
|
|
401
|
+
_post_adoption_rules() { # <dir>
|
|
402
|
+
jqf "$1" rules.json "(.[0] |= map(if .type == \"required_status_checks\" then .parameters.required_status_checks |= map(select(.context != \"CodeQL\")) else . end)) | (.[0] += [$_mq_rule])"
|
|
403
|
+
}
|
|
404
|
+
row_R36() { local d; d=$(mkrow R36); assert_fixture_dir "$d"; _post_adoption_rules "$d"
|
|
405
|
+
setrun "$d" CodeQL '.conclusion = "failure"'
|
|
406
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 0 && nomiss "$d" && verdict "$d" ready \
|
|
407
|
+
&& tailis "$d" 'required=25 absent=[] pending=[] failed=[]'; }
|
|
408
|
+
row_R37() { local d; d=$(mkrow R37); assert_fixture_dir "$d"; _post_adoption_rules "$d"
|
|
409
|
+
jqf "$d" rules.json '.[0] += [{type: "workflows", ruleset_id: 1}]'
|
|
410
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && reason "$d" unsupported-rule; }
|
|
411
|
+
row_help() { local d; d=$(mkrow help); assert_fixture_dir "$d"; run "$d" --help
|
|
412
|
+
rc_is "$d" 0 && grep -q SOLEUR_ADMIN_MERGE_READY "$d/out" && nocall "$d"; }
|
|
413
|
+
|
|
414
|
+
# ── --green-sha carryover rows ───────────────────────────────────────────────────────────────
|
|
415
|
+
# mkrow's head.json is already the valid shape: verified 2-parent commit [GREEN, P1] and
|
|
416
|
+
# compare.json says P1 is an ancestor-or-equal of main. Carryover rows mutate ONE property.
|
|
417
|
+
row_G1() { local d; d=$(mkrow G1); assert_fixture_dir "$d"
|
|
418
|
+
# The carryover grades GREEN's check runs: the fixture's head_sha must be GREEN.
|
|
419
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
420
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
421
|
+
rc_is "$d" 0 && nomiss "$d" && verdict "$d" ready \
|
|
422
|
+
&& logs "$d" "api repos/{owner}/{repo}/commits/$SHA" && logs "$d" "compare/$P1...main" \
|
|
423
|
+
&& logs "$d" "commits/$GREEN/check-runs" \
|
|
424
|
+
&& ! grep -q "commits/$SHA/check-runs" "$d/log" \
|
|
425
|
+
&& grep -Fq "GREEN-CARRYOVER: head $SHA" "$d/out" \
|
|
426
|
+
&& tailis "$d" "$READY_TAIL" \
|
|
427
|
+
|| why "G1: $(tail -3 "$d/out" | tr '\n' '|') err: $(tail -2 "$d/err" | tr '\n' '|')"; }
|
|
428
|
+
row_G2() { local d; d=$(mkrow G2); assert_fixture_dir "$d"
|
|
429
|
+
jqf "$d" head.json '.parents = [{"sha":"'$GREEN'"}]'
|
|
430
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
431
|
+
rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready && reason "$d" carryover-not-merge \
|
|
432
|
+
&& grep -Fq "GREEN-CARRYOVER refused" "$d/out"; }
|
|
433
|
+
row_G3() { local d; d=$(mkrow G3); assert_fixture_dir "$d"
|
|
434
|
+
jqf "$d" head.json '.commit.verification.verified = false'
|
|
435
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
436
|
+
rc_is "$d" 1 && nomiss "$d" && reason "$d" carryover-unverified; }
|
|
437
|
+
row_G4() { local d; d=$(mkrow G4); assert_fixture_dir "$d"
|
|
438
|
+
jqf "$d" head.json '.parents[0].sha = "cccccccccccccccccccccccccccccccccccccccc"'
|
|
439
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
440
|
+
rc_is "$d" 1 && nomiss "$d" && reason "$d" carryover-first-parent; }
|
|
441
|
+
row_G5() { local d s; for s in behind diverged; do d=$(mkrow "G5-$s"); assert_fixture_dir "$d"
|
|
442
|
+
printf '{"status":"%s"}' "$s" > "$d/compare.json"
|
|
443
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
444
|
+
rc_is "$d" 1 && nomiss "$d" && reason "$d" carryover-not-base || return 1; done; }
|
|
445
|
+
row_G6() { local d; d=$(mkrow G6); assert_fixture_dir "$d"
|
|
446
|
+
# Carryover proof holds but the PRIOR head's suite went red (a re-run): the gate must see it.
|
|
447
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
448
|
+
setrun "$d" test '.conclusion = "failure"'
|
|
449
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
450
|
+
rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)"; }
|
|
451
|
+
row_G7() { local d; d=$(mkrow G7); assert_fixture_dir "$d"
|
|
452
|
+
# UNTRUSTED-CI refuses FIRST: the carryover endpoints are never even called.
|
|
453
|
+
setfiles "$d" '[[{"filename":".github/workflows/x.yml"}]]'
|
|
454
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
455
|
+
rc_is "$d" 1 && reason "$d" untrusted-ci && ! grep -q 'compare/' "$d/log" \
|
|
456
|
+
|| why "G7: $(tail -2 "$d/out" | tr '\n' '|')"; }
|
|
457
|
+
row_G8() { local d; d=$(mkrow G8); assert_fixture_dir "$d"
|
|
458
|
+
run "$d" "$PR" "$SHA" --green-sha abc123; rc_is "$d" 2 && nocall "$d" || return 1
|
|
459
|
+
run "$d" "$PR" "$SHA" --green-sha "$SHA"; rc_is "$d" 2 && nocall "$d"; }
|
|
460
|
+
|
|
461
|
+
# ── --allow-local-merge rows: the unsigned-carryover arm (#9401) ───────────────
|
|
462
|
+
# mkrow's cmp_added.json/cmp_base.json are a clean docs-only replay of one file
|
|
463
|
+
# (docs/notes.md, disjoint from the PR's plugins/soleur/x.md). mklocal() flips
|
|
464
|
+
# verification off so the head is an unsigned local merge; each row then mutates
|
|
465
|
+
# ONE property of the proof.
|
|
466
|
+
mklocal() { assert_fixture_dir "$1"; jqf "$1" head.json '.commit.verification.verified = false'; }
|
|
467
|
+
row_L1() { local d; d=$(mkrow L1); assert_fixture_dir "$d"
|
|
468
|
+
mklocal "$d"; jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
469
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
470
|
+
rc_is "$d" 0 && nomiss "$d" && verdict "$d" ready && reason "$d" carryover-local-docs \
|
|
471
|
+
&& logs "$d" "compare/$GREEN...$SHA" && logs "$d" "compare/$GREEN...$P1" \
|
|
472
|
+
&& logs "$d" "commits/$GREEN/check-runs" \
|
|
473
|
+
&& ! grep -q "commits/$SHA/check-runs" "$d/log" \
|
|
474
|
+
&& grep -Fq "GREEN-CARRYOVER: head $SHA is a clean local merge" "$d/out" \
|
|
475
|
+
&& tailis "$d" "$READY_TAIL" \
|
|
476
|
+
|| why "L1: $(tail -3 "$d/out" | tr '\n' '|') err: $(tail -2 "$d/err" | tr '\n' '|')"; }
|
|
477
|
+
row_L2() { local d; d=$(mkrow L2); assert_fixture_dir "$d"
|
|
478
|
+
mklocal "$d"
|
|
479
|
+
# The runs must grade GREEN: a mutant that wrongly certifies must reach
|
|
480
|
+
# verdict=ready for the defect probe to see it (absent contexts would still
|
|
481
|
+
# read not-ready, masking the smuggling the mutation row exists to catch).
|
|
482
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
483
|
+
# A file the merge added beyond the base-side delta is smuggled.
|
|
484
|
+
jqf "$d" cmp_added.json '.files += [{filename:"docs/smuggled.md", status:"added", patch:"@@ s"}]'
|
|
485
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
486
|
+
rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready && reason "$d" carryover-local-not-clean; }
|
|
487
|
+
row_L3() { local d; d=$(mkrow L3); assert_fixture_dir "$d"
|
|
488
|
+
mklocal "$d"
|
|
489
|
+
# Same path, divergent patch: conflict resolution or authored content.
|
|
490
|
+
jqf "$d" cmp_added.json '.files[0].patch = "@@ -0,0 +1 @@\\n+edited"'
|
|
491
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
492
|
+
rc_is "$d" 1 && reason "$d" carryover-local-not-clean; }
|
|
493
|
+
row_L4() { local d; d=$(mkrow L4); assert_fixture_dir "$d"
|
|
494
|
+
mklocal "$d"
|
|
495
|
+
# The runs must grade GREEN: a mutant that wrongly certifies must reach
|
|
496
|
+
# verdict=ready for the defect probe to see it (absent contexts would still
|
|
497
|
+
# read not-ready, masking the smuggling the mutation row exists to catch).
|
|
498
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
499
|
+
# A clean replay of base-side CODE is still refused: the gate cannot replay it.
|
|
500
|
+
jqf "$d" cmp_added.json '.files[0].filename = "src/x.ts"'
|
|
501
|
+
jqf "$d" cmp_base.json '.files[0].filename = "src/x.ts"'
|
|
502
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
503
|
+
rc_is "$d" 1 && reason "$d" carryover-local-nondocs; }
|
|
504
|
+
row_L5() { local d; d=$(mkrow L5); assert_fixture_dir "$d"
|
|
505
|
+
mklocal "$d"
|
|
506
|
+
# The runs must grade GREEN: a mutant that wrongly certifies must reach
|
|
507
|
+
# verdict=ready for the defect probe to see it (absent contexts would still
|
|
508
|
+
# read not-ready, masking the smuggling the mutation row exists to catch).
|
|
509
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
510
|
+
# The merged delta touches the PR's own file -> overlap.
|
|
511
|
+
jqf "$d" cmp_added.json '.files[0].filename = "plugins/soleur/x.md" | .files[0].status = "modified"'
|
|
512
|
+
jqf "$d" cmp_base.json '.files[0].filename = "plugins/soleur/x.md" | .files[0].status = "modified"'
|
|
513
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
514
|
+
rc_is "$d" 1 && reason "$d" carryover-local-overlap; }
|
|
515
|
+
row_L6() { local d; d=$(mkrow L6); assert_fixture_dir "$d"
|
|
516
|
+
mklocal "$d"
|
|
517
|
+
# The runs must grade GREEN: a mutant that wrongly certifies must reach
|
|
518
|
+
# verdict=ready for the defect probe to see it (absent contexts would still
|
|
519
|
+
# read not-ready, masking the smuggling the mutation row exists to catch).
|
|
520
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
521
|
+
# No flag: the unsigned head is refused by the verified arm, as before.
|
|
522
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"
|
|
523
|
+
rc_is "$d" 1 && nomiss "$d" && reason "$d" carryover-unverified \
|
|
524
|
+
&& ! grep -q 'compare/' "$d/log" || why "L6: $(cat "$d/log")"; }
|
|
525
|
+
row_L7() { local d; d=$(mkrow L7); assert_fixture_dir "$d"
|
|
526
|
+
# The flag does not rescue a head that is not a 2-parent merge of GREEN.
|
|
527
|
+
jqf "$d" head.json '.parents = [{"sha":"'$GREEN'"}]'
|
|
528
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
529
|
+
rc_is "$d" 1 && reason "$d" carryover-not-merge || return 1
|
|
530
|
+
d=$(mkrow L7b); assert_fixture_dir "$d"
|
|
531
|
+
jqf "$d" head.json '.commit.verification.verified = false | .parents[0].sha = "cccccccccccccccccccccccccccccccccccccccc"'
|
|
532
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
533
|
+
rc_is "$d" 1 && reason "$d" carryover-first-parent; }
|
|
534
|
+
row_L8() { local d; d=$(mkrow L8); assert_fixture_dir "$d"
|
|
535
|
+
mklocal "$d"; printf '{"status":"behind"}' > "$d/compare.json"
|
|
536
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
537
|
+
rc_is "$d" 1 && reason "$d" carryover-not-base \
|
|
538
|
+
&& ! grep -q "compare/$GREEN" "$d/log" || why "L8: the delta compares must not run once p1 is off-base"; }
|
|
539
|
+
row_L9() { local d; d=$(mkrow L9); assert_fixture_dir "$d"
|
|
540
|
+
mklocal "$d"
|
|
541
|
+
# A >=300-entry compare delta cannot be proven complete -> error, not refuse.
|
|
542
|
+
jqf "$d" cmp_added.json '.files = [range(0;300) | {filename: "docs/f\(.).md", status:"added", patch:"@@ x"}]'
|
|
543
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
544
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error && reason "$d" incomplete-files; }
|
|
545
|
+
row_L10() { local d; d=$(mkrow L10); assert_fixture_dir "$d"
|
|
546
|
+
mklocal "$d"; jqf "$d" cmp_added.json 'del(.files[0].patch)'
|
|
547
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
548
|
+
rc_is "$d" 1 && reason "$d" carryover-local-not-clean; }
|
|
549
|
+
row_L11() { local d; d=$(mkrow L11); assert_fixture_dir "$d"
|
|
550
|
+
mklocal "$d"; echo '<html>502 Bad Gateway</html>' > "$d/cmp_added.json"
|
|
551
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
552
|
+
rc_is "$d" 3 && nomiss "$d" && verdict "$d" error; }
|
|
553
|
+
row_L12() { local d; d=$(mkrow L12); assert_fixture_dir "$d"
|
|
554
|
+
run "$d" "$PR" "$SHA" --allow-local-merge
|
|
555
|
+
rc_is "$d" 2 && verdict "$d" error && nocall "$d"; }
|
|
556
|
+
row_L13() { local d; d=$(mkrow L13); assert_fixture_dir "$d"
|
|
557
|
+
# Verified head + flag: the stronger VERIFIED arm wins — the flag is inert
|
|
558
|
+
# (elif ordering is load-bearing) and the delta compares never run.
|
|
559
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
560
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
561
|
+
rc_is "$d" 0 && nomiss "$d" && verdict "$d" ready && reason "$d" all-green \
|
|
562
|
+
&& logs "$d" "compare/$P1...main" \
|
|
563
|
+
&& ! grep -q "compare/$GREEN" "$d/log"; }
|
|
564
|
+
row_L14() { local d; d=$(mkrow L14); assert_fixture_dir "$d"
|
|
565
|
+
mklocal "$d"; jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"
|
|
566
|
+
# A merge that DROPPED the base-side delta (e.g. -s ours: parents [G, tip]
|
|
567
|
+
# with G's tree) produces an EMPTY added delta — subset-wise fine, but the
|
|
568
|
+
# admin merge would revert main's content. The bijection refuses it.
|
|
569
|
+
jqf "$d" cmp_added.json '.files = []'
|
|
570
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
571
|
+
rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready \
|
|
572
|
+
&& reason "$d" carryover-local-not-clean; }
|
|
573
|
+
row_L15() { local d; d=$(mkrow L15); assert_fixture_dir "$d"
|
|
574
|
+
mklocal "$d"
|
|
575
|
+
# A rename's SOURCE is part of the identity: same dest+patch but a different
|
|
576
|
+
# previous_filename means the merge replayed a different file.
|
|
577
|
+
jqf "$d" cmp_added.json '.files[0].status = "renamed" | .files[0].previous_filename = "docs/old.md"'
|
|
578
|
+
jqf "$d" cmp_base.json '.files[0].status = "renamed" | .files[0].previous_filename = "docs/other.md"'
|
|
579
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN" --allow-local-merge
|
|
580
|
+
rc_is "$d" 1 && reason "$d" carryover-local-not-clean; }
|
|
581
|
+
|
|
582
|
+
# ── ADR-276 S3 (#9728): the draft-era red `test` row of a PR that was marked ready ─────────────
|
|
583
|
+
# Under CI_DRAFT_LIGHT a draft's `test` is red by design. The latest-row-per-context rule already makes a NEWER ready-run
|
|
584
|
+
# row decide (S3/S4 pin that), but until that row exists the draft row is the latest: read as FAILED it ends --wait at
|
|
585
|
+
# once, and read as the whole truth it hides a ready run that was never created. The script asks the resolver ONLY when
|
|
586
|
+
# `test` is FAILED at the graded head, and can only move the context to PENDING or ABSENT, never to green.
|
|
587
|
+
row_S1() { local d; d=$(mkrow S1); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" pending-full 8
|
|
588
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "PENDING test (draft-era-row-while-ready-run-pending)" && verdict "$d" not-ready && reason "$d" not-green \
|
|
589
|
+
&& tailis "$d" 'required=26 absent=[] pending=["test"] failed=[]' && vcalled "$d" 1 && grep -Fxq "verdict $PR" "$d/vlog" || why "S1: $(tail -2 "$d/out" | tr '\n' '|')"; }
|
|
590
|
+
row_S2() { local d; d=$(mkrow S2); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"' runs.1.json; setv "$d" pending-full 8
|
|
591
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 0 && nomiss "$d" && polls "$d" 2 && verdict "$d" ready && sleeps "$d" 1 && count "$d" '^WAIT ' 1 && line "$d" 'WAIT poll=1/60 absent=[] pending=["test"]'; }
|
|
592
|
+
row_S3() { local d; d=$(mkrow S3); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'
|
|
593
|
+
runs "$d" '. + [(.[] | select(.name == "test") | .id = (.id + 100) | .status = "queued" | .conclusion = null | .started_at = null)]'; setv "$d" pending-full 8
|
|
594
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "PENDING test (queued)" && tailis "$d" 'required=26 absent=[] pending=["test"] failed=[]' && vcalled "$d" 0; }
|
|
595
|
+
row_S4() { local d; d=$(mkrow S4); assert_fixture_dir "$d"
|
|
596
|
+
runs "$d" '. + [(.[] | select(.name == "test") | .id = (.id - 100) | .conclusion = "failure")]'; setv "$d" no-run
|
|
597
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 0 && nomiss "$d" && verdict "$d" ready && tailis "$d" "$READY_TAIL" && vcalled "$d" 0; }
|
|
598
|
+
row_S5() { local d; d=$(mkrow S5); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" no-run
|
|
599
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "PENDING test (no-ready-run)" && reason "$d" not-green || return 1
|
|
600
|
+
run "$d" "$PR" "$SHA" --wait --timeout 120; rc_is "$d" 1 && polls "$d" 2 && verdict "$d" timeout && tailis "$d" 'required=26 absent=[] pending=["test"] failed=[]'; }
|
|
601
|
+
row_S6() { local d; d=$(mkrow S6); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" stalled
|
|
602
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready && reason "$d" stalled && line "$d" "ABSENT test (stalled: no full CI run decided after the ready event)" \
|
|
603
|
+
&& tailis "$d" 'required=26 absent=["test"] pending=[] failed=[]' && grep -Fq "gh pr ready --undo $PR" "$d/out" && grep -Fq "gh pr ready $PR" "$d/out" \
|
|
604
|
+
&& ! grep -Fq 'gh run rerun' "$d/out" || return 1
|
|
605
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && polls "$d" 1 && reason "$d" stalled; }
|
|
606
|
+
row_S7() { local d; d=$(mkrow S7); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" awaiting-approval 8
|
|
607
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && reason "$d" awaiting-approval && line "$d" "PENDING test (awaiting-approval: a maintainer must approve the fork workflow run)" \
|
|
608
|
+
&& tailis "$d" 'required=26 absent=[] pending=["test"] failed=[]' || return 1
|
|
609
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && polls "$d" 1 && reason "$d" awaiting-approval; }
|
|
610
|
+
row_S8() { local d; d=$(mkrow S8); assert_fixture_dir "$d"; setrun "$d" test ".conclusion = \"failure\" | .details_url = \"$TEST_URL_RUN8\""; setv "$d" full-decided 8
|
|
611
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)" && reason "$d" not-green && tailis "$d" 'required=26 absent=[] pending=[] failed=["test"]' || return 1
|
|
612
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && polls "$d" 1 && verdict "$d" not-ready; }
|
|
613
|
+
row_S9() { local d; d=$(mkrow S9); assert_fixture_dir "$d"
|
|
614
|
+
setrun "$d" test ".details_url = \"$TEST_URL_RUN8\""
|
|
615
|
+
runs "$d" ". + [(.[] | select(.name == \"test\") | .id = (.id + 1) | .conclusion = \"failure\" | .details_url = \"$TEST_URL_RUN6\")]"; setv "$d" full-decided 8
|
|
616
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready && reason "$d" stale-row && line "$d" "FAILED test (stale-row: the newest test row belongs to run 6, not the deciding run 8)" \
|
|
617
|
+
&& tailis "$d" 'required=26 absent=[] pending=[] failed=["test"]' && grep -Fq "gh pr ready --undo $PR" "$d/out" || return 1
|
|
618
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && polls "$d" 1 && reason "$d" stale-row; }
|
|
619
|
+
row_S10() { local d; d=$(mkrow S10); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" n/a
|
|
620
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)" && reason "$d" not-green && vcalled "$d" 1; }
|
|
621
|
+
row_S11() { local d; d=$(mkrow S11); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" pending-full 8; touch "$d/vstate.fail"
|
|
622
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)" && reason "$d" not-green && vcalled "$d" 1; }
|
|
623
|
+
row_S12() { local d; d=$(mkrow S12); assert_fixture_dir "$d"; drop "$d" test; setv "$d" pending-full 8
|
|
624
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "ABSENT test" && tailis "$d" 'required=26 absent=["test"] pending=[] failed=[]' && vcalled "$d" 0; }
|
|
625
|
+
row_S13() { local d; d=$(mkrow S13); assert_fixture_dir "$d"
|
|
626
|
+
jqf "$d" runs.json "map(.check_runs[].head_sha = \"$GREEN\")"; setrun "$d" test '.conclusion = "failure"'; setv "$d" pending-full 8
|
|
627
|
+
run "$d" "$PR" "$SHA" --green-sha "$GREEN"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)" && vcalled "$d" 0; }
|
|
628
|
+
row_S14() { local d; d=$(mkrow S14); assert_fixture_dir "$d"; setfiles "$d" '[[{"filename":".github/workflows/ci.yml"}]]'; setrun "$d" test '.conclusion = "failure"'; setv "$d" pending-full 8
|
|
629
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && reason "$d" untrusted-ci && grep -q '^UNTRUSTED-CI' "$d/out" && vcalled "$d" 0 || return 1
|
|
630
|
+
run "$d" "$PR" "$SHA" --wait; rc_is "$d" 1 && polls "$d" 1 && reason "$d" untrusted-ci; }
|
|
631
|
+
row_S15() { local d; d=$(mkrow S15); assert_fixture_dir "$d"; setrun "$d" test '.conclusion = "failure"'; setv "$d" pending-full 8 1111111111111111111111111111111111111111
|
|
632
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && line "$d" "FAILED test (failure)" && reason "$d" not-green; }
|
|
633
|
+
# S16: whatever the resolver says, a red or absent test is never READY (the guard cannot be a reject-everything stub: S4 passes).
|
|
634
|
+
row_S16() { local d st t
|
|
635
|
+
for st in n/a full-decided pending-full no-run stalled awaiting-approval; do for t in red absent; do
|
|
636
|
+
d=$(mkrow "S16-$st-$t"); assert_fixture_dir "$d"; setv "$d" "$st" 8
|
|
637
|
+
if [[ "$t" == red ]]; then setrun "$d" test '.conclusion = "failure"'; else drop "$d" test; fi
|
|
638
|
+
run "$d" "$PR" "$SHA"; rc_is "$d" 1 && nomiss "$d" && verdict "$d" not-ready || return 1
|
|
639
|
+
done; done; }
|
|
640
|
+
|
|
641
|
+
# defect probes for the mutation rows: the mutant must show the defect, not merely crash.
|
|
642
|
+
# R2's mutant iterates present checks, so the absent `test` is never named (the positive
|
|
643
|
+
# readiness count then refuses it as an error rather than a ready -- defence in depth).
|
|
644
|
+
dfx_R1_unnamed() { ! grep -Fxq 'ABSENT test' "$(rowdir R1)/out"; }
|
|
645
|
+
dfx_R11_absent() { [[ "$(rc_of R11)" == 1 ]] && grep -Fxq 'ABSENT test' "$(rowdir R11)/out"; }
|
|
646
|
+
dfx_H1_miss() { grep -q '^STUB-MISS' "$(rowdir H1)/log"; }
|
|
647
|
+
dfx_R4_green() { [[ "$(rc_of R4)" == 0 ]]; }
|
|
648
|
+
dfx_R27_green() { grep -q 'verdict=ready' "$SANDBOX/rows/R27-skipped/out"; }
|
|
649
|
+
dfx_R8_green() { [[ "$(rc_of R8)" == 0 ]]; }
|
|
650
|
+
dfx_R26_ready() { grep -q 'verdict=ready' "$(rowdir R26)/out"; }
|
|
651
|
+
dfx_R32_green() { [[ "$(rc_of R32)" == 0 ]]; }
|
|
652
|
+
dfx_R28_green() { [[ "$(rc_of R28)" == 0 ]]; }
|
|
653
|
+
dfx_R36_unsupported() { [[ "$(rc_of R36)" == 3 ]] && grep -q 'reason=unsupported-rule' "$(rowdir R36)/out"; }
|
|
654
|
+
dfx_L2_ready() { [[ "$(rc_of L2)" == 0 ]]; }
|
|
655
|
+
dfx_L4_ready() { [[ "$(rc_of L4)" == 0 ]]; }
|
|
656
|
+
dfx_L5_ready() { [[ "$(rc_of L5)" == 0 ]]; }
|
|
657
|
+
dfx_L6_ready() { [[ "$(rc_of L6)" == 0 ]]; }
|
|
658
|
+
dfx_L1_reason() { [[ "$(rc_of L1)" == 0 ]] && ! grep -q 'reason=carryover-local-docs' "$(rowdir L1)/out"; }
|
|
659
|
+
|
|
660
|
+
echo "== admin-merge-ready.sh (Guard 1)"
|
|
661
|
+
for r in S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12 S13 S14 S15 S16 H1 H2 R1 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 R30 R31 R32 R33 R34 R35 R36 R37 G1 G2 G3 G4 G5 G6 G7 G8 L1 L2 L3 L4 L5 L6 L7 L8 L9 L10 L11 L12 L13 L14 L15 help; do
|
|
662
|
+
case_ok "$r" "row_$r"
|
|
663
|
+
done
|
|
664
|
+
|
|
665
|
+
echo "== mutation rows"
|
|
666
|
+
# R2 -- the dispatch row: iterate the PRESENT checks instead of the REQUIRED set (#8458).
|
|
667
|
+
case_mutant R2 row_R1 dfx_R1_unnamed '| [ $req[] as $q' '| [ ($runs | map({context: .name, integration_id: .app.id}) | unique)[] as $q'
|
|
668
|
+
# R11 -- drop --paginate from the check-runs call only: page 2 (which holds `test`) is never read.
|
|
669
|
+
case_mutant R11-paginate row_R11 dfx_R11_absent 'gh api --paginate --slurp "repos/{owner}/{repo}/commits/' 'gh api --slurp "repos/{owner}/{repo}/commits/'
|
|
670
|
+
# H3 -- query a different endpoint: the strict stub must refuse it, not answer from the fixture.
|
|
671
|
+
case_mutant H3-endpoint row_H1 dfx_H1_miss 'repos/{owner}/{repo}/rules/branches/$enc' 'repos/{owner}/{repo}/rulesets'
|
|
672
|
+
# R4 by timestamp: pick the latest run by started_at instead of id.
|
|
673
|
+
case_mutant R4-started_at row_R4 dfx_R4_green '($c | max_by(.id | tonumber)) as $l' '($c | max_by(.started_at // "")) as $l'
|
|
674
|
+
# R27: drop the skipped-after-failure rule.
|
|
675
|
+
case_mutant R27-rule row_R27 dfx_R27_green 'elif any($sib[]; .status == "completed"' 'elif false and any($sib[]; .status == "completed"'
|
|
676
|
+
# R8/R22: match by name only.
|
|
677
|
+
case_mutant R8-app row_R8 dfx_R8_green 'select(.name == $q.context and .app.id == $q.integration_id)' 'select(.name == $q.context)'
|
|
678
|
+
# R26: the untrusted-CI refusal narrowed to workflows only (.github/actions/ edits pass).
|
|
679
|
+
case_mutant R26-actions row_R26 dfx_R26_ready 'select(test("^\\.github/(workflows|actions)/"))' 'select(test("^\\.github/workflows/"))'
|
|
680
|
+
# R32: drop the head_sha restriction.
|
|
681
|
+
case_mutant R32-headsha row_R32 dfx_R32_green '| [.[] | .check_runs[] | select(.head_sha == $sha)] as $runs' '| [.[] | .check_runs[]] as $runs'
|
|
682
|
+
# R28: read only the first page of the rules.
|
|
683
|
+
case_mutant R28-rulespage row_R28 dfx_R28_green '($rules[0] | add // []) as $all' '($rules[0][0] // []) as $all'
|
|
684
|
+
# R36 -- drop merge_queue from the evaluated rule types: the live post-adoption shape errors.
|
|
685
|
+
case_mutant R36-known row_R36 dfx_R36_unsupported '"required_signatures","required_status_checks","merge_queue"] as $known' '"required_signatures","required_status_checks"] as $known'
|
|
686
|
+
|
|
687
|
+
# ── mutation rows for the --allow-local-merge arm (#9401) ─────────────────────
|
|
688
|
+
# LM-clean: drop the byte-identical patch bijection -- a smuggled file now certifies.
|
|
689
|
+
case_mutant LM-clean row_L2 dfx_L2_ready \
|
|
690
|
+
'elif any($af[] + $bf[]; (.patch | type) != "string")
|
|
691
|
+
or ([$af[] | [.filename, .status, (.previous_filename // ""), .patch]] | sort)
|
|
692
|
+
!= ([$bf[] | [.filename, .status, (.previous_filename // ""), .patch]] | sort)
|
|
693
|
+
then "not-clean"' \
|
|
694
|
+
'elif false
|
|
695
|
+
then "not-clean"'
|
|
696
|
+
# LM-nondocs: drop the docs-surface filter -- a clean base-side CODE replay passes.
|
|
697
|
+
case_mutant LM-nondocs row_L4 dfx_L4_ready \
|
|
698
|
+
'elif any($af[]; docs | not) then "nondocs"' \
|
|
699
|
+
'elif false then "nondocs"'
|
|
700
|
+
# LM-overlap: drop the PR-file disjointness -- a merge touching a PR file passes.
|
|
701
|
+
case_mutant LM-overlap row_L5 dfx_L5_ready \
|
|
702
|
+
'elif any($af[]; [.filename, (.previous_filename // empty)]
|
|
703
|
+
| .[] | . as $f | ($pf | index($f)) != null) then "overlap"' \
|
|
704
|
+
'elif false then "overlap"'
|
|
705
|
+
# LM-flag: the arm reachable WITHOUT --allow-local-merge.
|
|
706
|
+
case_mutant LM-flag row_L6 dfx_L6_ready \
|
|
707
|
+
'elif [[ "$carry" == "carryover-unverified" && "$ALLOW_LOCAL" == "1" ]]; then' \
|
|
708
|
+
'elif [[ "$carry" == "carryover-unverified" ]]; then'
|
|
709
|
+
# LM-reason: a ready local-merge certified under a non-carryover reason token.
|
|
710
|
+
case_mutant LM-reason row_L1 dfx_L1_reason \
|
|
711
|
+
'REASON="carryover-local-docs"' \
|
|
712
|
+
'REASON="all-green"'
|
|
713
|
+
|
|
714
|
+
# ── ADR-276 S3 mutation rows: the head-verdict handling ────────────────────────────────────────
|
|
715
|
+
dfx_S1_failed() { grep -Fq 'FAILED test' "$(rowdir S1)/out"; }
|
|
716
|
+
dfx_S6_noabsent() { ! grep -Fq 'absent=["test"]' "$(rowdir S6)/out"; }
|
|
717
|
+
dfx_S9_nostale() { ! grep -Fq 'reason=stale-row' "$(rowdir S9)/out"; }
|
|
718
|
+
dfx_S13_called() { [[ "$(vcalls "$(rowdir S13)")" != 0 ]]; }
|
|
719
|
+
dfx_S15_softened() { grep -Fq 'PENDING test' "$(rowdir S15)/out"; }
|
|
720
|
+
dfx_S6_noreason() { ! grep -Fq 'reason=stalled' "$(rowdir S6)/out"; }
|
|
721
|
+
# MS1 -- pending-full no longer softens the draft row: --wait ends at once on a FAILED context again.
|
|
722
|
+
case_mutant MS1-pending row_S1 dfx_S1_failed ' pending-full)
|
|
723
|
+
jq -c' ' pending-full-off)
|
|
724
|
+
jq -c'
|
|
725
|
+
# MS2 -- stalled is reported as PENDING instead of ABSENT.
|
|
726
|
+
case_mutant MS2-stalled row_S6 dfx_S6_noabsent '.failed -= ["test"] | .absent += ["test"]' '.failed -= ["test"] | .pending += ["test"]'
|
|
727
|
+
# MS3 -- stalled loses its terminal reason: a --wait would burn the whole budget on a PR that will never run.
|
|
728
|
+
case_mutant MS3-reason row_S6 dfx_S6_noreason 'REASON_OVERRIDE="stalled"' 'REASON_OVERRIDE=""'
|
|
729
|
+
# MS4 -- a verdict for ANOTHER head is honoured.
|
|
730
|
+
case_mutant MS4-sha row_S15 dfx_S15_softened '[[ "$m" == *" sha=$SHA "* ]] || return 1' 'true'
|
|
731
|
+
# MS5 -- the carryover arm (grading another sha) consults the resolver for the PR head.
|
|
732
|
+
case_mutant MS5-carryover row_S13 dfx_S13_called '[[ "$CHECK_SHA" == "$SHA" ]] && jq -e' 'jq -e'
|
|
733
|
+
# MS6 -- the stale-row comparison inverted.
|
|
734
|
+
case_mutant MS6-stale row_S9 dfx_S9_nostale '"$last_run" != "$V_RUN"' '"$last_run" == "$V_RUN"'
|
|
735
|
+
|
|
736
|
+
# ── H4: anti-vacuity ─────────────────────────────────────────────────────────────────────────
|
|
737
|
+
echo
|
|
738
|
+
echo "cases_run=$CASES_RUN passes=$passes fails=$fails ledger=${#FAILED[@]}"
|
|
739
|
+
_min_cases=99
|
|
740
|
+
if [[ "$CASES_RUN" -lt "$_min_cases" ]]; then
|
|
741
|
+
printf '[FATAL] assertion floor: only %s case(s) ran, floor is %s\n' "$CASES_RUN" "$_min_cases" >&2; exit 1
|
|
742
|
+
fi
|
|
743
|
+
if [[ $((passes + fails)) -ne "$CASES_RUN" ]]; then
|
|
744
|
+
printf '[FATAL] %s verdicts for %s cases\n' "$((passes + fails))" "$CASES_RUN" >&2; exit 1
|
|
745
|
+
fi
|
|
746
|
+
if [[ "${#FAILED[@]}" -ne "$fails" ]]; then
|
|
747
|
+
printf '[FATAL] ledger/counter disagree: %s vs %s\n' "${#FAILED[@]}" "$fails" >&2; exit 1
|
|
748
|
+
fi
|
|
749
|
+
if [[ "${#FAILED[@]}" -ne 0 ]]; then
|
|
750
|
+
printf '[FATAL] %s failing assertion(s):\n' "${#FAILED[@]}" >&2
|
|
751
|
+
printf ' - %s\n' "${FAILED[@]}" >&2; exit 1
|
|
752
|
+
fi
|
|
753
|
+
echo "admin-merge-ready: all $passes cases passed"
|