Skip to main content
ThunderLang
← All articles
system-design

One Decision, Four Languages, One Source of Truth

6 min read · 2026-08-15 · Allen Codewell

Keeping feature flags consistent across languages is rarely a documentation problem. It is a codegen problem, and conform --all-targets is the specific tool that solves it.

The Drift Problem Nobody Talks About Honestly

Here is the situation that actually happens. A product team ships a feature flag called enable_price_rounding_v2. The TypeScript frontend checks it as a boolean. The Python data pipeline checks it as a string, because whoever wired it up was in a hurry and the config library they used deserved its star rating. The C# billing service checks it correctly but uses the key enablePriceRoundingV2 instead of enable_price_rounding_v2, so it silently falls back to the default and the flag does nothing. The Java payments service does not check it at all because the ticket got lost.

Four weeks later, the flag is "on" and users are seeing inconsistent rounding behavior across surfaces. The postmortem blames "cross-team communication" and adds a step to the release checklist.

It does not blame the actual cause: there was no single source of truth that enforced the decision across all four runtimes simultaneously.

What a Single Source of Truth Actually Means Here

The phrase gets used loosely. In the context of a polyglot system, a single source of truth for a feature flag means one place declares the flag's name, type, default, and rollout logic, and every language-specific implementation is a deterministic artifact of that declaration, not a separate human decision.

This is different from a shared config file that every team reads. A config file is passive. It tells you what the flag value is at runtime. It does not tell the TypeScript compiler, the Python type checker, the C# analyzer, or the Java build system what contract the flag is supposed to satisfy. Those teams still have to independently translate the intent, and that translation step is where drift lives.

Drift is not usually caused by negligence. It is caused by four engineers, working in four codebases, at four different times, making four locally reasonable decisions that do not compose. A single source of truth is only real if it eliminates the per-language translation step entirely.

How conform --all-targets Closes the Gap

conform --all-targets runs a conformance check against every declared target language in a single invocation. Instead of running TypeScript conformance in your TS CI pipeline, Python conformance in your Python pipeline, and hoping someone eventually ties them together, you run one command that treats the multi-language agreement as the unit of correctness.

For the feature-flag case, the workflow looks like this. You declare the flag in ThunderLang's schema format: its canonical snake-case key, its type as a boolean, its default value of false, and the rollout percentage. That declaration is your source of truth. conform --all-targets then verifies that the generated TypeScript interface, the Python TypedDict, the C# record, and the Java enum constant are all consistent derivations of that one declaration, and that none of them have drifted since the last verified state.

The key word is verified. Not "probably fine because nobody touched it." Verified, with a proof artifact that your CI pipeline can gate on.

If the C# team renames the property to camelCase for style reasons, that is a conformance failure. If the Python team changes the default to True locally because a test was flaky, that is a conformance failure. The command does not warn. It fails the build.

The Feature Flag Case Study, Concretely

The flag is enable_price_rounding_v2. The declaration sets the type as boolean, default false, affecting 10% of users in the initial rollout.

Without conform --all-targets, here is what the four-language surface area looks like after two sprints of independent development. TypeScript has it typed as boolean | undefined because someone added an optional chaining guard defensively. Python has it as Optional[str] because the config library returns strings. C# has it as bool with the right default. Java has it, but the constant name is ENABLE_PRICE_ROUNDING_V2 and the consuming code accidentally checks the negation because the original author was wrapping a "disable" flag they replaced.

Every one of those is a local decision that made sense in isolation. Collectively they mean the feature is live for TypeScript users, does nothing for Python pipelines because "false" is truthy in Python, behaves correctly for C# billing, and is inverted for Java payments.

With conform --all-targets, none of those states are possible at deploy time. The TypeScript type is generated, not handwritten. The Python TypedDict is generated. The C# record is generated. The Java constant and its accessor are generated. The only thing a human writes is the declaration, and the only thing any engineer in any language ever touches is that canonical declaration or the business logic that consumes the already-correct generated artifact.

The drift surface goes from four independent translation steps to zero.

Why Deterministic Codegen Beats Review and Documentation

The standard mitigation for cross-language drift is documentation and code review. Write a Confluence page describing the flag contract. Add a checklist item. Require cross-team review on flag-related PRs.

This works until it does not, which is usually around sprint three when everyone is busy.

Deterministic codegen does not get tired. It does not skip the Friday afternoon deploy because the author was out. It does not rely on a reviewer who does not actually run the Python service having caught the Optional[str] type. It produces the same output from the same input every single time, and conform --all-targets makes the verification of that property a hard gate rather than a soft hope.

The more important point is what this does to the cognitive load of adding a new language to your stack. Adding a fifth language to a polyglot system that manages flags through documentation means updating the docs, training the new team on the conventions, hoping they read the right revision, and waiting for the first production incident to surface what they missed. With ThunderLang's conformance model, adding a fifth target means adding a target to the schema and running the command. The new language inherits the existing verified contract automatically. That is not a small operational improvement. That is a fundamentally different scaling property.

What Conform Does Not Solve

conform --all-targets ensures structural consistency. It does not ensure behavioral correctness. If your feature flag declaration says the default is false but the correct default should be true for the C# service's use case, that is a specification error, not a drift error. The command will happily generate four perfectly consistent wrong artifacts.

It also does not replace integration tests. Two services can each correctly implement a feature flag contract and still disagree at the network boundary because of serialization format differences, header negotiation issues, or latency-dependent race conditions. Conformance is a necessary condition for correctness across languages. It is not sufficient.

You can read more about where ThunderLang's verification model fits in a broader quality pipeline in the getting-started documentation, which covers how verify-diff and proof artifacts compose with your existing CI setup.

The practical implication: use conform --all-targets to eliminate the class of bugs caused by independent translation of a shared intent. Keep your integration tests and contract tests for the rest.

The Organizational Consequence

There is a second-order effect worth naming. When four teams share a feature flag system built on documentation and convention, each team owns a local interpretation of the shared contract. When something goes wrong, the postmortem is a negotiation over which interpretation was authoritative.

When four teams share a feature flag system built on a single declared schema with verified generated artifacts, the canonical declaration is always authoritative. The postmortem is shorter. The blame is structural rather than personal. The fix is a schema change with a new conformance run, not a Confluence page update and a promise to communicate better.

This changes how teams talk to each other about flag changes. Instead of "can you make sure your team updates the Python side," the conversation becomes "here is the schema PR, conformance gates on merge." The process is self-enforcing because the tool enforces it.

A team that has shipped this pattern once does not go back to the documentation approach.

Gate your first AI change

ThunderLang lets you declare what a change must satisfy, then gates AI-written code against that intent with a verify-diff and durable proof artifacts, which is exactly the right foundation for polyglot feature flag work where an AI assistant might generate the C# and the Java and you need a hard guarantee they agree. Try it here.

The moment you make a declaration the source of truth and a tool the enforcer, cross-language drift stops being a people problem and starts being a solved one.