@thedecipherist/claude-packs 0.0.0-stage → 1.1.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 +754 -0
- package/LICENSE +21 -0
- package/README.md +573 -2
- package/bin/claude-packs.mjs +212 -0
- package/configurations/base/config.json +85 -0
- package/configurations/cpp/config.json +93 -0
- package/configurations/full-stack/config.json +153 -0
- package/configurations/go/config.json +98 -0
- package/configurations/node/config.json +102 -0
- package/configurations/python/config.json +99 -0
- package/configurations/rust/config.json +106 -0
- package/configurations/synth-creator/config.json +148 -0
- package/global/hooks/gnu-shell.mjs +131 -0
- package/global/hooks/lib/shell-writes.mjs +2 -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/build-queue.mjs +22 -0
- package/lib/claude-md.mjs +60 -0
- package/lib/config-cli.mjs +36 -0
- package/lib/configs.mjs +145 -0
- package/lib/coverage.mjs +94 -0
- package/lib/custom-packs.mjs +93 -0
- package/lib/doctor.mjs +126 -0
- package/lib/fix-plan.mjs +72 -0
- package/lib/found-folders.mjs +25 -0
- package/lib/git-tokens.mjs +64 -0
- package/lib/global.mjs +125 -0
- package/lib/hook-proof.mjs +45 -0
- package/lib/hook-timing.mjs +42 -0
- package/lib/hover-gate.mjs +29 -0
- package/lib/kit-command.mjs +14 -0
- package/lib/kit-lock.mjs +149 -0
- package/lib/layout.mjs +99 -0
- package/lib/logs.mjs +109 -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 +109 -0
- package/lib/planner.mjs +59 -0
- package/lib/repeats.mjs +65 -0
- package/lib/repo-weight.mjs +28 -0
- package/lib/rule-tests.mjs +42 -0
- package/lib/rules.mjs +40 -0
- package/lib/scan-detect.mjs +130 -0
- package/lib/scan.mjs +171 -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 +31 -0
- package/lib/switches.mjs +44 -0
- package/lib/symmetry-doctor.mjs +26 -0
- package/lib/sync.mjs +133 -0
- package/lib/workorder.mjs +26 -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 +172 -0
- package/packs/audio-core/hooks/realtime-guard.mjs +67 -0
- package/packs/audio-core/pack.json +192 -0
- package/packs/audio-core/rules/a-control-is-proved-through-its-input.md +26 -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 +28 -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 +23 -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 +35 -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 +25 -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 +99 -0
- package/packs/base/hooks/dispatch-once.mjs +124 -0
- package/packs/base/hooks/file-size-guard.mjs +61 -0
- package/packs/base/hooks/folder-law.mjs +77 -0
- package/packs/base/hooks/git-guard.mjs +202 -0
- package/packs/base/hooks/lesson-checks.mjs +182 -0
- package/packs/base/hooks/lib/apply-edit.mjs +20 -0
- package/packs/base/hooks/lib/code-shapes.mjs +142 -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/crash-policy.mjs +47 -0
- package/packs/base/hooks/lib/dup-index.mjs +204 -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 +68 -0
- package/packs/base/hooks/lib/function-shapes.mjs +90 -0
- package/packs/base/hooks/lib/git-adds.mjs +21 -0
- package/packs/base/hooks/lib/git-auth.mjs +44 -0
- package/packs/base/hooks/lib/git-guard-selftest.mjs +192 -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 +69 -0
- package/packs/base/hooks/lib/layout.mjs +58 -0
- package/packs/base/hooks/lib/making-check-selftest.mjs +112 -0
- package/packs/base/hooks/lib/near-copies.mjs +76 -0
- package/packs/base/hooks/lib/program-read.mjs +199 -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/rust-scan.mjs +139 -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-lists.mjs +31 -0
- package/packs/base/hooks/lib/shape-prose.mjs +78 -0
- package/packs/base/hooks/lib/shape.mjs +273 -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 +86 -0
- package/packs/base/hooks/lib/unread-writes.mjs +24 -0
- package/packs/base/hooks/lib/writes.mjs +71 -0
- package/packs/base/hooks/making-check.mjs +248 -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 +140 -0
- package/packs/base/hooks/secrets-guard.mjs +99 -0
- package/packs/base/hooks/shape-law.mjs +140 -0
- package/packs/base/hooks/suite-once.mjs +96 -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 +19 -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 +23 -0
- package/packs/base/rules/unattended-runs.md +15 -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/new-project/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/skills/write-a-workorder/SKILL.md +41 -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 +26 -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 +29 -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/postgres/checks/pg-bind-values.json +33 -0
- package/packs/postgres/checks/pg-concurrently-in-txn.json +18 -0
- package/packs/postgres/checks/pg-fk-not-valid.json +18 -0
- package/packs/postgres/checks/pg-index-concurrently.json +18 -0
- package/packs/postgres/checks/pg-no-float-money.json +19 -0
- package/packs/postgres/checks/pg-no-money.json +18 -0
- package/packs/postgres/checks/pg-no-required-column.json +18 -0
- package/packs/postgres/checks/pg-no-volatile-default.json +18 -0
- package/packs/postgres/checks/pg-not-exists.json +18 -0
- package/packs/postgres/checks/pg-timestamptz.json +18 -0
- package/packs/postgres/hooks/db-wipe-guard.mjs +95 -0
- package/packs/postgres/pack.json +48 -0
- package/packs/postgres/rules/postgres-migrations-never-stop-traffic.md +28 -0
- package/packs/postgres/rules/postgres-one-pool-per-process.md +21 -0
- package/packs/postgres/rules/postgres-queries-are-null-safe-and-bounded.md +26 -0
- package/packs/postgres/rules/postgres-types-say-what-they-hold.md +22 -0
- package/packs/postgres/rules/postgres-values-are-bound.md +130 -0
- package/packs/postgres/skills/postgres-safe-migration/SKILL.md +45 -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 +22 -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 +22 -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/rust/checks/rust-allow-needs-reason.json +16 -0
- package/packs/rust/checks/rust-blocking-in-async.json +32 -0
- package/packs/rust/checks/rust-if-chain-is-a-match.json +32 -0
- package/packs/rust/checks/rust-static-mut.json +32 -0
- package/packs/rust/checks/rust-string-as-error.json +34 -0
- package/packs/rust/checks/rust-stub-left-in.json +32 -0
- package/packs/rust/checks/rust-unsafe-needs-safety.json +31 -0
- package/packs/rust/checks/rust-unwrap-in-library.json +34 -0
- package/packs/rust/checks/rust-wildcard-dependency.json +16 -0
- package/packs/rust/clippy.toml +5 -0
- package/packs/rust/pack.json +27 -0
- package/packs/rust/rules/rust-async-never-blocks.md +20 -0
- package/packs/rust/rules/rust-borrow-before-you-clone.md +19 -0
- package/packs/rust/rules/rust-errors-are-returned.md +22 -0
- package/packs/rust/rules/rust-lints-are-the-gate.md +23 -0
- package/packs/rust/rules/rust-repeats-become-templates.md +28 -0
- package/packs/rust/rules/rust-unsafe-is-proved.md +21 -0
- package/packs/rust/skills/rust-extract-template/SKILL.md +50 -0
- package/packs/rust/skills/rust-port/SKILL.md +22 -0
- package/packs/rust/skills/rust-review/SKILL.md +24 -0
- package/packs/rust/tools/rust-lints.toml +19 -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/bounce-a-plugin/SKILL.md +40 -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/sound-design/tools/vst3host/build.sh +73 -0
- package/packs/sound-design/tools/vst3host/host_events.h +101 -0
- package/packs/sound-design/tools/vst3host/options.h +172 -0
- package/packs/sound-design/tools/vst3host/render.cpp +245 -0
- package/packs/sound-design/tools/vst3host/session.h +241 -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 +175 -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 +21 -0
- package/packs/synth-creator/tools/buildq.mjs +74 -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
- package/prompts/workorder/PROMPT.md +53 -0
- package/prompts/workorder/run.sh +36 -0
- package/prompts/workorder/workorder.md +59 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tenant-filter-from-url",
|
|
3
|
+
"why": "A query that takes its key from the URL and carries no tenant key reads or writes any tenant.",
|
|
4
|
+
"rule": ".claude/rules/no-role-crosses-a-tenant.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/routes/**/*.ts",
|
|
7
|
+
"**/routes/**/*.js",
|
|
8
|
+
"**/app/api/**/route.ts"
|
|
9
|
+
],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/tests/**",
|
|
12
|
+
"**/test/**",
|
|
13
|
+
"**/*.test.*",
|
|
14
|
+
"**/*.spec.*",
|
|
15
|
+
"**/e2e/**",
|
|
16
|
+
"**/node_modules/**",
|
|
17
|
+
"**/dist/**",
|
|
18
|
+
"**/build/**",
|
|
19
|
+
"**/.next/**"
|
|
20
|
+
],
|
|
21
|
+
"pattern": "\\b(?:queryOne|updateOne|deleteOne|updateMany|deleteMany|findOne|findOneAndUpdate)(?:<[^(]*?>)?\\(\\s*'[\\w-]+'\\s*,\\s*\\{(?:(?!company_id|tenant_id|org_id|account_id|\\.\\.\\.)[^{}])*(?:req\\.params|\\bslug\\b)(?:(?!company_id|tenant_id|org_id|account_id|\\.\\.\\.)[^{}])*\\}",
|
|
22
|
+
"bad": "await deleteOne('companies', { slug: req.params.slug });",
|
|
23
|
+
"good": "await deleteOne('companies', { slug: req.params.slug, company_id: user.company_id });",
|
|
24
|
+
"kind": "security"
|
|
25
|
+
}
|