@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,757 @@
|
|
|
1
|
+
# Feature Flags and Rollouts — Architecture Expertise Module
|
|
2
|
+
|
|
3
|
+
> Feature flags decouple deployment from release — code ships to production but features activate independently via configuration. Combined with progressive rollouts (canary, percentage-based, ring-based), they dramatically reduce deployment risk. But feature flags accumulate as technical debt and require active lifecycle management. Treat every flag as a short-lived construct with an expiration date, not a permanent branch in your code.
|
|
4
|
+
|
|
5
|
+
> **Category:** Scaling
|
|
6
|
+
> **Complexity:** Moderate
|
|
7
|
+
> **Applies when:** Teams practicing continuous deployment, releasing features to subsets of users, A/B testing, managing feature access by tenant/plan, or needing kill switches for operational safety
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What This Is (and What It Isn't)
|
|
12
|
+
|
|
13
|
+
A feature flag (also called a feature toggle, feature switch, or feature gate) is a **runtime configuration mechanism that controls whether a code path is active without redeploying the application**. At its simplest, it is a conditional branch:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
if feature_flags.is_enabled("new_checkout_flow", user=current_user):
|
|
17
|
+
return render_new_checkout(cart)
|
|
18
|
+
else:
|
|
19
|
+
return render_legacy_checkout(cart)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
But a production-grade feature flag system is far more than an `if` statement. It includes:
|
|
23
|
+
|
|
24
|
+
- **Targeting rules** — flag checks per-user, per-segment, per-tenant, per-geography, per-percentage
|
|
25
|
+
- **Flag lifecycle management** — creation, activation, GA promotion, and removal
|
|
26
|
+
- **Audit trails** — who changed what flag, when, and why
|
|
27
|
+
- **Real-time propagation** — flag changes take effect in seconds across all running instances
|
|
28
|
+
- **SDK-based checking** — server-side and client-side SDKs that check flags locally for performance
|
|
29
|
+
|
|
30
|
+
The concept originated in the mid-2000s at companies like Flickr (feature flippers, 2009) and Facebook (Gatekeeper, 2008), where deploying to millions of users demanded a way to separate "code is deployed" from "feature is live." Martin Fowler formalized the taxonomy in his seminal 2017 article on Feature Toggles, which remains the definitive reference.
|
|
31
|
+
|
|
32
|
+
### The Four Categories of Feature Flags
|
|
33
|
+
|
|
34
|
+
Not all flags are equal. Each category has different lifespans, ownership, and risk profiles:
|
|
35
|
+
|
|
36
|
+
| Category | Purpose | Lifespan | Owner | Example |
|
|
37
|
+
|---|---|---|---|---|
|
|
38
|
+
| **Release flags** | Decouple deployment from release; hide incomplete features | Days to weeks | Engineering | `enable_new_search_ui` |
|
|
39
|
+
| **Experiment flags** | A/B testing, multivariate testing | Weeks to months | Product/Growth | `checkout_flow_variant` (A/B/C) |
|
|
40
|
+
| **Ops flags** | Kill switches, circuit breakers, load shedding | Permanent (but rarely toggled) | SRE/Operations | `disable_recommendation_engine` |
|
|
41
|
+
| **Permission flags** | Entitlement gating, plan-based access | Permanent | Product/Business | `enable_premium_analytics` |
|
|
42
|
+
|
|
43
|
+
**Release flags** are the most common and the most dangerous from a debt perspective — they should be removed within days of a feature going to 100%, but in practice they linger for months or years.
|
|
44
|
+
|
|
45
|
+
**Experiment flags** carry multivariate values (not just boolean) and require statistical rigor — they integrate with analytics pipelines and demand sample size calculations before activation.
|
|
46
|
+
|
|
47
|
+
**Ops flags** are the safest category because they represent an intentional permanent control plane. A kill switch for a non-critical subsystem (`disable_email_notifications`) is a legitimate operational tool, not debt.
|
|
48
|
+
|
|
49
|
+
**Permission flags** overlap with entitlement/authorization systems. In multi-tenant SaaS, these often map to plan tiers (free/pro/enterprise) and should ideally live in the authorization layer, not the feature flag system.
|
|
50
|
+
|
|
51
|
+
### What Feature Flags Are NOT
|
|
52
|
+
|
|
53
|
+
- **Not a replacement for proper branching strategy.** Flags enable trunk-based development, but the code behind the flag still needs design, review, and testing. A flag does not excuse merging untested code.
|
|
54
|
+
- **Not a permanent architectural construct.** Release and experiment flags must have an expiration date. A flag that has been "on" for all users for six months is not a feature flag — it is dead code and a liability.
|
|
55
|
+
- **Not an authorization system.** While permission flags can gate features by plan/role, complex authorization logic belongs in a dedicated authz layer (RBAC, ABAC, policy engines) — not in feature flag conditionals scattered across the codebase.
|
|
56
|
+
- **Not a configuration management system.** Feature flags control feature activation. Application configuration (database URLs, timeout values, retry counts) belongs in environment variables or configuration services. Conflating the two creates a sprawling, unmanageable flag inventory.
|
|
57
|
+
- **Not free.** Every flag adds a branch to your code. Two flags create 4 possible states. Ten flags create 1,024. Twenty flags create over a million. The combinatorial explosion in testing and reasoning about system behavior is a real cost.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## When to Use It
|
|
62
|
+
|
|
63
|
+
### Trunk-based development with continuous deployment
|
|
64
|
+
|
|
65
|
+
Feature flags are the essential enabler of trunk-based development (TBD) — the practice where all developers commit to a single main branch, integrating changes multiple times per day. Without flags, incomplete features on trunk would be exposed to users. With flags, developers merge daily, incomplete features ship behind flags in the "off" state, and the codebase stays permanently deployable.
|
|
66
|
+
|
|
67
|
+
**Google, Facebook, and LinkedIn** all practice trunk-based development at massive scale. Google's entire codebase (billions of lines) lives in a single repository with a single branch, and feature flags (via their internal "Gating" system) control what is visible to users.
|
|
68
|
+
|
|
69
|
+
The workflow: developer creates a flag, writes code behind the flag, merges to trunk daily, deploys to production (flag off), gradually rolls out via targeting rules, reaches 100%, removes the flag. No long-lived branches, no merge hell, no "big bang" integration.
|
|
70
|
+
|
|
71
|
+
### Gradual rollouts to reduce blast radius
|
|
72
|
+
|
|
73
|
+
When a feature impacts millions of users, releasing to 100% simultaneously is reckless. Progressive rollout strategies use feature flags to control exposure:
|
|
74
|
+
|
|
75
|
+
- **Canary (1%)** — deploy to a tiny fraction, monitor error rates and latency
|
|
76
|
+
- **Early adopters (10%)** — expand to opted-in users or internal employees
|
|
77
|
+
- **Broader rollout (25% to 50%)** — increase while watching metrics
|
|
78
|
+
- **General availability (100%)** — full release, then remove the flag
|
|
79
|
+
|
|
80
|
+
**Netflix** uses this pattern extensively. A new recommendation algorithm might serve 1% of users for a week while engineers monitor engagement metrics, error rates, and latency percentiles. Only when the data shows positive or neutral impact does the rollout expand.
|
|
81
|
+
|
|
82
|
+
### A/B testing and experimentation
|
|
83
|
+
|
|
84
|
+
Multivariate feature flags are the backbone of product experimentation. An experiment flag assigns users to cohorts (control vs. variant A vs. variant B) and tracks conversion metrics per cohort. This requires:
|
|
85
|
+
|
|
86
|
+
- Consistent assignment (same user always sees same variant for the experiment duration)
|
|
87
|
+
- Statistical significance tracking
|
|
88
|
+
- Integration with analytics/data pipelines
|
|
89
|
+
- Mutual exclusion between overlapping experiments
|
|
90
|
+
|
|
91
|
+
**Booking.com** runs over 1,000 concurrent A/B tests at any time. Their experimentation platform is built on feature flags with multivariate assignment, and they attribute much of their revenue optimization to disciplined experimentation.
|
|
92
|
+
|
|
93
|
+
### Kill switches for operational safety
|
|
94
|
+
|
|
95
|
+
Ops flags let you instantly disable non-critical subsystems when the system is under stress. During a traffic spike that threatens database capacity, an ops flag can disable the recommendation engine, email notifications, or analytics tracking — shedding load without a deployment.
|
|
96
|
+
|
|
97
|
+
This is one of the few legitimate uses of a permanent feature flag. The flag exists as a documented operational control, not as a temporary release mechanism.
|
|
98
|
+
|
|
99
|
+
### Tenant-specific and plan-based feature gating
|
|
100
|
+
|
|
101
|
+
In multi-tenant SaaS systems, feature flags control which tenants or plan tiers have access to specific features. Enterprise customers get advanced analytics; free-tier users see the basic dashboard. This is particularly useful during migrations — you can gradually roll out a new billing system tenant-by-tenant rather than switching everyone simultaneously.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## When NOT to Use It
|
|
106
|
+
|
|
107
|
+
**This section is deliberately long because feature flag debt is one of the most insidious forms of technical debt — it accumulates silently, creates combinatorial complexity, and has caused some of the most expensive incidents in software history.**
|
|
108
|
+
|
|
109
|
+
### When you have no plan for flag removal
|
|
110
|
+
|
|
111
|
+
If your team creates flags but has no process for removing them, you will accumulate hundreds of stale flags within a year. Each stale flag is a branch in your code that no one understands, no one tests, and no one wants to remove because "what if we need it again?"
|
|
112
|
+
|
|
113
|
+
**Real-world evidence:** Industry surveys consistently show that most organizations have hundreds of stale flags in their codebases. The average flag lives 10x longer than intended. A codebase with 200 stale flags is harder to maintain, harder to reason about, and harder to test than a codebase with zero flags.
|
|
114
|
+
|
|
115
|
+
**The rule:** Never create a flag without an expiration date and an assigned owner responsible for removal. If your team cannot commit to this discipline, do not adopt feature flags — they will hurt you more than they help.
|
|
116
|
+
|
|
117
|
+
### When testing discipline is insufficient
|
|
118
|
+
|
|
119
|
+
With N boolean flags, you have 2^N possible system states. Ten flags create 1,024 states. Most teams test exactly two: all flags on, all flags off. The remaining 1,022 states are untested and potentially broken.
|
|
120
|
+
|
|
121
|
+
**Practical mitigation exists** (pairwise testing, modular isolation, testing only the "current production state" plus the "next flag flip"), but it requires engineering discipline. Teams that do not test flag combinations will eventually ship a broken state to production.
|
|
122
|
+
|
|
123
|
+
**Martin Fowler's guidance:** "It can be very challenging to do traditional automated integration testing with feature flags. You do not need to test every combination — but you must test the disaster scenario (all flags off) and the current production state."
|
|
124
|
+
|
|
125
|
+
### When flags substitute for proper architecture
|
|
126
|
+
|
|
127
|
+
A feature flag should wrap a cohesive feature, not be woven through dozens of files. If enabling a feature requires 47 `if` checks scattered across the codebase, the problem is not the flag — it is the architecture. The feature is not properly modularized.
|
|
128
|
+
|
|
129
|
+
**Anti-pattern:** Using flags to manage divergent implementations of the same feature across multiple services. If your "new payments flow" requires coordinated flag states across the payments service, the notifications service, the analytics service, and the frontend, you have a distributed feature flag — which is a distributed monolith in disguise.
|
|
130
|
+
|
|
131
|
+
### When you are using flags as an excuse for sloppy code
|
|
132
|
+
|
|
133
|
+
Wrapping performance-critical code in feature toggles as kill switches creates a false sense of security. "We can always turn it off" becomes an excuse for shipping code that is too slow, too resource-hungry, or too fragile. The kill switch does not fix the underlying problem — it hides it until someone forgets to test the "on" state.
|
|
134
|
+
|
|
135
|
+
### The Knight Capital disaster — $460 million in 45 minutes
|
|
136
|
+
|
|
137
|
+
On August 1, 2012, Knight Capital Group — which controlled 17% of NYSE trading volume — lost $460 million in 45 minutes because of a stale feature flag.
|
|
138
|
+
|
|
139
|
+
**What happened:** Developers replaced legacy trading code with new logic and repurposed an old feature flag to control activation. The deployment succeeded on 7 of 8 servers, but silently failed on the 8th. When the flag was enabled, 7 servers ran the new code correctly; the 8th ran the legacy code, which executed an obsolete trading strategy that hemorrhaged money.
|
|
140
|
+
|
|
141
|
+
**The cascade:** When operators noticed the problem, they attempted a rollback — but they did not know the flag was the root cause. They did not turn the flag off. Instead, they redeployed the old code to all 8 servers, which meant all servers now ran the legacy trading strategy. Losses compounded from millions to hundreds of millions.
|
|
142
|
+
|
|
143
|
+
**The lessons:**
|
|
144
|
+
1. Stale flags are ticking time bombs — the repurposed flag should have been removed years earlier.
|
|
145
|
+
2. Flag states must be observable — operators could not see which flag states were active on which servers.
|
|
146
|
+
3. Rollback procedures must account for flag states — "redeploy old code" is not sufficient when flags control behavior independently of the deployment.
|
|
147
|
+
|
|
148
|
+
Knight Capital filed for bankruptcy protection within days.
|
|
149
|
+
|
|
150
|
+
### When flag checking becomes a performance bottleneck
|
|
151
|
+
|
|
152
|
+
Every flag check has a cost. In hot code paths (inner loops, per-request middleware, real-time data processing), flag lookups can add measurable latency. Server-side SDKs with local caching mitigate this (lookup is a local hash table read, not a network call), but client-side SDKs that phone home for every check can degrade performance significantly.
|
|
153
|
+
|
|
154
|
+
**Rule of thumb:** If your code path executes more than 10,000 times per second, ensure flag lookup is a local in-memory read with sub-microsecond latency. Never make a network call per lookup in a hot path.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## How It Works
|
|
159
|
+
|
|
160
|
+
### Flag Checking Architecture
|
|
161
|
+
|
|
162
|
+
There are two fundamentally different models, and choosing the wrong one creates security and performance problems.
|
|
163
|
+
|
|
164
|
+
**Server-side model (recommended for most use cases):**
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
+--------------+ +------------------+ +--------------+
|
|
168
|
+
| Flag Mgmt |---->| Server-Side SDK |---->| Application |
|
|
169
|
+
| Service | | (local cache) | | Code |
|
|
170
|
+
| | | | | |
|
|
171
|
+
| - Rules | | - Fetches config | | - Calls |
|
|
172
|
+
| - Segments | | on startup + | | sdk.check()|
|
|
173
|
+
| - Targeting | | streams updates| | with user |
|
|
174
|
+
| | | - Checks | | context |
|
|
175
|
+
| | | locally | | |
|
|
176
|
+
+--------------+ +------------------+ +--------------+
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The server-side SDK downloads the full flag configuration (rules, segments, percentages) on startup and keeps it in memory via a streaming connection (SSE or WebSocket). Flag lookups are a local operation — no network call per request. The application passes user context (user ID, email, plan, country) to the SDK, which applies targeting rules locally and returns the flag value.
|
|
180
|
+
|
|
181
|
+
**Advantages:** Fast lookups (microseconds), no client-side data exposure, full targeting rule complexity, works for any backend language.
|
|
182
|
+
|
|
183
|
+
**Client-side model (for frontend/mobile):**
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
+--------------+ +------------------+ +--------------+
|
|
187
|
+
| Flag Mgmt |---->| Checking |---->| Client SDK |
|
|
188
|
+
| Service | | Service (edge) | | (browser/ |
|
|
189
|
+
| | | | | mobile) |
|
|
190
|
+
| - Rules | | - Receives user | | |
|
|
191
|
+
| - Segments | | context | | - Sends user |
|
|
192
|
+
| | | - Applies rules | | context |
|
|
193
|
+
| | | server-side | | - Caches |
|
|
194
|
+
| | | - Returns only | | results |
|
|
195
|
+
| | | flag values | | |
|
|
196
|
+
+--------------+ +------------------+ +--------------+
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The client SDK sends user context to a service (often at the CDN edge), which applies rules server-side and returns only the computed flag values — never the rules themselves. This prevents exposing targeting logic, segment definitions, and API keys to the client.
|
|
200
|
+
|
|
201
|
+
**Why not run rules on the client?** Client-side rule processing would require shipping all flag rules, segment definitions, and targeting logic to the browser or mobile app. This exposes sensitive business logic (who is in which experiment, pricing tier rules, internal user segments) and creates a security risk. Additionally, client-side contexts are relatively static (same user for the session), making server-side processing with caching highly efficient.
|
|
202
|
+
|
|
203
|
+
### Targeting Rules
|
|
204
|
+
|
|
205
|
+
Modern flag systems support layered targeting rules applied in priority order:
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
Flag: "new_dashboard"
|
|
209
|
+
+-- Rule 1: If user.email ends with "@company.com" -> ON (internal dogfooding)
|
|
210
|
+
+-- Rule 2: If user.segment = "beta_testers" -> ON (beta program)
|
|
211
|
+
+-- Rule 3: If user.plan = "enterprise" -> ON (plan gating)
|
|
212
|
+
+-- Rule 4: If user.country in ["US", "CA"] -> percentage(25%) (geo rollout)
|
|
213
|
+
+-- Default: OFF
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Rules are applied top-to-bottom. The first matching rule wins. This allows sophisticated rollout strategies: internal employees see the feature immediately, beta testers get it next, enterprise customers get priority access, and a percentage of US/Canadian users see it for geographic validation — all controlled by a single flag.
|
|
217
|
+
|
|
218
|
+
**Percentage-based targeting** uses deterministic hashing (typically MurmurHash3 of `flagKey + userId`) to assign users to buckets. This ensures:
|
|
219
|
+
- The same user always gets the same flag value (consistency)
|
|
220
|
+
- Different flags assign users to different buckets (independence)
|
|
221
|
+
- Increasing the percentage from 10% to 25% adds users but never removes existing ones (monotonic rollout)
|
|
222
|
+
|
|
223
|
+
### Flag Lifecycle
|
|
224
|
+
|
|
225
|
+
Every flag should follow a documented lifecycle with clear state transitions:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
+----------+ +----------+ +--------------+ +----------+ +---------+
|
|
229
|
+
| CREATED |---->| TESTING |---->| ROLLING OUT |---->| GA |---->| REMOVED |
|
|
230
|
+
| | | | | | | | | |
|
|
231
|
+
| Flag | | Internal | | 1% -> 10% ->| | 100% ON | | Code + |
|
|
232
|
+
| defined, | | users | | 50% -> 100% | | for all | | flag |
|
|
233
|
+
| code | | only | | | | users | | deleted |
|
|
234
|
+
| merged | | | | Monitoring | | | | |
|
|
235
|
+
| (OFF) | | | | at each step | | REMOVE | | |
|
|
236
|
+
| | | | | | | THE FLAG | | |
|
|
237
|
+
+----------+ +----------+ +--------------+ +----------+ +---------+
|
|
238
|
+
|
|
|
239
|
+
v
|
|
240
|
+
Expiration timer
|
|
241
|
+
starts (14 days)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**The critical transition is GA to REMOVED.** Once a flag reaches 100% and the feature is confirmed stable, a timer starts. If the flag is not removed within the grace period (typically 7-30 days), it should trigger an alert, a Jira ticket, or a linting error. Automated flag cleanup tools (like Piranha by Uber) can even submit pull requests to remove stale flags.
|
|
245
|
+
|
|
246
|
+
### Progressive Rollout Strategies
|
|
247
|
+
|
|
248
|
+
**Canary rollout (percentage-based):**
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
Day 1: 1% of users -> monitor error rates, latency p99, business metrics
|
|
252
|
+
Day 3: 5% of users -> watch for edge cases at slightly larger scale
|
|
253
|
+
Day 5: 25% of users -> statistical significance for A/B comparison
|
|
254
|
+
Day 8: 50% of users -> performance under meaningful load
|
|
255
|
+
Day 10: 100% -> GA, start flag removal timer
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Ring-based rollout (audience-based):**
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
Ring 0: Internal employees (dogfooding) -> 1-2 days
|
|
262
|
+
Ring 1: Beta program users (opted-in) -> 3-5 days
|
|
263
|
+
Ring 2: Low-risk geography (e.g., New Zealand) -> 3-5 days
|
|
264
|
+
Ring 3: Full production -> GA
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Ring-based and percentage-based rollouts are complementary. A common pattern is to use rings for early validation (employees, beta users) and then switch to percentage-based rollout for the broader audience.
|
|
268
|
+
|
|
269
|
+
**Monitoring triggers for rollback:**
|
|
270
|
+
|
|
271
|
+
At each rollout stage, automated monitoring should watch for:
|
|
272
|
+
- Error rate increase > 1% over baseline
|
|
273
|
+
- Latency p99 increase > 20% over baseline
|
|
274
|
+
- Business metric degradation (conversion rate, revenue per session)
|
|
275
|
+
- Client-side crash rate increase
|
|
276
|
+
- Support ticket volume spike
|
|
277
|
+
|
|
278
|
+
If any metric crosses its threshold, the flag should automatically roll back to the previous percentage (or to OFF). This is the "automated rollback" capability that makes progressive delivery safe.
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Trade-Offs Matrix
|
|
283
|
+
|
|
284
|
+
| Dimension | Without Feature Flags | With Feature Flags | Notes |
|
|
285
|
+
|---|---|---|---|
|
|
286
|
+
| **Deployment risk** | All-or-nothing releases; rollback requires redeployment | Instant feature disable via flag toggle; no redeployment needed | The primary value proposition — decoupling deploy from release |
|
|
287
|
+
| **Rollout speed** | Gated by release cycles (weekly, bi-weekly) | Continuous — features activate independently of deploys | Enables true continuous delivery |
|
|
288
|
+
| **Code complexity** | Linear code paths | Branched code paths per flag; N flags = 2^N possible states | The primary cost — combinatorial complexity grows exponentially |
|
|
289
|
+
| **Testing burden** | Test one code path | Must test both flag states; combinations multiply effort | Pairwise testing and modular isolation are mitigations, not solutions |
|
|
290
|
+
| **Technical debt** | Standard code debt | Flag-specific debt: stale flags, dead code, orphaned branches | Requires active lifecycle management that most teams neglect |
|
|
291
|
+
| **Operational visibility** | Behavior determined by deployed code version | Behavior determined by code version AND flag states | Must track flag states alongside deployments for incident response |
|
|
292
|
+
| **Time to rollback** | Minutes (redeploy previous version) | Seconds (toggle flag off) | Dramatic improvement for critical incidents |
|
|
293
|
+
| **Experimentation** | Requires separate A/B testing infrastructure | Built-in with multivariate flags | Significant product development advantage |
|
|
294
|
+
| **Infrastructure cost** | None additional | Flag service, SDK overhead, streaming connections | Ranges from free (env vars) to $100K+/year (LaunchDarkly enterprise) |
|
|
295
|
+
| **Cognitive load** | Developers reason about one code path | Developers must reason about all active flag states | Increases linearly with active flag count |
|
|
296
|
+
| **Audit and compliance** | Change tracked via deploy logs | Flag changes tracked via audit trail, separate from deploys | Can be an advantage (fine-grained tracking) or a burden (two audit streams) |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Evolution Path
|
|
301
|
+
|
|
302
|
+
Feature flag systems typically progress through four stages, each adding capability and complexity:
|
|
303
|
+
|
|
304
|
+
### Stage 1: Environment Variables and Config Files
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
# .env
|
|
308
|
+
ENABLE_NEW_SEARCH=false
|
|
309
|
+
|
|
310
|
+
# application code
|
|
311
|
+
if os.environ.get("ENABLE_NEW_SEARCH") == "true":
|
|
312
|
+
return new_search(query)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Characteristics:** No external service, no targeting rules, no gradual rollout. A flag is either on or off for the entire environment. Change requires redeployment or container restart.
|
|
316
|
+
|
|
317
|
+
**Appropriate for:** Small teams (fewer than 10 engineers), low deployment frequency, features that are either 100% on or 100% off. Startups before product-market fit should not invest in anything more sophisticated.
|
|
318
|
+
|
|
319
|
+
### Stage 2: Database-Backed Flags with Admin UI
|
|
320
|
+
|
|
321
|
+
```python
|
|
322
|
+
# Flag stored in PostgreSQL, editable via admin panel
|
|
323
|
+
flag = FlagModel.objects.get(key="new_search")
|
|
324
|
+
if flag.is_enabled:
|
|
325
|
+
return new_search(query)
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Characteristics:** Flags can be toggled without redeployment. Simple admin UI for non-engineers to toggle flags. No user targeting or percentage rollouts. Flag changes propagate on next request (no streaming).
|
|
329
|
+
|
|
330
|
+
**Appropriate for:** Teams of 10-30, products with moderate deployment frequency, need for non-engineer flag control (PM wants to launch a feature on a specific date).
|
|
331
|
+
|
|
332
|
+
### Stage 3: Purpose-Built Flag Service with Targeting
|
|
333
|
+
|
|
334
|
+
```python
|
|
335
|
+
# SDK-based flag check with user targeting
|
|
336
|
+
client = FlagClient(sdk_key="...")
|
|
337
|
+
if client.variation("new_search", user={"key": user.id, "plan": "enterprise"}):
|
|
338
|
+
return new_search(query)
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Characteristics:** Full targeting rules (user, segment, percentage), audit trails, real-time propagation via streaming, server-side and client-side SDKs. This is where most organizations should aim.
|
|
342
|
+
|
|
343
|
+
**Appropriate for:** Teams of 30+, products with continuous deployment, need for gradual rollouts and A/B testing, multi-tenant SaaS with plan-based gating.
|
|
344
|
+
|
|
345
|
+
**Technology options:** LaunchDarkly (hosted), Unleash (self-hosted/hosted), Flagsmith (self-hosted/hosted), GrowthBook (open source), PostHog (bundled with analytics), Statsig (bundled with experimentation).
|
|
346
|
+
|
|
347
|
+
### Stage 4: Experimentation Platform with Statistical Rigor
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
# Full experimentation with variants, metrics, and statistical analysis
|
|
351
|
+
variant = experiment_client.get_assignment(
|
|
352
|
+
experiment="checkout_redesign",
|
|
353
|
+
user=user,
|
|
354
|
+
metrics=["conversion_rate", "revenue_per_session", "cart_abandonment"]
|
|
355
|
+
)
|
|
356
|
+
if variant == "control":
|
|
357
|
+
return render_old_checkout()
|
|
358
|
+
elif variant == "variant_a":
|
|
359
|
+
return render_new_checkout_a()
|
|
360
|
+
elif variant == "variant_b":
|
|
361
|
+
return render_new_checkout_b()
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Characteristics:** Multivariate assignment, statistical significance tracking, mutual exclusion between experiments, metric attribution, automatic experiment termination when significance is reached. This is a dedicated experimentation platform that happens to use feature flags as its delivery mechanism.
|
|
365
|
+
|
|
366
|
+
**Appropriate for:** Large product organizations (100+ engineers), data-driven product teams, high-traffic products where 1% improvement in conversion is worth millions.
|
|
367
|
+
|
|
368
|
+
**Technology options:** Statsig, Eppo, Optimizely, GrowthBook, LaunchDarkly (Experimentation add-on).
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Failure Modes
|
|
373
|
+
|
|
374
|
+
### Flag debt — the silent killer
|
|
375
|
+
|
|
376
|
+
**Symptom:** 300+ flags in the codebase, fewer than 50 actively toggled. Engineers are afraid to remove flags because they do not know if the code path is still needed. New hires cannot understand the codebase because every function has 3-5 flag-gated branches.
|
|
377
|
+
|
|
378
|
+
**Root cause:** No flag lifecycle process. Flags are created eagerly and removed never.
|
|
379
|
+
|
|
380
|
+
**Impact:** Increased cognitive load, slower onboarding, increased testing surface area, higher risk of Knight Capital-style incidents from stale flag interactions.
|
|
381
|
+
|
|
382
|
+
**Prevention:**
|
|
383
|
+
- Every flag has an owner and an expiration date at creation time
|
|
384
|
+
- CI/CD pipeline fails if a flag exceeds its expiration date without an explicit extension
|
|
385
|
+
- Automated cleanup tools (Uber's Piranha, DevCycle's code references) scan for flags that have been 100% on for more than 14 days and create removal PRs
|
|
386
|
+
- Flag count per service is a tracked metric — alert if it exceeds a threshold (e.g., 20 active flags per service)
|
|
387
|
+
|
|
388
|
+
### Flag interaction — unexpected combinations
|
|
389
|
+
|
|
390
|
+
**Symptom:** Feature A works correctly. Feature B works correctly. Features A and B enabled simultaneously produce a broken user experience or data corruption.
|
|
391
|
+
|
|
392
|
+
**Root cause:** Flags are treated as independent, but the code paths they control share state, depend on the same data, or produce conflicting UI elements.
|
|
393
|
+
|
|
394
|
+
**Example:** Flag A enables a new checkout flow. Flag B enables a new payment processor. Each was tested independently. When both are on, the new checkout flow sends data in a format the new payment processor does not expect, and orders silently fail to process.
|
|
395
|
+
|
|
396
|
+
**Prevention:**
|
|
397
|
+
- Document flag dependencies explicitly (this flag requires/conflicts with these other flags)
|
|
398
|
+
- Test the "current production state + one flag flip" matrix rather than all combinations
|
|
399
|
+
- Isolate flagged code paths using modular architecture — if two features cannot interact, their flags cannot interact
|
|
400
|
+
- For critical flags, use mutually exclusive groups in the flag service
|
|
401
|
+
|
|
402
|
+
### Inconsistent flag state across services
|
|
403
|
+
|
|
404
|
+
**Symptom:** The frontend shows the new feature (flag ON), but the backend API returns data in the old format (flag OFF). Users see a broken experience.
|
|
405
|
+
|
|
406
|
+
**Root cause:** In microservices architectures, each service checks flags independently. If flag propagation is not instant, or if services cache flag values with different TTLs, a flag change creates a window of inconsistency.
|
|
407
|
+
|
|
408
|
+
**Prevention:**
|
|
409
|
+
- Use a single flag service with streaming updates to all SDKs (not polling)
|
|
410
|
+
- For flags that span services, use a "flag context" passed in request headers so all services in a request chain see the same flag state
|
|
411
|
+
- Design flagged features to be tolerant of mixed states (new frontend gracefully handles old API response format)
|
|
412
|
+
|
|
413
|
+
### Flag lookup performance degradation
|
|
414
|
+
|
|
415
|
+
**Symptom:** p99 latency increases 20ms. Investigation reveals that flag checks in a hot code path are making network calls or processing complex targeting rules per request.
|
|
416
|
+
|
|
417
|
+
**Root cause:** Client-side SDK configured to phone home for every check, or server-side SDK running complex segment rules (involving database lookups) per request.
|
|
418
|
+
|
|
419
|
+
**Prevention:**
|
|
420
|
+
- Server-side SDKs must cache flag configuration locally and run without network calls
|
|
421
|
+
- Pre-compute segment membership asynchronously, not during flag checks
|
|
422
|
+
- For hot paths (more than 10K checks per second), use a local boolean cache with a short TTL rather than full rule processing per call
|
|
423
|
+
- Monitor flag lookup latency as a system metric
|
|
424
|
+
|
|
425
|
+
### Configuration drift between environments
|
|
426
|
+
|
|
427
|
+
**Symptom:** A feature works in staging but fails in production. Investigation reveals that flag targeting rules differ between environments, or a flag exists in staging but not in production.
|
|
428
|
+
|
|
429
|
+
**Root cause:** Flag configuration is not managed as code. Teams modify flags via the admin UI in each environment independently.
|
|
430
|
+
|
|
431
|
+
**Prevention:**
|
|
432
|
+
- Treat flag configuration as code — store targeting rules in version-controlled YAML/JSON, apply via CI/CD
|
|
433
|
+
- Use environment-aware flag definitions: a single flag definition with per-environment overrides
|
|
434
|
+
- Audit differences between environment flag states regularly
|
|
435
|
+
|
|
436
|
+
### The "permanent beta" trap
|
|
437
|
+
|
|
438
|
+
**Symptom:** A feature has been at 50% rollout for six months. No one has decided whether to go to 100% or roll back. The flag has become a permanent partition in the user experience.
|
|
439
|
+
|
|
440
|
+
**Root cause:** No decision criteria were defined before the rollout began. No one owns the go/no-go decision. The flag drifts into an indefinite state.
|
|
441
|
+
|
|
442
|
+
**Prevention:**
|
|
443
|
+
- Before any rollout, define success criteria (metrics, thresholds, timeline)
|
|
444
|
+
- Assign a decision owner who will call GA or rollback by a specific date
|
|
445
|
+
- Flag service should alert on flags that have been in a partial rollout state for more than 30 days
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Technology Landscape
|
|
450
|
+
|
|
451
|
+
### Managed Services (SaaS)
|
|
452
|
+
|
|
453
|
+
| Tool | Strengths | Weaknesses | Pricing Model | Best For |
|
|
454
|
+
|---|---|---|---|---|
|
|
455
|
+
| **LaunchDarkly** | Most mature, best targeting, excellent SDKs (25+ languages), strong enterprise features, real-time streaming | Most expensive at scale, no self-hosted option, no source code visibility | Per-seat + MAU tiers; enterprise $$$$ | Large enterprises with budget, complex targeting needs |
|
|
456
|
+
| **Statsig** | Integrated experimentation + flags, statistical engine, warehouse-native analytics | Younger platform, less mature enterprise features | Free tier generous; usage-based | Data-driven product teams wanting experimentation built-in |
|
|
457
|
+
| **PostHog** | Bundled with product analytics, session recording, surveys; open-source core | Flag system is secondary to analytics; less sophisticated targeting | Free self-hosted; cloud usage-based | Teams wanting an all-in-one product analytics suite |
|
|
458
|
+
| **Optimizely** | Strong experimentation heritage, visual editor for non-engineers | Expensive, enterprise sales process, slower innovation | Enterprise pricing | Marketing-driven experimentation teams |
|
|
459
|
+
|
|
460
|
+
### Self-Hosted / Open-Source
|
|
461
|
+
|
|
462
|
+
| Tool | Strengths | Weaknesses | License | Best For |
|
|
463
|
+
|---|---|---|---|---|
|
|
464
|
+
| **Unleash** | Self-hosted or cloud, strong RBAC, good API, 11 well-documented principles for flag systems | Enterprise features (SAML, audit log, change requests) behind paid tier | Apache 2.0 (core) | Teams needing self-hosted with strong access control |
|
|
465
|
+
| **Flagsmith** | Flexible deployment (cloud/self-hosted/on-prem), multi-platform SDKs, edge proxy | Smaller community than Unleash, fewer integrations | BSD 3-Clause | Organizations with strict data governance requirements |
|
|
466
|
+
| **GrowthBook** | Open-source with built-in experimentation, Bayesian statistics engine, warehouse-native | Smaller team/community, less polished UI | MIT | Data teams wanting open-source experimentation |
|
|
467
|
+
| **OpenFeature** | CNCF incubating project, vendor-agnostic API specification, prevents vendor lock-in | Not a flag service itself — a standard that wraps other providers | Apache 2.0 | Teams wanting to avoid vendor lock-in at the code level |
|
|
468
|
+
|
|
469
|
+
### Build vs. Buy Decision
|
|
470
|
+
|
|
471
|
+
**Build your own when:**
|
|
472
|
+
- You need fewer than 20 flags with no targeting rules (database-backed flags with admin UI, approximately 2 weeks to build)
|
|
473
|
+
- You have extreme compliance requirements that prohibit any external service
|
|
474
|
+
- You are using OpenFeature as the API layer and can swap providers later
|
|
475
|
+
|
|
476
|
+
**Buy when:**
|
|
477
|
+
- You need targeting rules, percentage rollouts, or experimentation
|
|
478
|
+
- You have more than 50 active flags
|
|
479
|
+
- You need audit trails for compliance (SOC2, HIPAA)
|
|
480
|
+
- The cost of the service ($5K-50K/year) is less than the engineering time to build and maintain a custom solution (almost always true)
|
|
481
|
+
|
|
482
|
+
**Use OpenFeature when:**
|
|
483
|
+
- You want to avoid vendor lock-in at the code level
|
|
484
|
+
- You might switch providers in the future
|
|
485
|
+
- You want a consistent API across server-side and client-side SDKs
|
|
486
|
+
- You are assessing multiple providers and want to defer the decision
|
|
487
|
+
|
|
488
|
+
OpenFeature is a CNCF incubating project supported by LaunchDarkly, Split, Flagsmith, and end users including eBay, Google, SAP, and Spotify. It provides a vendor-agnostic API: you code against the OpenFeature SDK, and swap the backend provider without changing application code.
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## Decision Tree
|
|
493
|
+
|
|
494
|
+
```
|
|
495
|
+
START: Do you need to control feature visibility independent of deployment?
|
|
496
|
+
|
|
|
497
|
+
+-- NO -> Do you need kill switches for operational safety?
|
|
498
|
+
| +-- NO -> You don't need feature flags. Ship features via normal deploys.
|
|
499
|
+
| +-- YES -> Use simple env var / config flags (Stage 1). No targeting needed.
|
|
500
|
+
|
|
|
501
|
+
+-- YES -> How many engineers on the team?
|
|
502
|
+
|
|
|
503
|
+
+-- < 10 -> Use database-backed flags with admin UI (Stage 2).
|
|
504
|
+
| Keep flag count under 15. Track manually.
|
|
505
|
+
|
|
|
506
|
+
+-- 10+ -> Do you need user targeting or percentage rollouts?
|
|
507
|
+
|
|
|
508
|
+
+-- NO -> Database-backed flags (Stage 2) may still suffice.
|
|
509
|
+
| Consider upgrading if flag count exceeds 30.
|
|
510
|
+
|
|
|
511
|
+
+-- YES -> Do you need A/B testing with statistical rigor?
|
|
512
|
+
|
|
|
513
|
+
+-- NO -> Purpose-built flag service (Stage 3).
|
|
514
|
+
| +-- Budget for SaaS? -> LaunchDarkly, Statsig
|
|
515
|
+
| +-- Need self-hosted? -> Unleash, Flagsmith
|
|
516
|
+
| +-- Want vendor-agnostic? -> Use OpenFeature API
|
|
517
|
+
|
|
|
518
|
+
+-- YES -> Experimentation platform (Stage 4).
|
|
519
|
+
+-- Want integrated analytics? -> Statsig, PostHog
|
|
520
|
+
+-- Want open-source? -> GrowthBook
|
|
521
|
+
+-- Want enterprise? -> Optimizely, LaunchDarkly
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
**The most common mistake** is jumping to Stage 3 or 4 when Stage 1 or 2 is sufficient. A startup with 5 engineers does not need LaunchDarkly. An `ENABLE_NEW_SEARCH=true` environment variable and a 10-line middleware function will serve them for years.
|
|
525
|
+
|
|
526
|
+
**The second most common mistake** is staying at Stage 1 too long. When your team grows past 30 engineers and you have 40 environment variables controlling feature visibility with no targeting, no audit trail, and no lifecycle management, you are accumulating dangerous debt.
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Implementation Sketch
|
|
531
|
+
|
|
532
|
+
### Minimal Flag Service (Stage 2 — Database-Backed)
|
|
533
|
+
|
|
534
|
+
```python
|
|
535
|
+
# models.py -- Flag storage
|
|
536
|
+
class FeatureFlag(Model):
|
|
537
|
+
key = CharField(max_length=100, unique=True, db_index=True)
|
|
538
|
+
enabled = BooleanField(default=False)
|
|
539
|
+
description = TextField(blank=True)
|
|
540
|
+
owner = CharField(max_length=100) # who owns this flag
|
|
541
|
+
created_at = DateTimeField(auto_now_add=True)
|
|
542
|
+
expires_at = DateTimeField() # MANDATORY expiration
|
|
543
|
+
category = CharField(choices=["release", "experiment", "ops", "permission"])
|
|
544
|
+
|
|
545
|
+
def is_expired(self):
|
|
546
|
+
return timezone.now() > self.expires_at and self.category == "release"
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
# service.py -- Flag checking with in-memory cache
|
|
550
|
+
class FlagService:
|
|
551
|
+
def __init__(self):
|
|
552
|
+
self._cache = {}
|
|
553
|
+
self._cache_ttl = 30 # seconds
|
|
554
|
+
self._last_refresh = 0
|
|
555
|
+
|
|
556
|
+
def is_enabled(self, key: str) -> bool:
|
|
557
|
+
self._refresh_if_stale()
|
|
558
|
+
flag = self._cache.get(key)
|
|
559
|
+
if flag is None:
|
|
560
|
+
return False # unknown flags default to OFF
|
|
561
|
+
return flag["enabled"]
|
|
562
|
+
|
|
563
|
+
def _refresh_if_stale(self):
|
|
564
|
+
now = time.time()
|
|
565
|
+
if now - self._last_refresh > self._cache_ttl:
|
|
566
|
+
flags = FeatureFlag.objects.values("key", "enabled")
|
|
567
|
+
self._cache = {f["key"]: f for f in flags}
|
|
568
|
+
self._last_refresh = now
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
# middleware.py -- Inject flags into request context
|
|
572
|
+
class FeatureFlagMiddleware:
|
|
573
|
+
def __init__(self, get_response):
|
|
574
|
+
self.get_response = get_response
|
|
575
|
+
self.flag_service = FlagService()
|
|
576
|
+
|
|
577
|
+
def __call__(self, request):
|
|
578
|
+
request.flags = self.flag_service
|
|
579
|
+
return self.get_response(request)
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
# views.py -- Usage
|
|
583
|
+
def dashboard_view(request):
|
|
584
|
+
if request.flags.is_enabled("new_dashboard"):
|
|
585
|
+
return render(request, "dashboard_v2.html")
|
|
586
|
+
return render(request, "dashboard.html")
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### Flag Service with Targeting Rules (Stage 3)
|
|
590
|
+
|
|
591
|
+
```python
|
|
592
|
+
# targeting.py -- Rule application engine
|
|
593
|
+
class TargetingEngine:
|
|
594
|
+
def check(self, flag_config: dict, user_context: dict) -> bool:
|
|
595
|
+
# Apply rules in priority order
|
|
596
|
+
for rule in flag_config.get("rules", []):
|
|
597
|
+
if self._matches_rule(rule, user_context):
|
|
598
|
+
return self._resolve_variation(rule, user_context)
|
|
599
|
+
|
|
600
|
+
# Fall through to default
|
|
601
|
+
return flag_config.get("default", False)
|
|
602
|
+
|
|
603
|
+
def _matches_rule(self, rule: dict, user: dict) -> bool:
|
|
604
|
+
for condition in rule["conditions"]:
|
|
605
|
+
attr = user.get(condition["attribute"])
|
|
606
|
+
op = condition["operator"]
|
|
607
|
+
|
|
608
|
+
if op == "in" and attr not in condition["values"]:
|
|
609
|
+
return False
|
|
610
|
+
elif op == "equals" and attr != condition["value"]:
|
|
611
|
+
return False
|
|
612
|
+
elif op == "ends_with" and not str(attr).endswith(condition["value"]):
|
|
613
|
+
return False
|
|
614
|
+
elif op == "gte" and attr < condition["value"]:
|
|
615
|
+
return False
|
|
616
|
+
return True
|
|
617
|
+
|
|
618
|
+
def _resolve_variation(self, rule: dict, user: dict) -> bool:
|
|
619
|
+
if "percentage" in rule:
|
|
620
|
+
# Deterministic hashing for consistent assignment
|
|
621
|
+
hash_key = f"{rule['flag_key']}:{user['key']}"
|
|
622
|
+
bucket = mmh3.hash(hash_key, signed=False) % 100
|
|
623
|
+
return bucket < rule["percentage"]
|
|
624
|
+
return rule.get("value", True)
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
# Flag configuration (stored as JSON in DB or config file)
|
|
628
|
+
flag_config = {
|
|
629
|
+
"key": "new_checkout",
|
|
630
|
+
"rules": [
|
|
631
|
+
{
|
|
632
|
+
"flag_key": "new_checkout",
|
|
633
|
+
"conditions": [
|
|
634
|
+
{"attribute": "email", "operator": "ends_with", "value": "@company.com"}
|
|
635
|
+
],
|
|
636
|
+
"value": True # All internal users see it
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
"flag_key": "new_checkout",
|
|
640
|
+
"conditions": [
|
|
641
|
+
{"attribute": "plan", "operator": "in", "values": ["enterprise"]}
|
|
642
|
+
],
|
|
643
|
+
"value": True # All enterprise users see it
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
"flag_key": "new_checkout",
|
|
647
|
+
"conditions": [
|
|
648
|
+
{"attribute": "country", "operator": "in", "values": ["US", "CA"]}
|
|
649
|
+
],
|
|
650
|
+
"percentage": 25 # 25% of US/CA users
|
|
651
|
+
}
|
|
652
|
+
],
|
|
653
|
+
"default": False
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### Flag Cleanup Automation
|
|
658
|
+
|
|
659
|
+
```python
|
|
660
|
+
# cleanup.py -- Automated stale flag detection (run as scheduled job)
|
|
661
|
+
class FlagCleanupJob:
|
|
662
|
+
"""
|
|
663
|
+
Runs daily. Identifies flags that should be removed and creates
|
|
664
|
+
tickets/PRs for cleanup.
|
|
665
|
+
"""
|
|
666
|
+
GRACE_PERIOD_DAYS = 14
|
|
667
|
+
|
|
668
|
+
def run(self):
|
|
669
|
+
stale_flags = self._find_stale_flags()
|
|
670
|
+
for flag in stale_flags:
|
|
671
|
+
days_overdue = (timezone.now() - flag.expires_at).days
|
|
672
|
+
if days_overdue > self.GRACE_PERIOD_DAYS * 2:
|
|
673
|
+
self._create_critical_alert(flag) # Slack alert to flag owner
|
|
674
|
+
elif days_overdue > self.GRACE_PERIOD_DAYS:
|
|
675
|
+
self._create_cleanup_ticket(flag) # Jira ticket
|
|
676
|
+
else:
|
|
677
|
+
self._send_reminder(flag) # Email to flag owner
|
|
678
|
+
|
|
679
|
+
def _find_stale_flags(self):
|
|
680
|
+
return FeatureFlag.objects.filter(
|
|
681
|
+
category="release",
|
|
682
|
+
enabled=True,
|
|
683
|
+
expires_at__lt=timezone.now()
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
# ci_check.py -- Fail CI if code references expired flags
|
|
688
|
+
def check_flag_references(codebase_path: str, flag_service: FlagService):
|
|
689
|
+
"""
|
|
690
|
+
Scan source code for flag references. If any reference an expired
|
|
691
|
+
flag, fail the build with a clear error message.
|
|
692
|
+
"""
|
|
693
|
+
expired_flags = flag_service.get_expired_flags()
|
|
694
|
+
violations = []
|
|
695
|
+
|
|
696
|
+
for filepath in glob(f"{codebase_path}/**/*.py", recursive=True):
|
|
697
|
+
content = open(filepath).read()
|
|
698
|
+
for flag in expired_flags:
|
|
699
|
+
if flag.key in content:
|
|
700
|
+
violations.append(
|
|
701
|
+
f"{filepath}: references expired flag '{flag.key}' "
|
|
702
|
+
f"(expired {flag.expires_at.date()}, owner: {flag.owner})"
|
|
703
|
+
)
|
|
704
|
+
|
|
705
|
+
if violations:
|
|
706
|
+
print("EXPIRED FLAG REFERENCES FOUND:")
|
|
707
|
+
for v in violations:
|
|
708
|
+
print(f" - {v}")
|
|
709
|
+
sys.exit(1)
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
### OpenFeature Integration (Vendor-Agnostic)
|
|
713
|
+
|
|
714
|
+
```python
|
|
715
|
+
# Using OpenFeature API -- swap providers without changing application code
|
|
716
|
+
|
|
717
|
+
from openfeature import api
|
|
718
|
+
from openfeature.contrib.provider.flagd import FlagdProvider
|
|
719
|
+
# Alternatively: from openfeature_launchdarkly import LaunchDarklyProvider
|
|
720
|
+
|
|
721
|
+
# Configure provider once at startup
|
|
722
|
+
api.set_provider(FlagdProvider()) # or LaunchDarklyProvider(sdk_key="...")
|
|
723
|
+
|
|
724
|
+
# Application code uses the OpenFeature API -- never the provider directly
|
|
725
|
+
client = api.get_client()
|
|
726
|
+
|
|
727
|
+
# Boolean flag check
|
|
728
|
+
new_checkout = client.get_boolean_value(
|
|
729
|
+
flag_key="new_checkout",
|
|
730
|
+
default_value=False,
|
|
731
|
+
evaluation_context=EvaluationContext(
|
|
732
|
+
targeting_key=user.id,
|
|
733
|
+
attributes={"plan": user.plan, "country": user.country}
|
|
734
|
+
)
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
# String flag check (multivariate)
|
|
738
|
+
checkout_variant = client.get_string_value(
|
|
739
|
+
flag_key="checkout_variant",
|
|
740
|
+
default_value="control",
|
|
741
|
+
evaluation_context=EvaluationContext(targeting_key=user.id)
|
|
742
|
+
)
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## Cross-References
|
|
748
|
+
|
|
749
|
+
- **[Multi-Tenancy / Microservices](../patterns/microservices.md)** — Permission flags are the feature-gating layer in multi-tenant SaaS. Plan-based feature access (free/pro/enterprise) is often implemented via feature flags tied to tenant attributes. Consider whether permission flags belong in the flag system or in a dedicated authorization layer. In microservices architectures, feature flags require careful attention to flag state consistency across services. A flag change must propagate to all services atomically, or features that span services will experience split-brain states. Pass flag context in request headers to ensure consistent results across service boundaries.
|
|
750
|
+
|
|
751
|
+
- **[Plugin Architecture](../patterns/plugin-architecture.md)** — Plugin systems and feature flags solve overlapping problems (enabling/disabling functionality at runtime) but at different granularities. Plugins are coarse-grained (entire modules), feature flags are fine-grained (individual code paths). In mature systems, plugin activation may itself be controlled by feature flags.
|
|
752
|
+
|
|
753
|
+
- **[Monolith](../patterns/monolith.md)** — Monolithic architectures benefit enormously from feature flags because flag checks are in-process (no network consistency issues), deployment is atomic (no split-brain across services), and the blast radius of a flag misconfiguration is limited to a single process. Feature flags in monoliths are simpler, faster, and safer than in distributed systems.
|
|
754
|
+
|
|
755
|
+
- **[Event-Driven Architecture](../patterns/event-driven.md)** — Feature flags in event-driven systems require special care. If a flag changes while events are in-flight, consumers may process events under different flag states than the producer intended. Consider embedding flag state in event metadata for consistent processing.
|
|
756
|
+
|
|
757
|
+
- **[CQRS / Event Sourcing](../patterns/cqrs-event-sourcing.md)** — Flag state changes can be modeled as events in an event-sourced system, providing a complete audit trail of flag lifecycle. This is particularly valuable for compliance-heavy domains where regulators require proof of when features were enabled for which users.
|