You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/api/v1/accounts/{ss58}/positions publishes position_count: 0, total_stake_alpha: 0 and no degraded block for coldkeys that demonstrably hold positions in the ledger it reads.
Evidence
Coldkey 5Df7xwEPkZm4itD3PfSzHsV9extvnQpTFBiNCSgBCJtxEP9e is literally the first row of chain.nominator_positions:
No degraded marker — so this reads as measured fact: "this account holds nothing."
Root cause
buildAccountPositions (src/account-nominator-positions.ts:162) prices each position off the live
D1 neurons table and silently drops any position it cannot price:
neurons is healthy and current (129 netuids, 30,085 rows, captured_at minutes old), but it holds
only currently-registered neurons, while chain.nominator_positions is a frozen export from
2026-08-02. Sampling 8 distinct hotkeys from the ledger, only 1 of 8 is present in neurons.
So most positions are dropped, and an account whose positions are all dropped reports a confident
zero.
The unavailableAccountPositions card exists to prevent exactly this — but it only fires when every tier declines. Here a tier answered successfully; the loss happens per-position, below that check.
Secondary finding: the hot leg cannot fire
nominator_positionsdoes not exist as a table in the production D1 database:
SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%position%'
-> account_position_daily (only)
migrations/d1/0011_nominator_positions.sql was written but never applied (d1_migrations has 0
rows — the schema was clearly created outside that mechanism, so the whole migration ledger is
unreliable here, not just this entry). #9273's design says the hot leg's emptiness makes "the
cutover a property of the data, not of a deploy" — but a missing table is not an empty one, so the
route is pinned to the frozen export indefinitely.
The contract question this needs a decision on
Dropping unpriced positions may well be deliberate — #9066 explicitly removed the unpriced_*
escape hatches elsewhere. But a caller currently cannot distinguish:
"this coldkey holds nothing", from
"this coldkey holds positions we could not price".
Those are opposite answers and the payload gives them the same shape. Options, smallest first:
/api/v1/accounts/{ss58}/positionspublishesposition_count: 0,total_stake_alpha: 0and nodegradedblock for coldkeys that demonstrably hold positions in the ledger it reads.Evidence
Coldkey
5Df7xwEPkZm4itD3PfSzHsV9extvnQpTFBiNCSgBCJtxEP9eis literally the first row ofchain.nominator_positions:The route returns:
{ "position_count": 0, "total_stake_alpha": 0, "positions": [] }No
degradedmarker — so this reads as measured fact: "this account holds nothing."Root cause
buildAccountPositions(src/account-nominator-positions.ts:162) prices each position off the liveD1
neuronstable and silently drops any position it cannot price:neuronsis healthy and current (129 netuids, 30,085 rows,captured_atminutes old), but it holdsonly currently-registered neurons, while
chain.nominator_positionsis a frozen export from2026-08-02. Sampling 8 distinct hotkeys from the ledger, only 1 of 8 is present in
neurons.So most positions are dropped, and an account whose positions are all dropped reports a confident
zero.
The
unavailableAccountPositionscard exists to prevent exactly this — but it only fires when everytier declines. Here a tier answered successfully; the loss happens per-position, below that check.
Secondary finding: the hot leg cannot fire
nominator_positionsdoes not exist as a table in the production D1 database:migrations/d1/0011_nominator_positions.sqlwas written but never applied (d1_migrationshas 0rows — the schema was clearly created outside that mechanism, so the whole migration ledger is
unreliable here, not just this entry). #9273's design says the hot leg's emptiness makes "the
cutover a property of the data, not of a deploy" — but a missing table is not an empty one, so the
route is pinned to the frozen export indefinitely.
The contract question this needs a decision on
Dropping unpriced positions may well be deliberate — #9066 explicitly removed the
unpriced_*escape hatches elsewhere. But a caller currently cannot distinguish:
Those are opposite answers and the payload gives them the same shape. Options, smallest first:
existing
degradedblock, no schema change, and keeps fix(api): require the alpha price and drop the unpriced_* escape hatch #9066's no-unpriced-values rule intact.(Recommended.)
dropped_position_countalongside the list.stake_tao— contradicts fix(api): require the alpha price and drop the unpriced_* escape hatch #9066.Acceptance
neurons-coverage shortfall is visible to the caller rather than silently absorbednominator_positionstable should be created so the hot legcan ever take over, or whether fix(accounts): nominator_positions has no live refresh — /positions is frozen at the export and drifts forever #9273's lane is abandoned in favour of the export