docs: scope the media/IndeeHub/AIUI work from on-device evidence

Every item was observed on archi-dev-box or read from source, not inferred:
the content-card parser mispairing titles with the previous description (the
real cause of "idiotic responses" — the model's prose was correct), IndeeHub's
three independent faults (empty public library, Nostr-only private auth, relay
502 on loopback), the fleet-wide gate bug that 401s credential-less PWA
manifest fetches and app-owned auth endpoints, and AI Data Access grants living
in per-origin localStorage when they are a property of the node.

Input for a research + plan pass, explicitly not the plan itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-06 18:34:26 -04:00
co-authored by Claude Opus 5
parent 7c23505d8c
commit 71bf4f3eaf
+98
View File
@@ -0,0 +1,98 @@
# Media, IndeeHub & AIUI quality — scope from on-device evidence
**Written 2026-08-06, end of session.** Every item below was observed on archi-dev-box or
read from source — none is inferred. This is the input for a proper research + plan pass,
not the plan itself.
## A. The content-card parser is the "idiotic responses" bug
Operator-visible symptom: asking for Bitcoin films produced good model prose, then cards
that were **wrong**:
- `Banking on Bitcoin` captioned with *The Rise and Rise of Bitcoin*'s description
- `Cryptopia` captioned with *The Bitcoin Standard*'s
- `Documentaries:` and `Narrative Films:` rendered as if they were titles
- `The Social Network` captioned with *Related Financial/Tech Films:*
Cause is `updatePanelFromText` (useContentPanel.ts) pairing title *n* with description
*n-1* and not excluding section headers. **The model was not at fault** — the card layer
mangled correct prose. Fix the parser before touching prompts.
Deeper question for the research pass: a regex over prose is the wrong contract entirely.
The model should return **structured** recommendations (tool call / JSON), and the grid
should render those. D-12 already says node content is the source of truth for these
buckets; text-scraping is the legacy path that should shrink, not be patched forever.
## B. IndeeHub — three independent faults
1. **Content source.** Films are `projects` in IndeeHub's NestJS API
(`GET /api/projects` via its own nginx; port 4000 is not host-mapped; `/graphql` is the
SPA catch-all, NOT an API). On this node `/api/projects/count` = **`{"count":0}`** —
the public library is genuinely empty. `content.owned-list` (content.rs) has **no**
IndeeHub linkage; `owned` is Archipelago's own paid-content store. So AIUI has never had
a path to IndeeHub content and would render nothing even if wired.
2. **Signer / auth.** `GET /api/projects/private` → 401
`{"message":"Cognito authentication is disabled. Use Nostr login."}`. Private films need
a **Nostr session**. `/api/auth/nostr/session` 401s through the gate (see C). An adapter
must therefore authenticate as the user — which lands on the phase's non-negotiable:
keys stay out of the browser and the model, so this belongs node-side behind a capability
grant. Same shape as follow-on Phase C (Nostr first-class).
3. **Relay is down independently.** `/relay` returns **502 direct on loopback**, bypassing
the gate — IndeeHub's own nginx cannot reach the relay container. `wss://relay.damus.io`
also fails from that page. Not a gate fault.
## C. The app gate breaks apps that own their auth — FLEET-WIDE, highest priority
Verified: `http://<node>:7778/manifest.json`**401 + the gate's login HTML**.
- **A PWA manifest is fetched WITHOUT credentials** unless the tag sets
`crossorigin="use-credentials"`. The cookie is never sent, so the gate 401s it *even when
fully logged in*. This hits **every gated app with a PWA manifest**, not just IndeeHub.
- The app's service worker serves the cached shell, so the SPA boots ("Backend connected at
/api — real mode active") and only then does every network call 401 — which is why it
looks like an app bug rather than a gate bug.
- The gate also intercepts the app's own `/api/auth/nostr/session`, so IndeeHub can never
establish its own session. "Nostr login failed" / "Sovereign identity generation failed"
are all this one cause.
Same class as the `.125` cookie-strip that broke every companion UI. The gate needs a
stated policy for (a) credential-less subresource fetches the browser sends by design and
(b) app-owned auth endpoints once a valid gate session exists. **Each exemption is a hole in
a security control and needs its own written justification** — do not batch-fix this.
## D. AI Data Access grants do not survive — wrong storage layer
`aiPermissions.ts` persists to `localStorage` (`archipelago-ai-permissions`). No logout path
clears it (only SystemDangerZone, by design). **localStorage is per-origin**, and a node has
many: `192.168.63.240`, `100.69.68.39`, `<host>.local`, the Tailscale name. Granting on one
and returning via another shows everything off — which is exactly what "turns them all off"
looks like, and what made a films search look broken tonight.
These grants are a property of the NODE ("what may the AI read"), not of one browser at one
address. They belong node-side behind an RPC, with localStorage as an offline fallback and a
migration so existing local grants are not silently dropped.
## E. Also observed, unowned
- `/api/app-catalog`**502**, repeatedly, on the dashboard.
- AIUI web search blocked by CSP (`connect-src http://<node>:*/aiui/`) — confirms the
already-recorded 13-09 decision that the web-search setting must drive the CSP node-side.
- `Failed to scroll to index N after 10 attempts` — ChatWindow scroll bug, cosmetic but loud.
- `strfry.png` / `.svg` 404 — missing app icon.
## Suggested sequencing (to be challenged by the research pass)
1. **C** — fleet-wide, user-visible, security-critical. Blocks any app with its own login.
2. **D** — one RPC; unblocks every AI content path and stops false "broken" reports.
3. **A** — parser fix now, structured-output contract as the real answer.
4. **B** — needs C and D first; the signer question is a design decision, not a task.
## Nostr-first framing (per feedback_nostr_first_solutions)
Worth researching rather than assuming: IndeeHub already speaks Nostr for identity, and the
node already holds Nostr identity material. A single node-side signer serving both the
dashboard and gated apps (NIP-07-style bridge, already precedented by `nostr-provider.js`)
would address B-2, the app-auth half of C, and Phase C's zaps at once. Media identity/
distribution over Nostr (NIP-94/NIP-71 style events, Blossom for blobs) is the obvious
frame for "all the media types" and should be evaluated against the current
`content.*` RPC model before more sources are bolted onto it.