From 6efe42d3ae64f2417388ab57429548f8f74c97fb Mon Sep 17 00:00:00 2001 From: archipelago Date: Mon, 3 Aug 2026 14:52:02 -0400 Subject: [PATCH] =?UTF-8?q?docs(13-01):=20complete=20AIUI=20tracer-slice?= =?UTF-8?q?=20plan=20=E2=80=94=20SUMMARY=20+=20defect=20ledger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the continuation ground-truth review of WIP checkpoint 6ba52b22, the atomic per-task re-commit (fe6ccff7 Rust spine, 0ab9bdc7 neode-ui broker), and the external-repo Task 3 commit (AIUI e30ac1d, not yet pushed). Logs two open WINDOWS.md items: the cargo test run that never completed under machine resource contention (id 16), and the AIUI push blocked by an unreachable git.tx1138.com (id 17). Co-Authored-By: Claude Opus 5 (1M context) --- .planning/WINDOWS.md | 32 ++- .../13-01-SUMMARY.md | 267 ++++++++++++++++++ 2 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 .planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-01-SUMMARY.md diff --git a/.planning/WINDOWS.md b/.planning/WINDOWS.md index 553df6af..4638f5e1 100644 --- a/.planning/WINDOWS.md +++ b/.planning/WINDOWS.md @@ -1,10 +1,10 @@ --- schema_version: 1 -open_count: 11 +open_count: 13 waived_count: 0 fixed_count: 4 -total_count: 15 -last_updated: 2026-08-03T00:06:03.112Z +total_count: 17 +last_updated: 2026-08-03T18:50:07.659Z --- # Broken Windows Ledger @@ -30,6 +30,8 @@ last_updated: 2026-08-03T00:06:03.112Z | 13 | 10 | unrun-verify | core/archipelago/src/api/rpc/system/handlers.rs | | system.stats host_secrets never observed on a real node — proven against the file contract in unit tests only. Needs a build carrying 10-04 deployed to the dev pair, then a system.stats call. | fixed | | 2026-08-02T19:07:40.522Z | 2026-08-02T23:00:30.894Z | | 14 | 10 | unrun-verify | core/archipelago/src/container/prod_orchestrator.rs | | LIVE EXPOSURE on archi-dev-box: archy-bitcoin-ui (systemd/Quadlet-owned, user-uninstalled marker set) still serves unauthenticated POST /bitcoin-rpc/ on 0.0.0.0:8334 with Access-Control-Allow-Origin *, reaching Bitcoin Core RPC through a credential-injecting proxy. Verified live 2026-08-02 (returned a real block height with no cookies). Code fix committed f6b5245b but NOT deployed: closing it needs the new binary on the node plus an archy-bitcoin-ui restart. archy-electrs-ui is in the same uninstalled-but-running state (static UI only, no credential proxy). Operator-gated; no node touched. | fixed | | 2026-08-02T22:44:15.215Z | 2026-08-02T23:16:04.071Z | | 15 | 10 | unrun-verify | core/archipelago/src/container/prod_orchestrator.rs | | The f6b5245b reconcile fix is DEPLOYED on archi-dev-box (binary installed 19:06, running) but NEVER EXERCISED on hardware: the state it repairs (uninstall marker + Quadlet-running + stale config) stopped existing here at 18:36, when a separate rebuild of bitcoin-ui rendered the fixed conf and restarted the container. So :8334 returning 401 proves a05956c4's template, NOT the reconcile path that is supposed to deliver it. archy-electrs-ui still carries the marker+running shape and could exercise it, but has no rendered config to rewrite. Needs a node that still has a stale bitcoin-ui conf, or a deliberately re-staled one. | fixed | | 2026-08-02T23:16:04.510Z | 2026-08-03T00:06:03.112Z | +| 16 | 13 | unrun-verify | core/archipelago/src/assistant/loop_.rs | | cargo test --package archipelago assistant:: (disk_status_tool_executes, unknown_tool_is_refused_not_ignored, assistant_methods_require_session) never completed this session — killed twice under machine resource contention (load avg 35-46 on 4 cores, sibling worktree builds). cargo build --package archipelago DID complete clean (exit 0, only expected dead-code warnings). Test logic was read and reasoned correct but not independently executed — needs a follow-up cargo test run when the machine is free. | open | | 2026-08-03T18:49:48.842Z | | +| 17 | 13 | deviation | external:AIUI/packages/app/src/services/archyBridge.ts | | Task 3 (sendChat/streamViaArchy, external repo /home/archipelago/Projects/AIUI, branch development, commit e30ac1d) is committed locally but NOT pushed to git.tx1138.com — origin was unreachable this session (DNS resolves to 80.71.235.99 but TCP/TLS connect and even 'git ls-remote' timed out repeatedly, sandbox-disabled too). Needs a push from an environment with network access to git.tx1138.com before the fix lands upstream. | open | | 2026-08-03T18:50:07.659Z | | ````json [ @@ -212,6 +214,30 @@ last_updated: 2026-08-03T00:06:03.112Z "reason": "", "recorded_at": "2026-08-02T23:16:04.510Z", "resolved_at": "2026-08-03T00:06:03.112Z" + }, + { + "id": 16, + "kind": "unrun-verify", + "phase": "13", + "file": "core/archipelago/src/assistant/loop_.rs", + "line": null, + "description": "cargo test --package archipelago assistant:: (disk_status_tool_executes, unknown_tool_is_refused_not_ignored, assistant_methods_require_session) never completed this session — killed twice under machine resource contention (load avg 35-46 on 4 cores, sibling worktree builds). cargo build --package archipelago DID complete clean (exit 0, only expected dead-code warnings). Test logic was read and reasoned correct but not independently executed — needs a follow-up cargo test run when the machine is free.", + "status": "open", + "reason": "", + "recorded_at": "2026-08-03T18:49:48.842Z", + "resolved_at": null + }, + { + "id": 17, + "kind": "deviation", + "phase": "13", + "file": "external:AIUI/packages/app/src/services/archyBridge.ts", + "line": null, + "description": "Task 3 (sendChat/streamViaArchy, external repo /home/archipelago/Projects/AIUI, branch development, commit e30ac1d) is committed locally but NOT pushed to git.tx1138.com — origin was unreachable this session (DNS resolves to 80.71.235.99 but TCP/TLS connect and even 'git ls-remote' timed out repeatedly, sandbox-disabled too). Needs a push from an environment with network access to git.tx1138.com before the fix lands upstream.", + "status": "open", + "reason": "", + "recorded_at": "2026-08-03T18:50:07.659Z", + "resolved_at": null } ] ```` diff --git a/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-01-SUMMARY.md b/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-01-SUMMARY.md new file mode 100644 index 00000000..82ad1093 --- /dev/null +++ b/.planning/phases/13-aiui-functional-conversational-node-control-and-content-surf/13-01-SUMMARY.md @@ -0,0 +1,267 @@ +--- +phase: 13-aiui-functional-conversational-node-control-and-content-surf +plan: 01 +subsystem: ai +tags: [rust, tokio, anthropic-claude, tool-calling, postmessage, vue, aiui, rpc] + +requires: + - phase: 10-key-material-hardening + provides: "data_dir/secrets/claude-api-key convention, session-cookie + CSRF + role.can_access() RPC gate" +provides: + - "crate::assistant module: CallerScope, PermissionCategory, ToolExecCtx, chat() entry point" + - "Curated tool registry (tools.rs) with one tool, system_disk_status, hand-written JSON Schema" + - "run_loop / execute_tool tool-calling loop (loop_.rs) — the single choke point every tool call passes through" + - "Backend trait + BackendTurn seam (backends/mod.rs) with a real ClaudeBackend and a #[cfg(test)] ScriptedBackend" + - "assistant.* RPC prefix sub-dispatcher (api/rpc/assistant_chat.rs), registered as one guarded dispatcher.rs arm" + - "chat:request / chat:response postMessage transport in neode-ui's contextBroker + aiui-protocol" + - "AIUI embedded-mode delegation: archyBridge.sendChat + useAI.ts's streamViaArchy (external repo, committed not pushed)" +affects: [13-05, 13-08, 13-09, 13-10, 13-13, 13-14] + +tech-stack: + added: [] + patterns: + - "D-02 caller-scope authority model: CallerScope::granted_categories() is the sole source of tool authority; execute_tool never reads a caller-specific field directly" + - "D-06 curated tool registry: hand-written ToolDef list, never derived from the RPC dispatcher's method table" + - "Tool execution bridges back into api::rpc via a thin pub(crate) fn (assistant_dispatch_tool) so the SAME RpcHandler method every authenticated caller uses runs the tool — never a parallel AI-only path" + +key-files: + created: + - core/archipelago/src/assistant/mod.rs + - core/archipelago/src/assistant/tools.rs + - core/archipelago/src/assistant/loop_.rs + - core/archipelago/src/assistant/backends/mod.rs + - core/archipelago/src/assistant/backends/claude.rs + - core/archipelago/src/assistant/backends/scripted.rs + - core/archipelago/src/api/rpc/assistant_chat.rs + modified: + - core/archipelago/src/api/rpc/dispatcher.rs + - core/archipelago/src/api/rpc/middleware.rs + - core/archipelago/src/api/rpc/mod.rs + - core/archipelago/src/main.rs + - neode-ui/src/services/contextBroker.ts + - neode-ui/src/types/aiui-protocol.ts + - "/home/archipelago/Projects/AIUI/packages/app/src/services/archyBridge.ts (external repo)" + - "/home/archipelago/Projects/AIUI/packages/app/src/composables/useAI.ts (external repo)" + +key-decisions: + - "Chose continuation option (a): git reset --soft HEAD~1 on the inherited WIP checkpoint (6ba52b22), then re-committed atomically — one commit for the Rust spine (Task 1), one for the neode-ui broker (Task 2) — after verifying every file against the plan's must_haves and acceptance criteria" + - "UNAUTHENTICATED_METHODS visibility widened pub(super) -> pub(crate) so assistant_methods_require_session can assert directly against the live list; contents of the list are untouched (verified by diff, not just grep)" + - "assistant_dispatch_tool + data_dir() added as thin pub(crate) bridges on RpcHandler because handle_system_disk_status is pub(in crate::api::rpc) and crate::assistant lives outside that module tree — Rust privacy, not a new capability surface" + +requirements-completed: [AIUI-01] + +coverage: + - id: D1 + description: "Rust assistant spine (CallerScope, curated tool registry, run_loop/execute_tool choke point, Claude backend) compiles clean and wires into the existing session/CSRF/RBAC-gated RPC dispatcher via a single assistant.* arm" + requirement: AIUI-01 + verification: + - kind: unit + ref: "cargo build --package archipelago (full workspace build, exit 0, only pre-existing/expected dead-code warnings)" + status: pass + - kind: unit + ref: "cargo test --package archipelago assistant:: (disk_status_tool_executes, unknown_tool_is_refused_not_ignored, assistant_methods_require_session)" + status: unknown + human_judgment: true + rationale: "cargo test never completed this session — killed twice under machine resource contention (load avg 35-46 on a 4-core box with concurrent sibling-worktree builds), and the orchestrator subsequently throttled all cargo invocations in this worktree. The code was read function-by-function against the plan's must_haves and reasoned correct, and `cargo build` (not `test`) did complete clean, but the three named unit tests were never independently executed. Logged to WINDOWS.md (id 16) as an open unrun-verify; needs a follow-up `cargo test --package archipelago assistant::` when the machine is free." + - id: D2 + description: "neode-ui carries a chat turn over the existing origin-checked postMessage bridge to assistant.chat and back, without widening AIActionType or relaxing the origin guard" + requirement: AIUI-01 + verification: + - kind: unit + ref: "neode-ui/src/services/__tests__/contextBroker.test.ts (16/16 passing)" + status: pass + - kind: unit + ref: "neode-ui/src/views/__tests__/chatAiuiEmbed.test.ts (7/7 passing)" + status: pass + - kind: other + ref: "npx vue-tsc --noEmit (neode-ui) — exit 0" + status: pass + human_judgment: false + - id: D3 + description: "AIUI delegates chat to Archy's node-side assistant loop when embedded (archyBridge.sendChat, useAI.ts's streamViaArchy), while standalone mode keeps streamClaude/streamOpenRouter unchanged (D-17)" + requirement: AIUI-01 + verification: + - kind: unit + ref: "AIUI packages/app: npx vitest run — 332/335 passing; the 3 failures (seed-conversations.test.ts, seedExtraction.test.ts, useAI.test.ts web-search-integration) were confirmed pre-existing on HEAD before this change via a scratch git-worktree diff, unrelated to sendChat/streamViaArchy" + status: pass + - kind: other + ref: "AIUI packages/app: npx vue-tsc --noEmit — exit 0" + status: pass + human_judgment: true + rationale: "The commit (e30ac1d, branch development) is local-only — git.tx1138.com was unreachable from this session (DNS resolved but TCP/TLS connect and `git ls-remote` both timed out repeatedly, sandbox-disabled too). Nothing is lost (it's a normal commit in a real clone), but a human/later session needs to push it before it reaches anyone else's checkout. Logged to WINDOWS.md (id 17)." + +duration: ~1h50m (this continuation session; the original session that produced the bulk of this diff died on a broken pipe before this session started) +completed: 2026-08-03 +status: complete +--- + +# Phase 13 Plan 01: AIUI Tracer Slice — Chat-to-Tool-to-RPC Spine Summary + +**A typed "how much space is left" question in embedded AIUI reaches a curated Rust tool-calling loop over the authenticated RPC session, executes `system.disk-status` through the same handler every caller uses, and returns a real Claude-composed answer — model key stays node-side, `assistant.*` stays authenticated.** + +## Performance + +- **Duration:** ~1h50m (this continuation session only) +- **Started:** 2026-08-03T17:00:00Z (approx, this continuation) +- **Completed:** 2026-08-03T18:50:23Z +- **Tasks:** 3/3 completed +- **Files modified:** 15 (9 Rust, 2 neode-ui TS, 2 AIUI external-repo TS, 2 planning ledger updates) + +## Continuation Context + +This plan was interrupted mid-execution by a broken pipe in a prior session. The orchestrator +committed that session's uncommitted work verbatim as a WIP checkpoint (`6ba52b22`) so it could +not be lost, and spawned this continuation agent to establish ground truth on it rather than +trust or discard it. + +**Ground truth established:** every file in the WIP commit was read in full and checked against +the plan's `must_haves.artifacts` (`contains:` symbols), the acceptance-criteria greps, and the +threat-model dispositions. The Rust spine (`mod.rs`, `tools.rs`, `loop_.rs`, `backends/*`, +`assistant_chat.rs`, the `dispatcher.rs`/`middleware.rs`/`mod.rs`/`main.rs` edits) and the +neode-ui broker changes (`contextBroker.ts`, `aiui-protocol.ts`) matched the plan's design +faithfully — correct Anthropic Messages API shape, correct D-06 curated-registry discipline, +correct D-02 caller-scope authority resolution, `UNAUTHENTICATED_METHODS` genuinely untouched +(diffed, not just grepped), single dispatcher arm, no `schemars`, no second key location, no +mesh-timeout-constant reuse. `cargo build --package archipelago` was run to completion and +exited 0 with only expected dead-code warnings (unused `PermissionCategory`/`CallerScope`/`Role` +variants not yet exercised by this tracer) — confirming the WIP genuinely compiles. + +**Chosen path: option (a).** `git reset --soft HEAD~1` on the WIP checkpoint, then re-committed +atomically — one commit per completed plan task — after fixing one small acceptance-criteria +issue found during review (see Deviations). + +**Bonus discovery:** Task 3's AIUI-repo changes (`archyBridge.sendChat`, `useAI.ts`'s +`streamViaArchy`) were *also* already present, uncommitted, in `/home/archipelago/Projects/AIUI` +— that repo is outside this worktree's git history, so the broken pipe never touched it. Ground- +truthed the same way (full read against the plan's Task 3 spec), verified against a fresh +scratch `git worktree` at the AIUI repo's prior HEAD to confirm the 3 vitest failures pre-existed +the change, then committed it. + +## Accomplishments +- Rust `assistant` module: `CallerScope` (Mesh/LocalOperator), `PermissionCategory` (D-16's ten + categories), `ToolExecCtx`, `chat()` entry point — the D-02 shared-service root +- Curated D-06 tool registry with exactly one tool (`system_disk_status`), hand-written JSON + Schema (no `schemars`), with a round-trip test proving the schema and the args struct cannot + silently drift apart +- `run_loop`/`execute_tool` — the single choke point enforcing curated-allowlist refusal, + category-grant re-checking, schema validation, and the (not-yet-reachable) destructive-tool gate +- `Backend` trait + a real `ClaudeBackend` (Anthropic Messages API, tool_use/tool_result, new + `ASSISTANT_HTTP_TIMEOUT`/`ASSISTANT_MAX_TOKENS` constants — no mesh-timeout reuse) + a + `#[cfg(test)]`-only `ScriptedBackend` +- `assistant.*` RPC surface: one guarded `dispatcher.rs` arm, reached only after the existing + session/CSRF/RBAC gate, dispatching into `assistant_chat.rs`'s own sub-match +- neode-ui `chat:request`/`chat:response` postMessage transport over the existing + origin-checked bridge, with no new permission gate duplicated browser-side +- AIUI embedded-mode delegation (external repo, committed locally, push pending network access) + +## Task Commits + +Each task was committed atomically: + +1. **Task 1: End-to-end "how much space is left" — the Rust spine, one tool, one backend** - + `fe6ccff7` (feat) +2. **Task 2: neode-ui carries chat over the existing origin-checked bridge** - `0ab9bdc7` (feat) +3. **Task 3: AIUI delegates the loop to the node when embedded, keeps its own when not** - + `e30ac1d` (feat, **in the external `/home/archipelago/Projects/AIUI` repo, branch + `development` — NOT part of this worktree's git history and NOT yet pushed**) + +**Plan metadata:** this commit (docs: complete plan) — pending, see below. + +## Files Created/Modified + +- `core/archipelago/src/assistant/mod.rs` - `CallerScope`, `PermissionCategory`, `ToolExecCtx`, `chat()` +- `core/archipelago/src/assistant/tools.rs` - `ToolDef`, `ToolRegistry`, `system_disk_status_tool`, schema round-trip test +- `core/archipelago/src/assistant/loop_.rs` - `run_loop`, `execute_tool`, `MAX_TURNS`, the 3 unit tests +- `core/archipelago/src/assistant/backends/mod.rs` - `Backend` trait, `BackendTurn`, `select_backend` +- `core/archipelago/src/assistant/backends/claude.rs` - `ClaudeBackend` (Anthropic Messages API) +- `core/archipelago/src/assistant/backends/scripted.rs` - `ScriptedBackend` (`#[cfg(test)]` only) +- `core/archipelago/src/api/rpc/assistant_chat.rs` - `handle_assistant`, `handle_assistant_chat`, `assistant_dispatch_tool`, `data_dir()` +- `core/archipelago/src/api/rpc/dispatcher.rs` - one guarded `assistant.*` arm +- `core/archipelago/src/api/rpc/middleware.rs` - `UNAUTHENTICATED_METHODS` visibility widened to `pub(crate)` (contents unchanged) +- `core/archipelago/src/api/rpc/mod.rs` - re-export `UNAUTHENTICATED_METHODS`, `mod assistant_chat;` +- `core/archipelago/src/main.rs` - `mod assistant;` +- `neode-ui/src/types/aiui-protocol.ts` - `AIUIChatRequest`, `ArchyChatResponse` +- `neode-ui/src/services/contextBroker.ts` - `handleChatRequest` +- `/home/archipelago/Projects/AIUI/packages/app/src/services/archyBridge.ts` - `sendChat` (external repo) +- `/home/archipelago/Projects/AIUI/packages/app/src/composables/useAI.ts` - `streamViaArchy` (external repo) + +## Decisions Made + +- Reset-and-recommit (option a) rather than build-forward-from-WIP (option b): the plan asked me + to prefer (a) because it yields the clean per-task history the plan protocol expects, and + ground-truthing showed the WIP mapped cleanly onto exactly Task 1 + Task 2 with no partial or + wrong work to route around, so there was nothing (a) would have cost. +- Fixed one acceptance-criteria miss found during review before committing: a doc comment in + `backends/claude.rs` literally contained the string `OLLAMA_TIMEOUT` while explaining why it + is *not* reused — this tripped the acceptance criterion's grep even though the intent (don't + reuse the LoRa-tuned constant) was already honored. Reworded the comment to describe the same + thing without the literal identifier. No behavior change. +- Did not touch `.planning/STATE.md`, `.planning/ROADMAP.md`, or `.planning/REQUIREMENTS.md` — + per this session's explicit instruction, the orchestrator owns those writes after the wave + completes (and touching a shared cross-plan file from a parallel worktree risks merge + conflicts with sibling plans in this wave). + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 1 - Bug/acceptance-criteria] `OLLAMA_TIMEOUT` literal string tripped a negative grep it was meant to satisfy** +- **Found during:** Task 1 ground-truth review +- **Issue:** `backends/claude.rs`'s doc comment on `ASSISTANT_HTTP_TIMEOUT` explained the constant is "NOT `assist.rs`'s `OLLAMA_TIMEOUT`" — correct in intent, but the acceptance criterion `grep -rnE 'OLLAMA_TIMEOUT|MAX_REPLY_CHARS|CHUNK_CHARS' core/archipelago/src/assistant/` returns no match` is a literal grep and doesn't distinguish "reused" from "mentioned in a comment explaining non-reuse." +- **Fix:** Reworded the comment to convey the same non-reuse rationale without the literal constant name. +- **Files modified:** `core/archipelago/src/assistant/backends/claude.rs` +- **Verification:** `grep -rnE 'OLLAMA_TIMEOUT|MAX_REPLY_CHARS|CHUNK_CHARS' core/archipelago/src/assistant/` now returns no match. +- **Committed in:** `fe6ccff7` (the edit was made before the atomic re-commit, so it landed inside Task 1's commit directly rather than as a separate follow-up) + +--- + +**Total deviations:** 1 auto-fixed (Rule 1, cosmetic/acceptance-criteria only, no behavior change). +**Impact on plan:** None beyond the one comment edit. No scope creep. + +## Issues Encountered + +- **Machine resource contention blocked full test verification.** This session ran alongside at + least one sibling worktree (`p13-02`) also compiling the same large Rust workspace, on a + 4-core box also running a live Archipelago node (bitcoind/electrumx/lnd). Load average peaked + around 46. `cargo build --package archipelago` completed once, cleanly (~22 min). A subsequent + `cargo test --package archipelago assistant::` was attempted twice and was killed both times — + once implicitly by the harness after an extremely long run, once explicitly by me under the + orchestrator's throttle instruction once it flagged the contention. **I did not independently + observe the three named unit tests pass.** I read `loop_.rs`'s test module function-by-function + against the plan's `` spec and believe it is correct, but "I read it and it looks + right" is not the same as "it ran green," and I am reporting that distinction honestly rather + than claiming a verification I did not perform. This is the single biggest open item from this + plan — see WINDOWS.md id 16. +- **git.tx1138.com unreachable for the AIUI push.** DNS resolved (`80.71.235.99`) but every + connection attempt (`curl`, `git ls-remote`, `git push`, with and without sandbox) timed out. + Task 3's commit is safe (a normal local commit in a real, persistent clone at + `/home/archipelago/Projects/AIUI`, branch `development`, commit `e30ac1d`) but not yet visible + to anyone else's checkout of that repo. See WINDOWS.md id 17. + +## User Setup Required + +None - no external service configuration required by this plan itself. (The Claude API key at +`data_dir/secrets/claude-api-key` is a Phase-10-era prerequisite this plan consumes, not one it +introduces.) + +## Next Phase Readiness + +The spine this phase exists to prove is in place and (per the compiled build + the neode-ui/AIUI +test suites) structurally sound: chat request → postMessage → authenticated RPC → curated tool → +real handler → Claude → real answer, with the model key never leaving the node and +`assistant.*` never reachable unauthenticated. + +**Before the next plan builds on this spine:** +1. Run `cargo test --package archipelago assistant::` on an unloaded machine and confirm + `disk_status_tool_executes`, `unknown_tool_is_refused_not_ignored`, and + `assistant_methods_require_session` all pass (WINDOWS.md id 16). +2. Push `/home/archipelago/Projects/AIUI`'s `development` branch (commit `e30ac1d`) to + `git.tx1138.com` once network access is available (WINDOWS.md id 17). +3. The plan's live end-to-end verification line (`assistant.chat` with + `{"text":"how much space is left"}` against a running node, session cookie + CSRF) was not + exercised — no running node was available in this session. Worth doing once 1 and 2 above are + clear. + +--- +*Phase: 13-aiui-functional-conversational-node-control-and-content-surf* +*Completed: 2026-08-03*