docs(ops): feature flags are not worth a manager here (#318) #329

Merged
bermudalamb merged 1 commits from spike/318-feature-flags into main 2026-09-09 13:39:22 -05:00
Owner

Spike done. Recommendation: do not adopt a feature flag manager. docs/ops/feature-flags.md.

The finding

This project already has two flag mechanisms and uses both idiomatically.

Environment variables do per-environment gating — DEMO_MODE, REMBG_URL, BREVO_TRACKER_KEY, ANTHROPIC_API_KEY, USPS, SMTP — with a consistent documented convention: unset means the feature does not exist and the app is working, not broken. QA runs with several deliberately empty, which is precisely how it cannot reach PayPal, cannot email anyone, and cannot report browsing into the live Brevo account. That is a feature flag system; it just is not called one.

admin_settings does runtime tuning by whoever runs the shop. Its own header already states the principle a flag manager would sell you: a setting is changed by the person running the shop, not the person deploying it. drafting_model and intake_notify_email live there for exactly that reason.

What is actually missing

admin_settings supports hours, count, text and choice. There is no boolean.

So the single thing a manager would add that this project lacks — an admin-flippable on/off for a code path, without a rebuild — is a missing value type in a store that already does everything else. A definition entry, a parse branch, and a control.

That is the whole gap, and it is not a reason to run another service on a NAS already hosting Gitea, the CI runner, QA and production.

No tool was compared until that was established, because a spike that starts by comparing platforms will always find one.

Nothing to flag right now

The issue said a spike that cannot name a concrete change should conclude "not yet". It cannot.

  • Passkeys (#37–#42) is naturally incremental — nothing is user-visible until #41 puts it on the login form, so the ordering does the gating.
  • #313's trust proxy change cannot be flagged. It is only correct once Cloudflare is actually in front, so a runtime toggle would let it be wrong on purpose. Worse than not having one.

The strongest hypothetical is a kill switch for passkey login, since #41 records it as the one feature that cannot be fully proven in QA — credentials bind to the RP ID, so production is the first place it runs for real. Still not enough while passkeys are not being built and production is not live.

For whenever the answer changes

The comparison is in the doc, with the constraint that matters most stated plainly: fail-safe behaviour beats features. A flag service that takes the shop down when unreachable is worse than no flags — and admin_settings reads from the database the app already cannot run without, so it has no failure mode of its own. That is a real advantage over every hosted or sidecar option.

Flipt is the only candidate that obviously fits the machine. Unleash carries a caveat worth keeping: its OSS Edge sunsets 2026-12-31, which makes a free tool acquire a paid dependency inside a year.

The four conditions that would reopen this are written down rather than left implied.

Verification

Every claim about the repository was read from the code today: 10 settings in admin_settings, no boolean type, env-var gating across app.ts, envValidation.ts, anthropicClient.ts and draftingWorker.ts. Tool capabilities and pricing were checked 2026-09-08 and are worth re-confirming at decision time.

Docs-only — no code, no deploy, so the QA-before-production step does not apply here.

Closes #318

🤖 Generated with Claude Code

Spike done. **Recommendation: do not adopt a feature flag manager.** `docs/ops/feature-flags.md`. ## The finding This project **already has two flag mechanisms** and uses both idiomatically. **Environment variables** do per-environment gating — `DEMO_MODE`, `REMBG_URL`, `BREVO_TRACKER_KEY`, `ANTHROPIC_API_KEY`, USPS, SMTP — with a consistent documented convention: unset means the feature does not exist and the app is *working*, not broken. QA runs with several deliberately empty, which is precisely how it cannot reach PayPal, cannot email anyone, and cannot report browsing into the live Brevo account. That is a feature flag system; it just is not called one. **`admin_settings`** does runtime tuning by whoever runs the shop. Its own header already states the principle a flag manager would sell you: a setting is changed by the person running the shop, not the person deploying it. `drafting_model` and `intake_notify_email` live there for exactly that reason. ## What is actually missing `admin_settings` supports `hours`, `count`, `text` and `choice`. **There is no boolean.** So the single thing a manager would add that this project lacks — an admin-flippable on/off for a code path, without a rebuild — is a missing value type in a store that already does everything else. A definition entry, a parse branch, and a control. That is the whole gap, and it is not a reason to run another service on a NAS already hosting Gitea, the CI runner, QA and production. **No tool was compared until that was established**, because a spike that starts by comparing platforms will always find one. ## Nothing to flag right now The issue said a spike that cannot name a concrete change should conclude "not yet". It cannot. - **Passkeys (#37–#42)** is naturally incremental — nothing is user-visible until #41 puts it on the login form, so the ordering does the gating. - **#313's `trust proxy` change cannot be flagged.** It is only correct once Cloudflare is actually in front, so a runtime toggle would let it be wrong on purpose. Worse than not having one. The strongest hypothetical is a **kill switch for passkey login**, since #41 records it as the one feature that cannot be fully proven in QA — credentials bind to the RP ID, so production is the first place it runs for real. Still not enough while passkeys are not being built and production is not live. ## For whenever the answer changes The comparison is in the doc, with the constraint that matters most stated plainly: **fail-safe behaviour beats features.** A flag service that takes the shop down when unreachable is worse than no flags — and `admin_settings` reads from the database the app already cannot run without, so it has no failure mode of its own. That is a real advantage over every hosted or sidecar option. Flipt is the only candidate that obviously fits the machine. **Unleash carries a caveat worth keeping: its OSS Edge sunsets 2026-12-31**, which makes a free tool acquire a paid dependency inside a year. The four conditions that would reopen this are written down rather than left implied. ## Verification Every claim about the repository was read from the code today: 10 settings in `admin_settings`, no `boolean` type, env-var gating across `app.ts`, `envValidation.ts`, `anthropicClient.ts` and `draftingWorker.ts`. Tool capabilities and pricing were checked 2026-09-08 and are worth re-confirming at decision time. Docs-only — no code, no deploy, so the QA-before-production step does not apply here. Closes #318 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bermudalamb added 1 commit 2026-09-09 13:37:59 -05:00
docs(ops): feature flags are not worth a manager here (#318)
SonarQube Analysis / sonarqube (pull_request) Failing after 31m7s
Linting / lint (pull_request) Successful in 3m3s
0c297f8465
The spike asked whether this project should adopt feature flag management and whether a free option fits. The answer is that it already has two flag mechanisms, uses both idiomatically, and is not short of a third.

Environment variables do per-environment gating, with a consistent and documented convention: unset means the feature does not exist and the application is working rather than broken. QA runs with several deliberately empty, which is how it cannot reach PayPal, cannot email anyone and cannot report browsing into the live Brevo account. That is a feature flag system; it is simply not called one.

admin_settings does runtime tuning by whoever runs the shop, and its own header already states the principle a flag manager would sell: a setting is changed by the person running the shop rather than the person deploying it. drafting_model and intake_notify_email live there for exactly that reason.

What is missing is one value type. admin_settings supports hours, count, text and choice, and has no boolean — so the single thing a manager would add that this project lacks is an admin-flippable on/off, in a store that already does everything else. That is a definition entry, a parse branch and a control. It is not a reason to run another service on a NAS that already hosts Gitea, the runner, QA and production.

No tool was compared until that was established, because a spike that starts by comparing platforms will always find one. The comparison is included for whenever the answer changes, with the constraint that matters most stated plainly: fail-safe behaviour beats features, and a flag service that takes the shop down when unreachable is worse than no flags. admin_settings reads from the database the application already cannot run without, so it has no failure mode of its own.

The issue said a spike that cannot name a concrete change needing a flag should conclude not yet, and it cannot. Seven of the nine open issues are the Passkeys epic, which is naturally incremental and gates itself by ordering, and #313, whose trust proxy change cannot be flagged at all — it is only correct once Cloudflare is in front, so a runtime toggle would let it be wrong on purpose. The strongest hypothetical is a kill switch for passkey login, because #41 records it as the one feature that cannot be fully proven in QA, and that is still not enough while passkeys are not being built and production is not live.

The conditions that would change the answer are written down rather than left implied, so this does not get reopened from scratch.

Unleash carries a caveat worth keeping: its OSS Edge sunsets on 2026-12-31, which makes a free tool acquire a paid dependency inside a year.

Closes #318

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bermudalamb merged commit 6a2143696a into main 2026-09-09 13:39:22 -05:00
bermudalamb deleted branch spike/318-feature-flags 2026-09-09 13:39:23 -05:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bermudalamb/redefined-designs#329