docs: resume artifact — AIUI surfaces, the peer-files correction, SearXNG
Carries the full task list with per-item status, the three commits' rationale, the live measurements that overturned the earlier peers-have-no-content conclusion, the browser-verification recipe, and the binary-drift blocker that must clear before the ISO. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
9cf1c12213
commit
bca18c03d2
@@ -0,0 +1,292 @@
|
|||||||
|
# RESUME — 2026-08-07 (afternoon). AIUI surfaces + demo prep.
|
||||||
|
|
||||||
|
**Read this first.** Then `.planning/RESUME-2026-08-07-aiui-demo.md` (the previous
|
||||||
|
handoff, still the source for the traps list), then
|
||||||
|
`.planning/RESUME-2026-08-06-media-loop.md` (the fix→deploy→test loop).
|
||||||
|
|
||||||
|
Branch `gsd/phase-13-aiui-functional-conversational-node-control-and-content-surf`
|
||||||
|
@ `b1c5d138`. Working tree: clean except `neode-ui/shot.tmp.mjs` (a throwaway
|
||||||
|
Playwright driver, see "Browser verification" below — delete or keep, it is not
|
||||||
|
committed).
|
||||||
|
|
||||||
|
**Context: AIUI is being demoed soon and a clean ISO must be cut.** The operator's
|
||||||
|
priority order is #16, #15, #9, #17.
|
||||||
|
|
||||||
|
**The operator's standing instruction for this work:** fix → test → check the
|
||||||
|
browser with screenshots → deploy → debug → fix, in a loop, without stopping to
|
||||||
|
ask questions. And: *"if you think you know better like the peer files you are
|
||||||
|
completely wrong"* — see "The peer-files correction" below. Do not re-derive the
|
||||||
|
old conclusion.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## THE TASK LIST — rebuild this in the session task tool on resume
|
||||||
|
|
||||||
|
`[x]` = done, deployed AND verified on the node.
|
||||||
|
|
||||||
|
- [x] **1. Unify AI Data Access toggles with assistant tool grants** — `55155f2d`
|
||||||
|
- [ ] **2. Verify AI grants persist across refresh through the real UI path**
|
||||||
|
- [ ] **3. Add `app_install` / `app_uninstall` tools** (behind the 13-08 confirm gate)
|
||||||
|
- [ ] **4. `!archy` / `!ai` over mesh must action commands** with text responses
|
||||||
|
- [x] **5. Cap `content.browse-all-peers`** — `75919a20`, then rebuilt as Cloud's fan-out
|
||||||
|
- [~] **6. Settings link when a request needs an ungranted permission** — node + broker
|
||||||
|
+ chrome banner all landed in `9abc1623`; **NOT yet seen in a browser** (needs a
|
||||||
|
turn that actually hits an ungranted category — try revoking `media` and asking
|
||||||
|
for content). Finish by confirming the banner renders and its button lands on
|
||||||
|
the AI Data Access section.
|
||||||
|
- [ ] **7. App lifecycle defects** — fedimint guardian installs but doesn't work; BTCPay
|
||||||
|
uninstall-with-wipe reinstalls with an account still enabled; Bitcoin Knots and other
|
||||||
|
apps disappeared; fedimint gateway died at 88%; reconciler `chown postgres-btcpay`
|
||||||
|
failures (same volume-ownership family as the IndeeHub relay fix)
|
||||||
|
- [ ] **8. LND UI + filebrowser 401s** — every `:18083/proxy/lnd/*` and
|
||||||
|
`/app/filebrowser/api/resources/`. Node-owned `*-ui` apps need session passthrough;
|
||||||
|
memory says that rides DISK manifests because the catalog refuses build-source.
|
||||||
|
**Untouched this session.** Note the 403s still in the browser console (below) may
|
||||||
|
be this same family — worth checking before assuming a separate cause.
|
||||||
|
- [~] **9. AIUI must answer with content + context surfaces, NOT JUST prose** —
|
||||||
|
*(operator correction: the prose answer stays, it is wanted; what was missing is
|
||||||
|
the surfaces alongside it)*. Largely delivered by the work below and verified in a
|
||||||
|
browser. Remaining: only `content_list`/`apps_list` are surface-producing tools, so
|
||||||
|
turns about system/network/bitcoin still answer in prose only. Decide whether those
|
||||||
|
deserve context surfaces too.
|
||||||
|
- [~] **10. AIUI slow background image + console noise** — web-search CSP spam and the
|
||||||
|
web-search 403 are FIXED (`b1c5d138`). Still open, all observed live in the console:
|
||||||
|
wavlake.com + itunes.apple.com blocked by CSP (song cover enrichment — this is the
|
||||||
|
known 13-09 CSP issue; memory says the decision is that the web-search setting
|
||||||
|
should drive the CSP, moved node-side), three 403s, two 402 Payment Required, a 502,
|
||||||
|
a 404, and the sw.js SSL registration failure (self-signed cert). The slow
|
||||||
|
background image itself was not investigated.
|
||||||
|
- [ ] **11. Cmd/Ctrl+K → AIUI must carry the query into the expanded chat** — I read the
|
||||||
|
whole path (`SpotlightSearch.vue:294` → `Chat.vue` `askedAt` watcher → `flushAsk`
|
||||||
|
→ `chat:prefill` → `archyBridge.onPrefill` buffering → `ChatInput.vue:224`) and it
|
||||||
|
is **fully wired and looks correct**, including the cold-frame buffer. It
|
||||||
|
deliberately prefills-and-focuses rather than auto-sending. **Not reproduced, not
|
||||||
|
verified in a browser.** Do that before changing any code — the report may predate
|
||||||
|
the fix.
|
||||||
|
- [x] **12. Node certificate settings section** container/layout — `75919a20`
|
||||||
|
- [ ] **13. HTTPS dynamically on EVERY address** alongside Tailscale (LAN done; must
|
||||||
|
re-apply as addresses change, and the bare hostname must resolve)
|
||||||
|
- [ ] **14. Nostr signer + service worker over HTTPS** (operator: lower priority than AIUI)
|
||||||
|
- [x] **15. Content-surface header** — the stale-title half is DONE and browser-verified
|
||||||
|
("Loading…" during the turn, "Nothing found" on an empty result, correct count
|
||||||
|
after). **The header-overlap half is NOT confirmed:** at 1600×950 the close button
|
||||||
|
(`absolute top-3 right-3`) does not collide with anything — the tab row already
|
||||||
|
carries `pr-12` (`ChatPage.vue:38`). I never reproduced the overlap. **Check a
|
||||||
|
narrow/mobile viewport** before editing CSS; that is the most likely place it bites.
|
||||||
|
- [x] **16. Populate the content surface for own shared content + rich chat previews** —
|
||||||
|
DONE and browser-verified. See below.
|
||||||
|
- [ ] **17. Cut a clean ISO for the demo** — `UNBUNDLED=1 bash
|
||||||
|
image-recipe/build-debian-iso.sh` (the default env silently builds the wrong
|
||||||
|
full-bundle variant); verify the frontend INSIDE the ISO.
|
||||||
|
**BLOCKER: rebuild the release binary first** — see "Binary drift" below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What shipped this session
|
||||||
|
|
||||||
|
| What | Commit |
|
||||||
|
|---|---|
|
||||||
|
| Content surface renders what the assistant found (4 defects) | `9abc1623` |
|
||||||
|
| SearXNG JSON 403 — AIUI web search never worked | `c810b514` |
|
||||||
|
| Node content outranks the prose surface; web-search path | `b1c5d138` |
|
||||||
|
|
||||||
|
### `9abc1623` — the content surface, four separate defects, one symptom
|
||||||
|
|
||||||
|
The symptom was always the same: a correct prose answer beside an empty grid.
|
||||||
|
|
||||||
|
1. **The assistant's curated RPC bridge had an arm only for `content.list-mine`.**
|
||||||
|
`assistant/tools.rs` mapped the `peers`, `purchased` and `films` scopes onto
|
||||||
|
`content.browse-all-peers` / `content.owned-list` / `content.indeehub-projects`
|
||||||
|
— three real, dispatcher-registered handlers that `assistant_dispatch_tool`
|
||||||
|
(`api/rpc/assistant_chat.rs`) had never heard of. Every non-`own` scope died on
|
||||||
|
its catch-all with "no such handler". **The tool never ran.** Regression test
|
||||||
|
added: `every_content_scope_reaches_a_real_dispatch_handler`.
|
||||||
|
2. **`content.browse-all-peers` threw away completed work.** It wrapped the whole
|
||||||
|
fan-out in one `timeout(overall, ...).unwrap_or_default()`, which DISCARDED
|
||||||
|
every finished batch the moment the budget expired. One slow peer turned a
|
||||||
|
partly-successful browse into `peers_reached: 0, peers_unreachable: 16`. Now it
|
||||||
|
accumulates per batch and checks a deadline between batches, so partial results
|
||||||
|
always survive; budget 20s → 45s (two batches of 8 at a 10s per-peer timeout had
|
||||||
|
literally zero headroom).
|
||||||
|
3. **`assistant.chat` returned only `{ text }`.** The structured tool results were
|
||||||
|
dropped inside the loop. The turn now carries them through as `surfaces`,
|
||||||
|
captured RAW in `loop_::execute_tool`'s `Ok(v)` arm — deliberately BEFORE
|
||||||
|
`wrap_tool_result_if_untrusted`, because that boundary exists to stop peer text
|
||||||
|
being read as instructions by the MODEL, and this copy goes to a renderer that
|
||||||
|
treats every field as inert data and never re-enters the prompt.
|
||||||
|
4. **The adapter classified images as `'excluded'` and dropped them.** A node
|
||||||
|
sharing mostly photos rendered as an empty grid while AIUI's `panelImages` /
|
||||||
|
`ImageGrid` sat unused. Images now have a bucket end to end
|
||||||
|
(`archyContentAdapter` → `contextBroker` → `archyBridge` → `useArchy` →
|
||||||
|
`useContentPanel`), with the paid-lock and extension-fallback handling that
|
||||||
|
audio and video already had.
|
||||||
|
|
||||||
|
Also in that commit: the "Loading…" / "Nothing found" panel headings; a system-prompt
|
||||||
|
paragraph telling the model to call the content tool and summarise rather than
|
||||||
|
re-list what the cards already show; and `refused_categories` on the chat response so
|
||||||
|
the trusted chrome can offer the AI settings screen (task 6).
|
||||||
|
|
||||||
|
### `c810b514` — SearXNG JSON was 403, so AIUI web search never worked
|
||||||
|
|
||||||
|
The operator asked whether "Web search via your private SearXNG instance" is true.
|
||||||
|
**It is true** — `/aiui/api/web-search` proxies to `127.0.0.1:8888/search`, the local
|
||||||
|
container, and nothing leaves via a third-party API. But SearXNG defaults to
|
||||||
|
`formats: [html]`, so its JSON API answered **403**, and JSON is the only thing AIUI
|
||||||
|
speaks. Both seed sites (`scripts/first-boot-containers.sh` and
|
||||||
|
`api/rpc/package/install.rs`) omitted `search.formats`.
|
||||||
|
|
||||||
|
**Measured after the fix, live:** 28 results for "bitcoin halving", from Brave (20)
|
||||||
|
and DuckDuckGo (8). Google self-suspends ("access denied") and Startpage hits a
|
||||||
|
CAPTCHA — normal for a self-hosted instance, and it costs little because Brave runs
|
||||||
|
its own independent index. **The result quality is fine; the 403 was the whole
|
||||||
|
problem.** No case for replacing SearXNG on this evidence.
|
||||||
|
|
||||||
|
**Existing nodes need manual repair** (the commit only fixes what new installs get):
|
||||||
|
add to `/var/lib/archipelago/searxng/settings.yml`
|
||||||
|
```yaml
|
||||||
|
search:
|
||||||
|
formats:
|
||||||
|
- html
|
||||||
|
- json
|
||||||
|
```
|
||||||
|
then restart the app. **archi-dev-box is already repaired.**
|
||||||
|
|
||||||
|
### `b1c5d138` — the prose surface was winning, and the web-search path was wrong
|
||||||
|
|
||||||
|
- `setArchyContent` put the node's grids on the tab bar, then `updatePanelFromText`
|
||||||
|
**replaced** the bar with tabs inferred from the reply text. "show me my own shared
|
||||||
|
content" landed on an **"AI Brief"** — a prose restatement of the answer already on
|
||||||
|
the left — with the populated image grid no longer reachable. Guarding the `panel*`
|
||||||
|
arrays was not enough: they held the right data while the tab bar had discarded the
|
||||||
|
way to see it. Archy tabs now lead and the title follows the leading tab.
|
||||||
|
- Archy tabs are ordered by **bucket size**. A node with 13 photos and 2 tracks opened
|
||||||
|
on Songs and titled itself "2 Songs" for a 15-item answer.
|
||||||
|
- `searchWeb` hardcoded `/api/web-search` while every other call is built from
|
||||||
|
`BASE_URL`. Under `/aiui/` it asked the HOST for a path only the AIUI-scoped nginx
|
||||||
|
location serves → 403 from the node's API gate, plus a CSP refusal.
|
||||||
|
- The embedded path now skips client-side web search entirely: `streamViaArchy` sends
|
||||||
|
only the user's text, so the system prompt those results were folded into is never
|
||||||
|
transmitted. It was a round trip and a console error per turn whose output provably
|
||||||
|
reached no model. **Web search for the embedded path belongs node-side, next to the
|
||||||
|
other tools** — that is task #10's "web search through node chat" note.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The peer-files correction — READ THIS
|
||||||
|
|
||||||
|
The previous session concluded: *"Your 16 federated peers are not serving content…
|
||||||
|
peers_reached: 0 is correct. No AIUI work will make peer films appear until those
|
||||||
|
peers answer. This is a fleet problem, not a UI one."*
|
||||||
|
|
||||||
|
**That was wrong, and the operator said so.** Measured live on archi-dev-box:
|
||||||
|
|
||||||
|
- A direct `content.browse-all-peers` RPC returned **real peer items** (a peer's
|
||||||
|
`Music/Architects of Tomorrow.mp3`) on one call and **0 reached / 16 unreachable**
|
||||||
|
on the very next — the discard-on-timeout bug in defect 2 above.
|
||||||
|
- Through the assistant after the fixes: **4 of 16 peers reached, 7 items from 2
|
||||||
|
peers**, including paid tracks at 10,000 sats.
|
||||||
|
|
||||||
|
The peers were serving content the whole time. Two code bugs (a missing dispatch arm
|
||||||
|
and a timeout that threw away completed work) produced a number that looked exactly
|
||||||
|
like a fleet outage. **Do not re-diagnose this as infrastructure.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Browser verification — how it was done, and how to repeat it
|
||||||
|
|
||||||
|
This box **is** archi-dev-box (`hostname` confirms; LAN `192.168.63.240`, Tailscale
|
||||||
|
`100.69.68.39`). Everything can be tested locally.
|
||||||
|
|
||||||
|
**Authenticated RPC from the shell** —
|
||||||
|
`/tmp/claude-1000/.../scratchpad/rpc.mjs` (regenerate if the scratchpad is gone):
|
||||||
|
POST `https://192.168.63.240/rpc/v1`, `auth.login` with `{"password":"ThisIsWeb54321@"}`,
|
||||||
|
carry the `session` + `csrf_token` cookies and send `X-CSRF-Token`.
|
||||||
|
**The API is NOT on 7777 or 8101** — go through nginx on 443.
|
||||||
|
|
||||||
|
**Playwright driver** — `neode-ui/shot.tmp.mjs` (uncommitted, run it from
|
||||||
|
`neode-ui/`, which is where `playwright` is installed; the aiui package has it only
|
||||||
|
under pnpm's store). It logs in, opens `/dashboard/chat`, dismisses the Remote
|
||||||
|
Companion modal (**Escape first — its button uses a curly apostrophe, so
|
||||||
|
`has-text("I've installed it")` never matches**), finds the `/aiui/` frame, types
|
||||||
|
into the real composer, and screenshots. It also installs an `addInitScript` probe
|
||||||
|
that logs every `chat:response` with its surface bucket counts — that probe is what
|
||||||
|
proved the pipeline end to end.
|
||||||
|
|
||||||
|
**Latest verified run:**
|
||||||
|
```
|
||||||
|
heading before: "16 Images"
|
||||||
|
heading during turn: "Loading…"
|
||||||
|
heading after: "13 Images"
|
||||||
|
[PROBE] chat:response success=true surfaces=1
|
||||||
|
detail=[{"tool":"content_list","scope":"own","films":0,"songs":2,"images":13}]
|
||||||
|
```
|
||||||
|
Screenshots in the scratchpad: `13-answered.png` shows prose on the left and a
|
||||||
|
populated Songs/Images grid on the right — the thing that was empty before.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Binary drift — DO THIS BEFORE THE ISO
|
||||||
|
|
||||||
|
`core/target/release/archipelago` was built BEFORE the `install.rs` SearXNG change,
|
||||||
|
and the currently deployed `/usr/local/bin/archipelago` is that same binary. It has
|
||||||
|
all the surface/peer fixes (verified live) but **not** the SearXNG seed fix.
|
||||||
|
|
||||||
|
```
|
||||||
|
cd core && CARGO_INCREMENTAL=0 cargo build --release -p archipelago # ~9 min
|
||||||
|
```
|
||||||
|
Confirm it took: `strings core/target/release/archipelago | grep -A2 "limiter: false"`
|
||||||
|
should now show the `formats` lines. Then deploy per the loop below and cut the ISO.
|
||||||
|
|
||||||
|
## Deploy loop (archi-dev-box = this box)
|
||||||
|
|
||||||
|
```
|
||||||
|
# frontend
|
||||||
|
cd neode-ui && npm run build
|
||||||
|
sudo rsync -a --exclude 'aiui/' --exclude 'archipelago-runtime/' \
|
||||||
|
web/dist/neode-ui/ /opt/archipelago/web-ui/
|
||||||
|
# AIUI (build-aiui.sh HANGS after succeeding — wrap in `timeout 540 ... || true`
|
||||||
|
# and check dist/index.html's mtime; the dist is complete)
|
||||||
|
bash scripts/build-aiui.sh
|
||||||
|
sudo rsync -a --delete aiui/packages/app/dist/ /opt/archipelago/web-ui/aiui/
|
||||||
|
# binary
|
||||||
|
sudo cp -f /usr/local/bin/archipelago /opt/archipelago/rollback/archipelago.bak
|
||||||
|
sudo install -m 755 core/target/release/archipelago /usr/local/bin/archipelago
|
||||||
|
sudo systemctl restart archipelago
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test state
|
||||||
|
|
||||||
|
- **Rust:** `cargo test --bin archipelago assistant::` → **122 passed, 0 failed.**
|
||||||
|
(`-p archipelago --lib` fails with "no library targets" — it is a bin crate.)
|
||||||
|
- **neode-ui:** adapter + broker + views → **71 passed, 0 failed.** I also fixed a
|
||||||
|
**pre-existing** failure in `toolConfirm.test.ts` (it asserted `rpcClient.call` was
|
||||||
|
never called, but `ContextBroker.start()` hydrates AI permissions over RPC; narrowed
|
||||||
|
to "no `assistant.*` call", which is the property actually under test).
|
||||||
|
- **AIUI:** **348 passed, 3 failed — all three PRE-EXISTING**, confirmed by stashing
|
||||||
|
my changes and re-running. They are `seed-conversations.test.ts` (seed-songs content
|
||||||
|
types), `seedExtraction.test.ts` (extracts 10 songs), and `useAI.test.ts`
|
||||||
|
(`webSearch` flag in the request body — this one may now be *related* to the
|
||||||
|
embedded-mode gate; re-check it, it was failing before but for a different reason).
|
||||||
|
|
||||||
|
## Traps — do not repeat
|
||||||
|
|
||||||
|
- **I removed a running container** by running `podman restart searxng` directly. The
|
||||||
|
orchestrator owns lifecycle: it saw "stopping" and the container vanished. Recover
|
||||||
|
with the RPC `container-start` and params **`{"app_id": "..."}`** (not `{"name":...}`).
|
||||||
|
Do not drive podman by hand for app containers.
|
||||||
|
- `es.json` reformatted wholesale when edited with `json.dump` (470-line diff). Insert
|
||||||
|
keys textually, preserving the file's own formatting.
|
||||||
|
- Verify on the NODE, not from source (nginx template vs `/etc/nginx/sites-enabled/`).
|
||||||
|
- rustls does NOT check key/cert pairing — the check in `appgate/tls.rs` is load-bearing.
|
||||||
|
- AIUI must build with `VITE_BASE_PATH=/aiui/` or you get a black page.
|
||||||
|
- Never `rm -rf /opt/archipelago/web-ui/*` — it destroys `aiui/`.
|
||||||
|
- Restarting `archipelago` does NOT kill app containers (they live in `/user.slice`).
|
||||||
|
- Release build is ~9 min. Budget for it.
|
||||||
|
|
||||||
|
## Phase 13 GSD
|
||||||
|
|
||||||
|
14/15. **13-15 only** (device-close, blocking human-verify). Operator verified checks
|
||||||
|
1, 3 and 4. **Check 2 was the holdout — "no film content exists on this node to
|
||||||
|
display".** That premise should be re-tested now: peer content demonstrably reaches
|
||||||
|
the surface, and the images bucket means the node's own catalogue renders too. Then
|
||||||
|
write `13-UAT.md`, fill `13-VALIDATION.md`, close.
|
||||||
Reference in New Issue
Block a user