Isolate the remaining products so their backend changes stop cascading
@gantoine is already working on this.
Since Aug 4, 2026.
- Dominant language
- Python
- Stars
- 39.9k
- Forks
- 3.4k
- Avg merge
- 6h 51m
- Merged PRs (30d)
- 232
Description
Problem
54 products have a backend/ directory but are not isolated, meaning they do not declare backend:contract-check in their package.json.
Two consequences, and the first one is mostly solved:
- Merge queue lanes. Until recently a backend change in a non-isolated product claimed all 82 Python lanes, serializing it against every other backend PR. Stack #76952 fixes the bulk of that by deriving lanes from
tach.tomlinstead, so the median product now claims 3. Isolation is no longer the big lever here. - CI cost. This one is untouched. A non-isolated product pays the full Django test suite on every backend change.
turbo-discoverusesbackend:contract-checkto decide whether the full suite can be skipped, so without it there is no selective testing for that product at all.
There is also a residual lane cost. Without a declared contract surface every backend file seeds the cascade, including tests and internals, so the widest products still drag in a dozen-plus lanes for a change nothing outside them can see.
What isolation requires
Not a config edit. products/architecture.md is explicit that declaring the key is a claim you have to earn first:
Skipping the full suite for an isolated product is a claim that a change inside the product can only break the product's own tests. tach proves the import half of that claim. It cannot prove the other half. [...] "No importers" is necessary, not sufficient.
The unprovable half is that cross-cutting tests (permissions, schema, activity-log) reach a product's endpoints by URL, in process, with no import for any graph to see. So it is closed by construction, per product:
- A facade as the product's only public interface.
- A thin presentation layer that reaches internals only through the facade.
- Behavior tests kept in-product.
Then, and only then:
"scripts": {
"backend:contract-check": "echo 'Contract files unchanged'"
}
Plus a turbo.json declaring the contract surface, using products/error_tracking/turbo.json as the reference. That second part is what stops internals from cascading.
[!WARNING]
The inputs list is load-bearing for correctness, not just cost. Omitting a path other products import puts them in a parallel merge-queue lane, which is the silent-breakage mode lanes exist to prevent. Over-declaring only costs parallelism, so when in doubt leave a path in.
Suggested order
Ranked by current lane width, which correlates with how much cross-product surface each one presents. CI-cost savings roughly track suite size instead, so the two orderings differ - worth checking both before picking.
| Product | Lanes today |
|---|---|
product_analytics |
17 |
cohorts |
14 |
feature_flags |
14 |
actions |
12 |
dashboards |
12 |
notifications |
12 |
cdp |
11 |
ai_observability |
9 |
signals |
9 |
data_tools |
8 |
experiments |
8 |
alerts |
7 |
event_definitions |
7 |
surveys |
7 |
The remaining 40 sit at 5 lanes or fewer, so their payoff is almost entirely the full-suite skip rather than queue parallelism.
All 54 non-isolated products with a backend
access_control, actions, ai_gateway, ai_observability, alerts, analytics_platform, annotations, approvals, batch_exports, business_knowledge, cdp, cohorts, conversations, dashboards, data_catalog, data_tools, demo, early_access_features, event_definitions, experiments, exports, feature_flags, field_notes, growth, links, live_debugger, llm_analytics, logs, managed_migrations, marketing_analytics, mcp_analytics, mcp_store, messaging, notebooks, notifications, platform_features, posthog_ai, product_analytics, product_tours, pulse, reminders, replay, replay_vision, revenue_analytics, review_hog, signals, skills, slack_app, surveys, tracing, user_interviews, warehouse_sources_queue, web_analytics, workflows
Out of scope: 12 products with no backend
core_events, desktop, games, groups, ingestion, integrations, persons, session_replay, session_summaries, subscriptions, support, toolbar
Nothing to isolate. desktop is already narrow via the backendDetachedProducts rule (a pytest.ini --ignore entry plus absence from tach.toml).
Already isolated: 15
customer_analytics*, data_modeling, data_warehouse, endpoints, engineering_analytics*, error_tracking*, legal_documents*, managed_warehouse*, metrics*, stamphog*, streamlit_apps*, tasks, visual_review*, warehouse_sources, wizard*
* = also declares narrowed contract inputs in turbo.json. The five without one treat every backend file as contract, so they still cascade on internals and are worth a follow-up too.
Notes
This is a tracking issue, not a single PR. Each product is its own change and wants review from whoever owns it, since the architectural work is the substance and the declaration is just the last line of it.
Numbers here were measured against master with stack #76952 applied.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.