@1aboveio/skills 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -0
- package/README.md +90 -0
- package/bin/1aboveio-skills.mjs +18 -0
- package/package.json +28 -0
- package/runtime/skills/distribution/generated/recipes.json +1189 -0
- package/runtime/skills/distribution/scripts/bundles.mjs +280 -0
- package/runtime/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
- package/skills/backend/airflow-dag-develop/LICENSE +3 -0
- package/skills/backend/airflow-dag-develop/SKILL.md +111 -0
- package/skills/backend/app-debug/LICENSE +3 -0
- package/skills/backend/app-debug/SKILL.md +109 -0
- package/skills/backend/app-debug/references/common-errors.md +128 -0
- package/skills/backend/python-backend/LICENSE +3 -0
- package/skills/backend/python-backend/SKILL.md +326 -0
- package/skills/cicd-pipeline/cloud-build/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-build/SKILL.md +707 -0
- package/skills/cicd-pipeline/cloud-debug/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-debug/SKILL.md +316 -0
- package/skills/cicd-pipeline/cloud-debug/references/build-failures.md +238 -0
- package/skills/cicd-pipeline/cloud-debug/references/deploy-failures.md +376 -0
- package/skills/cicd-pipeline/cloud-debug/references/pipeline-failures.md +378 -0
- package/skills/cicd-pipeline/cloud-deploy/LICENSE +3 -0
- package/skills/cicd-pipeline/cloud-deploy/SKILL.md +229 -0
- package/skills/cicd-pipeline/cloud-deploy/references/config-templates.md +257 -0
- package/skills/cicd-pipeline/docker/LICENSE +3 -0
- package/skills/cicd-pipeline/docker/SKILL.md +126 -0
- package/skills/cicd-pipeline/google-cloud/LICENSE +3 -0
- package/skills/cicd-pipeline/google-cloud/SKILL.md +118 -0
- package/skills/cicd-pipeline/google-cloud/references/gcs.md +469 -0
- package/skills/cicd-pipeline/google-cloud/references/iam.md +451 -0
- package/skills/cicd-pipeline/google-cloud/references/project.md +349 -0
- package/skills/cicd-pipeline/google-cloud/references/secrets.md +336 -0
- package/skills/cicd-pipeline/google-cloud/references/vpc.md +312 -0
- package/skills/cicd-pipeline/google-cloud/scripts/create-sa.sh +36 -0
- package/skills/cicd-pipeline/google-cloud/scripts/gcp-config.sh +31 -0
- package/skills/cicd-pipeline/google-cloud/scripts/grant-iap.sh +41 -0
- package/skills/cicd-pipeline/google-cloud/scripts/setup-secrets.sh +48 -0
- package/skills/cicd-pipeline/mergify/LICENSE +3 -0
- package/skills/cicd-pipeline/mergify/SKILL.md +138 -0
- package/skills/cicd-pipeline/mergify/assets/templates/mergify.yml +237 -0
- package/skills/cicd-pipeline/mergify/assets/templates/ruleset.json +46 -0
- package/skills/cicd-pipeline/mergify/references/branch-protection.md +277 -0
- package/skills/cicd-pipeline/mergify/references/configuration.md +183 -0
- package/skills/cicd-pipeline/mergify/references/diagnosis.md +73 -0
- package/skills/cicd-pipeline/mergify/references/traps.md +78 -0
- package/skills/cicd-pipeline/mergify/references/watch-contract.md +218 -0
- package/skills/cicd-pipeline/mergify/scripts/audit-core.mjs +131 -0
- package/skills/cicd-pipeline/mergify/scripts/audit.mjs +4 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery-core.mjs +663 -0
- package/skills/cicd-pipeline/mergify/scripts/watch-pr-delivery.mjs +4 -0
- package/skills/cicd-pipeline/podman/LICENSE +3 -0
- package/skills/cicd-pipeline/podman/SKILL.md +70 -0
- package/skills/cicd-pipeline/podman/agents/openai.yaml +4 -0
- package/skills/cicd-pipeline/podman/assets/templates/podman-compose-socket-directory.yml +6 -0
- package/skills/cicd-pipeline/podman/assets/templates/podman-service-override.conf +3 -0
- package/skills/cicd-pipeline/podman/references/compose-compatibility.md +70 -0
- package/skills/cicd-pipeline/podman/references/networking-and-ports.md +74 -0
- package/skills/cicd-pipeline/podman/references/rootless-services-and-sockets.md +156 -0
- package/skills/cicd-pipeline/podman/references/troubleshooting.md +98 -0
- package/skills/engineering/e2e-test/LICENSE +3 -0
- package/skills/engineering/e2e-test/SKILL.md +156 -0
- package/skills/engineering/e2e-test/assets/ci-gates.cloudbuild.yaml +272 -0
- package/skills/engineering/e2e-test/assets/ci-gates.github.yml +451 -0
- package/skills/engineering/e2e-test/assets/e2e-workflow.yml +282 -0
- package/skills/engineering/e2e-test/references/authoring/auth-flows.md +159 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +71 -0
- package/skills/engineering/e2e-test/references/authoring/playwright-patterns.md +219 -0
- package/skills/engineering/e2e-test/references/authoring/test-skipping.md +44 -0
- package/skills/engineering/e2e-test/references/ci-integration.md +121 -0
- package/skills/engineering/e2e-test/references/ci-playwright-container.md +280 -0
- package/skills/engineering/e2e-test/references/debugging.md +36 -0
- package/skills/engineering/e2e-test/references/presentation-sweep.md +131 -0
- package/skills/engineering/e2e-test/references/reviewing.md +39 -0
- package/skills/engineering/e2e-test/references/route-discovery.md +50 -0
- package/skills/engineering/e2e-test/references/route-manifest.md +44 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-fastapi.py +290 -0
- package/skills/engineering/e2e-test/scripts/detect-routes-nextjs.mjs +200 -0
- package/skills/engineering/e2e-test/scripts/post-visual-evidence.mjs +158 -0
- package/skills/engineering/e2e-test/scripts/presentation-checks.mjs +171 -0
- package/skills/engineering/e2e-test/scripts/presentation-perceivability.mjs +179 -0
- package/skills/engineering/e2e-test/scripts/presentation-reachability.mjs +154 -0
- package/skills/engineering/e2e-test/scripts/presentation-render-health.mjs +141 -0
- package/skills/engineering/e2e-test/scripts/presentation-sweep.mjs +148 -0
- package/skills/engineering/e2e-test/scripts/presentation-temporal.mjs +127 -0
- package/skills/engineering/e2e-test/scripts/presentation-visual.mjs +84 -0
- package/skills/engineering/e2e-test/scripts/project-route-manifest.mjs +75 -0
- package/skills/engineering/e2e-test/scripts/validate-manifest.mjs +106 -0
- package/skills/engineering/engineering-runtime/LICENSE +3 -0
- package/skills/engineering/engineering-runtime/SKILL.md +10 -0
- package/skills/engineering/engineering-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/engineering-runtime/coherence/workflow.json +553 -0
- package/skills/engineering/engineering-runtime/scripts/exact-head-artifact.mjs +131 -0
- package/skills/engineering/engineering-runtime/scripts/head-check-set.mjs +398 -0
- package/skills/engineering/engineering-runtime/scripts/main-module.mjs +80 -0
- package/skills/engineering/engineering-runtime/scripts/mergify-yaml.mjs +11 -0
- package/skills/engineering/engineering-runtime/scripts/package-lock.json +43 -0
- package/skills/engineering/engineering-runtime/scripts/package.json +10 -0
- package/skills/engineering/engineering-runtime/scripts/required-check-plan.mjs +223 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-coherence.mjs +576 -0
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +166 -0
- package/skills/engineering/ensure-coverage/LICENSE +3 -0
- package/skills/engineering/ensure-coverage/SKILL.md +136 -0
- package/skills/engineering/ensure-coverage/evals/evals.json +125 -0
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +91 -0
- package/skills/engineering/ensure-coverage/references/breadth/inventory-contract.md +83 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +44 -0
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +16 -0
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +68 -0
- package/skills/engineering/ensure-coverage/references/depth/coverage.config.example.json +25 -0
- package/skills/engineering/ensure-coverage/references/depth/grading.md +35 -0
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +87 -0
- package/skills/engineering/ensure-coverage/references/depth/test-smells.md +23 -0
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +164 -0
- package/skills/engineering/ensure-coverage/references/enforcement/hooks.md +85 -0
- package/skills/engineering/ensure-coverage/references/examples/coverage-ledger.md +109 -0
- package/skills/engineering/ensure-coverage/references/examples/refund-flow.md +33 -0
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +78 -0
- package/skills/engineering/ensure-coverage/references/presentation/runner-contract.md +74 -0
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +33 -0
- package/skills/engineering/ensure-coverage/references/process/output-template.md +139 -0
- package/skills/engineering/ensure-coverage/references/process/review-contract-template.md +119 -0
- package/skills/engineering/ensure-coverage/references/process/scope-class.md +178 -0
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +55 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-config.schema.json +45 -0
- package/skills/engineering/ensure-coverage/schemas/coverage-file.schema.json +93 -0
- package/skills/engineering/ensure-coverage/scripts/adapters/nextjs-inventory.mjs +178 -0
- package/skills/engineering/ensure-coverage/scripts/check-quarantine-expiry.mjs +101 -0
- package/skills/engineering/ensure-coverage/scripts/ci-audit.mjs +358 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-checklist.mjs +494 -0
- package/skills/engineering/ensure-coverage/scripts/coverage-ledger.mjs +663 -0
- package/skills/engineering/ensure-coverage/scripts/design-parity.mjs +591 -0
- package/skills/engineering/ensure-coverage/scripts/evidence-block.mjs +367 -0
- package/skills/engineering/ensure-coverage/scripts/lint-tests.mjs +269 -0
- package/skills/engineering/ensure-coverage/scripts/mock-policy-config.mjs +176 -0
- package/skills/engineering/ensure-coverage/scripts/package-lock.json +76 -0
- package/skills/engineering/ensure-coverage/scripts/package.json +19 -0
- package/skills/engineering/ensure-coverage/scripts/scope-class.mjs +554 -0
- package/skills/engineering/harness-runtime/LICENSE +3 -0
- package/skills/engineering/harness-runtime/SKILL.md +18 -0
- package/skills/engineering/harness-runtime/agents/openai.yaml +6 -0
- package/skills/engineering/harness-runtime/bin/discover-models.mjs +4 -0
- package/skills/engineering/harness-runtime/bin/model-catalog.mjs +4 -0
- package/skills/engineering/harness-runtime/contracts.md +15 -0
- package/skills/engineering/harness-runtime/discover-models.mjs +392 -0
- package/skills/engineering/harness-runtime/fixtures/native-question-schemas.json +33 -0
- package/skills/engineering/harness-runtime/fixtures/question-responses.json +54 -0
- package/skills/engineering/harness-runtime/index.mjs +767 -0
- package/skills/engineering/harness-runtime/model-catalog.mjs +787 -0
- package/skills/engineering/harness-runtime/native-question-contracts.md +37 -0
- package/skills/engineering/harness-runtime/references/model-catalog-seed.json +159 -0
- package/skills/engineering/harness-runtime/references/model-catalog.md +57 -0
- package/skills/engineering/implement-and-pr/LICENSE +3 -0
- package/skills/engineering/implement-and-pr/SKILL.md +176 -0
- package/skills/engineering/implement-and-pr/references/ci-iteration.md +10 -0
- package/skills/engineering/implement-and-pr/references/closeout.md +27 -0
- package/skills/engineering/implement-and-pr/references/contract-complete-fix-rounds.md +34 -0
- package/skills/engineering/implement-and-pr/references/evidence-rules.md +39 -0
- package/skills/engineering/implement-and-pr/references/incremental-plan.md +16 -0
- package/skills/engineering/implement-and-pr/references/self-review.md +23 -0
- package/skills/engineering/implement-and-pr/references/tdd-mode.md +18 -0
- package/skills/engineering/resolve-issues/LICENSE +3 -0
- package/skills/engineering/resolve-issues/SKILL.md +167 -0
- package/skills/engineering/resolve-issues/generated/workflow-repair-policy.json +448 -0
- package/skills/engineering/resolve-issues/references/breaker.md +82 -0
- package/skills/engineering/resolve-issues/references/deliverables.md +27 -0
- package/skills/engineering/resolve-issues/references/delivery.md +108 -0
- package/skills/engineering/resolve-issues/references/evidence-lane.md +21 -0
- package/skills/engineering/resolve-issues/references/exact-head-ci.md +287 -0
- package/skills/engineering/resolve-issues/references/fan-out.md +33 -0
- package/skills/engineering/resolve-issues/references/finalization.md +68 -0
- package/skills/engineering/resolve-issues/references/guarantees.md +10 -0
- package/skills/engineering/resolve-issues/references/high-risk.md +29 -0
- package/skills/engineering/resolve-issues/references/incidents/848/README.md +156 -0
- package/skills/engineering/resolve-issues/references/intake.md +86 -0
- package/skills/engineering/resolve-issues/references/integration-gate.md +53 -0
- package/skills/engineering/resolve-issues/references/interference.md +87 -0
- package/skills/engineering/resolve-issues/references/loop.md +134 -0
- package/skills/engineering/resolve-issues/references/model-catalog.md +9 -0
- package/skills/engineering/resolve-issues/references/postmortem.md +27 -0
- package/skills/engineering/resolve-issues/references/pre-flight-model-slots.md +41 -0
- package/skills/engineering/resolve-issues/references/pre-flight-recording-and-checkout.md +48 -0
- package/skills/engineering/resolve-issues/references/pre-flight.md +41 -0
- package/skills/engineering/resolve-issues/references/regression-checklist.md +26 -0
- package/skills/engineering/resolve-issues/references/run-state.md +288 -0
- package/skills/engineering/resolve-issues/references/sandboxed-testing.md +48 -0
- package/skills/engineering/resolve-issues/references/spawn-contract.md +96 -0
- package/skills/engineering/resolve-issues/references/terminal-evidence-journal.md +40 -0
- package/skills/engineering/resolve-issues/references/why.md +653 -0
- package/skills/engineering/resolve-issues/schemas/fix-round.schema.json +49 -0
- package/skills/engineering/resolve-issues/scripts/combine-and-verify.mjs +721 -0
- package/skills/engineering/resolve-issues/scripts/component-candidate.mjs +962 -0
- package/skills/engineering/resolve-issues/scripts/contract-revision.mjs +220 -0
- package/skills/engineering/resolve-issues/scripts/detect-delivery-mode.mjs +420 -0
- package/skills/engineering/resolve-issues/scripts/detect-target-branch.mjs +256 -0
- package/skills/engineering/resolve-issues/scripts/detect-workspace-mode.mjs +168 -0
- package/skills/engineering/resolve-issues/scripts/discover-models.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/doctrine.mjs +62 -0
- package/skills/engineering/resolve-issues/scripts/evidence-lifecycle-contract.mjs +191 -0
- package/skills/engineering/resolve-issues/scripts/exact-head-ci.mjs +413 -0
- package/skills/engineering/resolve-issues/scripts/exact-head-github-provider.mjs +332 -0
- package/skills/engineering/resolve-issues/scripts/finalize.mjs +488 -0
- package/skills/engineering/resolve-issues/scripts/fix-rounds.mjs +3307 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-circular-1001.json +16 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/evidence-lifecycle-valid-sequencing.json +51 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/fmm-express-830-component-candidate.json +17 -0
- package/skills/engineering/resolve-issues/scripts/fixtures/head-check-set-1081.json +166 -0
- package/skills/engineering/resolve-issues/scripts/gate-value-series.mjs +92 -0
- package/skills/engineering/resolve-issues/scripts/guide-index.mjs +73 -0
- package/skills/engineering/resolve-issues/scripts/head-check-set.mjs +159 -0
- package/skills/engineering/resolve-issues/scripts/interference.mjs +427 -0
- package/skills/engineering/resolve-issues/scripts/model-catalog.mjs +9 -0
- package/skills/engineering/resolve-issues/scripts/next-operations.mjs +419 -0
- package/skills/engineering/resolve-issues/scripts/postmortem.mjs +909 -0
- package/skills/engineering/resolve-issues/scripts/preflight-questions.mjs +322 -0
- package/skills/engineering/resolve-issues/scripts/reconcile-contained-unit-prs.mjs +415 -0
- package/skills/engineering/resolve-issues/scripts/release-state-contract.mjs +697 -0
- package/skills/engineering/resolve-issues/scripts/report.mjs +494 -0
- package/skills/engineering/resolve-issues/scripts/required-check-plan.mjs +172 -0
- package/skills/engineering/resolve-issues/scripts/round-metadata.mjs +79 -0
- package/skills/engineering/resolve-issues/scripts/run-state-review6-cases.mjs +334 -0
- package/skills/engineering/resolve-issues/scripts/run-state.mjs +4784 -0
- package/skills/engineering/resolve-issues/scripts/sandbox-selftest.mjs +395 -0
- package/skills/engineering/resolve-issues/scripts/spawn-contract.mjs +290 -0
- package/skills/engineering/resolve-issues/scripts/terminal-dispositions.mjs +170 -0
- package/skills/engineering/resolve-issues/scripts/terminal-evidence-journal.mjs +293 -0
- package/skills/engineering/resolve-issues/scripts/unit-kind.mjs +197 -0
- package/skills/engineering/resolve-issues/scripts/unit-lifecycle.mjs +127 -0
- package/skills/engineering/resolve-issues/scripts/watch-delivery.mjs +893 -0
- package/skills/engineering/resolve-issues/scripts/workspaces.mjs +829 -0
- package/skills/engineering/resolve-issues/workflows/independent-review.workflow.js +290 -0
- package/skills/engineering/resolve-issues/workflows/prior-art-scan.workflow.js +80 -0
- package/skills/engineering/resolve-issues/workflows/workflow-smoke.mjs +102 -0
- package/skills/engineering/resolve-release/LICENSE +3 -0
- package/skills/engineering/resolve-release/SKILL.md +112 -0
- package/skills/engineering/resolve-release/references/assembly.md +137 -0
- package/skills/engineering/resolve-release/references/auto-when-green.md +56 -0
- package/skills/engineering/resolve-release/references/candidate.md +167 -0
- package/skills/engineering/resolve-release/references/exposure.md +178 -0
- package/skills/engineering/resolve-release/references/handoff.md +24 -0
- package/skills/engineering/resolve-release/references/postmortem.md +230 -0
- package/skills/engineering/resolve-release/references/preflight.md +207 -0
- package/skills/engineering/resolve-release/references/principles.md +94 -0
- package/skills/engineering/resolve-release/references/regression-checklist.md +36 -0
- package/skills/engineering/resolve-release/references/related-skills.md +12 -0
- package/skills/engineering/resolve-release/references/routing.md +149 -0
- package/skills/engineering/resolve-release/references/verified-sha-github-flow.md +285 -0
- package/skills/engineering/resolve-release/references/versioning.md +202 -0
- package/skills/engineering/resolve-release/references/why.md +53 -0
- package/skills/engineering/resolve-release/scripts/adapter-completion-artifact.mjs +389 -0
- package/skills/engineering/resolve-release/scripts/build-changes.mjs +209 -0
- package/skills/engineering/resolve-release/scripts/candidate-hygiene.mjs +407 -0
- package/skills/engineering/resolve-release/scripts/candidate-identity.mjs +904 -0
- package/skills/engineering/resolve-release/scripts/candidate-traffic.mjs +81 -0
- package/skills/engineering/resolve-release/scripts/checked-adapter-loader.mjs +612 -0
- package/skills/engineering/resolve-release/scripts/close-attempt.mjs +135 -0
- package/skills/engineering/resolve-release/scripts/closeout-release.mjs +161 -0
- package/skills/engineering/resolve-release/scripts/doctrine.mjs +106 -0
- package/skills/engineering/resolve-release/scripts/durable-processing.mjs +522 -0
- package/skills/engineering/resolve-release/scripts/ensure-target-green.mjs +659 -0
- package/skills/engineering/resolve-release/scripts/evidence-bundle.mjs +1014 -0
- package/skills/engineering/resolve-release/scripts/finalize-release.mjs +526 -0
- package/skills/engineering/resolve-release/scripts/fixtures/durable-processing-adapter.mjs +169 -0
- package/skills/engineering/resolve-release/scripts/green-gate.mjs +599 -0
- package/skills/engineering/resolve-release/scripts/isolated-adapter-evaluator.mjs +752 -0
- package/skills/engineering/resolve-release/scripts/metadata-pr-status.mjs +56 -0
- package/skills/engineering/resolve-release/scripts/metadata-sync.mjs +1538 -0
- package/skills/engineering/resolve-release/scripts/postmortem.mjs +381 -0
- package/skills/engineering/resolve-release/scripts/preflight-probes.mjs +498 -0
- package/skills/engineering/resolve-release/scripts/production-endpoints.mjs +326 -0
- package/skills/engineering/resolve-release/scripts/rc-circuit-breaker.mjs +272 -0
- package/skills/engineering/resolve-release/scripts/report.mjs +417 -0
- package/skills/engineering/resolve-release/scripts/reprobe-credentials.mjs +114 -0
- package/skills/engineering/resolve-release/scripts/revalidate-candidate.mjs +238 -0
- package/skills/engineering/resolve-release/scripts/review-packet.mjs +503 -0
- package/skills/engineering/resolve-release/scripts/rollback-floor.mjs +263 -0
- package/skills/engineering/resolve-release/scripts/version-assert.mjs +339 -0
- package/skills/engineering/resolve-release/scripts/version-postmortem.mjs +485 -0
- package/skills/engineering/resolve-release/scripts/version.mjs +1199 -0
- package/skills/engineering/resolve-release/scripts/watch-candidate-delivery.mjs +449 -0
- package/skills/engineering/resolve-release/vendor/ACORN-LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/README.md +60 -0
- package/skills/engineering/resolve-release/vendor/acorn.mjs +6233 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.md +341 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/README.template.md +70 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-TAV5CUKK.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs +7 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/chunk-V2S4ZYJR.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.mts +2033 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.d.ts +2033 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js +7 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-ES6BEMUI.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/dist/module-asyncify-2EFITU5U.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/core/package.json +49 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/LICENSE +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/README.md +5 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.mts +549 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.d.ts +549 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/ffi-types/package.json +36 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/LICENSE +47 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/README.md +82 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.browser.mjs +22 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cjs +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.cjs +21 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.cloudflare.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.d.ts +11 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.mjs +25 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/emscripten-module.wasm +0 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.mts +85 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.d.ts +85 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/ffi.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.mts +20 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.d.ts +20 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.js.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs +2 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/dist/index.mjs.map +1 -0
- package/skills/engineering/resolve-release/vendor/quickjs/release-sync/package.json +61 -0
- package/skills/engineering/review-pr/LICENSE +3 -0
- package/skills/engineering/review-pr/SKILL.md +123 -0
- package/skills/engineering/review-pr/references/adversarial-reviewer-prompt.md +42 -0
- package/skills/engineering/review-pr/references/code-correctness.md +5 -0
- package/skills/engineering/review-pr/references/contract-freshness.md +9 -0
- package/skills/engineering/review-pr/references/coordination.md +18 -0
- package/skills/engineering/review-pr/references/domain-hazards.md +123 -0
- package/skills/engineering/review-pr/references/finding-themes.md +7 -0
- package/skills/engineering/review-pr/references/github-posting.md +98 -0
- package/skills/engineering/review-pr/references/golden-path-smoke.md +5 -0
- package/skills/engineering/review-pr/references/incremental-output.md +16 -0
- package/skills/engineering/review-pr/references/inputs-and-discovery.md +31 -0
- package/skills/engineering/review-pr/references/output-format.md +99 -0
- package/skills/engineering/review-pr/references/over-mock-screen.md +7 -0
- package/skills/engineering/review-pr/references/promotion-prs.md +16 -0
- package/skills/engineering/review-pr/references/re-review.md +18 -0
- package/skills/engineering/review-pr/references/review-method.md +199 -0
- package/skills/engineering/review-pr/references/review-mode.md +30 -0
- package/skills/engineering/review-pr/references/review-posture.md +53 -0
- package/skills/engineering/review-pr/references/round1-depth.md +62 -0
- package/skills/engineering/review-pr/references/scripts.md +17 -0
- package/skills/engineering/review-pr/references/workflow.md +16 -0
- package/skills/engineering/review-pr/schemas/findings.schema.json +282 -0
- package/skills/engineering/review-pr/scripts/finding-contract.mjs +285 -0
- package/skills/engineering/review-pr/scripts/post-review.mjs +405 -0
- package/skills/engineering/review-pr/scripts/pr-context.mjs +207 -0
- package/skills/engineering/review-pr/scripts/scan-diff.mjs +365 -0
- package/skills/engineering/review-pr/scripts/theme-contract.mjs +57 -0
- package/skills/engineering/smoke/LICENSE +3 -0
- package/skills/engineering/smoke/SKILL.md +131 -0
- package/skills/engineering/smoke/assets/smoke.manifest.example.json +53 -0
- package/skills/engineering/smoke/references/manifest.md +192 -0
- package/skills/engineering/smoke/scripts/smoke.mjs +713 -0
- package/skills/fullstack/better-auth/LICENSE +3 -0
- package/skills/fullstack/better-auth/SKILL.md +601 -0
- package/skills/fullstack/better-auth/references/feishu-api.md +270 -0
- package/skills/fullstack/monorepo/LICENSE +3 -0
- package/skills/fullstack/monorepo/SKILL.md +465 -0
- package/skills/fullstack/nextjs-fullstack/LICENSE +3 -0
- package/skills/fullstack/nextjs-fullstack/SKILL.md +210 -0
- package/skills/fullstack/nextjs-fullstack/conventions.md +318 -0
- package/skills/fullstack/nextjs-fullstack/frontend-conventions.md +61 -0
- package/skills/fullstack/nextjs-fullstack/nextjs16.md +287 -0
- package/skills/fullstack/nextjs-fullstack/server-actions.md +409 -0
- package/skills/fullstack/prisma-setup/LICENSE +3 -0
- package/skills/fullstack/prisma-setup/SKILL.md +180 -0
- package/skills/fullstack/prisma-setup/nextjs.md +258 -0
- package/skills/fullstack/prisma-setup/turborepo.md +301 -0
- package/skills/fullstack/shadcn/LICENSE +3 -0
- package/skills/fullstack/shadcn/SKILL.md +119 -0
- package/skills/fullstack/shadcn/assets/shadcn-small.png +0 -0
- package/skills/fullstack/shadcn/assets/shadcn.png +0 -0
- package/skills/fullstack/shadcn/cli.md +411 -0
- package/skills/fullstack/shadcn/customization.md +224 -0
- package/skills/fullstack/shadcn/evals/evals.json +90 -0
- package/skills/fullstack/shadcn/mcp.md +101 -0
- package/skills/fullstack/shadcn/rules/base-vs-radix.md +323 -0
- package/skills/fullstack/shadcn/rules/component-selection.md +67 -0
- package/skills/fullstack/shadcn/rules/composition.md +195 -0
- package/skills/fullstack/shadcn/rules/data-table.md +201 -0
- package/skills/fullstack/shadcn/rules/forms.md +255 -0
- package/skills/fullstack/shadcn/rules/icons.md +103 -0
- package/skills/fullstack/shadcn/rules/styling.md +167 -0
- package/skills/fullstack/zod-v4/LICENSE +3 -0
- package/skills/fullstack/zod-v4/SKILL.md +287 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Mergify Configuration
|
|
2
|
+
|
|
3
|
+
The four settings this skill opinionates, and the checklist that puts them in
|
|
4
|
+
place. Governed by [Rule 1](../SKILL.md#rule-1--fetch-the-docs-before-writing-config):
|
|
5
|
+
fetch the schema before writing any of it, and finish with `validate` **and**
|
|
6
|
+
`simulate`.
|
|
7
|
+
|
|
8
|
+
## The Four Settings
|
|
9
|
+
|
|
10
|
+
### 1. Enqueue — auto on ready + review-PASS, manual otherwise
|
|
11
|
+
|
|
12
|
+
A PR **auto-enqueues** the moment it is ready, a review has passed, and CI is
|
|
13
|
+
green. Short of that it stays held, and a human enqueues it by hand with
|
|
14
|
+
`@mergifyio queue`.
|
|
15
|
+
|
|
16
|
+
**How:** set `merge_protections_settings.auto_merge_conditions` to that AND-list.
|
|
17
|
+
Its *presence* enables conditional auto-merge; the conditions scope *which* PRs.
|
|
18
|
+
The manual path is not a second setting — `@mergifyio queue` queues a PR
|
|
19
|
+
regardless of `auto_merge_conditions`, and `merge_conditions` gate on CI only
|
|
20
|
+
(never review), so a hand-queued PR still merges on green without a review.
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
merge_protections_settings:
|
|
24
|
+
reporting_method: check-runs
|
|
25
|
+
post_comment: true
|
|
26
|
+
# AUTO-enqueue only a ready PR whose review passed; everything else waits for a
|
|
27
|
+
# human `@mergifyio queue`. "review PASS" = ≥1 approval and no open change request.
|
|
28
|
+
# `-draft` belongs HERE (don't auto-queue a draft), but stays OUT of
|
|
29
|
+
# queue_conditions/merge_conditions — see the `-draft` note further down.
|
|
30
|
+
auto_merge_conditions:
|
|
31
|
+
- "-draft"
|
|
32
|
+
- "#approved-reviews-by >= 1"
|
|
33
|
+
- "#changes-requested-reviews-by = 0"
|
|
34
|
+
- *gate
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Why this is the default and not bare-manual: scoping auto-merge to a *passed
|
|
38
|
+
review* keeps the routine case one-click-free **without** letting an unreviewed
|
|
39
|
+
PR ride in — the failure a review gate exists to stop. It also avoids the mirror
|
|
40
|
+
failure: the retired "auto-queue every non-draft PR" form had no review arm, so a
|
|
41
|
+
green-but-unreviewed PR merged and a reviewer requesting changes could lose the
|
|
42
|
+
race to the queue. The review arm is the point; the manual hatch (above) covers
|
|
43
|
+
the "land it without waiting" case.
|
|
44
|
+
|
|
45
|
+
**To go fully manual instead** (queueing the only entry), omit
|
|
46
|
+
`auto_merge_conditions` entirely and say so in a comment — an omitted key reads as
|
|
47
|
+
an oversight and someone will "fix" it back.
|
|
48
|
+
|
|
49
|
+
Do **not** use `merge_protections_settings.auto_merge: true` or
|
|
50
|
+
`queue_rules[].autoqueue: true` — both are deprecated.
|
|
51
|
+
|
|
52
|
+
Developers enqueue by commenting `@mergifyio queue`, or by ticking the checkbox
|
|
53
|
+
Mergify renders in its queue status comment (`merge_queue.queue_controls_comment`,
|
|
54
|
+
default `true`). Mergify acknowledges a command with a 👍 reaction; **no 👍 means
|
|
55
|
+
the command was not processed**, which is a different problem from a PR that
|
|
56
|
+
failed its conditions.
|
|
57
|
+
|
|
58
|
+
### 2 & 3. Batch mode, size 3
|
|
59
|
+
|
|
60
|
+
```yaml
|
|
61
|
+
queue_rules:
|
|
62
|
+
- name: default
|
|
63
|
+
batch_size: 3
|
|
64
|
+
batch_max_wait_time: 30 seconds
|
|
65
|
+
batch_max_failure_resolution_attempts: 10
|
|
66
|
+
merge_queue:
|
|
67
|
+
max_parallel_checks: 3
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**The default this skill ships is `batch_size: 3`** — written explicitly, never
|
|
71
|
+
assumed: an unset `batch_size` silently runs the queue at Mergify's built-in
|
|
72
|
+
default of 1, i.e. no batching, so the key being present is the act that turns
|
|
73
|
+
batching on. With it set, Mergify does not simply test "the next three in the
|
|
74
|
+
queue": priority and
|
|
75
|
+
queue order seed a batch, **stacks always stay together**, and similarity (shared
|
|
76
|
+
scopes, then changed directories, then queue time) fills the remaining slots.
|
|
77
|
+
Related PRs enqueued together reliably ride one batch — that is how the queue
|
|
78
|
+
collects a delivery — while unrelated ones may split, deliberately, so one PR's
|
|
79
|
+
failure cannot drag unrelated work into a bisection. When a batch goes red,
|
|
80
|
+
Mergify **bisects** it — splitting and retesting until it isolates the culprit,
|
|
81
|
+
then dequeuing only that PR. Innocent PRs stay in the queue. `max_parallel_checks`
|
|
82
|
+
caps how many splits run at once, so match it to `batch_size`; more is wasted.
|
|
83
|
+
|
|
84
|
+
`batch_max_wait_time` is the knob that decides how eagerly the queue collects a
|
|
85
|
+
batch, and it is a straight latency tax on a **lone** PR — Mergify waits the full
|
|
86
|
+
window before giving up on company. Where PRs arrive one at a time, keep it at
|
|
87
|
+
seconds, not minutes. Where delivery is bursty — an epic landing a stack, a set
|
|
88
|
+
of related PRs expected together — a longer window (a few minutes) buys the batch
|
|
89
|
+
(N PRs, one CI run) at the cost of a slightly slower lone PR. Set it from how PRs
|
|
90
|
+
actually arrive, not from either extreme.
|
|
91
|
+
|
|
92
|
+
**Two hard requirements:**
|
|
93
|
+
|
|
94
|
+
- GitHub branch protection **"Require branches to be up to date before merging"
|
|
95
|
+
must be DISABLED.** Batches cannot merge with it on — the original PRs are not
|
|
96
|
+
up to date by GitHub's reckoning even though the batch was tested against base.
|
|
97
|
+
This is the single most common reason a batched queue never merges anything.
|
|
98
|
+
- Batching disables **in-place checks**. In-place is only active when all three
|
|
99
|
+
hold: `max_parallel_checks == 1`, every queue has `batch_size == 1`, *and*
|
|
100
|
+
every queue CI is single-step (no extra `merge_conditions` — either empty or
|
|
101
|
+
identical to `queue_conditions`). A two-step CI like this repo's `*gate` +
|
|
102
|
+
`*queue_gate` fails the third condition even at `batch_size 1`. Everything
|
|
103
|
+
downstream of that (below) follows from it.
|
|
104
|
+
|
|
105
|
+
Revisit the size from evidence, not taste: if batches go red often enough that
|
|
106
|
+
bisection is the normal path, the changes are less independent than assumed and
|
|
107
|
+
3 is too wide.
|
|
108
|
+
|
|
109
|
+
### 4. Enforce head (freshness against base)
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
queue_rules:
|
|
113
|
+
- name: default
|
|
114
|
+
update_method: rebase # rebase | merge
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Read this before relying on it.** `update_method` governs how a PR is updated
|
|
118
|
+
with its base branch **when the check is done in place** — and in-place checks
|
|
119
|
+
are off whenever `batch_size > 1`. Under `batch_size: 3` the option is inert.
|
|
120
|
+
|
|
121
|
+
That is not a gap. With batching, Mergify builds a **queue branch** of
|
|
122
|
+
`base + batch` and runs CI there, so what gets tested is always fresh against
|
|
123
|
+
base by construction. The PR's own branch simply is not what gets tested.
|
|
124
|
+
|
|
125
|
+
Keep `update_method: rebase` in the config anyway, so dropping to `batch_size: 1`
|
|
126
|
+
does not silently change behaviour — but comment it, or the next reader will
|
|
127
|
+
believe it is doing work it is not.
|
|
128
|
+
|
|
129
|
+
**If you need the PR branch itself kept fresh** (e.g. contributors run local
|
|
130
|
+
checks against it), that is a separate lever:
|
|
131
|
+
|
|
132
|
+
| Want | Use |
|
|
133
|
+
|------|-----|
|
|
134
|
+
| Fresh tree under test | Nothing — the queue branch already gives you this |
|
|
135
|
+
| Rebase the PR branch, on demand | `@mergifyio update` or `@mergifyio rebase` comment |
|
|
136
|
+
| Rebase the PR branch, automatically | a `pull_request_rules` entry with the `update` or `rebase` action |
|
|
137
|
+
| Fresh head at enqueue time | `#commits-behind = 0` in `queue_conditions` (blocks entry rather than fixing it) |
|
|
138
|
+
|
|
139
|
+
Automatic updating fights the queue — every update retriggers the PR's CI — so
|
|
140
|
+
prefer on-demand unless you have a reason.
|
|
141
|
+
|
|
142
|
+
## Setup Checklist
|
|
143
|
+
|
|
144
|
+
1. Fetch the schema and the relevant doc pages.
|
|
145
|
+
2. Copy `assets/templates/mergify.yml` → `.mergify.yml`; replace placeholders.
|
|
146
|
+
3. Name the real CI check in the `gate` anchor; add the `or` exemption **only**
|
|
147
|
+
if that check is path-filtered, and list the workflow file's own path.
|
|
148
|
+
4. `mergify config validate`.
|
|
149
|
+
5. `mergify config simulate <PR-URL>` against a real PR — ideally one that hits
|
|
150
|
+
the exempt path, since that is where configs break.
|
|
151
|
+
6. **Audit against this skill's default:**
|
|
152
|
+
`node ~/.agents/skills/mergify/scripts/audit.mjs --file .mergify.yml`.
|
|
153
|
+
(Absolute, like the watcher above: you run this from the repo being audited, where a
|
|
154
|
+
CWD-relative `scripts/…` does not resolve.)
|
|
155
|
+
It checks the shape `config validate` can't — enqueue policy (hybrid vs the retired
|
|
156
|
+
indiscriminate auto-queue), `branch_protection_injection_mode: merge`, the
|
|
157
|
+
define-once/assert-many gate anchor, `-draft` misplaced in queue/merge
|
|
158
|
+
conditions, and batch mode actually on (`batch_size: 3` — this skill's
|
|
159
|
+
default; an unset `batch_size` runs at Mergify's built-in 1, so batching
|
|
160
|
+
silently off is a real state). It **abstains** rather than guess, so a `?` means "check by hand," not
|
|
161
|
+
"fine." `--json` for machine output; exits non-zero on any warn (`--allow-warn` to
|
|
162
|
+
downgrade). Runs on the committed `.mergify.yml`, so it fits a pre-merge check.
|
|
163
|
+
7. Confirm Mergify's app id: `gh api /apps/mergify --jq .id`.
|
|
164
|
+
8. `gh ruleset list` — if a ruleset already covers this branch, fold these rules
|
|
165
|
+
into it (**PUT**) rather than stacking a second one. Overlapping rulesets are
|
|
166
|
+
additive and the most restrictive wins, which is a confusing way to be blocked.
|
|
167
|
+
9. Inventory anything that pushes to the protected branch — the `update` rule
|
|
168
|
+
will block it. Add each as a bypass actor (GitHub Actions = `15368`):
|
|
169
|
+
`grep -rnE 'git push|create-pull-request|github-script' .github/workflows/`
|
|
170
|
+
10. Apply `assets/templates/ruleset.json`. Dry-run with
|
|
171
|
+
`"enforcement": "evaluate"` first if you want to see what it would block —
|
|
172
|
+
read the results from `rule-suites`.
|
|
173
|
+
11. Prove the allowed path **before** the blocked one: enqueue a PR with
|
|
174
|
+
`@mergifyio queue`, confirm the 👍, and watch `mergify queue show <PR> -v`
|
|
175
|
+
through to merge. A ruleset strict enough to block humans can also block
|
|
176
|
+
Mergify if a bypass id is wrong, and you would rather learn that while you
|
|
177
|
+
can still merge the fix.
|
|
178
|
+
12. Now prove the blocked path: open a throwaway PR and try to merge it without
|
|
179
|
+
enqueuing, as a non-bypass user. GitHub must refuse, naming the ruleset.
|
|
180
|
+
13. Decide the escape hatches: keep `priority_rules` (jump the line), and either
|
|
181
|
+
keep or delete the `emergency-merge` rule (skips CI, cannot be limited to
|
|
182
|
+
admins). Keep the `OrganizationAdmin` bypass either way — it is the only way
|
|
183
|
+
back in if Mergify has an outage.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Diagnosing A Stuck PR
|
|
2
|
+
|
|
3
|
+
Two tools, two different questions — and when they disagree, the disagreement is
|
|
4
|
+
itself the diagnosis. For watching a PR through to merge (a different job, with
|
|
5
|
+
its own rules) see [`watch-contract.md`](watch-contract.md).
|
|
6
|
+
|
|
7
|
+
## Querying PR and Queue Status
|
|
8
|
+
|
|
9
|
+
### Mergify's own view — why a PR is or isn't moving
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
mergify queue status # all batches + waiting PRs
|
|
13
|
+
mergify queue status --branch main # one branch
|
|
14
|
+
mergify queue status --json # parseable
|
|
15
|
+
mergify queue show <PR> # one PR: position, priority, CI state
|
|
16
|
+
mergify queue show <PR> -v # + full checks table and conditions tree
|
|
17
|
+
mergify queue show <PR> --json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`mergify queue show <PR> -v` is the one to reach for. The conditions tree shows
|
|
21
|
+
which conditions are met and **which single one is blocking** — that is the
|
|
22
|
+
answer to "why is this stuck", and nothing else in the toolchain reports it.
|
|
23
|
+
|
|
24
|
+
Queue states worth recognising:
|
|
25
|
+
|
|
26
|
+
| State | Meaning |
|
|
27
|
+
|-------|---------|
|
|
28
|
+
| `waiting_for_batch` | Queued, not yet picked into a batch |
|
|
29
|
+
| `waiting_for_previous_batches` | Blocked on an earlier batch |
|
|
30
|
+
| `preparing` / `running` | Batch is being set up / running CI |
|
|
31
|
+
| `bisecting` | Batch failed; splitting to find the culprit |
|
|
32
|
+
| `failed` | CI failed for this batch |
|
|
33
|
+
| `waiting_for_merge` | CI passed, waiting on GitHub |
|
|
34
|
+
| `waiting_schedule` | Outside the configured merge schedule |
|
|
35
|
+
| `frozen` | Queue is paused |
|
|
36
|
+
|
|
37
|
+
### GitHub's view — the raw checks and merge state
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
gh pr checks <PR> # check-run table, exit 1 if any failed
|
|
41
|
+
gh pr checks <PR> --watch # block until they settle
|
|
42
|
+
gh pr view <PR> --json state,isDraft,mergeable,mergeStateStatus,statusCheckRollup
|
|
43
|
+
gh pr view <PR> --json labels --jq '.labels[].name' # queued / dequeued labels
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Mergify labels a PR `queued` on entry and `dequeued` on removal
|
|
47
|
+
(`merge_queue.queued_label` / `dequeued_label`). These are **lifecycle** signals,
|
|
48
|
+
not a cheap membership check — what they mean depends on what you saw before
|
|
49
|
+
them, which is why reading them is the watcher's job and not a one-off `gh`
|
|
50
|
+
call. See [`watch-contract.md`](watch-contract.md).
|
|
51
|
+
|
|
52
|
+
### Which one to ask
|
|
53
|
+
|
|
54
|
+
Use **both, in this order** — they answer different questions and disagreeing
|
|
55
|
+
answers are themselves the diagnosis:
|
|
56
|
+
|
|
57
|
+
1. `mergify queue show <PR> -v` — is it in the queue, and what condition blocks it?
|
|
58
|
+
2. `gh pr checks <PR>` — is the underlying CI actually green?
|
|
59
|
+
|
|
60
|
+
A check that is **green in GitHub but unmet in Mergify** means the condition
|
|
61
|
+
names the wrong check. A check that is **absent** (never created, e.g. filtered
|
|
62
|
+
out by the workflow's `paths:`) reads as permanently unmet — see the trap below.
|
|
63
|
+
|
|
64
|
+
### Pause / resume
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
mergify queue pause --reason "production incident — halting merges"
|
|
68
|
+
mergify queue unpause
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Pausing does not cancel running CI; it stops new merges. The reason is visible
|
|
72
|
+
to everyone in `queue status`. Add `--yes-i-am-sure` in scripts.
|
|
73
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Traps
|
|
2
|
+
|
|
3
|
+
These are the ones that cost real time. Each has been hit in production.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
**A path-filtered check is *absent*, not failing.** If the workflow has an
|
|
7
|
+
`on.pull_request.paths:` filter, a PR touching none of those paths never creates
|
|
8
|
+
the check — and `check-success = <name>` can never be satisfied. Those PRs sit in
|
|
9
|
+
the queue forever with nothing reporting why. Write the condition as an `or` with
|
|
10
|
+
an explicit exemption (see the template's `gate` anchor), and **include the
|
|
11
|
+
workflow file's own path in the exemption** — otherwise a workflow-only PR takes
|
|
12
|
+
the exempt branch and can merge with the gate red, which is precisely the change
|
|
13
|
+
most able to disable the gate.
|
|
14
|
+
|
|
15
|
+
**Never write `success_conditions: [queue-name = default]`** in a
|
|
16
|
+
`merge_protections` rule to force merges through the queue. Merge-protection
|
|
17
|
+
conditions are injected into the queue's **entry** conditions, while the GitHub
|
|
18
|
+
ruleset requires the resulting check **before** entry — entry waits on a check
|
|
19
|
+
that cannot go green until after entry, and the repository deadlocks with every
|
|
20
|
+
PR parked at "Waiting for queue conditions". `branch_protection_injection_mode:
|
|
21
|
+
merge` does **not** prevent this; it governs GitHub-side injection, not Mergify's
|
|
22
|
+
own merge protections. Queue-only merges are a **GitHub ruleset** job, not a
|
|
23
|
+
Mergify-config job — use the `update` rule, as in
|
|
24
|
+
[Enforcing Queue-Only Merges](branch-protection.md#enforcing-queue-only-merges).
|
|
25
|
+
|
|
26
|
+
**A required status check does not make the queue mandatory.** Once it goes
|
|
27
|
+
green, anyone with write access can merge directly and the queue never sees the
|
|
28
|
+
PR. Only the `update` rule stops that.
|
|
29
|
+
|
|
30
|
+
**`update` locks out your own automation.** Enabling it without adding the
|
|
31
|
+
GitHub Actions app (or whatever pushes to the branch) as a bypass actor turns
|
|
32
|
+
every release/version-bump job red. Inventory pushers before you enable it.
|
|
33
|
+
|
|
34
|
+
**Do not make Mergify the sole bypass actor without a break-glass path.** If
|
|
35
|
+
Mergify is the only actor that can write to the branch and Mergify has an
|
|
36
|
+
outage, nobody can merge the fix either. Keep `OrganizationAdmin` bypass.
|
|
37
|
+
|
|
38
|
+
**Define the gate once, assert it three times.** The queue-entry gate, the
|
|
39
|
+
queue-merge gate and the GitHub-required merge protection must be the same YAML
|
|
40
|
+
anchor. Three hand-written copies drift, and the drift shows up as an
|
|
41
|
+
unmergeable PR, not as an error.
|
|
42
|
+
|
|
43
|
+
**`merge_conditions` re-asserting `queue_conditions` is not redundant.** Mergify
|
|
44
|
+
tests the batch merged with its base — a tree that existed when no individual
|
|
45
|
+
PR's CI ran.
|
|
46
|
+
|
|
47
|
+
**`-draft` is deliberately absent** from `queue_conditions` and
|
|
48
|
+
`merge_conditions`. Under manual enqueue nothing queues a draft by accident, and
|
|
49
|
+
a leftover draft condition presents as "queued, no reason given". Know what the
|
|
50
|
+
absence costs before you re-add it or rely on it: GitHub cannot merge a draft PR,
|
|
51
|
+
so a draft that *is* enqueued rides a whole batch CI run and then fails at the
|
|
52
|
+
merge call, taking the batch's innocent PRs through that failure. Marking a
|
|
53
|
+
queued PR as draft no longer dequeues it either — `@mergifyio dequeue` does.
|
|
54
|
+
|
|
55
|
+
**Stop drafts at *creation*, not just at the queue.** The paragraph above is the
|
|
56
|
+
queue side — it does not stop a PR being *born* a draft, and the queue does not
|
|
57
|
+
filter drafts out. So the guard belongs where PRs are opened. `mergify stack`
|
|
58
|
+
opens each PR per its `--draft` flag, falling back to git config
|
|
59
|
+
`mergify-cli.stack-create-as-draft`, which is `false` when unset and only counts
|
|
60
|
+
the literal string `"true"`. The failure mode is therefore a **global**
|
|
61
|
+
`mergify-cli.stack-create-as-draft=true` inherited into every repo, silently
|
|
62
|
+
drafting every agent-opened PR. Pin it off in the repo so no inherited value can
|
|
63
|
+
flip it:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git config mergify-cli.stack-create-as-draft false
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
An explicit `--draft` on the `mergify stack` invocation still overrides this, so
|
|
70
|
+
also confirm no wrapper or alias passes it. (Deliberate drafting is a separate
|
|
71
|
+
case: `resolve-issues`' integration gate converts per-unit PRs to draft *after*
|
|
72
|
+
opening the combined PR — that is intended and not what this guard is about.)
|
|
73
|
+
|
|
74
|
+
**Under a required Mergify check, set `branch_protection_injection_mode: merge`.**
|
|
75
|
+
The default (`queue`) injects ruleset requirements into entry conditions too, and
|
|
76
|
+
a Mergify check that deliberately fails pre-queue then blocks the enqueue that
|
|
77
|
+
would make it pass.
|
|
78
|
+
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Mergify Delivery Watch Contract
|
|
2
|
+
|
|
3
|
+
Use this contract whenever an agent queues or watches a PR through Mergify, whether the work is a full `resolve-issues` delivery or a simple PR. The goal is to avoid the recurring false states where a dequeued PR is reported as healthy, a not-yet-admitted PR is reported as failed, or a stale GitHub check-rollup is treated as Mergify queue truth.
|
|
4
|
+
|
|
5
|
+
## A Watch Observes A Progression, Not A State
|
|
6
|
+
|
|
7
|
+
Read this before the state machine — it is the premise the rest of the file rests on, and skipping it is how a correct-looking watcher gets built anyway.
|
|
8
|
+
|
|
9
|
+
The queue lifecycle is a **sequence**, and every verdict worth having is a *transition* between its phases, never a property of a single reading:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
NOT_YET_QUEUED ──enqueue accepted──▶ QUEUED ──┬──▶ MERGED
|
|
13
|
+
│ ├──▶ DEQUEUED
|
|
14
|
+
└──▶ STALLED (never admitted) └──▶ CLOSED_UNMERGED
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The identical observation means opposite things on either side of queue entry:
|
|
18
|
+
|
|
19
|
+
| Reading | Before entry | After entry |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| active queue membership absent | `NOT_YET_QUEUED` — healthy, keep waiting | **`DEQUEUED`** — terminal, read the reason |
|
|
22
|
+
|
|
23
|
+
So the watcher's memory *is* the verdict. Four pieces of state must survive across polls:
|
|
24
|
+
|
|
25
|
+
1. **`seenQueued`** — has queue entry ever been observed? Every downstream transition depends on it. Set from the `queued` label **or** `mergify queue show`.
|
|
26
|
+
2. **A re-read counter** (`missingActiveReads` / `absentStreak`) — one absence is suspicion, two consecutive *readable* absences settle `DEQUEUED`.
|
|
27
|
+
3. **Readable vs. absent** — a failed `gh`/`mergify` call is *no information* and must not advance that counter.
|
|
28
|
+
4. **A change clock** (`lastChangeMs`) — the stall bound is *no observable change*, not elapsed time.
|
|
29
|
+
|
|
30
|
+
### Why a per-poll predicate cannot satisfy this
|
|
31
|
+
|
|
32
|
+
A background-task runner that re-executes a command each tick and reads its exit code is a **stateless predicate evaluator**. There is nowhere to keep items 1–4, so the shape is wrong before the code is. This is not theoretical — pi session `019fae8f` produced four hand-rolled watchers for one PR, and each failed a different one of the four:
|
|
33
|
+
|
|
34
|
+
| Hand-rolled watcher | Failure |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `state ∈ {MERGED, CLOSED}` | A dequeued PR is plain `OPEN`. Dequeue is structurally invisible; the watch runs to its ceiling reporting health. |
|
|
37
|
+
| `.queued // false` | The JSON-shape trap below — never observes entry, so item 1 stays false and the whole dequeue path is dead code. |
|
|
38
|
+
| single absent read → terminal | No item 2. Settled `DEQUEUED` on a PR that was mid-`checking`. |
|
|
39
|
+
| `mergify … \|\| printf '{"queued":false}'` | No item 3. Converts an outage into a false dequeue, *faster* than the stall bound rather than through it. |
|
|
40
|
+
|
|
41
|
+
Two of the four were written *after* the agent had been told to check for dequeue, and one of those reported a false `DEQUEUED` on a healthy PR. Knowing the requirement does not rescue the shape.
|
|
42
|
+
|
|
43
|
+
**Therefore: run [`../scripts/watch-pr-delivery.mjs`](../scripts/watch-pr-delivery.mjs).** It is one long-lived process owning its own poll loop, so items 1–4 live in its locals. Do not wrap it in an outer poller — that reintroduces exactly the shape it exists to replace.
|
|
44
|
+
|
|
45
|
+
### `phases` — the progression as output
|
|
46
|
+
|
|
47
|
+
The watcher emits `phases`: the ordered list of lifecycle phases actually observed, on both the terminal verdict and every heartbeat. It resolves the one ambiguity the terminal outcome cannot:
|
|
48
|
+
|
|
49
|
+
| terminal | `phases` | meaning | fix |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| `STALLED` | `["NOT_YET_QUEUED","STALLED"]` | never admitted (`reason` is usually `admission-stall`) | enqueue it, or diagnose why admission never happened |
|
|
52
|
+
| `STALLED` | `["NOT_YET_QUEUED","QUEUED","STALLED"]` | admitted, then wedged in the queue (`reason` is usually `stall-bound`) | read the blocking condition |
|
|
53
|
+
|
|
54
|
+
`WAITING` is deliberately not a phase — it is the re-read suspicion state *inside* `QUEUED`, and recording it would oscillate a healthy PR's progression into noise.
|
|
55
|
+
|
|
56
|
+
## Enqueue Before You Watch
|
|
57
|
+
|
|
58
|
+
The watch observes only — it never posts `@mergifyio queue`. Check membership first, because on a repo configured for manual delivery the answer decides whether a watch is worth starting at all:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
mergify queue show <PR> --json | jq '{position, queue_rule_name, queued_at}' # membership now
|
|
62
|
+
mergify queue show <PR> --json | jq '.queue_rule.config.autoqueue' # can it self-queue?
|
|
63
|
+
grep -n "auto_merge_conditions" .mergify.yml # or auto-enqueue?
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Read `autoqueue` from the **resolved** config Mergify reports, not from `.mergify.yml`. The authorable key is deprecated, so a correct config never contains it and grepping the file always finds nothing — which tells you nothing. `queue show` reports the effective value either way.
|
|
67
|
+
|
|
68
|
+
If the PR is not queued, `autoqueue` is `false`, **and** the repo has no `auto_merge_conditions`, nothing will ever put it in the queue on its own. A watch started there can only end `STALLED` — enqueue first, then watch. A repo whose `.mergify.yml` says *"delivery stays manual"* is exactly this case.
|
|
69
|
+
|
|
70
|
+
A 👍 on the command comment acknowledges the *command*, not queue entry.
|
|
71
|
+
|
|
72
|
+
## Batch Delivery — Enqueue The Whole Ready Set Together
|
|
73
|
+
|
|
74
|
+
Batch mode is configured at the queue level (`batch_size`, `batch_max_wait_time`), but whether a batch ever *happens* is a delivery decision. Mergify only batches PRs that are **in the queue together**: it holds the gate open for `batch_max_wait_time`, then tests up to `batch_size` PRs as one CI run. So the batching lever in an agent's hands is *enqueue timing and grouping* — not config. (Config's part is one line: write `batch_size: 3` — the skill's default. It must be explicit: an unset `batch_size` silently runs at Mergify's built-in default of 1, i.e. no batching — see [`configuration.md`](configuration.md#2--3-batch-mode-size-3).)
|
|
75
|
+
|
|
76
|
+
**The default delivery pattern is to enqueue the whole ready set in one pass.** When several PRs against the same base are merge-ready — a stack, an epic's units, a burst of related edits — enqueue them all before watching any:
|
|
77
|
+
|
|
78
|
+
- One batch CI run for N PRs instead of N. Serial delivery — enqueue #1, watch it merge, then enqueue #2 — means each PR rides its own batch: N CI runs and N watch cycles for work that could have landed in one. Being in the queue together is never slower; it is usually several CI runs faster.
|
|
79
|
+
- A red batch is safe: Mergify bisects it and dequeues only the culprit; the innocent PRs carry on.
|
|
80
|
+
- **"If possible" is the escape hatch, not the rule.** A lone PR, or a set where the rest still wait on review/CI/conflict, is enqueued as-is — `batch_max_wait_time` bounds the wait for company, and a ready PR is never held back for a straggler.
|
|
81
|
+
|
|
82
|
+
**Mergify groups PRs into a batch by relationship, not queue order.** It does not simply take the next N in the queue: priority and queue order seed a batch, **stacks always stay together**, and similarity (shared scopes, then changed directories, then queue time) fills the remaining slots. Consequences:
|
|
83
|
+
|
|
84
|
+
- Related PRs enqueued together reliably ride one batch — that is the pattern to aim for.
|
|
85
|
+
- Unrelated PRs may still split across batches. That is Mergify's choice and it is correct: it keeps one PR's failure from dragging unrelated work into a bisection. Do not force co-batching (e.g. by inventing scopes) to fight it.
|
|
86
|
+
|
|
87
|
+
**Mechanics.** `@mergifyio queue` is per-PR — it is a comment posted on the PR and takes no PR list — so "together" means posting it on each ready PR in the same pass, then watching: one `watch-pr-delivery.mjs` per PR, launched together (they are cheap at the default interval), or the batch as a whole via `mergify queue status`. Enqueue promptly once a PR is ready: the batch window is the fill time, and a PR entering after it closes rides the *next* batch.
|
|
88
|
+
|
|
89
|
+
While a batch forms, `waiting_for_batch` just means the gate is still open — keep watching, do not read it as stuck. `bisecting` means the batch went red and Mergify is splitting it — keep watching; only the culprit leaves the queue.
|
|
90
|
+
|
|
91
|
+
## Source Of Truth
|
|
92
|
+
|
|
93
|
+
Use Mergify and GitHub for different facts:
|
|
94
|
+
|
|
95
|
+
1. `gh pr view <PR> --json state,mergedAt,mergeCommit,labels,url,comments`
|
|
96
|
+
- authoritative for whether the PR merged or closed
|
|
97
|
+
- source for Mergify lifecycle labels: `queued` and `dequeued`
|
|
98
|
+
- `comments` is not optional padding: it is the only source for *when* a `dequeued` label was applied (Mergify's status-comment payload), which is what distinguishes this attempt's dequeue from a stale label left by a previous one. Omit it and that guard silently degrades to "no reliable timestamp" on every poll. It costs no extra request — same call.
|
|
99
|
+
2. `mergify queue show <PR> --json`
|
|
100
|
+
- authoritative for active queue membership, position, queue rule, CI state, and condition tree
|
|
101
|
+
3. `gh pr checks <PR>` / check-rollup
|
|
102
|
+
- useful for debugging CI, but not authoritative for queue membership
|
|
103
|
+
|
|
104
|
+
Do not use `Mergify Merge Queue` check-rollup state alone to decide queued/dequeued status. It can be stale, neutral, or in progress while the queue tool says something more precise.
|
|
105
|
+
|
|
106
|
+
## State Machine
|
|
107
|
+
|
|
108
|
+
A watcher must retain history for the PR it is watching.
|
|
109
|
+
|
|
110
|
+
- `MERGED`: PR state is `MERGED` or `mergedAt` is set. Return the PR merge commit SHA, not the branch head. The caller still owes ancestry verification.
|
|
111
|
+
|
|
112
|
+
On this path Mergify removes `queued` **without ever adding `dequeued`** — so a watcher that waits for a `dequeued` label to decide anything waits forever on the happy path. The label is also a lifecycle mirror that is never cleared on re-enqueue, so its mere presence is not this attempt's outcome; date it against the watch's start before treating it as terminal (see the `#629` guards in the script).
|
|
113
|
+
- `CLOSED_UNMERGED`: PR state is `CLOSED` with no merge. Terminal hand-back.
|
|
114
|
+
- `QUEUED`: `queued` label is present, or `mergify queue show --json` reports active membership. Set `seenQueued = true`.
|
|
115
|
+
|
|
116
|
+
**Do not test for `queued: true` — that field does not exist on a queued PR.** Verified live against PR #1396: a PR *in* the queue returns `position`, `queue_rule_name`, `queued_at`, and `queue_rule` — and no `queued` key at all. Only the *not*-queued answer is literally `{"number": <PR>, "queued": false}`. A watcher keyed on `queued === true` therefore never observes queue entry, so `seenQueued` stays false forever and every downstream transition that depends on it (`DEQUEUED`, the re-read rule) is silently dead. Infer membership the way the bundled script does:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
const queued = parsed.queued === true || Boolean(parsed.queue_rule_name || parsed.queue_rule)
|
|
120
|
+
```
|
|
121
|
+
- `DEQUEUED`: PR is still open and unmerged, and either:
|
|
122
|
+
- `dequeued` label is present (this-watch timestamp guards apply — see `#629`), or
|
|
123
|
+
- **process-local** membership was observed (`everActive`) and is now absent across two consecutive readable re-reads (`lost-queue-membership`).
|
|
124
|
+
- `NOT_YET_QUEUED`: active queue membership is absent before this process has observed membership. This is not a dequeue. It usually means the queue command has not been processed yet, the PR is waiting for queue conditions, or Mergify status has not refreshed. **`--seen-queued` alone does not leave this state** — that flag is a resume *hint* for callers/phases; it does not prove this process saw membership (epic-824 `#859` first watch false-`DEQUEUED` when the counter started from the seed).
|
|
125
|
+
- `WAITING`: membership was observed, then one readable absence — re-read suspicion, not terminal.
|
|
126
|
+
- `STALLED`: no observable queue/admission state has changed for the configured stall bound. Terminal hand-back, not a merge failure. The bound is **phase-aware**: pre-admission (never observed membership this process) uses the shorter `--admission-stall-minutes` (default 3) and reports `reason: "admission-stall"`; after membership has been observed, the full `--stall-minutes` (default 10) applies and reports `reason: "stall-bound"`. Same terminal outcome and exit code either way — only wall time and `reason` change. A dead admission path (forgotten enqueue, stale Mergify status, unreadable queue API) must not burn the post-entry bound. An `admission-stall` while Mergify is visibly waiting on a green-or-pending admission check is often a **too-short window**, not a broken enqueue — relaunch with the CI-gated 15m pair above rather than treating 60m as the next step.
|
|
127
|
+
|
|
128
|
+
The critical invariant: after a watcher has **observed** queue entry in this process (`everActive`), it must never keep reporting `queued:false` as a routine healthy snapshot. If the PR did not merge, loss of queue membership is a queue exit. Seeding `seenQueued` via `--seen-queued` before the first successful membership poll must not invent that observation.
|
|
129
|
+
|
|
130
|
+
## Re-read Rule
|
|
131
|
+
|
|
132
|
+
GitHub can briefly expose neither `queued` nor `dequeued` during a label transition. Treat a single missing-label read **after process-local membership** as suspicion, then re-read. Two consecutive missing active-membership reads settle the transition as `DEQUEUED` unless the PR merged in the meantime. Absences before `everActive` stay `NOT_YET_QUEUED`.
|
|
133
|
+
|
|
134
|
+
## Dequeue Reason
|
|
135
|
+
|
|
136
|
+
Record both fields when the queue gives you a reason:
|
|
137
|
+
|
|
138
|
+
- `rawReason`: the provider's exact string or visible status text
|
|
139
|
+
- `reason`: the routing class used by the caller
|
|
140
|
+
|
|
141
|
+
Suggested routing classes:
|
|
142
|
+
|
|
143
|
+
| raw reason shape | route |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `checks-failed` | fix round, fresh verdict, new enqueue |
|
|
146
|
+
| `pull-request-updated`, `draft-pull-request-changed` | HEAD moved; verdict stale; re-enter delivery after fresh validation |
|
|
147
|
+
| `conflict`, `conflict-with-base-branch` | rebase/evidence refresh, then enqueue |
|
|
148
|
+
| `conditions-unmet`, `frozen`, `manual`, `pr-manually-dequeued`, `checks-timeout` | hand back with the condition/reason quoted |
|
|
149
|
+
| unknown | hand back; fail closed |
|
|
150
|
+
|
|
151
|
+
When the reason is not machine-readable, quote the Mergify status comment, queue show condition leaf, or event-log URL in `rawReason` rather than inventing a reason.
|
|
152
|
+
|
|
153
|
+
## Watcher Requirements
|
|
154
|
+
|
|
155
|
+
- Run as one background task or one script invocation; do not spend foreground turns polling.
|
|
156
|
+
- Retry transient `gh`, GraphQL, and Mergify CLI failures. EOF, TLS handshake timeouts, and temporary API failures are not dequeue signals — an unreadable read is *no information*, not a "not queued" observation, and must not advance the counter that settles `DEQUEUED`.
|
|
157
|
+
- Bound every subprocess read on its own timeout, in addition to the stall/ceiling bounds below — those are only evaluated after a poll returns, so an unbounded read can hang the watcher past both of them.
|
|
158
|
+
- **Run the bundled script. Do not hand-roll a watcher** — see the progression section above for why the hand-rolled shape cannot hold the contract, whatever care goes into the code. (If you are reading a legacy shell watcher: avoid shell-reserved variable names such as `status`.)
|
|
159
|
+
- Keep enqueue and watch separate. A watch observes only; it does not post `@mergifyio queue`, `@mergifyio dequeue`, or merge.
|
|
160
|
+
- Confirm the PR is queued, or can become queued, *before* launching the watch — see [Enqueue Before You Watch](#enqueue-before-you-watch). A watch that cannot enqueue, on a PR nothing else will enqueue either, can only end `STALLED`.
|
|
161
|
+
- Emit an observation record every poll, not only on the terminal verdict. `NOT_YET_QUEUED` and `QUEUED` are both non-terminal and cover the entire healthy path, so a watcher that speaks only at the end is silent for essentially its whole life — indistinguishable, to the caller trying to decide whether delivery is progressing, from a hung or dead process. Keep the heartbeat off the machine-contract stream: stdout carries exactly the one terminal JSON document callers parse, stderr carries the per-poll records.
|
|
162
|
+
- Bound on stalled state, not total elapsed time alone. `waiting_for_previous_batches` can be slow but healthy if position/state changes.
|
|
163
|
+
|
|
164
|
+
## Script
|
|
165
|
+
|
|
166
|
+
Use the bundled watcher for simple PR delivery checks:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
node ~/.agents/skills/mergify/scripts/watch-pr-delivery.mjs \
|
|
170
|
+
--repo <owner>/<repo> \
|
|
171
|
+
--pr 1302
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Options:
|
|
175
|
+
|
|
176
|
+
| flag | default | meaning |
|
|
177
|
+
|---|---:|---|
|
|
178
|
+
| `--interval-seconds` | `90` | poll interval |
|
|
179
|
+
| `--stall-minutes` | `10` | post-entry terminal stall bound — no observable delivery-state change for this long *after queue membership has been observed* is `STALLED` with `reason: "stall-bound"`. A *no-change* bound, not elapsed time: any movement in position, label, or queue state resets it, so a slow-but-healthy queue is never cut off by it |
|
|
180
|
+
| `--admission-stall-minutes` | `3` | pre-admission terminal stall bound — no observable change *before this process has observed membership* is `STALLED` with `reason: "admission-stall"`. Shorter on purpose: after enqueue, queue entry should appear quickly, and a dead admission path must not wait out the full post-entry bound. Capped at `--stall-minutes` so a caller that shortens the post-entry bound keeps both phases tight. **When Mergify admission itself waits on CI** (status still "waiting on PR admission gate" / warehouse lane / similar), keep the 3m default for the first watch, then relaunch with **`--admission-stall-minutes 15` and `--stall-minutes` ≥ 15** — the admission bound cannot exceed the post-entry stall. Do **not** jump to `--max-minutes 60` for that; 60 is only the absolute ceiling |
|
|
181
|
+
| `--max-minutes` | `60` | absolute safety ceiling; bounds the watch even while the queue keeps reporting change, so a busy queue whose position keeps moving cannot keep the stall clock resetting forever. **60 minutes is also a hard maximum** — a larger value exits `2` rather than being silently clamped, because a caller that believes it has a four-hour watch and has one hour is worse off than one told plainly to relaunch. A batch takes minutes, so an hour of continuous movement without finishing is already a queue to hand back to a human. The sibling `resolve-issues` watcher enforces the same ceiling; a cap honoured by one of two watchers is not a cap |
|
|
182
|
+
| `--quiet` | off | suppress the per-poll progress heartbeat on stderr |
|
|
183
|
+
|
|
184
|
+
Output streams:
|
|
185
|
+
|
|
186
|
+
| stream | content |
|
|
187
|
+
|---|---|
|
|
188
|
+
| stdout | exactly one pretty-printed terminal JSON verdict, at exit — carrying `phases`, `seenQueued`, and the outcome |
|
|
189
|
+
| stderr | one compact JSON record per poll (`progress: true`), with the live outcome, PR labels, queue membership/position, `phases`, `changed`, and `sinceChangeMs` — the stall clock made visible |
|
|
190
|
+
|
|
191
|
+
Each subprocess read (`gh pr view`, `mergify queue show`) also carries its own bounded
|
|
192
|
+
timeout — a small multiple of `--interval-seconds`, clamped to never exceed the **effective
|
|
193
|
+
phase stall bound** (pre-admission: `--admission-stall-minutes`; post-entry: `--stall-minutes`)
|
|
194
|
+
capped by `--max-minutes`, then divided by the number of reads made per poll (2 here:
|
|
195
|
+
`gh pr view` + `mergify queue show`). The two reads together cannot outlive the bound that will
|
|
196
|
+
actually fire `STALLED` on this poll — so a hung pre-admission poll cannot outlive the short
|
|
197
|
+
admission clock, and a post-entry poll is not permanently clamped to the admission value.
|
|
198
|
+
Those stall/ceiling bounds are only evaluated after a poll returns, and a single hung read
|
|
199
|
+
cannot alone consume more than half of a small stall/ceiling bound. (The sibling watcher makes
|
|
200
|
+
one read per poll, so its clamp divides by 1 and the single-read guarantee is the whole bound
|
|
201
|
+
there.)
|
|
202
|
+
|
|
203
|
+
The `--interval-seconds` default is already set for scale. Two API calls per poll at 90s is
|
|
204
|
+
80/hour per watched PR — roughly 60 concurrent watchers before an authenticated GitHub token's
|
|
205
|
+
5,000/hour limit is in range, which comfortably covers an epic-sized `resolve-issues` delivery.
|
|
206
|
+
(At the former 30s default it was 240/hour, or about 20 watchers.) The cost is at most 90s of
|
|
207
|
+
extra merge-detection latency against a queue that takes minutes per batch — a cheap trade.
|
|
208
|
+
Shorten it only for a single foreground watch where that latency actually matters.
|
|
209
|
+
|
|
210
|
+
Exit codes:
|
|
211
|
+
|
|
212
|
+
| code | meaning |
|
|
213
|
+
|---:|---|
|
|
214
|
+
| 0 | merged; JSON includes `outcome:"MERGED"` and `mergedSha` |
|
|
215
|
+
| 4 | terminal but not merged: `DEQUEUED`, `CLOSED_UNMERGED`, or `STALLED` |
|
|
216
|
+
| 2 | usage error |
|
|
217
|
+
|
|
218
|
+
The script emits JSON on stdout. The caller is responsible for recording the delivery attempt/outcome and proving ancestry for `MERGED`.
|