@wazir-dev/cli 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/AGENTS.md +111 -0
- package/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +101 -0
- package/LICENSE +21 -0
- package/README.md +314 -0
- package/assets/composition-engine.mmd +34 -0
- package/assets/demo-script.sh +17 -0
- package/assets/logo-dark.svg +14 -0
- package/assets/logo.svg +14 -0
- package/assets/pipeline.mmd +39 -0
- package/assets/record-demo.sh +51 -0
- package/docs/README.md +51 -0
- package/docs/adapters/context-mode.md +60 -0
- package/docs/concepts/architecture.md +87 -0
- package/docs/concepts/artifact-model.md +60 -0
- package/docs/concepts/composition-engine.md +36 -0
- package/docs/concepts/indexing-and-recall.md +160 -0
- package/docs/concepts/observability.md +41 -0
- package/docs/concepts/roles-and-workflows.md +59 -0
- package/docs/concepts/terminology-policy.md +27 -0
- package/docs/getting-started/01-installation.md +78 -0
- package/docs/getting-started/02-first-run.md +102 -0
- package/docs/getting-started/03-adding-to-project.md +15 -0
- package/docs/getting-started/04-host-setup.md +15 -0
- package/docs/guides/ci-integration.md +15 -0
- package/docs/guides/creating-skills.md +15 -0
- package/docs/guides/expertise-module-authoring.md +15 -0
- package/docs/guides/hook-development.md +15 -0
- package/docs/guides/memory-and-learnings.md +34 -0
- package/docs/guides/multi-host-export.md +15 -0
- package/docs/guides/troubleshooting.md +101 -0
- package/docs/guides/writing-custom-roles.md +15 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
- package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
- package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
- package/docs/readmes/INDEX.md +99 -0
- package/docs/readmes/features/expertise/README.md +171 -0
- package/docs/readmes/features/exports/README.md +222 -0
- package/docs/readmes/features/hooks/README.md +103 -0
- package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
- package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
- package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
- package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
- package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
- package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
- package/docs/readmes/features/hooks/session-start.md +119 -0
- package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
- package/docs/readmes/features/roles/README.md +157 -0
- package/docs/readmes/features/roles/clarifier.md +152 -0
- package/docs/readmes/features/roles/content-author.md +190 -0
- package/docs/readmes/features/roles/designer.md +193 -0
- package/docs/readmes/features/roles/executor.md +184 -0
- package/docs/readmes/features/roles/learner.md +210 -0
- package/docs/readmes/features/roles/planner.md +182 -0
- package/docs/readmes/features/roles/researcher.md +164 -0
- package/docs/readmes/features/roles/reviewer.md +184 -0
- package/docs/readmes/features/roles/specifier.md +162 -0
- package/docs/readmes/features/roles/verifier.md +215 -0
- package/docs/readmes/features/schemas/README.md +178 -0
- package/docs/readmes/features/skills/README.md +63 -0
- package/docs/readmes/features/skills/brainstorming.md +96 -0
- package/docs/readmes/features/skills/debugging.md +148 -0
- package/docs/readmes/features/skills/design.md +120 -0
- package/docs/readmes/features/skills/prepare-next.md +109 -0
- package/docs/readmes/features/skills/run-audit.md +159 -0
- package/docs/readmes/features/skills/scan-project.md +109 -0
- package/docs/readmes/features/skills/self-audit.md +176 -0
- package/docs/readmes/features/skills/tdd.md +137 -0
- package/docs/readmes/features/skills/using-skills.md +92 -0
- package/docs/readmes/features/skills/verification.md +120 -0
- package/docs/readmes/features/skills/writing-plans.md +104 -0
- package/docs/readmes/features/tooling/README.md +320 -0
- package/docs/readmes/features/workflows/README.md +186 -0
- package/docs/readmes/features/workflows/author.md +181 -0
- package/docs/readmes/features/workflows/clarify.md +154 -0
- package/docs/readmes/features/workflows/design-review.md +171 -0
- package/docs/readmes/features/workflows/design.md +169 -0
- package/docs/readmes/features/workflows/discover.md +162 -0
- package/docs/readmes/features/workflows/execute.md +173 -0
- package/docs/readmes/features/workflows/learn.md +167 -0
- package/docs/readmes/features/workflows/plan-review.md +165 -0
- package/docs/readmes/features/workflows/plan.md +170 -0
- package/docs/readmes/features/workflows/prepare-next.md +167 -0
- package/docs/readmes/features/workflows/review.md +169 -0
- package/docs/readmes/features/workflows/run-audit.md +191 -0
- package/docs/readmes/features/workflows/spec-challenge.md +159 -0
- package/docs/readmes/features/workflows/specify.md +160 -0
- package/docs/readmes/features/workflows/verify.md +177 -0
- package/docs/readmes/packages/README.md +50 -0
- package/docs/readmes/packages/ajv.md +117 -0
- package/docs/readmes/packages/context-mode.md +118 -0
- package/docs/readmes/packages/gray-matter.md +116 -0
- package/docs/readmes/packages/node-test.md +137 -0
- package/docs/readmes/packages/yaml.md +112 -0
- package/docs/reference/configuration-reference.md +159 -0
- package/docs/reference/expertise-index.md +52 -0
- package/docs/reference/git-flow.md +43 -0
- package/docs/reference/hooks.md +87 -0
- package/docs/reference/host-exports.md +50 -0
- package/docs/reference/launch-checklist.md +172 -0
- package/docs/reference/marketplace-listings.md +76 -0
- package/docs/reference/release-process.md +34 -0
- package/docs/reference/roles-reference.md +77 -0
- package/docs/reference/skills.md +33 -0
- package/docs/reference/templates.md +29 -0
- package/docs/reference/tooling-cli.md +94 -0
- package/docs/truth-claims.yaml +222 -0
- package/expertise/PROGRESS.md +63 -0
- package/expertise/README.md +18 -0
- package/expertise/antipatterns/PROGRESS.md +56 -0
- package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
- package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
- package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
- package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
- package/expertise/antipatterns/backend/index.md +24 -0
- package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
- package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
- package/expertise/antipatterns/code/async-antipatterns.md +622 -0
- package/expertise/antipatterns/code/code-smells.md +1186 -0
- package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
- package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
- package/expertise/antipatterns/code/index.md +27 -0
- package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
- package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
- package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
- package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
- package/expertise/antipatterns/design/dark-patterns.md +1121 -0
- package/expertise/antipatterns/design/index.md +22 -0
- package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
- package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
- package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
- package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
- package/expertise/antipatterns/frontend/index.md +23 -0
- package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
- package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
- package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
- package/expertise/antipatterns/index.md +31 -0
- package/expertise/antipatterns/performance/index.md +20 -0
- package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
- package/expertise/antipatterns/performance/premature-optimization.md +623 -0
- package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
- package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
- package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
- package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
- package/expertise/antipatterns/process/index.md +23 -0
- package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
- package/expertise/antipatterns/security/index.md +20 -0
- package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
- package/expertise/antipatterns/security/security-theater.md +843 -0
- package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
- package/expertise/architecture/PROGRESS.md +70 -0
- package/expertise/architecture/data/caching-architecture.md +671 -0
- package/expertise/architecture/data/data-consistency.md +574 -0
- package/expertise/architecture/data/data-modeling.md +536 -0
- package/expertise/architecture/data/event-streams-and-queues.md +634 -0
- package/expertise/architecture/data/index.md +25 -0
- package/expertise/architecture/data/search-architecture.md +663 -0
- package/expertise/architecture/data/sql-vs-nosql.md +708 -0
- package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
- package/expertise/architecture/decisions/build-vs-buy.md +616 -0
- package/expertise/architecture/decisions/index.md +23 -0
- package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
- package/expertise/architecture/decisions/technology-selection.md +616 -0
- package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
- package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
- package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
- package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
- package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
- package/expertise/architecture/distributed/index.md +25 -0
- package/expertise/architecture/distributed/saga-pattern.md +797 -0
- package/expertise/architecture/foundations/architectural-thinking.md +460 -0
- package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
- package/expertise/architecture/foundations/design-principles-solid.md +649 -0
- package/expertise/architecture/foundations/domain-driven-design.md +719 -0
- package/expertise/architecture/foundations/index.md +25 -0
- package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
- package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
- package/expertise/architecture/index.md +34 -0
- package/expertise/architecture/integration/api-design-graphql.md +638 -0
- package/expertise/architecture/integration/api-design-grpc.md +804 -0
- package/expertise/architecture/integration/api-design-rest.md +892 -0
- package/expertise/architecture/integration/index.md +25 -0
- package/expertise/architecture/integration/third-party-integration.md +795 -0
- package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
- package/expertise/architecture/integration/websockets-realtime.md +791 -0
- package/expertise/architecture/mobile-architecture/index.md +22 -0
- package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
- package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
- package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
- package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
- package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
- package/expertise/architecture/patterns/event-driven.md +797 -0
- package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
- package/expertise/architecture/patterns/index.md +27 -0
- package/expertise/architecture/patterns/layered-architecture.md +736 -0
- package/expertise/architecture/patterns/microservices.md +753 -0
- package/expertise/architecture/patterns/modular-monolith.md +692 -0
- package/expertise/architecture/patterns/monolith.md +626 -0
- package/expertise/architecture/patterns/plugin-architecture.md +735 -0
- package/expertise/architecture/patterns/serverless.md +780 -0
- package/expertise/architecture/scaling/database-scaling.md +615 -0
- package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
- package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
- package/expertise/architecture/scaling/index.md +24 -0
- package/expertise/architecture/scaling/multi-tenancy.md +800 -0
- package/expertise/architecture/scaling/stateless-design.md +787 -0
- package/expertise/backend/embedded-firmware.md +625 -0
- package/expertise/backend/go.md +853 -0
- package/expertise/backend/index.md +24 -0
- package/expertise/backend/java-spring.md +448 -0
- package/expertise/backend/node-typescript.md +625 -0
- package/expertise/backend/python-fastapi.md +724 -0
- package/expertise/backend/rust.md +458 -0
- package/expertise/backend/solidity.md +711 -0
- package/expertise/composition-map.yaml +443 -0
- package/expertise/content/foundations/content-modeling.md +395 -0
- package/expertise/content/foundations/editorial-standards.md +449 -0
- package/expertise/content/foundations/index.md +24 -0
- package/expertise/content/foundations/microcopy.md +455 -0
- package/expertise/content/foundations/terminology-governance.md +509 -0
- package/expertise/content/index.md +34 -0
- package/expertise/content/patterns/accessibility-copy.md +518 -0
- package/expertise/content/patterns/index.md +24 -0
- package/expertise/content/patterns/notification-content.md +433 -0
- package/expertise/content/patterns/sample-content.md +486 -0
- package/expertise/content/patterns/state-copy.md +439 -0
- package/expertise/design/PROGRESS.md +58 -0
- package/expertise/design/disciplines/dark-mode-theming.md +577 -0
- package/expertise/design/disciplines/design-systems.md +595 -0
- package/expertise/design/disciplines/index.md +25 -0
- package/expertise/design/disciplines/information-architecture.md +800 -0
- package/expertise/design/disciplines/interaction-design.md +788 -0
- package/expertise/design/disciplines/responsive-design.md +552 -0
- package/expertise/design/disciplines/usability-testing.md +516 -0
- package/expertise/design/disciplines/user-research.md +792 -0
- package/expertise/design/foundations/accessibility-design.md +796 -0
- package/expertise/design/foundations/color-theory.md +797 -0
- package/expertise/design/foundations/iconography.md +795 -0
- package/expertise/design/foundations/index.md +26 -0
- package/expertise/design/foundations/motion-and-animation.md +653 -0
- package/expertise/design/foundations/rtl-design.md +585 -0
- package/expertise/design/foundations/spacing-and-layout.md +607 -0
- package/expertise/design/foundations/typography.md +800 -0
- package/expertise/design/foundations/visual-hierarchy.md +761 -0
- package/expertise/design/index.md +32 -0
- package/expertise/design/patterns/authentication-flows.md +474 -0
- package/expertise/design/patterns/content-consumption.md +789 -0
- package/expertise/design/patterns/data-display.md +618 -0
- package/expertise/design/patterns/e-commerce.md +1494 -0
- package/expertise/design/patterns/feedback-and-states.md +642 -0
- package/expertise/design/patterns/forms-and-input.md +819 -0
- package/expertise/design/patterns/gamification.md +801 -0
- package/expertise/design/patterns/index.md +31 -0
- package/expertise/design/patterns/microinteractions.md +449 -0
- package/expertise/design/patterns/navigation.md +800 -0
- package/expertise/design/patterns/notifications.md +705 -0
- package/expertise/design/patterns/onboarding.md +700 -0
- package/expertise/design/patterns/search-and-filter.md +601 -0
- package/expertise/design/patterns/settings-and-preferences.md +768 -0
- package/expertise/design/patterns/social-and-community.md +748 -0
- package/expertise/design/platforms/desktop-native.md +612 -0
- package/expertise/design/platforms/index.md +25 -0
- package/expertise/design/platforms/mobile-android.md +825 -0
- package/expertise/design/platforms/mobile-cross-platform.md +983 -0
- package/expertise/design/platforms/mobile-ios.md +699 -0
- package/expertise/design/platforms/tablet.md +794 -0
- package/expertise/design/platforms/web-dashboard.md +790 -0
- package/expertise/design/platforms/web-responsive.md +550 -0
- package/expertise/design/psychology/behavioral-nudges.md +449 -0
- package/expertise/design/psychology/cognitive-load.md +1191 -0
- package/expertise/design/psychology/error-psychology.md +778 -0
- package/expertise/design/psychology/index.md +22 -0
- package/expertise/design/psychology/persuasive-design.md +736 -0
- package/expertise/design/psychology/user-mental-models.md +623 -0
- package/expertise/design/tooling/open-pencil.md +266 -0
- package/expertise/frontend/angular.md +1073 -0
- package/expertise/frontend/desktop-electron.md +546 -0
- package/expertise/frontend/flutter.md +782 -0
- package/expertise/frontend/index.md +27 -0
- package/expertise/frontend/native-android.md +409 -0
- package/expertise/frontend/native-ios.md +490 -0
- package/expertise/frontend/react-native.md +1160 -0
- package/expertise/frontend/react.md +808 -0
- package/expertise/frontend/vue.md +1089 -0
- package/expertise/humanize/domain-rules-code.md +79 -0
- package/expertise/humanize/domain-rules-content.md +67 -0
- package/expertise/humanize/domain-rules-technical-docs.md +56 -0
- package/expertise/humanize/index.md +35 -0
- package/expertise/humanize/self-audit-checklist.md +87 -0
- package/expertise/humanize/sentence-patterns.md +218 -0
- package/expertise/humanize/vocabulary-blacklist.md +105 -0
- package/expertise/i18n/PROGRESS.md +65 -0
- package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
- package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
- package/expertise/i18n/advanced/complex-scripts.md +30 -0
- package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
- package/expertise/i18n/advanced/testing-i18n.md +28 -0
- package/expertise/i18n/content/content-adaptation.md +23 -0
- package/expertise/i18n/content/locale-specific-formatting.md +23 -0
- package/expertise/i18n/content/machine-translation-integration.md +28 -0
- package/expertise/i18n/content/translation-management.md +29 -0
- package/expertise/i18n/foundations/date-time-calendars.md +67 -0
- package/expertise/i18n/foundations/i18n-architecture.md +272 -0
- package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
- package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
- package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
- package/expertise/i18n/foundations/string-externalization.md +236 -0
- package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
- package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
- package/expertise/i18n/index.md +38 -0
- package/expertise/i18n/platform/backend-i18n.md +31 -0
- package/expertise/i18n/platform/flutter-i18n.md +148 -0
- package/expertise/i18n/platform/native-android-i18n.md +36 -0
- package/expertise/i18n/platform/native-ios-i18n.md +36 -0
- package/expertise/i18n/platform/react-i18n.md +103 -0
- package/expertise/i18n/platform/web-css-i18n.md +81 -0
- package/expertise/i18n/rtl/arabic-specific.md +175 -0
- package/expertise/i18n/rtl/hebrew-specific.md +149 -0
- package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
- package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
- package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
- package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
- package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
- package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
- package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
- package/expertise/i18n/rtl/rtl-typography.md +160 -0
- package/expertise/index.md +113 -0
- package/expertise/index.yaml +216 -0
- package/expertise/infrastructure/cloud-aws.md +597 -0
- package/expertise/infrastructure/cloud-gcp.md +599 -0
- package/expertise/infrastructure/cybersecurity.md +816 -0
- package/expertise/infrastructure/database-mongodb.md +447 -0
- package/expertise/infrastructure/database-postgres.md +400 -0
- package/expertise/infrastructure/devops-cicd.md +787 -0
- package/expertise/infrastructure/index.md +27 -0
- package/expertise/performance/PROGRESS.md +50 -0
- package/expertise/performance/backend/api-latency.md +1204 -0
- package/expertise/performance/backend/background-jobs.md +506 -0
- package/expertise/performance/backend/connection-pooling.md +1209 -0
- package/expertise/performance/backend/database-query-optimization.md +515 -0
- package/expertise/performance/backend/index.md +23 -0
- package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
- package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
- package/expertise/performance/foundations/caching-strategies.md +489 -0
- package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
- package/expertise/performance/foundations/index.md +24 -0
- package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
- package/expertise/performance/foundations/memory-management.md +964 -0
- package/expertise/performance/foundations/performance-budgets.md +1314 -0
- package/expertise/performance/index.md +31 -0
- package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
- package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
- package/expertise/performance/infrastructure/index.md +22 -0
- package/expertise/performance/infrastructure/load-balancing.md +1081 -0
- package/expertise/performance/infrastructure/observability.md +1079 -0
- package/expertise/performance/mobile/index.md +23 -0
- package/expertise/performance/mobile/mobile-animations.md +544 -0
- package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
- package/expertise/performance/mobile/mobile-network.md +452 -0
- package/expertise/performance/mobile/mobile-rendering.md +599 -0
- package/expertise/performance/mobile/mobile-startup-time.md +505 -0
- package/expertise/performance/platform-specific/flutter-performance.md +647 -0
- package/expertise/performance/platform-specific/index.md +22 -0
- package/expertise/performance/platform-specific/node-performance.md +1307 -0
- package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
- package/expertise/performance/platform-specific/react-performance.md +1403 -0
- package/expertise/performance/web/bundle-optimization.md +1239 -0
- package/expertise/performance/web/image-and-media.md +636 -0
- package/expertise/performance/web/index.md +24 -0
- package/expertise/performance/web/network-optimization.md +1133 -0
- package/expertise/performance/web/rendering-performance.md +1098 -0
- package/expertise/performance/web/ssr-and-hydration.md +918 -0
- package/expertise/performance/web/web-vitals.md +1374 -0
- package/expertise/quality/accessibility.md +985 -0
- package/expertise/quality/evidence-based-verification.md +499 -0
- package/expertise/quality/index.md +24 -0
- package/expertise/quality/ml-model-audit.md +614 -0
- package/expertise/quality/performance.md +600 -0
- package/expertise/quality/testing-api.md +891 -0
- package/expertise/quality/testing-mobile.md +496 -0
- package/expertise/quality/testing-web.md +849 -0
- package/expertise/security/PROGRESS.md +54 -0
- package/expertise/security/agentic-identity.md +540 -0
- package/expertise/security/compliance-frameworks.md +601 -0
- package/expertise/security/data/data-encryption.md +364 -0
- package/expertise/security/data/data-privacy-gdpr.md +692 -0
- package/expertise/security/data/database-security.md +1171 -0
- package/expertise/security/data/index.md +22 -0
- package/expertise/security/data/pii-handling.md +531 -0
- package/expertise/security/foundations/authentication.md +1041 -0
- package/expertise/security/foundations/authorization.md +603 -0
- package/expertise/security/foundations/cryptography.md +1001 -0
- package/expertise/security/foundations/index.md +25 -0
- package/expertise/security/foundations/owasp-top-10.md +1354 -0
- package/expertise/security/foundations/secrets-management.md +1217 -0
- package/expertise/security/foundations/secure-sdlc.md +700 -0
- package/expertise/security/foundations/supply-chain-security.md +698 -0
- package/expertise/security/index.md +31 -0
- package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
- package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
- package/expertise/security/infrastructure/container-security.md +721 -0
- package/expertise/security/infrastructure/incident-response.md +1295 -0
- package/expertise/security/infrastructure/index.md +24 -0
- package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
- package/expertise/security/infrastructure/network-security.md +1337 -0
- package/expertise/security/mobile/index.md +23 -0
- package/expertise/security/mobile/mobile-android-security.md +1218 -0
- package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
- package/expertise/security/mobile/mobile-data-storage.md +1265 -0
- package/expertise/security/mobile/mobile-ios-security.md +1401 -0
- package/expertise/security/mobile/mobile-network-security.md +1520 -0
- package/expertise/security/smart-contract-security.md +594 -0
- package/expertise/security/testing/index.md +22 -0
- package/expertise/security/testing/penetration-testing.md +1258 -0
- package/expertise/security/testing/security-code-review.md +1765 -0
- package/expertise/security/testing/threat-modeling.md +1074 -0
- package/expertise/security/testing/vulnerability-scanning.md +1062 -0
- package/expertise/security/web/api-security.md +586 -0
- package/expertise/security/web/cors-and-headers.md +433 -0
- package/expertise/security/web/csrf.md +562 -0
- package/expertise/security/web/file-upload.md +1477 -0
- package/expertise/security/web/index.md +25 -0
- package/expertise/security/web/injection.md +1375 -0
- package/expertise/security/web/session-management.md +1101 -0
- package/expertise/security/web/xss.md +1158 -0
- package/exports/README.md +17 -0
- package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
- package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
- package/exports/hosts/claude/.claude/agents/designer.md +55 -0
- package/exports/hosts/claude/.claude/agents/executor.md +55 -0
- package/exports/hosts/claude/.claude/agents/learner.md +51 -0
- package/exports/hosts/claude/.claude/agents/planner.md +53 -0
- package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
- package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
- package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
- package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
- package/exports/hosts/claude/.claude/commands/author.md +42 -0
- package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
- package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
- package/exports/hosts/claude/.claude/commands/design.md +44 -0
- package/exports/hosts/claude/.claude/commands/discover.md +37 -0
- package/exports/hosts/claude/.claude/commands/execute.md +48 -0
- package/exports/hosts/claude/.claude/commands/learn.md +38 -0
- package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
- package/exports/hosts/claude/.claude/commands/plan.md +39 -0
- package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
- package/exports/hosts/claude/.claude/commands/review.md +40 -0
- package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
- package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
- package/exports/hosts/claude/.claude/commands/specify.md +38 -0
- package/exports/hosts/claude/.claude/commands/verify.md +37 -0
- package/exports/hosts/claude/.claude/settings.json +34 -0
- package/exports/hosts/claude/CLAUDE.md +19 -0
- package/exports/hosts/claude/export.manifest.json +38 -0
- package/exports/hosts/claude/host-package.json +67 -0
- package/exports/hosts/codex/AGENTS.md +19 -0
- package/exports/hosts/codex/export.manifest.json +38 -0
- package/exports/hosts/codex/host-package.json +41 -0
- package/exports/hosts/cursor/.cursor/hooks.json +16 -0
- package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
- package/exports/hosts/cursor/export.manifest.json +38 -0
- package/exports/hosts/cursor/host-package.json +42 -0
- package/exports/hosts/gemini/GEMINI.md +19 -0
- package/exports/hosts/gemini/export.manifest.json +38 -0
- package/exports/hosts/gemini/host-package.json +41 -0
- package/hooks/README.md +18 -0
- package/hooks/definitions/loop_cap_guard.yaml +21 -0
- package/hooks/definitions/post_tool_capture.yaml +24 -0
- package/hooks/definitions/pre_compact_summary.yaml +19 -0
- package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
- package/hooks/definitions/protected_path_write_guard.yaml +19 -0
- package/hooks/definitions/session_start.yaml +19 -0
- package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
- package/hooks/loop-cap-guard +17 -0
- package/hooks/post-tool-lint +36 -0
- package/hooks/protected-path-write-guard +17 -0
- package/hooks/session-start +41 -0
- package/llms-full.txt +2355 -0
- package/llms.txt +43 -0
- package/package.json +79 -0
- package/roles/README.md +20 -0
- package/roles/clarifier.md +42 -0
- package/roles/content-author.md +63 -0
- package/roles/designer.md +55 -0
- package/roles/executor.md +55 -0
- package/roles/learner.md +51 -0
- package/roles/planner.md +53 -0
- package/roles/researcher.md +43 -0
- package/roles/reviewer.md +54 -0
- package/roles/specifier.md +47 -0
- package/roles/verifier.md +71 -0
- package/schemas/README.md +24 -0
- package/schemas/accepted-learning.schema.json +20 -0
- package/schemas/author-artifact.schema.json +156 -0
- package/schemas/clarification.schema.json +19 -0
- package/schemas/design-artifact.schema.json +80 -0
- package/schemas/docs-claim.schema.json +18 -0
- package/schemas/export-manifest.schema.json +20 -0
- package/schemas/hook.schema.json +67 -0
- package/schemas/host-export-package.schema.json +18 -0
- package/schemas/implementation-plan.schema.json +19 -0
- package/schemas/proposed-learning.schema.json +19 -0
- package/schemas/research.schema.json +18 -0
- package/schemas/review.schema.json +29 -0
- package/schemas/run-manifest.schema.json +18 -0
- package/schemas/spec-challenge.schema.json +18 -0
- package/schemas/spec.schema.json +20 -0
- package/schemas/usage.schema.json +102 -0
- package/schemas/verification-proof.schema.json +29 -0
- package/schemas/wazir-manifest.schema.json +173 -0
- package/skills/README.md +40 -0
- package/skills/brainstorming/SKILL.md +77 -0
- package/skills/debugging/SKILL.md +50 -0
- package/skills/design/SKILL.md +61 -0
- package/skills/dispatching-parallel-agents/SKILL.md +128 -0
- package/skills/executing-plans/SKILL.md +70 -0
- package/skills/finishing-a-development-branch/SKILL.md +169 -0
- package/skills/humanize/SKILL.md +123 -0
- package/skills/init-pipeline/SKILL.md +124 -0
- package/skills/prepare-next/SKILL.md +20 -0
- package/skills/receiving-code-review/SKILL.md +123 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +108 -0
- package/skills/run-audit/SKILL.md +197 -0
- package/skills/scan-project/SKILL.md +41 -0
- package/skills/self-audit/SKILL.md +153 -0
- package/skills/subagent-driven-development/SKILL.md +154 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
- package/skills/subagent-driven-development/implementer-prompt.md +102 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/tdd/SKILL.md +23 -0
- package/skills/using-git-worktrees/SKILL.md +163 -0
- package/skills/using-skills/SKILL.md +95 -0
- package/skills/verification/SKILL.md +22 -0
- package/skills/wazir/SKILL.md +463 -0
- package/skills/writing-plans/SKILL.md +30 -0
- package/skills/writing-skills/SKILL.md +157 -0
- package/skills/writing-skills/anthropic-best-practices.md +122 -0
- package/skills/writing-skills/persuasion-principles.md +50 -0
- package/templates/README.md +20 -0
- package/templates/artifacts/README.md +10 -0
- package/templates/artifacts/accepted-learning.md +19 -0
- package/templates/artifacts/accepted-learning.template.json +12 -0
- package/templates/artifacts/author.md +74 -0
- package/templates/artifacts/author.template.json +19 -0
- package/templates/artifacts/clarification.md +21 -0
- package/templates/artifacts/clarification.template.json +12 -0
- package/templates/artifacts/execute-notes.md +19 -0
- package/templates/artifacts/implementation-plan.md +21 -0
- package/templates/artifacts/implementation-plan.template.json +11 -0
- package/templates/artifacts/learning-proposal.md +19 -0
- package/templates/artifacts/next-run-handoff.md +21 -0
- package/templates/artifacts/plan-review.md +19 -0
- package/templates/artifacts/proposed-learning.template.json +12 -0
- package/templates/artifacts/research.md +21 -0
- package/templates/artifacts/research.template.json +12 -0
- package/templates/artifacts/review-findings.md +19 -0
- package/templates/artifacts/review.template.json +11 -0
- package/templates/artifacts/run-manifest.template.json +8 -0
- package/templates/artifacts/spec-challenge.md +19 -0
- package/templates/artifacts/spec-challenge.template.json +11 -0
- package/templates/artifacts/spec.md +21 -0
- package/templates/artifacts/spec.template.json +12 -0
- package/templates/artifacts/verification-proof.md +19 -0
- package/templates/artifacts/verification-proof.template.json +11 -0
- package/templates/examples/accepted-learning.example.json +14 -0
- package/templates/examples/author.example.json +152 -0
- package/templates/examples/clarification.example.json +15 -0
- package/templates/examples/docs-claim.example.json +8 -0
- package/templates/examples/export-manifest.example.json +7 -0
- package/templates/examples/host-export-package.example.json +11 -0
- package/templates/examples/implementation-plan.example.json +17 -0
- package/templates/examples/proposed-learning.example.json +13 -0
- package/templates/examples/research.example.json +15 -0
- package/templates/examples/research.example.md +6 -0
- package/templates/examples/review.example.json +17 -0
- package/templates/examples/run-manifest.example.json +9 -0
- package/templates/examples/spec-challenge.example.json +14 -0
- package/templates/examples/spec.example.json +21 -0
- package/templates/examples/verification-proof.example.json +21 -0
- package/templates/examples/wazir-manifest.example.yaml +65 -0
- package/templates/task-definition-schema.md +99 -0
- package/tooling/README.md +20 -0
- package/tooling/src/adapters/context-mode.js +50 -0
- package/tooling/src/capture/command.js +376 -0
- package/tooling/src/capture/store.js +99 -0
- package/tooling/src/capture/usage.js +270 -0
- package/tooling/src/checks/branches.js +50 -0
- package/tooling/src/checks/brand-truth.js +110 -0
- package/tooling/src/checks/changelog.js +231 -0
- package/tooling/src/checks/command-registry.js +36 -0
- package/tooling/src/checks/commits.js +102 -0
- package/tooling/src/checks/docs-drift.js +103 -0
- package/tooling/src/checks/docs-truth.js +201 -0
- package/tooling/src/checks/runtime-surface.js +156 -0
- package/tooling/src/cli.js +116 -0
- package/tooling/src/command-options.js +56 -0
- package/tooling/src/commands/validate.js +320 -0
- package/tooling/src/doctor/command.js +91 -0
- package/tooling/src/export/command.js +77 -0
- package/tooling/src/export/compiler.js +498 -0
- package/tooling/src/guards/loop-cap-guard.js +52 -0
- package/tooling/src/guards/protected-path-write-guard.js +67 -0
- package/tooling/src/index/command.js +152 -0
- package/tooling/src/index/storage.js +1061 -0
- package/tooling/src/index/summarizers.js +261 -0
- package/tooling/src/loaders.js +18 -0
- package/tooling/src/project-root.js +22 -0
- package/tooling/src/recall/command.js +225 -0
- package/tooling/src/schema-validator.js +30 -0
- package/tooling/src/state-root.js +40 -0
- package/tooling/src/status/command.js +71 -0
- package/wazir.manifest.yaml +135 -0
- package/workflows/README.md +19 -0
- package/workflows/author.md +42 -0
- package/workflows/clarify.md +38 -0
- package/workflows/design-review.md +46 -0
- package/workflows/design.md +44 -0
- package/workflows/discover.md +37 -0
- package/workflows/execute.md +48 -0
- package/workflows/learn.md +38 -0
- package/workflows/plan-review.md +42 -0
- package/workflows/plan.md +39 -0
- package/workflows/prepare-next.md +37 -0
- package/workflows/review.md +40 -0
- package/workflows/run-audit.md +41 -0
- package/workflows/spec-challenge.md +41 -0
- package/workflows/specify.md +38 -0
- package/workflows/verify.md +37 -0
|
@@ -0,0 +1,622 @@
|
|
|
1
|
+
# Caching Anti-Patterns
|
|
2
|
+
> A field guide to the most destructive caching mistakes — with real incident post-mortems, concrete fixes, and detection rules.
|
|
3
|
+
> **Domain:** Backend
|
|
4
|
+
> **Anti-patterns covered:** 18
|
|
5
|
+
> **Highest severity:** Critical
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why Caching Anti-Patterns Matter
|
|
10
|
+
|
|
11
|
+
Caching is one of the most powerful performance tools in a backend engineer's arsenal — and one of the most dangerous when misused. A cache that silently serves stale data can cause financial losses for months before anyone notices. A cache without TTL can exhaust all available memory at 3 AM. A cache key missing a tenant ID can leak private data between customers. Unlike a slow query that triggers an alert, caching bugs hide behind improved response times — the system feels fast while quietly serving wrong answers. Every anti-pattern below has caused real production outages, data breaches, or silent data corruption.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Anti-Pattern Catalog
|
|
16
|
+
|
|
17
|
+
### AP-01: Cache and Forget (No Invalidation Strategy)
|
|
18
|
+
|
|
19
|
+
**Also known as:** Fire-and-forget cache, set-and-pray, stale forever
|
|
20
|
+
**Frequency:** Very Common | **Severity:** Critical | **Detection difficulty:** Hard
|
|
21
|
+
|
|
22
|
+
**What it looks like:**
|
|
23
|
+
```python
|
|
24
|
+
def get_user_profile(user_id):
|
|
25
|
+
cached = redis.get(f"user:{user_id}")
|
|
26
|
+
if cached: return json.loads(cached)
|
|
27
|
+
profile = db.query("SELECT * FROM users WHERE id = %s", user_id)
|
|
28
|
+
redis.set(f"user:{user_id}", json.dumps(profile)) # No TTL, no invalidation
|
|
29
|
+
return profile
|
|
30
|
+
|
|
31
|
+
def update_user_profile(user_id, data):
|
|
32
|
+
db.execute("UPDATE users SET ... WHERE id = %s", user_id)
|
|
33
|
+
# Cache? What cache? We forgot it exists.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Why developers do it:** The read path and write path are built by different developers at different times. Adding a cache on reads is a quick win requiring no coordination. Invalidation requires knowing every mutation path — writes, migrations, admin panels, background jobs.
|
|
37
|
+
|
|
38
|
+
**What goes wrong:** A production incident documented in a 2026 postmortem described an Aurora MySQL Lambda-based system where the `cacheInvalidate -> cacheRebuild` flow failed silently after a database engine upgrade. The cache stayed empty for hours before manual detection. In a separate e-commerce incident, product prices were updated in the database but the cache served old prices for 6 hours, requiring manual refund processing.
|
|
39
|
+
|
|
40
|
+
**The fix:**
|
|
41
|
+
```python
|
|
42
|
+
# Before # After
|
|
43
|
+
def update_user_profile(user_id, data): def update_user_profile(user_id, data):
|
|
44
|
+
db.execute("UPDATE ...", user_id) db.execute("UPDATE ...", user_id)
|
|
45
|
+
redis.delete(f"user:{user_id}") # Invalidate
|
|
46
|
+
pubsub.publish("cache_inv", f"user:{user_id}")
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Detection rule:** Audit every `cache.set()` and verify a corresponding `cache.delete()` exists for every mutation path touching the same data.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### AP-02: Cache Stampede
|
|
54
|
+
|
|
55
|
+
**Also known as:** Thundering herd, cache avalanche
|
|
56
|
+
**Frequency:** Common | **Severity:** Critical | **Detection difficulty:** Moderate
|
|
57
|
+
|
|
58
|
+
**What it looks like:**
|
|
59
|
+
```python
|
|
60
|
+
def get_popular_product(product_id):
|
|
61
|
+
cached = cache.get(f"product:{product_id}")
|
|
62
|
+
if cached: return cached
|
|
63
|
+
# Hot key expires -> 10,000 concurrent requests ALL hit the database
|
|
64
|
+
product = db.query("SELECT * FROM products WHERE id = %s", product_id)
|
|
65
|
+
cache.set(f"product:{product_id}", product, ttl=300)
|
|
66
|
+
return product
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Why developers do it:** The basic cache-aside pattern is what every tutorial teaches. It works perfectly under low concurrency. The failure mode only manifests under production traffic.
|
|
70
|
+
|
|
71
|
+
**What goes wrong:** Facebook's 2010 cache stampede took hours to resolve. A documented e-commerce outage saw database CPU spike to 98%, response times balloon from 20ms to 4,500ms, and checkout pages time out — the 8-minute outage cost an estimated $10M in lost sales.
|
|
72
|
+
|
|
73
|
+
**The fix:**
|
|
74
|
+
```python
|
|
75
|
+
def get_popular_product(product_id):
|
|
76
|
+
key = f"product:{product_id}"
|
|
77
|
+
cached = cache.get(key)
|
|
78
|
+
if cached: return cached
|
|
79
|
+
lock_key = f"lock:{key}"
|
|
80
|
+
if cache.set(lock_key, "1", nx=True, ex=10): # Only one thread rebuilds
|
|
81
|
+
try:
|
|
82
|
+
product = db.query("SELECT * FROM products WHERE id = %s", product_id)
|
|
83
|
+
cache.set(key, product, ttl=300)
|
|
84
|
+
return product
|
|
85
|
+
finally:
|
|
86
|
+
cache.delete(lock_key)
|
|
87
|
+
else:
|
|
88
|
+
time.sleep(0.05)
|
|
89
|
+
return cache.get(key) or get_popular_product(product_id)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Detection rule:** Alert when more than 50 identical queries arrive within a 1-second window. Correlate cache miss rate spikes with database CPU spikes.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### AP-03: Caching Without TTL
|
|
97
|
+
|
|
98
|
+
**Also known as:** Eternal cache, immortal entries, forever cache
|
|
99
|
+
**Frequency:** Very Common | **Severity:** High | **Detection difficulty:** Easy
|
|
100
|
+
|
|
101
|
+
**What it looks like:**
|
|
102
|
+
```python
|
|
103
|
+
cache.set(f"config:{tenant_id}", config_data) # No TTL — lives forever
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Why developers do it:** Redis `SET` does not require a TTL. Developers assume data is "static enough." Some frameworks default to no TTL.
|
|
107
|
+
|
|
108
|
+
**What goes wrong:** GitLab experienced a production outage when redis-cache memory usage forced emergency maintenance to avoid failover — keys without TTL had accumulated unboundedly. Azure Managed Redis users reported multi-hour OOM outages where the cache rejected all writes.
|
|
109
|
+
|
|
110
|
+
**The fix:**
|
|
111
|
+
```python
|
|
112
|
+
class SafeCache:
|
|
113
|
+
DEFAULT_TTL = 3600
|
|
114
|
+
MAX_TTL = 86400
|
|
115
|
+
def set(self, key, value, ttl=None):
|
|
116
|
+
ttl = min(ttl or self.DEFAULT_TTL, self.MAX_TTL)
|
|
117
|
+
self._client.set(key, value, ex=ttl) # TTL enforced at wrapper level
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Detection rule:** Run `redis-cli --scan` and check for keys where `TTL keyname` returns `-1`. Alert if >5% of keys lack TTL.
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
### AP-04: Not Handling Cache Misses Gracefully
|
|
125
|
+
|
|
126
|
+
**Also known as:** Cache-or-crash, missing fallback, brittle read path
|
|
127
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Moderate
|
|
128
|
+
|
|
129
|
+
**What it looks like:**
|
|
130
|
+
```python
|
|
131
|
+
def get_dashboard_data(user_id):
|
|
132
|
+
data = cache.get(f"dashboard:{user_id}")
|
|
133
|
+
return render_dashboard(data) # data is None on miss -> crash or empty page
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Why developers do it:** During development the cache is always warm. The miss path is never exercised locally.
|
|
137
|
+
|
|
138
|
+
**What goes wrong:** A 2026 postmortem titled "The Day Our Cache Became Our Single Point of Failure" documented a Redis cluster restart causing all requests to fall through to a database not provisioned for the full load, taking down the entire service.
|
|
139
|
+
|
|
140
|
+
**The fix:**
|
|
141
|
+
```python
|
|
142
|
+
def get_with_fallback(key, fallback_fn, ttl=300):
|
|
143
|
+
try:
|
|
144
|
+
data = cache.get(key)
|
|
145
|
+
except CacheConnectionError:
|
|
146
|
+
return fallback_fn() # Cache down? Degrade, don't crash
|
|
147
|
+
if data is None:
|
|
148
|
+
data = fallback_fn()
|
|
149
|
+
try: cache.set(key, data, ttl=ttl)
|
|
150
|
+
except CacheConnectionError: pass
|
|
151
|
+
return data
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Detection rule:** Search for `cache.get()` calls not followed by a `None` check. Load-test with an empty cache.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### AP-05: Cache as Source of Truth
|
|
159
|
+
|
|
160
|
+
**Also known as:** Cache-as-database, ephemeral primary, volatile truth
|
|
161
|
+
**Frequency:** Common | **Severity:** Critical | **Detection difficulty:** Hard
|
|
162
|
+
|
|
163
|
+
**What it looks like:**
|
|
164
|
+
```python
|
|
165
|
+
def add_to_cart(user_id, item_id, qty):
|
|
166
|
+
cart = cache.get(f"cart:{user_id}") or {}
|
|
167
|
+
cart[item_id] = qty
|
|
168
|
+
cache.set(f"cart:{user_id}", cart, ttl=86400) # No database write — cache only
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Why developers do it:** Cache writes are fast and simple. "We will add persistence later" — and never do.
|
|
172
|
+
|
|
173
|
+
**What goes wrong:** Any eviction, restart, or failover causes permanent data loss. Users lose shopping carts during peak traffic (when eviction is most likely). Customer support is flooded but there is no way to recover data that was never persisted.
|
|
174
|
+
|
|
175
|
+
**The fix:**
|
|
176
|
+
```python
|
|
177
|
+
def add_to_cart(user_id, item_id, qty):
|
|
178
|
+
db.execute("INSERT INTO cart_items ... ON CONFLICT DO UPDATE ...", user_id, item_id, qty)
|
|
179
|
+
cart = db.query("SELECT * FROM cart_items WHERE user_id = %s", user_id)
|
|
180
|
+
cache.set(f"cart:{user_id}", cart, ttl=3600) # Cache accelerates, DB persists
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Detection rule:** Grep for `cache.set()` not preceded by a database write. Flag data models existing only in Redis with no corresponding table.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### AP-06: Caching Error Responses
|
|
188
|
+
|
|
189
|
+
**Also known as:** Negative caching of failures, error amplification, cached 500s
|
|
190
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Moderate
|
|
191
|
+
|
|
192
|
+
**What it looks like:**
|
|
193
|
+
```python
|
|
194
|
+
try:
|
|
195
|
+
result = http.get(f"https://api.example.com/data/{key}").json()
|
|
196
|
+
except Exception:
|
|
197
|
+
result = {"error": "Service unavailable"}
|
|
198
|
+
cache.set(f"ext:{key}", result, ttl=3600) # Caches the error for 1 hour!
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Why developers do it:** The caching logic does not distinguish success from failure. Google Cloud Apigee documentation specifically identifies this as a common API gateway anti-pattern.
|
|
202
|
+
|
|
203
|
+
**What goes wrong:** An upstream API returns a 500 for 2 seconds during a deployment. The cache stores the error with a 1-hour TTL. Every user gets the cached error for 3,598 seconds longer than necessary.
|
|
204
|
+
|
|
205
|
+
**The fix:**
|
|
206
|
+
```python
|
|
207
|
+
try:
|
|
208
|
+
response = http.get(url)
|
|
209
|
+
response.raise_for_status()
|
|
210
|
+
cache.set(key, response.json(), ttl=3600) # Cache success: long TTL
|
|
211
|
+
except Exception:
|
|
212
|
+
cache.set(f"{key}:neg", True, ttl=10) # Negative cache: short TTL
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Detection rule:** Alert if error-tagged cache entries have TTL > 60 seconds. Review all `cache.set()` calls inside `except` blocks.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### AP-07: Over-Caching
|
|
220
|
+
|
|
221
|
+
**Also known as:** Cache everything, premature caching, cache bloat
|
|
222
|
+
**Frequency:** Common | **Severity:** Medium | **Detection difficulty:** Moderate
|
|
223
|
+
|
|
224
|
+
**What it looks like:**
|
|
225
|
+
```python
|
|
226
|
+
# Separate cache entries for every fragment of user data
|
|
227
|
+
cache.set(f"user:{uid}", user) # user object
|
|
228
|
+
cache.set(f"user_prefs:{uid}", prefs) # preferences
|
|
229
|
+
cache.set(f"user_avatar:{uid}", avatar) # avatar URL
|
|
230
|
+
cache.set(f"user_teams:{uid}", teams) # team memberships
|
|
231
|
+
# Updating a user now requires invalidating 4+ keys (often missed)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Why developers do it:** Once caching works for one endpoint, the instinct is to cache everything. Each addition is individually reasonable; the aggregate is unmanageable.
|
|
235
|
+
|
|
236
|
+
**What goes wrong:** Invalidation becomes a combinatorial explosion. Stale data bugs are frequent but hard to reproduce. The operational cost of maintaining cache consistency exceeds the original performance cost.
|
|
237
|
+
|
|
238
|
+
**The fix:** Cache at the aggregate level for hot paths only. Rule: only cache data read >10x more than written.
|
|
239
|
+
|
|
240
|
+
**Detection rule:** If cache-key-to-table ratio exceeds 5:1, caching is over-fragmented. Keys with hit rates below 10% waste memory.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### AP-08: Under-Caching
|
|
245
|
+
|
|
246
|
+
**Also known as:** Cache-shy, database-for-everything
|
|
247
|
+
**Frequency:** Common | **Severity:** Medium | **Detection difficulty:** Easy
|
|
248
|
+
|
|
249
|
+
**What it looks like:**
|
|
250
|
+
```python
|
|
251
|
+
def get_homepage():
|
|
252
|
+
# 12 DB queries on every page load — data changes once/hour, queried 50,000 times/hour
|
|
253
|
+
featured = db.query("SELECT * FROM products WHERE featured = true")
|
|
254
|
+
categories = db.query("SELECT * FROM categories")
|
|
255
|
+
# ...
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Why developers do it:** Fear of stale data. Past caching bugs. "The database can handle it."
|
|
259
|
+
|
|
260
|
+
**What goes wrong:** When a marketing campaign drives 10x traffic, the un-cached homepage brings down the database cluster, affecting all services.
|
|
261
|
+
|
|
262
|
+
**The fix:** Cache data proportional to its read:write ratio. Any query executing >100 times/minute with identical parameters is a caching candidate.
|
|
263
|
+
|
|
264
|
+
**Detection rule:** Calculate read:write ratios per table — ratio > 50:1 warrants caching. Flag endpoints responsible for >10% of total query volume.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### AP-09: Cache Key Collisions
|
|
269
|
+
|
|
270
|
+
**Also known as:** Key namespace pollution, tenant bleed, hash collision
|
|
271
|
+
**Frequency:** Uncommon | **Severity:** Critical | **Detection difficulty:** Hard
|
|
272
|
+
|
|
273
|
+
**What it looks like:**
|
|
274
|
+
```python
|
|
275
|
+
def get_dashboard(tenant_id):
|
|
276
|
+
cached = cache.get("dashboard_stats") # Same key for ALL tenants!
|
|
277
|
+
if cached: return cached
|
|
278
|
+
stats = db.query("SELECT * FROM stats WHERE tenant_id = %s", tenant_id)
|
|
279
|
+
cache.set("dashboard_stats", stats, ttl=300)
|
|
280
|
+
return stats # Tenant B gets Tenant A's data
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Why developers do it:** Multi-tenancy is added after the caching layer is built. Single-tenant dev environments mask the problem.
|
|
284
|
+
|
|
285
|
+
**What goes wrong:** Pingora (Cloudflare's proxy) disclosed CVE-2026-2836: versions prior to 0.8.0 generated cache keys using only the URI path, excluding the host header, enabling cross-tenant data leakage. A SaaS incident involved Tenant A's financial data written to a generic key and served to Tenant B milliseconds later.
|
|
286
|
+
|
|
287
|
+
**The fix:**
|
|
288
|
+
```python
|
|
289
|
+
def cache_key(tenant_id, resource, resource_id, version="v1"):
|
|
290
|
+
return f"{version}:{tenant_id}:{resource}:{resource_id}"
|
|
291
|
+
# "v1:acme:dashboard:stats" — unique per tenant, versioned
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Detection rule:** Grep for cache keys missing tenant/user/org identifiers in multi-tenant systems. Unit-test key generation with multiple tenants.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### AP-10: Not Warming Caches
|
|
299
|
+
|
|
300
|
+
**Also known as:** Cold start penalty, empty cache deployment, first-request tax
|
|
301
|
+
**Frequency:** Common | **Severity:** Medium | **Detection difficulty:** Easy
|
|
302
|
+
|
|
303
|
+
**What it looks like:** Application deploys with empty cache. First 10,000 users all hit the database simultaneously. Response times: 2,000ms until cache fills, 20ms after.
|
|
304
|
+
|
|
305
|
+
**Why developers do it:** Cache warming requires extra infrastructure. Teams treat cache as a transparent layer that "will fill up on its own."
|
|
306
|
+
|
|
307
|
+
**What goes wrong:** During rolling deployment of 20 servers with in-memory caching, the first minute sees 20x database load spike. Combined with stampede on hot keys, this cascades into a full outage.
|
|
308
|
+
|
|
309
|
+
**The fix:**
|
|
310
|
+
```python
|
|
311
|
+
def on_startup():
|
|
312
|
+
hot_keys = db.query("SELECT key FROM cache_manifest WHERE priority = 'critical'")
|
|
313
|
+
for k in hot_keys:
|
|
314
|
+
cache.set(k.key, fetch_from_source(k), ttl=k.ttl)
|
|
315
|
+
logger.info(f"Warmed {len(hot_keys)} cache entries")
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Detection rule:** Compare p99 latency at T+0 vs T+10 minutes post-deploy. If ratio >5x, cache warming is needed.
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
### AP-11: Infinite Cache Growth
|
|
323
|
+
|
|
324
|
+
**Also known as:** Unbounded cache, memory leak via cache, OOM time bomb
|
|
325
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Moderate
|
|
326
|
+
|
|
327
|
+
**What it looks like:**
|
|
328
|
+
```python
|
|
329
|
+
app_cache = {} # Unbounded dict — unique queries accumulate forever
|
|
330
|
+
def get_search_results(query):
|
|
331
|
+
if query not in app_cache:
|
|
332
|
+
app_cache[query] = db.search(query)
|
|
333
|
+
return app_cache[query]
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
**Why developers do it:** Python dicts are easy caches with zero dependencies. Redis defaults to no memory limit on many installations.
|
|
337
|
+
|
|
338
|
+
**What goes wrong:** GitLab production outage from redis-cache memory exhaustion forced emergency maintenance. AWS ElastiCache users documented multi-hour OOM outages where Redis rejected all writes while reads served increasingly stale data.
|
|
339
|
+
|
|
340
|
+
**The fix:**
|
|
341
|
+
```python
|
|
342
|
+
from cachetools import TTLCache
|
|
343
|
+
app_cache = TTLCache(maxsize=10000, ttl=600) # Bounded + TTL
|
|
344
|
+
# Redis: always set maxmemory 2gb + maxmemory-policy allkeys-lru
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Detection rule:** Monitor Redis memory; alert at 70% of `maxmemory`. Flag bare `dict` used as cache without size limits.
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
### AP-12: Distributed Cache Inconsistency
|
|
352
|
+
|
|
353
|
+
**Also known as:** Split-brain cache, replica drift, cross-region staleness
|
|
354
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Hard
|
|
355
|
+
|
|
356
|
+
**What it looks like:**
|
|
357
|
+
```python
|
|
358
|
+
# Service A writes to primary: redis_primary.set("inventory:42", 0) # sold out
|
|
359
|
+
# Service B reads from replica: redis_replica.get("inventory:42") # -> 5 (stale) -> overselling
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Why developers do it:** Read replicas are standard scaling. Replication lag is usually milliseconds — invisible in testing. The 0.1% inconsistency matters for financial data and inventory.
|
|
363
|
+
|
|
364
|
+
**What goes wrong:** Facebook's Memcached architecture documented permanent stale data from concurrent updates to different cached copies in different orders. A documented inventory incident: Instance A decremented from 700 to 690, Instance B decremented from 700 to 695, replication messages crossed, final count 695 instead of correct 685.
|
|
365
|
+
|
|
366
|
+
**The fix:** Read from primary for critical paths. Publish invalidation events. Use short TTLs as safety nets.
|
|
367
|
+
|
|
368
|
+
**Detection rule:** Compare values between primary and replica for critical keys. Alert when replication lag >100ms for financial data.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
### AP-13: Caching User-Specific Data Globally
|
|
373
|
+
|
|
374
|
+
**Also known as:** Shared personal data, auth context leak, session bleed
|
|
375
|
+
**Frequency:** Uncommon | **Severity:** Critical | **Detection difficulty:** Hard
|
|
376
|
+
|
|
377
|
+
**What it looks like:**
|
|
378
|
+
```python
|
|
379
|
+
@app.route("/dashboard")
|
|
380
|
+
def dashboard():
|
|
381
|
+
user = get_current_user()
|
|
382
|
+
response = make_response(render_template("dashboard.html", user=user))
|
|
383
|
+
response.headers["Cache-Control"] = "public, max-age=300" # CDN caches this!
|
|
384
|
+
return response # User A's bank balance served to User B
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Why developers do it:** CDN caching added globally without distinguishing public from authenticated pages.
|
|
388
|
+
|
|
389
|
+
**What goes wrong:** The Cloudbleed incident (2017) exposed private data — cookies, auth tokens, POST bodies — from Cloudflare customers to other customers through cached memory. Over 18 million requests potentially leaked data. Application-level incidents have served one user's financial dashboard to other users via CDN.
|
|
390
|
+
|
|
391
|
+
**The fix:**
|
|
392
|
+
```python
|
|
393
|
+
@app.after_request
|
|
394
|
+
def set_cache_headers(response):
|
|
395
|
+
if hasattr(g, 'current_user') and g.current_user:
|
|
396
|
+
response.headers["Cache-Control"] = "private, no-store"
|
|
397
|
+
return response
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Detection rule:** Scan authenticated endpoints for `Cache-Control: public`. Flag CDN-cached URLs returning `Set-Cookie`.
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
### AP-14: Cache Penetration
|
|
405
|
+
|
|
406
|
+
**Also known as:** Cache-miss attack, nonexistent key flood, phantom query storm
|
|
407
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Moderate
|
|
408
|
+
|
|
409
|
+
**What it looks like:**
|
|
410
|
+
```python
|
|
411
|
+
def get_user(user_id):
|
|
412
|
+
cached = cache.get(f"user:{user_id}")
|
|
413
|
+
if cached: return cached
|
|
414
|
+
user = db.query("SELECT * FROM users WHERE id = %s", user_id)
|
|
415
|
+
if user: cache.set(f"user:{user_id}", user, ttl=3600)
|
|
416
|
+
return user # IDs -1, -2, -3... always miss cache AND DB
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Why developers do it:** Only positive results are cached. Nonexistent keys bypass both cache and database on every request.
|
|
420
|
+
|
|
421
|
+
**What goes wrong:** Attackers send millions of requests for nonexistent IDs. Every request bypasses cache and hits the database. 100% miss rate sustained indefinitely.
|
|
422
|
+
|
|
423
|
+
**The fix:**
|
|
424
|
+
```python
|
|
425
|
+
EMPTY = "__NULL__"
|
|
426
|
+
def get_user(user_id):
|
|
427
|
+
if not bloom_filter.might_contain(f"user:{user_id}"): return None # O(1) reject
|
|
428
|
+
cached = cache.get(f"user:{user_id}")
|
|
429
|
+
if cached == EMPTY: return None
|
|
430
|
+
if cached: return cached
|
|
431
|
+
user = db.query("SELECT * FROM users WHERE id = %s", user_id)
|
|
432
|
+
cache.set(f"user:{user_id}", user if user else EMPTY, ttl=3600 if user else 60)
|
|
433
|
+
return user
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Detection rule:** Alert if cache miss rate exceeds 90% for a key pattern. Monitor for high volumes of "row not found" queries.
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
### AP-15: Dog-Pile Effect
|
|
441
|
+
|
|
442
|
+
**Also known as:** Cache rebuild storm, recompute avalanche, hot key reconstruction
|
|
443
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Moderate
|
|
444
|
+
|
|
445
|
+
**What it looks like:**
|
|
446
|
+
```python
|
|
447
|
+
def get_leaderboard():
|
|
448
|
+
cached = cache.get("leaderboard")
|
|
449
|
+
if cached: return cached
|
|
450
|
+
# 30-second aggregation query — 500 concurrent users trigger 500 parallel copies
|
|
451
|
+
leaderboard = db.query("SELECT user_id, SUM(score) ... GROUP BY ... ORDER BY ... LIMIT 100")
|
|
452
|
+
cache.set("leaderboard", leaderboard, ttl=300)
|
|
453
|
+
return leaderboard
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
**Why developers do it:** A specific variant of stampede (AP-02) for expensive computations. The longer the rebuild, the worse the pile-up.
|
|
457
|
+
|
|
458
|
+
**What goes wrong:** A gaming platform's leaderboard cache expired during peak hours. The 45-second query attracted 12,000 concurrent requests, each spawning its own copy. Connection pool exhausted in 3 seconds. 20-minute outage — 19 minutes longer than one query would have taken.
|
|
459
|
+
|
|
460
|
+
**The fix:**
|
|
461
|
+
```python
|
|
462
|
+
def get_leaderboard():
|
|
463
|
+
cached, ttl_remaining = cache.get_with_ttl("leaderboard")
|
|
464
|
+
if cached:
|
|
465
|
+
if ttl_remaining < 60: trigger_background_refresh("leaderboard") # Async rebuild
|
|
466
|
+
return cached # Serve stale while refreshing
|
|
467
|
+
return compute_with_lock() # First load only
|
|
468
|
+
# Schedule background refresh every 4 min (before 5-min TTL expires)
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Detection rule:** Identify cache keys with recomputation > 1 second. Alert on >2 concurrent executions of the same expensive query.
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
### AP-16: Not Versioning Cache Keys
|
|
476
|
+
|
|
477
|
+
**Also known as:** Schema-cache mismatch, deployment cache poison, format drift
|
|
478
|
+
**Frequency:** Common | **Severity:** High | **Detection difficulty:** Hard
|
|
479
|
+
|
|
480
|
+
**What it looks like:**
|
|
481
|
+
```python
|
|
482
|
+
# v1 cached: {"name": "Alice", "email": "a@co.com"}
|
|
483
|
+
# v2 code expects: user["role"] -> KeyError! Old schema in cache
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**Why developers do it:** Cache keys are treated as permanent. Rolling deployments mean old and new code coexist, reading/writing different formats with the same keys.
|
|
487
|
+
|
|
488
|
+
**What goes wrong:** New instances write `v2` format, old instances expect `v1`. Requests randomly succeed or fail depending on which instance handles them and which version is cached. Extremely hard to reproduce.
|
|
489
|
+
|
|
490
|
+
**The fix:**
|
|
491
|
+
```python
|
|
492
|
+
CACHE_VERSION = "v3" # Bump on every schema change
|
|
493
|
+
def cache_key(resource, resource_id):
|
|
494
|
+
return f"{CACHE_VERSION}:{resource}:{resource_id}"
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
**Detection rule:** Flag deployments that change cached data structures without bumping a version constant. Monitor deserialization errors in cache reads.
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
### AP-17: Caching at the Wrong Layer
|
|
502
|
+
|
|
503
|
+
**Also known as:** Misplaced cache, layer confusion, redundant caching
|
|
504
|
+
**Frequency:** Common | **Severity:** Medium | **Detection difficulty:** Moderate
|
|
505
|
+
|
|
506
|
+
**What it looks like:**
|
|
507
|
+
```python
|
|
508
|
+
@app.route("/api/products/<pid>")
|
|
509
|
+
def get_product(pid):
|
|
510
|
+
cached = cache.get(f"product_response:{pid}")
|
|
511
|
+
if cached: return cached # Cached as serialized HTTP response
|
|
512
|
+
product = product_service.get(pid)
|
|
513
|
+
response = jsonify(product)
|
|
514
|
+
cache.set(f"product_response:{pid}", response, ttl=300)
|
|
515
|
+
return response
|
|
516
|
+
# Mobile API, gRPC, admin panel — none benefit from this cache
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
**Why developers do it:** Controller-level caching is the easiest to add. It requires no changes to business logic.
|
|
520
|
+
|
|
521
|
+
**What goes wrong:** Updating a product requires clearing REST cache, GraphQL cache, mobile cache, admin cache — each with different keys. One is missed; one consumer serves stale data.
|
|
522
|
+
|
|
523
|
+
**The fix:** Cache at the service/repository layer. All consumers (REST, GraphQL, gRPC) share one cache with one invalidation point.
|
|
524
|
+
|
|
525
|
+
**Detection rule:** Search for `cache.get`/`cache.set` in controller/handler files. Cache should live in service or repository layers.
|
|
526
|
+
|
|
527
|
+
---
|
|
528
|
+
|
|
529
|
+
### AP-18: Multi-Level Cache Inconsistency
|
|
530
|
+
|
|
531
|
+
**Also known as:** L1/L2 desync, layered cache drift, tiered staleness
|
|
532
|
+
**Frequency:** Uncommon | **Severity:** High | **Detection difficulty:** Very Hard
|
|
533
|
+
|
|
534
|
+
**What it looks like:**
|
|
535
|
+
```python
|
|
536
|
+
def update_config(key, value):
|
|
537
|
+
db.execute("UPDATE config SET value = %s WHERE key = %s", value, key)
|
|
538
|
+
redis.delete(f"config:{key}") # Invalidate L2 (shared Redis)
|
|
539
|
+
# But L1 (in-process memory) on all 20 instances still has old value!
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
**Why developers do it:** L1 eliminates network round-trips, L2 eliminates repeated computation. But invalidation must propagate through all levels — developers invalidate L2 and forget L1.
|
|
543
|
+
|
|
544
|
+
**What goes wrong:** Microsoft documents that HybridCache's L1 does not synchronize across nodes — Node B serves stale data until L1 expires. A config change (feature flag, rate limit) propagates to Redis but 20 app instances enforce the old value from their L1 caches for the remaining TTL.
|
|
545
|
+
|
|
546
|
+
**The fix:**
|
|
547
|
+
```python
|
|
548
|
+
def update_config(key, value):
|
|
549
|
+
db.execute("UPDATE config SET value = %s WHERE key = %s", value, key)
|
|
550
|
+
redis.delete(f"config:{key}") # Invalidate L2
|
|
551
|
+
local_cache.pop(key, None) # Invalidate local L1
|
|
552
|
+
pubsub.publish("cache_inv", key) # Broadcast to all instances
|
|
553
|
+
|
|
554
|
+
def on_cache_invalidation(key):
|
|
555
|
+
local_cache.pop(key, None) # Clear L1 on every node
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
**Detection rule:** Verify invalidation touches every cache level. Set L1 TTL shorter than L2 TTL. Test by updating a value and reading from multiple instances.
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## Root Cause Analysis
|
|
563
|
+
|
|
564
|
+
| Root Cause | Anti-Patterns It Drives | Mitigation |
|
|
565
|
+
|---|---|---|
|
|
566
|
+
| Read/write paths built separately | AP-01, AP-05, AP-16 | Cache-aside with invalidation hooks at the repository layer |
|
|
567
|
+
| Caching added without concurrency analysis | AP-02, AP-15 | Locking, probabilistic early recompute, background refresh |
|
|
568
|
+
| Default configs accepted without review | AP-03, AP-11 | Enforce TTL and maxmemory via wrapper classes |
|
|
569
|
+
| Happy-path-only development | AP-04, AP-06, AP-14 | Chaos testing: empty cache, cache down, nonexistent keys |
|
|
570
|
+
| Cache treated as durable storage | AP-05, AP-01 | Rule: cache is always a derived, disposable copy |
|
|
571
|
+
| Single-tenant dev, multi-tenant production | AP-09, AP-13 | Tenant ID in every key; multi-tenant integration tests |
|
|
572
|
+
| Optimization without measurement | AP-07, AP-08 | Profile before caching; track hit rates and read:write ratios |
|
|
573
|
+
| Ignoring deployment-time state transitions | AP-10, AP-16 | Warming scripts; versioned keys; blue-green deploys |
|
|
574
|
+
| Not modeling distributed propagation | AP-12, AP-18 | Pub/sub invalidation; short L1 TTLs; read-your-writes |
|
|
575
|
+
| Cache placed in wrong architectural tier | AP-17, AP-07 | Cache at service/repository layer, not HTTP handlers |
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## Self-Check Questions
|
|
580
|
+
|
|
581
|
+
1. **What happens when this cache key expires under high concurrency?** Can 1,000 requests simultaneously rebuild it? (AP-02, AP-15)
|
|
582
|
+
2. **If Redis restarts right now, does the app crash or degrade gracefully?** (AP-04, AP-05)
|
|
583
|
+
3. **Every `cache.set()` has a corresponding invalidation — where is it?** Can I trace every mutation path? (AP-01)
|
|
584
|
+
4. **Does every cache key include all discriminators?** Tenant ID, user ID, locale, API version? (AP-09, AP-13)
|
|
585
|
+
5. **What is the maximum memory this cache can consume?** Is there `maxmemory` or `maxsize`? (AP-03, AP-11)
|
|
586
|
+
6. **Am I caching errors?** If upstream fails, do I cache the failure for an hour? (AP-06)
|
|
587
|
+
7. **What happens on the first request after deployment?** Cold cache? How long until performance stabilizes? (AP-10)
|
|
588
|
+
8. **If I change cached data schema, what happens to existing entries?** (AP-16)
|
|
589
|
+
9. **Am I caching at the right layer?** Would service-layer caching benefit multiple consumers? (AP-17)
|
|
590
|
+
10. **For multi-level caches: does invalidation propagate to ALL levels?** (AP-18)
|
|
591
|
+
11. **What is the read:write ratio?** If <10:1, is caching worth the invalidation complexity? (AP-07, AP-08)
|
|
592
|
+
12. **Can an attacker force 100% cache miss rates?** (AP-14)
|
|
593
|
+
13. **Is `Cache-Control` correct for authenticated endpoints?** Any user-specific responses marked `public`? (AP-13)
|
|
594
|
+
14. **In a distributed cache, what is the replication lag?** Can stale reads cause overselling? (AP-12)
|
|
595
|
+
15. **Can I delete the entire cache right now and the system still works?** If no, the cache is the source of truth. (AP-05)
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Code Smell Quick Reference
|
|
600
|
+
|
|
601
|
+
| Code Smell | Likely Anti-Pattern | Quick Check |
|
|
602
|
+
|---|---|---|
|
|
603
|
+
| `cache.set()` without `ttl`/`ex` parameter | AP-03: No TTL | Grep `\.set\(` without TTL arg |
|
|
604
|
+
| `cache.set()` with no corresponding `cache.delete()` | AP-01: No invalidation | Trace DB writes; verify invalidation |
|
|
605
|
+
| `cache.get()` with no `None` check or fallback | AP-04: No miss handling | Find `cache.get` without conditional |
|
|
606
|
+
| `Cache-Control: public` on authenticated routes | AP-13: Global user data | Scan response headers on `/api/*` |
|
|
607
|
+
| Cache key without tenant prefix in multi-tenant app | AP-09: Key collision | Grep keys for missing scope IDs |
|
|
608
|
+
| `cache.set()` inside `except` block | AP-06: Caching errors | Find cache writes in error handlers |
|
|
609
|
+
| `dict`/`HashMap` as cache without size bound | AP-11: Infinite growth | Find unbounded in-memory caches |
|
|
610
|
+
| `cache.set()` in HTTP handler/controller | AP-17: Wrong layer | Cache belongs in service/repo layer |
|
|
611
|
+
| Cache key without version prefix | AP-16: No versioning | Check key format for version component |
|
|
612
|
+
| `cache.get()` as only data source (no DB fallback) | AP-05: Cache as truth | Verify DB fallback exists |
|
|
613
|
+
| Multiple `cache.set()` for same data in different formats | AP-07: Over-caching | Look for duplicate caching |
|
|
614
|
+
| Expensive query (>1s) with simple cache-aside | AP-15: Dog-pile risk | Needs locking or background refresh |
|
|
615
|
+
| `redis.delete()` without `local_cache.pop()` | AP-18: L1/L2 desync | Verify all cache tiers invalidated |
|
|
616
|
+
| No negative caching for user lookups | AP-14: Penetration | Add null sentinel or Bloom filter |
|
|
617
|
+
| `maxmemory` not set in `redis.conf` | AP-11: Infinite growth | Audit Redis configuration |
|
|
618
|
+
| No cache metrics (hit/miss/eviction rates) | All patterns | Instrument all cache operations |
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
*Researched: 2026-03-08 | Sources: [Facebook Memcached Scaling (NSDI 2013)](https://www.usenix.org/conference/nsdi13/technical-sessions/presentation/nishtala), [Cloudbleed Incident Report](https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/), [GitLab Redis-Cache Outage](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/482), [Pingora CVE-2026-2836](https://advisories.gitlab.com/pkg/cargo/pingora-cache/CVE-2026-2836/), [Google Cloud Memorystore Best Practices](https://docs.cloud.google.com/memorystore/docs/redis/memory-management-best-practices), [Google Apigee Caching Error Anti-Pattern](https://docs.cloud.google.com/apigee/docs/api-platform/antipatterns/caching-error), [AWS ElastiCache OOM Troubleshooting](https://repost.aws/knowledge-center/oom-command-not-allowed-redis), [Next.js Cache Poisoning CVE-2025-49826](https://zeropath.com/blog/nextjs-cache-poisoning-cve-2025-49826), [HybridCache Distributed Invalidation](https://www.milanjovanovic.tech/blog/solving-the-distributed-cache-invalidation-problem-with-redis-and-hybridcache), [Cache Stampede & Thundering Herd](https://distributed-computing-musings.com/2021/12/thundering-herd-cache-stampede/), [Redis Cache Invalidation Bug Postmortem](https://dev.to/jayesh_shinde/how-a-cache-invalidation-bug-nearly-took-down-our-system-and-what-we-changed-after-2dd2), [Cache as Single Point of Failure Postmortem](https://naveen-metta.medium.com/the-day-our-cache-became-our-single-point-of-failure-a-postmortem-758dc85364fc)*
|