docs(02-07): resolve AIUI source location and record real D-14 contract
AIUI is now cloned at /home/archipelago/Projects/AIUI (git.tx1138.com/lfg2025/AIUI, development branch — 17 commits ahead of main with zero unique main commits). Replaces the exhausted-search conclusion with the real embed-parameter contract read from source and records the D-14a/D-14b implementation: chatCollapsed's initial state now honors a new ?chatExpanded param (chat.ts), and ChatPage.vue re-asserts mobileTab='chat' on mount when ?mobileChat is present, guarding against carry-over from AIUI's own module-singleton content- panel state on an internal remount. Both are static, unconditional query params — no runtime-varying URL input. AIUI-side commit lives on feat/d14-embed-defaults (900c0b9) in the local clone only — anonymous push to origin returned 403 Forbidden. Needs a maintainer with push rights to land it before any deployed AIUI build can honor these two parameters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
c10f415c6b
commit
71b2703213
@ -1,140 +1,186 @@
|
||||
# AIUI D-14 Embed Contract
|
||||
|
||||
**Written:** 2026-07-30 (Phase 02 Plan 07, Task 1)
|
||||
**Purpose:** Record where AIUI's source lives, what its embed parameter contract is today,
|
||||
which side implements each of D-14's two UX defaults, and what deploying the AIUI half
|
||||
would require — so Task 2 (and any future agent) does not re-run this search.
|
||||
**Amended:** 2026-07-30 (Phase 02 Plan 07, Task 2 resume) — the orchestrator supplied the
|
||||
missing fact this document's original Task 1 pass could not obtain from within this
|
||||
environment: AIUI's source repository location. This amendment replaces the "search
|
||||
exhausted" conclusion below with the real contract read directly from source, and records
|
||||
the D-14a/D-14b implementation actually shipped.
|
||||
|
||||
## Source Location
|
||||
|
||||
AIUI's source is **not present on this machine and not reachable via the noted build
|
||||
server at this time.** Search performed and exhausted:
|
||||
**AIUI's source is now located and was cloned for this plan:**
|
||||
|
||||
1. **Sibling-repo checks** (the two places `neode-ui`'s own tooling expects it):
|
||||
- `neode-ui/package.json`'s `dev:mock` script: `cd ../../AIUI && pnpm dev` (relative to
|
||||
`neode-ui/`, i.e. `<parent-of-archy>/AIUI`) — degrades to
|
||||
`echo '[AIUI] Not found at ../../AIUI — chat will show placeholder'` when absent.
|
||||
- `scripts/setup-aiui-server.sh`: `AIUI_DIST="$PROJECT_DIR/../AIUI/packages/app/dist"`
|
||||
(relative to the `archy` repo root, i.e. the same sibling directory), with a
|
||||
documented prerequisite: "AIUI must be built locally first:
|
||||
`cd AIUI/packages/app && VITE_BASE_PATH=/aiui/ npx vite build`".
|
||||
- Checked directly: `/home/archipelago/Projects/AIUI` does **not** exist.
|
||||
`ls /home/archipelago/Projects/` shows only `archy` and various `archy-*`
|
||||
worktree/backup checkouts, `botfights`, and two unrelated Indeehub projects — no
|
||||
`AIUI` directory.
|
||||
- **Repository:** `https://git.tx1138.com/lfg2025/AIUI` (anonymous `git ls-remote` succeeds;
|
||||
clone succeeded read-only, push is `403 Forbidden` anonymously — see Deployment Impact).
|
||||
- **Cloned to:** `/home/archipelago/Projects/AIUI` — the exact sibling path
|
||||
`neode-ui/package.json`'s `dev:mock` script and `scripts/setup-aiui-server.sh` both already
|
||||
expected (`<parent-of-archy>/AIUI`), so no changes to either script were needed once the
|
||||
clone existed.
|
||||
- **Branch used: `development`**, not the repository's default `main`. Verified via
|
||||
`git log main..origin/development` vs `git log origin/development..main`: `development` is
|
||||
17 commits ahead of `main` (including a run of `fix(app):` security-hardening commits —
|
||||
origin validation, rate limiting, CSP, SSRF protection, dev-server auth — and the
|
||||
feature/content work this session's grep relies on) with **zero** commits unique to `main`.
|
||||
`main` is simply stale here; `development` is the actual working branch. (AIUI's own
|
||||
`CLAUDE.md` documents the intended name as `dev`, but the real remote branch is named
|
||||
`development` — a doc/reality mismatch noted for AIUI's own maintainers, out of scope to
|
||||
fix from this repository.)
|
||||
- **ThinkPad build server:** confirmed reachable this session at `100.69.68.39` (Tailscale),
|
||||
per the orchestrator-supplied fact. Not needed once the git clone succeeded — recorded here
|
||||
for completeness since Task 1's original search treated it as the fallback path.
|
||||
- **Hosting note (context only, not acted on):** the user noted AIUI hosting may later be
|
||||
ported to "our main vps2." No action taken on this in this plan; recorded for whoever picks
|
||||
up AIUI's deployment next.
|
||||
|
||||
2. **Broader filesystem search** for any directory literally named `AIUI` (case-insensitive)
|
||||
containing AIUI's own `package.json`: `find / -maxdepth 6 -iname "AIUI" -type d` returned
|
||||
only deployed **build output** directories — `/opt/archipelago/web-ui*/aiui` (dozens of
|
||||
timestamped backup copies), `/opt/archipelago/apps/aiui` (this repo's manifest dir, no
|
||||
source), `archy`'s own `apps/aiui` and `demo/aiui` (built static assets, mirrors of the
|
||||
deployed bundle), and installer-ISO copies under `image-recipe/`. None of these are
|
||||
AIUI's source repository — they are prebuilt `dist/` output, deployed or bundled.
|
||||
### Original Task 1 search (superseded, kept for history)
|
||||
|
||||
3. **ThinkPad build server reachability** (project memory notes `.116` as the primary build
|
||||
server, where AIUI may live if not here): both ping and SSH to `192.168.1.116` failed —
|
||||
`ping` returned "Destination Host Unreachable" from the local gateway (`192.168.1.66`),
|
||||
and `ssh -o BatchMode=yes -o ConnectTimeout=3` timed out after 3s with "Connection timed
|
||||
out" on port 22. The build server is not reachable from this execution environment right
|
||||
now (machine likely off or off this network segment).
|
||||
|
||||
**Conclusion:** The search is exhausted for this session. AIUI's source cannot be read from
|
||||
`archy` alone, confirming RESEARCH.md's Open Question 1. Task 2's `<precondition>` — which
|
||||
requires this section to name a reachable checkout — is **not met**; this plan halts before
|
||||
any code targeting the AIUI side is written, per the plan's own instruction not to invent a
|
||||
parameter and ship it.
|
||||
The initial pass searched the sibling path (`<parent-of-archy>/AIUI` — not present at that
|
||||
time), a broader filesystem sweep (found only prebuilt `dist/` output under
|
||||
`/opt/archipelago/web-ui*/aiui`, this repo's `apps/aiui`/`demo/aiui`, and installer-ISO
|
||||
copies — never source), and the ThinkPad at `192.168.1.116` (ping/ssh both failed at that
|
||||
time — host unreachable from this environment on that address/path). That search was
|
||||
genuinely exhausted with the facts available at the time; the blocker was resolved
|
||||
externally (see Amended note above), not by anything different this pass did on the same
|
||||
inputs.
|
||||
|
||||
## Embed Parameter Contract
|
||||
|
||||
`neode-ui/src/views/Chat.vue`'s `aiuiUrl` computed (lines ~74-82) constructs the iframe URL
|
||||
today with:
|
||||
- `embedded=true` — always present when a URL is built.
|
||||
- `hideClose=true` — always present when a URL is built.
|
||||
- `&mockArchy=1&seed=1` — only appended when `IS_DEMO` is true.
|
||||
`neode-ui/src/views/Chat.vue`'s `aiuiUrl` computed (lines ~74-82) sends, unchanged by this
|
||||
plan:
|
||||
- `embedded=true` — always present.
|
||||
- `hideClose=true` — always present.
|
||||
- `&mockArchy=1&seed=1` — only when `IS_DEMO` (build-time env var, stable for the life of
|
||||
the bundle).
|
||||
|
||||
Because AIUI's own source could not be inspected, the exact file/line where each parameter
|
||||
is *parsed inside AIUI* cannot be recorded from source, per the instruction not to invent
|
||||
what wasn't verified. As a diligence step (not a substitute for source access), the
|
||||
currently-**deployed** AIUI build's static JS bundle was inspected instead — this is a
|
||||
built artifact, not source, so variable/function names are minified and the full parsing
|
||||
logic cannot be confirmed with certainty from it. Findings, treated as supporting evidence
|
||||
only:
|
||||
Read from AIUI source (`development` branch, commit `9176324` before this plan's changes):
|
||||
|
||||
- Bundle inspected: `/opt/archipelago/web-ui/aiui/assets/index-Lh5NfTCq.js` (byte-identical
|
||||
copy also present in this repo at `demo/aiui/assets/index-Lh5NfTCq.js` and
|
||||
`web/dist/neode-ui/../aiui`-style deploy mirrors — same build hash everywhere checked).
|
||||
- `embedded` — read via `new URLSearchParams(window.location.search).has("embedded")`,
|
||||
stored as `window.__AIUI_EMBEDDED__`. This is a **presence-only** check (any value,
|
||||
including none, counts as embedded=true). Confirmed present in the bundle.
|
||||
- `mockArchy` — read via `.has("mockArchy")`, but only takes effect when the embedded flag
|
||||
is *false* (`&&!embedded` in the minified logic). This does not match how `Chat.vue`'s
|
||||
demo mode currently sends both `embedded=true` and `mockArchy=1` together — flagging as
|
||||
an existing inconsistency in the deployed build, unrelated to D-14 and out of this plan's
|
||||
scope to investigate or fix.
|
||||
- `hideClose` — **zero** occurrences of the literal string anywhere in this build's JS. No
|
||||
evidence this deployed build reads or honors it at all.
|
||||
- `seed` — not exhaustively searched this pass; irrelevant to D-14, not pursued further.
|
||||
|
||||
No parameter resembling an expanded-state or mobile-initial-view control (see D-14a/D-14b
|
||||
below) was found anywhere in this bundle.
|
||||
- **`embedded`** — `packages/app/src/main.ts:34-35`. Read once, before router init, via
|
||||
`new URLSearchParams(window.location.search).has('embedded')` (presence-only check) and
|
||||
stored on `window.__AIUI_EMBEDDED__` so it survives SPA navigation. Matches the deployed
|
||||
build's minified behavior exactly (independently confirmed by the diligence pass on the
|
||||
built bundle before source access — see history above).
|
||||
- **`mockArchy`** — `packages/app/src/composables/useArchy.ts:83-96`. Read via
|
||||
`import.meta.env.VITE_MOCK_ARCHY === 'true' || new URLSearchParams(...).has('mockArchy')`,
|
||||
but the mock-data branch is only entered `if (useMock && !embedded)` — i.e. **mutually
|
||||
exclusive with `embedded`** in this codebase today. This confirms the inconsistency flagged
|
||||
during the original diligence pass: `Chat.vue`'s demo mode sends `embedded=true` and
|
||||
`mockArchy=1` together, but AIUI only honors `mockArchy` when NOT embedded. Pre-existing,
|
||||
unrelated to D-14, **not fixed here** (out of this plan's file scope — flagged for whoever
|
||||
owns the demo-mode AIUI experience next).
|
||||
- **`hideClose`** — confirmed absent from AIUI's source entirely (`grep -rn "hideClose"
|
||||
packages/` returns nothing). AIUI does not read or honor this parameter at all today. Not
|
||||
part of D-14; not investigated further.
|
||||
- **`seed`** — confirmed absent from AIUI's source entirely (no `URLSearchParams` read
|
||||
anywhere references it). `Chat.vue`'s `&seed=1` in demo mode currently does nothing on the
|
||||
AIUI side. Pre-existing, unrelated to D-14, not fixed here.
|
||||
|
||||
## D-14a
|
||||
|
||||
**Default:** the AIUI chat should start EXPANDED rather than requiring the user to expand it.
|
||||
|
||||
- **Status: needs a new AIUI-side parameter** (or a postMessage control, per the plan's
|
||||
fallback path). No string resembling `expandedState`, `chatExpanded`, `expandChat`, or
|
||||
similar chat-UI-state control was found in the deployed bundle. The one `expanded` hit in
|
||||
the bundle is inside a third-party media-player library's ARIA `aria-expanded` attribute
|
||||
code — unrelated to chat panel state.
|
||||
- **Which side implements it:** AIUI (the receiving half must read the flag and render
|
||||
itself in the expanded state on load). neode-ui's half — appending the agreed flag name
|
||||
to the iframe URL — is inert and forward-compatible even before AIUI reads it, but cannot
|
||||
usefully ship without the AIUI-side change, and the AIUI-side change itself is blocked:
|
||||
its source is unreachable this session (see Source Location above).
|
||||
- **Root cause, found in source:** `packages/app/src/stores/chat.ts:132` (before this plan's
|
||||
change): `const chatCollapsed = ref(localStorage.getItem('aiui-chat-collapsed') !== 'false')`
|
||||
— defaults to **collapsed** (`true`) on any fresh/unset `localStorage`, i.e. exactly the
|
||||
behavior CONTEXT.md describes ("requiring the user to expand it"). `chatCollapsed` gates
|
||||
`ChatWindow.vue`'s `PromptIndex` (collapsed quick-pick view) vs. the full virtualized
|
||||
message list (expanded view) — confirmed at `ChatWindow.vue:35` /
|
||||
`ChatWindow.vue:249`. Once a user manually expands, the choice is written back to
|
||||
`localStorage` (`chat.ts:196-198`) and persists — so this bug only bites on a genuinely
|
||||
fresh `localStorage`, matching the reported "starts collapsed" default.
|
||||
- **Status: implemented, on the AIUI side, gated by a new query parameter** — `?chatExpanded`.
|
||||
Not something the deployed build already read (see original diligence pass); a source
|
||||
change was required and made.
|
||||
- **Which side implements it:** AIUI reads the flag; neode-ui sends it. Implementation:
|
||||
`chatCollapsed`'s initial ref now checks
|
||||
`new URLSearchParams(window.location.search).has('chatExpanded')` first, defaulting to
|
||||
`false` (expanded) when present, before falling back to the existing `localStorage` check.
|
||||
**Never written back to `localStorage`** — it is a one-time initial-state override for this
|
||||
session only, so a later manual collapse/expand while embedded still persists exactly as
|
||||
before, and the standalone (non-embedded) app's own default is completely untouched (it
|
||||
never sends `?chatExpanded`, so its `localStorage`-based behavior is unchanged).
|
||||
- **Why a new parameter rather than reusing the existing `embedded` flag:** `embedded` is
|
||||
already overloaded (transparent background, mock-Archy gating, passphrase-prompt skip);
|
||||
tying `chatCollapsed`'s default to it directly would mean *every* embedded session forces
|
||||
expanded with no way to decouple the two concerns later. A dedicated flag keeps the
|
||||
contract self-documenting and matches this plan's acceptance criteria (the flag name must
|
||||
be discoverable in the built neode-ui bundle).
|
||||
|
||||
## D-14b
|
||||
|
||||
**Default:** on a mobile viewport, AIUI should open on its CHAT view rather than its
|
||||
context view.
|
||||
**Default:** on a mobile viewport, AIUI should open on its CHAT view rather than its context
|
||||
view.
|
||||
|
||||
- **Status: needs a new AIUI-side parameter** (or a postMessage control). No string
|
||||
resembling `mobileView`, `initialView`, `view=chat`, `view=context`, or similar was found
|
||||
in the deployed bundle.
|
||||
- **Which side implements it:** AIUI (it owns the chat-view/context-view routing and would
|
||||
need to read an initial-view flag or a fixed mobile-view-preference flag on load).
|
||||
Same blocked status as D-14a — the AIUI-side change cannot be made without source access.
|
||||
- **Root cause, found in source:** `packages/app/src/pages/ChatPage.vue:469` already
|
||||
initializes `mobileTab` to `'chat'` (`const mobileTab = ref<'chat' | 'content' |
|
||||
'context'>('chat')`) — so a truly fresh mount already defaults correctly. The reported bug
|
||||
is a **carry-over**, not a wrong default: `panelOpen`, `selectedFilm`/`selectedBook`/etc.,
|
||||
and `hasDetailOpen` (computed from those) are **module-scope singleton refs** in
|
||||
`useContentPanel.ts` (`ref()` calls at module top level, not inside the composable
|
||||
function), shared across every mount of `ChatPage.vue` within the same AIUI SPA session.
|
||||
If a user previously opened a detail item (making `hasDetailOpen` true, which
|
||||
`ChatPage.vue`'s own `watch(hasDetailOpen, ...)` at line ~507 flips `mobileTab` to
|
||||
`'context'` for), and `ChatPage.vue` later remounts within the same iframe session (e.g. an
|
||||
internal AIUI navigation to `/guide` and back) without those refs resetting,
|
||||
`hasDetailOpen` is still `true` on the new mount and the "opens on chat" default never gets
|
||||
a chance to hold — it's immediately superseded by state carried over from before. Note this
|
||||
is now less likely to surface at all going forward, since Task 2's URL-stability fix (see
|
||||
D-14 URL stability, below) keeps the iframe itself from reloading on an Archipelago tab
|
||||
switch — but it can still happen from AIUI's own internal navigation, independent of
|
||||
Archipelago.
|
||||
- **Status: implemented, on the AIUI side, gated by a new query parameter** — `?mobileChat`.
|
||||
- **Which side implements it:** AIUI reads the flag; neode-ui sends it. Implementation: a new
|
||||
`onMounted` hook in `ChatPage.vue` re-asserts `mobileTab.value = 'chat'` when `?mobileChat`
|
||||
is present and `isMobile.value` is true, at mount time only. This does not touch the
|
||||
`panelOpen`/`hasDetailOpen` watchers that drive normal tab-switching in response to actual
|
||||
user taps after the initial paint — those are unchanged, so a user can still navigate to
|
||||
the content/context tabs exactly as before; only the *initial* tab on a (re)mount is
|
||||
affected.
|
||||
- **Why AIUI decides from its own viewport rather than neode-ui passing a computed
|
||||
boolean:** per Task 2's URL-stability constraint, `aiuiUrl` cannot embed a reactive
|
||||
viewport read (see below). `?mobileChat` is sent unconditionally and is unconditionally
|
||||
interpreted by AIUI against its **own** `isMobile` computed (`windowWidth.value < 1024`,
|
||||
read from the iframe's own `window.innerWidth`) — this is the "let AIUI decide from its own
|
||||
viewport" option named in the plan's Task 2 action, chosen over resolving neode-ui's outer
|
||||
viewport once at setup time, since AIUI's iframe has its own layout breakpoint and is the
|
||||
side that actually owns the mobile/desktop layout switch.
|
||||
|
||||
## D-14 URL Stability (how neode-ui sends both flags)
|
||||
|
||||
Both `?chatExpanded` and `?mobileChat` are appended unconditionally in `Chat.vue`'s `aiuiUrl`
|
||||
computed — static strings, not derived from any runtime-varying input (no viewport read, no
|
||||
connection state, no timestamp). This preserves the property Task 2 exists to protect: the
|
||||
iframe `src` stays byte-identical across re-renders, viewport resizes, and
|
||||
deactivate/reactivate cycles, so the AIUI panel never reloads on an Archipelago tab switch.
|
||||
|
||||
## Deployment Impact
|
||||
|
||||
`apps/aiui/manifest.yml` declares:
|
||||
```yaml
|
||||
container:
|
||||
image: localhost/archipelago-aiui:latest
|
||||
pull_policy: always
|
||||
```
|
||||
`apps/aiui/manifest.yml` still declares a **prebuilt container image**
|
||||
(`localhost/archipelago-aiui:latest`, `pull_policy: always`) — this plan's AIUI-side change
|
||||
does not alter that; shipping it still requires:
|
||||
|
||||
AIUI ships as a **prebuilt container image**, not as neode-ui-bundled static assets served
|
||||
alongside the rest of the dashboard. Shipping any AIUI-side source change requires, in
|
||||
order:
|
||||
1. **Merging the AIUI-side commit.** Changes are committed locally in the cloned checkout at
|
||||
`/home/archipelago/Projects/AIUI` on branch **`feat/d14-embed-defaults`** (based on
|
||||
`development`), commit `900c0b9`. **Anonymous push to `origin` failed with `403
|
||||
Forbidden`** (`git push origin feat/d14-embed-defaults`) — this account has read-only
|
||||
access to `git.tx1138.com/lfg2025/AIUI`. The branch and commit exist only in this local
|
||||
checkout until someone with write access pushes it (or opens a PR from a fork/mirror they
|
||||
do have write access to) and merges it into `development`.
|
||||
2. Rebuilding AIUI's production bundle from the merged source:
|
||||
`cd AIUI/packages/app && VITE_BASE_PATH=/aiui/ npx vite build` (per
|
||||
`scripts/setup-aiui-server.sh`'s documented prerequisite).
|
||||
3. Rebuilding the `localhost/archipelago-aiui:latest` container image from that build output
|
||||
(a local/on-node image tag, not a registry pull).
|
||||
4. Redeploying/restarting the `aiui` app container on the target node(s) so `pull_policy:
|
||||
always` picks up the new local image.
|
||||
|
||||
1. Access to the AIUI source repository (currently unreachable — see Source Location).
|
||||
2. Rebuilding AIUI's production bundle, per the documented prerequisite in
|
||||
`scripts/setup-aiui-server.sh`: `cd AIUI/packages/app && VITE_BASE_PATH=/aiui/ npx vite build`.
|
||||
3. Rebuilding the `localhost/archipelago-aiui:latest` container image from that fresh build
|
||||
output (the manifest names a `localhost`-scoped image tag, implying a local/on-node
|
||||
build or push into each target node's local image store — not a registry pull from
|
||||
outside the fleet).
|
||||
4. Redeploying/restarting the `aiui` app container on the target node(s) so
|
||||
`pull_policy: always` picks up the new local image tag.
|
||||
|
||||
Per D-15, this phase restricts deployment to the **dev pair only, with no OTA** — so even
|
||||
once source access becomes available, an AIUI-side D-14 change would be built and deployed
|
||||
only to the designated dev nodes (per plan 02-08, which owns the deploy step), not pushed
|
||||
through the normal fleet release train.
|
||||
|
||||
**Bottom line:** until AIUI source access is available (e.g. the ThinkPad build server at
|
||||
`.116` comes back online and is confirmed to hold the AIUI checkout, or the repository is
|
||||
otherwise made reachable), the AIUI half of D-14 cannot be implemented, built, or deployed
|
||||
at all. This is a genuine blocking external dependency, not a scope reduction — D-14 is not
|
||||
dropped, it is blocked pending a fact only the developer can supply.
|
||||
Per D-15, deployment is **dev pair only this phase, no OTA** — plan 02-08 owns the deploy
|
||||
step under that constraint, once the AIUI-side commit is actually mergeable (i.e., once a
|
||||
maintainer with push rights lands `feat/d14-embed-defaults` on `development` and it's
|
||||
rebuilt/redeployed). **Until that push/merge happens, the deployed AIUI build on any node
|
||||
(including archi-dev-box) will NOT carry these two parameters** — neode-ui's side is fully
|
||||
forward-compatible with that (both flags are inert query-string additions the current
|
||||
deployed AIUI build simply ignores, per the confirmed absence of `hideClose`-style unknown
|
||||
params breaking anything), but the two visual defaults (expanded start, mobile-chat-first
|
||||
start) will not be observable against any currently-deployed AIUI build until the AIUI
|
||||
commit ships.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user