@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,282 @@
|
|
|
1
|
+
# E2E Tests — GitHub Actions Workflow
|
|
2
|
+
#
|
|
3
|
+
# Triggered by Cloud Build via repository_dispatch after successful deployment.
|
|
4
|
+
# Posts structured results as PR comment + sets commit status.
|
|
5
|
+
#
|
|
6
|
+
# To use: copy to .github/workflows/e2e.yml and customize marked sections.
|
|
7
|
+
|
|
8
|
+
name: E2E Tests
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
repository_dispatch:
|
|
12
|
+
types: [deploy-complete]
|
|
13
|
+
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
inputs:
|
|
16
|
+
environment:
|
|
17
|
+
description: 'Environment (dev/prod)'
|
|
18
|
+
required: true
|
|
19
|
+
type: choice
|
|
20
|
+
options:
|
|
21
|
+
- dev
|
|
22
|
+
- prod
|
|
23
|
+
service_url:
|
|
24
|
+
description: 'Deployed service URL'
|
|
25
|
+
required: true
|
|
26
|
+
type: string
|
|
27
|
+
sha:
|
|
28
|
+
description: 'Git commit SHA'
|
|
29
|
+
required: false
|
|
30
|
+
type: string
|
|
31
|
+
pr_number:
|
|
32
|
+
description: 'PR number to comment on'
|
|
33
|
+
required: false
|
|
34
|
+
type: string
|
|
35
|
+
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
statuses: write
|
|
39
|
+
pull-requests: write
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
e2e:
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
if: github.event.client_payload.commit != '' || github.event_name == 'workflow_dispatch'
|
|
45
|
+
timeout-minutes: 15
|
|
46
|
+
# DOCKER-PREFERRED: run in the official pinned Playwright container — browsers and
|
|
47
|
+
# OS deps ship in the image, so there is no per-run browser install. Keep the tag
|
|
48
|
+
# aligned with the repo's @playwright/test version and with ci-gates.github.yml.
|
|
49
|
+
# Alternative (plain runner): drop `container:` and add a step
|
|
50
|
+
# `npx playwright install --with-deps chromium` after the dependency install.
|
|
51
|
+
container:
|
|
52
|
+
image: mcr.microsoft.com/playwright:v1.61.0-noble
|
|
53
|
+
options: --ipc=host
|
|
54
|
+
|
|
55
|
+
env:
|
|
56
|
+
ENV: ${{ github.event.client_payload.env || inputs.environment }}
|
|
57
|
+
SERVICE_URL: ${{ github.event.client_payload.service_url || inputs.service_url }}
|
|
58
|
+
SHA: ${{ github.event.client_payload.commit || inputs.sha || github.sha }}
|
|
59
|
+
PR_NUMBER: ${{ github.event.client_payload.pr_number || inputs.pr_number }}
|
|
60
|
+
|
|
61
|
+
steps:
|
|
62
|
+
- name: Determine checkout ref
|
|
63
|
+
id: ref
|
|
64
|
+
run: |
|
|
65
|
+
if [[ "$ENV" == "dev" ]]; then
|
|
66
|
+
echo "ref=dev" >> $GITHUB_OUTPUT
|
|
67
|
+
else
|
|
68
|
+
echo "ref=$SHA" >> $GITHUB_OUTPUT
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
- name: Checkout
|
|
72
|
+
uses: actions/checkout@v4
|
|
73
|
+
with:
|
|
74
|
+
ref: ${{ steps.ref.outputs.ref }}
|
|
75
|
+
fetch-depth: 0
|
|
76
|
+
|
|
77
|
+
# ── CUSTOMIZE: Node version and package manager ──
|
|
78
|
+
- name: Setup Node
|
|
79
|
+
uses: actions/setup-node@v4
|
|
80
|
+
with:
|
|
81
|
+
node-version: 22
|
|
82
|
+
cache: npm
|
|
83
|
+
cache-dependency-path: package-lock.json
|
|
84
|
+
|
|
85
|
+
- name: Install dependencies
|
|
86
|
+
run: npm ci
|
|
87
|
+
# No browser install: the job container ships the browsers. If the image tag
|
|
88
|
+
# and @playwright/test versions can't be aligned, add
|
|
89
|
+
# `npx playwright install chromium` here (prefer aligning instead).
|
|
90
|
+
|
|
91
|
+
- name: Wait for service readiness
|
|
92
|
+
run: |
|
|
93
|
+
echo "Waiting for $SERVICE_URL to be ready..."
|
|
94
|
+
for i in $(seq 1 30); do
|
|
95
|
+
if curl -sf -o /dev/null "$SERVICE_URL"; then
|
|
96
|
+
echo "Service is ready"
|
|
97
|
+
exit 0
|
|
98
|
+
fi
|
|
99
|
+
echo "Attempt $i/30 — retrying in 10s..."
|
|
100
|
+
sleep 10
|
|
101
|
+
done
|
|
102
|
+
echo "Service not ready after 5 minutes"
|
|
103
|
+
exit 1
|
|
104
|
+
|
|
105
|
+
# ── CUSTOMIZE: test command and env vars ──
|
|
106
|
+
- name: Run E2E tests
|
|
107
|
+
id: run_tests
|
|
108
|
+
run: npm run test:e2e
|
|
109
|
+
continue-on-error: true # Phase 1: non-blocking. Remove for Phase 2.
|
|
110
|
+
env:
|
|
111
|
+
BASE_URL: ${{ env.SERVICE_URL }}
|
|
112
|
+
CI: true
|
|
113
|
+
# Add repo-specific secrets:
|
|
114
|
+
# E2E_DASHBOARD_TOKEN: ${{ secrets.E2E_DASHBOARD_TOKEN }}
|
|
115
|
+
|
|
116
|
+
- name: Post E2E results to PR
|
|
117
|
+
if: always() && env.PR_NUMBER != ''
|
|
118
|
+
uses: actions/github-script@v7
|
|
119
|
+
with:
|
|
120
|
+
script: |
|
|
121
|
+
const fs = require('fs');
|
|
122
|
+
|
|
123
|
+
// Parse Playwright JSON results
|
|
124
|
+
let results = { total: 0, passed: 0, failed: 0, skipped: 0, duration: 0, failures: [] };
|
|
125
|
+
try {
|
|
126
|
+
const raw = JSON.parse(fs.readFileSync('e2e-results.json', 'utf8'));
|
|
127
|
+
const suites = raw.suites || [];
|
|
128
|
+
function walk(suite) {
|
|
129
|
+
for (const spec of (suite.specs || [])) {
|
|
130
|
+
for (const test of (spec.tests || [])) {
|
|
131
|
+
results.total++;
|
|
132
|
+
const status = test.results?.[test.results.length - 1]?.status || 'unknown';
|
|
133
|
+
if (status === 'passed' || status === 'expected') results.passed++;
|
|
134
|
+
else if (status === 'skipped') results.skipped++;
|
|
135
|
+
else {
|
|
136
|
+
results.failed++;
|
|
137
|
+
const err = test.results?.[test.results.length - 1]?.error?.message || 'Unknown error';
|
|
138
|
+
results.failures.push({ title: spec.title + ' › ' + test.title, error: err.slice(0, 200) });
|
|
139
|
+
}
|
|
140
|
+
results.duration += (test.results?.[test.results.length - 1]?.duration || 0);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const child of (suite.suites || [])) walk(child);
|
|
144
|
+
}
|
|
145
|
+
suites.forEach(walk);
|
|
146
|
+
} catch (e) {
|
|
147
|
+
console.log('Could not parse e2e-results.json:', e.message);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Parse route manifest for coverage
|
|
151
|
+
let coverage = { covered: 0, total: 0 };
|
|
152
|
+
try {
|
|
153
|
+
const manifest = JSON.parse(fs.readFileSync('e2e/route-manifest.json', 'utf8'));
|
|
154
|
+
const routes = manifest.routes || manifest.endpoints || [];
|
|
155
|
+
coverage.total = routes.length;
|
|
156
|
+
coverage.covered = routes.filter(r => (r.specs || []).length > 0).length;
|
|
157
|
+
} catch (e) {
|
|
158
|
+
console.log('No route manifest found:', e.message);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const icon = results.failed > 0 ? '❌' : '✅';
|
|
162
|
+
const status = results.failed > 0 ? 'FAILED' : 'PASSED';
|
|
163
|
+
const durationStr = `${Math.floor(results.duration / 60000)}m ${Math.floor((results.duration % 60000) / 1000)}s`;
|
|
164
|
+
const coverageStr = coverage.total > 0
|
|
165
|
+
? `${Math.round(coverage.covered / coverage.total * 100)}% (${coverage.covered}/${coverage.total})`
|
|
166
|
+
: 'N/A (no manifest)';
|
|
167
|
+
|
|
168
|
+
let body = `## 🧪 E2E ${status} — ${process.env.ENV}\n\n`;
|
|
169
|
+
body += `| Metric | Value |\n|--------|-------|\n`;
|
|
170
|
+
body += `| Total | ${results.total} |\n`;
|
|
171
|
+
body += `| ✅ Passed | ${results.passed} |\n`;
|
|
172
|
+
body += `| ❌ Failed | ${results.failed} |\n`;
|
|
173
|
+
body += `| ⏭️ Skipped | ${results.skipped} |\n`;
|
|
174
|
+
body += `| ⏱️ Duration | ${durationStr} |\n`;
|
|
175
|
+
body += `| 📊 Route coverage | ${coverageStr} |\n\n`;
|
|
176
|
+
|
|
177
|
+
if (results.failures.length > 0) {
|
|
178
|
+
body += `<details><summary>❌ Failed (${results.failures.length})</summary>\n\n`;
|
|
179
|
+
for (const f of results.failures) {
|
|
180
|
+
body += `- \`${f.title}\` — ${f.error}\n`;
|
|
181
|
+
}
|
|
182
|
+
body += `\n</details>\n\n`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
body += `> Commit: ${process.env.SHA?.slice(0, 7)} | [Workflow run](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID})`;
|
|
186
|
+
|
|
187
|
+
// Post or update PR comment
|
|
188
|
+
const prNumber = parseInt(process.env.PR_NUMBER);
|
|
189
|
+
if (prNumber) {
|
|
190
|
+
const { data: comments } = await github.rest.issues.listComments({
|
|
191
|
+
owner: context.repo.owner,
|
|
192
|
+
repo: context.repo.repo,
|
|
193
|
+
issue_number: prNumber,
|
|
194
|
+
});
|
|
195
|
+
const existing = comments.find(c => c.body?.startsWith('## 🧪 E2E'));
|
|
196
|
+
if (existing) {
|
|
197
|
+
await github.rest.issues.updateComment({
|
|
198
|
+
owner: context.repo.owner,
|
|
199
|
+
repo: context.repo.repo,
|
|
200
|
+
comment_id: existing.id,
|
|
201
|
+
body,
|
|
202
|
+
});
|
|
203
|
+
} else {
|
|
204
|
+
await github.rest.issues.createComment({
|
|
205
|
+
owner: context.repo.owner,
|
|
206
|
+
repo: context.repo.repo,
|
|
207
|
+
issue_number: prNumber,
|
|
208
|
+
body,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
- name: Set commit status
|
|
214
|
+
if: always()
|
|
215
|
+
uses: actions/github-script@v7
|
|
216
|
+
with:
|
|
217
|
+
script: |
|
|
218
|
+
const state = '${{ steps.run_tests.outcome }}' === 'success' ? 'success' : 'failure';
|
|
219
|
+
const env = '${{ env.ENV }}';
|
|
220
|
+
await github.rest.repos.createCommitStatus({
|
|
221
|
+
owner: context.repo.owner,
|
|
222
|
+
repo: context.repo.repo,
|
|
223
|
+
sha: '${{ env.SHA }}',
|
|
224
|
+
state,
|
|
225
|
+
target_url: `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`,
|
|
226
|
+
description: state === 'success' ? `E2E ${env}: all tests passed` : `E2E ${env}: tests failed`,
|
|
227
|
+
context: 'e2e',
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
- name: Report to Discord
|
|
231
|
+
if: always() && github.event_name == 'repository_dispatch'
|
|
232
|
+
env:
|
|
233
|
+
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
234
|
+
run: |
|
|
235
|
+
if [[ -z "$DISCORD_WEBHOOK_URL" ]]; then
|
|
236
|
+
echo "DISCORD_WEBHOOK_URL not set — skipping"
|
|
237
|
+
exit 0
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
OUTCOME="${{ steps.run_tests.outcome }}"
|
|
241
|
+
RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
|
|
242
|
+
COMMIT_URL="https://github.com/${GITHUB_REPOSITORY}/commit/${SHA}"
|
|
243
|
+
REPO_NAME="${GITHUB_REPOSITORY#*/}"
|
|
244
|
+
|
|
245
|
+
if [[ "$OUTCOME" == "success" ]]; then
|
|
246
|
+
ICON="✅"; STATUS="PASSED"; COLOR=3066993
|
|
247
|
+
else
|
|
248
|
+
ICON="❌"; STATUS="FAILED"; COLOR=15158332
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
# Built with node (always present in the Playwright image), not jq (not installed there).
|
|
252
|
+
PAYLOAD=$(node -e '
|
|
253
|
+
const [icon, status, env, commit, commitUrl, serviceUrl, runUrl, repo, color] = process.argv.slice(1);
|
|
254
|
+
console.log(JSON.stringify({ embeds: [{
|
|
255
|
+
title: `${icon} E2E ${status} — ${repo} (${env})`,
|
|
256
|
+
url: runUrl, color: Number(color),
|
|
257
|
+
fields: [
|
|
258
|
+
{ name: "Commit", value: `[${commit}](${commitUrl})`, inline: true },
|
|
259
|
+
{ name: "Environment", value: env, inline: true },
|
|
260
|
+
{ name: "Service", value: serviceUrl, inline: false },
|
|
261
|
+
],
|
|
262
|
+
footer: { text: `${repo} CI` },
|
|
263
|
+
}]}));
|
|
264
|
+
' "$ICON" "$STATUS" "$ENV" "${SHA:0:7}" "$COMMIT_URL" "$SERVICE_URL" "$RUN_URL" "$REPO_NAME" "$COLOR")
|
|
265
|
+
|
|
266
|
+
curl -sf -X POST -H "Content-Type: application/json" -d "$PAYLOAD" "$DISCORD_WEBHOOK_URL" || true
|
|
267
|
+
|
|
268
|
+
# Phase 2: uncomment to make E2E blocking
|
|
269
|
+
# - name: Fail if tests failed
|
|
270
|
+
# if: steps.run_tests.outcome == 'failure'
|
|
271
|
+
# run: exit 1
|
|
272
|
+
|
|
273
|
+
- name: Upload artifacts on failure
|
|
274
|
+
if: failure() || steps.run_tests.outcome == 'failure'
|
|
275
|
+
uses: actions/upload-artifact@v4
|
|
276
|
+
with:
|
|
277
|
+
name: e2e-results-${{ github.run_id }}
|
|
278
|
+
path: |
|
|
279
|
+
test-results/
|
|
280
|
+
playwright-report/
|
|
281
|
+
e2e-results.json
|
|
282
|
+
retention-days: 7
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Auth Flows (login, signup, forgot-password)
|
|
2
|
+
|
|
3
|
+
> Read when: testing authentication surfaces — login, signup, password reset, magic link, OAuth callback. These span three tiers and cross an external boundary (email/SMS), which is why they are the most commonly mis-tested feature in a codebase.
|
|
4
|
+
|
|
5
|
+
Auth is special on two counts, both easy to get wrong:
|
|
6
|
+
|
|
7
|
+
1. **It spans all three tiers** — the same feature owes a render-health test, functional negatives, *and* a real journey. Confusing them produces a test that looks like a journey but proves nothing.
|
|
8
|
+
2. **It crosses an external boundary you don't own** — reset/verification email. The token round-trip is the whole point, and must be proven without calling a live provider.
|
|
9
|
+
|
|
10
|
+
## The anti-pattern this exists to kill
|
|
11
|
+
|
|
12
|
+
A test tagged `@level journey` that only checks *a form element is visible*:
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
// ✗ A smoke test wearing a journey label. Proves nothing; can't fail the way the
|
|
16
|
+
// name promises. When the form fails to render at all (e.g. a seed/cache race),
|
|
17
|
+
// the disjunction just goes falsy with no specific signal.
|
|
18
|
+
test('Customer login page loads and renders login form', async ({ page }) => {
|
|
19
|
+
const response = await page.goto(`/${MERCHANT}/account/login`);
|
|
20
|
+
expect(response?.ok()).toBeTruthy();
|
|
21
|
+
const hasEmail = await page.getByLabel(/email/i).isVisible().catch(() => false);
|
|
22
|
+
const hasPassword = await page.getByLabel(/password/i).isVisible().catch(() => false);
|
|
23
|
+
const hasButton = await page.getByRole('button', { name: /login/i }).isVisible().catch(() => false);
|
|
24
|
+
expect(hasEmail || hasPassword || hasButton).toBeTruthy(); // weak disjunction
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Two syntactic tells — `.catch(() => false)` (swallows a locator throw, defeating web-first retry) and `expect(a || b || c).toBeTruthy()` (passes if *any* branch holds) — are flagged as leads by `review-pr`'s `scan-diff.mjs` (`swallowed-assertion`, `weak-assertion`). Writing them means a vacuous check, not a journey — replace with a real journey below.
|
|
29
|
+
|
|
30
|
+
## Login
|
|
31
|
+
|
|
32
|
+
Separate two jobs that get conflated:
|
|
33
|
+
|
|
34
|
+
### 1. Proving the login flow itself
|
|
35
|
+
|
|
36
|
+
A Tier-3 journey drives credentials to an **authenticated outcome** (not form presence), backed by Tier-2 functional negatives where most real bugs live.
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// @covers /[merchant]/account/login
|
|
40
|
+
// @level journey
|
|
41
|
+
test('customer logs in and lands authenticated', async ({ page }) => {
|
|
42
|
+
const user = await factory.customer({ password: 'Correct-horse-9' }); // seed real state
|
|
43
|
+
await page.goto(`/${MERCHANT}/account/login`);
|
|
44
|
+
await page.getByLabel(/email/i).fill(user.email);
|
|
45
|
+
await page.getByLabel(/password/i).fill('Correct-horse-9');
|
|
46
|
+
await page.getByRole('button', { name: /log in|sign in/i }).click();
|
|
47
|
+
// Assert a CONCRETE post-login signal — redirect + authed-only content:
|
|
48
|
+
await expect(page).toHaveURL(new RegExp(`/${MERCHANT}/account$`));
|
|
49
|
+
await expect(page.getByRole('heading', { name: /my account/i })).toBeVisible();
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Back it with **Tier-2 functional negatives** where most real bugs live — e.g. `@level functional` "wrong password shows error and stays unauthenticated": fill a bad password, assert the error text is visible *and* `toHaveURL(/login/)` (did NOT get in).
|
|
54
|
+
|
|
55
|
+
Rules:
|
|
56
|
+
|
|
57
|
+
- **Seed the user** with a factory/seed script — never depend on ambient data. Missing state is the test's *arrange* step, never a skip reason ([test-skipping.md](test-skipping.md)).
|
|
58
|
+
- **Name every seeded account with the `e2e-` prefix** (see [the naming convention](#the-e2e--account-naming-convention) below) — the factory should emit it by default, not leave it to each call site.
|
|
59
|
+
- **Assert authenticated state**, not form presence: a redirect to an authed route, an authed-only element, or the session cookie. "A button is visible" is Tier-1 render-health.
|
|
60
|
+
- **Don't mock first-party auth endpoints** in the journey — real DB, real session. Intercepting `/api/auth/*` makes it `Over-mocked` (`ensure-coverage` → `references/depth/mock-policy.md`).
|
|
61
|
+
|
|
62
|
+
### 2. Login as a precondition for other journeys
|
|
63
|
+
|
|
64
|
+
Don't re-type credentials in every test. Log in once and reuse the session via a shared auth fixture (`storageState`) or `E2E_AUTH_BYPASS`; other journeys start already-authed and only the login spec proves login itself. This is the "Seed auth" path in [test-skipping.md](test-skipping.md) — the cure for "no session" is to seed it, never skip.
|
|
65
|
+
|
|
66
|
+
## A session fixture asserts its own preconditions, and throws
|
|
67
|
+
|
|
68
|
+
A minted session the app then rejects is the worst failure mode in this file: the request fails closed, nothing renders, and the spec dies on an **undiagnostic timeout**. Nothing in the diff looks wrong — there is no assertion against a 404 to spot, because the assertion was never reached. The lane goes on reporting green-or-flaky while proving nothing.
|
|
69
|
+
|
|
70
|
+
The recurring cause is a value the **app and the harness each default independently**: a tenant/org slug, an auth secret, a base URL, an API version. They agree until one side's default moves.
|
|
71
|
+
|
|
72
|
+
**Rules, in the order they close the hole:**
|
|
73
|
+
|
|
74
|
+
- **One owner per shared value.** A single constant mirrors the app's own resolver (`getRequiredOrgSlug()`, not a re-typed `?? "skyee"`), and the Playwright config sets the env var *from that constant* — in `webServer.env` **and** any inline command string, which drift apart otherwise.
|
|
75
|
+
- **Make the wrong value inexpressible.** Identities come from constructor functions (`authorizedIdentity()`, `denyOnlyIdentity()`) that fill the shared value themselves. If no call site can state it, no call site can state it wrongly — a rule prose cannot enforce, structure can.
|
|
76
|
+
- **Assert at mint time and throw with a diagnosis.** The fixture checks the value as it mints and, on mismatch, throws naming the identity id, *both* values, and the owning constant's file path. A loud throw is the entire difference between a five-minute fix and a five-round one; a timeout names nothing.
|
|
77
|
+
- **Close the vacuous-pass hole in deny fixtures.** A fixture that deliberately uses a wrong value opts in explicitly (`{ allowWrongOrg: true }`), and that flag is **rejected on a right-value identity** — otherwise a denial assertion passes for the wrong reason, and the negative test is as vacuous as the positive one.
|
|
78
|
+
|
|
79
|
+
The first two rules are what make this stick: a value no call site can express is a value no call site can get wrong. (Named incident: `skyee-ai-risk` #1144 — a tenant slug defaulted independently in four files left authorized journeys minting sessions the app rejected, so the endpoint 403'd before any row rendered and those lanes **stayed green for five review rounds** while exercising nothing. Fixed in `f97f879e`, whose message records why structure rather than a fourth sentence: *"prose had already failed at this twice in these exact files."*)
|
|
80
|
+
|
|
81
|
+
## The `e2e-*` account naming convention
|
|
82
|
+
|
|
83
|
+
Every account, email, and tenant a test seeds carries an **`e2e-` prefix**:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
account e2e-<role>-<runid>@<test-domain> e2e-customer-x7f2@example.test
|
|
87
|
+
tenant e2e-<name> e2e-synthetic
|
|
88
|
+
username e2e-<role>-<runid> e2e-admin-x7f2
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Bake it into the **factory default** — `factory.customer()` emits a conforming email without the call site asking — so the convention can't erode one test at a time. Why a naming convention and not just "use seeded data":
|
|
92
|
+
|
|
93
|
+
- **Identifiable at a glance.** In a DB dump, log line, admin UI, or bug report, `e2e-` says "test artifact" with no lookup.
|
|
94
|
+
- **Bulk-cleanable.** `DELETE FROM users WHERE email LIKE 'e2e-%'` is a safe janitor job; without the prefix, cleanup needs a bookkeeping table that drifts.
|
|
95
|
+
- **Mechanically guarded.** The app/monitoring can special-case the prefix (exclude from analytics/emails/billing), and `smoke`'s deployed-target rule builds on it: a mutating golden path off-`local` runs only against a declared synthetic tenant, and `smoke.mjs validate` warns when a tenant is not `e2e-`-prefixed. (Production is governed by the stricter **read-only production profile** (`prod-preview`/`prod-active`), where a tenant grants nothing — this convention is what makes *staging* runs safe, not prod ones.)
|
|
96
|
+
- **Unambiguous in shared environments.** On staging/preview where real-ish data coexists, the prefix keeps a cleanup script or mutating smoke run from touching anything live.
|
|
97
|
+
|
|
98
|
+
Use a **run-scoped suffix** (a short random id per run) so parallel workers and repeated CI runs never collide on unique columns — never a fixed `e2e-test@example.com` singleton, which serializes workers and flakes on re-runs.
|
|
99
|
+
|
|
100
|
+
## Forgot password — the email boundary is the whole flow
|
|
101
|
+
|
|
102
|
+
Email/SMS is an **external boundary you don't own** → *real internals, faked externals, nothing in between* (`mock-policy.md`).
|
|
103
|
+
|
|
104
|
+
- ✗ Don't call a live email provider in CI (non-deterministic, flaky, leaks keys).
|
|
105
|
+
- ✗ Don't skip it because "email is external" — the exact rationalization the no-skip policy forbids; **sandbox the boundary** instead.
|
|
106
|
+
- ✗ Don't assert "the form renders" and call it a journey.
|
|
107
|
+
|
|
108
|
+
✓ Fake the mail adapter so the app writes to a test outbox, then drive the **full durable-state** round-trip:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// @covers /[merchant]/account/forgot-password
|
|
112
|
+
// @level journey
|
|
113
|
+
test('reset password end to end', async ({ page }) => {
|
|
114
|
+
const user = await factory.customer({ password: 'old-pass-1' });
|
|
115
|
+
|
|
116
|
+
// 1. Request reset
|
|
117
|
+
await page.goto(`/${MERCHANT}/account/forgot-password`);
|
|
118
|
+
await page.getByLabel(/email/i).fill(user.email);
|
|
119
|
+
await page.getByRole('button', { name: /reset|send/i }).click();
|
|
120
|
+
await expect(page.getByText(/check your (email|inbox)/i)).toBeVisible();
|
|
121
|
+
|
|
122
|
+
// 2. Read the token from the FAKE outbox (or directly from the DB token table —
|
|
123
|
+
// both are real internals; live SMTP is the banned outward reach)
|
|
124
|
+
const link = await fakeMail.lastResetLink(user.email);
|
|
125
|
+
|
|
126
|
+
// 3. Complete the reset
|
|
127
|
+
await page.goto(link);
|
|
128
|
+
await page.getByLabel(/new password/i).fill('new-pass-2');
|
|
129
|
+
await page.getByRole('button', { name: /set|update/i }).click();
|
|
130
|
+
|
|
131
|
+
// 4. Prove the durable change: new password works
|
|
132
|
+
await login(page, { email: user.email, password: 'new-pass-2' });
|
|
133
|
+
await expect(page.getByRole('heading', { name: /my account/i })).toBeVisible();
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- Reading the token from the **fake outbox** also proves the send wiring; reading it from the **DB token table** proves only the token logic. Either is real-internal and valid — pick based on whether email dispatch is part of the contract you're proving.
|
|
138
|
+
- Cover the negatives as Tier-2 functional against the real DB: **expired token**, **already-used token**, **unknown email** (should not reveal account existence).
|
|
139
|
+
|
|
140
|
+
## CI wiring
|
|
141
|
+
|
|
142
|
+
| Concern | Practice |
|
|
143
|
+
|---|---|
|
|
144
|
+
| **Where they run** | The **blocking** E2E lane. Once email is faked, both flows are fully hermetic — *no quarantine*. Quarantine is only for genuinely un-sandboxable externals (e.g. a real-provider deliverability check), which is a separate secret-gated test with a dedicated mailbox ([ci-integration.md](../ci-integration.md) → Quarantine lane). |
|
|
145
|
+
| **Seed timing** | Migrate → seed → **start servers** → run. Seed the user/tenant *before* servers boot, or bypass caches for E2E (e.g. an `ALLOW_E2E_ROUTES` flag). A freshly-seeded row a cached read can't yet see is a classic auth-journey flake. |
|
|
146
|
+
| **Email adapter** | Inject a fake/in-memory mail adapter via env in CI; never real keys, never a live provider. |
|
|
147
|
+
| **Presentation** | The presentation sweep ([presentation-sweep.md](../presentation-sweep.md)) catches "the form didn't render at all" — the bug a green functional run sails past. It is a **separate gate**; the journey assertion is not a substitute. |
|
|
148
|
+
| **Getting to green** | Never weaken assertions or skip to pass — `review-pr`'s manufactured-green check and the `weak-assertion`/`swallowed-assertion` leads flag exactly that. |
|
|
149
|
+
|
|
150
|
+
## Checklist
|
|
151
|
+
|
|
152
|
+
- [ ] Login journey asserts **authenticated state** (redirect / authed element / session cookie), not form presence.
|
|
153
|
+
- [ ] User/session **seeded** before server boot; caches bypassed for E2E.
|
|
154
|
+
- [ ] Values the app and harness share (tenant/org, secret, base URL) have **one owner**, and the session fixture **throws** on mismatch rather than letting the lane time out.
|
|
155
|
+
- [ ] Seeded accounts/tenants carry the **`e2e-` prefix** with a run-scoped suffix (factory default, not per-call-site).
|
|
156
|
+
- [ ] Forgot-password drives the **full reset → new-password-works** loop with a **faked mail boundary**.
|
|
157
|
+
- [ ] Negatives (wrong password, expired/used token, unknown email) are **Tier-2 functional** against the real DB.
|
|
158
|
+
- [ ] No first-party `page.route`/MSW interception in the journeys; no `.catch(() => false)`; no disjunctive `toBeTruthy()`.
|
|
159
|
+
- [ ] Everything in the **blocking lane**; no skips; presentation sweep is a separate job.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Playwright Config
|
|
2
|
+
|
|
3
|
+
```typescript
|
|
4
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
testDir: './e2e',
|
|
8
|
+
// Timeout convention: 15s for any single action/assertion — a real state change
|
|
9
|
+
// arrives in seconds; anything slower is a bug the test should surface, not wait out.
|
|
10
|
+
// The per-test ceiling stays higher (a journey is many 15s-bounded steps).
|
|
11
|
+
timeout: 60_000,
|
|
12
|
+
expect: { timeout: 15_000 },
|
|
13
|
+
fullyParallel: true,
|
|
14
|
+
forbidOnly: !!process.env.CI,
|
|
15
|
+
retries: process.env.CI ? 2 : 0,
|
|
16
|
+
// Parallel in CI too — wall clock ≈ slowest spec, not the sum. E2E_WORKERS is the
|
|
17
|
+
// CI-side knob (see ../ci-playwright-container.md → Resource Envelope and Workers);
|
|
18
|
+
// 4 fits a 4 CPU / 16 GB job. Drop to 2 only on OOM/browser crashes.
|
|
19
|
+
workers: process.env.CI ? Number(process.env.E2E_WORKERS) || 4 : undefined,
|
|
20
|
+
reporter: process.env.CI
|
|
21
|
+
? [['github'], ['json', { outputFile: 'e2e-results.json' }], ['html', { open: 'never' }]]
|
|
22
|
+
: [['list'], ['html', { open: 'never' }]],
|
|
23
|
+
use: {
|
|
24
|
+
baseURL: process.env.BASE_URL || 'http://localhost:3000',
|
|
25
|
+
actionTimeout: 15_000,
|
|
26
|
+
navigationTimeout: 15_000,
|
|
27
|
+
trace: 'retain-on-failure',
|
|
28
|
+
screenshot: 'only-on-failure',
|
|
29
|
+
ignoreHTTPSErrors: true,
|
|
30
|
+
},
|
|
31
|
+
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
|
|
32
|
+
webServer: {
|
|
33
|
+
command: 'npm run dev',
|
|
34
|
+
url: process.env.BASE_URL || 'http://localhost:3000',
|
|
35
|
+
timeout: 120_000,
|
|
36
|
+
reuseExistingServer: !process.env.CI,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Time budget (the 5-minute PR lane)
|
|
42
|
+
|
|
43
|
+
The per-PR browser gates (render sweep, curated smoke) target **≤5 min wall clock**, enforced by `timeout-minutes: 5` / `timeout: 300s` on the CI job (`ci-gates.*` templates carry it; `ci-audit.mjs` checks it). The levers: **parallel workers** (above — wall clock is the slowest spec, not the sum); **curation** (the floor runs the `@smoke` subset + the sweep, never the broad suite — gate 4 is demoted to the integration lane, see [../ci-integration.md](../ci-integration.md)); the **15s action timeout** (a hung step fails fast); **matrix fan-out** if the curated set still can't fit (the commented `smoke-drive` variant in `assets/ci-gates.github.yml`). Longer leashes belong to the integration-lane suite (`timeout-minutes: 30`) and auxiliary quarantine/visual jobs (10–15) — never the PR-lane gates.
|
|
44
|
+
|
|
45
|
+
## AGENTS.md section
|
|
46
|
+
|
|
47
|
+
Drop into each repo's AGENTS.md or CLAUDE.md:
|
|
48
|
+
|
|
49
|
+
```markdown
|
|
50
|
+
## E2E Testing
|
|
51
|
+
|
|
52
|
+
### Rules
|
|
53
|
+
1. Every new route/endpoint MUST be added to `e2e/route-manifest.json` (CI will fail otherwise)
|
|
54
|
+
2. Every new route needs at least a Tier 1 render-health test
|
|
55
|
+
3. Interactive routes need Tier 2 functional tests (success + error + edge cases)
|
|
56
|
+
4. Core business flows need Tier 3 journey tests — the golden paths (multi-step, real API); tag the do-not-ship subset `@smoke`
|
|
57
|
+
5. Directory: `render/`, `functional/`, `journeys/`
|
|
58
|
+
6. Use `getByRole`/`getByLabel`/`getByText` -- not CSS selectors
|
|
59
|
+
7. No `waitForTimeout()` -- wait for real state
|
|
60
|
+
8. Run route discovery and reachability analysis before E2E coverage audits; do not audit from memory, sampling, or file enumeration alone
|
|
61
|
+
9. No `test.skip()` unless it matches the Test Skipping Policy: allowed category, GitHub issue/blocker link, and replacement verification
|
|
62
|
+
10. Auth in shared fixtures (`e2e/fixtures/auth.ts`); test accounts and synthetic tenants carry the `e2e-` prefix (e.g. `e2e-customer-x1@example.test`, tenant `e2e-synthetic`)
|
|
63
|
+
11. Timeouts: 15s per action/assertion (`actionTimeout`/`expect.timeout`); no per-test timeout raises without justification
|
|
64
|
+
|
|
65
|
+
### CI Enforcement
|
|
66
|
+
- Route detection runs on every PR -- adding a page/endpoint without a manifest entry fails CI
|
|
67
|
+
- The presentation sweep runs as a separate blocking job -- a route that throws on render fails CI even when a functional spec passes
|
|
68
|
+
- Browser jobs run in the pinned official Playwright container (docker-preferred); PR-lane jobs carry a 5-minute timeout
|
|
69
|
+
- Branch protection requires only the `all-gates` umbrella job
|
|
70
|
+
- Reviewer will block PRs with uncovered interactive routes without justification
|
|
71
|
+
```
|