wip: phase 13 AIUI paused at 6/17 (operator demo list)
Handoff carries the peer-files correction, the podman-lifecycle trap, the concurrent-agent warning, and the release-binary drift that blocks 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
bca18c03d2
commit
c9de1e6c53
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"timestamp": "2026-08-07T10:02:11.548Z",
|
||||
"phase": "13",
|
||||
"phase_name": "aiui-functional-conversational-node-control-and-content-surf",
|
||||
"phase_dir": ".planning/phases/13-aiui-functional-conversational-node-control-and-content-surf",
|
||||
"plan": 15,
|
||||
"task": 6,
|
||||
"total_tasks": 17,
|
||||
"status": "paused",
|
||||
"note": "Task ids below are the OPERATOR's 17-item demo list (see .planning/RESUME-2026-08-07-aiui-surfaces.md), not 13-XX plan tasks. Phase 13's own GSD plans are 14/15 done with only 13-15 (device-close) open.",
|
||||
"completed_tasks": [
|
||||
{"id": 1, "name": "Unify AI Data Access toggles with assistant tool grants", "status": "done", "commit": "55155f2d"},
|
||||
{"id": 5, "name": "Cap content.browse-all-peers, rebuilt as Cloud's fan-out", "status": "done", "commit": "75919a20"},
|
||||
{"id": 12, "name": "Node certificate settings section container/layout", "status": "done", "commit": "75919a20"},
|
||||
{"id": 16, "name": "Populate the content surface for own shared content + rich chat previews", "status": "done", "commit": "9abc1623,b1c5d138", "evidence": "browser: chat:response surfaces=1 songs:2 images:13; heading '13 Images'"},
|
||||
{"id": 15, "name": "Content-surface stale title", "status": "done", "commit": "9abc1623", "evidence": "browser: 'Loading...' during turn, '13 Images' after", "caveat": "header-OVERLAP half never reproduced at 1600x950; check a narrow/mobile viewport"},
|
||||
{"id": 6, "name": "Settings link when a permission is ungranted", "status": "in_progress", "commit": "9abc1623", "progress": "node refused_categories + broker event + Teleported chrome banner all landed and typecheck clean; NEVER seen in a browser"},
|
||||
{"id": 9, "name": "Answer with content + context surfaces, not JUST prose", "status": "in_progress", "commit": "b1c5d138", "progress": "content turns verified in browser; system/network/bitcoin turns still prose-only because only content_list/apps_list are surface-producing"},
|
||||
{"id": 10, "name": "AIUI slow background image + console noise", "status": "in_progress", "commit": "b1c5d138", "progress": "web-search CSP spam and its 403 fixed; wavlake/itunes CSP block, 3x403, 2x402, 502, 404, sw.js SSL all still present; slow background image not investigated"}
|
||||
],
|
||||
"remaining_tasks": [
|
||||
{"id": 2, "name": "Verify AI grants persist across refresh through the real UI path", "status": "not_started"},
|
||||
{"id": 3, "name": "Add app_install / app_uninstall tools behind the confirm gate", "status": "not_started"},
|
||||
{"id": 4, "name": "!archy / !ai over mesh must action commands with text responses", "status": "not_started"},
|
||||
{"id": 7, "name": "App lifecycle defects (fedimint guardian, BTCPay wipe-reinstall, disappearing apps, chown postgres-btcpay)", "status": "not_started"},
|
||||
{"id": 8, "name": "LND UI + filebrowser 401s (session passthrough on node-owned *-ui apps)", "status": "not_started", "hint": "the 3x403 still in the AIUI console may be this same family"},
|
||||
{"id": 11, "name": "Cmd/Ctrl+K carries the query into the expanded chat", "status": "not_started", "hint": "whole path read and appears correctly wired incl. cold-frame buffer; REPRODUCE IN A BROWSER before editing code"},
|
||||
{"id": 13, "name": "Serve HTTPS dynamically on EVERY address alongside Tailscale", "status": "not_started"},
|
||||
{"id": 14, "name": "Nostr signer + service worker over HTTPS", "status": "not_started"},
|
||||
{"id": 17, "name": "Cut a clean ISO for the demo (UNBUNDLED=1)", "status": "blocked", "blocked_by": "release binary predates the install.rs SearXNG seed fix"}
|
||||
],
|
||||
"blockers": [
|
||||
{"description": "core/target/release/archipelago and the deployed /usr/local/bin/archipelago were both built BEFORE the install.rs SearXNG seed fix (c810b514). They carry every surface/peer fix (verified live) but not the SearXNG one.", "type": "technical", "workaround": "cd core && CARGO_INCREMENTAL=0 cargo build --release -p archipelago (~9 min), verify with: strings core/target/release/archipelago | grep -A2 'limiter: false' should show the formats lines, then redeploy. MUST clear before task 17 (ISO)."},
|
||||
{"description": "Existing fleet nodes still have SearXNG JSON disabled — c810b514 only fixes what NEW installs get. Every existing node's AIUI web search returns 403.", "type": "external", "workaround": "Add search.formats [html, json] to /var/lib/archipelago/searxng/settings.yml on each node and restart the app. archi-dev-box is already repaired."},
|
||||
{"description": "A concurrent agent is committing to the same branch (1eb75a1e, a7368b8b, 9cf1c122 — a full AIUI security/mission assessment with 6 HIGH/MED findings S1-S6). Stage by path only; never git add -A.", "type": "external", "workaround": "Read .planning/phases/13-.../ASSESSMENT-FIX-PLAN-2026-08-07.md before the next wave; its findings partly overlap tasks 8 and 10."}
|
||||
],
|
||||
"async_jobs": [],
|
||||
"human_actions_pending": [
|
||||
{"action": "Operator device-close for 13-15 check 2 (film content displayed on the surface)", "context": "The old holdout reason was 'no film content exists on this node'. That premise is now stale: peer content demonstrably reaches the surface and the images bucket renders the node's own catalogue. Re-test before asking again.", "blocking": true},
|
||||
{"action": "Decide whether system/network/bitcoin turns deserve context surfaces (task 9 remainder)", "context": "Only content_list and apps_list are surface-producing tools today.", "blocking": false}
|
||||
],
|
||||
"decisions": [
|
||||
{"decision": "Capture surfaces RAW in loop_::execute_tool's Ok(v) arm, BEFORE wrap_tool_result_if_untrusted", "rationale": "The untrusted boundary exists to stop peer-authored text being read as instructions by the MODEL. This copy goes to a renderer that treats every field as inert data and never re-enters the prompt; wrapping it would leave the UI parsing delimiter noise instead of JSON.", "phase": "13"},
|
||||
{"decision": "Gate chat surfaces on media/files in the broker as well as node-side", "rationale": "Mirrors handleContentRequest — this channel carries node data into the iframe, so it is a consent surface and is checked in the host rather than trusting the node's grant check to be the only one. Dropping surfaces never drops the prose answer.", "phase": "13"},
|
||||
{"decision": "Archy tabs outrank regex-inferred tabs, ordered by bucket size", "rationale": "setArchyContent put the node grids up and updatePanelFromText then replaced the bar, landing on an AI Brief with the real grid unreachable. Size ordering because a 13-photo/2-track answer opened on Songs and titled itself '2 Songs'.", "phase": "13"},
|
||||
{"decision": "Skip client-side web search entirely when embedded in Archy", "rationale": "streamViaArchy sends only the user's text, so the system prompt those results were folded into is never transmitted. It cost a round trip and a CSP console error per turn while its output provably reached no model. Web search for the embedded path belongs node-side with the other tools.", "phase": "13"},
|
||||
{"decision": "Keep SearXNG rather than replace it", "rationale": "Operator suspected poor results. Measured live after the JSON fix: 28 results for 'bitcoin halving' from Brave (20) + DuckDuckGo (8). Google self-suspends and Startpage CAPTCHAs, normal for self-hosted and cheap given Brave's independent index. The 403 was the whole problem.", "phase": "13"},
|
||||
{"decision": "browse-all-peers accumulates per batch with a between-batch deadline, no outer timeout", "rationale": "Every future is already bounded by PER_PEER_TIMEOUT, so an outer timeout can only discard completed work — which is the exact bug being fixed.", "phase": "13"}
|
||||
],
|
||||
"uncommitted_files": ["neode-ui/shot.tmp.mjs (untracked Playwright driver — deliberately not committed; recreate from the recipe in the resume doc if deleted)"],
|
||||
"next_action": "Rebuild the release binary (CARGO_INCREMENTAL=0 cargo build --release -p archipelago) to clear the ISO blocker, and while it builds verify task 6's permission banner in a browser by revoking the media grant and asking for content.",
|
||||
"context_notes": "This box IS archi-dev-box, so everything is testable locally. The session's method was: read code, form a hypothesis, then PROVE it against the live node before changing anything — that is what overturned the previous session's 'peers have no content' conclusion (the operator flagged it as wrong, and they were right: two code bugs produced a number that looked like a fleet outage). Authenticated RPC goes through nginx on 443, NOT ports 7777/8101. The Playwright driver at neode-ui/shot.tmp.mjs installs an addInitScript probe that logs every chat:response with its bucket counts — that probe is what proved the surface pipeline end to end, and it is the fastest way to re-verify after any change."
|
||||
}
|
||||
+213
@@ -0,0 +1,213 @@
|
||||
---
|
||||
context: phase
|
||||
phase: 13-aiui-functional-conversational-node-control-and-content-surf
|
||||
task: 6
|
||||
total_tasks: 17
|
||||
status: in_progress
|
||||
last_updated: 2026-08-07T10:02:11.548Z
|
||||
---
|
||||
|
||||
# BLOCKING CONSTRAINTS — Read Before Anything Else
|
||||
|
||||
> These are not suggestions. Each constraint below was discovered through failure
|
||||
> in this session. Acknowledge each one explicitly before proceeding.
|
||||
|
||||
- [ ] CONSTRAINT: **Do not re-diagnose peer content as a fleet problem.** The previous
|
||||
session concluded "the 16 federated peers are not serving content, this is a fleet
|
||||
problem, not a UI one." The operator said that was completely wrong, and it was.
|
||||
Two code bugs produced a number identical to a fleet outage. Live proof after the
|
||||
fix: 4 of 16 peers reached, 7 items from 2 peers, through the assistant.
|
||||
**Mitigation: before attributing any empty result to infrastructure, call the RPC
|
||||
directly twice and compare. Flapping between "real items" and "0 reached" is a
|
||||
code bug, not a network.**
|
||||
- [ ] CONSTRAINT: **Never drive podman directly for app containers.** I ran
|
||||
`podman restart searxng` and the orchestrator, which owns lifecycle, saw
|
||||
"stopping" and the container vanished from the node.
|
||||
**Mitigation: use the RPC `container-start` / `container-stop` / `container-restart`
|
||||
with params `{"app_id": "<id>"}` — note `app_id`, not `name`.**
|
||||
- [ ] CONSTRAINT: **A concurrent agent is committing to this same branch.**
|
||||
`1eb75a1e`, `a7368b8b`, `9cf1c122` are not mine.
|
||||
**Mitigation: stage explicitly by path (`git add <paths>`). Never `git add -A` or
|
||||
`git commit -a`.**
|
||||
|
||||
**Do not proceed until all boxes are checked.**
|
||||
|
||||
## Critical Anti-Patterns
|
||||
|
||||
| Pattern | Description | Severity | Prevention Mechanism |
|
||||
|---------|-------------|----------|---------------------|
|
||||
| Infrastructure-blaming a code bug | `content.browse-all-peers` wrapped its whole fan-out in `timeout(...).unwrap_or_default()`, discarding every COMPLETED batch on expiry. One slow peer turned a partial success into `0 reached / 16 unreachable`, which reads exactly like "the peers are down". | blocking | Call the RPC twice and compare before blaming the network. A result that flaps between real data and zero is code. |
|
||||
| Direct podman control of app containers | `podman restart searxng` removed a healthy running app; the orchestrator reconciled it away. | blocking | Use RPC `container-*` with `{"app_id": ...}`. Never `podman start/stop/restart/rm` on an app container. |
|
||||
| Trusting a tool-name→RPC mapping without a reachability test | `tools.rs` named three real dispatcher-registered methods that `assistant_dispatch_tool` had no arm for. Every non-`own` content scope died on the catch-all and the tool never ran. Schema validation passed; the failure was entirely downstream of it. | blocking | The regression test `every_content_scope_reaches_a_real_dispatch_handler` now asserts no scope returns "no such handler". Extend it when adding tools. |
|
||||
| Editing JSON locale files with `json.dump` | Reformatted `es.json` wholesale — a 470-line diff for two keys. | advisory | Insert keys textually, preserving the file's own formatting. Verify with `git diff --stat`. |
|
||||
| Declaring a UI fix done without a browser | Three defects this session were invisible from source: the tab bar being overwritten by the prose surface, the web-search path 403, and the images bucket being dropped. All only appeared when the real UI was driven. | blocking | Drive `neode-ui/shot.tmp.mjs` and read the screenshot before claiming any UI item complete. |
|
||||
|
||||
<current_state>
|
||||
Phase 13's own GSD plans are 14/15 (only 13-15, the device-close human-verify, is open).
|
||||
The active work is the operator's **17-item demo list**, not 13-XX tasks — the full list
|
||||
with per-item status lives in `.planning/RESUME-2026-08-07-aiui-surfaces.md`.
|
||||
|
||||
Branch `gsd/phase-13-aiui-functional-conversational-node-control-and-content-surf`
|
||||
@ `bca18c03`, pushed to `gitea-ai`. Working tree clean except the untracked
|
||||
`neode-ui/shot.tmp.mjs` (deliberate — throwaway Playwright driver).
|
||||
|
||||
archi-dev-box (this box) is running the new frontends and a release binary that carries
|
||||
every surface/peer fix but NOT the SearXNG seed fix.
|
||||
|
||||
Three commits landed this session: `9abc1623`, `c810b514`, `b1c5d138`.
|
||||
</current_state>
|
||||
|
||||
<completed_work>
|
||||
|
||||
Operator list — done and browser-verified:
|
||||
- Task 1: Unify AI Data Access toggles with assistant tool grants — `55155f2d`
|
||||
- Task 5: Cap `content.browse-all-peers`, rebuilt as Cloud's fan-out — `75919a20`
|
||||
- Task 12: Node certificate settings section container/layout — `75919a20`
|
||||
- Task 16: Content surface populated for own shared content — `9abc1623` + `b1c5d138`
|
||||
- Task 15: Stale-title half — "Loading…" during the turn, "13 Images" after
|
||||
|
||||
In progress:
|
||||
- Task 6: Ungranted-permission Settings offer — node `refused_categories` + broker
|
||||
`aiui:permission-needed` event + Teleported chrome banner all landed in `9abc1623`,
|
||||
typecheck clean, **never seen in a browser**
|
||||
- Task 9: Surfaces alongside prose — content turns verified; system/network/bitcoin
|
||||
turns still prose-only (only `content_list`/`apps_list` produce surfaces)
|
||||
- Task 10: Console noise — web-search CSP spam and its 403 fixed; the rest still present
|
||||
|
||||
What the three commits actually fixed (all four of these produced ONE symptom — a
|
||||
correct prose answer beside an empty grid):
|
||||
1. `assistant_dispatch_tool` had an arm only for `content.list-mine`; the `peers`,
|
||||
`purchased` and `films` scopes named real handlers it had never heard of, so they
|
||||
died on its catch-all. The tool never ran.
|
||||
2. `content.browse-all-peers` discarded completed batches on timeout expiry.
|
||||
Budget 20s → 45s (two batches of 8 at a 10s per-peer timeout had zero headroom).
|
||||
3. `assistant.chat` returned only `{ text }`; tool results were dropped in the loop.
|
||||
Now carried as `surfaces`, captured raw before the untrusted wrap.
|
||||
4. The adapter classified images as `'excluded'`; a photo-heavy node rendered empty
|
||||
while AIUI's `panelImages`/`ImageGrid` sat unused.
|
||||
Plus: SearXNG's JSON API was 403 (default `formats: [html]`), so AIUI web search could
|
||||
never have worked; and `searchWeb` used a host-absolute path instead of BASE_URL.
|
||||
</completed_work>
|
||||
|
||||
<remaining_work>
|
||||
|
||||
- Task 2: Verify AI grants persist across refresh through the real UI
|
||||
- Task 3: Add `app_install` / `app_uninstall` tools behind the 13-08 confirm gate
|
||||
- Task 4: `!archy` / `!ai` over mesh must action commands with text responses
|
||||
- Task 6: Finish — verify the permission banner in a browser
|
||||
- Task 7: App lifecycle defects (fedimint guardian, BTCPay wipe-reinstall, disappearing
|
||||
apps, fedimint gateway 88%, reconciler `chown postgres-btcpay`)
|
||||
- Task 8: LND UI + filebrowser 401s — untouched. The 3×403 still in the AIUI console
|
||||
may be this same family; check before assuming a separate cause.
|
||||
- Task 9: Decide whether system/network/bitcoin turns get context surfaces
|
||||
- Task 10: wavlake/itunes CSP block (song covers), 3×403, 2×402, 502, 404, sw.js SSL,
|
||||
and the slow background image (not yet investigated)
|
||||
- Task 11: Cmd/Ctrl+K query carry — **reproduce before editing**; the whole path
|
||||
(`SpotlightSearch.vue:294` → `Chat.vue` `askedAt` watcher → `flushAsk` →
|
||||
`chat:prefill` → `archyBridge.onPrefill` buffer → `ChatInput.vue:224`) reads as
|
||||
correct and complete, including the cold-frame buffer. It prefills-and-focuses by
|
||||
design rather than auto-sending.
|
||||
- Task 13: HTTPS on every address as addresses change
|
||||
- Task 14: Nostr signer + service worker over HTTPS
|
||||
- Task 15: Header-OVERLAP half — never reproduced at 1600×950 (the tab row already
|
||||
carries `pr-12`, `ChatPage.vue:38`). Try a narrow/mobile viewport.
|
||||
- Task 17: ISO — **blocked**, see Blockers
|
||||
</remaining_work>
|
||||
|
||||
<decisions_made>
|
||||
|
||||
- Capture surfaces RAW, before `wrap_tool_result_if_untrusted`. The untrusted boundary
|
||||
stops peer text being read as instructions **by the model**; this copy goes to a
|
||||
renderer that treats every field as inert data and never re-enters the prompt.
|
||||
Wrapping it would leave the UI parsing delimiter noise instead of JSON.
|
||||
- Gate chat surfaces on media/files in the broker as well as node-side, mirroring
|
||||
`handleContentRequest`. Dropping surfaces never drops the prose answer.
|
||||
- Archy tabs outrank regex-inferred tabs, ordered by bucket size — a 13-photo/2-track
|
||||
answer had been opening on Songs and titling itself "2 Songs".
|
||||
- Skip client-side web search when embedded: `streamViaArchy` sends only the user's
|
||||
text, so those results provably reached no model. Web search for the embedded path
|
||||
belongs node-side.
|
||||
- Keep SearXNG. Measured after the JSON fix: 28 results from Brave + DuckDuckGo.
|
||||
Google self-suspends, Startpage CAPTCHAs — normal self-hosted, and cheap given
|
||||
Brave's own index. The 403 was the whole problem, not result quality.
|
||||
- `browse-all-peers` uses a between-batch deadline and no outer timeout: every future
|
||||
is already bounded per-peer, so an outer timeout can only discard completed work.
|
||||
</decisions_made>
|
||||
|
||||
<blockers>
|
||||
- **Binary drift (blocks task 17).** `core/target/release/archipelago` and the deployed
|
||||
`/usr/local/bin/archipelago` were both built before the `install.rs` SearXNG fix.
|
||||
Rebuild: `cd core && CARGO_INCREMENTAL=0 cargo build --release -p archipelago` (~9 min).
|
||||
Verify: `strings core/target/release/archipelago | grep -A2 "limiter: false"` should
|
||||
show the `formats` lines. Then redeploy and cut the ISO.
|
||||
- **Fleet SearXNG repair.** `c810b514` only fixes new installs. Every existing node's
|
||||
AIUI web search still 403s. Add to `/var/lib/archipelago/searxng/settings.yml`:
|
||||
`search:` / ` formats:` / ` - html` / ` - json`, then restart the app.
|
||||
archi-dev-box is already repaired.
|
||||
- **Concurrent agent on this branch** — see the constraint above.
|
||||
</blockers>
|
||||
|
||||
## Required Reading (in order)
|
||||
1. `.planning/RESUME-2026-08-07-aiui-surfaces.md` — the full 17-item list with
|
||||
per-item status, the peer-files correction, and the browser-verification recipe
|
||||
2. `.planning/phases/13-.../ASSESSMENT-FIX-PLAN-2026-08-07.md` — another agent's
|
||||
full-stack security/mission audit, S1–S6 (network_status leaks WAN IP + SSID against
|
||||
a label promising "no IP addresses"; Claude key plaintext in localStorage; standalone
|
||||
mode reachable on a node with unscreened egress; unauthenticated web-search proxy;
|
||||
unredacted `app_logs`; G-B2 turn-minimality silently stripping prior user turns).
|
||||
Overlaps tasks 8 and 10.
|
||||
3. `.planning/RESUME-2026-08-06-media-loop.md` — the fix→deploy→test loop and deploy commands
|
||||
4. `.planning/METHODOLOGY.md` (if it exists) — project analytical lenses
|
||||
|
||||
## Critical Anti-Patterns (do NOT repeat these)
|
||||
- [ANTI-PATTERN]: Blaming infrastructure for a flapping empty result → call the RPC
|
||||
twice and compare before concluding anything about the network.
|
||||
- [ANTI-PATTERN]: `podman restart <app>` → use RPC `container-*` with `{"app_id": ...}`.
|
||||
- [ANTI-PATTERN]: Claiming a UI fix without driving the browser → run `shot.tmp.mjs`
|
||||
and read the screenshot.
|
||||
- [ANTI-PATTERN]: `git add -A` while another agent shares the tree → stage by path.
|
||||
|
||||
## Infrastructure State
|
||||
- **This box IS archi-dev-box** (`hostname`; LAN `192.168.63.240`, Tailscale `100.69.68.39`).
|
||||
Everything is testable locally; no remote SSH needed.
|
||||
- `archipelago.service`: active, running the newly deployed binary (restarted this session).
|
||||
- Deployed: `/opt/archipelago/web-ui/` (neode-ui) and `/opt/archipelago/web-ui/aiui/`
|
||||
both carry this session's builds.
|
||||
- **Authenticated RPC goes through nginx on 443 — NOT ports 7777 or 8101.**
|
||||
POST `https://192.168.63.240/rpc/v1`, `auth.login` `{"password":"ThisIsWeb54321@"}`,
|
||||
carry `session` + `csrf_token` cookies and send `X-CSRF-Token`.
|
||||
- SearXNG: running and healthy; `settings.yml` repaired with `formats: [html, json]`;
|
||||
`format=json` verified 200.
|
||||
- AI grants on this node: `apps=Y system=Y files=Y media=Y`, rest closed.
|
||||
- Node has 18 own shared items (mostly photos + 2 mp3 + 3 APKs) and reaches ~4 of 16 peers.
|
||||
- `neode-ui/shot.tmp.mjs` — uncommitted Playwright driver. **Run it from `neode-ui/`**
|
||||
(that is where `playwright` is installed; the aiui package only has it under pnpm's
|
||||
store). Dismiss the Remote Companion modal with **Escape first** — its button uses a
|
||||
curly apostrophe so `has-text("I've installed it")` never matches. It installs an
|
||||
`addInitScript` probe logging every `chat:response` with bucket counts.
|
||||
|
||||
## Pre-Execution Critique Required
|
||||
Not applicable — this is mid-execution, not a design/execute boundary.
|
||||
|
||||
<context>
|
||||
The method that worked this session: read the code, form a hypothesis, then PROVE it
|
||||
against the live node before changing anything. That is what overturned the previous
|
||||
session's peer conclusion. Every claim in the commits is backed by a measurement taken
|
||||
on archi-dev-box, and the three UI defects that mattered most were invisible from
|
||||
source — they only appeared when the real browser drove the real node.
|
||||
|
||||
The surface pipeline is now proven end to end:
|
||||
`[PROBE] chat:response success=true surfaces=1 detail=[{"tool":"content_list",
|
||||
"scope":"own","films":0,"songs":2,"images":13}]`, heading "Loading…" → "13 Images",
|
||||
with the prose answer still on the left. That is the shape the operator asked for —
|
||||
"not JUST prose", surfaces alongside it.
|
||||
</context>
|
||||
|
||||
<next_action>
|
||||
Start with: `cd core && CARGO_INCREMENTAL=0 cargo build --release -p archipelago` to
|
||||
clear the ISO blocker (~9 min, run it in the background). While it builds, verify
|
||||
task 6 in a browser: revoke the `media` grant via `assistant.grants-set`, ask AIUI for
|
||||
content, and confirm the permission banner renders and its button lands on the AI Data
|
||||
Access section. Then re-check task 15's header overlap at a narrow viewport, and
|
||||
task 11's ⌘K carry — both are read-only verifications that may need no code at all.
|
||||
</next_action>
|
||||
Reference in New Issue
Block a user