Compared refactor/centralize-feature-flag-registry with develop.
7aeca17e109 (refactor: centralize feature flag registry)
The branch changes feature flags from many module-local files merged at build time to one complete central file per variant.
The intended result is:
For a selected variant, every module sees the same feature values. Terraform and UI builds use the same source of truth as backend builds.
The central source is p8-variation-values/features/.
The design is simpler and easier to change, but this branch also exposes a few problems that should be fixed or consciously accepted before merging:
../features already exists. A clean checkout no longer has that directory, so deployment-gated modules such as the file converter can be skipped incorrectly (scripts/deployments/build_and_deploy.sh:803-806).
P8_FeatureFirmInAccount was removed from every registry although the UI still uses it. The validator does not detect the omission because it misses REACT_APP_P8_... references.
P8_DEPLOYMENT_TYPE into the shell variable used by envsubst, so its operation-cycle Lambdas can receive an empty deployment type.
Before this branch, a build commonly did this:
p8-variation-values/features/.
features/ directory.
features/p8_features.conf.
The old implementation is visible in the develop version of p8-deployments/scripts/build_utils.sh and p8-deployments/scripts/common.sh.
This allowed a component to disagree with another component for the same variant. It also made behavior depend on symlinks, file presence, and load order. For example, the matching engine had a CIX-local override for P8_ProductVariant, and API/system-manager files had their own flag values.
There are eight authoritative variant files:
p8-variation-values/features/
p8_bpx_features.conf
p8_carbon_features.conf
p8_cix_features.conf
p8_crypto_features.conf
p8_da_features.conf
p8_default_features.conf
p8_imperium_features.conf
p8_prediction_features.conf
Each file has the same 93 assignments. Only values differ. For example, CIX deliberately has:
P8_ProductVariant=carbon
P8_SolutionVariant=cix
This matters because CIX is a solution variant built on the Carbon product variant.
The registry includes more than feature switches. It also includes deployment flags, risk flags, operation-cycle flags, UI flags, and variant identity values.
registry.csv is metadata, not runtime input (p8-variation-values/features/registry.csv:1-94):
name,owner,default
P8_FeatureAnnouncement,p8-api,true
It records who owns a flag and what the default value should be. The loader does not read the CSV; the validator does.
init_feature_flags in p8-deployments/scripts/build_utils.sh:151-185:
P8_FEATURE_REGISTRY_DIR or known repository-relative paths.
feature_flags.sh.
features/p8_features.conf.
The generated file is a build/package artifact. It is not an independently edited source file.
common.sh::read_feature_info follows the same process (p8-deployments/scripts/common.sh:465-492).
p8-digital-asset-module/build_utils.sh is now a symlink to the shared implementation instead of a 532-line copy. This removes a second copy that could drift.
Twenty-seven deployments/tfvars.sh files now use the same three calls. For example, p8-api/p8-integrations/deployments/tfvars.sh:53-59:
source "$registry_dir/feature_flags.sh"
p8_load_feature_flags "$registry_dir" "${P8_SOLUTION_VARIATION:-$variant}"
p8_export_terraform_flags "$registry_dir/terraform-mappings.conf" "p8-api/p8-integrations"
terraform-mappings.conf has 97 rows for 27 consumers. A row has this shape:
consumer|source flag|Terraform variable|type
p8-api/p8-integrations|P8_FeatureIntegrations|enable_integrations|bool
The mapping layer is explicit. It does not guess Terraform names from flag names. It also:
true/false for bool mappings;
The processing engine intentionally maps several values as string, because its Terraform variables are string-typed (p8-variation-values/features/terraform-mappings.conf:80-86; p8-processing-engine/deployments/variables.tf:80-124).
The packaging logic now copies the complete central feature directory, including the loader, registry metadata, and mappings (scripts/deployments/build_and_deploy.sh:501-503).
A packaged deployment uses the already-generated features/p8_features.conf; it does not try to rebuild the registry from a source checkout (p8-deployments/scripts/build_utils.sh:156-167). This is the right separation:
Both UI scripts now call the shared loader and convert the generated environment variables from P8_* to REACT_APP_P8_*:
p8-trader-ui/scripts/p8_manage_feature_files.sh:15-36
p8-ui/scripts/p8_manage_feature_files.sh:17-58
The flow is:
central p8_<variant>_features.conf
-> generated features/p8_features.conf
-> variant .env file
-> P8_* renamed to REACT_APP_P8_*
-> webpack/rspack feature elimination
Variant-specific .env files are still appended after the central file. That means a UI .env file can still override a central value even though the new documentation says module-local overrides are prohibited.
The branch deletes 113 module-local variant feature files from components including API, auth, custody, file manager, post-trade, processing, refdata, system-manager, tools, and deployment scripts.
It also removes the feature-file include patterns from 20 module_conf.yaml files. The module configurations still decide whether a module supports a variant and whether an allowed_on_condition flag enables it; they no longer provide the flag values themselves.
Examples:
p8-api/module_conf.yaml:68-84
p8-file-manager/module_conf.yaml:1-45
p8-system-manager/module_conf.yaml:60-70
The file converter still uses a feature condition:
allowed_on_condition: "P8_FeatureDocxToPdfConverter"
The condition remains, but its value must now come from the central registry.
Two old include patterns remain:
p8-data-cache/module_conf.yaml still includes ./features/p8-default*.
p8-starter-pack/module_conf.yaml still includes uppercase ./features/P8_$P8_* patterns.
They look like remnants of older conventions and are not part of the new lowercase central registry model.
The old system-manager feature files contained both flags and ordinary Kafka/output configuration. This branch separates those concepts.
These values moved into per-variant YAML files:
p8-system-manager/p8-system-manager-engine/configs/*-config.yaml
The new files contain:
ops_cycle_cron_expression
system_stabilization_wait_time
sm_output_topic
sm_output_encoding_method
data_archival_output_topics
p8-system-manager/p8-system-manager-engine/deployments/tfvars.sh:60-65 reads the output settings from YAML. This is a good separation: feature flags remain in the registry, while operational configuration stays with system-manager.
scripts/deployments/build_and_deploy.sh:803-806 contains:
if [ -d "../features" ]; then
pushd ../
init_feature_flags $mode
popd
fi
The branch deletes tracked variant files and the features directory from many modules. On a clean checkout, ../features may not exist yet, so init_feature_flags is never called.
is_deployable_module then checks an unset feature variable (scripts/deployments/build_and_deploy.sh:731-747). For example, p8-file-manager/module_conf.yaml gates p8-file-converter on P8_FeatureDocxToPdfConverter, which is true for Carbon and CIX in the central registry. With no loaded environment variable, the converter can be treated as disabled.
The guard should be based on the central loader being available, or the orchestrator should always initialize flags before checking module conditions.
P8_FeatureFirmInAccount is missing but still useddevelop had this flag in the central files. The current registry.csv and all eight current variant files do not contain it.
The UI still contains feature-controlled branches, for example:
p8-ui/packages/p8-admin-ui-core/src/hooks/participants/useFirmAccounts.ts:20-32
p8-trader-ui/src/products/trader/services/AccountBalanceService/impl/AccountBalanceServiceImpl.ts:240-248
p8-trader-ui/src/products/admin/pages/sub-pages/RefData/EntityView/ParticipantsEntityView/FirmAccounts.tsx:221-229
Carbon and CIX previously set this flag to true; DA and most other variants used false.
The new validator misses this because its regular expression looks for a word boundary before P8_ (validate.py:15). In REACT_APP_P8_..., the preceding underscore is itself a word character. The validator also does not scan .env files.
This flag should be restored with per-variant values, or all consumers should be deliberately removed/rewritten.
deployment_type can become empty in system-manager TerraformThe old system-manager loader explicitly did:
export deployment_type="${P8_DEPLOYMENT_TYPE:-}"
The new loader removes that assignment (p8-system-manager/p8-system-manager-engine/deployments/tfvars.sh:51-65), but the generated Terraform file still contains:
deployment_type="$deployment_type"
at lines 201 and 213.
The shared provision script separately exports TF_VAR_deployment_type, but an explicit empty terraform.tfvars value takes precedence over that environment variable. The value is consumed by operation-cycle Lambdas as P8_DEPLOYMENT_TYPE (operation_cycle.tf:151-171 and later entries).
The old passthrough needs to be preserved or the Terraform template needs to use the shared variable consistently.
Centralization removes overrides by design. The important differences found during comparison are:
P8_EnablePasswordExpiration: true in the old API/system-manager local files, now false in p8-variation-values/features/p8_cix_features.conf:24. This gates the password-expiration Lambda and schedule.
P8_FeatureMarketDataUpdate: old API-local value false, current central value true (p8-variation-values/features/p8_imperium_features.conf:69). This now enables the market-data update API path.
P8_FeatureFileOperations: old API-local value false, current central value true (p8-variation-values/features/p8_imperium_features.conf:57).
P8_ProductVariant: old matching-engine override was cix; current central value is carbon, while P8_SolutionVariant remains cix.
These may be intended cleanup, but they are behavior changes rather than mechanical file moves.
Some documentation still describes per-module overrides:
documentation/architecture.md:1499
documentation/components.md:180
p8-deployments/scripts/AGENTS.md:226-234 has the new model, but other nearby guidance still assumes local feature files.
.agents/skills/product/add-variant/SKILL.md:103 still instructs contributors to create module-local feature files.
A future contributor following the old variant skill can immediately reintroduce the problem this branch is trying to remove.
Edit only the relevant central file:
p8-variation-values/features/p8_<variant>_features.conf
Do not edit generated features/p8_features.conf files. They are recreated by builds.
Example:
# p8_cix_features.conf
P8_FeatureMarketDataUpdate=true
Remember that this one value is now shared by every consumer of the CIX registry.
p8_*_features.conf files.
registry.csv with the owner and default.
The validator requires every variant to have the same key set and requires the default metadata value to match p8_default_features.conf (validate.py:34-106).
deployments/*.tf.
terraform-mappings.conf:
consumer|P8_SourceFlag|terraform_variable|bool
tfvars.sh calls p8_export_terraform_flags with the exact consumer name.
Use string instead of bool only when the Terraform variable is intentionally string-typed.
The current branch hard-codes the supported variant set in validate.py:14:
VARIANTS = {"bpx", "carbon", "cix", "crypto", "da", "default", "imperium", "prediction"}
A new variant therefore needs, at minimum:
VARIANTS;
variants: participation where appropriate;
Do not create module-local feature files for the new variant.
The branch’s new checks pass locally:
python3 p8-deployments/tools/feature_flag_tools/validate.py
Feature flag registry is valid
python3 p8-deployments/tools/feature_flag_tools/test_validate.py
6 tests passed
bash p8-deployments/scripts/tests/feature_flags_test.sh
feature flag loader tests passed
bash -n on changed shell scripts
passed
git diff --check
passed
The tests cover registry shape, loading, default fallback, Terraform mapping mechanics, and all eight variant loads. They do not cover UI builds, the clean-checkout orchestrator guard, system-manager Terraform output, or preservation of module-specific behavior.
| File | Role |
|---|---|
p8-variation-values/features/p8_<variant>_features.conf |
Authoritative values |
p8-variation-values/features/registry.csv |
Owner/default metadata used by validation |
p8-variation-values/features/terraform-mappings.conf |
Explicit Terraform consumer mappings |
p8-variation-values/features/feature_flags.sh |
Shared loader and Terraform exporter |
p8-deployments/scripts/build_utils.sh |
Build-time loading and generated package file |
p8-deployments/scripts/common.sh |
Main deployment/build helper’s registry loading |
scripts/deployments/build_and_deploy.sh |
Module selection, packaging, and deploy orchestration |
*/deployments/tfvars.sh |
Per-consumer Terraform variable generation |
p8-deployments/tools/feature_flag_tools/validate.py |
Registry/reference/mapping validation |
p8-deployments/scripts/tests/feature_flags_test.sh |
Shell integration coverage |
The architectural idea is straightforward and worthwhile: one variant file, one loader, explicit Terraform mappings, and validation in CI. The safest way to work with it is to treat p8-variation-values/features/ as the only editable feature source and remember that one value now affects every module.
Before relying on the branch, resolve the clean-checkout loading guard, restore or remove P8_FeatureFirmInAccount deliberately, preserve deployment_type, and confirm the listed CIX/Imperium value changes.