From 6f453364cbbcd000311bd85ca6900f83967af5d6 Mon Sep 17 00:00:00 2001 From: "@permadeath.com" Date: Wed, 21 Oct 2026 12:06:18 -0400 Subject: [PATCH] fix(index): answer usage only for an account the view holds /usage/{did} and /usage/operator/{did} are a 404 for a DID the view does not hold, without a query service asking the index. Co-Authored-By: Claude Opus 5.5 Change-Id: Ibb31fc431fc2d8690dbbd4e5f7a4c28b90e14ffb --- crates/vibescrobble-index/src/burn.rs | 28 ++++++++++++++++++++++++--- docs/running-locally.md | 3 ++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/crates/vibescrobble-index/src/burn.rs b/crates/vibescrobble-index/src/burn.rs index ec86c558..cd61f540 100644 --- a/crates/vibescrobble-index/src/burn.rs +++ b/crates/vibescrobble-index/src/burn.rs @@ -1380,14 +1380,36 @@ impl Burn { } /// An agent's or an operator's summary, from the store or the index. + /// + /// `None` at once for an account `view` does not hold, which nothing has + /// counted, so a made-up DID costs the index no question. An operator's + /// row is whoever an agent rolls up to: a person, or an agent nobody + /// answers for. pub async fn usage_of(&self, view: &View, whose: Whose<'_>) -> Option { + let held = match whose { + Whose::Agent(did) => view.agent(did).is_some(), + Whose::Operator(did) => { + view.operator(did).is_some() + || view.agent(did).is_some() + || view + .agents_after(None, |agent| { + agent + .operator + .as_ref() + .is_some_and(|human| human.did == did) + }) + .next() + .is_some() + } + }; + if !held { + debug!(?whose, "no usage for an account the view does not hold"); + return None; + } match self { Burn::Local(store) => { // The view only for who rolls up where; the sums run off // the runtime. - if let Whose::Agent(did) = whose { - view.agent(did)?; - } let lineages = Lineages::of(store, view); let store = Arc::clone(store); let (agent, did) = match whose { diff --git a/docs/running-locally.md b/docs/running-locally.md index 8917987b..d4db10fe 100644 --- a/docs/running-locally.md +++ b/docs/running-locally.md @@ -371,7 +371,8 @@ has a counted window: `own` and `subtree`, each per `hour`, `day`, `week` and on, and the same `usage` over every account they operate (the set their `by=operator` row counts), without `own`. The query service keeps no rollups and asks the index for all three, on the index's `/leaderboard`, -`/usage/{did}` and `/usage/operator/{did}`. +`/usage/{did}` and `/usage/operator/{did}`; a DID the view does not hold is a +404 without asking. These are ordinary JSON on ordinary paths and deliberately not `/xrpc/…`: there are no query lexicons behind them, and a path that claimed otherwise -- knotmirror 0.0.1