diff --git a/.planning/INDEEHUB-CONTENT-INVENTORY-2026-08-07.md b/.planning/INDEEHUB-CONTENT-INVENTORY-2026-08-07.md new file mode 100644 index 00000000..b8518502 --- /dev/null +++ b/.planning/INDEEHUB-CONTENT-INVENTORY-2026-08-07.md @@ -0,0 +1,83 @@ +# IndeeHub content inventory on archi-dev-box — 2026-08-07 + +Measured, not inferred. Written as a separate file because the surfaces todo and the +resume doc were being edited by a concurrent session at the time. + +## The operator's report + +Asked AIUI "what films are there to watch from my peers", and the assistant replied +that it *"[doesn't] have a tool that lets me query the content library of IndeedHub"* +and told them to open `localhost:7778` themselves. + +Two separate defects sit behind that one answer. **They have different fixes and only +one of them is being worked.** + +## 1. The tool gap — already in flight, do not duplicate + +A concurrent session is adding a `content_list` tool with `own` / `peers` / +`purchased` / `films` scopes, a `SURFACE_TOOLS` list so grid-ready results are +RENDERED rather than narrated, and a test that every advertised scope reaches a real +dispatch handler. Its own comment names this symptom ("it could find no peer +content"). Uncommitted at the time of writing — `assistant/tools.rs`, +`archyBridge.ts`, `contextBroker.ts` and 7 more. + +## 2. The category union is narrower in AIUI than in the broker — SEPARATE, unowned + +The broker serves **ten** categories (`neode-ui/src/types/aiui-protocol.ts`): + + apps system network wallet files media search ai-local notes bitcoin + +AIUI declares **six**, in two places: + + aiui/packages/app/src/composables/useArchy.ts:11 + aiui/packages/app/src/services/archyBridge.ts:8 + → apps system network wallet files bitcoin + +`media`, `search`, `ai-local` and `notes` cannot be requested by AIUI at all — the +string never appears in its source. `contextBroker.fetchAndSanitize` has a working +`case 'media': return this.sanitizeMedia(appStore)` arm on the other side of a door +AIUI cannot open. This is very likely why the model reported having no capability +rather than reporting an empty library. + +Whether `content_list` supersedes this or runs beside it is a real design question: +the content scopes and the context categories are two different channels. Decide it +deliberately rather than letting the union drift further. + +## 3. The library is EMPTY — the part that will not be fixed by either + +Measured on archi-dev-box, with a real Nostr session obtained through the gate +(node-signed NIP-98 → JWT): + +| endpoint | auth | result | +|---|---|---| +| `GET /api/projects` | none | `[]` — **0 items** | +| `GET /api/projects/private` | Bearer (valid nostr-session) | `[]` — **0 items** | +| `GET /api/projects/mine` | Bearer | 404 `"Film not found"` — route does not exist | + +So once the tool lands, the honest answer to "what films are there to watch" **from +this node's own library is still "none"**. Anything the operator sees must come from +the `peers` scope — the federated browse over FIPS with Tor fallback, which is the +slow path the concurrent session just made progressive so it no longer blocks `own`. + +**Do not let a correct "0 results" read as the tool still being broken.** When +verifying the `content_list` work, seed at least one project into IndeeHub first, or +verify against a peer node that has content — otherwise a fully working tool and a +completely broken one produce the same empty grid. That ambiguity is the same trap +recorded for the AI grants ("ungranted" and "empty library" were indistinguishable). + +## Verification recipe (reusable) + +The node can sign a real NIP-98 event itself, so IndeeHub's authenticated API can be +exercised with no browser and no extension: + +1. `auth.login` on `127.0.0.1:5678/rpc/v1` → capture the `session` **and** + `csrf_token` cookies from the Set-Cookie headers (curl's jar drops session cookies). +2. `node.nostr-pubkey` → the node's pubkey. +3. `node.nostr-sign` with a kind-27235 event, tags `[["u", ], ["method","POST"]]`. + **The CSRF header is required for signing** — `node.nostr-pubkey` is exempt, the + sign is not, and it 401s without it. +4. `POST /api/auth/nostr/session` with `Authorization: Nostr ` → JWT. +5. Use `Authorization: Bearer ` for the private endpoints. + +Both the NIP-98 login and the app's own bearer now survive the gate — see +`RESUME-2026-08-06-media-loop.md` item 1.