Docs Supply-chain weighting

Supply-chain weighting

Weights are a company's share of the object's bill of materials and value. Unlisted makers stay in the picture but out of the basket.

Click a row to drop it from the basketΣ = 100.00%

The iPhone 17 Pro basket from lib/catalog.ts. Click a company to pretend its ticker is not live: the rest renormalise exactly as resolveBasket does.

What a weight means

A weight is a company's approximate share of the object's cost and value. Bill of materials is the starting point. Design and brand margin count for the maker, which is why Apple carries 46% of an iPhone while TSMC, which fabs the chip, carries 18%. Weights across the listed companies always sum to exactly 1.

The prompt asks for three to seven companies and a one-to-three-word role for each: Design, Silicon, Memory, Modem, Glass, Display, Assembly, Battery, Engines, Retail, Ingredients. Roles are for reading. Weights are for buying.

Listed and unlisted

Only companies with a live tokenized stock on Robinhood Chain go in companies. Everyone else who matters goes in unlisted with a reason, and stays visible on the page, greyed out. The three reasons you will see:

  • Private company: no public stock anywhere.
  • Listed only in Taiwan / Korea / Japan: public, but not on a US exchange Robinhood mirrors.
  • Not tokenized on Robinhood Chain: public in the US, not issued on chain 4663 yet.

Unlisted companies carry no weight. They are context, and a note about what the basket is missing.

Renormalisation

resolveBasket in lib/robinhood.ts runs on every basket, catalog or AI, before it reaches the UI. It looks each ticker up in the live quote map. A ticker with no quote moves to unlisted. The survivors are divided by their total, sorted by weight, rounded to four decimals, and the rounding residual lands on the largest leg so the sum is exactly 1.

const total = companies.reduce((s, c) => s + c.weight, 0);
for (const c of companies) c.weight = c.weight / total;
companies.sort((a, b) => b.weight - a.weight);
let acc = 0;
for (let i = 1; i < companies.length; i++) {
  companies[i].weight = Math.round(companies[i].weight * 1e4) / 1e4;
  acc += companies[i].weight;
}
companies[0].weight = Math.round((1 - acc) * 1e4) / 1e4;

The same thing happens again at buy time in planBasketBuy when a stock has a contract but no v4 liquidity for the requested size. Those legs go to unroutable and the rest absorb their weight, so you still spend the full amount.

The iPhone example

TickerCompanyRoleWeight
AAPLAppleDesign46%
TSMTSMCSilicon18%
QCOMQualcommModem10%
SKHYSK HynixMemory10%
AVGOBroadcomWireless8%
GLWCorningGlass8%

And the makers that stay in the picture but out of the basket:

CompanyRoleReason
FoxconnAssemblyListed only in Taiwan
SonyCamera sensorsNot tokenized on Robinhood Chain
Samsung DisplayOLED panelListed only in Korea
LG DisplayOLED panelNot tokenized on Robinhood Chain
MurataRF componentsListed only in Japan

Where weights come from

For the fourteen catalog objects, weights are hand-written opinions in lib/catalog.ts, checked to sum to 1 at module load (the file throws otherwise). For scans, the model writes them. Both go through the same resolveBasket.

Opinions, not audits

No one publishes a true bill of materials for an iPhone. The weights are defensible approximations from teardown estimates and public filings. Treat them as a starting point you can edit, not a fact.