@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,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: ui, painter
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# A UI built from a reference matches its look, not only its layout
|
|
8
|
+
|
|
9
|
+
Stellix's layers landed flat and without glow (B-161): the analysis measured positions, the side-by-sides compared positions, no gate measured the look, and the brief said "not widget details".
|
|
10
|
+
|
|
11
|
+
<constraints>
|
|
12
|
+
Always do:
|
|
13
|
+
- Analyse the reference into numbers before drawing anything, with the `analyse-reference-look` skill: layout, colours sampled by script, type, glow and its colour and radius, surfaces and gradients, every control's parts (track, arc, pointer, ticks, value placement), and the gaps between elements.
|
|
14
|
+
- Gate the look: render off-screen at the reference's size and compare region by region (glow, colour, contrast, position, overlap) against the analysis, with a stated tolerance per measure. A knob count differs or a knob moves past tolerance: the gate fails. Plant a fault (bloom off, a value overlapping a label) and show it fail.
|
|
15
|
+
- Keep repeated components identical: one component, one size (cards, tabs, knobs). A component never shrinks to fit; the container scrolls.
|
|
16
|
+
- Keep text readable: at least 4.5 : 1 contrast for small text, measured, on every fill it can sit on.
|
|
17
|
+
- End every drawn page with the user's picture stop on the side by side. A page is not done before that.
|
|
18
|
+
|
|
19
|
+
Never do:
|
|
20
|
+
- Treat a reference drawing as "layout and control list only". Where a drawing is inconsistent with itself, the written spec picks the right version; it is never a reason to drop the look.
|
|
21
|
+
- Report a side by side as passing from positions alone.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: ui, params
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# One gesture is one undo step; host automation never enters undo
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Call `UndoManager::beginNewTransaction()` on mouse-down only. During the drag, perform actions that coalesce on the same target (`UndoableAction::createCoalescedAction`), so a whole drag undoes in one step.
|
|
12
|
+
- Make a patch load either clear the undo history or be one transaction of its own.
|
|
13
|
+
- Tell user gestures and host automation apart: only changes made inside the editor during a gesture are undoable.
|
|
14
|
+
|
|
15
|
+
Never do:
|
|
16
|
+
- Create one undo step per mouse-move event.
|
|
17
|
+
- Record host automation or modulation (pushes, orbits) as undo actions.
|
|
18
|
+
</constraints>
|
|
19
|
+
|
|
20
|
+
## Check
|
|
21
|
+
Test: drag a moon across 500 values, undo once. Pass: the value is back exactly where it started, and the transaction holds one coalesced action.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: audio
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# A stolen voice fades out; it is never cut
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- When every voice is busy, steal by a stated policy (released voices first, then the quietest, then the oldest), and fade the stolen voice over a short fixed ramp (about 1 to 5 ms) before restarting it.
|
|
12
|
+
- Reset filter and envelope state cleanly when the voice restarts, after its fade completes.
|
|
13
|
+
- Keep the voice count fixed and allocated in `prepareToPlay()`. Stealing never creates a voice.
|
|
14
|
+
|
|
15
|
+
Never do:
|
|
16
|
+
- Restart a sounding voice instantly at full level (a click on every steal).
|
|
17
|
+
- Pick the voice to steal by array index alone.
|
|
18
|
+
</constraints>
|
|
19
|
+
|
|
20
|
+
## Check
|
|
21
|
+
Test: fill all voices with held notes, play one more, and assert no sample-to-sample jump in the output exceeds the same threshold the smoothing test uses.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
# concepts: audio
|
|
3
|
+
paths:
|
|
4
|
+
- "placeholder"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 96 voices summed can never clip the output stage
|
|
8
|
+
|
|
9
|
+
<constraints>
|
|
10
|
+
Always do:
|
|
11
|
+
- Scale per-voice output for the full voice count. 96 uncorrelated voices sum about +19.8 dB above one voice (√96); phase-reset, same-note voices can sum up to +39.6 dB.
|
|
12
|
+
- Keep the gain staging before any post-sum nonlinearity independent of the number of voices playing, so the effects see the same level for one note or a chord.
|
|
13
|
+
- End the signal chain with a soft clipper or limiter at a fixed ceiling, never hard clipping or wraparound.
|
|
14
|
+
|
|
15
|
+
Never do:
|
|
16
|
+
- Normalise by the *current* number of active voices (pumping as notes start and stop).
|
|
17
|
+
</constraints>
|
|
18
|
+
|
|
19
|
+
## Check
|
|
20
|
+
Test: 96 voices, same note, phase reset, maximum resonance. Pass (house choice): the peak before the limiter is ≤ +6 dBFS and the output never exceeds the limiter ceiling.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: analyse-reference-look
|
|
3
|
+
description: Use before building or rebuilding a page, panel or layer from a reference picture or an existing panel image. Also /analyse-reference-look.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Analyse a reference picture into numbers
|
|
7
|
+
|
|
8
|
+
Write one analysis file per reference, beside it in the design reference folder. Measure by script, never by eye.
|
|
9
|
+
|
|
10
|
+
First, separate the object from the photograph. You are learning a design, to draw it flat and straight on (`straight-on-and-aligned`). List what belongs to the photograph: the camera's angle, the lens, the lighting, bends, wear and missing parts. A bend moves everything near it. Start from what is known of the object: a panel is a flat rectangle, controls of a kind are one size, what looks like a row is a row, ears mirror each other, text sits level. A measurement that disagrees with those belongs to the photograph.
|
|
11
|
+
|
|
12
|
+
1. **Layout:** every region and every control's centre and size as fractions of the picture. Then find the grid: which controls share a row or a column, which look grouped, and the one size of each kind. Snap to it, and record what the snap moved and why.
|
|
13
|
+
2. **Colour:** sample background, panels, borders, text levels, accents, lit and unlit states.
|
|
14
|
+
3. **Glow:** for every glowing part, the colour, radius and strength, measured from the falloff.
|
|
15
|
+
4. **Surfaces:** gradients, edge glow, bevels, shadows, textures.
|
|
16
|
+
5. **Type:** font, size, weight and letter spacing of every text style, and how they relate.
|
|
17
|
+
6. **Controls:** each kind's parts (track ring, value arc, pointer, ticks, cap, skirt, scale numbers) and where its label and value sit.
|
|
18
|
+
7. **Spacing:** the gaps between elements and rows, and the dividers.
|
|
19
|
+
8. **Unclear:** what the picture leaves open, or shows damaged: decide from the object, and say so.
|
|
20
|
+
|
|
21
|
+
Then list the tolerances the look gate will use for each measure, and mask what is damaged. The gate checks alignment, sizes and shared centres on their own, because a whole-picture score passes while every knob is wrong. Report the analysis file's path and the list of open items.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: copy-and-prove
|
|
3
|
+
description: Use when code is taken from another house synth (an engine, an effect, any part) into this one, when a fresh copy must be measured against its source, or when a ported part sounds different from where it came from. Also /copy-and-prove.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Copy a part, prove it, then make it yours
|
|
7
|
+
|
|
8
|
+
The canonical text is the target synth's `CLAUDE.md` (its sharing rule: which synth parts come from, and from which
|
|
9
|
+
branch) and its `docs/licences.md`. This file is the operating summary; the repo wins.
|
|
10
|
+
|
|
11
|
+
The rule: global components are LINKED (`synthcore`, `dspblocks`, `synthkit`, and the components
|
|
12
|
+
in `synthkit/components`). Everything else that comes from another synth is COPIED and becomes the new synth's own. The
|
|
13
|
+
source synth is not touched and nothing is shared with it. A project that links no global component copies those too,
|
|
14
|
+
with a licence row, like any other part.
|
|
15
|
+
|
|
16
|
+
Why the proof comes first: on MegaSynth, regrouping one multiply in a copied engine moved all 907 programs. Nobody could
|
|
17
|
+
say whether the copy or the tidy-up did it, because the copy had never been measured by itself.
|
|
18
|
+
|
|
19
|
+
## 0. Is it a copy at all?
|
|
20
|
+
|
|
21
|
+
- Already a global component, or a block in `dspblocks`? Link it. This skill does not apply.
|
|
22
|
+
- In `~/projects/synthcatalog`? Check before writing or copying a sound component.
|
|
23
|
+
- Finished and wanted by more than one synth? It may be time to make it a global component.
|
|
24
|
+
|
|
25
|
+
## 1. The licence row, before the first file moves
|
|
26
|
+
|
|
27
|
+
Write the row in the target's `docs/licences.md`: what it is, where it came from (repo, path, commit hash), its licence,
|
|
28
|
+
where it will be used. Read "the user's rulings" at the top of that file first; they say what is already allowed.
|
|
29
|
+
|
|
30
|
+
What never comes across, whatever the source:
|
|
31
|
+
|
|
32
|
+
- hardware, brand or machine names in program names, labels or strings that reach the product. Every preset and program
|
|
33
|
+
name is our own;
|
|
34
|
+
- factory preset bodies, sample data, ROM bytes, vendor artwork;
|
|
35
|
+
- anything from `~/firmware`.
|
|
36
|
+
|
|
37
|
+
Tables and numbers derived from a hardware unit but written as our own code come across only where the user has ruled so in
|
|
38
|
+
`docs/licences.md`. For any other such table, ask the user and record the answer.
|
|
39
|
+
|
|
40
|
+
Search the part and everything it includes before copying:
|
|
41
|
+
`grep -rniE "factory|firmware|korg|roland|lexicon|eventide|yamaha|\btc\b|re-201|h910|pcm ?[0-9]" <files>`
|
|
42
|
+
|
|
43
|
+
## 2. Render the source first
|
|
44
|
+
|
|
45
|
+
Build the SOURCE synth (its current trunk, read through git at a named commit) and render the part alone through its
|
|
46
|
+
probe: one fixed setting, a fresh processor, a fixed seed, at least two notes away from middle C, long enough to hold the
|
|
47
|
+
whole tail of an effect. Keep the WAV, its hash and the exact settings in the target's evidence folder. This is the
|
|
48
|
+
baseline. Build it before theorising about anything.
|
|
49
|
+
|
|
50
|
+
First assertion: render the source twice. If the two differ, find the un-reset state (grep for `static`, seeds, phases)
|
|
51
|
+
before going on. Nothing can be compared with a source that does not match itself.
|
|
52
|
+
|
|
53
|
+
## 3. Copy, changing nothing
|
|
54
|
+
|
|
55
|
+
Copy every file the part needs (follow its includes; an envelope may be two files) into a COPY TREE: a folder declared in
|
|
56
|
+
`.claude/layout.json` with `"kind": "copy"`, read-only from then on (`protect-vendor` refuses edits; only the project's
|
|
57
|
+
copy tools in `guards.copy.tools` write there). Change only what is needed to compile: namespace, include paths. No
|
|
58
|
+
renames, no tidying, no regrouped arithmetic. Give every file its origin (repo, path, commit, SHA-256, licence row). Save
|
|
59
|
+
it as its own commit: "copy of <part> from <repo>@<hash>, unchanged".
|
|
60
|
+
|
|
61
|
+
## 4. Prove it
|
|
62
|
+
|
|
63
|
+
Render the copy in the new synth with the same settings and compare:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
python3 tools/null_compare.py source.wav copy.wav
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `IDENTICAL` is the only pass. The tool prints the first sample that differs, the size of the difference and any level
|
|
70
|
+
change.
|
|
71
|
+
- It refuses two silences. A control behind a closed switch is correctly silent: open the switch.
|
|
72
|
+
- A clean 6 dB level change is nearly always a default hidden inside the module or a weight missing from a normaliser,
|
|
73
|
+
not the algorithm.
|
|
74
|
+
- A difference only in the tail is un-reset state or a different block size.
|
|
75
|
+
- `--allow-db` is for a difference the user has accepted, with the reason written in `docs/licences.md`. It is not for making
|
|
76
|
+
a red result green.
|
|
77
|
+
|
|
78
|
+
Show the gate can fail: change one coefficient in the copy, see `DIFFERENT`, put it back.
|
|
79
|
+
|
|
80
|
+
If it will not come out identical after an honest try, log it in `bugs.md` with both renders' numbers and ask. Do not
|
|
81
|
+
start reworking a copy that has not matched.
|
|
82
|
+
|
|
83
|
+
## 5. Only now, change it
|
|
84
|
+
|
|
85
|
+
A file that measured identical is promoted out of the copy tree into the project's own code (a folder of kind `"own"`)
|
|
86
|
+
with its origin record kept; only then is it changed. Rework in small saved commits (one parameter set per oscillator,
|
|
87
|
+
the synth's own rate ladder for a time grid, our own program names). After each, measure what was meant to change and
|
|
88
|
+
confirm what was not meant to change is still bit-identical. A time grid moved onto the synth's ladder is checked at 90,
|
|
89
|
+
120 and 140 BPM against absolute times, changing the tempo, not only the division.
|
|
90
|
+
|
|
91
|
+
Every module ships off, including every default inside it, and off is bit-identical to absent.
|
|
92
|
+
|
|
93
|
+
## 6. Record
|
|
94
|
+
|
|
95
|
+
- `docs/licences.md`: the row now says "measured identical on <date>, commit <hash>".
|
|
96
|
+
- The synth's tempo audit, if the part has a time in it.
|
|
97
|
+
- A lesson that would help the next synth: `~/projects/eproms/synth-design.md`.
|
|
98
|
+
- If this is a step in `build.md`, it is on that step's branch: finish it with `build-step`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: juce-realtime-audit
|
|
3
|
+
description: Use for a realtime-safety audit, after a crackle, dropout, xrun or CPU spike, or before merging changes to anything reachable from processBlock.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Realtime audit (one job: find what the audio thread can reach that it must not)
|
|
7
|
+
|
|
8
|
+
The realtime-guard hook only sees the bodies of known audio functions. This audit follows the **call graph**, which is where most real violations hide.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
1. Find every audio-thread entry point: `processBlock`, `processBlockBypassed`, `renderNextBlock`, and any `[[clang::nonblocking]]` function.
|
|
12
|
+
2. From each one, follow every call into the project's own code (voices, oscillators, filters, effects, matrix, arp). Record the chain, e.g. `processBlock → Matrix::tick → Row::advance`.
|
|
13
|
+
3. In each reached function, look for what `.claude/rules/audio-thread-realtime-safe.md` and `audio-ui-thread-handoff.md` forbid. Also look for hidden allocations:
|
|
14
|
+
- `juce::Array` / `std::vector` growth, `MidiBuffer::addEvent` past its reserved size, `AudioBuffer::setSize` / `makeCopyOf` without `avoidReallocating`
|
|
15
|
+
- `std::function` assignment, lambdas capturing by value into containers, `shared_ptr` whose last reference drops on the audio thread
|
|
16
|
+
- `ValueTree` reads or writes, `var`, `DynamicObject`
|
|
17
|
+
4. Stop at JUCE and std library calls. Judge them by the hidden-allocation list above rather than reading their source.
|
|
18
|
+
|
|
19
|
+
## Report
|
|
20
|
+
A table with columns Severity, File:line, Call chain, What, Fix. Sort it with blocking or allocating calls first. End with the list of functions that should get `[[clang::nonblocking]]`, so the hook and RealtimeSanitizer cover them from now on.
|
|
21
|
+
|
|
22
|
+
Don't change code in this skill. The report is the output.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: measure-tone
|
|
3
|
+
description: Use when an oscillator, shaper, HEAT/BIT stage, filter or effect is new or changed, or a sound is harsh, buzzy, metallic, thin or has DC.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Measure a tone (one job: put numbers on how clean a sound path is)
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
1. Render offline with the project's own render probe or test harness (CLAUDE.md, Project commands), not the live standalone: 2 s mono, 32-bit float WAV, 48 kHz.
|
|
10
|
+
- Oscillators: f0 = 110, 1000, 2000 and 4186 Hz.
|
|
11
|
+
- Nonlinear stages: sine probes at 1, 3, 5 and 7 kHz at the stated drive (add 10 kHz when rendering at 96 kHz).
|
|
12
|
+
- DC check: 1 kHz sine with +0.3 offset into the stage.
|
|
13
|
+
2. For each file run `node .claude/tools/tone-report.mjs <wav> <f0> --max-freq 15000` with the threshold for that case:
|
|
14
|
+
- oscillator: `--nonharm-max -60` up to 2 kHz, `-40` at 4186 Hz
|
|
15
|
+
- nonlinear stage: `--snr-min 45`
|
|
16
|
+
- DC: `--dc-max -80`
|
|
17
|
+
3. A deliberate crusher or vintage mode is exempt from the aliasing thresholds. Compare it against its golden file instead.
|
|
18
|
+
|
|
19
|
+
## Report
|
|
20
|
+
A table with columns Case, f0, Worst non-harmonic dB, SNR, THD, DC, and PASS/FAIL. For each FAIL, name the rule it breaks (`oscillators-bandlimited`, `nonlinear-stages-antialiased` or `dc-block-after-asymmetry`) and the likely fix. Don't change code in this skill.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: new-panel-control
|
|
3
|
+
description: Use when adding a control to a panel or page, or changing what an existing control does. Also /new-panel-control.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a panel control
|
|
7
|
+
|
|
8
|
+
1. **Use the shared piece.** Find the shared control component (knob, slider, switch, segmented button, handle) and place it. Never draw a control by hand.
|
|
9
|
+
2. **Parameter.** Append the parameter at the end of the parameter table, with a new id that never changes (`parameter-ids-never-change`). Never insert, never reuse an id.
|
|
10
|
+
3. **Wire all three links.** Drawn (on the page), bound (the control moves the parameter, and the parameter moves the control), carried (the sound changes). Check each one with `prove-control`.
|
|
11
|
+
4. **House behaviours.** Double click to default, fine drag, wheel, value readout, no keyboard focus, one undo step (`house-control-behaviours`).
|
|
12
|
+
5. **Look.** Match the page's reference: the control's parts, value placement and spacing (`ui-matches-reference-look`).
|
|
13
|
+
6. **Gates.** Run the behaviour gate, the look gate and the silent-control gate. Each must pass and must still fail on its planted fault.
|
|
14
|
+
|
|
15
|
+
Report: the parameter id, and the evidence from each step as command plus result.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prove-control
|
|
3
|
+
description: Use after adding, renaming, re-ranging or removing a control, or before calling a control's step or bug done.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Prove a control at every surface it has
|
|
7
|
+
|
|
8
|
+
## Steps
|
|
9
|
+
For the control's parameter ID, run each check through the real path and save the command plus its output as evidence. Use the project's own probes and tests (see CLAUDE.md, Project commands).
|
|
10
|
+
|
|
11
|
+
1. **Host:** set the parameter by ID in an offline render, at its minimum, default and maximum. The render must change, and a null test against default must fail where it should and pass where it should.
|
|
12
|
+
2. **Editor:** the widget is attached to that same ID. Moving it changes the parameter, and a host-set value shows in the widget with the same text as the host's value-to-text.
|
|
13
|
+
3. **Patch:** save, load and compare. The value is bit-identical, and old patches without the ID load the spec default.
|
|
14
|
+
4. **Init and reset:** the init patch and the reset action give the value the spec states.
|
|
15
|
+
5. **MIDI** (if mapped): the CC or learn moves the parameter over its full range.
|
|
16
|
+
6. **Undo:** one drag is one undo step, and host automation never enters undo.
|
|
17
|
+
7. **In the real window:** press, drag, wheel and double click one control of this template on a loaded patch (not only INIT); a table
|
|
18
|
+
read proves the same control on the other slots is that template and is wired (`test-the-template-once`). The value and the sound or picture change. A choice control (dropdown, select, menu) opens its list on a press, shows every
|
|
19
|
+
choice with the current one marked, sets the one chosen, and closes on Escape or a press outside; it never steps on a press.
|
|
20
|
+
8. **IDs:** the parameter ID list diff is empty except for the intended change (see `parameter-ids-never-change`).
|
|
21
|
+
|
|
22
|
+
## Report
|
|
23
|
+
A table with the columns Surface, Command, Result and PASS/FAIL. A surface the control doesn't have is marked N/A, with the reason. Change nothing in this skill. Fix through `bug-fix-starts-red`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: trace-parameter
|
|
3
|
+
description: Use when a control sounds wrong, reads wrong, zips, jumps or does nothing; when the display and the sound disagree; or before changing how a parameter maps to its range.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Trace one parameter from the host to the sound and the screen
|
|
7
|
+
|
|
8
|
+
This skill is read-only: it reports, and changes nothing.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
1. Name the parameter by its ID. Find its definition (parameter layout, range, skew, default, value-to-text).
|
|
12
|
+
2. Follow each hop and write down `file:line` and the exact transform at each:
|
|
13
|
+
1. host or automation value (normalized 0–1);
|
|
14
|
+
2. parameter tree, then the cached pointer (or the parameter snapshot for the block);
|
|
15
|
+
3. smoothing: which smoother, what ramp time, and is it reset in `prepareToPlay`;
|
|
16
|
+
4. the mapping to physical units (Hz, dB, ms…), and where that function lives;
|
|
17
|
+
5. per-voice or per-sample use in the DSP;
|
|
18
|
+
6. the audible result: render a short sweep of the parameter and run `measure-tone` if the sound itself is in question.
|
|
19
|
+
3. Follow the other branch: parameter → editor attachment → widget → displayed text. Write down the mapping used there.
|
|
20
|
+
4. Search for any second computation of the same value: `grep` for the parameter ID, its member name and its unit conversion.
|
|
21
|
+
|
|
22
|
+
## Report
|
|
23
|
+
A hop table with the columns Hop, `file:line`, Transform and Units. Then a list of findings, each tied to its rule:
|
|
24
|
+
- a second formula (`one-formula-per-value`);
|
|
25
|
+
- missing or wrong smoothing (`smooth-continuous-parameters`);
|
|
26
|
+
- a stepped value not snapped (`discrete-params-snap`);
|
|
27
|
+
- a lookup per block (`cached-parameter-pointers`);
|
|
28
|
+
- a unit or range mismatch;
|
|
29
|
+
- a hop that never runs.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Blackman-Harris windowed FFT analysis of a steady tone.
|
|
2
|
+
const MAX_N = 1 << 18;
|
|
3
|
+
const LOBE = 6; // bins either side of a peak treated as part of it (BH-4 main lobe is ±4)
|
|
4
|
+
const ENBW_BH4 = 2.0044; // equivalent noise bandwidth of the 4-term Blackman-Harris window, in bins
|
|
5
|
+
|
|
6
|
+
function fft(re, im) {
|
|
7
|
+
const n = re.length;
|
|
8
|
+
for (let i = 1, j = 0; i < n; i += 1) {
|
|
9
|
+
let bit = n >> 1;
|
|
10
|
+
for (; j & bit; bit >>= 1) j ^= bit;
|
|
11
|
+
j ^= bit;
|
|
12
|
+
if (i < j) {
|
|
13
|
+
[re[i], re[j]] = [re[j], re[i]];
|
|
14
|
+
[im[i], im[j]] = [im[j], im[i]];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (let len = 2; len <= n; len <<= 1) {
|
|
18
|
+
const ang = (-2 * Math.PI) / len;
|
|
19
|
+
for (let i = 0; i < n; i += len) {
|
|
20
|
+
for (let k = 0; k < len / 2; k += 1) {
|
|
21
|
+
const wr = Math.cos(ang * k);
|
|
22
|
+
const wi = Math.sin(ang * k);
|
|
23
|
+
const a = i + k;
|
|
24
|
+
const b = a + len / 2;
|
|
25
|
+
const tr = re[b] * wr - im[b] * wi;
|
|
26
|
+
const ti = re[b] * wi + im[b] * wr;
|
|
27
|
+
re[b] = re[a] - tr;
|
|
28
|
+
im[b] = im[a] - ti;
|
|
29
|
+
re[a] += tr;
|
|
30
|
+
im[a] += ti;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const db = (power) => 10 * Math.log10(Math.max(power, 1e-30));
|
|
37
|
+
|
|
38
|
+
export function analyse(samples, sampleRate, f0, maxFreq) {
|
|
39
|
+
let nonFinite = 0;
|
|
40
|
+
let peak = 0;
|
|
41
|
+
let sum = 0;
|
|
42
|
+
for (const s of samples) {
|
|
43
|
+
if (!Number.isFinite(s)) nonFinite += 1;
|
|
44
|
+
else {
|
|
45
|
+
peak = Math.max(peak, Math.abs(s));
|
|
46
|
+
sum += s;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
let n = 1;
|
|
50
|
+
while (n * 2 <= Math.min(samples.length, MAX_N)) n *= 2;
|
|
51
|
+
const start = Math.floor((samples.length - n) / 2); // skip the attack
|
|
52
|
+
const re = new Float64Array(n);
|
|
53
|
+
const im = new Float64Array(n);
|
|
54
|
+
let wsum = 0;
|
|
55
|
+
for (let i = 0; i < n; i += 1) {
|
|
56
|
+
const x = (2 * Math.PI * i) / (n - 1);
|
|
57
|
+
const w = 0.35875 - 0.48829 * Math.cos(x) + 0.14128 * Math.cos(2 * x) - 0.01168 * Math.cos(3 * x);
|
|
58
|
+
const s = samples[start + i];
|
|
59
|
+
re[i] = (Number.isFinite(s) ? s : 0) * w;
|
|
60
|
+
wsum += w;
|
|
61
|
+
}
|
|
62
|
+
fft(re, im);
|
|
63
|
+
const half = n / 2;
|
|
64
|
+
const scale = 2 / wsum;
|
|
65
|
+
const power = new Float64Array(half);
|
|
66
|
+
for (let k = 0; k < half; k += 1) power[k] = (re[k] * scale) ** 2 + (im[k] * scale) ** 2;
|
|
67
|
+
|
|
68
|
+
const binHz = sampleRate / n;
|
|
69
|
+
const lobePower = (centre) => {
|
|
70
|
+
let p = 0;
|
|
71
|
+
for (let k = Math.max(1, centre - LOBE); k <= Math.min(half - 1, centre + LOBE); k += 1) p += power[k];
|
|
72
|
+
return p;
|
|
73
|
+
};
|
|
74
|
+
const harmonicBins = [];
|
|
75
|
+
for (let h = 1; h * f0 < sampleRate / 2; h += 1) harmonicBins.push(Math.round((h * f0) / binHz));
|
|
76
|
+
const isHarmonic = new Uint8Array(half);
|
|
77
|
+
for (const b of harmonicBins) for (let k = b - LOBE; k <= b + LOBE; k += 1) if (k >= 0 && k < half) isHarmonic[k] = 1;
|
|
78
|
+
for (let k = 0; k <= LOBE; k += 1) isHarmonic[k] = 1; // DC region
|
|
79
|
+
|
|
80
|
+
const fund = lobePower(harmonicBins[0]);
|
|
81
|
+
let harmTotal = 0;
|
|
82
|
+
let thd = 0;
|
|
83
|
+
harmonicBins.forEach((b, i) => {
|
|
84
|
+
const p = lobePower(b);
|
|
85
|
+
harmTotal += p;
|
|
86
|
+
if (i >= 1 && i <= 9) thd += p;
|
|
87
|
+
});
|
|
88
|
+
let rest = 0;
|
|
89
|
+
let worst = 0;
|
|
90
|
+
let worstBin = 0;
|
|
91
|
+
const maxBin = Math.min(half - 1, Math.floor(maxFreq / binHz));
|
|
92
|
+
for (let k = 0; k < half; k += 1) {
|
|
93
|
+
if (isHarmonic[k]) continue;
|
|
94
|
+
rest += power[k];
|
|
95
|
+
if (k <= maxBin && power[k] > worst) {
|
|
96
|
+
worst = power[k];
|
|
97
|
+
worstBin = k;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
maxFreq,
|
|
102
|
+
nonFinite,
|
|
103
|
+
fundamentalDbfs: db(fund / ENBW_BH4), // summed lobe power over-reads by the window's noise bandwidth
|
|
104
|
+
thdDb: db(thd) - db(fund),
|
|
105
|
+
thdPercent: 100 * Math.sqrt(thd / Math.max(fund, 1e-30)),
|
|
106
|
+
worstNonHarmonicDb: db(worst) - db(power[harmonicBins[0]] ?? 0),
|
|
107
|
+
worstNonHarmonicHz: worstBin * binHz,
|
|
108
|
+
snrDb: db(harmTotal) - db(rest),
|
|
109
|
+
dcDbfs: 20 * Math.log10(Math.max(Math.abs(sum / Math.max(samples.length, 1)), 1e-15)),
|
|
110
|
+
peakDbfs: 20 * Math.log10(Math.max(peak, 1e-15)),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Minimal WAV reader: PCM 16/24/32-bit and IEEE float 32/64. Returns channel 0 as Float64Array.
|
|
2
|
+
export function readWav(buf) {
|
|
3
|
+
if (buf.toString('ascii', 0, 4) !== 'RIFF' || buf.toString('ascii', 8, 12) !== 'WAVE') throw new Error('not a WAV file');
|
|
4
|
+
let off = 12;
|
|
5
|
+
let fmt = null;
|
|
6
|
+
while (off + 8 <= buf.length) {
|
|
7
|
+
const id = buf.toString('ascii', off, off + 4);
|
|
8
|
+
const size = buf.readUInt32LE(off + 4);
|
|
9
|
+
const body = off + 8;
|
|
10
|
+
if (id === 'fmt ') {
|
|
11
|
+
let format = buf.readUInt16LE(body);
|
|
12
|
+
if (format === 0xfffe) format = buf.readUInt16LE(body + 24); // WAVE_FORMAT_EXTENSIBLE sub-format
|
|
13
|
+
fmt = { format, channels: buf.readUInt16LE(body + 2), sampleRate: buf.readUInt32LE(body + 4), bits: buf.readUInt16LE(body + 14) };
|
|
14
|
+
} else if (id === 'data') {
|
|
15
|
+
if (!fmt) throw new Error('data chunk before fmt chunk');
|
|
16
|
+
return { sampleRate: fmt.sampleRate, samples: decode(buf, body, Math.min(size, buf.length - body), fmt) };
|
|
17
|
+
}
|
|
18
|
+
off = body + size + (size % 2);
|
|
19
|
+
}
|
|
20
|
+
throw new Error('no data chunk');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// One reader per sample encoding: format 3 is IEEE float (64 bit, else 32), any other is integer PCM by bit depth.
|
|
24
|
+
const READERS = {
|
|
25
|
+
f32: (buf, p) => buf.readFloatLE(p),
|
|
26
|
+
f64: (buf, p) => buf.readDoubleLE(p),
|
|
27
|
+
i16: (buf, p) => buf.readInt16LE(p) / 32768,
|
|
28
|
+
i24: (buf, p) => buf.readIntLE(p, 3) / 8388608,
|
|
29
|
+
i32: (buf, p) => buf.readInt32LE(p) / 2147483648,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function decode(buf, start, size, { format, channels, bits }) {
|
|
33
|
+
const encoding = format === 3 ? (bits === 64 ? 'f64' : 'f32') : `i${bits}`;
|
|
34
|
+
if (!Object.hasOwn(READERS, encoding)) throw new Error(`unsupported bit depth ${bits}`);
|
|
35
|
+
const read = READERS[encoding]; // chosen once, not per sample
|
|
36
|
+
const bytes = bits / 8;
|
|
37
|
+
const frames = Math.floor(size / (bytes * channels));
|
|
38
|
+
const out = new Float64Array(frames);
|
|
39
|
+
for (let i = 0; i < frames; i += 1) out[i] = read(buf, start + i * bytes * channels);
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Measures a rendered test tone: fundamental level, THD, worst non-harmonic peak (aliasing),
|
|
3
|
+
// SNR, DC offset, peak, and non-finite samples. No dependencies.
|
|
4
|
+
// node tone-report.mjs <file.wav> <f0 Hz> [--max-freq 15000] [--nonharm-max -60] [--snr-min 45] [--dc-max -80] [--json]
|
|
5
|
+
// Exit 1 when a given threshold fails, so it can run as a test.
|
|
6
|
+
import { readFileSync } from 'node:fs';
|
|
7
|
+
import { readWav } from './lib/wav.mjs';
|
|
8
|
+
import { analyse } from './lib/spectrum.mjs';
|
|
9
|
+
|
|
10
|
+
function arg(name, fallback) {
|
|
11
|
+
const i = process.argv.indexOf(name);
|
|
12
|
+
return i === -1 ? fallback : Number(process.argv[i + 1]);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function main() {
|
|
16
|
+
const [file, f0Text] = process.argv.slice(2);
|
|
17
|
+
if (!file || !f0Text) {
|
|
18
|
+
console.error('usage: tone-report.mjs <file.wav> <f0> [--max-freq Hz] [--nonharm-max dB] [--snr-min dB] [--dc-max dBFS] [--json]');
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
const { sampleRate, samples } = readWav(readFileSync(file));
|
|
22
|
+
const r = analyse(samples, sampleRate, Number(f0Text), arg('--max-freq', sampleRate / 2));
|
|
23
|
+
|
|
24
|
+
const fails = [];
|
|
25
|
+
const nonharmMax = arg('--nonharm-max', null);
|
|
26
|
+
const snrMin = arg('--snr-min', null);
|
|
27
|
+
const dcMax = arg('--dc-max', null);
|
|
28
|
+
if (r.nonFinite > 0) fails.push(`${r.nonFinite} non-finite samples`);
|
|
29
|
+
if (nonharmMax !== null && r.worstNonHarmonicDb > nonharmMax) fails.push(`non-harmonic ${r.worstNonHarmonicDb.toFixed(1)} dB > ${nonharmMax}`);
|
|
30
|
+
if (snrMin !== null && r.snrDb < snrMin) fails.push(`SNR ${r.snrDb.toFixed(1)} dB < ${snrMin}`);
|
|
31
|
+
if (dcMax !== null && r.dcDbfs > dcMax) fails.push(`DC ${r.dcDbfs.toFixed(1)} dBFS > ${dcMax}`);
|
|
32
|
+
|
|
33
|
+
if (process.argv.includes('--json')) console.log(JSON.stringify({ ...r, pass: fails.length === 0, fails }));
|
|
34
|
+
else {
|
|
35
|
+
const f = (x) => (Number.isFinite(x) ? x.toFixed(1) : String(x));
|
|
36
|
+
console.log(`file ${file} (${sampleRate} Hz, ${samples.length} samples)`);
|
|
37
|
+
console.log(`fundamental ${f(r.fundamentalDbfs)} dBFS at ${f0Text} Hz`);
|
|
38
|
+
console.log(`THD (2-10) ${f(r.thdDb)} dB (${r.thdPercent.toFixed(3)} %)`);
|
|
39
|
+
console.log(`worst non-harm ${f(r.worstNonHarmonicDb)} dB re fundamental at ${f(r.worstNonHarmonicHz)} Hz (below ${f(r.maxFreq)} Hz)`);
|
|
40
|
+
console.log(`SNR ${f(r.snrDb)} dB (harmonic vs everything else)`);
|
|
41
|
+
console.log(`DC ${f(r.dcDbfs)} dBFS peak ${f(r.peakDbfs)} dBFS non-finite ${r.nonFinite}`);
|
|
42
|
+
console.log(fails.length ? `FAIL: ${fails.join('; ')}` : 'PASS');
|
|
43
|
+
}
|
|
44
|
+
return fails.length ? 1 : 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
process.exit(main());
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "field-map-over-if-runs",
|
|
3
|
+
"why": "Three or more ifs in a row on fields of the same object (if (args.filter?.flag !== undefined) filter.flags = \u2026) grow by one line per field forever. A field table plus one loop keeps every field in one place and makes the next field one table row.",
|
|
4
|
+
"rule": ".claude/rules/field-map-over-if-runs.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"cpp",
|
|
7
|
+
"js"
|
|
8
|
+
],
|
|
9
|
+
"globs": [],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/*.min.js",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**",
|
|
19
|
+
"**/*_test.*"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "if\\s*\\(\\s*!?\\s*([A-Za-z_$][\\w$]*(?:(?:\\?\\.|\\.|->)[A-Za-z_$][\\w$]*)*)(?:\\?\\.|\\.|->)[A-Za-z_$][\\w$]*\\s*(?:(?:!==?|===?)\\s*(?:undefined|null|nullptr)\\s*)?\\)[^\\n]*\\n(?:[^\\n]*\\n){0,3}?\\s*if\\s*\\(\\s*!?\\s*\\1(?:\\?\\.|\\.|->)[A-Za-z_$][\\w$]*\\s*(?:(?:!==?|===?)\\s*(?:undefined|null|nullptr)\\s*)?\\)[^\\n]*\\n(?:[^\\n]*\\n){0,3}?\\s*if\\s*\\(\\s*!?\\s*\\1(?:\\?\\.|\\.|->)[A-Za-z_$][\\w$]*\\s*(?:(?:!==?|===?)\\s*(?:undefined|null|nullptr)\\s*)?\\)",
|
|
23
|
+
"bad": " if (args.filter?.flag !== undefined) filter.flags = args.filter.flag;\n if (args.filter?.kind !== undefined) filter.kind = args.filter.kind;\n if (args.filter?.path !== undefined) filter.path = { $regex: escapeRe(args.filter.path) };\n",
|
|
24
|
+
"good": "const FILTER_FIELDS = {\n flag: (v) => ({ flags: v }),\n kind: (v) => ({ kind: v }),\n path: (v) => ({ path: { $regex: escapeRe(v) } }),\n};\nfor (const [k, put] of Object.entries(FILTER_FIELDS)) if (args.filter?.[k] !== undefined) Object.assign(filter, put(args.filter[k]));\nif (a.x) f();\nif (b.y) g();\nif (c.z) h();\n"
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "lookup-over-if-chains",
|
|
3
|
+
"why": "Three or more branches on one value (if/else if, or ifs in a row that each return) are a lookup table (JS/TS) or an object per kind (C++; an exhaustive switch over an enum class only in a hot inner loop): one place to add a case, and a missing case is a compile error. The chain hides a missing case and grows forever.",
|
|
4
|
+
"rule": ".claude/rules/lookup-over-if-chains.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"cpp",
|
|
7
|
+
"js"
|
|
8
|
+
],
|
|
9
|
+
"globs": [],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/*.min.js",
|
|
15
|
+
"**/*.test.*",
|
|
16
|
+
"**/*.spec.*",
|
|
17
|
+
"**/test/**",
|
|
18
|
+
"**/tests/**",
|
|
19
|
+
"**/*_test.*"
|
|
20
|
+
],
|
|
21
|
+
"code": true,
|
|
22
|
+
"pattern": "if\\s*\\(\\s*(?![\\w.]*\\.length\\b)([A-Za-z_][\\w.]*(?:->\\w+)*(?:\\(\\))?)\\s*===?(?!=)(?!\\s*(?:null|undefined|nullptr)\\b)\\s*[^)&|]+\\)[\\s\\S]{0,600}?(?:else\\s+)?if\\s*\\(\\s*\\1\\s*===?(?!=)(?!\\s*(?:null|undefined|nullptr)\\b)\\s*[^)&|]+\\)[\\s\\S]{0,600}?(?:else\\s+)?if\\s*\\(\\s*\\1\\s*===?(?!=)(?!\\s*(?:null|undefined|nullptr)\\b)",
|
|
23
|
+
"bad": "if (row.kind === 'turn') return `<div>${turn(row)}</div>`;\nif (row.kind === 'system') return `<div>${note(row)}</div>`;\nif (row.kind === 'bash') return detailed(row);",
|
|
24
|
+
"good": "const RENDER = { turn: (row) => `<div>${turn(row)}</div>`, system: (row) => `<div>${note(row)}</div>`, bash: detailed };\nreturn (RENDER[row.kind] ?? unknownKind)(row);\nswitch (mode) {\n case Mode::line: return drawLine (ctx);\n case Mode::fill: return drawFill (ctx);\n case Mode::text: return drawText (ctx);\n}\nif (score > 90) a(); else if (score > 80) b(); else if (score > 70) c();\nif (a == 1) x(); else if (b == 2) y(); else if (c == 3) z();\nif (row.kind === 'turn') return t(row);\nif (row.kind === 'system') return s(row);\nif (x === null) return a;\nif (x === undefined) return b;\nif (x === '') return c;\n"
|
|
25
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "lookup-over-ternary-chains",
|
|
3
|
+
"why": "A ternary chain is a lookup table written as control flow: adding a kind means finding every chain, and the compiler checks none of them.",
|
|
4
|
+
"rule": ".claude/rules/lookup-over-if-chains.md",
|
|
5
|
+
"concepts": [
|
|
6
|
+
"cpp",
|
|
7
|
+
"js"
|
|
8
|
+
],
|
|
9
|
+
"globs": [],
|
|
10
|
+
"exclude": [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/build/**",
|
|
14
|
+
"**/*.min.js"
|
|
15
|
+
],
|
|
16
|
+
"code": true,
|
|
17
|
+
"pattern": "\\?(?:[^?:;,()\\n]|::|\\((?:[^()\\n]|\\([^()\\n]*\\))*\\))*:(?:[^?:;,()\\n]|::|\\((?:[^()\\n]|\\([^()\\n]*\\))*\\))*\\?(?:[^?:;,()\\n]|::|\\((?:[^()\\n]|\\([^()\\n]*\\))*\\))*:(?:[^?:;,()\\n]|::|\\((?:[^()\\n]|\\([^()\\n]*\\))*\\))*\\?",
|
|
18
|
+
"bad": "const char* n = s == a ? \"A\" : s == b ? \"B\" : s == c ? \"C\" : \"D\";",
|
|
19
|
+
"good": "const auto f = g ? h : i ? j : k;\nprint (a ? \"x\" : \"y\", b ? \"x\" : \"y\", c ? \"x\" : \"y\");"
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-code-after-midline-comment",
|
|
3
|
+
"why": "A // put in the middle of a line swallows every statement after it, and it still compiles (Stellix WB-25: five times in one step). A comment goes at the end of the line, after the code. The pattern stays within one line: a line ending in a comment, followed by a line of code, is fine (KWB-9).",
|
|
4
|
+
"concepts": [
|
|
5
|
+
"cpp",
|
|
6
|
+
"shaders"
|
|
7
|
+
],
|
|
8
|
+
"pattern": "^(?!.*https?://)[ \\t]*[^\\s/][^\\n]*?[^\"\\n]//[^\\n]*?(?:[;{}:,]|\\)|[ \\t])[ \\t]*(?:[A-Za-z_]\\w*(?:\\.\\w+|->\\w+|\\[[^\\]\\n]*\\])*[ \\t]*[-+*/|&]?=[ \\t]*[^=\\s][^;\\n]*|return\\b[^;\\n]*|[A-Za-z_]\\w*(?:::\\w+)*\\([^;\\n]*\\))[ \\t]*;[ \\t]*}?[ \\t]*$",
|
|
9
|
+
"flags": "m",
|
|
10
|
+
"bad": " c.power = p; // its share c.pitch = t.pitch; c.energy = e;\n const size_t i = d.trav; // kicked after if (d.trav < 0 || !live) return;",
|
|
11
|
+
"good": " c.power = p; // its share: a = b in the text, never code\n open(url); // see https://x.y/a?b=c;\n// a = b; whole-line comments are prose\nlaunchNote(w, L, from, set); // fire( in a comment\n x = f(); // the note\n return y;\n a(); // the note\n go(x);"
|
|
12
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "one-walk-per-template",
|
|
3
|
+
"why": "A test that presses, clicks or drags every instance of one template repeats the same behaviour hundreds of times and proves nothing more than one press does. Walk one instance of each template and every one-off; prove the rest with a read of the table that each is built from its template and wired.",
|
|
4
|
+
"rule": ".claude/rules/test-the-template-once.md",
|
|
5
|
+
"globs": [
|
|
6
|
+
"**/gates/**",
|
|
7
|
+
"**/probes/**",
|
|
8
|
+
"**/tests/**",
|
|
9
|
+
"**/test/**",
|
|
10
|
+
"**/*.test.*",
|
|
11
|
+
"**/*.spec.*",
|
|
12
|
+
"**/*_test.*",
|
|
13
|
+
"**/e2e/**"
|
|
14
|
+
],
|
|
15
|
+
"exclude": [
|
|
16
|
+
"**/build/**",
|
|
17
|
+
"**/node_modules/**"
|
|
18
|
+
],
|
|
19
|
+
"code": true,
|
|
20
|
+
"pattern": "(?:for\\s*\\([^;\\n]*?(?::|\\bof\\b|\\bin\\b)\\s*(?:await\\s+)?[^;\\n]*?(?:\\b(?:controls|ctls|kDefs|kPanel|widgets|knobs|sliders|buttons)\\b(?:\\(\\))?|\\.all\\(\\))\\s*\\)|for\\s*\\([^;\\n]*;[^;\\n]*<\\s*[\\w:.>-]*(?:kControls|kCount|(?:controls|ctls|kDefs|kPanel|widgets|knobs|sliders|buttons)\\.size\\(\\)|(?:controls|ctls|kDefs|kPanel|widgets|knobs|sliders|buttons)\\.length)[^;\\n]*;[^)\\n]*\\)|\\b(?:controls|ctls|kDefs|kPanel|widgets|knobs|sliders|buttons)\\.forEach\\()(?![^}\\n]{0,300}?\\.id\\s*===?(?!=))(?:\\s*\\{[^}]{0,300}?|[^;}]{0,300}?)\\b(?:press\\w*(?:\\.push_back|\\.push)?|click\\w*|drag\\w*|hover\\w*|tap)\\s*\\(",
|
|
21
|
+
"bad": "for (const auto& c : L.controls) if (c.visible) pressIds.push_back(c.id);\nfor (const b of buttons) {\n await b.click();\n}\nfor (int i = 0; i < ctl::kCount; i++) pressAt (centreOf (i));\nbuttons.forEach((b) => b.hover());",
|
|
22
|
+
"good": "for (const auto& c : L.controls) if (c.id == id) pressAt (c.box.getCentre());\nfor (const d : kDefs) assert (d.bind != nullptr);\nawait buttons[0].click();\nfor (const row of table) expect(row.template).toBe('knob');"
|
|
23
|
+
}
|