Archipelago — open-source initial import
This commit is contained in:
@@ -0,0 +1,331 @@
|
||||
---
|
||||
phase: 01-federation-mesh-hardening
|
||||
plan: 18
|
||||
subsystem: ui
|
||||
tags: [verification, deploy, dev-pair, on-device, checkpoint, gap-closure]
|
||||
status: blocked-on-checkpoint
|
||||
|
||||
requires:
|
||||
- phase: 01-federation-mesh-hardening
|
||||
plan: 12
|
||||
provides: "UIFIX-02 connected-nodes sibling-matched scroll contract"
|
||||
- phase: 01-federation-mesh-hardening
|
||||
plan: 13
|
||||
provides: "UIFIX-03 onboarding scroll cue"
|
||||
- phase: 01-federation-mesh-hardening
|
||||
plan: 14
|
||||
provides: "UIFIX-04/UIFIX-06 paid-item lightbox + Opening… loader"
|
||||
- phase: 01-federation-mesh-hardening
|
||||
plan: 15
|
||||
provides: "UIFIX-05 PiP custodial-host handoff"
|
||||
- phase: 01-federation-mesh-hardening
|
||||
plan: 17
|
||||
provides: "UIFIX-01 transport-pill wrap fix + pin test"
|
||||
provides:
|
||||
- "All six UIFIX fixes delivered to archi-dev-box and proven present in the bundle the node actually serves, fetched over HTTP and matched against the live service-worker chunk manifest"
|
||||
- "An on-device boot check of the deployed bundle at 1440x900 and 390x740 — zero console errors, zero page errors, zero failed requests"
|
||||
- "Two of the planner's flagged open questions settled from the node's own data: it HAS one purchased image, and it has NO purchased video and NO audio/video content at all"
|
||||
- "A per-check VERIFIED / NOT VERIFIED table with the exact human action each unverified check still needs"
|
||||
affects: [cloud, web5, onboarding, media-viewer]
|
||||
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "Served-bundle verification must resolve the live chunk set first: /opt/archipelago/web-ui/assets accumulates every prior deploy's hashed chunks, so a naive `grep -rl` across the directory returns hits from dead chunks. The service-worker precache manifest (sw.js) is the authoritative list of the chunks the current build actually loads — grep only those, and fetch them over HTTP rather than off disk."
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- .planning/phases/01-federation-mesh-hardening/01-18-SUMMARY.md
|
||||
modified: []
|
||||
|
||||
key-decisions:
|
||||
- "No source file was modified and no fix was made. This is a verification plan (files_modified: []) and three other executors were live in the same working tree on plans 10-02/10-04/10-06 for its whole duration; anything found here is recorded as a finding, not patched inline."
|
||||
- "Task 2's six numbered checks are recorded NOT VERIFIED. Every one of them requires an authenticated session on archi-dev-box, and the node's UI password was not available to this executor (02-08 records it being supplied out-of-band by the coordinator and passed only via ARCHY_PASSWORD). No credential was guessed against a live node holding real federation trust and real funds."
|
||||
- "STATE.md/ROADMAP.md/REQUIREMENTS.md were deliberately NOT updated and NOT committed. .planning/STATE.md was already dirty with another agent's in-flight edit, and the execution brief restricted this plan's commit to the SUMMARY alone. UIFIX-01..06 must NOT be marked complete until the Task 2 checkpoint is answered."
|
||||
|
||||
requirements-completed: []
|
||||
|
||||
metrics:
|
||||
duration: ~20min
|
||||
tasks: 1 of 2 (Task 2 is a blocking human checkpoint, unanswered)
|
||||
files-changed: 0 source files
|
||||
completed: 2026-08-02
|
||||
---
|
||||
|
||||
# Phase 1 Plan 18: Six-Fix Sign-Off on archi-dev-box — Summary
|
||||
|
||||
**Task 1 is complete with full evidence: all six UI fixes are live in the bundle archi-dev-box actually serves, and the deployed bundle boots clean on the node. Task 2 — the six-check human sign-off, which is the entire point of this plan — is UNANSWERED. No UIFIX requirement is closed by this summary.**
|
||||
|
||||
## Verdict
|
||||
|
||||
**Not signed off.** The operator's response is this plan's verification (`<verification>`), and there was no operator response. Task 1's delivery evidence is complete and reproducible; Task 2's six numbered behavioural checks all remain open.
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Deploy to archi-dev-box — COMPLETE
|
||||
|
||||
### Exact command and host list
|
||||
|
||||
```
|
||||
ARCHIPELAGO_TARGET=archipelago@archi-dev-box scripts/deploy-to-target.sh --frontend-only
|
||||
```
|
||||
|
||||
Run from `/home/archipelago/Projects/archy` on **archi-dev-box itself** (`hostname` = `archi-dev-box`;
|
||||
Tailscale `100.69.68.39`). Exit code **0**, 346 s, `2026-08-02T18:20:08Z → 18:25:54Z`.
|
||||
|
||||
**Host list targeted: `archipelago@archi-dev-box` and nothing else.** Confirmed three ways:
|
||||
|
||||
1. The script's own deploy manifest written on the node:
|
||||
`/opt/archipelago/deploy-manifest.json` → `"target": "archipelago@archi-dev-box"`,
|
||||
`"deployed_from": "archi-dev-box"`, `"commit_short": "527f6023"`,
|
||||
`"deployed_at": "2026-08-02T18:25:26Z"`.
|
||||
2. `--tailscale`, `--tailscale-node=`, `--both` and `--fleet` were **not** passed, so the
|
||||
`SEC_TARGET` fan-out branch (lines 355–385, which contains the only `192.168.1.228` reference on
|
||||
any AIUI path) was never entered. The AIUI step that did run is the `LIVE` branch at lines
|
||||
725–736, which talks only to `$TARGET_HOST`.
|
||||
3. No release was cut, no OTA manifest touched, no catalog signed. Acceptance check:
|
||||
`git status --short -- release-manifest.json releases/ app-catalog/` → **empty**.
|
||||
|
||||
The prohibition was respected: **frontend only, dev pair only, no fleet node, no alpha-tester node,
|
||||
no Tailscale path, no OTA, no release.**
|
||||
|
||||
### Deployed commit contains all six fixes
|
||||
|
||||
Deployed commit `527f6023` (branch `main`). Every contributing commit is an ancestor of it:
|
||||
|
||||
| Plan | Commit | In `527f6023`? |
|
||||
|---|---|---|
|
||||
| 01-12 (UIFIX-02) | `ceafbcb5`, `b5628d96` | yes |
|
||||
| 01-13 (UIFIX-03) | (in `527f6023` via HEAD) | yes |
|
||||
| 01-14 (UIFIX-04/06) | `bc9a210c` | yes |
|
||||
| 01-15 (UIFIX-05) | `3288a02d` | yes |
|
||||
| 01-17 (UIFIX-01) | `8255b69a` | yes |
|
||||
|
||||
`git status --short -- neode-ui web` was **empty** before and after the deploy — the frontend was
|
||||
built from committed state only, and `npm install` did not dirty `package-lock.json`. The manifest's
|
||||
`dirty: true` refers to other executors' concurrent backend work in `core/` (plans 10-02/10-04/10-06),
|
||||
not to any frontend file.
|
||||
|
||||
### Served-bundle grep — the T-01-83 check
|
||||
|
||||
A trap was hit and is worth recording, because the naive version of this check would have produced a
|
||||
false pass. `/opt/archipelago/web-ui/assets` accumulates hashed chunks from **every previous deploy**,
|
||||
so `grep -rl` across that directory finds strings in long-dead chunks. Before the deploy, a naive
|
||||
directory grep reported UIFIX-02/03/04/05 "FOUND" — but three of those hits were in stale chunk
|
||||
generations, and the *live* `Web5-*.js` at that moment did not contain the 40rem floor at all.
|
||||
|
||||
The live chunk set was therefore resolved from the service-worker precache manifest (`sw.js`, 110
|
||||
entries, containing the entry chunk `index--lyLAgu1.js` referenced by the served `index.html`), and
|
||||
each chunk was then **fetched over HTTP from `http://archi-dev-box`** and grepped — not read from
|
||||
`web/dist`, and not read from the assets directory.
|
||||
|
||||
| Fix | String probed | Live chunk fetched over HTTP | Result |
|
||||
|---|---|---|---|
|
||||
| UIFIX-01 | `flex flex-wrap items-center gap-2 text-xs` | `/assets/Cloud-yWcQ9GU-.js` | **PRESENT** |
|
||||
| UIFIX-01 | `inline-flex shrink-0 items-center gap-1.5` | `/assets/Cloud-yWcQ9GU-.js` | **PRESENT** |
|
||||
| UIFIX-02 | `xl:basis-0` | `/assets/Web5-BvURT8TJ.js` | **PRESENT** |
|
||||
| UIFIX-02 | `min-h-[40rem]` | `/assets/Web5-BvURT8TJ.js` | **PRESENT** |
|
||||
| UIFIX-03 | `One more step below` | `/assets/OnboardingSeedGenerate-C7UXVA3p.js` | **PRESENT** |
|
||||
| UIFIX-04 | `resolveBlobUrl` | `/assets/Cloud-yWcQ9GU-.js` | **PRESENT** |
|
||||
| UIFIX-05 | `lightbox-pip-handoff` | `/assets/MediaLightbox-DKht-qI-.js` + `MediaLightbox-DAsuRYOD.css` | **PRESENT** |
|
||||
| UIFIX-06 | `Opening…` | `/assets/Cloud-yWcQ9GU-.js` | **PRESENT** |
|
||||
|
||||
URL base fetched: **`http://archi-dev-box`** (`index.html`, `sw.js`, and each chunk under `/assets/`).
|
||||
All chunk hashes changed from the pre-deploy build, so this is provably a new build and not a no-op.
|
||||
|
||||
### On-device boot check (real Chromium, on the node)
|
||||
|
||||
Beyond the grep, the deployed bundle was loaded in a real Chromium (Playwright 1.58.2, chromium-1208)
|
||||
against `http://archi-dev-box` at **1440×900** and **390×740**:
|
||||
|
||||
| Viewport | App mounted | Entry script | Console errors | Page errors | Failed requests |
|
||||
|---|---|---|---|---|---|
|
||||
| 1440×900 | yes | `/assets/index--lyLAgu1.js` | 0 | 0 | 0 |
|
||||
| 390×740 | yes | `/assets/index--lyLAgu1.js` | 0 | 0 | 0 |
|
||||
|
||||
Both land on `http://archi-dev-box/login` with a password field. Post-deploy health check reported
|
||||
`Health: OK (200) after 5s`; backend `active`. The entry script matches the served `index.html` and
|
||||
the `sw.js` manifest, so the boot check exercised the same build the grep table describes.
|
||||
|
||||
**This proves the deploy is live and healthy. It proves nothing about any of the six numbered checks.**
|
||||
|
||||
### archy-x250-dev — the second dev-pair node
|
||||
|
||||
**OFFLINE. Recorded as an explicit gap, per the plan's instruction not to wait for it or pretend the
|
||||
pair was covered.**
|
||||
|
||||
```
|
||||
100.113.100.55 archy-x250-dev.tail08d8f2.ts.net ssmithx@ linux
|
||||
active; relay "mad"; offline, last seen 2d ago, tx 5573880 rx 0
|
||||
```
|
||||
|
||||
MagicDNS has no record (`lookup archy-x250-dev ... no such host`), so it cannot even be addressed by
|
||||
name. This continues unbroken from phase 2, where 02-08 checked three times and never found it up.
|
||||
**archy-x250-dev has received neither phase 2's nor this plan set's frontend and still needs the same
|
||||
`--frontend-only` deploy once it is reachable.**
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Six-fix sign-off — NOT DONE (blocking human checkpoint)
|
||||
|
||||
### Per-check status
|
||||
|
||||
| # | Check | Requirement | Status | Why |
|
||||
|---|---|---|---|---|
|
||||
| 1 | Connected-nodes card sibling-matched height + inner scroll, tab-switch stability, single-column unchanged | UIFIX-02 | **NOT VERIFIED** | Needs an authenticated session on the node; no UI password available to this executor |
|
||||
| 2 | Onboarding cue at ~1280×620, click-to-reveal, Continue stays disabled, no cue at full height | UIFIX-03 | **NOT VERIFIED** | Needs an authenticated session; and see the safety note below — this executor will not drive a seed-generation flow on a provisioned node holding real funds |
|
||||
| 3a | Purchased **picture** → row spinner + "Opening…" → app lightbox, no new tab | UIFIX-04 / UIFIX-06 | **NOT VERIFIED** | Needs an authenticated session. The content exists (see below), so this one is genuinely runnable by a human today |
|
||||
| 3b | Purchased **video** → lightbox with player controls | UIFIX-04 | **NOT VERIFIED — and NOT CURRENTLY TESTABLE** | The node owns no purchased video (see below) |
|
||||
| 3c | Purchased **music** → bottom-bar player, not the lightbox | UIFIX-04 | **NOT VERIFIED — and NOT CURRENTLY TESTABLE** | The node owns no purchased audio (see below) |
|
||||
| 3d | Double-click issues one load, not two | UIFIX-06 | **NOT VERIFIED** | Needs an authenticated session |
|
||||
| 4 | PiP handoff animation, survives tab changes, survives a buffering pause, clean explicit close, unchanged normal close/Escape | UIFIX-05 | **NOT VERIFIED — and NOT CURRENTLY TESTABLE** | Requires a video in the lightbox; the node has **no video content at all** (see below) |
|
||||
| 5 | FIPS/Tor pills fully readable at phone width on peer cards and peer files, long names included; desktop unchanged | UIFIX-01 | **NOT VERIFIED** | Needs an authenticated session and a real phone or stated device emulation |
|
||||
| 6 | Nothing else moved — page margins, tab slide transitions, existing animations | (standing visual-invisibility rule) | **NOT VERIFIED** | Needs an authenticated session and human perceptual judgment |
|
||||
|
||||
**Zero of the six numbered checks passed. None of them failed either — none were run.** The plan's
|
||||
transparency prohibition forbids signing any node-named check off on local-preview evidence, and that
|
||||
is all the prior evidence is: 01-12/13/15/17 each verified themselves against a local dev preview or
|
||||
`:4321` build preview, and 01-14 against unit tests only.
|
||||
|
||||
### The two blockers, precisely
|
||||
|
||||
**Blocker A — no authenticated session.** `http://archi-dev-box` redirects to `/login` and requires a
|
||||
password; `POST /rpc/v1 {system.status}` returns `401 Unauthorized`. 02-08 records the node's UI
|
||||
password being supplied out-of-band by the coordinator and passed only via the `ARCHY_PASSWORD`
|
||||
environment variable. It was not supplied for this run. **No credential was guessed** — this node
|
||||
holds real federation trust, real purchases and real funds, and probing passwords against it is not a
|
||||
verification step.
|
||||
|
||||
**Blocker B — missing media on the node.** Settled from the node's own data (read-only, counts and
|
||||
mime types only; no filenames, no content, no seed material read):
|
||||
|
||||
- `/var/lib/archipelago/purchased-content/owned.json` — **1 owned item, mime `image/jpeg`**.
|
||||
So the planner's flagged question is answered: **archi-dev-box does have purchased content, but
|
||||
exactly one item and it is a picture.** Check 3a is runnable on real purchased content today.
|
||||
- **No purchased video and no purchased audio exist**, so checks 3b and 3c cannot be exercised on
|
||||
purchased content on this node at all.
|
||||
- A scan of `content/`, `blobs/`, `filebrowser-data/`, `content/files/`, `~/Files`, `~/Videos`,
|
||||
`~/Music`, `~/Documents` found **zero video files and zero audio files anywhere**. Check 4 (PiP)
|
||||
needs a video in the lightbox and therefore **cannot be run on this node as it stands.**
|
||||
|
||||
Per the plan's own instruction, this is said plainly rather than passed on the demo: **a demo-only or
|
||||
preview-only pass for the paid-content and PiP paths would be exactly the divergence class this phase
|
||||
exists to remove.**
|
||||
|
||||
### What still needs a human at a device
|
||||
|
||||
1. **Supply the archi-dev-box UI password out-of-band** (as in 02-08), or drive the checks by hand in
|
||||
a logged-in browser on the node. Without this, checks 1, 2, 3a, 3d, 5 and 6 cannot start.
|
||||
2. **Put one video file on the node** — upload an `.mp4` through My Files is enough — so check 4 (PiP)
|
||||
and the video half of check 3 have something to open. Without it check 4 is untestable, not failing.
|
||||
3. **Purchase (or seed) one audio item and one video item** if checks 3b/3c are to be run against the
|
||||
genuine Paid Files path rather than My Files. If that is not worth doing, record 3b/3c as
|
||||
permanently deferred with that reason rather than as passed.
|
||||
4. **Use a real phone, or state that device emulation was used**, for checks 1 (narrow), 2 and 5. The
|
||||
plan asks explicitly which was used; this summary cannot answer it.
|
||||
5. **Check 4's buffering-pause sub-step needs devtools network throttling or a long seek** — a human
|
||||
action, on the node's own browser.
|
||||
6. **Check 6 is irreducibly perceptual** ("look exactly as they did before"). Phase 2 broke margins
|
||||
and slide transitions this way once; no script substitutes for the eye here.
|
||||
7. **Re-deploy to `archy-x250-dev` once it comes back** — it is 2 days offline and has neither this
|
||||
plan set's nor phase 2's frontend.
|
||||
|
||||
### Safety note on check 2
|
||||
|
||||
Check 2 exercises the onboarding **seed step**. Threat `T-01-84` in this plan's register covers exactly
|
||||
this: the operator is asked to judge the step's *layout* only. Do not screenshot, photograph,
|
||||
transcribe or paste the recovery words, and do not attach an image of that screen to any summary,
|
||||
issue or chat. This executor did not open that flow at all — beyond the credential blocker, generating
|
||||
or restoring a seed on a provisioned node holding real funds is not a layout check.
|
||||
|
||||
---
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Precondition, satisfied in substance but not in letter — recorded
|
||||
|
||||
Task 1's `<precondition>` names `scripts/deploy-config.sh`. **That file does not exist on this
|
||||
machine.** It was not treated as an unmet precondition after checking what it actually supplies:
|
||||
`scripts/deploy-config.example` shows its only required content is `ARCHIPELAGO_PASSWORD`, and the
|
||||
deploy authenticated fine without it — `ssh -i ~/.ssh/archipelago-deploy archipelago@archi-dev-box`
|
||||
succeeded under `BatchMode=yes` (key auth, symlinked to `id_ed25519`) and `sudo -n true` returned
|
||||
`SUDO_NOPASSWD_OK` on the target. The precondition's stated purpose ("so the deploy script can
|
||||
authenticate") was therefore met by other means, and the deploy's exit code 0 confirms it. Recorded
|
||||
rather than glossed: **if a future run of this plan needs the password path — a different target, or
|
||||
`sudo` tightened on this one — `deploy-config.sh` will have to be created first.**
|
||||
|
||||
### Task 2 not executed; no checkpoint round-trip
|
||||
|
||||
This plan is `autonomous: false` and Task 2 is `checkpoint:human-verify gate="blocking"`. Its
|
||||
verification is a human verdict, which was not obtainable in this run. Rather than stop with nothing
|
||||
recorded, Task 1 was completed in full and the checkpoint's blockers were investigated so that whoever
|
||||
picks it up starts with the environment already proven ready (bundle confirmed live) and the two
|
||||
practical obstacles already identified and quantified. **The plan is not complete and UIFIX-01..06 are
|
||||
not closed.**
|
||||
|
||||
### Plan-state files deliberately not updated
|
||||
|
||||
`STATE.md`, `ROADMAP.md` and `REQUIREMENTS.md` were **not** modified and **not** committed:
|
||||
`.planning/STATE.md` was already dirty with a concurrent executor's edit, the execution brief limited
|
||||
this plan's commit to this SUMMARY alone, and — most importantly — **marking UIFIX-01..06 complete
|
||||
would be false** while the sign-off that closes them is unanswered.
|
||||
|
||||
### No source file modified, no fix applied
|
||||
|
||||
`files_modified: []` was honoured. Nothing was found that needed fixing, but the standing rule for
|
||||
this run was that a genuine bug would be recorded as a finding, not patched inline, because three
|
||||
other executors held the same working tree throughout.
|
||||
|
||||
## Findings
|
||||
|
||||
1. **The assets directory on the node is never pruned.** `/opt/archipelago/web-ui/assets` holds many
|
||||
generations of hashed chunks (the deploy's `rm -rf` excludes `aiui`/`claude-login.html` but the
|
||||
directory still showed several `Cloud-*.js`, `Web5-*.js` and `MediaLightbox-*.js` hashes
|
||||
simultaneously). Harmless at runtime — the entry chunk and `sw.js` pin the live set — but it makes
|
||||
any disk-side "is the fix deployed?" grep unreliable, and it silently inflates the directory.
|
||||
Not fixed here (out of scope). Anyone verifying a deploy by grep must resolve the live set from
|
||||
`sw.js` first, as this plan did.
|
||||
2. **The container doctor applied 2 fixes during the deploy** (`rootless-ports` restart of
|
||||
`netbird-server` for a missing 3478 listener, and an NPM public-hosts sync), 12 checks passed. This
|
||||
is the deploy script's normal behaviour, noted only because it means the deploy was not purely a
|
||||
frontend file copy.
|
||||
3. **`⚠️ No ANTHROPIC_API_KEY found`** during the Claude API proxy step — pre-existing on this node,
|
||||
unrelated to this plan, not acted on.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — this plan wrote no code.
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None. No new endpoint, auth path, file-access pattern or schema change.
|
||||
|
||||
Threat register status:
|
||||
- **T-01-82** (verification deploy reaching fleet/alpha-tester nodes) — **mitigated**: frontend-only
|
||||
dev-pair path, no Tailscale/alpha-tester/`--both`/`--fleet` flag, no release or OTA path; exact
|
||||
command and single-host list recorded above and corroborated by the node's own deploy manifest.
|
||||
- **T-01-83** (signing off against a stale bundle) — **mitigated, and the threat was real**: the naive
|
||||
disk-side grep would have produced false hits from dead chunks. Verified instead against the live
|
||||
`sw.js` chunk set fetched over HTTP.
|
||||
- **T-01-84** (a seed exposed by check 2's verification) — **mitigated**: the onboarding seed flow was
|
||||
not opened, nothing was captured, and the warning is restated for whoever runs check 2.
|
||||
- **T-01-85** (a demo/preview-only pass recorded as a node pass) — **mitigated**: no check is marked
|
||||
passed. The node's purchased-content inventory (1 image, 0 video, 0 audio) is stated explicitly so
|
||||
the paid-content path cannot be quietly signed off on the demo.
|
||||
- **T-01-SC** (package installs) — nothing installed. `npm install --silent` inside the deploy ran
|
||||
against the existing committed lockfile and left `neode-ui` clean; no dependency added.
|
||||
|
||||
## Self-Check: PASSED
|
||||
|
||||
- `.planning/phases/01-federation-mesh-hardening/01-18-SUMMARY.md` — FOUND (this file)
|
||||
- Deployed commit `527f6023` — FOUND on the node in `/opt/archipelago/deploy-manifest.json`
|
||||
- `8255b69a`, `ceafbcb5`, `b5628d96`, `bc9a210c`, `3288a02d` — all confirmed ancestors of `527f6023`
|
||||
- Served chunks `Cloud-yWcQ9GU-.js`, `Web5-BvURT8TJ.js`, `MediaLightbox-DKht-qI-.js`,
|
||||
`OnboardingSeedGenerate-C7UXVA3p.js` — all fetched over HTTP from `http://archi-dev-box` and grepped
|
||||
- `git status --short -- release-manifest.json releases/ app-catalog/` — empty
|
||||
- `git status --short -- neode-ui web` — empty
|
||||
- No source file modified by this plan
|
||||
|
||||
---
|
||||
*Phase: 01-federation-mesh-hardening*
|
||||
*Task 1 complete 2026-08-02. Task 2 open — awaiting a human at the device.*
|
||||
Reference in New Issue
Block a user