Files
archy/.planning/MEDIA-AND-INDEEHUB-SCOPE.md
T

7.7 KiB

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.json401 + 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-catalog502, 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.

F. Added by operator 2026-08-06, late — not yet started

  • Cmd/Ctrl+K search → AIUI. Choosing "search with AIUI" from the command palette must open the EXPANDED chat with the typed query actually sent to AIUI and answered — today it does not carry the words through. Wire the palette's query into the chat open path.
  • Mock data types. Add more mock content types for dev/preview, and make the whole content path performant (the grid, the fan-out, the panel).
  • Node questions — full coverage. Every "ask the node about itself" question class should be answerable: apps, system, network, wallet, bitcoin, files, media, search, ai-local, notes are the declared AIContextCategory set in contextBroker's fetchAndSanitize. Audit each for real coverage rather than a stub.
  • AIUI seed/history as design input. The operator asked that the solution be researched from AIUI's own seed/history and the project's Nostr-first ethos, not invented fresh.

G. Status of the fixes made 2026-08-06

Shipped + deployed to archi-dev-box: content-grid sequence guard (aac81503), owned/peer scopes wired (11b9cb50), per-scope permission logging (7c23505d), warm-up app status (c65ee03a), scheme-following app frames (f09ff102), per-node CA + Settings flow (aab74127), app-port TLS with HTTP on the same socket (7515166a), key perms for the daemon (1dfd9e72).

Shipped, NOT yet deployed: the credential-less allowlist that fixes the IndeeHub regression — release build was in flight at end of session. Deploy is: install -m 755 core/target/release/archipelago /usr/local/bin/archipelago then systemctl restart archipelago (containers are unaffected — verified, they live in /user.slice, not the service cgroup), then re-test curl -o /dev/null -w "%{http_code}" http://<node>:7778/manifest.json — expect 200, not 401.