Feature Tiers
Fichero’s contributor-facing feature tier system has one source of truth: features.yaml. python scripts/gen_feature_tiers.py regenerates three derived artifacts from it: the Swift tier map in fichero/fichero/Models/FeatureTiers.generated.swift, the backend route-tier data in fichero-server/src/fichero_server/api/feature_tiers_generated.py, and the public matrix in docs/reference_manual/features.md.
Tiers
FeatureTier defines four ordered ranks:
| Rank | Tier | Meaning |
|---|---|---|
| 1 | dev |
AI added; rawest tier. |
| 2 | alpha |
Daniel review queue. |
| 3 | beta |
Tester-facing candidate. |
| 4 | release |
Publicly shipped. |
The generated backend route sets implement a maturity floor: a build tier T exposes features and routes whose maturity rank is greater than or equal to T. CUMULATIVE_ROUTE_PREFIXES shows that rule directly:
releaseincludesreleaseroutes only.betaincludesbetaandreleaseroutes.alphaincludesalpha,beta, andreleaseroutes.devincludes every tier.
On the app side, the baked tier key is FicheroFeatureTier and the environment override name is FICHERO_FEATURE_TIER. The backend resolves FICHERO_FEATURE_TIER in resolve_feature_tier() with valid values release, beta, alpha, and dev, defaulting to release on missing or unknown input. In this branch, FeatureManager.swift reads activeBuildTier from the baked FicheroFeatureTier Info.plist key, then FICHERO_FEATURE_TIER, then defaults to .dev. isVisible(_:) enforces the maturity floor with FeatureTiers.map[key]!.tier.rank >= activeBuildTier.rank, and each isXEnabled property gates its stored flag behind isVisible(key) && (allFeaturesEnabled || flag), so allFeaturesEnabled still cannot surface features below the active build tier. isDevFeatureTier is now deprecated shorthand for activeBuildTier == .dev.
Promotion
Promotion is a source edit plus regeneration:
- Change that feature’s
tier:infeatures.yaml. - Run
python scripts/gen_feature_tiers.py. - Commit the YAML change and the regenerated outputs together.
Use docs/reference_manual/features.md to verify the generated user-facing matrix after the bump.
scripts/promote_feature.py is a read-only validator for this workflow. It checks that the feature exists, the tier change is a real promotion unless --allow-demote is set, the generated files are fresh, and beta-or-higher route promotions still match the backend cumulative route data.
Checklist
Promotion should satisfy the target tier before you bump tier::
| Target tier | Minimum contributor checklist |
|---|---|
dev |
AI added; tests pass; swiftlint clean. |
alpha |
Daniel reviewed UX, edge cases, undo behavior, and side-effects. |
beta |
Smoke-tested on a clean install and through the TestFlight build checklist. |
release |
Full pytest and adversarial/security tests green; docs updated; appcast/DMG signed. |
Ownership
Promotion spans disjoint lanes:
- Scripts/docs lane edits
features.yaml, runsscripts/gen_feature_tiers.py, updates this page, and validates withscripts/promote_feature.py. - The generated user matrix lives in
docs/reference_manual/features.md; do not hand-edit it. - Manager-owned Xcode files such as
Info.plist, schemes, andproject.pbxprojstay out of the promotion lane even though they carry the bakedFicheroFeatureTierbuild setting.