@thedecipherist/claude-packs 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +680 -0
- package/LICENSE +21 -0
- package/README.md +316 -2
- package/bin/claude-packs.mjs +204 -0
- package/configurations/base/config.json +85 -0
- package/configurations/cpp/config.json +92 -0
- package/configurations/full-stack/config.json +152 -0
- package/configurations/go/config.json +96 -0
- package/configurations/node/config.json +100 -0
- package/configurations/python/config.json +97 -0
- package/configurations/synth-creator/config.json +148 -0
- package/global/hooks/gnu-shell.mjs +131 -0
- package/global/hooks/lib/program-read.mjs +196 -0
- package/global/hooks/lib/program-writes.mjs +177 -0
- package/global/hooks/lib/shell-writes.mjs +293 -0
- package/global/hooks/shell-traps.mjs +79 -0
- package/global/hooks/version-pin-guard.mjs +280 -0
- package/global/skills/latest-versions/SKILL.md +49 -0
- package/lib/backup.mjs +34 -0
- package/lib/claude-md.mjs +58 -0
- package/lib/config-cli.mjs +36 -0
- package/lib/configs.mjs +145 -0
- package/lib/coverage.mjs +86 -0
- package/lib/custom-packs.mjs +93 -0
- package/lib/doctor.mjs +115 -0
- package/lib/fix-plan.mjs +71 -0
- package/lib/git-tokens.mjs +64 -0
- package/lib/global.mjs +125 -0
- package/lib/hook-proof.mjs +28 -0
- package/lib/hook-timing.mjs +42 -0
- package/lib/hover-gate.mjs +29 -0
- package/lib/kit-lock.mjs +149 -0
- package/lib/layout.mjs +75 -0
- package/lib/logs.mjs +69 -0
- package/lib/manifest.mjs +24 -0
- package/lib/new.mjs +49 -0
- package/lib/once-only-report.mjs +54 -0
- package/lib/pack-manifest.mjs +20 -0
- package/lib/packs.mjs +107 -0
- package/lib/planner.mjs +59 -0
- package/lib/repeats.mjs +65 -0
- package/lib/repo-weight.mjs +28 -0
- package/lib/rules.mjs +40 -0
- package/lib/scan-detect.mjs +94 -0
- package/lib/scan.mjs +168 -0
- package/lib/selftest-cache.mjs +39 -0
- package/lib/settings.mjs +138 -0
- package/lib/shape-cli.mjs +76 -0
- package/lib/shape.mjs +4 -0
- package/lib/suggest.mjs +18 -0
- package/lib/switches.mjs +44 -0
- package/lib/symmetry-doctor.mjs +26 -0
- package/lib/sync.mjs +130 -0
- package/package.json +34 -4
- package/packs/ai/checks/boundary-computes-its-own-hash.json +30 -0
- package/packs/ai/checks/model-call-needs-boundary.json +29 -0
- package/packs/ai/checks/model-id-from-config.json +28 -0
- package/packs/ai/checks/model-output-validated.json +26 -0
- package/packs/ai/pack.json +38 -0
- package/packs/ai/rules/ai-input-sha-boundary.md +31 -0
- package/packs/ai/rules/llm-pipeline-security.md +26 -0
- package/packs/audio-core/checks/denormals-not-in-prepare.json +12 -0
- package/packs/audio-core/checks/dsp-without-apvts.json +12 -0
- package/packs/audio-core/checks/float-phase-or-rate.json +12 -0
- package/packs/audio-core/checks/juce-snap-to-zero-off.json +12 -0
- package/packs/audio-core/checks/keep-werror.json +12 -0
- package/packs/audio-core/checks/no-fast-math.json +14 -0
- package/packs/audio-core/checks/no-locale-change.json +12 -0
- package/packs/audio-core/checks/no-march-native.json +14 -0
- package/packs/audio-core/clang-tidy +28 -0
- package/packs/audio-core/hooks/lib/realtime-checks.mjs +56 -0
- package/packs/audio-core/hooks/param-id-lock.mjs +129 -0
- package/packs/audio-core/hooks/realtime-guard.mjs +67 -0
- package/packs/audio-core/pack.json +187 -0
- package/packs/audio-core/rules/audio-thread-realtime-safe.md +27 -0
- package/packs/audio-core/rules/audio-ui-thread-handoff.md +21 -0
- package/packs/audio-core/rules/boundary-tests-cross-the-boundary.md +16 -0
- package/packs/audio-core/rules/build-flags-safe.md +20 -0
- package/packs/audio-core/rules/cached-parameter-pointers.md +28 -0
- package/packs/audio-core/rules/clang-tidy-core-guidelines.md +21 -0
- package/packs/audio-core/rules/control-reaches-every-surface.md +23 -0
- package/packs/audio-core/rules/cpu-worst-case-per-block.md +26 -0
- package/packs/audio-core/rules/dc-block-after-asymmetry.md +22 -0
- package/packs/audio-core/rules/discrete-params-snap.md +19 -0
- package/packs/audio-core/rules/double-where-precision-matters.md +20 -0
- package/packs/audio-core/rules/filters-stable-under-modulation.md +29 -0
- package/packs/audio-core/rules/host-parameters-at-scale.md +24 -0
- package/packs/audio-core/rules/house-control-behaviours.md +34 -0
- package/packs/audio-core/rules/math-domain-guards.md +19 -0
- package/packs/audio-core/rules/modulated-delay-interpolation.md +22 -0
- package/packs/audio-core/rules/multiband-phase-coherent.md +22 -0
- package/packs/audio-core/rules/nonlinear-stages-antialiased.md +28 -0
- package/packs/audio-core/rules/note-ledger-and-pedals.md +22 -0
- package/packs/audio-core/rules/one-formula-per-value.md +20 -0
- package/packs/audio-core/rules/optimisations-are-null-tested.md +23 -0
- package/packs/audio-core/rules/oscillators-bandlimited.md +23 -0
- package/packs/audio-core/rules/output-limiter.md +23 -0
- package/packs/audio-core/rules/parameter-ids-never-change.md +20 -0
- package/packs/audio-core/rules/params-and-state-thread-safe.md +19 -0
- package/packs/audio-core/rules/params-snapshot-per-block.md +21 -0
- package/packs/audio-core/rules/patch-excludes-performance-controls.md +18 -0
- package/packs/audio-core/rules/per-sample-code-inlinable.md +22 -0
- package/packs/audio-core/rules/prepare-is-repeatable.md +23 -0
- package/packs/audio-core/rules/recursive-state-nan-guard.md +20 -0
- package/packs/audio-core/rules/reverb-loop-gain-bounded.md +24 -0
- package/packs/audio-core/rules/sample-accurate-midi.md +22 -0
- package/packs/audio-core/rules/sample-rate-and-block-size-from-host.md +23 -0
- package/packs/audio-core/rules/scoped-no-denormals.md +26 -0
- package/packs/audio-core/rules/smooth-continuous-parameters.md +22 -0
- package/packs/audio-core/rules/state-load-versioned-and-safe.md +22 -0
- package/packs/audio-core/rules/straight-on-and-aligned.md +21 -0
- package/packs/audio-core/rules/ui-matches-reference-look.md +21 -0
- package/packs/audio-core/rules/undo-one-gesture-one-step.md +21 -0
- package/packs/audio-core/rules/voice-steal-fades.md +21 -0
- package/packs/audio-core/rules/voice-sum-headroom.md +20 -0
- package/packs/audio-core/skills/analyse-reference-look/SKILL.md +21 -0
- package/packs/audio-core/skills/copy-and-prove/SKILL.md +98 -0
- package/packs/audio-core/skills/juce-realtime-audit/SKILL.md +22 -0
- package/packs/audio-core/skills/measure-tone/SKILL.md +20 -0
- package/packs/audio-core/skills/new-panel-control/SKILL.md +15 -0
- package/packs/audio-core/skills/prove-control/SKILL.md +23 -0
- package/packs/audio-core/skills/trace-parameter/SKILL.md +29 -0
- package/packs/audio-core/tools/lib/spectrum.mjs +112 -0
- package/packs/audio-core/tools/lib/wav.mjs +41 -0
- package/packs/audio-core/tools/tone-report.mjs +47 -0
- package/packs/base/checks/field-map-over-if-runs.json +25 -0
- package/packs/base/checks/lookup-over-if-chains.json +25 -0
- package/packs/base/checks/lookup-over-ternary-chains.json +20 -0
- package/packs/base/checks/no-code-after-midline-comment.json +12 -0
- package/packs/base/checks/one-walk-per-template.json +23 -0
- package/packs/base/checks/stub-reports-success.json +31 -0
- package/packs/base/checks/test-skip-on-failed-setup.json +17 -0
- package/packs/base/hooks/brief-guard.mjs +96 -0
- package/packs/base/hooks/code-shape.mjs +95 -0
- package/packs/base/hooks/dispatch-once.mjs +87 -0
- package/packs/base/hooks/file-size-guard.mjs +61 -0
- package/packs/base/hooks/folder-law.mjs +74 -0
- package/packs/base/hooks/git-guard.mjs +289 -0
- package/packs/base/hooks/lesson-checks.mjs +174 -0
- package/packs/base/hooks/lib/apply-edit.mjs +20 -0
- package/packs/base/hooks/lib/code-shapes.mjs +137 -0
- package/packs/base/hooks/lib/content.mjs +14 -0
- package/packs/base/hooks/lib/cpp-scan.mjs +94 -0
- package/packs/base/hooks/lib/dup-index.mjs +199 -0
- package/packs/base/hooks/lib/dup.mjs +127 -0
- package/packs/base/hooks/lib/elements.mjs +87 -0
- package/packs/base/hooks/lib/event-log.mjs +67 -0
- package/packs/base/hooks/lib/function-shapes.mjs +90 -0
- package/packs/base/hooks/lib/git-adds.mjs +20 -0
- package/packs/base/hooks/lib/git-guard-selftest.mjs +99 -0
- package/packs/base/hooks/lib/glob.mjs +33 -0
- package/packs/base/hooks/lib/hook-log.mjs +100 -0
- package/packs/base/hooks/lib/house.py +77 -0
- package/packs/base/hooks/lib/languages.mjs +66 -0
- package/packs/base/hooks/lib/layout.mjs +54 -0
- package/packs/base/hooks/lib/making-check-selftest.mjs +109 -0
- package/packs/base/hooks/lib/near-copies.mjs +76 -0
- package/packs/base/hooks/lib/program-read.mjs +196 -0
- package/packs/base/hooks/lib/program-writes.mjs +177 -0
- package/packs/base/hooks/lib/project.mjs +81 -0
- package/packs/base/hooks/lib/prose.mjs +11 -0
- package/packs/base/hooks/lib/pushed.mjs +201 -0
- package/packs/base/hooks/lib/repo-index.mjs +52 -0
- package/packs/base/hooks/lib/secret-patterns.mjs +18 -0
- package/packs/base/hooks/lib/selftest.mjs +45 -0
- package/packs/base/hooks/lib/shape-code.mjs +126 -0
- package/packs/base/hooks/lib/shape.mjs +294 -0
- package/packs/base/hooks/lib/shell-writes-selftest.mjs +65 -0
- package/packs/base/hooks/lib/shell-writes.mjs +293 -0
- package/packs/base/hooks/lib/turn.mjs +81 -0
- package/packs/base/hooks/lib/writes.mjs +71 -0
- package/packs/base/hooks/making-check.mjs +243 -0
- package/packs/base/hooks/making.mjs +106 -0
- package/packs/base/hooks/once-only.mjs +150 -0
- package/packs/base/hooks/placement-law.mjs +84 -0
- package/packs/base/hooks/repo-litter.mjs +75 -0
- package/packs/base/hooks/reuse-hint.mjs +75 -0
- package/packs/base/hooks/run-hooks.mjs +132 -0
- package/packs/base/hooks/secrets-guard.mjs +99 -0
- package/packs/base/hooks/shape-law.mjs +133 -0
- package/packs/base/hooks/suite-once.mjs +80 -0
- package/packs/base/hooks/template-law.mjs +148 -0
- package/packs/base/hooks/untrusted-boundary.mjs +53 -0
- package/packs/base/pack.json +214 -0
- package/packs/base/rules/a-control-is-seen-to-fire.md +27 -0
- package/packs/base/rules/behaviour-lives-with-its-kind.md +51 -0
- package/packs/base/rules/bug-fix-starts-red.md +25 -0
- package/packs/base/rules/field-map-over-if-runs.md +47 -0
- package/packs/base/rules/finished-work-lands.md +17 -0
- package/packs/base/rules/git-right-first-time.md +19 -0
- package/packs/base/rules/instances-by-index-identities-by-id.md +54 -0
- package/packs/base/rules/lookup-over-if-chains.md +49 -0
- package/packs/base/rules/making-line-first.md +14 -0
- package/packs/base/rules/open-items-tagged.md +17 -0
- package/packs/base/rules/plan-and-logs.md +22 -0
- package/packs/base/rules/references-use-anchors.md +19 -0
- package/packs/base/rules/refusals-are-judged.md +18 -0
- package/packs/base/rules/reuse-before-writing.md +15 -0
- package/packs/base/rules/secrets-never-committed.md +16 -0
- package/packs/base/rules/skill-writing.md +23 -0
- package/packs/base/rules/split-before-the-limit.md +14 -0
- package/packs/base/rules/subagent-dispatch.md +26 -0
- package/packs/base/rules/test-only-what-changed.md +17 -0
- package/packs/base/rules/test-the-template-once.md +22 -0
- package/packs/base/rules/untrusted-content-boundary.md +15 -0
- package/packs/base/skills/add-lesson-check/SKILL.md +26 -0
- package/packs/base/skills/fix-from-scan/SKILL.md +25 -0
- package/packs/base/skills/land-branch/SKILL.md +24 -0
- package/packs/base/skills/make-it-a-template/SKILL.md +23 -0
- package/packs/base/skills/pdf-to-md/SKILL.md +25 -0
- package/packs/base/skills/pick-tests/SKILL.md +20 -0
- package/packs/base/skills/pressure-test-skill/SKILL.md +23 -0
- package/packs/base/skills/prove-instances-identical/SKILL.md +37 -0
- package/packs/base/tools/shape-symmetry-selftest.mjs +66 -0
- package/packs/base/tools/shape-symmetry.mjs +178 -0
- package/packs/base/tools/test-verdict.mjs +75 -0
- package/packs/ci/checks/ci-permissions-stated.json +18 -0
- package/packs/ci/checks/ci-tools-pinned.json +14 -0
- package/packs/ci/pack.json +21 -0
- package/packs/ci/rules/ci-covers-what-ships.md +20 -0
- package/packs/ci/rules/generated-files-have-no-diff.md +15 -0
- package/packs/content-site/checks/captcha-is-not-constant.json +27 -0
- package/packs/content-site/checks/img-has-size.json +20 -0
- package/packs/content-site/checks/page-head-complete.json +26 -0
- package/packs/content-site/pack.json +22 -0
- package/packs/content-site/rules/content-has-one-source.md +23 -0
- package/packs/content-site/rules/media-is-sized.md +24 -0
- package/packs/content-site/rules/page-head-is-complete.md +26 -0
- package/packs/content-site/rules/public-forms-are-defended.md +27 -0
- package/packs/content-site/skills/publish-a-page/SKILL.md +21 -0
- package/packs/cpp/checks/cpp-clamp-before-cast.json +16 -0
- package/packs/cpp/checks/cpp-find-with-the-library.json +12 -0
- package/packs/cpp/checks/cpp-hardened-test-build.json +18 -0
- package/packs/cpp/checks/cpp-m-pi-not-standard.json +23 -0
- package/packs/cpp/checks/cpp-no-atoi.json +16 -0
- package/packs/cpp/checks/cpp-no-const-cast.json +16 -0
- package/packs/cpp/checks/cpp-no-float-loop-counter.json +16 -0
- package/packs/cpp/checks/cpp-no-getenv-in-product.json +22 -0
- package/packs/cpp/checks/cpp-no-mutable-global.json +20 -0
- package/packs/cpp/checks/cpp-no-mutable-local-static.json +23 -0
- package/packs/cpp/checks/cpp-no-unchecked-fwrite.json +17 -0
- package/packs/cpp/checks/cpp-no-using-namespace-in-header.json +19 -0
- package/packs/cpp/checks/cpp-no-zero-size-array.json +23 -0
- package/packs/cpp/checks/cpp-numbers-pi.json +16 -0
- package/packs/cpp/pack.json +22 -0
- package/packs/cpp/rules/cpp-absent-and-failed-are-types.md +24 -0
- package/packs/cpp/rules/cpp-builds-everywhere.md +26 -0
- package/packs/cpp/rules/cpp-faults-only-in-the-test-build.md +21 -0
- package/packs/cpp/rules/cpp-find-with-the-library.md +19 -0
- package/packs/cpp/rules/cpp-gates-share-one-reader.md +22 -0
- package/packs/cpp/rules/cpp-headers-declare.md +22 -0
- package/packs/cpp/rules/cpp-numbers-and-casts.md +22 -0
- package/packs/cpp/rules/cpp-repeats-become-templates.md +33 -0
- package/packs/cpp/rules/cpp-static-analysis-runs.md +22 -0
- package/packs/cpp/rules/cpp-thread-contracts-are-code.md +23 -0
- package/packs/cpp/skills/cpp-extract-template/SKILL.md +38 -0
- package/packs/docker/checks/alpine-with-native-build.json +13 -0
- package/packs/docker/checks/compose-db-needs-auth.json +14 -0
- package/packs/docker/checks/compose-image-pinned.json +14 -0
- package/packs/docker/checks/compose-no-hardcoded-ip.json +12 -0
- package/packs/docker/checks/compose-no-host-bind-for-data.json +18 -0
- package/packs/docker/checks/compose-no-plaintext-secret.json +13 -0
- package/packs/docker/checks/compose-no-swarm-ignored-keys.json +13 -0
- package/packs/docker/checks/compose-overlay-not-bridge.json +13 -0
- package/packs/docker/checks/compose-service-needs-healthcheck.json +11 -0
- package/packs/docker/checks/compose-service-needs-init.json +11 -0
- package/packs/docker/checks/copy-needs-chown-with-user.json +17 -0
- package/packs/docker/checks/copy-source-before-deps.json +13 -0
- package/packs/docker/checks/docker-exec-form.json +16 -0
- package/packs/docker/checks/dockerfile-needs-healthcheck.json +17 -0
- package/packs/docker/checks/dockerfile-needs-user.json +21 -0
- package/packs/docker/checks/dockerignore-has-the-basics.json +21 -0
- package/packs/docker/checks/gitattributes-forces-lf.json +17 -0
- package/packs/docker/checks/health-checks-nothing.json +25 -0
- package/packs/docker/checks/no-crlf-in-scripts.json +15 -0
- package/packs/docker/checks/no-latest-base.json +13 -0
- package/packs/docker/checks/no-secret-in-image.json +13 -0
- package/packs/docker/checks/no-sensitive-file-copy.json +13 -0
- package/packs/docker/checks/node-env-before-install.json +13 -0
- package/packs/docker/checks/npm-ci-not-install.json +13 -0
- package/packs/docker/pack.json +46 -0
- package/packs/docker/rules/compose-pinned-and-closed.md +21 -0
- package/packs/docker/rules/compose-swarm-safe.md +26 -0
- package/packs/docker/rules/docker-exec-form.md +19 -0
- package/packs/docker/rules/dockerfile-multistage.md +13 -0
- package/packs/docker/rules/dockerfile-production.md +25 -0
- package/packs/docker/skills/docker-diagnose/SKILL.md +23 -0
- package/packs/dynamic-data/checks/draft-on-the-server.json +27 -0
- package/packs/dynamic-data/checks/guard-does-its-job.json +28 -0
- package/packs/dynamic-data/checks/key-is-not-a-display-name.json +28 -0
- package/packs/dynamic-data/checks/no-code-from-data.json +29 -0
- package/packs/dynamic-data/checks/no-collection-from-request.json +27 -0
- package/packs/dynamic-data/checks/no-pipeline-from-stored-text.json +27 -0
- package/packs/dynamic-data/checks/no-regexp-from-stored-config.json +27 -0
- package/packs/dynamic-data/checks/no-template-from-stored-text.json +27 -0
- package/packs/dynamic-data/checks/save-takes-named-paths.json +27 -0
- package/packs/dynamic-data/pack.json +23 -0
- package/packs/dynamic-data/rules/a-list-is-a-saved-query.md +23 -0
- package/packs/dynamic-data/rules/definitions-are-validated-data.md +24 -0
- package/packs/dynamic-data/rules/every-dynamic-surface-has-a-boundary.md +29 -0
- package/packs/dynamic-data/rules/fields-have-owners.md +22 -0
- package/packs/dynamic-data/rules/imports-drop-nothing.md +26 -0
- package/packs/dynamic-data/rules/one-definition-many-surfaces.md +24 -0
- package/packs/dynamic-data/rules/one-fact-one-place.md +28 -0
- package/packs/dynamic-data/rules/rules-live-in-the-engine.md +29 -0
- package/packs/dynamic-data/rules/saves-are-patches.md +28 -0
- package/packs/dynamic-data/rules/tenant-costs-one-document.md +22 -0
- package/packs/dynamic-data/skills/design-a-definition/SKILL.md +24 -0
- package/packs/fastify/checks/api-routes-versioned.json +28 -0
- package/packs/fastify/checks/cookie-host-prefix.json +24 -0
- package/packs/fastify/checks/hijack-needs-try.json +28 -0
- package/packs/fastify/checks/no-cast-at-route-boundary.json +24 -0
- package/packs/fastify/checks/no-db-in-route-file.json +28 -0
- package/packs/fastify/checks/no-err-message-to-client.json +24 -0
- package/packs/fastify/checks/no-regexp-from-input.json +24 -0
- package/packs/fastify/checks/no-trust-proxy-true.json +25 -0
- package/packs/fastify/checks/one-error-body.json +26 -0
- package/packs/fastify/checks/origin-from-config-not-host.json +31 -0
- package/packs/fastify/checks/password-needs-slow-hash.json +30 -0
- package/packs/fastify/checks/sec-headers-present.json +28 -0
- package/packs/fastify/checks/secrets-compared-constant-time.json +24 -0
- package/packs/fastify/checks/sse-needs-error-listener.json +28 -0
- package/packs/fastify/checks/user-bytes-need-disposition.json +29 -0
- package/packs/fastify/pack.json +41 -0
- package/packs/fastify/rules/credentials-and-input.md +23 -0
- package/packs/fastify/rules/security-one-switch.md +28 -0
- package/packs/fastify/rules/streams-and-hijacks.md +22 -0
- package/packs/fastify/rules/tests-use-inject.md +13 -0
- package/packs/fastify/rules/three-layers.md +20 -0
- package/packs/fastify/rules/trust-config-not-headers.md +24 -0
- package/packs/full-stack/checks/no-express-no-vite.json +23 -0
- package/packs/full-stack/hooks/stack-guard.mjs +90 -0
- package/packs/full-stack/pack.json +76 -0
- package/packs/full-stack/rules/stack-is-fastify-and-nextjs.md +20 -0
- package/packs/go/checks/go-exec-result-ignored.json +15 -0
- package/packs/go/checks/go-unmarshal-error-ignored.json +15 -0
- package/packs/go/pack.json +21 -0
- package/packs/go/rules/go-errors-are-handled.md +22 -0
- package/packs/gpu-painter/checks/dawn-backends-and-validation.json +9 -0
- package/packs/gpu-painter/checks/dawn-no-spontaneous.json +10 -0
- package/packs/gpu-painter/checks/dawn-present-on-render-thread.json +17 -0
- package/packs/gpu-painter/checks/gpu-no-frame-stalls.json +12 -0
- package/packs/gpu-painter/checks/no-opengl-link.json +11 -0
- package/packs/gpu-painter/checks/no-opengl.json +13 -0
- package/packs/gpu-painter/hooks/browser-guard.py +196 -0
- package/packs/gpu-painter/pack.json +91 -0
- package/packs/gpu-painter/rules/dawn-build-and-shaders.md +27 -0
- package/packs/gpu-painter/rules/dawn-device-and-render-thread.md +26 -0
- package/packs/gpu-painter/rules/gpu-antialiasing.md +20 -0
- package/packs/gpu-painter/rules/gpu-blend-order.md +22 -0
- package/packs/gpu-painter/rules/gpu-bloom.md +20 -0
- package/packs/gpu-painter/rules/gpu-frame-budget.md +25 -0
- package/packs/gpu-painter/rules/gpu-frame-pacing-and-power.md +27 -0
- package/packs/gpu-painter/rules/gpu-frame-work.md +30 -0
- package/packs/gpu-painter/rules/gpu-golden-images.md +21 -0
- package/packs/gpu-painter/rules/gpu-hdr-and-tonemap.md +23 -0
- package/packs/gpu-painter/rules/gpu-picking-on-cpu.md +19 -0
- package/packs/gpu-painter/rules/gpu-render-lifecycle.md +25 -0
- package/packs/gpu-painter/rules/gpu-text-atlas.md +24 -0
- package/packs/gpu-painter/rules/gpu-travellers-from-snapshot.md +24 -0
- package/packs/gpu-painter/rules/hover-every-pressable.md +25 -0
- package/packs/gpu-painter/skills/gpu-capture/SKILL.md +15 -0
- package/packs/gpu-painter/skills/gpu-frame-bench/SKILL.md +14 -0
- package/packs/gpu-painter/skills/gpu-golden-check/SKILL.md +13 -0
- package/packs/gpu-painter/skills/gpu-golden-update/SKILL.md +16 -0
- package/packs/gpu-painter/skills/gpu-lifecycle-stress/SKILL.md +15 -0
- package/packs/gpu-painter/skills/hover-state/SKILL.md +33 -0
- package/packs/hook-proof/checks/hook-catch-must-not-allow.json +16 -0
- package/packs/hook-proof/checks/hook-command-no-pipe.json +16 -0
- package/packs/hook-proof/checks/hook-exit-1-does-not-block.json +17 -0
- package/packs/hook-proof/checks/hook-no-or-true.json +18 -0
- package/packs/hook-proof/checks/hook-refusal-on-stderr.json +17 -0
- package/packs/hook-proof/pack.json +38 -0
- package/packs/hook-proof/rules/a-refusal-is-exit-2.md +28 -0
- package/packs/hook-proof/skills/prove-a-hook/SKILL.md +21 -0
- package/packs/host-agent/checks/file-path-from-param.json +27 -0
- package/packs/host-agent/checks/integrity-check-optional.json +27 -0
- package/packs/host-agent/checks/quoted-value-into-config.json +24 -0
- package/packs/host-agent/checks/secret-on-argv.json +28 -0
- package/packs/host-agent/checks/ssh-verifies-host-key.json +27 -0
- package/packs/host-agent/checks/system-file-written-in-place.json +26 -0
- package/packs/host-agent/checks/tmp-path-predictable.json +27 -0
- package/packs/host-agent/pack.json +22 -0
- package/packs/host-agent/rules/root-on-other-machines.md +27 -0
- package/packs/html-ui/checks/email-html-escapes.json +25 -0
- package/packs/html-ui/checks/external-link-rel.json +21 -0
- package/packs/html-ui/checks/no-duplicate-escape.json +26 -0
- package/packs/html-ui/checks/no-inline-client-script.json +21 -0
- package/packs/html-ui/checks/no-inline-style.json +23 -0
- package/packs/html-ui/pack.json +33 -0
- package/packs/html-ui/rules/email-html-escapes.md +19 -0
- package/packs/html-ui/rules/server-html-escapes-everything.md +22 -0
- package/packs/http-api/checks/api-path-versioned.json +31 -0
- package/packs/http-api/checks/authz-from-request-body.json +26 -0
- package/packs/http-api/checks/client-calls-a-version.json +28 -0
- package/packs/http-api/checks/client-ip-not-leftmost-xff.json +28 -0
- package/packs/http-api/checks/cors-needs-origin.json +26 -0
- package/packs/http-api/checks/csp-not-switched-off.json +28 -0
- package/packs/http-api/checks/debug-route-not-shipped.json +26 -0
- package/packs/http-api/checks/encrypted-name-plaintext-value.json +26 -0
- package/packs/http-api/checks/err-text-stays-server-side.json +27 -0
- package/packs/http-api/checks/failure-is-not-empty.json +28 -0
- package/packs/http-api/checks/gate-is-not-a-todo.json +27 -0
- package/packs/http-api/checks/guard-fails-open.json +28 -0
- package/packs/http-api/checks/hmac-over-reserialised-body.json +26 -0
- package/packs/http-api/checks/jwt-verify-pins-algorithm.json +26 -0
- package/packs/http-api/checks/middleware-skips-without-user.json +26 -0
- package/packs/http-api/checks/next-api-route-versioned.json +47 -0
- package/packs/http-api/checks/no-security-off-switch.json +28 -0
- package/packs/http-api/checks/oauth-state-signed.json +26 -0
- package/packs/http-api/checks/one-time-code-compared-raw.json +26 -0
- package/packs/http-api/checks/query-cast-is-not-validation.json +28 -0
- package/packs/http-api/checks/queue-action-from-client.json +26 -0
- package/packs/http-api/checks/rate-limit-one-module.json +28 -0
- package/packs/http-api/checks/role-checked-in-one-guard.json +27 -0
- package/packs/http-api/checks/route-body-needs-schema.json +31 -0
- package/packs/http-api/checks/route-scopes-to-the-caller.json +31 -0
- package/packs/http-api/checks/secret-compared-constant-time-any.json +28 -0
- package/packs/http-api/checks/secret-in-job-record.json +27 -0
- package/packs/http-api/checks/server-fetches-tenant-url.json +30 -0
- package/packs/http-api/checks/short-code-needs-limit.json +26 -0
- package/packs/http-api/checks/user-url-through-safe-fetch.json +28 -0
- package/packs/http-api/checks/webhook-dedupes-event-id.json +30 -0
- package/packs/http-api/pack.json +45 -0
- package/packs/http-api/rules/adapters-one-db-gateway.md +18 -0
- package/packs/http-api/rules/apis-are-versioned.md +27 -0
- package/packs/http-api/rules/credentials-handled-safely.md +22 -0
- package/packs/http-api/rules/handlers-own-the-work.md +17 -0
- package/packs/http-api/rules/health-and-correlation.md +17 -0
- package/packs/http-api/rules/one-error-contract.md +17 -0
- package/packs/http-api/rules/routes-are-thin.md +17 -0
- package/packs/http-api/rules/routes-scope-to-the-caller.md +26 -0
- package/packs/http-api/rules/routes-validate-and-answer.md +25 -0
- package/packs/http-api/skills/change-an-api/SKILL.md +20 -0
- package/packs/http-api/skills/secure-a-route/SKILL.md +21 -0
- package/packs/instrument-shell/checks/no-raw-struct-blob.json +23 -0
- package/packs/instrument-shell/pack.json +22 -0
- package/packs/instrument-shell/rules/fold-keeps-every-route.md +24 -0
- package/packs/instrument-shell/rules/quiet-announces-itself.md +22 -0
- package/packs/instrument-shell/rules/render-the-extremes.md +25 -0
- package/packs/instrument-shell/rules/seams-are-declared.md +27 -0
- package/packs/instrument-shell/rules/session-blob-append-only.md +25 -0
- package/packs/instrument-shell/skills/gates-from-commit-one/SKILL.md +20 -0
- package/packs/instrument-shell/skills/hit-the-painted-control/SKILL.md +18 -0
- package/packs/js-ts/checks/async-callback-unguarded.json +26 -0
- package/packs/js-ts/checks/background-loop-needs-stop.json +28 -0
- package/packs/js-ts/checks/child-process-error-handler.json +28 -0
- package/packs/js-ts/checks/entry-registers-shutdown.json +31 -0
- package/packs/js-ts/checks/fetch-needs-timeout.json +30 -0
- package/packs/js-ts/checks/job-only-in-memory.json +28 -0
- package/packs/js-ts/checks/json-only-through-helper.json +29 -0
- package/packs/js-ts/checks/line-under-200-chars.json +34 -0
- package/packs/js-ts/checks/localhost-default-in-server.json +29 -0
- package/packs/js-ts/checks/no-any.json +27 -0
- package/packs/js-ts/checks/no-cast-escape-hatches.json +24 -0
- package/packs/js-ts/checks/no-console-in-app.json +31 -0
- package/packs/js-ts/checks/no-dynamic-import-node-builtin.json +25 -0
- package/packs/js-ts/checks/no-inline-binary.json +20 -0
- package/packs/js-ts/checks/no-inline-zod-outside-schemas.json +27 -0
- package/packs/js-ts/checks/no-local-sleep.json +25 -0
- package/packs/js-ts/checks/no-nested-ternary.json +20 -0
- package/packs/js-ts/checks/no-secret-in-log.json +24 -0
- package/packs/js-ts/checks/no-shell-string-interpolation.json +24 -0
- package/packs/js-ts/checks/no-swallowed-errors.json +25 -0
- package/packs/js-ts/checks/no-ts-enum.json +20 -0
- package/packs/js-ts/checks/process-env-only-in-config.json +31 -0
- package/packs/js-ts/checks/race-leaves-work-running.json +23 -0
- package/packs/js-ts/checks/reject-as-catch-all-exists.json +24 -0
- package/packs/js-ts/checks/secret-has-no-fallback.json +24 -0
- package/packs/js-ts/checks/secret-needs-crypto-random.json +24 -0
- package/packs/js-ts/checks/server-close-awaited.json +27 -0
- package/packs/js-ts/checks/session-user-typed-once.json +24 -0
- package/packs/js-ts/checks/switch-is-a-table.json +24 -0
- package/packs/js-ts/checks/test-imports-the-source.json +19 -0
- package/packs/js-ts/checks/test-name-says-behaviour.json +16 -0
- package/packs/js-ts/checks/tsconfig-flags.json +21 -0
- package/packs/js-ts/checks/void-needs-catch.json +24 -0
- package/packs/js-ts/checks/zod-string-needs-max.json +25 -0
- package/packs/js-ts/checks/zod-v4-formats.json +23 -0
- package/packs/js-ts/pack.json +84 -0
- package/packs/js-ts/rules/await-handled-at-a-boundary.md +66 -0
- package/packs/js-ts/rules/env-through-config.md +36 -0
- package/packs/js-ts/rules/errors-never-swallowed.md +33 -0
- package/packs/js-ts/rules/files-under-300-lines.md +18 -0
- package/packs/js-ts/rules/guard-clauses-over-nesting.md +34 -0
- package/packs/js-ts/rules/js-repeats-become-templates.md +26 -0
- package/packs/js-ts/rules/json-only-through-one-helper.md +62 -0
- package/packs/js-ts/rules/named-constants-not-magic-numbers.md +34 -0
- package/packs/js-ts/rules/no-any.md +34 -0
- package/packs/js-ts/rules/no-console.md +30 -0
- package/packs/js-ts/rules/no-floating-promises.md +31 -0
- package/packs/js-ts/rules/no-param-mutation.md +28 -0
- package/packs/js-ts/rules/no-unsafe-assertions.md +30 -0
- package/packs/js-ts/rules/one-logger.md +24 -0
- package/packs/js-ts/rules/outbound-calls-have-a-limit.md +20 -0
- package/packs/js-ts/rules/parallel-independent-awaits.md +29 -0
- package/packs/js-ts/rules/process-lifecycle.md +47 -0
- package/packs/js-ts/rules/schema-single-source-of-truth.md +36 -0
- package/packs/js-ts/rules/secrets-stay-secret.md +22 -0
- package/packs/js-ts/rules/small-functions.md +20 -0
- package/packs/js-ts/rules/test-names-describe-behavior.md +28 -0
- package/packs/js-ts/rules/tests-can-fail.md +19 -0
- package/packs/js-ts/rules/tsconfig-strict.md +32 -0
- package/packs/js-ts/rules/typed-exports.md +27 -0
- package/packs/js-ts/rules/types-once-at-the-edge.md +18 -0
- package/packs/js-ts/rules/unions-over-enums.md +29 -0
- package/packs/js-ts/rules/zod-at-route-boundaries.md +40 -0
- package/packs/midi/checks/active-sensing-no-pulse.json +24 -0
- package/packs/midi/checks/clock-not-at-sample-zero.json +23 -0
- package/packs/midi/checks/midi-realtime-first.json +27 -0
- package/packs/midi/checks/no-tempo-writeback.json +23 -0
- package/packs/midi/checks/position-not-integrated.json +25 -0
- package/packs/midi/checks/stub-playhead-advances.json +27 -0
- package/packs/midi/checks/sysex-length-literal.json +23 -0
- package/packs/midi/checks/sysex-not-on-audio.json +24 -0
- package/packs/midi/checks/sysex-survives-realtime.json +27 -0
- package/packs/midi/pack.json +22 -0
- package/packs/midi/rules/clock-is-a-pulse-stream.md +30 -0
- package/packs/midi/rules/imports-count-every-loss.md +25 -0
- package/packs/midi/rules/measure-the-clock-in-audio.md +30 -0
- package/packs/midi/rules/sync-is-a-mode.md +29 -0
- package/packs/midi/rules/sysex-is-a-record.md +29 -0
- package/packs/midi/skills/clock-probe/SKILL.md +23 -0
- package/packs/midi/skills/clock-probe/clock-law.md +417 -0
- package/packs/midi/skills/does-it-sync/SKILL.md +19 -0
- package/packs/mongo/checks/bulk-over-many.json +28 -0
- package/packs/mongo/checks/created-at-immutable.json +25 -0
- package/packs/mongo/checks/driver-outside-gateway.json +24 -0
- package/packs/mongo/checks/key-lookup-is-hashed.json +24 -0
- package/packs/mongo/checks/mongoclient-cached-and-named.json +34 -0
- package/packs/mongo/checks/mongoclient-outside-gateway.json +24 -0
- package/packs/mongo/checks/no-count-plus-one-ids.json +25 -0
- package/packs/mongo/checks/no-db-write-in-loop.json +25 -0
- package/packs/mongo/checks/no-drop-in-code.json +27 -0
- package/packs/mongo/checks/no-empty-deletemany.json +26 -0
- package/packs/mongo/checks/no-find-reads.json +26 -0
- package/packs/mongo/checks/no-input-spread-into-write.json +24 -0
- package/packs/mongo/checks/no-mongoose.json +23 -0
- package/packs/mongo/checks/no-negation-delete.json +26 -0
- package/packs/mongo/checks/no-non-null-after-findone.json +25 -0
- package/packs/mongo/checks/objectid-equals.json +26 -0
- package/packs/mongo/checks/update-then-reread.json +24 -0
- package/packs/mongo/checks/watch-not-poll.json +25 -0
- package/packs/mongo/pack.json +52 -0
- package/packs/mongo/rules/deletes-name-what-dies.md +21 -0
- package/packs/mongo/rules/driver-only-in-gateway.md +26 -0
- package/packs/mongo/rules/keys-hashed-input-picked.md +21 -0
- package/packs/mongo/rules/one-client-one-pool.md +32 -0
- package/packs/mongo/rules/reads-aggregate-writes-bulk.md +25 -0
- package/packs/mongo/rules/writes-are-atomic.md +27 -0
- package/packs/multi-tenant/checks/role-sees-all-tenants.json +26 -0
- package/packs/multi-tenant/checks/tenant-filter-from-url.json +25 -0
- package/packs/multi-tenant/pack.json +22 -0
- package/packs/multi-tenant/rules/no-role-crosses-a-tenant.md +21 -0
- package/packs/multi-tenant/skills/prove-tenant-isolation/SKILL.md +19 -0
- package/packs/nginx/checks/modsec-no-blanket-off.json +16 -0
- package/packs/nginx/checks/nginx-csp-no-unsafe.json +15 -0
- package/packs/nginx/checks/nginx-headers-always.json +15 -0
- package/packs/nginx/checks/nginx-keepalive-http11.json +20 -0
- package/packs/nginx/checks/nginx-logs-to-stdout.json +15 -0
- package/packs/nginx/checks/nginx-no-crlf.json +17 -0
- package/packs/nginx/checks/nginx-resolver-ttl.json +19 -0
- package/packs/nginx/pack.json +43 -0
- package/packs/nginx/rules/modsecurity-tuning.md +22 -0
- package/packs/nginx/rules/nginx-production.md +26 -0
- package/packs/nginx/skills/waf-rollout/SKILL.md +20 -0
- package/packs/python/checks/py-no-bare-except.json +18 -0
- package/packs/python/checks/py-no-eval.json +18 -0
- package/packs/python/checks/py-no-mutable-default.json +18 -0
- package/packs/python/checks/py-no-shell-true.json +18 -0
- package/packs/python/checks/py-no-star-import.json +18 -0
- package/packs/python/checks/py-no-swallowed-exception.json +18 -0
- package/packs/python/checks/py-none-by-is.json +18 -0
- package/packs/python/checks/py-open-with-with.json +18 -0
- package/packs/python/checks/py-requests-timeout.json +18 -0
- package/packs/python/checks/py-subprocess-output-checked.json +18 -0
- package/packs/python/checks/py-yaml-safe-load.json +18 -0
- package/packs/python/pack.json +26 -0
- package/packs/python/rules/python-errors-and-resources.md +26 -0
- package/packs/python/rules/python-repeats-become-templates.md +27 -0
- package/packs/python/skills/python-extract-template/SKILL.md +35 -0
- package/packs/react/checks/dialog-needs-role.json +28 -0
- package/packs/react/checks/effect-not-for-derived-state.json +24 -0
- package/packs/react/checks/icon-button-needs-name.json +24 -0
- package/packs/react/checks/label-needs-a-field.json +24 -0
- package/packs/react/checks/ui-failed-fetch-says-so.json +23 -0
- package/packs/react/checks/ui-ok-branch-has-an-else.json +23 -0
- package/packs/react/pack.json +20 -0
- package/packs/react/rules/react-accessible-controls.md +20 -0
- package/packs/react/rules/react-state-and-effects.md +23 -0
- package/packs/reverse-engineering/checks/ear-constant-tagged.json +23 -0
- package/packs/reverse-engineering/checks/no-default-on-distrust.json +24 -0
- package/packs/reverse-engineering/checks/no-rom-table-literal.json +29 -0
- package/packs/reverse-engineering/checks/prose-never-decides.json +22 -0
- package/packs/reverse-engineering/hooks/firmware-out-of-git.mjs +49 -0
- package/packs/reverse-engineering/pack.json +35 -0
- package/packs/reverse-engineering/rules/a-negative-names-what-was-scanned.md +19 -0
- package/packs/reverse-engineering/rules/account-every-term.md +20 -0
- package/packs/reverse-engineering/rules/addresses-name-their-space.md +21 -0
- package/packs/reverse-engineering/rules/every-law-has-a-source.md +18 -0
- package/packs/reverse-engineering/rules/findings-are-withdrawn-in-place.md +17 -0
- package/packs/reverse-engineering/rules/firmware-stays-out.md +18 -0
- package/packs/reverse-engineering/rules/names-before-code.md +19 -0
- package/packs/reverse-engineering/rules/reproduction-or-original.md +18 -0
- package/packs/reverse-engineering/rules/two-sources-before-naming.md +21 -0
- package/packs/reverse-engineering/skills/bank-census/SKILL.md +18 -0
- package/packs/reverse-engineering/skills/gather-sources/SKILL.md +21 -0
- package/packs/reverse-engineering/skills/menu-map/SKILL.md +28 -0
- package/packs/reverse-engineering/skills/names-first/SKILL.md +41 -0
- package/packs/reverse-engineering/skills/re-deliverables/SKILL.md +21 -0
- package/packs/reverse-engineering/skills/tripwire-the-law/SKILL.md +19 -0
- package/packs/reverse-engineering/tools/lib/unwrap.mjs +115 -0
- package/packs/reverse-engineering/tools/names-sweep.mjs +264 -0
- package/packs/shell/checks/sh-mktemp.json +18 -0
- package/packs/shell/checks/sh-no-backticks.json +18 -0
- package/packs/shell/checks/sh-no-eval.json +18 -0
- package/packs/shell/checks/sh-no-parse-ls.json +18 -0
- package/packs/shell/checks/sh-no-pipe-to-shell.json +18 -0
- package/packs/shell/checks/sh-no-program-in-heredoc.json +18 -0
- package/packs/shell/checks/sh-quote-arguments.json +18 -0
- package/packs/shell/checks/sh-rm-guarded.json +18 -0
- package/packs/shell/checks/sh-strict-mode.json +20 -0
- package/packs/shell/pack.json +28 -0
- package/packs/shell/rules/shell-repeats-become-templates.md +23 -0
- package/packs/shell/rules/shell-strict-and-quoted.md +27 -0
- package/packs/shell/skills/shell-extract-template/SKILL.md +32 -0
- package/packs/shell-hooks/checks/gnu-only-in-shell.json +18 -0
- package/packs/shell-hooks/checks/hook-command-anchored.json +12 -0
- package/packs/shell-hooks/checks/hook-json-by-tool.json +18 -0
- package/packs/shell-hooks/checks/no-bash-c-with-variable.json +20 -0
- package/packs/shell-hooks/pack.json +36 -0
- package/packs/shell-hooks/rules/hooks-portable-anchored-quoted.md +26 -0
- package/packs/sound-design/checks/audio-seed-fixed.json +23 -0
- package/packs/sound-design/checks/mix-is-a-crossfade.json +30 -0
- package/packs/sound-design/checks/no-hash-in-the-signal.json +30 -0
- package/packs/sound-design/checks/no-literal-key-anchor.json +30 -0
- package/packs/sound-design/checks/test-compares-a-function-with-itself.json +22 -0
- package/packs/sound-design/pack.json +22 -0
- package/packs/sound-design/rules/algorithms-are-data.md +26 -0
- package/packs/sound-design/rules/meter-before-engine.md +27 -0
- package/packs/sound-design/rules/neutral-is-exact.md +26 -0
- package/packs/sound-design/rules/test-off-the-easy-point.md +28 -0
- package/packs/sound-design/rules/unreachable-is-said.md +25 -0
- package/packs/sound-design/rules/waveforms-and-octaves.md +24 -0
- package/packs/sound-design/skills/choose-observable/SKILL.md +18 -0
- package/packs/sound-design/skills/measure-a-law/SKILL.md +18 -0
- package/packs/sound-design/skills/measure-reverb/SKILL.md +19 -0
- package/packs/sound-design/skills/spread-probe/SKILL.md +18 -0
- package/packs/stellix/checks/no-keyboard-focus.json +12 -0
- package/packs/stellix/checks/one-seeded-random.json +16 -0
- package/packs/stellix/checks/world-never-includes-painter.json +12 -0
- package/packs/stellix/checks/world-no-libm.json +15 -0
- package/packs/stellix/checks/world-no-unordered.json +10 -0
- package/packs/stellix/hooks/no-shipped-images.mjs +88 -0
- package/packs/stellix/pack.json +61 -0
- package/packs/stellix/rules/stellix-deterministic-world.md +29 -0
- package/packs/stellix/rules/stellix-reset-generated.md +24 -0
- package/packs/stellix/rules/stellix-world-snapshot.md +27 -0
- package/packs/stellix/rules/world-continuous-collision.md +26 -0
- package/packs/stellix/rules/world-fp-determinism.md +28 -0
- package/packs/stored-text/checks/no-raw-html-from-data.json +31 -0
- package/packs/stored-text/checks/stored-text-libs-only-in-renderer.json +31 -0
- package/packs/stored-text/checks/stored-text-renderer-complete.json +24 -0
- package/packs/stored-text/checks/stored-text-through-renderer.json +25 -0
- package/packs/stored-text/pack.json +41 -0
- package/packs/stored-text/rules/stored-text-renders-once.md +26 -0
- package/packs/stored-text/skills/render-stored-text/SKILL.md +24 -0
- package/packs/synth-creator/checks/timing-from-synthcore.json +24 -0
- package/packs/synth-creator/checks/ui-drawn-in-code.json +23 -0
- package/packs/synth-creator/hooks/build-guard.mjs +232 -0
- package/packs/synth-creator/hooks/build-sweep.mjs +166 -0
- package/packs/synth-creator/hooks/frozen-files.mjs +63 -0
- package/packs/synth-creator/hooks/idle-wake.mjs +90 -0
- package/packs/synth-creator/hooks/protect-vendor.mjs +174 -0
- package/packs/synth-creator/hooks/spec-lock.mjs +117 -0
- package/packs/synth-creator/hooks/stage-guard.mjs +50 -0
- package/packs/synth-creator/hooks/time-guard.mjs +292 -0
- package/packs/synth-creator/hooks/user-asks.mjs +165 -0
- package/packs/synth-creator/pack.json +136 -0
- package/packs/synth-creator/rules/copy-trees-read-only.md +25 -0
- package/packs/synth-creator/rules/debug-by-measurement.md +20 -0
- package/packs/synth-creator/rules/done-means-fresh-evidence.md +18 -0
- package/packs/synth-creator/rules/hooks-and-gates.md +21 -0
- package/packs/synth-creator/rules/long-work-in-the-background.md +16 -0
- package/packs/synth-creator/rules/timing-from-synthcore.md +16 -0
- package/packs/synth-creator/skills/build-step/SKILL.md +125 -0
- package/packs/synth-creator/skills/build-through-the-queue/SKILL.md +19 -0
- package/packs/synth-creator/tools/freeze.mjs +36 -0
- package/packs/tui/checks/tui-entry-restores-terminal.json +27 -0
- package/packs/tui/checks/tui-gates-on-tty.json +25 -0
- package/packs/tui/checks/tui-no-ris-reset.json +22 -0
- package/packs/tui/checks/tui-resize-listener-removed.json +26 -0
- package/packs/tui/checks/tui-width-is-state.json +33 -0
- package/packs/tui/pack.json +44 -0
- package/packs/tui/rules/tui-resize-and-screen.md +25 -0
- package/packs/tui/skills/build-tui/SKILL.md +21 -0
- package/packs/ui-craft/checks/ui-input-needs-autocomplete.json +23 -0
- package/packs/ui-craft/checks/ui-intl-for-dates.json +21 -0
- package/packs/ui-craft/checks/ui-no-ai-palette.json +22 -0
- package/packs/ui-craft/checks/ui-no-animate-layout.json +22 -0
- package/packs/ui-craft/checks/ui-no-assistant-palette.json +23 -0
- package/packs/ui-craft/checks/ui-no-bounce-easing.json +22 -0
- package/packs/ui-craft/checks/ui-no-custom-cursor.json +22 -0
- package/packs/ui-craft/checks/ui-no-emoji-as-ui.json +22 -0
- package/packs/ui-craft/checks/ui-no-empty-image.json +21 -0
- package/packs/ui-craft/checks/ui-no-eyebrow.json +21 -0
- package/packs/ui-craft/checks/ui-no-furniture-text.json +22 -0
- package/packs/ui-craft/checks/ui-no-gradient-text.json +22 -0
- package/packs/ui-craft/checks/ui-no-index-numbering.json +21 -0
- package/packs/ui-craft/checks/ui-no-lorem.json +22 -0
- package/packs/ui-craft/checks/ui-no-marketing-buzzword.json +22 -0
- package/packs/ui-craft/checks/ui-no-paste-block.json +21 -0
- package/packs/ui-craft/checks/ui-no-placeholder-names.json +21 -0
- package/packs/ui-craft/checks/ui-no-scroll-hijack.json +21 -0
- package/packs/ui-craft/checks/ui-no-side-tab.json +21 -0
- package/packs/ui-craft/checks/ui-no-stock-labels.json +22 -0
- package/packs/ui-craft/checks/ui-no-transition-all.json +22 -0
- package/packs/ui-craft/checks/ui-no-uppercase-table-header.json +21 -0
- package/packs/ui-craft/checks/ui-no-zebra-rows.json +22 -0
- package/packs/ui-craft/checks/ui-no-zoom-lock.json +21 -0
- package/packs/ui-craft/pack.json +43 -0
- package/packs/ui-craft/rules/apps-are-not-pages.md +26 -0
- package/packs/ui-craft/rules/data-tells-the-truth.md +26 -0
- package/packs/ui-craft/rules/dates-and-numbers.md +18 -0
- package/packs/ui-craft/rules/forms-never-fight.md +22 -0
- package/packs/ui-craft/rules/interface-copy.md +26 -0
- package/packs/ui-craft/rules/motion-is-rare.md +31 -0
- package/packs/ui-craft/rules/no-generated-look.md +37 -0
- package/packs/ui-craft/rules/page-holds-its-frame.md +28 -0
- package/packs/ui-craft/rules/page-proved-rendered.md +19 -0
- package/packs/ui-craft/rules/pictures-do-a-job.md +25 -0
- package/packs/ui-craft/rules/pointer-feedback.md +28 -0
- package/packs/ui-craft/rules/screen-answers-one-question.md +24 -0
- package/packs/ui-craft/rules/survives-real-data.md +23 -0
- package/packs/ui-craft/rules/touch-and-small-screens.md +19 -0
- package/packs/ui-craft/rules/type-space-colour.md +26 -0
- package/packs/ui-craft/rules/url-holds-the-state.md +19 -0
- package/packs/ui-craft/skills/app-screen/SKILL.md +33 -0
- package/packs/ui-craft/skills/build-from-reference/SKILL.md +28 -0
- package/packs/ui-craft/skills/chart-choice/SKILL.md +34 -0
- package/packs/ui-craft/skills/hover-state/SKILL.md +28 -0
- package/packs/ui-craft/skills/page-critique/SKILL.md +33 -0
- package/packs/ui-craft/skills/prove-page/SKILL.md +23 -0
- package/packs/ui-craft/skills/redesign-page/SKILL.md +19 -0
- package/packs/ui-craft/skills/ui-code-review/SKILL.md +22 -0
- package/packs/ui-craft/skills/write-the-page/SKILL.md +21 -0
- package/packs/ui-craft/tools/page-measure.mjs +41 -0
- package/packs/web/checks/a11y-img-needs-alt.json +26 -0
- package/packs/web/checks/a11y-no-bare-outline-none.json +21 -0
- package/packs/web/checks/a11y-no-clickable-div.json +26 -0
- package/packs/web/checks/a11y-no-positive-tabindex.json +26 -0
- package/packs/web/checks/client-no-api-key.json +29 -0
- package/packs/web/checks/client-no-browser-global-at-module-scope.json +28 -0
- package/packs/web/checks/client-no-server-import.json +31 -0
- package/packs/web/checks/client-no-window-location-nav.json +28 -0
- package/packs/web/checks/css-no-inline-style.json +30 -0
- package/packs/web/checks/ds-pages-compose-primitives.json +28 -0
- package/packs/web/checks/key-from-index.json +23 -0
- package/packs/web/checks/prodbuild-no-cdn-runtime-deps.json +21 -0
- package/packs/web/checks/prodbuild-no-dev-flags.json +21 -0
- package/packs/web/checks/prodbuild-no-remote-fonts.json +22 -0
- package/packs/web/checks/rcss-button-cursor.json +30 -0
- package/packs/web/checks/rcss-no-100vw.json +21 -0
- package/packs/web/checks/rcss-no-fixed-wide-width.json +21 -0
- package/packs/web/checks/rcss-viewport-meta.json +28 -0
- package/packs/web/checks/secret-not-in-web-storage.json +25 -0
- package/packs/web/checks/tw-no-raw-hex-in-markup.json +34 -0
- package/packs/web/checks/wp-hero-not-lazy.json +27 -0
- package/packs/web/checks/wp-img-needs-dimensions.json +26 -0
- package/packs/web/pack.json +73 -0
- package/packs/web/rules/accessibility.md +26 -0
- package/packs/web/rules/client-boundaries.md +23 -0
- package/packs/web/rules/production-build.md +22 -0
- package/packs/web/rules/secrets-not-in-the-browser.md +18 -0
- package/packs/web/rules/styles-live-in-stylesheets.md +23 -0
- package/packs/web/rules/tailwind-v4.md +23 -0
- package/packs/web/rules/ui-primitives-one-module.md +30 -0
- package/packs/web/rules/web-performance.md +21 -0
- package/packs/web/skills/design-direction/SKILL.md +30 -0
- package/packs/web/skills/design-review/SKILL.md +28 -0
- package/packs/web/skills/pick-rendering-mode/SKILL.md +21 -0
- package/packs/web/skills/preflight-build/SKILL.md +23 -0
- package/packs/web/skills/seo-audit/SKILL.md +22 -0
- package/packs/websocket/checks/no-token-in-query.json +26 -0
- package/packs/websocket/checks/stale-socket-deletes-new-entry.json +25 -0
- package/packs/websocket/checks/ws-identity-from-message.json +26 -0
- package/packs/websocket/pack.json +21 -0
- package/packs/websocket/rules/identity-comes-from-the-connection.md +24 -0
- package/packs/writing/checks/ascii-no-em-dash.json +17 -0
- package/packs/writing/checks/no-copula-dodging.json +18 -0
- package/packs/writing/checks/no-dramatic-colon.json +18 -0
- package/packs/writing/checks/no-not-x-but-y.json +18 -0
- package/packs/writing/checks/no-participial-opener.json +18 -0
- package/packs/writing/checks/no-pseudo-wisdom.json +18 -0
- package/packs/writing/checks/no-slop-words.json +18 -0
- package/packs/writing/checks/no-stock-connectors.json +18 -0
- package/packs/writing/checks/no-time-or-date.json +27 -0
- package/packs/writing/checks/no-trailing-ing.json +18 -0
- package/packs/writing/checks/no-vague-attribution.json +18 -0
- package/packs/writing/pack.json +43 -0
- package/packs/writing/rules/ascii-no-em-dash.md +21 -0
- package/packs/writing/rules/cut-the-padding.md +20 -0
- package/packs/writing/rules/direct-voice.md +22 -0
- package/packs/writing/rules/no-cargo-cult.md +16 -0
- package/packs/writing/rules/no-scaffolding.md +19 -0
- package/packs/writing/rules/no-stock-language.md +27 -0
- package/packs/writing/rules/no-time-or-date.md +18 -0
- package/packs/writing/rules/rhythm-like-talk.md +20 -0
- package/packs/writing/rules/write-from-your-own-corner.md +20 -0
- package/packs/writing/skills/argument-post/SKILL.md +28 -0
- package/packs/writing/skills/humanize/SKILL.md +28 -0
- package/packs/writing/skills/launch-post/SKILL.md +38 -0
- package/packs/writing/skills/pick-subreddit/SKILL.md +69 -0
- package/packs/writing/skills/post-voice/SKILL.md +22 -0
- package/packs/writing/skills/reddit-post/SKILL.md +63 -0
- package/packs/writing/skills/reddit-title/SKILL.md +23 -0
- package/packs/writing/skills/reply-moves/SKILL.md +40 -0
- package/packs/writing/skills/reply-stance/SKILL.md +23 -0
- package/packs/writing/skills/should-i-reply/SKILL.md +21 -0
- package/packs/zod/hooks/schemas-only.mjs +53 -0
- package/packs/zod/pack.json +44 -0
- package/packs/zod/rules/env-shapes-only.md +14 -0
- package/packs/zod/rules/zod-4-schemas.md +14 -0
- package/profiles/stellix.layout.json +315 -0
- package/profiles/sub37.layout.json +247 -0
- package/prompts/scan-review.md +40 -0
- package/prompts/survey.md +82 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "key-lookup-is-hashed",
|
|
3
|
+
"why": "One database read, backup or log then yields every customer's working credential.",
|
|
4
|
+
"rule": ".claude/rules/keys-hashed-input-picked.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"js"
|
|
7
|
+
],
|
|
8
|
+
"globs": [],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/tests/**",
|
|
11
|
+
"**/test/**",
|
|
12
|
+
"**/*.test.*",
|
|
13
|
+
"**/*.spec.*",
|
|
14
|
+
"**/e2e/**",
|
|
15
|
+
"**/node_modules/**",
|
|
16
|
+
"**/dist/**",
|
|
17
|
+
"**/build/**",
|
|
18
|
+
"**/.next/**"
|
|
19
|
+
],
|
|
20
|
+
"code": true,
|
|
21
|
+
"pattern": "\\$match:\\s*\\{\\s*(?:apiKey|token)\\b|find(?:One)?\\(\\s*\\{\\s*(?:apiKey|token)\\b",
|
|
22
|
+
"bad": "col.aggregate([{ $match: { apiKey } }]);",
|
|
23
|
+
"good": "col.aggregate([{ $match: { apiKeyHash: sha256(apiKey) } }]);"
|
|
24
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mongoclient-cached-and-named",
|
|
3
|
+
"why": "A MongoClient created without the globalThis cache stacks a new pool on every hot reload, and without appName it is anonymous in the Atlas connection view.",
|
|
4
|
+
"rule": ".claude/rules/one-client-one-pool.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**",
|
|
19
|
+
"**/scripts/**",
|
|
20
|
+
"**/migrations/**",
|
|
21
|
+
"**/seeds/**",
|
|
22
|
+
"**/bin/**"
|
|
23
|
+
],
|
|
24
|
+
"code": true,
|
|
25
|
+
"mode": "needs",
|
|
26
|
+
"pattern": "\\bnew\\s+MongoClient\\s*\\(",
|
|
27
|
+
"needs": [
|
|
28
|
+
"\\bglobalThis\\b|\\b(?:let|var)\\s+\\w*[Cc]lient\\b|\\b\\w*[Cc]lient\\s*\\?\\?=",
|
|
29
|
+
"\\bappName\\s*:",
|
|
30
|
+
"\\bmaxPoolSize\\s*:"
|
|
31
|
+
],
|
|
32
|
+
"bad": "client = new MongoClient(uri, { ignoreUndefined: true });",
|
|
33
|
+
"good": "const g = globalThis as { __mongoClient?: MongoClient };\ng.__mongoClient ??= new MongoClient(env.MONGODB_URI, { appName: env.APP_NAME, maxPoolSize: 10 });\nlet client;\nexport const getClient = () => (client ??= new MongoClient(uri, { appName: name, maxPoolSize: 10 }));\n"
|
|
34
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "mongoclient-outside-gateway",
|
|
3
|
+
"why": "A second MongoClient is a second connection pool. The client lives in the gateway (cached on globalThis) or in a one-off script, nowhere else.",
|
|
4
|
+
"rule": ".claude/rules/one-client-one-pool.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-callers"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**"
|
|
19
|
+
],
|
|
20
|
+
"code": true,
|
|
21
|
+
"pattern": "\\bnew\\s+MongoClient\\s*\\(",
|
|
22
|
+
"bad": "const client = new MongoClient(uri);",
|
|
23
|
+
"good": "const db = await getDb();"
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-count-plus-one-ids",
|
|
3
|
+
"why": "countDocuments()+1 as an id races: two concurrent creates get the same number and the unique index throws an opaque E11000. Use an $inc counter document with findOneAndUpdate.",
|
|
4
|
+
"rule": ".claude/rules/writes-are-atomic.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-scripts"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
"**/.next/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/tests/**"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "countDocuments\\s*\\([^;]*\\)\\s*\\)?\\s*\\+\\s*1\\b|\\bn\\s*\\+\\s*1\\s*\\}`|\\(await\\s+[\\w.]*countDocuments[^;]*\\)\\s*\\+\\s*1",
|
|
23
|
+
"bad": "return `WO-${(await scope.countDocuments({ kind: 'work' })) + 1}`;",
|
|
24
|
+
"good": "const c = await counters.findOneAndUpdate({ _id: `wo:${sessionId}` }, { $inc: { n: 1 } }, { upsert: true, returnDocument: 'after' });\nreturn `WO-${c.n}`;"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-db-write-in-loop",
|
|
3
|
+
"why": "A write per iteration is a round trip per iteration. Collect the ops and run one bulkWrite, or update one document with arrayFilters.",
|
|
4
|
+
"rule": ".claude/rules/writes-are-atomic.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-scripts"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
"**/.next/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/tests/**"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "\\bfor\\s*(?:await\\s*)?\\([^)]*\\)\\s*\\{[^{}]*?\\bawait\\s+[\\w.()]*\\.(?:insertOne|updateOne|deleteOne|replaceOne|findOneAndUpdate)\\s*\\(",
|
|
23
|
+
"bad": "for (const s of steps) {\n await scope.workorders.updateOne({ number }, { $set: { [`plan.$[s].status`]: 'done' } });\n}",
|
|
24
|
+
"good": "await scope.workorders.bulkWrite(steps.map((s) => ({ updateOne: { filter: { number }, update: { $set: { 'plan.$[s].status': 'done' } }, arrayFilters: [{ 's.qid': s.qid }] } })));"
|
|
25
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-drop-in-code",
|
|
3
|
+
"why": "dropDatabase()/drop() in application code is an ops runbook action with a human gate, not a script line.",
|
|
4
|
+
"rule": ".claude/rules/deletes-name-what-dies.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-scripts",
|
|
8
|
+
"db-callers"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/.next/**",
|
|
15
|
+
".claude/**",
|
|
16
|
+
"**/.claude/**",
|
|
17
|
+
"**/*.test.*",
|
|
18
|
+
"**/*.spec.*",
|
|
19
|
+
"**/test/**",
|
|
20
|
+
"**/tests/**",
|
|
21
|
+
"**/data/**"
|
|
22
|
+
],
|
|
23
|
+
"code": true,
|
|
24
|
+
"pattern": "\\.(dropDatabase|dropCollection)\\s*\\(|\\bcollection\\([^)]*\\)\\s*\\.drop\\s*\\(",
|
|
25
|
+
"bad": "await db.dropDatabase();",
|
|
26
|
+
"good": "await col.deleteMany({ sessionId });"
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-empty-deletemany",
|
|
3
|
+
"why": "deleteMany with an empty filter wipes the collection. Name what to delete; if the store upserts on a stable key, ask whether the delete is needed at all.",
|
|
4
|
+
"rule": ".claude/rules/deletes-name-what-dies.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-scripts",
|
|
8
|
+
"db-callers"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/.next/**",
|
|
15
|
+
".claude/**",
|
|
16
|
+
"**/.claude/**",
|
|
17
|
+
"**/*.test.*",
|
|
18
|
+
"**/*.spec.*",
|
|
19
|
+
"**/test/**",
|
|
20
|
+
"**/tests/**"
|
|
21
|
+
],
|
|
22
|
+
"code": true,
|
|
23
|
+
"pattern": "\\.deleteMany\\s*\\(\\s*(\\{\\s*\\})?\\s*\\)",
|
|
24
|
+
"bad": "await col.deleteMany({});",
|
|
25
|
+
"good": "await col.deleteMany({ sessionId, status: 'expired' });"
|
|
26
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-find-reads",
|
|
3
|
+
"why": "Reads are aggregation pipelines: shaping happens in the database and the pipeline is composable data. Add '// mongo: allow find' with a reason for a real exception.",
|
|
4
|
+
"rule": ".claude/rules/reads-aggregate-writes-bulk.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-scripts"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
"**/.next/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/tests/**"
|
|
20
|
+
],
|
|
21
|
+
"code": false,
|
|
22
|
+
"pattern": "^(?!.*//\\s*mongo:\\s*allow find)(?![^\\n]*\\.(?:limit|sort)\\s*\\()[^\\n]*[Cc]ollection\\b[^\\n]*\\.find\\s*\\(|^(?![^\\n]*\\.(?:limit|sort)\\s*\\()[^\\n]*\\.find\\s*\\(\\s*\\{[^\\n]*\\)\\s*\\.(?:toArray|skip)\\s*\\(",
|
|
23
|
+
"flags": "m",
|
|
24
|
+
"bad": "const docs = await collection.find({ a: 1 }).toArray();\nconst rows = await collection.find(q).toArray();\n",
|
|
25
|
+
"good": "const docs = await col.aggregate([{ $match: { a: 1 } }, { $limit: 50 }]).toArray();\nconst x = items.find((i) => i.id === id);\nconst last = await collection.find(q).sort({ at: -1 }).limit(20).toArray();\n"
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-input-spread-into-write",
|
|
3
|
+
"why": "Whatever field the server trusts later can be set by the client today.",
|
|
4
|
+
"rule": ".claude/rules/keys-hashed-input-picked.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"js"
|
|
7
|
+
],
|
|
8
|
+
"globs": [],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/tests/**",
|
|
11
|
+
"**/test/**",
|
|
12
|
+
"**/*.test.*",
|
|
13
|
+
"**/*.spec.*",
|
|
14
|
+
"**/e2e/**",
|
|
15
|
+
"**/node_modules/**",
|
|
16
|
+
"**/dist/**",
|
|
17
|
+
"**/build/**",
|
|
18
|
+
"**/.next/**"
|
|
19
|
+
],
|
|
20
|
+
"code": true,
|
|
21
|
+
"pattern": "(?:insertOne\\(|insertMany\\(|document:\\s*|\\$set:\\s*)\\{\\s*\\.\\.\\.(?:req\\.body|body|payload|input|event|data|params)\\b|\\.\\.\\.(?:req\\.body|body)\\s*,\\s*\\n\\s*\\w+At\\b|\\.map\\(\\(?(?:event|e|doc|item)\\)?\\s*=>\\s*\\(\\{\\s*\\.\\.\\.(?:event|e|item)\\s*,",
|
|
22
|
+
"bad": "await col.insertOne({ ...body, receivedAt: new Date() });",
|
|
23
|
+
"good": "await col.insertOne({ error: input.error, receivedAt: new Date() });"
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-mongoose",
|
|
3
|
+
"why": "Mongoose is not used: the native driver plus Zod is the data layer.",
|
|
4
|
+
"rule": ".claude/rules/driver-only-in-gateway.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/*.ts",
|
|
7
|
+
"**/*.js",
|
|
8
|
+
"**/*.mjs",
|
|
9
|
+
"**/package.json"
|
|
10
|
+
],
|
|
11
|
+
"exclude": [
|
|
12
|
+
"**/node_modules/**",
|
|
13
|
+
"**/dist/**",
|
|
14
|
+
"**/build/**",
|
|
15
|
+
"**/.next/**",
|
|
16
|
+
".claude/**",
|
|
17
|
+
"**/.claude/**"
|
|
18
|
+
],
|
|
19
|
+
"code": false,
|
|
20
|
+
"pattern": "[\\\"']mongoose[\\\"']",
|
|
21
|
+
"bad": "import mongoose from 'mongoose';",
|
|
22
|
+
"good": "import { MongoClient } from 'mongodb';"
|
|
23
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-negation-delete",
|
|
3
|
+
"why": "A delete filter on $ne/$nin/$not deletes everything EXCEPT one value; one wrong constant empties the store while reading as a cleanup. Name what to delete, not what to keep, and count first.",
|
|
4
|
+
"rule": ".claude/rules/deletes-name-what-dies.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-scripts",
|
|
8
|
+
"db-callers"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/.next/**",
|
|
15
|
+
".claude/**",
|
|
16
|
+
"**/.claude/**",
|
|
17
|
+
"**/*.test.*",
|
|
18
|
+
"**/*.spec.*",
|
|
19
|
+
"**/test/**",
|
|
20
|
+
"**/tests/**"
|
|
21
|
+
],
|
|
22
|
+
"code": true,
|
|
23
|
+
"pattern": "\\.delete(Many|One)\\s*\\([^)]*\\$(ne|nin|not)\\b",
|
|
24
|
+
"bad": "await col.deleteMany({ version: { $ne: current } });",
|
|
25
|
+
"good": "await col.deleteMany({ version: { $in: staleVersions } });"
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-non-null-after-findone",
|
|
3
|
+
"why": "(await findOne())! after a write turns a race (purge, archive) into a TypeError reported as INTERNAL. Return the document from findOneAndUpdate, or handle null.",
|
|
4
|
+
"rule": ".claude/rules/writes-are-atomic.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-callers"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
"**/.next/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/tests/**"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "\\(\\s*await\\s+[^()]*findOne\\s*\\((?:[^()]|\\([^()]*\\))*\\)\\s*\\)\\s*!|\\bawait\\s+[\\w.]*findOne\\s*\\((?:[^()]|\\([^()]*\\))*\\)\\s*;[^;]{0,120}?\\b(\\w+)!\\)",
|
|
23
|
+
"bad": "return (await goals.findOne({ _id: r.insertedId }))!;\nconst experiment = await scope.experiments.findOne({ _id });\nreturn { experiment: toResponse(experiment!) };",
|
|
24
|
+
"good": "const doc = await goals.findOneAndUpdate(filter, update, { upsert: true, returnDocument: 'after' });\nif (doc === null) throw new AdmiralError(ErrorCodes.NOT_FOUND, 'goal vanished');"
|
|
25
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "objectid-equals",
|
|
3
|
+
"why": "Comparing ObjectIds by toHexString() is four calls and a string compare where ObjectId.equals exists and also accepts a string.",
|
|
4
|
+
"rule": ".claude/rules/writes-are-atomic.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-callers",
|
|
8
|
+
"db-scripts"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/.next/**",
|
|
15
|
+
".claude/**",
|
|
16
|
+
"**/.claude/**",
|
|
17
|
+
"**/*.test.*",
|
|
18
|
+
"**/*.spec.*",
|
|
19
|
+
"**/test/**",
|
|
20
|
+
"**/tests/**"
|
|
21
|
+
],
|
|
22
|
+
"code": true,
|
|
23
|
+
"pattern": "toHexString\\(\\)\\s*[!=]==?\\s*[\\w.]*toHexString\\(\\)",
|
|
24
|
+
"bad": "if (o._id.toHexString() === parent._id.toHexString())",
|
|
25
|
+
"good": "if (o._id.equals(parent._id))"
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "update-then-reread",
|
|
3
|
+
"why": "updateOne followed by findOne/findOrder to return the document is two round trips where findOneAndUpdate({ returnDocument: 'after' }) is one.",
|
|
4
|
+
"rule": ".claude/rules/writes-are-atomic.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway"
|
|
7
|
+
],
|
|
8
|
+
"exclude": [
|
|
9
|
+
"**/node_modules/**",
|
|
10
|
+
"**/dist/**",
|
|
11
|
+
"**/build/**",
|
|
12
|
+
"**/.next/**",
|
|
13
|
+
".claude/**",
|
|
14
|
+
"**/.claude/**",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**"
|
|
19
|
+
],
|
|
20
|
+
"code": true,
|
|
21
|
+
"pattern": "\\.updateOne\\s*\\((?:[^()]|\\([^()]*\\))*\\)\\s*;\\s*(?:return\\s+)?(?:\\w+\\s*=\\s*)?(?:await\\s+)?[\\w.]*find(?:One|Order|Session|Message)\\s*\\(",
|
|
22
|
+
"bad": "await scope.workorders.updateOne({ number }, { $set: { status: 'sent' } });\nreturn findOrder(scope, number);",
|
|
23
|
+
"good": "return scope.workorders.findOneAndUpdate({ number }, { $set: { status: 'sent' } }, { returnDocument: 'after' });"
|
|
24
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "watch-not-poll",
|
|
3
|
+
"why": "A deadline loop that sleeps and re-queries is ~130 round trips per wait. A change stream or a findOneAndUpdate wake-up costs one.",
|
|
4
|
+
"rule": ".claude/rules/writes-are-atomic.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"db-gateway",
|
|
7
|
+
"db-callers"
|
|
8
|
+
],
|
|
9
|
+
"exclude": [
|
|
10
|
+
"**/node_modules/**",
|
|
11
|
+
"**/dist/**",
|
|
12
|
+
"**/build/**",
|
|
13
|
+
"**/.next/**",
|
|
14
|
+
".claude/**",
|
|
15
|
+
"**/.claude/**",
|
|
16
|
+
"**/*.test.*",
|
|
17
|
+
"**/*.spec.*",
|
|
18
|
+
"**/test/**",
|
|
19
|
+
"**/tests/**"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "\\bwhile\\s*\\(\\s*Date\\.now\\s*\\(\\)\\s*<[^{]*\\{[\\s\\S]{0,400}?\\bawait\\s+(?:sleep|delay|setTimeout|wait)\\s*\\(",
|
|
23
|
+
"bad": "while (Date.now() < deadline) {\n const op = await fileops.findOne({ _id });\n if (op?.status !== 'pending') return op;\n await sleep(150);\n}",
|
|
24
|
+
"good": "const stream = fileops.watch([{ $match: { 'documentKey._id': _id } }]);\nconst next = await Promise.race([stream.next(), timeout]);"
|
|
25
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mongo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MongoDB with the native driver: one client, one gateway, aggregation reads, bulkWrite writes, safe deletes.",
|
|
5
|
+
"type": "stock",
|
|
6
|
+
"author": "claude-packs",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"homepage": "https://github.com/TheDecipherist/claude-packs",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/TheDecipherist/claude-packs.git",
|
|
12
|
+
"directory": "packs/mongo"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mongodb"
|
|
16
|
+
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"claude-packs": ">=0.19.0"
|
|
19
|
+
},
|
|
20
|
+
"folders": {},
|
|
21
|
+
"concepts": {
|
|
22
|
+
"db-gateway": [
|
|
23
|
+
"**/gateway.ts",
|
|
24
|
+
"**/gateway/**",
|
|
25
|
+
"**/db/**",
|
|
26
|
+
"**/lib/db.*",
|
|
27
|
+
"**/lib/db/**",
|
|
28
|
+
"**/adapters/**",
|
|
29
|
+
"**/repositories/**",
|
|
30
|
+
"**/*.repository.*",
|
|
31
|
+
"**/*mongo*"
|
|
32
|
+
],
|
|
33
|
+
"db-scripts": [
|
|
34
|
+
"**/scripts/**",
|
|
35
|
+
"**/migrations/**",
|
|
36
|
+
"**/seeds/**",
|
|
37
|
+
"**/bin/**"
|
|
38
|
+
],
|
|
39
|
+
"db-callers": [
|
|
40
|
+
"**/routes/**",
|
|
41
|
+
"**/handlers/**",
|
|
42
|
+
"**/services/**",
|
|
43
|
+
"**/app/**",
|
|
44
|
+
"**/pages/**",
|
|
45
|
+
"**/components/**",
|
|
46
|
+
"**/ui/**",
|
|
47
|
+
"**/lifecycle/**"
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"skillsIn": null,
|
|
51
|
+
"hooks": {}
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: db-gateway, db-scripts
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# A delete names what to delete, never what to keep
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Count first: run the filter as a count or `$match` + `$count`, log the number, then delete. A delete whose match count surprises you was about to be an incident.
|
|
12
|
+
- Prefer an upsert on a stable key over a purge-and-reload: overwriting in place makes most deletes unnecessary.
|
|
13
|
+
- Identity in the filter, never in the body of a write (`_id` in `$set` after a JSON round-trip throws code 66).
|
|
14
|
+
- `_id` is an `ObjectId`. A string `_id` against an ObjectId document matches nothing, silently.
|
|
15
|
+
- `null` is not "missing": `{ f: null }` matches null **and** absent. Use `$exists: false` for missing.
|
|
16
|
+
|
|
17
|
+
Never do:
|
|
18
|
+
- `deleteMany({})` or `deleteMany()` outside test cleanup (`no-empty-deletemany` check).
|
|
19
|
+
- A delete filter built on a negation (`$ne`, `$nin`, `$not`) against a status or version field: it deletes everything except one value, and one wrong constant empties the store while reading as a cleanup (`no-negation-delete` check).
|
|
20
|
+
- `dropDatabase()` / `drop()` in application code: that is an ops runbook action with a human gate (`no-drop-in-code` check).
|
|
21
|
+
</constraints>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: db-callers
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# The driver is touched in one gateway; features import functions from it
|
|
8
|
+
|
|
9
|
+
The model writes new code by imitating the imports it sees. One obvious gateway gets reused; a scattered one gets reinvented, and with it the session scoping, the id rehydration and the error mapping that the gateway was built to centralise.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Reach the database only by importing a named function from the gateway (`findSessionById`, `appendActivity`). New collection, new query shape: **a new function in the gateway**, never a driver call at the call site.
|
|
14
|
+
- Keep the gateway's header contract (five lines, at the top of its entry module) so whoever extends it reads the rules at that moment:
|
|
15
|
+
```ts
|
|
16
|
+
// DATABASE GATEWAY: the ONLY module that touches the driver.
|
|
17
|
+
// Features import query/write functions from here; no MongoClient or db.collection() anywhere else.
|
|
18
|
+
// Reads are aggregation pipelines; multi-doc writes go through bulkWrite.
|
|
19
|
+
// New collection => new function here. Rule: driver-only-in-gateway.
|
|
20
|
+
```
|
|
21
|
+
- Rehydrate at the boundary: JSON turns `ObjectId` and `Date` into strings; the gateway function takes a string id and wraps it with `new ObjectId(id)` itself.
|
|
22
|
+
|
|
23
|
+
Never do:
|
|
24
|
+
- `MongoClient`, `db.collection(`, `getDb()` in routes, handlers, services, UI or lifecycle code. The `driver-outside-gateway` check refuses them. The gateway's **typed scope** (`forSession(id).experiments.insertOne(...)`) is its exported surface and is fine to call; a raw `Collection` is not.
|
|
25
|
+
- Pass a raw `Collection` out of the gateway "just this once".
|
|
26
|
+
</constraints>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: js
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Keys are matched by hash, and a stored document is built from named fields
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Look up API keys and tokens by their hash.
|
|
12
|
+
- Build a stored document from the fields you name.
|
|
13
|
+
- Make a filter sanitiser throw on what it cannot pass: one that drops a condition widens the query.
|
|
14
|
+
- Put a limit on every list read.
|
|
15
|
+
|
|
16
|
+
Never do:
|
|
17
|
+
- Spread a request object into a write.
|
|
18
|
+
</constraints>
|
|
19
|
+
|
|
20
|
+
## Check
|
|
21
|
+
`key-lookup-is-hashed`, `no-input-spread-into-write`.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: db-gateway, db-scripts
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# One MongoClient per process: it IS the pool
|
|
8
|
+
|
|
9
|
+
The client owns the connection pool (`maxPoolSize`, default 100 per server). A second client is a second pool. Five clients at defaults can claim a free Atlas cluster's whole 500-connection budget before one query runs, and `client.close()` per request does not help: it adds a full TCP/TLS/auth handshake per request and pools still overlap under load.
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Create the client **once, in the gateway**, cached on `globalThis`, because hot reload (Next.js dev, tsx watch) re-runs module scope and a plain module-level client stacks a new pool per save:
|
|
14
|
+
```ts
|
|
15
|
+
const g = globalThis as { __mongoClient?: MongoClient };
|
|
16
|
+
export function mongoClient(): MongoClient {
|
|
17
|
+
g.__mongoClient ??= new MongoClient(env.MONGODB_URI, { appName: env.APP_NAME, maxPoolSize: env.MONGO_POOL_SIZE, ignoreUndefined: true });
|
|
18
|
+
return g.__mongoClient;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
- Set `appName`: it tags every connection in the Atlas dashboard, so "who is eating our connections" becomes a lookup.
|
|
22
|
+
- Set `maxPoolSize` on purpose. The real ceiling is pool size × running instances, and that product must fit under the cluster's connection limit. Serverless and Next.js route handlers: 5–10.
|
|
23
|
+
- URI from the config module only (`env-through-config`). **Never log, print or paste it.**
|
|
24
|
+
- Export `closeDb()` from the gateway and call it from the process lifecycle **after** the HTTP server has closed (`process-lifecycle` in js-ts). Nowhere else closes the client.
|
|
25
|
+
- One-off scripts, seeds and migrations: connect, work, `close()`, exit. That is the one place connect-work-close is right, because the process ends.
|
|
26
|
+
|
|
27
|
+
Never do:
|
|
28
|
+
- `new MongoClient` outside the gateway or a script. The `mongoclient-outside-gateway` check refuses it.
|
|
29
|
+
- `new MongoClient` in the gateway without `globalThis` and `appName`. The `mongoclient-cached-and-named` check refuses it.
|
|
30
|
+
- `client.close()` after a query, in a route, or in a `finally` of request code.
|
|
31
|
+
- `connect()` lazily inside a request handler: connect at startup so the first request is not the one that discovers a bad URI.
|
|
32
|
+
</constraints>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: db-gateway, db-scripts
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Reads shape and bound in the database; multi-document writes are one bulkWrite
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Read with `.aggregate([{ $match }, { $sort }, { $limit }, { $project }])`: the shaping happens in the database and the pipeline is data you can log, test and compose. `Array.prototype.find` on a plain array is fine; `collection.find()` is not.
|
|
12
|
+
- Paginate by keyset: `$match: { sortKey: { $gt: last }, ... }` on an indexed sort with `_id` as tie-breaker. `$skip` rescans everything before the page.
|
|
13
|
+
- Build the ops in the loop, run **one** `bulkWrite` after it. Never a database call inside a loop.
|
|
14
|
+
- Make writes idempotent (stable keys, set-to-value over blind `$inc`) so a retry is safe. After a partial `bulkWrite` failure retry only the failed ops (`writeErrors[].index`).
|
|
15
|
+
- Upsert is `updateOne(filter, { $set, $setOnInsert }, { upsert: true })` paired with a unique index. Uniqueness is the index, never check-then-insert: the race window is real traffic.
|
|
16
|
+
- Independent queries go in one `Promise.all` (`parallel-independent-awaits`).
|
|
17
|
+
- `createIndex` runs in a deploy or startup step, never in request code.
|
|
18
|
+
- Count with `estimatedDocumentCount` for "roughly how many"; `countDocuments` only when a filter demands it.
|
|
19
|
+
|
|
20
|
+
Never do:
|
|
21
|
+
- An unbounded `collection.find(` (`no-find-reads` check): a `find` with `.sort()` or `.limit()` in the database is fine; anything that joins or reshapes is a pipeline. Add `// mongo: allow find` with the reason for the rare exception.
|
|
22
|
+
- `insertMany` / `updateMany` / `deleteMany` as the multi-document write path (`bulk-over-many` check). `deleteMany` stays for test cleanup.
|
|
23
|
+
- `$skip` for pagination; an unanchored `$regex` (it forces a collection scan; anchor with `^`).
|
|
24
|
+
- `findOne` then `insertOne` as a uniqueness check.
|
|
25
|
+
</constraints>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: db-gateway
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# A write is one atomic operation; what spans collections is a transaction
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- A counter is `findOneAndUpdate({ _id: key }, { $inc: { n: 1 } }, { upsert: true, returnDocument: 'after' })`, never `countDocuments() + 1` (`no-count-plus-one-ids`): two concurrent creates get the same number, and the count is wrong after the first delete.
|
|
12
|
+
- A conditional update puts the condition **in the filter** (`{ _id, 'budget.max_turns': { $lt: value } }`), never read → check in JS → write (`no-read-merge-write`).
|
|
13
|
+
- Update-and-return is one `findOneAndUpdate(..., { returnDocument: 'after' })`, not `updateOne` then `findOne` (`update-then-reread`).
|
|
14
|
+
- Writes to two or more collections that must succeed together run inside `session.withTransaction(...)` (the replica set is already there), and the transaction body is idempotent so a retry is safe.
|
|
15
|
+
- Uniqueness is a (partial) unique index: `{ name: 1 }` with `partialFilterExpression: { deleted: false }` lets a soft-deleted name be reused and still blocks live duplicates.
|
|
16
|
+
- Every field a query filters or sorts on is in `indexes.ts`, compound indexes start with the chain key (`session_id`), and GridFS `*.files` metadata queries are indexed too.
|
|
17
|
+
- Driver errors are mapped **in the gateway** to typed app errors: E11000 → `CONFLICT`, code 121 → `VALIDATION`; nobody upstream sees a `MongoServerError`.
|
|
18
|
+
- A changed `facts`/payload from outside is parsed with Zod before it is used (`facts-validated-by-zod`); `as GateResult[]` is not validation.
|
|
19
|
+
|
|
20
|
+
Never do:
|
|
21
|
+
- `insertOne`/`updateOne` inside a `for` loop (`no-db-write-in-loop`): collect ops, one `bulkWrite` (or `arrayFilters` for one document).
|
|
22
|
+
- `$set: { created_at: … }` on an existing document (`created-at-immutable`): add `queued_at` for re-sorting.
|
|
23
|
+
- `a.toHexString() === b.toHexString()` (`objectid-equals`): `a.equals(b)`.
|
|
24
|
+
- `while (Date.now() < deadline) { …; await sleep(150) }` against the database (`watch-not-poll`): a change stream or a `findOneAndUpdate` wake-up.
|
|
25
|
+
- `(await col.findOne(...))!` right after a write (`no-non-null-after-findone`): return the document from the write.
|
|
26
|
+
- `.find(...)` then `.filter(...)` in JS: the `$nin`/`$match` belongs in the query.
|
|
27
|
+
</constraints>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "role-sees-all-tenants",
|
|
3
|
+
"why": "A role inside a tenant must never decide a query across tenants.",
|
|
4
|
+
"rule": ".claude/rules/no-role-crosses-a-tenant.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/*.ts",
|
|
7
|
+
"**/*.js",
|
|
8
|
+
"**/*.mjs",
|
|
9
|
+
"**/*.cjs"
|
|
10
|
+
],
|
|
11
|
+
"exclude": [
|
|
12
|
+
"**/tests/**",
|
|
13
|
+
"**/test/**",
|
|
14
|
+
"**/*.test.*",
|
|
15
|
+
"**/*.spec.*",
|
|
16
|
+
"**/e2e/**",
|
|
17
|
+
"**/node_modules/**",
|
|
18
|
+
"**/dist/**",
|
|
19
|
+
"**/build/**",
|
|
20
|
+
"**/.next/**"
|
|
21
|
+
],
|
|
22
|
+
"pattern": "role\\s*===\\s*(?:UserRole\\.)?['\"]?[Oo]wner['\"]?\\s*\\?\\s*\\[\\]|role\\s*!==\\s*(?:UserRole\\.)?['\"]?[Oo]wner['\"]?\\s*&&\\s*\\w+\\._id",
|
|
23
|
+
"bad": "const pipeline = user.role === UserRole.Owner\n ? []\n : [{ $match: { _id: id } }];",
|
|
24
|
+
"good": "const pipeline = [{ $match: { _id: new ObjectId(user.company_id) } }];",
|
|
25
|
+
"kind": "security"
|
|
26
|
+
}
|