@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,148 @@
|
|
|
1
|
+
// Presentation route SWEEP — the runner that opens every manifest route in a real
|
|
2
|
+
// browser and asserts the presentation floor, spine first. This is the gate that
|
|
3
|
+
// catches a crashing route a green functional E2E suite sails past, because it
|
|
4
|
+
// drives the REAL render path (no first-party interception) over the WHOLE manifest
|
|
5
|
+
// instead of the handful of routes someone wrote a spec for.
|
|
6
|
+
//
|
|
7
|
+
// Satisfies ensure-coverage references/presentation/runner-contract.md and is the
|
|
8
|
+
// "render sweep" gate (#3) of references/enforcement/ci-contract.md. It is a SEPARATE CI job
|
|
9
|
+
// from the functional/journey suite.
|
|
10
|
+
//
|
|
11
|
+
// Usage (reference; adapt the fixtures to the repo):
|
|
12
|
+
// E2E_AUTH_BYPASS=1 node presentation-sweep.mjs \
|
|
13
|
+
// --manifest e2e/route-manifest.json --base-url http://127.0.0.1:3000 \
|
|
14
|
+
// --out docs/tests/_generated/presentation-results.json
|
|
15
|
+
//
|
|
16
|
+
// Fixtures the repo supplies (see the contract): auth bypass, seeded data, and a
|
|
17
|
+
// param resolver for dynamic segments. Routes that cannot be rendered are reported
|
|
18
|
+
// `blocked`, never silently skipped or passed.
|
|
19
|
+
|
|
20
|
+
import fs from 'node:fs'
|
|
21
|
+
import path from 'node:path'
|
|
22
|
+
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
23
|
+
|
|
24
|
+
// ---- pure, unit-testable core (no browser) ----
|
|
25
|
+
|
|
26
|
+
// Expand a manifest into the concrete routes to visit. Dynamic segments ([id], :id)
|
|
27
|
+
// are resolved via `paramResolver(route) -> concreteUrl | null`. A dynamic route
|
|
28
|
+
// with no resolver answer becomes a `blocked` plan entry (cannot render → not pass).
|
|
29
|
+
export function planRoutes(manifest, { paramResolver = () => null, ignore = [] } = {}) {
|
|
30
|
+
const routes = (manifest?.routes || manifest?.surfaces || [])
|
|
31
|
+
.map((r) => (typeof r === 'string' ? { route: r } : r))
|
|
32
|
+
.filter((r) => r.route && (r.kind ? r.kind === 'route' : true))
|
|
33
|
+
.filter((r) => !ignore.some((ig) => r.route.includes(ig)))
|
|
34
|
+
const plan = []
|
|
35
|
+
for (const r of routes) {
|
|
36
|
+
const isDynamic = /[:\[]/.test(r.route)
|
|
37
|
+
if (!isDynamic) { plan.push({ route: r.route, url: r.route }); continue }
|
|
38
|
+
const concrete = paramResolver(r.route)
|
|
39
|
+
if (concrete) plan.push({ route: r.route, url: concrete })
|
|
40
|
+
else plan.push({ route: r.route, url: null, blocked: 'dynamic segment has no param resolver answer' })
|
|
41
|
+
}
|
|
42
|
+
return plan
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Reduce raw per-route outcomes into the contract's result rows + an exit verdict.
|
|
46
|
+
// `fail` and `blocked` fail the gate (exit non-zero); `pass` does not.
|
|
47
|
+
export function summarize(rawResults) {
|
|
48
|
+
const results = rawResults.flatMap((r) => r.levels.map((l) => ({
|
|
49
|
+
route: r.route, level: l.level, status: l.status, evidence: l.evidence || undefined,
|
|
50
|
+
})))
|
|
51
|
+
const failed = results.filter((r) => r.status === 'fail' || r.status === 'blocked')
|
|
52
|
+
return { viewportFloor: [375, 1280], results, ok: failed.length === 0, failedCount: failed.length }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function parseArgs(argv) {
|
|
56
|
+
const f = {}
|
|
57
|
+
for (let i = 2; i < argv.length; i++) {
|
|
58
|
+
const a = argv[i]
|
|
59
|
+
if (a.startsWith('--')) f[a.slice(2)] = argv[i + 1]?.startsWith('--') || i + 1 >= argv.length ? true : argv[++i]
|
|
60
|
+
}
|
|
61
|
+
return f
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ---- browser orchestration (Playwright, lazy-imported) ----
|
|
65
|
+
|
|
66
|
+
// Run the sweep. `fixtures` lets the repo inject auth + param resolution:
|
|
67
|
+
// { applyAuth: async (context) => {}, paramResolver: (route) => url|null,
|
|
68
|
+
// extraFatal: [], ignoreRoutes: [], spatialIgnore: [] }
|
|
69
|
+
export async function runSweep({ manifestPath, baseURL, outPath, fixtures = {} }) {
|
|
70
|
+
const { chromium } = await import('@playwright/test')
|
|
71
|
+
const { watchRenderHealth, isFatalResponse } = await import('./presentation-render-health.mjs')
|
|
72
|
+
const { assertNoHorizontalOverflow } = await import('./presentation-checks.mjs')
|
|
73
|
+
|
|
74
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
75
|
+
const plan = planRoutes(manifest, { paramResolver: fixtures.paramResolver, ignore: fixtures.ignoreRoutes })
|
|
76
|
+
|
|
77
|
+
const browser = await chromium.launch()
|
|
78
|
+
const context = await browser.newContext()
|
|
79
|
+
if (fixtures.applyAuth) await fixtures.applyAuth(context)
|
|
80
|
+
|
|
81
|
+
const raw = []
|
|
82
|
+
for (const entry of plan) {
|
|
83
|
+
if (entry.blocked) {
|
|
84
|
+
raw.push({ route: entry.route, levels: [
|
|
85
|
+
{ level: 'presentation:render-health', status: 'blocked', evidence: entry.blocked },
|
|
86
|
+
{ level: 'presentation:spatial', status: 'blocked', evidence: entry.blocked },
|
|
87
|
+
] })
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
const page = await context.newPage()
|
|
91
|
+
const levels = []
|
|
92
|
+
const health = watchRenderHealth(page, { origin: baseURL, extraFatal: fixtures.extraFatal })
|
|
93
|
+
try {
|
|
94
|
+
const res = await page.goto(baseURL + entry.url, { waitUntil: 'domcontentloaded' })
|
|
95
|
+
await page.waitForLoadState('networkidle').catch(() => {})
|
|
96
|
+
// spine: render-health
|
|
97
|
+
const docFatal = res && isFatalResponse(res.status(), res.url(), { origin: baseURL })
|
|
98
|
+
const verdict = await health.evaluate()
|
|
99
|
+
if (docFatal || !verdict.healthy) {
|
|
100
|
+
const ev = docFatal ? `document ${res.status()}` : verdict.offenders.map((o) => `[${o.kind}] ${o.detail}`).join('; ')
|
|
101
|
+
levels.push({ level: 'presentation:render-health', status: 'fail', evidence: ev })
|
|
102
|
+
// layout is not assessable once the page failed to render
|
|
103
|
+
levels.push({ level: 'presentation:spatial', status: 'blocked', evidence: 'render-health failed; layout not assessable' })
|
|
104
|
+
} else {
|
|
105
|
+
levels.push({ level: 'presentation:render-health', status: 'pass' })
|
|
106
|
+
try {
|
|
107
|
+
await assertNoHorizontalOverflow(page, { ignore: fixtures.spatialIgnore || [] })
|
|
108
|
+
levels.push({ level: 'presentation:spatial', status: 'pass' })
|
|
109
|
+
} catch (e) {
|
|
110
|
+
levels.push({ level: 'presentation:spatial', status: 'fail', evidence: e.message })
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
} catch (e) {
|
|
114
|
+
levels.push({ level: 'presentation:render-health', status: 'fail', evidence: e.message })
|
|
115
|
+
} finally {
|
|
116
|
+
await page.close()
|
|
117
|
+
}
|
|
118
|
+
raw.push({ route: entry.route, levels })
|
|
119
|
+
}
|
|
120
|
+
await browser.close()
|
|
121
|
+
|
|
122
|
+
const summary = summarize(raw)
|
|
123
|
+
if (outPath) {
|
|
124
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true })
|
|
125
|
+
fs.writeFileSync(outPath, JSON.stringify(summary, null, 2))
|
|
126
|
+
}
|
|
127
|
+
return summary
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// CLI entry: load a repo-supplied fixtures module via --fixtures (optional).
|
|
131
|
+
async function main() {
|
|
132
|
+
const f = parseArgs(process.argv)
|
|
133
|
+
const manifestPath = f.manifest || 'e2e/route-manifest.json'
|
|
134
|
+
const baseURL = (f['base-url'] || 'http://127.0.0.1:3000').replace(/\/$/, '')
|
|
135
|
+
const outPath = f.out || 'docs/tests/_generated/presentation-results.json'
|
|
136
|
+
let fixtures = {}
|
|
137
|
+
if (f.fixtures) fixtures = (await import(path.resolve(f.fixtures))).default || {}
|
|
138
|
+
const summary = await runSweep({ manifestPath, baseURL, outPath, fixtures })
|
|
139
|
+
const failed = summary.results.filter((r) => r.status === 'fail' || r.status === 'blocked')
|
|
140
|
+
for (const r of failed) console.error(`✖ ${r.route} ${r.level} — ${r.status}: ${r.evidence || ''}`)
|
|
141
|
+
console.log(`presentation sweep: ${summary.results.length} checks, ${summary.failedCount} failing across ${summary.results.length ? new Set(summary.results.map((r) => r.route)).size : 0} routes`)
|
|
142
|
+
process.exit(summary.ok ? 0 : 1)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Run as CLI only when invoked directly (not when imported by tests).
|
|
146
|
+
if (isMainModule(import.meta.url)) {
|
|
147
|
+
main().catch((e) => { console.error(e); process.exit(1) })
|
|
148
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Presentation-axis Temporal-stability instrument for e2e-test (issue #199).
|
|
2
|
+
//
|
|
3
|
+
// "Does the layout hold still" — content must not jump as things inject. Tag specs
|
|
4
|
+
// `@level presentation:temporal`. Drives a REAL browser; DOM-only is Over-mocked.
|
|
5
|
+
//
|
|
6
|
+
// Split by WHO renders the shift (the functional axis says "fake externals", but
|
|
7
|
+
// faking the payment iframe makes the shift we want to catch disappear):
|
|
8
|
+
//
|
|
9
|
+
// • FIRST-PARTY shift (lazy images, async data, our own dynamic fields) — a
|
|
10
|
+
// HERMETIC gate: real render, no network. Gate on a stable condition, not a
|
|
11
|
+
// fixed sleep.
|
|
12
|
+
// • THIRD-PARTY iframe shift (Stripe/Adyen/Braintree payfields) — the provider's
|
|
13
|
+
// official SANDBOX iframe in a SEPARATE NON-BLOCKING PR lane: a failure posts a
|
|
14
|
+
// visible annotation and the surface stays `Unverified` until a reviewer
|
|
15
|
+
// attests — never a silent advisory. (Faking the iframe defeats the check.)
|
|
16
|
+
//
|
|
17
|
+
// Why not top-page CLS: the Layout Instability API does NOT report shifts inside
|
|
18
|
+
// cross-origin iframes (WICG spec excludes descendant browsing contexts). So a
|
|
19
|
+
// top-page PerformanceObserver is blind to the payfields case — the deterministic
|
|
20
|
+
// answer is a before/after getBoundingClientRect assertion gated on a provider-ready
|
|
21
|
+
// signal. CLS IS fine for first-party shift.
|
|
22
|
+
|
|
23
|
+
// ---------- pure cores (no browser) ----------
|
|
24
|
+
|
|
25
|
+
// Compare two geometry snapshots and return elements that MOVED beyond tolerance.
|
|
26
|
+
// `before`/`after` are arrays of { selector, rect:{left,top,right,bottom} }; matched
|
|
27
|
+
// by selector. An element only present after (newly injected) is not itself a shift —
|
|
28
|
+
// what matters is whether EXISTING elements moved because of the injection.
|
|
29
|
+
export function findLayoutShift(before, after, { tolerancePx = 2 } = {}) {
|
|
30
|
+
const afterBySel = new Map(after.map((e) => [e.selector, e.rect]))
|
|
31
|
+
const shifted = []
|
|
32
|
+
for (const b of before) {
|
|
33
|
+
const a = afterBySel.get(b.selector)
|
|
34
|
+
if (!a) continue // element gone — not a shift of a stable element
|
|
35
|
+
const dx = Math.max(Math.abs(a.left - b.rect.left), Math.abs(a.right - b.rect.right))
|
|
36
|
+
const dy = Math.max(Math.abs(a.top - b.rect.top), Math.abs(a.bottom - b.rect.bottom))
|
|
37
|
+
if (dx > tolerancePx || dy > tolerancePx) {
|
|
38
|
+
shifted.push({ selector: b.selector, dx: Math.round(dx), dy: Math.round(dy) })
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return shifted
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Cumulative Layout Shift from PerformanceObserver `layout-shift` entries: sum of
|
|
45
|
+
// `value` for entries NOT following recent user input. Pure; feed it the raw entries
|
|
46
|
+
// captured in-page. An OPTIONAL first-party alternative to the geometry diff — the
|
|
47
|
+
// wrappers below use `findLayoutShift` (before/after geometry) as the default
|
|
48
|
+
// mechanism because it pinpoints the offending element; CLS is offered for teams
|
|
49
|
+
// that prefer the Web Vital. (First-party only — see header note on the iframe blind spot.)
|
|
50
|
+
export function cumulativeShiftScore(entries = []) {
|
|
51
|
+
return entries
|
|
52
|
+
.filter((e) => !e.hadRecentInput)
|
|
53
|
+
.reduce((sum, e) => sum + (e.value || 0), 0)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ---------- in-browser collectors ----------
|
|
57
|
+
|
|
58
|
+
// NOTE: elements are keyed by a derived selector (`#id` else `tag.class…`). Two
|
|
59
|
+
// id-less elements sharing tag+classes collide on the same key (last-wins), which
|
|
60
|
+
// can mask or spoof a shift. Prefer stable ids / `data-testid` on elements whose
|
|
61
|
+
// stability you assert; id'd elements are unaffected.
|
|
62
|
+
function collectGeometryAll() {
|
|
63
|
+
const sel = (el) => {
|
|
64
|
+
if (el.id) return '#' + el.id
|
|
65
|
+
let s = el.tagName.toLowerCase()
|
|
66
|
+
if (typeof el.className === 'string' && el.className.trim()) s += '.' + el.className.trim().split(/\s+/).join('.')
|
|
67
|
+
return s
|
|
68
|
+
}
|
|
69
|
+
return [...document.querySelectorAll('body *')].map((el) => {
|
|
70
|
+
const r = el.getBoundingClientRect()
|
|
71
|
+
return { selector: sel(el), rect: { left: r.left, top: r.top, right: r.right, bottom: r.bottom } }
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---------- Playwright wrappers (need a real browser) ----------
|
|
76
|
+
|
|
77
|
+
// FIRST-PARTY hermetic gate. Snapshot geometry, run `trigger` (the action that
|
|
78
|
+
// injects first-party content — load more, resolve async data), wait for a STABLE
|
|
79
|
+
// condition (a settle locator becoming visible, else network-idle — never a fixed
|
|
80
|
+
// sleep), snapshot again, and fail if existing elements moved beyond tolerance.
|
|
81
|
+
export async function assertNoFirstPartyShift(page, { trigger, settle, tolerancePx = 2 } = {}) {
|
|
82
|
+
const before = await page.evaluate(collectGeometryAll)
|
|
83
|
+
if (trigger) await trigger()
|
|
84
|
+
if (settle) await settle.waitFor({ state: 'visible' })
|
|
85
|
+
else await page.waitForLoadState('networkidle').catch(() => {})
|
|
86
|
+
const after = await page.evaluate(collectGeometryAll)
|
|
87
|
+
const shifted = findLayoutShift(before, after, { tolerancePx })
|
|
88
|
+
if (shifted.length) {
|
|
89
|
+
const lines = shifted.map((s) => ` ${s.selector} moved Δx=${s.dx} Δy=${s.dy}px`)
|
|
90
|
+
throw new Error(`presentation:temporal (first-party) — layout shifted after injection:\n${lines.join('\n')}`)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// THIRD-PARTY (payfields) check. Runs against the provider's SANDBOX iframe. Wait on
|
|
95
|
+
// a provider-ready signal (`ready`: a locator or async fn — NOT a sleep), then assert
|
|
96
|
+
// the elements AROUND the payment container did not move. Intended for the separate
|
|
97
|
+
// NON-BLOCKING lane; a failure here should be annotated and tracked as `Unverified`,
|
|
98
|
+
// not block the PR (it touches an external sandbox).
|
|
99
|
+
export async function assertNoThirdPartyShift(page, { container, ready, tolerancePx = 2 } = {}) {
|
|
100
|
+
const before = await page.evaluate(collectGeometryAll)
|
|
101
|
+
if (typeof ready === 'function') await ready()
|
|
102
|
+
else if (ready) await ready.waitFor({ state: 'visible' })
|
|
103
|
+
const after = await page.evaluate(collectGeometryAll)
|
|
104
|
+
const shifted = findLayoutShift(before, after, { tolerancePx })
|
|
105
|
+
.filter((s) => !container || !s.selector.includes(container)) // the iframe box itself may grow; we care about NEIGHBORS moving
|
|
106
|
+
if (shifted.length) {
|
|
107
|
+
const lines = shifted.map((s) => ` ${s.selector} moved Δx=${s.dx} Δy=${s.dy}px`)
|
|
108
|
+
throw new Error(`presentation:temporal (third-party payfields) — surrounding layout shifted when the provider iframe injected:\n${lines.join('\n')}`)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Mobile dynamic-viewport (dvh) gate. Emulate a mobile viewport, then shrink the
|
|
113
|
+
// height (the mobile address bar collapsing/expanding) and assert content does not
|
|
114
|
+
// jump — catches `100vh`-behind-the-chrome bugs. Gated via emulation with a tuned
|
|
115
|
+
// tolerance; fall back to staging if flake proves unmanageable (see design doc).
|
|
116
|
+
export async function assertNoDynamicViewportShift(page, { width = 390, tall = 844, short = 740, tolerancePx = 2 } = {}) {
|
|
117
|
+
await page.setViewportSize({ width, height: tall })
|
|
118
|
+
await page.waitForLoadState('networkidle').catch(() => {})
|
|
119
|
+
const before = await page.evaluate(collectGeometryAll)
|
|
120
|
+
await page.setViewportSize({ width, height: short }) // address bar appears
|
|
121
|
+
const after = await page.evaluate(collectGeometryAll)
|
|
122
|
+
const shifted = findLayoutShift(before, after, { tolerancePx })
|
|
123
|
+
if (shifted.length) {
|
|
124
|
+
const lines = shifted.map((s) => ` ${s.selector} moved Δx=${s.dx} Δy=${s.dy}px`)
|
|
125
|
+
throw new Error(`presentation:temporal (dynamic viewport) — content jumped when the mobile viewport height changed (100vh/dvh):\n${lines.join('\n')}`)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Presentation-axis instrument for e2e-test: visual regression (`presentation:visual`).
|
|
2
|
+
//
|
|
3
|
+
// The OPT-IN presentation level. The floor levels (render-health/spatial/
|
|
4
|
+
// perceivability/reachability/temporal) are auto-applied and assert *structure*;
|
|
5
|
+
// this level pins *appearance* against a committed pixel baseline and fails on
|
|
6
|
+
// drift — catching the restyle / wrong-content / looks-broken-but-doesn't-throw
|
|
7
|
+
// class the structural levels miss. A surface earns it only by declaring
|
|
8
|
+
// `requiredLevels: [presentation:visual]` in its `*.coverage.yml` (raise-only).
|
|
9
|
+
//
|
|
10
|
+
// Wraps Playwright's built-in `toHaveScreenshot()` — we do NOT hand-roll a differ;
|
|
11
|
+
// baselines, the 3-up diff on failure, masking, and `maxDiffPixelRatio` are native.
|
|
12
|
+
//
|
|
13
|
+
// NON-NEGOTIABLE (see ensure-coverage references/presentation/runner-contract.md
|
|
14
|
+
// and references/enforcement/ci-contract.md):
|
|
15
|
+
// 1. CI-only, in a pinned Playwright container (mcr.microsoft.com/playwright:vX.Y)
|
|
16
|
+
// for BOTH baseline generation and the gate. Never mint baselines on a dev host
|
|
17
|
+
// — host-OS anti-aliasing differs from Linux CI and reds every PR.
|
|
18
|
+
// 2. Baselines are committed; only the on-demand `visual-baseline-regen` job
|
|
19
|
+
// (`--update-snapshots`) writes them. The blocking `visual-gate` job only reads.
|
|
20
|
+
//
|
|
21
|
+
// Tag the proving spec `@covers <route>` / `@level presentation:visual` so the
|
|
22
|
+
// Coverage Ledger resolves it. Drives a REAL browser — a DOM/JSDOM snapshot cannot
|
|
23
|
+
// see pixels and is graded `Over-mocked`.
|
|
24
|
+
|
|
25
|
+
// ---- pure, unit-testable core (no browser) ----
|
|
26
|
+
|
|
27
|
+
// The floor viewports visual is captured at — mirrors PRESENTATION_VIEWPORT_FLOOR
|
|
28
|
+
// in ensure-coverage's coverage-ledger.mjs. Visual is captured per viewport.
|
|
29
|
+
export const VISUAL_VIEWPORT_FLOOR = [375, 1280]
|
|
30
|
+
|
|
31
|
+
// Deterministic baseline filename for a (route, viewport) cell. Stable + filesystem
|
|
32
|
+
// safe so the committed PNG path never churns. Playwright appends its own
|
|
33
|
+
// `-<project>-<platform>` suffix; we own the route+viewport stem.
|
|
34
|
+
export function baselineName(route, viewport) {
|
|
35
|
+
const slug = route.replace(/^\//, '').replace(/[^a-z0-9]+/gi, '-').replace(/^-|-$/g, '') || 'index'
|
|
36
|
+
return `${slug}-${viewport}.png`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Normalize a coverage-file `visual.mask` list into the shape the spec consumes,
|
|
40
|
+
// dropping entries with no `reason` (masking is a GATED concession — every masked
|
|
41
|
+
// region must carry a reason, surfaced in the census). Returns { selectors, gaps }
|
|
42
|
+
// where `gaps` names mask entries rejected for a missing reason (a finding).
|
|
43
|
+
export function resolveMasks(visualConfig = {}) {
|
|
44
|
+
const raw = Array.isArray(visualConfig.mask) ? visualConfig.mask : []
|
|
45
|
+
const selectors = []
|
|
46
|
+
const gaps = []
|
|
47
|
+
for (const m of raw) {
|
|
48
|
+
if (typeof m === 'string') { gaps.push({ selector: m, why: 'mask entry has no reason' }); continue }
|
|
49
|
+
if (!m.reason || !String(m.reason).trim()) { gaps.push({ selector: m.selector, why: 'mask entry has no reason' }); continue }
|
|
50
|
+
selectors.push(m.selector)
|
|
51
|
+
}
|
|
52
|
+
return { selectors, gaps }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Build the per-(route, viewport) result the ledger consumes (runner-contract.md
|
|
56
|
+
// "Result shape"). `status` ∈ pass|fail|blocked. On fail, carry the committed
|
|
57
|
+
// baseline path (durable evidence) and the diff artifact URL (ephemeral).
|
|
58
|
+
export function visualResult({ route, viewport, status, evidence, baseline, diffArtifact }) {
|
|
59
|
+
const r = { route, level: 'presentation:visual', status, viewport }
|
|
60
|
+
if (evidence) r.evidence = evidence
|
|
61
|
+
if (baseline) r.baseline = baseline
|
|
62
|
+
if (diffArtifact) r.diffArtifact = diffArtifact
|
|
63
|
+
return r
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---- browser wrapper (thin over Playwright's native assertion) ----
|
|
67
|
+
|
|
68
|
+
// Assert a route matches its committed visual baseline at one viewport. Applies the
|
|
69
|
+
// determinism prep the surface owes (animations off — the rest, clock-freeze/seed,
|
|
70
|
+
// is the harness's job before calling this) and masks the gated dynamic regions.
|
|
71
|
+
// `expect` and `page` are injected so this stays testable and Playwright-version
|
|
72
|
+
// agnostic. Throws (Playwright's assertion) on drift; the sweep maps that to a
|
|
73
|
+
// `fail` result via visualResult().
|
|
74
|
+
export async function assertVisualBaseline(page, expect, route, viewport, opts = {}) {
|
|
75
|
+
const { maskSelectors = [], maxDiffPixelRatio = 0.001, settle } = opts
|
|
76
|
+
await page.setViewportSize({ width: viewport, height: 900 })
|
|
77
|
+
await page.goto(route)
|
|
78
|
+
if (settle) await settle(page) // gate on a stable condition, NEVER a fixed sleep
|
|
79
|
+
await expect(page).toHaveScreenshot(baselineName(route, viewport), {
|
|
80
|
+
mask: maskSelectors.map((s) => page.locator(s)),
|
|
81
|
+
maxDiffPixelRatio,
|
|
82
|
+
animations: 'disabled',
|
|
83
|
+
})
|
|
84
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Project the E2E route-manifest FROM the canonical surface inventory + a curated
|
|
2
|
+
// overlay. The manifest is GENERATED, never hand-enumerated — so its route set
|
|
3
|
+
// cannot drift from the inventory (regenerate + `git diff --exit-code` is CI gate 1).
|
|
4
|
+
//
|
|
5
|
+
// node project-route-manifest.mjs \
|
|
6
|
+
// --inventory docs/tests/_generated/surface-inventory.json \
|
|
7
|
+
// --overlay e2e/route-manifest.overlay.json \
|
|
8
|
+
// --out e2e/route-manifest.json
|
|
9
|
+
//
|
|
10
|
+
// What lives where:
|
|
11
|
+
// - inventory (ensure-coverage, generated) = the route SET + (kind, class).
|
|
12
|
+
// - overlay (curated, small) = E2E-only deviations: tier, ignore
|
|
13
|
+
// (don't sweep), spatial allowlist.
|
|
14
|
+
// - manifest (generated here) = inventory(routes) ⨝ overlay.
|
|
15
|
+
// Coverage is NOT tracked here — the ledger computes it from `@covers` annotations.
|
|
16
|
+
// `specs` is optional/informational only; it is not a coverage signal.
|
|
17
|
+
|
|
18
|
+
import fs from 'node:fs'
|
|
19
|
+
import path from 'node:path'
|
|
20
|
+
import { isMainModule } from '../../engineering-runtime/scripts/main-module.mjs'
|
|
21
|
+
|
|
22
|
+
// Default E2E tier from the inventory's mechanical class. Overlay can raise it
|
|
23
|
+
// (e.g. a route on a core journey → tier 3); it cannot be derived from a single
|
|
24
|
+
// route because "journey" is a cross-page property.
|
|
25
|
+
const DEFAULT_TIER = { read: 1, detail: 2, mutation: 2 }
|
|
26
|
+
|
|
27
|
+
// Pure: inventory + overlay -> manifest object. Deterministic + sorted so the diff
|
|
28
|
+
// is stable.
|
|
29
|
+
export function projectManifest(inventory, overlay = {}) {
|
|
30
|
+
const ov = overlay.routes || {}
|
|
31
|
+
const routes = (inventory?.surfaces || [])
|
|
32
|
+
.filter((s) => s.kind === 'route')
|
|
33
|
+
.filter((s) => !ov[s.id]?.ignore) // curated: explicitly not swept (still owes its ledger floor)
|
|
34
|
+
.map((s) => {
|
|
35
|
+
const o = ov[s.id] || {}
|
|
36
|
+
const entry = { path: s.id, tier: o.tier ?? DEFAULT_TIER[s.class] ?? 1 }
|
|
37
|
+
if (o.specs) entry.specs = o.specs // informational only
|
|
38
|
+
return entry
|
|
39
|
+
})
|
|
40
|
+
.sort((a, b) => a.path.localeCompare(b.path))
|
|
41
|
+
const manifest = { version: 1, generated: true, routes }
|
|
42
|
+
if (overlay.spatialIgnore) manifest.spatialIgnore = overlay.spatialIgnore
|
|
43
|
+
return manifest
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Report overlay entries that reference a route no longer in the inventory — curated
|
|
47
|
+
// rot the diff alone won't explain. Returned so the CLI can warn (not throw).
|
|
48
|
+
export function staleOverlayEntries(inventory, overlay = {}) {
|
|
49
|
+
const ids = new Set((inventory?.surfaces || []).filter((s) => s.kind === 'route').map((s) => s.id))
|
|
50
|
+
return Object.keys(overlay.routes || {}).filter((id) => !ids.has(id))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function arg(flags, name, def) { return flags[name] ?? def }
|
|
54
|
+
|
|
55
|
+
function main() {
|
|
56
|
+
const argv = process.argv.slice(2)
|
|
57
|
+
const flags = {}
|
|
58
|
+
for (let i = 0; i < argv.length; i++) if (argv[i].startsWith('--')) flags[argv[i].slice(2)] = argv[++i]
|
|
59
|
+
const inventoryPath = arg(flags, 'inventory', 'docs/tests/_generated/surface-inventory.json')
|
|
60
|
+
const overlayPath = arg(flags, 'overlay', 'e2e/route-manifest.overlay.json')
|
|
61
|
+
const outPath = arg(flags, 'out', 'e2e/route-manifest.json')
|
|
62
|
+
|
|
63
|
+
const inventory = JSON.parse(fs.readFileSync(inventoryPath, 'utf8'))
|
|
64
|
+
const overlay = fs.existsSync(overlayPath) ? JSON.parse(fs.readFileSync(overlayPath, 'utf8')) : {}
|
|
65
|
+
|
|
66
|
+
const stale = staleOverlayEntries(inventory, overlay)
|
|
67
|
+
if (stale.length) console.error(`⚠ overlay references routes not in inventory (stale curation): ${stale.join(', ')}`)
|
|
68
|
+
|
|
69
|
+
const manifest = projectManifest(inventory, overlay)
|
|
70
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true })
|
|
71
|
+
fs.writeFileSync(outPath, JSON.stringify(manifest, null, 2) + '\n')
|
|
72
|
+
console.log(`wrote ${outPath} — ${manifest.routes.length} routes (generated from ${inventoryPath})`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (isMainModule(import.meta.url)) main()
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validate route manifest against actual spec files.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node scripts/validate-manifest.mjs [--manifest e2e/route-manifest.json] [--e2e-dir e2e]
|
|
8
|
+
*
|
|
9
|
+
* Checks:
|
|
10
|
+
* 1. Manifest is valid JSON with required fields
|
|
11
|
+
* 2. All referenced spec files exist
|
|
12
|
+
* 3. Reports uncovered routes (specs: [])
|
|
13
|
+
* 4. Reports coverage percentage
|
|
14
|
+
*
|
|
15
|
+
* Exit codes:
|
|
16
|
+
* 0 = valid (may have warnings)
|
|
17
|
+
* 1 = errors found (missing files, invalid format)
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readFileSync, existsSync } from 'fs';
|
|
21
|
+
import { join, resolve } from 'path';
|
|
22
|
+
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
function getArg(name, defaultVal) {
|
|
25
|
+
const idx = args.indexOf(`--${name}`);
|
|
26
|
+
return idx >= 0 && args[idx + 1] ? args[idx + 1] : defaultVal;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const manifestPath = resolve(getArg('manifest', 'e2e/route-manifest.json'));
|
|
30
|
+
const e2eDir = resolve(getArg('e2e-dir', 'e2e'));
|
|
31
|
+
|
|
32
|
+
let errors = 0;
|
|
33
|
+
let warnings = 0;
|
|
34
|
+
|
|
35
|
+
// Check manifest exists
|
|
36
|
+
if (!existsSync(manifestPath)) {
|
|
37
|
+
console.error(`❌ Manifest not found: ${manifestPath}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Parse manifest
|
|
42
|
+
let manifest;
|
|
43
|
+
try {
|
|
44
|
+
manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
45
|
+
} catch (e) {
|
|
46
|
+
console.error(`❌ Invalid JSON in manifest: ${e.message}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const routes = manifest.routes || manifest.endpoints || [];
|
|
51
|
+
|
|
52
|
+
if (routes.length === 0) {
|
|
53
|
+
console.error('❌ Manifest has no routes/endpoints');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
console.log(`📋 Validating ${routes.length} routes from ${manifestPath}\n`);
|
|
58
|
+
|
|
59
|
+
// Validate each route
|
|
60
|
+
let covered = 0;
|
|
61
|
+
for (const route of routes) {
|
|
62
|
+
const label = route.method ? `${route.method} ${route.path}` : route.path;
|
|
63
|
+
|
|
64
|
+
// Check required fields
|
|
65
|
+
if (!route.path) {
|
|
66
|
+
console.error(`❌ Route missing "path" field`);
|
|
67
|
+
errors++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (typeof route.tier !== 'number' || route.tier < 1 || route.tier > 3) {
|
|
71
|
+
console.error(`❌ ${label}: invalid tier (must be 1-3, got ${route.tier})`);
|
|
72
|
+
errors++;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Check specs
|
|
76
|
+
const specs = route.specs || [];
|
|
77
|
+
if (specs.length === 0) {
|
|
78
|
+
console.warn(`⚠️ ${label}: uncovered (no specs)`);
|
|
79
|
+
warnings++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
covered++;
|
|
84
|
+
for (const spec of specs) {
|
|
85
|
+
const specPath = join(e2eDir, spec);
|
|
86
|
+
if (!existsSync(specPath)) {
|
|
87
|
+
console.error(`❌ ${label}: spec file not found: ${specPath}`);
|
|
88
|
+
errors++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Summary
|
|
94
|
+
const coverage = Math.round((covered / routes.length) * 100);
|
|
95
|
+
console.log(`\n${'─'.repeat(50)}`);
|
|
96
|
+
console.log(`📊 Coverage: ${coverage}% (${covered}/${routes.length} routes covered)`);
|
|
97
|
+
console.log(`❌ Errors: ${errors}`);
|
|
98
|
+
console.log(`⚠️ Warnings: ${warnings}`);
|
|
99
|
+
|
|
100
|
+
if (errors > 0) {
|
|
101
|
+
console.log('\n🚫 Validation failed');
|
|
102
|
+
process.exit(1);
|
|
103
|
+
} else {
|
|
104
|
+
console.log('\n✅ Validation passed');
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: engineering-runtime
|
|
3
|
+
description: Internal support package for shared Engineering Workflow executable behavior. Never select or invoke this package as a user capability.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
user-invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Engineering Runtime
|
|
9
|
+
|
|
10
|
+
This is a support-only runtime package for Engineering Workflow consumers. It exposes no user workflow.
|