@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,263 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// rollback-floor — terminal close when floor smoke cannot go ALIVE after a correct restore (#800).
|
|
3
|
+
//
|
|
4
|
+
// Doctrine wants smoke ALIVE for verified-rollback (routing.md). identity-v0.4.1 attempt.1
|
|
5
|
+
// restored traffic to v0.4.0 correctly, then prod-active stayed DEAD on the incumbent for the
|
|
6
|
+
// same pre-existing CF Insights vs app CSP reason (identity#677). Agents had no terminal path
|
|
7
|
+
// and invented lease states or blamed the candidate code.
|
|
8
|
+
//
|
|
9
|
+
// This module defines the close:
|
|
10
|
+
// state: rolled-back
|
|
11
|
+
// closedBy: verified-rollback
|
|
12
|
+
// smoke: blocked-by-preexisting-gate
|
|
13
|
+
// incident: REQUIRED
|
|
14
|
+
// when traffic+attestation prove restore AND the floor itself fails the same check.
|
|
15
|
+
//
|
|
16
|
+
// Pure classifier — the agent (or a thin CLI) still issues the traffic restore and the
|
|
17
|
+
// record-release-attempt call; this only decides whether that close is legal and shapes
|
|
18
|
+
// the evidence string. It does not invent a new lease state.
|
|
19
|
+
//
|
|
20
|
+
// Doctrine: references/routing.md § Verification failed after exposure.
|
|
21
|
+
// Regression: identity-v0.4.1 · identity#677 · #800.
|
|
22
|
+
|
|
23
|
+
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
24
|
+
|
|
25
|
+
export const SMOKE_BLOCKED_BY_PREEXISTING_GATE = 'blocked-by-preexisting-gate'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Concrete traffic attestation is required for any verified-rollback close.
|
|
29
|
+
* A missing/empty/malformed attestation must not produce evidence that claims
|
|
30
|
+
* "traffic+attestation verified" (#800 / identity-v0.4.1).
|
|
31
|
+
*/
|
|
32
|
+
export function hasConcreteAttestation(attestation) {
|
|
33
|
+
if (!attestation || typeof attestation !== 'object' || Array.isArray(attestation)) return false
|
|
34
|
+
// Accept a revision id, a source SHA, a resource name, or an explicit verified flag.
|
|
35
|
+
const revision = attestation.revision != null ? String(attestation.revision).trim() : ''
|
|
36
|
+
const sourceSha = attestation.sourceSha != null ? String(attestation.sourceSha).trim() : ''
|
|
37
|
+
const resource = attestation.resource != null ? String(attestation.resource).trim() : ''
|
|
38
|
+
if (revision || sourceSha || resource) return true
|
|
39
|
+
if (attestation.verified === true || attestation.ok === true) return true
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {object} input
|
|
45
|
+
* @param {{ previousRevision?: string, previousPercent?: number, candidatePercent?: number, attestation?: object }} input.traffic
|
|
46
|
+
* @param {{ verdict?: string, profile?: string, target?: string, floorAlsoDead?: boolean, reason?: string }} input.smoke
|
|
47
|
+
* @param {{ number?: number, url?: string } | null} input.incidentIssue
|
|
48
|
+
*/
|
|
49
|
+
export function classifyRollbackClose({ traffic = {}, smoke = {}, incidentIssue = null } = {}) {
|
|
50
|
+
const prevPct = Number(traffic.previousPercent)
|
|
51
|
+
const candPct = traffic.candidatePercent == null ? 0 : Number(traffic.candidatePercent)
|
|
52
|
+
const percentsRestored =
|
|
53
|
+
typeof traffic.previousRevision === 'string' &&
|
|
54
|
+
traffic.previousRevision.length > 0 &&
|
|
55
|
+
Number.isFinite(prevPct) &&
|
|
56
|
+
prevPct === 100 &&
|
|
57
|
+
Number.isFinite(candPct) &&
|
|
58
|
+
candPct === 0
|
|
59
|
+
|
|
60
|
+
if (!percentsRestored) {
|
|
61
|
+
return {
|
|
62
|
+
closeable: false,
|
|
63
|
+
reason: 'traffic-not-restored',
|
|
64
|
+
detail: 'verified-rollback requires previousRevision at exactly 100% and candidate at 0%',
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Attestation is part of the restore proof, not optional garnish. Without it the
|
|
69
|
+
// close cannot claim "traffic+attestation verified".
|
|
70
|
+
if (!hasConcreteAttestation(traffic.attestation)) {
|
|
71
|
+
return {
|
|
72
|
+
closeable: false,
|
|
73
|
+
reason: 'attestation-missing',
|
|
74
|
+
detail:
|
|
75
|
+
'verified-rollback requires traffic.attestation with a concrete revision/sourceSha/resource (or verified:true); percents alone are not enough',
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const verdict = String(smoke.verdict || '').toUpperCase()
|
|
80
|
+
if (verdict === 'ALIVE') {
|
|
81
|
+
// Standard path — still requires an incident on post-exposure rollback (routing.md).
|
|
82
|
+
if (!hasIncident(incidentIssue)) {
|
|
83
|
+
return {
|
|
84
|
+
closeable: false,
|
|
85
|
+
reason: 'incident-required',
|
|
86
|
+
detail: 'post-exposure rollback always files an incident issue',
|
|
87
|
+
closedBy: 'verified-rollback',
|
|
88
|
+
smoke: 'ALIVE',
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
closeable: true,
|
|
93
|
+
closedBy: 'verified-rollback',
|
|
94
|
+
smoke: 'ALIVE',
|
|
95
|
+
requiresIncident: true,
|
|
96
|
+
incidentIssue: normalizeIncident(incidentIssue),
|
|
97
|
+
traffic: {
|
|
98
|
+
previousRevision: traffic.previousRevision,
|
|
99
|
+
previousPercent: 100,
|
|
100
|
+
candidatePercent: 0,
|
|
101
|
+
attestation: traffic.attestation,
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// DEAD / EMPTY / cannot-run: only closeable when the floor itself is known to fail the
|
|
107
|
+
// same check (pre-existing gate/env), not when the restore may have left production bad.
|
|
108
|
+
if (verdict === 'DEAD' || verdict === 'EMPTY' || verdict === 'CANNOT-RUN' || verdict === 'CANNOT_RUN') {
|
|
109
|
+
if (!smoke.floorAlsoDead) {
|
|
110
|
+
return {
|
|
111
|
+
closeable: false,
|
|
112
|
+
reason: 'smoke-dead-without-floor-preexistence',
|
|
113
|
+
detail:
|
|
114
|
+
'prod-active DEAD after restore without floorAlsoDead evidence — do not invent a close; page and establish whether the incumbent itself fails the same check',
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!hasIncident(incidentIssue)) {
|
|
118
|
+
return {
|
|
119
|
+
closeable: false,
|
|
120
|
+
reason: 'incident-required',
|
|
121
|
+
detail: 'blocked-by-preexisting-gate requires a filed incident issue (identity#677 class)',
|
|
122
|
+
smoke: SMOKE_BLOCKED_BY_PREEXISTING_GATE,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
closeable: true,
|
|
127
|
+
closedBy: 'verified-rollback',
|
|
128
|
+
smoke: SMOKE_BLOCKED_BY_PREEXISTING_GATE,
|
|
129
|
+
requiresIncident: true,
|
|
130
|
+
incidentIssue: normalizeIncident(incidentIssue),
|
|
131
|
+
floorReason: smoke.reason || 'pre-existing floor gate/env failure',
|
|
132
|
+
traffic: {
|
|
133
|
+
previousRevision: traffic.previousRevision,
|
|
134
|
+
previousPercent: 100,
|
|
135
|
+
candidatePercent: 0,
|
|
136
|
+
attestation: traffic.attestation,
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
closeable: false,
|
|
143
|
+
reason: 'smoke-unreadable',
|
|
144
|
+
detail: `smoke verdict ${JSON.stringify(smoke.verdict)} is not ALIVE or a floor-preexistence DEAD`,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function buildRollbackClosePayload(classified) {
|
|
149
|
+
if (!classified || !classified.closeable) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
`buildRollbackClosePayload: not closeable (${classified && classified.reason}) — ${classified && classified.detail}`,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
const rev = classified.traffic.previousRevision
|
|
155
|
+
const incident = classified.incidentIssue
|
|
156
|
+
const incidentRef = incident.number != null ? `#${incident.number}` : incident.url
|
|
157
|
+
let evidence
|
|
158
|
+
if (classified.smoke === SMOKE_BLOCKED_BY_PREEXISTING_GATE) {
|
|
159
|
+
evidence =
|
|
160
|
+
`${rev} restored to 100%; traffic+attestation verified; ` +
|
|
161
|
+
`smoke: ${SMOKE_BLOCKED_BY_PREEXISTING_GATE} (${classified.floorReason}); ` +
|
|
162
|
+
`incident ${incidentRef}`
|
|
163
|
+
} else {
|
|
164
|
+
evidence =
|
|
165
|
+
`${rev} restored to 100%; smoke ALIVE against live service; incident ${incidentRef}`
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
state: 'rolled-back',
|
|
169
|
+
closedBy: classified.closedBy,
|
|
170
|
+
evidence,
|
|
171
|
+
smoke: classified.smoke,
|
|
172
|
+
incidentIssue: incident,
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function hasIncident(issue) {
|
|
177
|
+
return !!(issue && (issue.number != null || issue.url))
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function normalizeIncident(issue) {
|
|
181
|
+
if (!issue) return null
|
|
182
|
+
return {
|
|
183
|
+
number: issue.number != null ? Number(issue.number) : null,
|
|
184
|
+
url: issue.url || null,
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export const USAGE = `rollback-floor — classify a post-exposure rollback close when floor smoke cannot pass.
|
|
189
|
+
|
|
190
|
+
rollback-floor classify --traffic <json> --smoke <json> [--incident <json>]
|
|
191
|
+
Pure decision. Prints {closeable, closedBy, smoke, ...}. Exit 0 always when readable;
|
|
192
|
+
exit 2 on usage.
|
|
193
|
+
|
|
194
|
+
rollback-floor payload --traffic <json> --smoke <json> --incident <json>
|
|
195
|
+
Shape the record-release-attempt JSON when closeable. Exit 0 on closeable, 1 otherwise.
|
|
196
|
+
|
|
197
|
+
Why: identity-v0.4.1 restored traffic correctly then prod-active stayed DEAD on the
|
|
198
|
+
incumbent (CF Insights vs CSP, identity#677). Without this path agents invent lease
|
|
199
|
+
states. See references/routing.md and issue #800.`
|
|
200
|
+
|
|
201
|
+
export function parseArgs(argv) {
|
|
202
|
+
const args = { positional: [] }
|
|
203
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
204
|
+
const a = argv[i]
|
|
205
|
+
if (a === '--help' || a === '-h') args.help = true
|
|
206
|
+
else if (a === '--traffic') args.traffic = argv[++i]
|
|
207
|
+
else if (a === '--smoke') args.smoke = argv[++i]
|
|
208
|
+
else if (a === '--incident') args.incident = argv[++i]
|
|
209
|
+
else if (a.startsWith('-')) args.unknown = a
|
|
210
|
+
else args.positional.push(a)
|
|
211
|
+
}
|
|
212
|
+
args.cmd = args.positional[0] || null
|
|
213
|
+
return args
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function parseJsonFlag(raw, name) {
|
|
217
|
+
if (!raw) return null
|
|
218
|
+
try {
|
|
219
|
+
return JSON.parse(raw)
|
|
220
|
+
} catch (err) {
|
|
221
|
+
throw new Error(`${name} is not valid JSON: ${err.message}`)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function main(argv) {
|
|
226
|
+
const args = parseArgs(argv)
|
|
227
|
+
if (args.help || args.cmd === 'help') {
|
|
228
|
+
console.log(USAGE)
|
|
229
|
+
return 0
|
|
230
|
+
}
|
|
231
|
+
if (args.unknown) {
|
|
232
|
+
console.error(`rollback-floor: unknown flag ${args.unknown}`)
|
|
233
|
+
return 2
|
|
234
|
+
}
|
|
235
|
+
if (!args.cmd || !['classify', 'payload'].includes(args.cmd)) {
|
|
236
|
+
console.error('rollback-floor: use classify|payload (see --help)')
|
|
237
|
+
return 2
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
const traffic = parseJsonFlag(args.traffic, '--traffic') || {}
|
|
241
|
+
const smoke = parseJsonFlag(args.smoke, '--smoke') || {}
|
|
242
|
+
const incidentIssue = parseJsonFlag(args.incident, '--incident')
|
|
243
|
+
const classified = classifyRollbackClose({ traffic, smoke, incidentIssue })
|
|
244
|
+
if (args.cmd === 'classify') {
|
|
245
|
+
console.log(JSON.stringify(classified, null, 2))
|
|
246
|
+
return 0
|
|
247
|
+
}
|
|
248
|
+
if (!classified.closeable) {
|
|
249
|
+
console.error(`rollback-floor: not closeable — ${classified.reason}: ${classified.detail}`)
|
|
250
|
+
console.log(JSON.stringify(classified, null, 2))
|
|
251
|
+
return 1
|
|
252
|
+
}
|
|
253
|
+
console.log(JSON.stringify(buildRollbackClosePayload(classified), null, 2))
|
|
254
|
+
return 0
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.error(`rollback-floor: ${err.message}`)
|
|
257
|
+
return 2
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (isMainModule(import.meta.url)) {
|
|
262
|
+
process.exit(main(process.argv.slice(2)))
|
|
263
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// version-assert — display-version policy check for the release lane (issue #822).
|
|
2
|
+
//
|
|
3
|
+
// A release has two version concepts:
|
|
4
|
+
// - identity version: the immutable tag / SHA that names what is running
|
|
5
|
+
// (candidate-identity.mjs owns this: sourceSha, revision, imageDigest).
|
|
6
|
+
// - display version: the string the running service prints in UI and /api/health.
|
|
7
|
+
//
|
|
8
|
+
// Under rc-tag deploy topology the pipeline triggers on vX.Y.Z-rc.N, but the version
|
|
9
|
+
// that should be SHOWN to operators is the final vX.Y.Z — otherwise a verified release
|
|
10
|
+
// leaves every dashboard claiming it is still an rc. This script asserts that the
|
|
11
|
+
// serving health endpoint's displayed version matches the policy declared in the
|
|
12
|
+
// authorization envelope, or records an explicit exception.
|
|
13
|
+
//
|
|
14
|
+
// Contract:
|
|
15
|
+
// version-assert serving --health <health.json> --settings <settings.json> --frontend-asset <asset.json> [--policy <policy>] [--deploy-trigger <topology>] [--version <v>] [--sha <sha>] [--trigger-tag <tag>] [--record-mismatch <reason>]
|
|
16
|
+
// Reads the health, settings, and frontend-asset JSON files, extracts each `version`
|
|
17
|
+
// display value, and checks every one against the policy. Prints JSON
|
|
18
|
+
// { decision, policy, displayed, expected, mismatch, failed }.
|
|
19
|
+
// final-semver --version <v> displayed version must equal the final semver vX.Y.Z
|
|
20
|
+
// trigger-tag --trigger-tag <t> displayed version must equal the attempt tag (e.g. vX.Y.Z-rc.N)
|
|
21
|
+
// short-sha --sha <sha> displayed version must match the short SHA
|
|
22
|
+
// --deploy-trigger rc-tag when --policy is omitted, resolves to final-semver (the rc-tag default).
|
|
23
|
+
// --record-mismatch <reason> on mismatch, record a declared exception and ACCEPT instead of refusing.
|
|
24
|
+
//
|
|
25
|
+
// exit 0 = ACCEPT — display version matches policy, or a mismatch was recorded with reason.
|
|
26
|
+
// exit 1 = REFUSE — display version does not match policy and no exception was recorded.
|
|
27
|
+
// exit 2 = usage / unreadable-input error.
|
|
28
|
+
|
|
29
|
+
import fs from 'node:fs'
|
|
30
|
+
import { shaMatches } from './candidate-identity.mjs'
|
|
31
|
+
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
32
|
+
|
|
33
|
+
export const DISPLAY_VERSION_POLICIES = ['final-semver', 'trigger-tag', 'short-sha']
|
|
34
|
+
|
|
35
|
+
// Health endpoints may render with or without a leading 'v'. Normalize so the policy
|
|
36
|
+
// comparison is about the version, not the rendering choice.
|
|
37
|
+
export function normalizeVersion(s) {
|
|
38
|
+
if (typeof s !== 'string') return ''
|
|
39
|
+
return s.trim().toLowerCase().replace(/^v/, '')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isSemver(s) {
|
|
43
|
+
return /^\d+\.\d+\.\d+(?:-[0-9a-z.-]+)?(?:\+[0-9a-z.-]+)?$/i.test(String(s ?? '').replace(/^v/, ''))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Compute the expected display string from the policy and the supplied identity inputs.
|
|
47
|
+
export function expectedDisplayVersion(policy, { version, triggerTag, sha } = {}) {
|
|
48
|
+
if (policy === 'final-semver') {
|
|
49
|
+
const v = normalizeVersion(version)
|
|
50
|
+
if (!isSemver(v)) return null
|
|
51
|
+
// Expected display is the release semver, with no prerelease segment.
|
|
52
|
+
const base = v.split('-')[0].split('+')[0]
|
|
53
|
+
return base
|
|
54
|
+
}
|
|
55
|
+
if (policy === 'trigger-tag') {
|
|
56
|
+
const t = normalizeVersion(triggerTag)
|
|
57
|
+
return t || null
|
|
58
|
+
}
|
|
59
|
+
if (policy === 'short-sha') {
|
|
60
|
+
const s = String(sha ?? '').trim().toLowerCase()
|
|
61
|
+
if (!s) return null
|
|
62
|
+
return s.slice(0, 7)
|
|
63
|
+
}
|
|
64
|
+
return null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Resolve an omitted policy against the deploy topology. rc-tag defaults to
|
|
68
|
+
// final-semver so a verified release does not leave operators staring at the
|
|
69
|
+
// attempt tag while the published tag is the final semver.
|
|
70
|
+
export function resolveDisplayVersionPolicy(policy, deployTrigger) {
|
|
71
|
+
if (policy) return { policy }
|
|
72
|
+
if (deployTrigger === 'rc-tag') return { policy: 'final-semver' }
|
|
73
|
+
return { error: 'e:missing-display-version-policy' }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Read the display version from a health JSON payload. Field aliases are intentionally
|
|
77
|
+
// narrow: the point is to read a real endpoint, not to accept anything version-shaped.
|
|
78
|
+
export function readDisplayVersion(health) {
|
|
79
|
+
if (!health || typeof health !== 'object') return { error: 'e:unreadable-health' }
|
|
80
|
+
const version = health.version ?? health.displayVersion ?? health.deployedVersion ?? health.DEPLOYED_VERSION
|
|
81
|
+
if (typeof version !== 'string' || version.trim().length === 0) {
|
|
82
|
+
return { error: 'e:no-display-version', missing: ['version'] }
|
|
83
|
+
}
|
|
84
|
+
return { version: version.trim() }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function evaluateDisplayVersion({ health, settings, frontendAsset, policy, version, triggerTag, sha, recordMismatch = null }) {
|
|
88
|
+
if (!DISPLAY_VERSION_POLICIES.includes(policy)) {
|
|
89
|
+
return { decision: 'refuse', phase: 'display-version', policy, failed: ['e:unknown-policy'], evidence: {} }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const sourceInputs = [
|
|
93
|
+
['health', health],
|
|
94
|
+
['settings', settings],
|
|
95
|
+
['frontend-asset', frontendAsset],
|
|
96
|
+
].filter(([, value]) => value !== undefined)
|
|
97
|
+
const displayedBySource = {}
|
|
98
|
+
for (const [source, input] of sourceInputs) {
|
|
99
|
+
const read = readDisplayVersion(input)
|
|
100
|
+
if (read.error) {
|
|
101
|
+
const error = source === 'health' ? read.error : `${read.error}:${source}`
|
|
102
|
+
return { decision: 'refuse', phase: 'display-version', policy, failed: [error], evidence: { missing: read.missing } }
|
|
103
|
+
}
|
|
104
|
+
displayedBySource[source] = read.version
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const displayed = sourceInputs.length === 1 ? displayedBySource.health : displayedBySource
|
|
108
|
+
const expected = expectedDisplayVersion(policy, { version, triggerTag, sha })
|
|
109
|
+
if (expected == null) {
|
|
110
|
+
return {
|
|
111
|
+
decision: 'refuse',
|
|
112
|
+
phase: 'display-version',
|
|
113
|
+
policy,
|
|
114
|
+
displayed,
|
|
115
|
+
failed: ['e:missing-expected-input'],
|
|
116
|
+
evidence: { policy, version, triggerTag, sha },
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const mismatchedSources = Object.entries(displayedBySource)
|
|
121
|
+
.filter(([, sourceDisplayed]) => (
|
|
122
|
+
policy === 'short-sha'
|
|
123
|
+
? !shaMatches(sourceDisplayed, expected)
|
|
124
|
+
: normalizeVersion(sourceDisplayed) !== normalizeVersion(expected)
|
|
125
|
+
))
|
|
126
|
+
.map(([source]) => source)
|
|
127
|
+
|
|
128
|
+
if (mismatchedSources.length === 0) {
|
|
129
|
+
return {
|
|
130
|
+
decision: 'accept',
|
|
131
|
+
phase: 'display-version',
|
|
132
|
+
policy,
|
|
133
|
+
displayed,
|
|
134
|
+
expected,
|
|
135
|
+
mismatch: null,
|
|
136
|
+
failed: [],
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (recordMismatch && String(recordMismatch).trim().length > 0) {
|
|
141
|
+
return {
|
|
142
|
+
decision: 'accept',
|
|
143
|
+
phase: 'display-version',
|
|
144
|
+
policy,
|
|
145
|
+
displayed,
|
|
146
|
+
expected,
|
|
147
|
+
mismatch: { recorded: true, reason: String(recordMismatch).trim(), sources: mismatchedSources },
|
|
148
|
+
failed: [],
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
decision: 'refuse',
|
|
154
|
+
phase: 'display-version',
|
|
155
|
+
policy,
|
|
156
|
+
displayed,
|
|
157
|
+
expected,
|
|
158
|
+
mismatch: null,
|
|
159
|
+
failed: mismatchedSources.map((source) => (
|
|
160
|
+
source === 'health' ? 'e:display-version-mismatch' : `e:display-version-mismatch:${source}`
|
|
161
|
+
)),
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const USAGE = `version-assert — display-version policy check for the release lane.
|
|
166
|
+
|
|
167
|
+
A release has an identity version (the immutable tag/SHA that names what is running,
|
|
168
|
+
owned by candidate-identity.mjs) and a display version (the string UI and /api/health
|
|
169
|
+
show). Under rc-tag topology the pipeline triggers on vX.Y.Z-rc.N, but the operator-
|
|
170
|
+
visible version should be vX.Y.Z unless the envelope deliberately says otherwise.
|
|
171
|
+
|
|
172
|
+
Usage:
|
|
173
|
+
version-assert serving --health <health.json> --settings <settings.json> --frontend-asset <asset.json> --policy <policy> [policy-inputs] [--record-mismatch <reason>]
|
|
174
|
+
version-assert serving --health <health.json> --settings <settings.json> --frontend-asset <asset.json> --deploy-trigger rc-tag [policy-inputs] [--record-mismatch <reason>]
|
|
175
|
+
|
|
176
|
+
All three JSON inputs must expose the operator-visible version under version,
|
|
177
|
+
displayVersion, deployedVersion, or DEPLOYED_VERSION.
|
|
178
|
+
|
|
179
|
+
Policies:
|
|
180
|
+
final-semver --version <v> displayed version must equal the final semver vX.Y.Z
|
|
181
|
+
trigger-tag --trigger-tag <t> displayed version must equal the attempt tag (e.g. vX.Y.Z-rc.N)
|
|
182
|
+
short-sha --sha <sha> displayed version must match the short SHA
|
|
183
|
+
|
|
184
|
+
--deploy-trigger <rc-tag|branch-push|final-tag|no-deploy>
|
|
185
|
+
when --policy is omitted, rc-tag resolves to final-semver;
|
|
186
|
+
other topologies must declare the policy explicitly.
|
|
187
|
+
--record-mismatch <reason> on mismatch, record a declared exception and ACCEPT instead of refusing.
|
|
188
|
+
|
|
189
|
+
Exit codes:
|
|
190
|
+
0 ACCEPT — display version matches policy, or a mismatch was recorded with reason
|
|
191
|
+
1 REFUSE — display version does not match policy and no exception was recorded
|
|
192
|
+
2 usage / unreadable-input error / missing policy on a topology with no default
|
|
193
|
+
|
|
194
|
+
Output: JSON { decision, phase, policy, displayed, expected, mismatch, failed }
|
|
195
|
+
|
|
196
|
+
Doctrine (display vs identity version, rc-tag default, Cloud Build strip pattern):
|
|
197
|
+
references/versioning.md.`
|
|
198
|
+
|
|
199
|
+
/** Known serving flags that take a value. Anything else is refused (exit 2). */
|
|
200
|
+
const KNOWN_VALUE_FLAGS = new Set([
|
|
201
|
+
'health',
|
|
202
|
+
'settings',
|
|
203
|
+
'frontend-asset',
|
|
204
|
+
'policy',
|
|
205
|
+
'version',
|
|
206
|
+
'sha',
|
|
207
|
+
'trigger-tag',
|
|
208
|
+
'deploy-trigger',
|
|
209
|
+
'record-mismatch',
|
|
210
|
+
])
|
|
211
|
+
|
|
212
|
+
function parseArgs(argv) {
|
|
213
|
+
const opts = {}
|
|
214
|
+
const positional = []
|
|
215
|
+
const unknown = []
|
|
216
|
+
const missing = []
|
|
217
|
+
for (let i = 0; i < argv.length; i++) {
|
|
218
|
+
const a = argv[i]
|
|
219
|
+
if (a === '--help' || a === '-h') {
|
|
220
|
+
opts.help = true
|
|
221
|
+
continue
|
|
222
|
+
}
|
|
223
|
+
if (a.startsWith('--')) {
|
|
224
|
+
const key = a.slice(2)
|
|
225
|
+
if (!KNOWN_VALUE_FLAGS.has(key)) {
|
|
226
|
+
unknown.push(a)
|
|
227
|
+
// If the next token looks like a value (not a flag), consume it so it is not
|
|
228
|
+
// re-classified as a bare positional — the flag itself is the error.
|
|
229
|
+
const next = argv[i + 1]
|
|
230
|
+
if (next !== undefined && !next.startsWith('-')) i++
|
|
231
|
+
continue
|
|
232
|
+
}
|
|
233
|
+
const next = argv[i + 1]
|
|
234
|
+
if (next === undefined || next.startsWith('-')) {
|
|
235
|
+
if (next !== undefined && next.startsWith('-')) {
|
|
236
|
+
// leave next token for the next iteration (flag/unknown)
|
|
237
|
+
}
|
|
238
|
+
missing.push(a)
|
|
239
|
+
continue
|
|
240
|
+
}
|
|
241
|
+
opts[key] = next
|
|
242
|
+
i++
|
|
243
|
+
continue
|
|
244
|
+
}
|
|
245
|
+
positional.push(a)
|
|
246
|
+
}
|
|
247
|
+
return { opts, positional, unknown, missing }
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function readJson(file, what) {
|
|
251
|
+
if (!file) return { error: `usage: --${what} <file> is required` }
|
|
252
|
+
let raw
|
|
253
|
+
try {
|
|
254
|
+
raw = fs.readFileSync(file, 'utf8')
|
|
255
|
+
} catch {
|
|
256
|
+
return { error: `${what} not readable: ${file}` }
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
return { value: JSON.parse(raw) }
|
|
260
|
+
} catch {
|
|
261
|
+
return { error: `${what} is not valid JSON: ${file}` }
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function main(argv) {
|
|
266
|
+
const { opts, positional, unknown, missing } = parseArgs(argv)
|
|
267
|
+
const cmd = positional[0]
|
|
268
|
+
const extraPositionals = positional.slice(1)
|
|
269
|
+
|
|
270
|
+
if (opts.help || cmd === 'help') {
|
|
271
|
+
console.log(USAGE)
|
|
272
|
+
return 0
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (unknown.length > 0) {
|
|
276
|
+
console.error(`version-assert: unknown argument(s): ${unknown.join(', ')}`)
|
|
277
|
+
return 2
|
|
278
|
+
}
|
|
279
|
+
if (missing.length > 0) {
|
|
280
|
+
console.error(`version-assert: missing or invalid value for: ${missing.join(', ')}`)
|
|
281
|
+
return 2
|
|
282
|
+
}
|
|
283
|
+
if (extraPositionals.length > 0) {
|
|
284
|
+
console.error(`version-assert: unexpected positional argument(s): ${extraPositionals.join(', ')}`)
|
|
285
|
+
return 2
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (cmd !== 'serving') {
|
|
289
|
+
const what = cmd ? `unknown command "${cmd}"` : 'no subcommand given'
|
|
290
|
+
console.error(`version-assert: ${what}. Use serving (see --help).`)
|
|
291
|
+
return 2
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const health = readJson(opts.health, 'health')
|
|
295
|
+
const settings = readJson(opts.settings, 'settings')
|
|
296
|
+
const frontendAsset = readJson(opts['frontend-asset'], 'frontend-asset')
|
|
297
|
+
for (const source of [health, settings, frontendAsset]) {
|
|
298
|
+
if (source.error) {
|
|
299
|
+
console.error(`version-assert: ${source.error}`)
|
|
300
|
+
return 2
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!opts.policy && !opts['deploy-trigger']) {
|
|
305
|
+
console.error('version-assert: serving requires --policy <final-semver|trigger-tag|short-sha>, or --deploy-trigger <topology> to resolve a default')
|
|
306
|
+
return 2
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Explicit --policy must be a known policy before we evaluate health. An invalid
|
|
310
|
+
// policy is a usage error (exit 2), not a display-version mismatch (exit 1).
|
|
311
|
+
if (opts.policy && !DISPLAY_VERSION_POLICIES.includes(opts.policy)) {
|
|
312
|
+
console.error(`version-assert: unknown policy "${opts.policy}". Use one of: ${DISPLAY_VERSION_POLICIES.join(', ')}`)
|
|
313
|
+
return 2
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const resolved = resolveDisplayVersionPolicy(opts.policy, opts['deploy-trigger'])
|
|
317
|
+
if (resolved.error) {
|
|
318
|
+
console.error(`version-assert: ${resolved.error}: --policy is required when --deploy-trigger is not rc-tag`)
|
|
319
|
+
return 2
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const result = evaluateDisplayVersion({
|
|
323
|
+
health: health.value,
|
|
324
|
+
settings: settings.value,
|
|
325
|
+
frontendAsset: frontendAsset.value,
|
|
326
|
+
policy: resolved.policy,
|
|
327
|
+
version: opts.version ?? null,
|
|
328
|
+
triggerTag: opts['trigger-tag'] ?? null,
|
|
329
|
+
sha: opts.sha ?? null,
|
|
330
|
+
recordMismatch: opts['record-mismatch'] ?? null,
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
console.log(JSON.stringify(result, null, 2))
|
|
334
|
+
return result.decision === 'accept' ? 0 : 1
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (isMainModule(import.meta.url)) {
|
|
338
|
+
process.exit(main(process.argv.slice(2)))
|
|
339
|
+
}
|