Orchestrate
The whole portfolio, in one graph
Most companies do not ship one product. Stripe runs Payments, Billing, Connect, Radar, and Terminal: separate products on shared infrastructure, serving overlapping customers. Kept as separate files, the relationships between them go missing: the dependency, the shared customer, the metric that should add up and does not. The portfolio layer types those relationships, so a question about how two products connect resolves to a traversal of one graph.
One organisation, two ways to slice it
A portfolio answers a strategic question: where does the company invest? An org chart answers a different one: who owns what? UPG keeps them as two independent axes over the same products. Collapsing the two into one tree forces a product to live where its funding sits or where its team sits, and the other fact is lost.
At Stripe, Radar is funded under the Core Payments portfolioportfolioA grouping of products by strategic axis and owned by the Acceptance & Risk product areaproduct_areaA grouping of products by organisational axis. Those are two separate facts about one productproductThe product being created, the root of the graph. A product can sit on one axis, both, or neither, and each axis nests to any depth.
organizationThe top-level organisational entityproduct_areaA grouping of products by organisational axisproduct_areaA grouping of products by organisational axisproductThe product being created, the root of the graphportfolioA grouping of products by strategic axisportfolioA grouping of products by strategic axisproductThe product being created, the root of the graphRadar sits in the Acceptance & Risk team’s remit and draws from the Core Payments investment line. One product, placed on two independent axes: a nested product area on the organisational side, a nested portfolio on the strategic side. A product may belong to an area, a portfolio, both, or neither.
The shared vocabulary the products agree on
The moment two products both have “customers”, they begin to disagree about what a customer is. Billing tracks a subscription; Connect tracks a connected account; Radar tracks a risk profile. Each is reasonable on its own. Together they make “active customers” a number nobody can total.
The registry is the shared-vocabulary tier. The canonical Customer is defined once, and each productproductThe product being created, the root of the graph registers its local copy as an instance_of it. The definitions stay linked, so portfolio_validate flags the moment an instance drifts from canon, while the divergence is still small.
Customer { email, subscription_status }Account { email, country, payouts }RiskProfile { email, risk_score }Three products, three definitions of the same person. “Active customers” means something different in each, so the company can never add them up.
registry/customerCustomer → registry/customerCustomer → registry/customerCustomer → registry/customerDefine it once in the portfolio registry; each product registers an instance. portfolio_validate flags an instance the moment its definition drifts from canon.
The relationships that usually go missing
Between products, the relationships that matter become typed edges, stored at the portfolio level rather than buried inside any one product. Billing, Connect, Radar, and Terminal all depend on the Payments productproductThe product being created, the root of the graph, so a change to the core names every product that feels it, before it ships.
Billing shares a persona with Connect, so a research insight about that developer is relevant to both at once; and a no-code Payment Link cannibalises the sales-led integration, turning a surprise into a tradeoff somebody decided on purpose. That is three of a dozen cross-product edge types, shares_competitor, succeeds, rolls_up_to, and the rest, each with a direction and a meaning.
productThe product being created, the root of the graphproductThe product being created, the root of the graphproductThe product being created, the root of the graphproductThe product being created, the root of the graphchange the core, see who feels itproductThe product being created, the root of the graphBetween products, the relationships that matter become typed edges, stored at the portfolio level rather than buried inside any one product. Four products depend on Payments, Billing shares a persona with Connect, and Payment Links cannibalises the sales-led integration. That is three of a dozen cross-product edge types, each with a direction, a meaning, and a use case, so a surprise becomes a tradeoff somebody decided on purpose.
Numbers and goals that roll up across products
Typing the relationships lets numbers and goals connect across levels. Billing’s monthly recurring revenue metricmetricA unified metric that measures progress, health, or behaviour across the product rolls_up_to Stripe’s total revenue run-rate; Billing’s objectiveobjectiveA strategic goal (OKR) to make recurring revenue easier contributes_to the company objective to grow payment volume.
When the leaf metric moves, the company north-star moves with it, because the edge between them was recorded once and stays in place. The cascade runs the other way too: ask what a company goal rests on, and the graph names the products carrying it.
Total revenue run-rateMonthly recurring revenueGrow total payment volumeMake recurring revenue effortlessA number moves on one product and the portfolio sees it at the top. The metric cascade (rolls_up_to) and the OKR cascade (contributes_to) keep leaf work legible at company scale, without a quarterly spreadsheet to reconcile it.
The watched field, in the same portfolio
The portfolio so far models what the organisation owns. The same tier extends to what it does not: a competitorcompetitorA competing product or company is a watched graph (member_kind: watched) inside the same portfolio, scored differently so it never drags the company health score down.
From there the competitive picture becomes structure. Every rival move is one dated competitor signalcompetitor_signalA competitor signal entity typed back onto a feature the company ships; parity becomes a traversal with the assessment on the edge; and every rival is placed against one shared classification. The Competitive Intelligence use case walks the whole motion.
not scored · no dragnot scored · no dragnot scored · no dragA competitor is a graph the company does not own. Marked member_kind: watched, it sits in the same portfolio as the products it competes with, but portfolio_validateand the coverage scorers skip it: an empty discovery region in Adyen’s graph is not a gap in the owned product.
The portfolio layer is optional and additive. A single-product file never has to know it exists; when the second product arrives, the same graph grows an organisational root, two axes, and a registry without rewriting what was already there. Follow a thread:
The reference: the dual-axis hierarchy, the registry, and all twelve cross-product edge types, with full property schemas.
The same tier turned on the field a company does not own: watched rivals, dated signals, parity, and classification.
The registry of specifications a portfolio shares, registered once for many products.