Files
archy/docs/external-access-and-websites.md
T

645 lines
41 KiB
Markdown
Raw Normal View History

# External access and website publishing
Approved on 2026-10-08. Worktree: `archy-external-access`; branch:
`work/external-access-websites`; base: `c57119e9`. The release checkout,
services, build directories, artifacts and publication refs are not work areas.
## Product contract
AI creation uses Routstr by default, with Claude and OpenAI API-key choices in
the trusted dashboard. The operator explicitly approved these optional API
providers. Reuse the node's ecash receive flow for top-ups; funding must not change
the spending allowance or trigger inference. Preserve saved provider choices.
Ollama is deprioritized and its live-model test is not a release prerequisite for
this work; older progress entries below describe the superseded local-model path.
Setup offers Allow external connections and Publish a website. Both use node-owned
connection state. Each app or site can select FIPS, public HTTPS, Tor, and (static
sites only) Nostr publication together. Each route has independent status and
revocation. Configured, locally available, and externally verified are different
states. Never infer public reachability from a saved record or running daemon.
Reuse existing FIPS IPv6 ingress, AppGate and IPv4 loopback backends. Never widen
container bindings as a blanket IPv6 migration. Preserve local-only APIs and
wallet/admin exclusion policies. Existing routes are not adopted or revoked
without an explicit ownership handoff. Private route success does not satisfy a
public website's prerequisite. Removing one publication must retain shared routes.
All required components are open source and self-hostable. No Tailscale or
proprietary control-plane dependency. Public routing uses frp with TLS terminating
on the node; gateways are selectable and replaceable. DNS and gateways remain
operator dependencies, even when their software is open source.
Consider Nostr first wherever an existing standard fits: FIPS identity/discovery,
NIP-5A/nsyte/Blossom for optional static-site replication, existing signing flows,
and ngit contribution/review. Public announcements and replication require an
explicit choice. Keys and infrastructure credentials never enter model context.
Mynymbox is an optional external Bitcoin/Lightning domain checkout. Explain its
registrant-of-record model. Generate exact DNS record instructions for the chosen
route; support existing domains and free addresses. Preserve mail records and
verify authoritative DNS, hostname routing, TLS and external HTTP independently.
FIPS/onion addresses do not require a purchased domain. No automatic purchases.
AIUI creates node-owned static website projects with isolated previews, revisions,
download, publish, rollback and unpublish. Local/open model operation is supported;
no silent fallback to a proprietary model. A published website has a separate
origin from management and cannot read dashboard cookies or access signing
authority or RPC. Direct FIPS ports share a hostname, so a browser may send
host cookies to the trusted static handler; it neither reflects nor forwards
them, and published HTML runs under a script-blocking sandbox policy. Public
copies may survive unpublishing from Nostr/Blossom.
The user also requested removal of the File Browser Setup card because the app
is already bundled in the ISO. Keep the installed app and launcher unchanged.
## Implementation and acceptance ledger
- [x] Isolated worktree and branch created.
- [ ] Persistent, versioned project and multi-route configuration; conflict-safe writes.
- [ ] Both Setup entry points and shared connection readiness.
- [ ] DNS guidance with Mynymbox handoff and correct per-route records.
- [ ] Static site workspace, local model generation, isolated preview and version history.
- [ ] FIPS publication and revocation through owned listeners/policies.
- [ ] Public HTTPS/frp configuration, scoped enrollment and node TLS lifecycle.
- [ ] Tor publication preserving service identity through restart.
- [ ] NIP-5A signing and Blossom replication with explicit consent and pinned versions.
- [ ] Per-app restricted access without sharing administrator credentials.
- [ ] External verification, certificate renewal, restarts, rollback and route isolation.
- [ ] Framework acceptance with confirmed identity, access and release coordination.
- [ ] ngit review and exact accepted-commit mirror parity before any release.
The user authorized Framework as a free test node and a separate test proxy route
on Yaya. Access has been verified on both actual nodes. Preserve all
wallet/channel/app data. Source tests are not node acceptance. Backend unit tests
run only through `scripts/test-backend-isolated.sh`; use a worktree-local target.
### Current integration checkpoint
The operator reaffirmed the existing Setup walkthrough design during UAT.
The follow-up UI uses the existing numbered goal cards, progress styling and
Back/Continue navigation, with one expanded step. Previously saved connections
are reused; installed Blossom omits the installation step. Blossom installation
uses the normal app-store installer. Navigation itself never saves, signs or
publishes. This UI revision is now active on Framework. The actual dashboard walkthrough
saved the synthetic draft, archived it in local Blossom with a profile identity,
fetched it back to verify exact bytes, and published it through FIPS port 32000.
The 390-pixel mobile layout passed the overflow check. Browser request monitoring
recorded no external requests during this journey.
Live archive acceptance exposed an older `node-*` identity whose `is_node` flag
was false. The container correctly rejected its upload because the canonical
signer allowlist excludes legacy node records. The website identity filter now
matches that rule, including node-name fallbacks and public-key validation, and
checks it again before signing. No public Nostr event or external replica was
created during this failure. The selected 20-test suite covers the regression and
walkthrough navigation; the production typecheck and Vite build passed. A further
new-project connection-inheritance check passed, giving eight Setup and thirteen
Nostr tests for the revised UI.
Blossom is installed and healthy on Framework through the normal app installer.
Protocol, real HTTP/HTTPS tab signing and lifecycle/data-preservation evidence is
recorded in `apps/blossom/README.md`. The combined dashboard/backend candidate
from local commit `28a92fcc` is now deployed privately on Framework. The
authenticated publishing status probe passes; native Bitcoin/LND process IDs and
start times are unchanged. Complete browser acceptance is still in progress. No public Nostr test events or external file replicas have
been created. The earlier standalone proxy route/certificate were removed. A new owned UAT
route now connects the dashboard-published synthetic site to
`https://free.archipelago.builders` through Yaya. Trusted TLS, exact page bytes,
`/rpc` returning 404, and traversal rejection (400) pass. The route remains for UAT;
FIPS/HTTPS revocation retained the Tor publication and archive, and Tor
revocation retained HTTPS. Republishing retained the onion hostname. The existing
Yaya Tor client timed out after republish, while a separate fresh Tor client
fetched the exact restored page; do not treat the first timeout as a confirmed
publisher defect or a universal reachability pass. Temporary notice logging was
removed and the isolated test client was stopped after qualification.
A management-service restart retained exact project/archive state, all app
container IDs/states, and native Bitcoin/LND PIDs/start times. Public HTTPS and
Tor both returned exact content after that restart. A full machine reboot is
separate and awaits the operator's recovery arrangement. The actual dashboard
Blossom iframe passed profile selection, explicit denial with zero uploads, and
an approved local upload through the canonical signer. Physical companion
acceptance remains separate; this was a browser iframe test.
The operator requested a further UX pass informed by all existing guides. The
seven existing goal guides, help tree, shared walkthrough and onboarding patterns
were reviewed. The revised flow uses concise visitor-oriented multiselect cards,
an AIUI-first creation path, optional HTML/model controls, a saved-version preview,
explicit Save and continue, and contextual Help entries. The Home shortcuts now
respect the same dedicated guide routes as the Setup cards. The final polish is active on Framework. The production typecheck and build pass,
as do 23 focused tests. The deployed flow again passed real draft save, local
Blossom archive/readback, FIPS publishing and the mobile overflow check, with zero
external browser requests. It preserves original Setup visuals, a single main
Save and continue action, keyboard focus/scroll handling, and visible revoke
controls even when an already-published route is deselected.
No local Ollama service responded on Framework; live model generation remains
unqualified. No proprietary fallback was used or added.
New source work includes local Blossom website archives, explicit app-only guest
credentials, and an on-demand HTTPS check against exact published page bytes.
Guest tokens cannot authenticate to node login; scope/expiry are checked on each
request, and revocation affects subsequent requests, not established streams.
Only opted-in gated app manifests expose guest access. Persistent credentials use
serialized, atomic 0600 writes and refuse corruption/capacity without evicting an
existing device. HTTPS checks pin validated public DNS addresses, validate TLS,
refuse redirects/proxies and bound response reads. They are point-in-time checks
from the node, not proof of outside-device access or future certificate renewal.
Public-web projects can explicitly publish a FIPS upstream for an existing proxy
without selecting FIPS again. The confirmation still explains its FIPS visibility.
Automated frp enrollment/end-to-node TLS and selective local public Blossom assets
remain unfinished. Source validation and standalone routes must not be described
as acceptance of those features or of the complete dashboard journey.
The current dashboard production build and supported AIUI build both pass and
are activated on Framework. The original backend and full web tree remain
backed up for rollback. The selected
dashboard suite passed 36 tests; subsequent HTTPS UI coverage passed six tests,
and tightened Nostr signing/receipt coverage passed 12 tests. The latest combined
18-test run, TypeScript check and dashboard rebuild passed. Catalog drift is zero
(37 catalog entries, 64 manifests). Full isolated backend validation now passes
1,699 tests, zero failures and four explicit ignores. The focused app-gate run
passes 53 tests, and all three credential tests pass. The deployable backend build
passed. Its stripped deployment artifact SHA-256 is
`11e571a7636779d7a956f9e98dab951f19de12262cf89e5ea478cdc8ba864eae`.
Passing tests and the initial authenticated activation probe do not establish
complete live-node acceptance. The private catalogue signing ceremony remains
pending; six app-sharing policies have not yet been activated.
## Development evidence (2026-10-08, not release acceptance)
Latest addition: [Blossom candidate package and acceptance ledger](../apps/blossom/README.md).
Setup offers catalogue installation and skips that prompt for installed Blossom.
The candidate is built and protocol-tested on Framework, and normal installation
and the real HTTPS tab signer work. Further lifecycle acceptance is in progress.
The operator temporarily disabled dashboard 2FA for tests; restore it afterwards.
Nostr publication now includes a local
preparation/review step showing exact HTML, hash, identity, manifest and destinations;
upload and announcement require explicit consent. No public Nostr events or external
Blossom uploads have been performed. Local Blossom website-asset integration remains
outstanding. Earlier evidence below records its own point in development.
The isolated branch now contains versioned node-owned projects, multi-route
preferences, both Setup screens, local Ollama draft generation, sandboxed static
previews, revision restore and FIPS-only static publication/revocation. AIUI can
hand HTML to Setup for explicit import. Public HTTPS, Tor and Nostr adapters and
per-app grants remain outstanding; selecting a route does not enable it.
The File Browser Setup card has been removed as requested. Its catalog entry and
launcher remain intact. No installed applications were changed.
The backend compilation passed, including the supervisor snapshot repair. Eleven focused backend tests passed
through the isolated runner, including the actual publishing and FIPS interface
modules. The initial frontend typecheck and six publishing tests passed. Later
AIUI handoff checks subsequently passed: AIUI typechecking, dashboard typechecking,
and 30 bridge/import tests, including rejection of messages from another frame or
origin. The earlier combined dashboard run passed 52 tests. These are source
checks, not full application deployment acceptance.
Framework access and availability were confirmed by the operator. Read-only SSH
inspection identified framework-pt and its installed FIPS 0.4.1. Yaya access was
also confirmed; its reverse proxy has the existing archipelago.builders route.
The operator subsequently confirmed Yaya is free and explicitly authorized a
separate test route. The standalone production publisher driver ran on Framework
under `archy-publishing-smoke.service`, using only
`/home/archipelago/publishing-smoke`. The main backend was not replaced or
restarted. No wallet, channel, application data or DNS settings were changed.
Live checks completed:
- Two temporary static sites used FIPS ports 32000 and 32001. Yaya fetched the
first over FIPS with HTTP 200 and the restrictive CSP intact.
- Restarting only the test publisher retained the sites. Unpublishing the first
closed its listener and removed its rule while the second still returned 200.
- Temporarily removing the test state file closed the second listener and removed
its allowance. Restoring the file restored the publication. This validates the
repaired stale-snapshot failure case.
- NPM proxy host 9 routed only `free.archipelago.builders` to Framework's second
FIPS site. Certificate 16 was issued successfully. Public HTTPS returned the
expected page with normal certificate verification; `/rpc` returned 404 and
`/../../etc/passwd` was rejected with 400.
- Unpublishing the remaining site left no website allowances or listeners. The
proxy request timed out without returning the old page (not a claimed 404 or
verified friendly error page).
- The temporary publisher was stopped; its empty owned firewall drop-in was
removed and the FIPS baseline reapplied. Framework's main backend remained
active. Test proxy host 9 was deleted; certificate cleanup is checked separately.
This proves the static serving module and the existing-proxy/FIPS path. It does
not prove dashboard RPC integration on Framework, full-node reboot recovery,
certificate renewal, automated gateway enrollment, Tor or Nostr publishing. The
test HTTPS setup terminated TLS at the operator's proxy; end-to-node TLS for a
new frp gateway is still separate outstanding work.
## Research links
- FIPS master `57bc5108f708258c67dfc713e98e6bbb5a828e95` (2026-10-07), latest release
v0.5.2: https://github.com/jmcorgan/fips . Gateway forwards accept IPv6 targets;
Archipelago already has a separate FIPS-to-IPv4 relay and an IPv6-capable AppGate.
- frp: https://github.com/fatedier/frp (Apache-2.0).
- nsyte: https://github.com/sandwichfarm/nsyte (MIT).
- NIP-5A: https://github.com/nostr-protocol/nips/blob/master/5A.md (draft).
- Mynymbox: https://mynymbox.io/domainregistration and
https://mynymbox.io/docs?doc=domains/dns-records .
## Tor website adapter
Website publication uses a dedicated child Tor process with `SocksPort 0` and
`ControlPort 0`, explicit owned configuration, and 0700 identity/runtime directories
under `publishing/onions`. It does not regenerate app Tor configuration or restart
the system Tor daemon. Each onion forwards only to its own static listener on
127.0.0.1:32100–32131. Removing a website closes that listener before reloading
this owned process; the other onions and all private keys are retained. The
process exits when there are no published onion websites. No key wipe is part of
unpublishing. The UI distinguishes having an onion address from verified external
reachability.
A standalone candidate on Framework served the second temporary onion to Yaya's
Tor client with HTTP 200 and the expected CSP. After unpublishing the first onion,
the second still returned 200. Republishing the first retained its hostname; a
publisher restart also retained that hostname. The existing system Tor process
remained PID 1449 throughout these checks. A fresh external fetch after restart
and final cleanup are recorded below when complete.
Source validation now includes per-transport revoke isolation, Tor configuration
path/port constraints and shared connection preferences. All 12 isolated backend
tests passed; the latest selected frontend run passed 36 tests and typechecking.
The AIUI package typecheck passed separately. The final integrated backend check
passed. NPM test certificate 16 was successfully deleted after proxy
host 9; no test proxy remains on Yaya.
The fresh external fetch of the first onion after republish and publisher restart
returned HTTP 200 with the original hostname and expected page. Both test onions
were then unpublished and the smoke unit stopped. Only system Tor PID 1449
remained; no website listeners or owned FIPS drop-in remained. Both onion identity
directories were preserved. The final state-directory durability change passed
the 12-test isolated backend suite as well.
### Walkthrough layout correction — 2026-10-08
The publishing guides now use the same available width and step alignment as
GoalDetail, with the existing small glass action buttons throughout. Step
navigation and grouped actions align left with consistent wrapping and gaps.
The external-access guide no longer renders the entire app inventory. A native
searchable app dropdown offers only guest-enabled apps and reveals grant controls
after a valid selection; installations without eligible apps show a short empty
state and a Browse apps link.
The UI-only update was deployed to Framework with the previous UI retained at
`/opt/archipelago/web-ui.before-guide-layout-uat`. Production build and ten
walkthrough tests passed. Live browser comparisons at 1440px and 390px confirmed
matching original-guide widths/alignment and no horizontal overflow. Management
and wallet services were not restarted for this update.
### Signed private catalogue and guest access — 2026-10-08
After the operator signed the private candidate, verification against the pinned
release root passed locally and on Framework. The node accepted the exact signed
catalogue through `ARCHY_APP_CATALOG_CANDIDATE`; wallet process identities and all
app container IDs/states were unchanged. This remains a private UAT catalogue,
not a published release. The owned override is
`/etc/systemd/system/archipelago.service.d/50-external-access-uat-catalog.conf`;
remove it after the reviewed catalogue release or rollback to restore normal
catalogue refresh. The preceding cache is retained in
`~/external-access-uat/catalog-before-private-candidate.json` on Framework.
Framework now reports guest eligibility for Home Assistant, Immich, Jellyfin,
Nextcloud, PhotoPrism and Strfry. Actual-node checks with a temporary Home Assistant
grant passed anonymous challenge, bearer and browser-cookie access, denial at
Immich, rejection for dashboard login, and revocation of both bearer and cookie
access. One-hour expiry metadata was checked; elapsed expiry remains covered by
unit tests, not a one-hour live wait. The temporary grant was removed. No Nostr
events were posted and no other app data was changed.
### Controlled Framework reboot — 2026-10-08
The operator confirmed physical recovery access and authorized remaining
qualification. A fresh native LND snapshot and static channel backup were retained
privately on the node before reboot; no pending HTLCs were present. A changed boot
ID confirms the full reboot. Native wallet identity, channel set, on-chain and
channel balances matched exactly afterward, and LND reported chain sync without
manual unlock/restart. Backend and signed-catalogue hashes matched. All app
running/stopped states, exact publishing/project/archive state, FIPS address, onion
address and guest eligibility survived. Public HTTPS and Tor returned the exact
synthetic page. Guest scope, dashboard denial and revocation passed again.
Physical companion acceptance remains OPEN: the operator found the native
`datalist` app picker invisible in the companion, and Blossom blank after choosing
an identity. These are tracked as current regressions, not successful companion
acceptance. The picker replacement uses an in-page glass menu; the tab signer
must copy public identity fields instead of passing a Vue reactive Proxy through
postMessage. Blossom also requests the canonical chooser once on opening and
disables the unrelated generic NIP-98 web-app login. Deployment and actual-device
retest are required before closing these reports. Operator will restore 2FA after
the remaining installer/signer tests.
### Selective public archive implementation — 2026-10-08
Each FIPS/public-web or Tor publication can separately expose its exact archived
HTML snapshot at `/<sha256>`, only after an acknowledged action verifies the
local archive receipt matches the published bytes. This is a read-only
hash-addressed snapshot route, not a publicly opened Blossom app or upload API.
GET/HEAD and CORS reads serve only the selected immutable bytes with sandbox and
attachment headers. Unknown hashes, listings and uploads remain unavailable.
Later drafts cannot change the served bytes; publishing an update resets archive
sharing, and removing sharing does not unpublish the page or remove private files.
The focused harness and isolated platform suite each passed 12 publishing tests.
The candidate backend is deployed on Framework with its preceding executable and
publishing state retained under `~/external-access-uat/`. Live trusted HTTPS
readback matched the exact snapshot; unknown hashes/list/upload returned 404.
Revocation returned the selected hash to 404 while the website still served.
The synthetic archive was unshared after the test. No external replica or Nostr
announcement was made. UI deployment and live UI acceptance are still pending.
Stored Publication now has an optional `public_archive` field. Before rolling back
to the preceding binary, account for its deny-unknown-fields parser: retain the
latest state and migrate only this field away, or restore the pre-test state only
if no user changes would be lost. Do not blindly restore an older project file.
### Companion corrections deployed — 2026-10-08
The final dashboard build includes the in-page searchable glass app picker and
the tab signer's explicit cloneable identity fields. Sixteen UI tests passed,
including a structuredClone regression test using a reactive picker identity.
Live touch-browser checks at 390px and 1440px opened all six choices, filtered to
Immich, selected it and exposed the grant controls without horizontal overflow.
The normal Blossom lifecycle rebuilt/restarted the private candidate with
`data-app-id="blossom"`, `data-no-nip98` and one automatic chooser request. Its
previous image and build context are retained for rollback. The live direct app
window reproduced the blank frame before the signer correction; after deployment,
automatic selection returned to the visible file page, the signer iframe was
hidden, no generic login request occurred, refusal prevented upload and explicit
approval stored the synthetic file. Actual phone confirmation is still pending.
The archive UI is deployed with backend capability gating; UI tests cover fresh
consent on snapshot changes and independent revocation. No public release made.
### AI provider direction — 2026-10-08
The operator selected Routstr as the default, with Claude and OpenAI API keys as
alternatives, and deprioritized Ollama. The isolated publishing branch merged the
already accepted provider setup through commit `83ba98ab`, preserving its history.
Website design now opens that trusted dashboard setup and its existing ecash
Receive flow directly. New/missing provider settings default to Routstr; saved
provider selections remain unchanged. AIUI lists Routstr first. The Ollama draft
form was removed from the walkthrough; its compatibility RPC remains available.
The failed Framework Ollama test installation was removed through normal package
uninstall with `preserve_data: true`; no model was downloaded.
Funding and spending permission remain separate. Opening setup/top-up does not
change the allowance, send a payment, start inference, or publish content. API
keys use the existing private node credential store and are not passed to AIUI.
Focused provider/publishing tests and production qualification are in progress;
these changes are not yet deployed or publicly released.
Provider-focused validation: 20 dashboard/setup/signer tests, 22 AIUI provider
and generation tests, and 22 trusted bridge/integration tests pass. Initial
publishing tests required an AI-connection component stub for their isolated
mounts; the provider default test now checks initial state before the suite's
explicit Claude selection. The full backend suite and production builds remain
pending. Framework still runs the preceding candidate; its management service is
active and no Ollama container exists after cleanup.
The funding modal's Scan action now opens the existing wallet scanner and returns
to funding on close; six focused connection-modal tests pass after that wiring.
The first dashboard production build passed; it will be rebuilt for this final
scanner wiring before deployment. AIUI and isolated backend builds are ongoing.
The first full isolated backend run passed 1,717 tests with one outdated default
selection assertion failing (four explicit ignores). The assertion expected an
unconfigured node to choose Claude. Updated coverage distinguishes the new Routstr
default from a saved legacy Auto choice, and the Routstr adapter now rejects zero
allowance before even discovering providers. A rerun is required; no passing full
suite or deployment is claimed yet. Final dashboard and AIUI production builds
have both passed.
Final isolated backend rerun: **1,719 passed, zero failed, four explicit ignores**.
This includes the default Routstr zero-allowance stop and saved Auto behavior.
The deployable backend build is in progress; Framework deployment remains pending.
### Routstr-first Framework deployment — 2026-10-08
The private provider backend built successfully and is active on Framework:
SHA-256 `6002af4c131545e9c93c21a65e31ef8719e6beb2682d47825d0ac95ee724e12a`.
Authenticated publishing health passed. Native Bitcoin/LND process IDs and start
times were identical before and after the management restart. The prior backend
is retained as `~/external-access-uat/backend-before-provider-setup`.
Live qualification found a browser-history race while replacing the connection
modal with Receive: closing the first panel consumed a history entry after the
new panel opened, immediately dismissing it. AI setup now owns one history entry
across connection, funding and scanning. Other BaseModal/Receive callers retain
their default history behavior. Ten modal/connection tests and nine receive tests
pass. The final dashboard production build passed and is deployed; index SHA-256
`d53ef48ec61f0c947df75ca57af9dd44ccf1c8a6db13ff61931b73e0dd0df1d3`.
UI backups are `/opt/archipelago/web-ui.before-provider-setup-uat` and
`/opt/archipelago/web-ui.before-provider-handoff-uat`.
Actual Framework Chromium checks at 390px and 1440px pass: Routstr-first setup,
Claude/OpenAI inputs, empty password fields, direct ecash receive/Lightning
address display, repeated top-up opens, close/return and browser Back. No horizontal
overflow and no provider-setting, allowance or publishing mutations occurred.
The existing Claude credential is recognized by status; its value was never read.
No paid inference, new API-key save, or public content publication was performed.
Real paid-provider responses and physical companion confirmation remain separate
acceptance items. The earlier routing, Nostr, 2FA-restoration and release gates
remain open; this is a private Framework UAT update, not a general release.
### Existing Claude credential clarity — 2026-10-08
Framework already reports `claude_configured: true`. The chooser now explicitly
recognizes the Settings credential, hides the empty key form, and offers Use
Claude; Change API key deliberately reveals an empty replacement input. The form
also waits for credential status before asking for a missing key. Existing OpenAI
credentials use the same presentation. Selecting an existing key writes only the
provider choice, never reads back or rewrites the credential. Seven focused tests
and the production build pass. The UI-only update is deployed on Framework, with
rollback at `/opt/archipelago/web-ui.before-existing-claude-uat`. Actual browser
checks at 390px and 1440px pass recognition, enabled Use Claude, hidden secret
input and explicit empty replacement field. Live checks did not change provider,
allowance or keys and did not run inference. Refresh the dashboard to load it.
For the remaining end-to-end AIUI journey, also check that a provider chosen in
Setup is synchronized into an already-cached Chat iframe on return. Source
inspection shows configuration synchronization on iframe readiness; reactivation
currently arms listeners without explicitly refreshing the provider. This is a
follow-up acceptance concern, not a confirmed live inference result.
### Remaining qualification decisions — 2026-10-08
Operator confirmed all three physical companion checks pass: the app dropdown,
Blossom identity selection, and AI top-up screen. This closes those manual checks.
The operator authorized isolated Yaya test ports for the new tunnel. Preserve
existing ingress on ports 80/443 and the working free.archipelago.builders route.
Isolated-port TLS qualification must not be described as public ACME issuance.
Local nsite asset integration and cached Chat provider synchronization are in
source qualification; they are not yet deployed on Framework.
### Isolated Yaya tunnel qualification — 2026-10-08
Pinned frp0.71.0 and Caddy2.11.7 archives were SHA-256 verified against the
upstream release digests before use. Separate user services under
`~/external-access-uat/tunnel` run frps and the enrollment admission plugin on
Yaya (192.168.63.169:17400/control, :14443/HTTPS, loopback:17700/policy), and
frpc/Caddy on Framework (Caddy loopback:33443). Existing ports80/443 and NPM
configuration were not changed. These transient qualification units are not yet
the finished app installer or reboot-persistent product implementation.
The gateway forwards SNI TLS to Framework. Caddy's test CA and leaf private keys
were generated on Framework and stayed there; only its public root certificate
was retrieved for verification. The frpc control connection pins Yaya's test
certificate and requires TLS plus token authentication. A separate enrollment
policy restricts Framework to free.archipelago.builders and HTTPS proxies;
policy checks also apply to new connections and heartbeats. Enrollment values
remain in private0600 files, outside publishing state and the catalogue.
Actual-node tests passed exact synthetic website bytes (SHA-256
`6618540be22ec1a7fbdb89ef329ac851d7ddd0391cec8aa847ac8976f9b8598d`),
404 for management/upload/list paths, rejection of unassigned SNI, revocation of
new connections to an existing route, restored-enrollment recovery, gateway
restart/reconnect, and fail-closed admission-plugin outage/recovery. Both the
isolated route and the existing public HTTPS route returned the exact same
synthetic bytes. Evidence: `.build/isolated-tunnel-live.log`. Four focused Python
admission-policy tests pass. The first outage-test cleanup attempted to restart
a removed transient unit; recreated that owned unit and reran the full live
sequence successfully. Public ACME issuance on443 remains unqualified by these
private-certificate tests. No public Nostr events were sent.
The manifest-based router image now builds on Framework and has passed the same
live isolated-port sequence inside a rootless slirp4netns container with read-only
root, no capabilities, no published host ports and a256MiB memory limit. Evidence:
`.build/isolated-container-tunnel-live.log`. The old transient Framework frpc/Caddy
units were stopped; the owned test container is `archy-uat-public-web-router`.
Yaya's frps/admission units remain separate from existing public ingress. Actual
frpc clients were denied for an unassigned domain and a wrong enrollment token;
a wrong TLS server name also failed login (frpc reported session shutdown).
The new source includes a private enrollment adapter, normal-catalogue installer
button, shared Setup connection and per-website connection controls. Three gateway
UI tests,27publishing UI tests, eight gateway/router Python tests and16manifest
checks pass. Final full backend tests/build, matched UI deployment, trusted
catalogue signing/install, automatic app-gate routes, public ACME443 acceptance,
final reboot and release gates remain pending. The current installed management
backend is unchanged. No paid AI call or public Nostr event was made here.
Container lifecycle qualification also passed removal of configuration, restored
configuration, and container restart, with the same certificate and exact bytes
after recovery (`.build/router-lifecycle-live.log`). The first full isolated
backend run passed1,721tests, zero failed, four ignored; that run predates the new
gateway integration, so it is not final candidate acceptance. The subsequent
full build/test pipeline remains in progress. Automatic catalogue-app routes
and live app-identity/policy enforcement have now been added in source; their
backend and live qualification remain pending.
### Saved Claude credential: actual inference — 2026-10-08
The authenticated Framework AIUI Claude proxy returned its model list, then
successfully handled one synthetic HTML request using the existing saved key.
The selected available model was `claude-haiku-4-5-20251001`, maximum64output
tokens; actual usage was44input and33output tokens. Returned HTML SHA-256:
`0c61e55d9f4c80f36d0db9dce2834677ae02a3d1cefa587d60426e6b14b8d6b1`.
The private result is `~/external-access-uat/claude-live-generated.html` on
Framework. No tools, private files, prior conversation history, provider-setting
writes, allowance changes or publications were involved. The key was injected by
the node proxy and never read back. This verifies real saved-key inference, not
completion of the separate browser AIUI-to-publishing handoff. This request may
incur the provider's normal API charge; no top-up or payment transaction was made.
The first curl-cookie attempt was unauthorized; using the existing qualification
helper's authenticated cookie handling succeeded without disabling authentication.
### Final candidate deployment and live installer checks — 2026-10-08
Backend SHA-256 `683a02e1cf00d291ee82bcc2e95d159c8cf7f922b9da7e1c72187de5d8595b66`
is deployed on Framework with the matched dashboard and signed private gateway
catalogue. Final isolated backend suite: 1,726 passed, zero failed, four ignored;
focused publishing suite: 21 passed. The dashboard build initially caught a null
store access; optional chaining fixed it and the production build passes.
Live normal installation exposed the Setup helper's missing `dockerImage`.
Both Setup install buttons now resolve the image/build tag and version from the
backend-verified catalogue and use the normal package installer. Sixteen Setup
component tests and two installation-contract tests pass. The signed catalogue
listing also resolves build tags. No catalogue signature changed.
Framework restores runtime assets from `web-ui/archipelago-runtime` at startup.
Staging only `/opt/archipelago/apps` was therefore insufficient: startup restored
the old manifests. Updated the owned runtime payload for Blossom and Public Web
Router, then repeated normal installation successfully through the orchestrator.
The initially bare test installs were stopped/removed; their data was empty.
The owned manual qualification container was removed after the normal app was
ready; its existing certificate storage was preserved in the manifest data bind.
Normal Router enrollment through owner RPC, private 0600 configuration, credential
redaction and exact selected website HTTPS bytes pass. Blossom updated normally
to 6.4.1-archy.2 and is healthy. Its automatic identity chooser, signing denial and
approved local upload passed again. Guest app routing through isolated Yaya TLS
passed anonymous challenge, app-only token login, Secure/HttpOnly/SameSite cookie
and revocation. Removed the temporary grant/app route and restored the website.
Existing Yaya public80/443 remains unchanged. Native wallet processes retained
PID/start time throughout management restarts.
Local nsite live acceptance passed signer-authorized BUD-02 upload into Blossom,
exact selected hash over public HTTPS, CORS and sandboxed attachment headers,
denial of upload/list/unknown-hash endpoints, and asset revocation. Restored the
original synthetic project's routes and left its website available. No manifest
was signed or sent to relays. Evidence: `.build/local-nsite-live.log`,
`.build/gateway-app-live.log`, `.build/blossom-archy2-live.log`.
The normal rootless router has read-only root/config, dropped capabilities and
slirp networking. Framework reports memory cgroup limit zero despite the manifest
request: resource-limit enforcement is a retained host-runtime limitation, not a
passed 256MiB boundary. Public ACME443 and general publication remain outside this
isolated-port acceptance. Final AIUI handoff and reboot checks follow below.
The full browser AIUI path subsequently passed with the saved Claude key: actual
synthetic HTML generation, Continue to website setup, and explicit import into a
new private project. The first attempt hit the test's short navigation timeout;
the rerun with the normal page-load allowance passed. Original AI provider settings
were restored. No generated site was published. Evidence:
`.build/aiui-handoff-live.log`. Claude's normal inference charges may apply; no
Routstr top-up, wallet payment, or allowance change was performed.
### Final controlled Framework reboot — PASS, 2026-10-08
The operator-authorized reboot changed boot ID from
`1eb5205a-ba5e-46de-a519-89a066bd8aac` to
`b30e5001-5ca0-4738-9e82-0a29cef0e7a6`. Preflight saved the native LND snapshot
and static channel backup privately and verified no pending HTLCs. LND initially
reported locked/not-ready during normal startup; the dashboard RPC correctly
returned unavailable rather than a false zero. It unlocked automatically without
manual restart or unlock. Native identity, channel set, on-chain/channel balances,
and chain sync then passed the saved-snapshot comparison.
The complete installed app set returned. Blossom is healthy; the normally
installed router started without intervention and retained its certificate.
Publishing state, gateway settings, onion identity and the absence of temporary
guest grants matched the pre-reboot snapshot exactly. Both the existing public443
route and the isolated14443 tunnel returned the original synthetic website hash
`6618540be22ec1a7fbdb89ef329ac851d7ddd0391cec8aa847ac8976f9b8598d`.
Backend and dashboard bytes and the shipped router manifest survived restart.
Dashboard index SHA-256:
`dbcff02ed9bf8cc6bab4765e1b6f81155a938145f75b3f588bc2154dbb5476a9`.
Repeated the normal router's negative/lifecycle sequence after reboot: management,
upload/list paths denied; unassigned SNI denied; enrollment revocation denied new
connections; restore recovered; isolated gateway restart reconnected; policy
outage failed closed and recovered. Initial attempt could not authenticate to
Yaya because the old SSH control session had expired; no policy mutation occurred.
Reauthenticated with the supplied account and the complete sequence passed.
Evidence: `.build/normal-router-after-reboot-live.log`. Existing public ingress
was unchanged. Final related UI regression group passed27tests and gateway Python
group passed10tests. No public Nostr events, source push, catalogue publication,
OTA or ISO publication occurred.
Framework UAT candidate is ready. Retained boundaries: public ACME443 passthrough
needs a dedicated public ingress, external Nostr propagation is deliberately not
claimed, Framework's rootless memory cgroup limit is not enforced, and general
release remains gated by the separate release checklist and ngit/mirror review.
The operator was asked to restore the 2FA they temporarily disabled for testing.
Private catalogue pin and isolated Yaya services remain for UAT; remove/replace
them only during the reviewed release or explicit rollback.
Final Tor readback from Yaya's SOCKS client also returned the original synthetic
website SHA-256 after reboot. Thus FIPS-backed public HTTPS, the isolated TLS
passthrough, and the existing Tor onion all retained the same content.