228 lines
15 KiB
Markdown
228 lines
15 KiB
Markdown
---
|
||||
|
|
phase: 01-federation-mesh-hardening
|
|||
|
|
plan: 18
|
|||
|
|
type: execute
|
|||
|
|
wave: 9
|
|||
|
|
depends_on: ["01-12", "01-13", "01-14", "01-15", "01-17"]
|
|||
|
|
files_modified: []
|
|||
|
|
autonomous: false
|
|||
|
|
requirements: [UIFIX-01, UIFIX-02, UIFIX-03, UIFIX-04, UIFIX-05, UIFIX-06]
|
|||
|
|
gap_closure: true
|
|||
|
|
|
|||
|
|
must_haves:
|
|||
|
|
truths:
|
|||
|
|
- "All six UI fixes are exercised on real node hardware, not only on the local preview, because two of them are about how the app behaves on a device rather than in a viewport"
|
|||
|
|
- "The connected-nodes list scrolls at a sibling-matched height on the node's own screen and at a phone width"
|
|||
|
|
- "The onboarding tickbox is discoverable on a genuinely short viewport on the node"
|
|||
|
|
- "A purchased picture opens in the app's lightbox on the node, with the wait visible"
|
|||
|
|
- "Picture-in-picture closes the lightbox with a handoff and survives a real tab change and a real buffering pause on the node"
|
|||
|
|
- "The FIPS/Tor pills are readable at phone width on the node"
|
|||
|
|
- "Every surface that was not supposed to change is confirmed unchanged on the node — the standing visual-invisibility rule is verified, not assumed"
|
|||
|
|
prohibitions:
|
|||
|
|
- statement: "This phase's frontend MUST NOT be deployed beyond the dev pair — no OTA, no release, no fleet node, no alpha-tester path; a verification step is never a reason to widen a deploy"
|
|||
|
|
category: safety
|
|||
|
|
- statement: "Sign-off MUST NOT be given on local-preview evidence alone for any check that names the node — the local preview and a real device disagree exactly where these fixes matter, which is why phase 2's on-device pass found four issues the preview did not"
|
|||
|
|
category: transparency
|
|||
|
|
artifacts: []
|
|||
|
|
key_links: []
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
<objective>
|
|||
|
|
Put all six UI fixes in front of a human, on the node, once.
|
|||
|
|
|
|||
|
|
Purpose: each of plans 01-12 through 01-17 verifies itself with tests and a local-preview observation,
|
|||
|
|
which is the right granularity for an autonomous plan but is not sufficient evidence for a
|
|||
|
|
user-reported blocker. Two of these fixes — picture-in-picture surviving a tab change, and the pills
|
|||
|
|
at phone width — are about device behaviour that a desktop preview cannot reproduce. Rather than
|
|||
|
|
interrupting five plans with five checkpoints, they are gathered here so the operator is asked once,
|
|||
|
|
after the code is on archi-dev-box. This mirrors how plan 01-10 consolidates the federation and
|
|||
|
|
Lightning sign-offs.
|
|||
|
|
Output: a recorded sign-off, or a numbered issue list that becomes the input to a gap-closure pass.
|
|||
|
|
</objective>
|
|||
|
|
|
|||
|
|
<execution_context>
|
|||
|
|
@$HOME/.claude/gsd-core/workflows/execute-plan.md
|
|||
|
|
@$HOME/.claude/gsd-core/templates/summary.md
|
|||
|
|
</execution_context>
|
|||
|
|
|
|||
|
|
<context>
|
|||
|
|
@.planning/PROJECT.md
|
|||
|
|
@.planning/STATE.md
|
|||
|
|
@.planning/phases/01-federation-mesh-hardening/01-12-SUMMARY.md
|
|||
|
|
@.planning/phases/01-federation-mesh-hardening/01-13-SUMMARY.md
|
|||
|
|
@.planning/phases/01-federation-mesh-hardening/01-14-SUMMARY.md
|
|||
|
|
@.planning/phases/01-federation-mesh-hardening/01-15-SUMMARY.md
|
|||
|
|
@.planning/phases/01-federation-mesh-hardening/01-17-SUMMARY.md
|
|||
|
|
</context>
|
|||
|
|
|
|||
|
|
<tasks>
|
|||
|
|
|
|||
|
|
<task type="auto">
|
|||
|
|
<name>Task 1: Put the six fixes on archi-dev-box, frontend only, dev pair only</name>
|
|||
|
|
<files>none — this task builds, deploys and verifies delivery; it modifies no file in the repository</files>
|
|||
|
|
<precondition>archi-dev-box resolves and answers over HTTP from this machine, and `scripts/deploy-config.sh` exists (it is gitignored; `scripts/deploy-config.example` documents it) so the deploy script can authenticate</precondition>
|
|||
|
|
<read_first>
|
|||
|
|
- `scripts/deploy-to-target.sh` lines 1-30 — the usage block. `--frontend-only` skips the Rust
|
|||
|
|
build and container rebuilds; `--live` targets the default host; `--both` fans out to additional
|
|||
|
|
hosts; `--tailscale` reaches the alpha-tester nodes and must not be used here.
|
|||
|
|
- `.planning/phases/02-ui-performance/02-08-SUMMARY.md` — the exact command phase 2 used for the
|
|||
|
|
same kind of dev-pair frontend deploy, and its record of archy-x250-dev being offline. Reuse the
|
|||
|
|
command shape rather than inventing one.
|
|||
|
|
- The five plan SUMMARYs listed in `<context>` — specifically each one's recorded local-preview
|
|||
|
|
observations, so you know what the node is expected to reproduce.
|
|||
|
|
</read_first>
|
|||
|
|
<action>
|
|||
|
|
Build the frontend and deploy it to archi-dev-box with the dev-pair frontend-only path. Record the
|
|||
|
|
exact command in the SUMMARY.
|
|||
|
|
|
|||
|
|
Do not use the Tailscale or alpha-tester paths, do not cut a release, do not touch the OTA manifest,
|
|||
|
|
and do not deploy to any fleet node. Note that this plan set's FED-07 work is backend and is
|
|||
|
|
verified separately by plan 01-16 — this deploy is frontend only.
|
|||
|
|
|
|||
|
|
Check whether archy-x250-dev is reachable. It has been offline since phase 2. If it is still
|
|||
|
|
offline, record that plainly as a gap rather than waiting for it or pretending the pair was
|
|||
|
|
covered; single-node verification on archi-dev-box with the second-node gap recorded honestly is
|
|||
|
|
the expected pattern for this phase.
|
|||
|
|
|
|||
|
|
Then confirm the node is actually serving this build before handing over to the checkpoint — fetch
|
|||
|
|
the served bundle from archi-dev-box and grep it for strings this plan set introduced (the
|
|||
|
|
onboarding cue copy, the picture-in-picture handoff class, and the paid-item viewer). Grep the
|
|||
|
|
served asset, not the local `web/dist` copy: per CLAUDE.md the frontend build can silently no-op,
|
|||
|
|
and a checkpoint run against a stale bundle is worse than no checkpoint.
|
|||
|
|
</action>
|
|||
|
|
<verify>
|
|||
|
|
<automated>curl -fsS --max-time 20 "${ARCHY_DEV_URL:?set ARCHY_DEV_URL to archi-dev-box's UI base URL}/" -o /dev/null && echo served</automated>
|
|||
|
|
</verify>
|
|||
|
|
<acceptance_criteria>
|
|||
|
|
- The SUMMARY records the exact deploy command and the host list it targeted, and that list contains no fleet, alpha-tester or Tailscale host.
|
|||
|
|
- The SUMMARY records the served-bundle grep result for all three introduced strings, naming the URL fetched.
|
|||
|
|
- The SUMMARY records archy-x250-dev's reachability, and if unreachable records it as an explicit gap.
|
|||
|
|
- No release artifact, OTA manifest or catalog was modified — `git status --short -- release-manifest.json releases/ app-catalog/` is empty.
|
|||
|
|
</acceptance_criteria>
|
|||
|
|
<done>archi-dev-box is serving a bundle that provably contains all six fixes, and the second-node gap is recorded.</done>
|
|||
|
|
</task>
|
|||
|
|
|
|||
|
|
<task type="checkpoint:human-verify" gate="blocking">
|
|||
|
|
<name>Task 2: Six-fix sign-off on archi-dev-box</name>
|
|||
|
|
<what-built>
|
|||
|
|
Six user-reported UI issues, now on archi-dev-box:
|
|||
|
|
- **Connected nodes (UIFIX-02).** On the Web5 tab, the connected-nodes card no longer grows to fit
|
|||
|
|
every node. Its height now comes from the card beside it in the row and the list scrolls inside
|
|||
|
|
that height, with a floor so a short neighbour cannot squash it. Below the two-column breakpoint
|
|||
|
|
nothing changed.
|
|||
|
|
- **Onboarding tickbox (UIFIX-03).** On a screen too short to show the whole seed step, a soft
|
|||
|
|
gradient and a small glass pill reading "One more step below" now appear at the bottom edge of
|
|||
|
|
the scrolling area. Clicking it scrolls the confirmation tickbox into view, and it disappears
|
|||
|
|
once the tickbox is visible. On a tall screen it never appears at all.
|
|||
|
|
- **Paid Files pictures (UIFIX-04).** Purchased pictures and videos now open in the app's own
|
|||
|
|
lightbox instead of a browser tab. Purchased music still goes to the bottom-bar player, and
|
|||
|
|
purchased documents still open the way they did.
|
|||
|
|
- **Loader states (UIFIX-06).** Opening a purchased file now shows a spinner and an "Opening…"
|
|||
|
|
label on its row for as long as the fetch takes, and a failure now shows an error instead of
|
|||
|
|
appearing to do nothing. Every other surface that was flagged as slow was audited and its verdict
|
|||
|
|
recorded.
|
|||
|
|
- **Picture-in-picture (UIFIX-05).** Entering picture-in-picture now closes the lightbox with a
|
|||
|
|
handoff animation, and the video keeps playing. The session survives switching main tabs and
|
|||
|
|
survives buffering pauses; only explicitly stopping it ends it.
|
|||
|
|
- **FIPS/Tor pills (UIFIX-01).** The pills are now pinned by a test so no future cleanup can remove
|
|||
|
|
them, and every site that could not be read at phone width was fixed.
|
|||
|
|
</what-built>
|
|||
|
|
<how-to-verify>
|
|||
|
|
Run all of this against archi-dev-box's own UI, not the local preview. Use a real phone or the
|
|||
|
|
browser's device emulation for the narrow checks, and say which you used.
|
|||
|
|
|
|||
|
|
1. **Connected nodes scroll (UIFIX-02).** Open the Web5 tab on a wide window. Expected: the
|
|||
|
|
connected-nodes card and the card to its right are the same height, and if there are more nodes
|
|||
|
|
than fit, the list scrolls inside the card — the row does not get taller. Switch between the
|
|||
|
|
trusted, observers and requests tabs: expected the card's height does not change. Then narrow the
|
|||
|
|
window to a single column: expected exactly the layout you had before this change.
|
|||
|
|
|
|||
|
|
2. **Onboarding cue (UIFIX-03).** Open the onboarding seed step at a short viewport (a small laptop
|
|||
|
|
height, or device emulation at roughly 1280×620). Expected: a soft fade and a small pill reading
|
|||
|
|
"One more step below" at the bottom of the scrolling area; clicking it brings the tickbox into
|
|||
|
|
view and the cue disappears. Confirm the cue does not tick the box for you and the Continue
|
|||
|
|
button stays disabled until you tick it yourself. Then open the same step at full height:
|
|||
|
|
expected no cue at all and a step that looks exactly as it did before.
|
|||
|
|
|
|||
|
|
3. **Paid Files in the lightbox (UIFIX-04) and the loader (UIFIX-06).** Go to Cloud → Paid Files
|
|||
|
|
and click a purchased picture. Expected: the row shows a spinner and "Opening…" while it loads,
|
|||
|
|
then the picture opens in the app's lightbox — no new browser tab. Click a purchased video:
|
|||
|
|
expected the same, in the lightbox with player controls. Click a purchased music track: expected
|
|||
|
|
the bottom-bar player, not the lightbox. If you can, click one twice quickly: expected one load,
|
|||
|
|
not two.
|
|||
|
|
|
|||
|
|
4. **Picture-in-picture (UIFIX-05).** Open a video in the lightbox and click the
|
|||
|
|
picture-in-picture button. Expected: the lightbox animates away in a way that reads as the video
|
|||
|
|
moving into the small window rather than the lightbox being dismissed, and the video keeps
|
|||
|
|
playing. Now switch between main tabs a few times: expected playback continues. Now cause a
|
|||
|
|
buffering pause — throttle the network in devtools, or seek far ahead: expected it recovers and
|
|||
|
|
the small window stays. Now close the small window explicitly: expected playback stops and
|
|||
|
|
nothing is left behind. Finally open the lightbox again and close it with the close button and
|
|||
|
|
with Escape: expected exactly the close animation it had before.
|
|||
|
|
|
|||
|
|
5. **FIPS/Tor pills at phone width (UIFIX-01).** At a phone width, go to Cloud and look at the peer
|
|||
|
|
cards, then open a peer's files. Expected: wherever a FIPS or Tor pill appears on desktop it
|
|||
|
|
appears here too, fully readable, not clipped and not overlapping anything, including when a peer
|
|||
|
|
name or filename is long. Compare the same screens at desktop width: expected unchanged.
|
|||
|
|
|
|||
|
|
6. **Nothing else moved.** Move through the main tabs and the Cloud sub-tabs. Expected: the page
|
|||
|
|
margins, the slide transitions between tabs, and every existing animation look exactly as they
|
|||
|
|
did before this plan set. Phase 2 broke margins and slide transitions this way once, so this is a
|
|||
|
|
real check, not a formality.
|
|||
|
|
|
|||
|
|
If anything fails, say which numbered step and what you saw — that becomes the gap list rather than
|
|||
|
|
a re-run of the whole plan set.
|
|||
|
|
</how-to-verify>
|
|||
|
|
<resume-signal>Type "approved" to sign off UIFIX-01 through UIFIX-06, or describe the issues by step number.</resume-signal>
|
|||
|
|
</task>
|
|||
|
|
|
|||
|
|
</tasks>
|
|||
|
|
|
|||
|
|
## Planner Assumptions (flagged, unresolved)
|
|||
|
|
|
|||
|
|
- **archy-x250-dev is assumed to still be offline.** Phase 2 checked three times and found it gone.
|
|||
|
|
Task 1 re-checks rather than assuming, and records the gap either way; nothing in this plan blocks on
|
|||
|
|
it.
|
|||
|
|
- **Whether archi-dev-box has purchased content to test step 3 with** is unknown to the planner. If it
|
|||
|
|
has none, say so in the sign-off rather than marking step 3 passed on the demo — a demo-only pass for
|
|||
|
|
a paid-content path is exactly the divergence class this phase exists to remove.
|
|||
|
|
|
|||
|
|
<threat_model>
|
|||
|
|
## Trust Boundaries
|
|||
|
|
|
|||
|
|
| Boundary | Description |
|
|||
|
|
|----------|-------------|
|
|||
|
|
| operator judgement → sign-off | A human verdict gates whether these six blockers are considered closed |
|
|||
|
|
| deploy host → node | A frontend bundle crosses this boundary onto a live node |
|
|||
|
|
| live node → operator observation | Verification runs against a real node holding real federation trust, real purchases and real funds |
|
|||
|
|
|
|||
|
|
## STRIDE Threat Register
|
|||
|
|
|
|||
|
|
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
|||
|
|
|-----------|----------|-----------|----------|-------------|-----------------|
|
|||
|
|
| T-01-82 | Elevation of Privilege | a verification deploy reaching fleet or alpha-tester nodes | high | mitigate | Task 1 requires the frontend-only dev-pair path, forbids the Tailscale and alpha-tester flags and any release or OTA path, and requires the exact command and host list to be recorded for audit |
|
|||
|
|
| T-01-83 | Repudiation | signing off against a stale bundle the node never actually received | high | mitigate | Task 1 requires grepping the bundle served by the node — not the local build output — for three strings this plan set introduced, before the checkpoint runs |
|
|||
|
|
| T-01-84 | Information Disclosure | a screenshot or recording of the verification exposing a recovery seed from step 2 | high | mitigate | Step 2 exercises the onboarding step's layout only; the operator is not asked to capture or transcribe the words, and nothing in this plan asks for an image of that screen |
|
|||
|
|
| T-01-85 | Repudiation | a demo-only pass on the paid-content path being recorded as a node pass | medium | mitigate | The prohibition forbids local-preview evidence for node-named checks, and the planner assumption requires saying so explicitly if the node has no purchased content |
|
|||
|
|
| T-01-SC | Tampering | npm/pip/cargo installs | high | mitigate | This plan installs nothing and modifies no source file — it builds, deploys and asks. If a fix arising from the checkpoint needs a dependency, it belongs in a gap-closure plan whose research covers the Package Legitimacy Gate first |
|
|||
|
|
</threat_model>
|
|||
|
|
|
|||
|
|
<verification>
|
|||
|
|
The operator's response is the verification. An "approved" response closes UIFIX-01 through UIFIX-06;
|
|||
|
|
any described issue is captured verbatim in the SUMMARY as a gap for `/gsd-plan-phase 1 --gaps`.
|
|||
|
|
</verification>
|
|||
|
|
|
|||
|
|
<success_criteria>
|
|||
|
|
- All six numbered checks were exercised on archi-dev-box, at the widths each one names.
|
|||
|
|
- The operator either approved or produced a numbered issue list.
|
|||
|
|
- The outcome is recorded in the SUMMARY, including which device or emulation was used for the narrow checks.
|
|||
|
|
- The archy-x250-dev gap is recorded rather than glossed over.
|
|||
|
|
</success_criteria>
|
|||
|
|
|
|||
|
|
<output>
|
|||
|
|
Create `.planning/phases/01-federation-mesh-hardening/01-18-SUMMARY.md` when done, recording the
|
|||
|
|
verdict, the deploy command, the served-bundle grep evidence, the device used for narrow checks, and
|
|||
|
|
any issue text verbatim.
|
|||
|
|
Stage by explicit path, commit, and `git push gitea-ai main`.
|
|||
|
|
</output>
|