Skip to content

Every client uses LAN, then Tailscale, then T3 Connect to every server #292

Open

Description

@lukemaj

What: #364/#365 are deployed on the fleet and #366 on bestia; cavallo-to-bestia T3 Connect fallback and restored LAN now pass.
Why: The prior bestia tunnel failure is restored through the supported relink; transport proof remains separate from saved catalog, phone and other-client acceptance.
So what: Keep #292 open for direct saved-route membership/order/persistence, rocky desktop destinations, the physical iPhone and applicable remote web clients; current proof is linked below.

Current rollout and remaining acceptance: #292 (comment). Earlier implementation handoffs below are historical.

Outcome and current user decisions

Required final state: rocky desktop must hold LAN, Tailscale and T3 Connect routes to bestia and cavallo; cavallo desktop must hold them to bestia and rocky; iPhone must hold them to all three servers. Existing bestia web clients, if any, need their remote saved environments checked; served-web primary environments are excluded. Required order is LAN, Tailscale, T3 Connect, with T3 Connect used only when earlier routes fail. Authentication remains required.

User decision, 2026-10-14: a desktop does not need backup routes to its own server, and served-web primary routing is out of scope. The former primary-route requirement and #286 repair are dropped; #286 is closed as not planned for this reason. No primary ownership/authentication changes are being built.

This supports the Objective by keeping Chromeria and its agents usable across machines during an internet outage without changing Project Direction.

Acceptance per server

  • bestia: normal service listens beyond loopback; LAN, numeric Tailscale and the existing HTTPS 443 endpoint are reachable from both other machines; anonymous protected requests are rejected.
  • bestia: inspect actual advertised LAN/tailnet endpoints and automatic persistence where supported. Source/config expectations alone are not advertisement proof.
  • cavallo: supported Network access and Tailscale HTTPS 443 settings enabled; authenticated configuration advertised LAN, numeric Tailscale and HTTPS; both other machines reached all three endpoints with required auth.
  • rocky: supported Network access enabled, Tailscale CLI shim installed, managed Tailscale HTTPS 8446 activated and advertised, existing unrelated settings and Serve mappings preserved, and the deploy owner's restart/resume and ten-minute health check passed.
  • Mac application firewalls: incoming Chromeria 3773 traffic is permitted; no permanent application-firewall change was needed.

Acceptance per client

Client Required destinations and order Remaining proof
rocky desktop bestia and cavallo: LAN / Tailscale / T3 Connect Only own-loopback sockets observed; conditional bestia simulation skipped. Remote catalog/order and connections to bestia/cavallo remain unobserved
cavallo desktop bestia and rocky: LAN / Tailscale / T3 Connect Bestia full sequence proved 2026-10-15; rocky full sequence previously proved 2026-10-14. Saved catalog membership/order/persistence remains unobserved
iPhone bestia, rocky and cavallo: LAN / Tailscale / T3 Connect Current installed catalog, learned routes, saved order and selected routes remain unobserved
existing bestia web clients Remote saved servers only, excluding served-web primary Inventory actual clients/origins and remote catalog; preserve browser mixed-content rules
  • Record cavallo -> rocky: baseline LAN, LAN blocked -> Tailscale HTTPS 8446, LAN plus Tailscale blocked -> T3 Connect, and restored LAN.
  • Execute cavallo -> bestia after the fresh client-work pre-check and record the result: LAN / Tailscale / no observed relay fallback / restored LAN.
  • Resolve cavallo -> bestia relay fallback and repeat that stage; actual T3 Connect traffic and restored LAN proved on 2026-10-15. Saved catalog inspection remains separate.
  • Check rocky -> bestia conditional test: its real desktop network helper retained only own-loopback sockets in all simulation samples; no applicable direct connection was observed, so the test was skipped. This is not remote route proof.
  • Record the bestia relay gap and exact supported UI steps. Add a relay only if absent; if present, inspect relay status/error. The simulation cannot establish encrypted catalog membership.
  • Record remaining saved route membership/order and any other remote destination/phone/web observations still requiring the user's hands.
  • Each agent machine mutation has retained backup, cause/change/proof/rollback runbook evidence, explicit-path commit and ordinary push. Latest authored documentation has verified exact-SHA independent success; actual machine restoration is independently observed.
  • Any newly required in-scope product fix passes focused proof and review/independent-sol plus review/independent-grok on its exact head before the authorized merge. PR fix(connections): learn saved servers T3 Connect routes automatically #364 now implements automatic relay learning; current exact-head review and CI are recorded on that PR.

Approved simulation and safety boundary

The user explicitly authorized temporary outbound TCP blocks on the client machines through a dedicated pf anchor, with timed self-removal installed before any blocking rule. Back up the pf configuration and relevant prior state first. Check for client-driven mid-turn work before starting. Server-side agents continue running; no application or server is restarted.

Cavallo's test blocks only the Chromeria LAN endpoints of bestia and rocky, then their known Tailscale Chromeria endpoints. Rocky's test, if connected, targets only bestia. Account for both numeric-Tailscale 3773 and each server's supported HTTPS port, otherwise a surviving Tailscale HTTPS route is not a T3 Connect fallback. Preserve SSH, other destination ports and unrelated pf rules/anchors. The installed macOS pfctl cannot delete a single state by ID. The reviewed transaction requires empty states and refuses to continue if states appear; it performs no state deletion.

Rollback is pfctl -a <task-anchor> -F all, plus release only a task-owned PF enable reference if this task temporarily enabled PF. Do not disable a firewall another owner enabled. Timed cleanup must survive a lost SSH or agent connection. Record all step times and verify rule removal and return to LAN.

Server socket observations identify direct peer addresses. Tailscale HTTPS and T3 Connect can both reach the backend through local proxy paths, so identify the transport's process/upstream connection or retain an explicit ambiguity. A loopback socket alone does not prove T3 Connect. No tokens, pairing URLs, secret values or full user payloads are captured.

Verified progress and retained evidence

At 2026-10-14 11:45:11Z after the bcc4db8 fleet deployment, all 18 cross-machine endpoint probes passed: each machine reached each other server through LAN, numeric Tailscale and Tailscale HTTPS. Discovery returned 200, anonymous protected API 401, and environment identity matched internally across each server's three endpoints. Identifiers stayed private. These are reachability/authentication checks, not selected-route or fallback proof.

Bestia's reviewed network drop-in was activated at 10:40:08Z under the immediate-restart decision. The planner opened only the required LAN-subnet and tailscale-interface UFW access. Cavallo's supported settings were changed by the user and independently checked. Rocky's CLI shim was installed with backup and rollback.

The separate deploy task activated rocky's managed HTTPS 8446 while stopped at 12:12:50Z, in the same normal restart that installed 8f939c24ea89. Its activation record confirms only the two approved settings changed, unrelated Serve mappings were equivalent, discovery 200 and anonymous protected API 401, no lost continuations/held queues, and one callback. Its ten-minute follow-up passed 21 samples over 602.43 seconds with unchanged backend PID/start and is pushed in runbook 8958552. This implementation task did not restart rocky.

The read-only headless check at 12:21:28Z returned real server.getConfig advertisements on both Macs: cavallo LAN/numeric Tailscale/HTTPS443 and rocky LAN/numeric Tailscale/HTTPS8446. Existing read credentials stayed in memory; no credential was issued. The supported client-session inventory returned 403 with these read credentials and, in any event, its contract has no route order or actual endpoint field. Historical mobile/web session rows cannot establish today's physical client catalog. Bestia's authenticated advertisements remain unverified because no existing normal read credential was found in the checked task/state locations.

Earlier cavallo desktop sockets to bestia and rocky used LAN, and its encrypted catalog changed after bestia activation. These corroborate learning/promotion but do not establish its catalog contents. The later controlled rocky simulation below supersedes the earlier fallback unknown; encrypted catalog contents and persistence remain unobserved.

Our earlier runbook changes are pushed as 71a53bc, fcf992d and b527fde. The cumulative candidate b527fde has independent review success. The planner's UFW record is separate, ea0ee18. This evidence does not certify the remaining client outcome.

Controlled cavallo -> rocky proof, 2026-10-14 UTC

No client/server was restarted. Baseline LAN was observed at 14:15:51.773. Exact rocky LAN blocking applied at 14:15:52.591; the first subsequent Tailscale HTTPS 8446 observation was 14:16:27.902, at most 35.311 seconds later. Rocky's Tailscale process owned the matching backend proxy; the former client LAN socket disappeared.

LAN plus all known rocky tailnet Chromeria endpoints were blocked at 14:17:44.525. At 14:17:58.116, at most 13.591 seconds later, cavallo had no direct rocky endpoint socket and rocky's cloudflared process owned the persistent backend connection. PF counters confirmed both route groups were blocked; no states were killed. This proves real T3 Connect fallback and supersedes the earlier assumption that cavallo necessarily needs a new rocky relay route.

Restore was requested at 14:20:02.089 and blocking rules were flushed. Relay was still observed at 14:20:50.551; LAN was observed again at 14:22:57.461. The observation gap prevents an exact promotion latency claim. Repeated later samples retained LAN and the same app/backend processes; bestia's separate LAN connection remained active during the rocky test.

The old guardian's automatic reference release failed because its parser rejected installed pfctl's column headers. It had already removed the blocking rules, but PF remained enabled with default pass behavior. At 14:25:42.019 the single proven task-owned reference was released manually, using the private recorded PID/acquisition time and no printed handle. The guardian then reported restoration and exited. Final checks at 14:31:31 proved PF disabled, no held references or states, zero task rules, unchanged live root/NAT and byte-identical disk PF configuration/anchor files. Private backups are retained; rollback is sudo pfctl -a com.apple/000.chromeria292 -F all, then release only the identified task-owned reference if still held.

The owning parser has since been fixed and independently reviewed at exact full/subset digests; the next bestia-only candidate is d673e4b3d363bf0f77b8adaae1a37954669be583163d955ff51793d128994b7d. The simulation is behavior proof for this one client/destination, not on-disk route persistence or phone acceptance. Runbook proof and rollback are pushed in 2dcc427; independent exact-SHA review passed.

Controlled cavallo -> bestia proof, 2026-10-14 UTC

Fresh 14:53:23Z metadata showed no affected human/unknown input or active interactive request; the sole pending async message had a completed owner. Cavallo PF was disabled with no states/references or task rules. The bestia-only independently reviewed guard backed up PF privately and armed its nominal 300-second cleanup before any rules. No app/server was restarted or UI driven.

Baseline LAN was observed at 14:54:12.379. LAN blocking applied 14:54:53.641; the first observed Tailscale HTTPS 443 sample was 14:55:02.069, an upper bound of 8.428 seconds. The client's new persistent tailnet socket and bestia tailscaled backend proxy with increasing traffic stayed through ten samples. Old backend LAN sockets lingered with stalled traffic after the client dropped them; they were not counted as working LAN.

Combined LAN and all known tailnet Chromeria blocks applied 14:56:19.131. Eleven samples through 14:57:13.950 covered the first 54.820 seconds and showed no bestia cloudflared backend connection or new client relay socket; client direct bestia sockets were gone by 14:56:24.724. Bestia's cloudflared process existed, which does not prove tunnel/auth health. The next 23 seconds before restore were unsampled. This records an unavailable observed fallback; it does not establish saved relay membership absence or diagnose a product defect. PF counters recorded blocks on both LAN and tailnet; no states were killed.

Automatic cleanup verified at 14:57:37.258 released the task's own PF reference and removed its rules with no retry/manual recovery. A new persistent LAN client socket appeared at 14:57:42.930, at most 5.672 seconds later, and was present in the later 12 of 13 total restoration samples through 14:58:43.906. Final 14:58:24 proof showed PF disabled, zero rules/states/references, stopped guardian and byte-identical disk PF/anchor files plus unchanged root/NAT policy. The separate rocky LAN socket and all desktop/backend process identities remained unchanged. The root-only backups are retained; exact rollback and proof are pushed in 7a78100. Its authored documentation has independent exact-SHA success. Review clarified that LAN was present in 12 later samples out of 13 total, and the Add T3 Connect button depends on account discovery; the proof and steps here include those limits. After restoration, cavallo's 15:08:23Z probes again returned discovery 200 and anonymous protected API 401 through bestia LAN, numeric Tailscale and HTTPS443.

Remaining client steps

Cavallo: Settings > Connections > bestia > Routes (or N routes). Inspect the actual list and drag LAN first, all Tailscale routes next and T3 Connect last. The test found no working bestia relay fallback; if its route is absent, click Add route > Remote link > Add T3 Connect. This button is offered only when the signed-in T3 Connect account can discover bestia and its relay route is not already registered. If the button is absent, inspect the account's bestia entry/relay status and report that state; do not delete existing routes or issue a pairing code. If a relay route already exists, inspect its displayed status/error before treating the gap as missing membership. Repeat the controlled fallback after repair. Inspect rocky's Routes for the same saved order; its relay already worked, so no new rocky relay route is required by this evidence. In use identifies the selected route. The advertised endpoint's Default badge is a pairing endpoint, not client priority. Saved membership/order and restart persistence remain unobserved.

Rocky remote servers: use the same saved-server Routes controls for bestia and cavallo if a needed kind is absent; the user wants no manual rocky screen work, so prefer an existing authorized control path or keep the exact unavailable action explicit. No own-server route step remains.

iPhone: connect to each server through its existing T3 Connect entry so it receives current advertisements. Settings > Environments > each server > Routes > Edit; LAN first, Tailscale next, T3 Connect last; Done. Learned addresses are marked found automatically. If learning is absent, inspect it before issuing a new pairing code; Add route requires Address and Code. Keep the existing relay entry. These steps match source; the actual installed phone build/catalog remains unknown.

Existing web clients: inspect only remote saved environments; an HTTPS page cannot use an HTTP LAN route. Current clients and page origins are unobserved, and no mixed-content bypass is permitted.

Related records and non-goals

#286 is not planned under the new user scope. #287 still owns the inherited-development-Serve defect that twice displaced bestia's normal HTTPS mapping; the mapping was restored and no competing fix is started here. #164/#290 owns headless cross-machine control, not a desktop route-catalog editor.

No primary/own-server route implementation, new server against live userdata, raw database/catalog surgery, credential rotation, authentication weakening, extra restart, unrelated ports/settings, global pf reset, recurring firewall automation or competing headless API.

Elon record

Requirements and who asked: User's 2026-10-14 updated decision requires ordered remote LAN / Tailscale / T3 Connect routes, excludes desktop own servers and served-web primary, and authorizes screen-free pf simulations with pre-checks, backups, timed cleanup, exact-port scope, restoration and committed runbook proof.
Deleted: Own-server and served-web primary acceptance, the #286 product repair and its uncommitted test changes, another rocky restart, raw catalog manipulation, unsafe mixed content, broad host/state firewall resets and recurring automation.
Bottleneck: Resolve the observed cavallo -> bestia relay gap through actual saved-route/relay inspection, then obtain phone and remote catalog evidence. Rocky relay is no longer an assumed gap because its real fallback worked.
Checked myself: Server/source records, protected-client-inventory limitation, authenticated Mac advertisements, deploy activation/follow-up, actual cavallo NetworkService and rocky Tailscale/cloudflared sockets under exact-port failure, PF counters, final restoration, and the reviewed actual-header parser correction. The old guard removed blocking rules but failed automatic reference release; manual owned-reference release is recorded rather than hidden.

Canonical continuation handoff

The cancelled #286 worktree remains clean at 8f939c2 in /home/luke/dev/toolboxmd/chromeria-worktrees/286-primary-connection-routes, bound to this active operational task. Only the task's two experimental test additions were removed; no product implementation, commit, PR or merge exists. Its design and source evidence remain in app-owned completed delegation records. The worktree is retained while this calling agent is active and will be eligible for retirement after the operational task no longer needs it.

Private runbook workspace /home/luke/.local/state/chromeria-lan-first/runbook is clean at pushed 7a78100d92d9153c2d407bcd20ca533553fa672a, with verified exact-SHA independent review r15 success: findings. Prior 2dcc427 has verified independent success: findings. Pull with rebase immediately before every future commit, explicitly stage only owned paths and preserve other owners' entries. Both simulation backups and evidence remain private under the existing PF evidence directory and their root-only cavallo directories. Both guardians are stopped; final read-only recheck at 15:14:41Z still showed PF disabled, zero task rules/states/references and unchanged root/NAT policy. The earlier complete disk comparison matched retained backups. Bestia-only candidate d673e4b3d363bf0f77b8adaae1a37954669be583163d955ff51793d128994b7d passed independent actual-header/lifecycle review and then automatic live cleanup. Next: the planner passes the exact physical client steps above; inspect/repair bestia relay, observe the phone/remote saved catalogs, then repeat the applicable missing proof. Rocky -> bestia simulation was skipped because its observed desktop sockets were own-loopback only.

Operational proof/delivery is complete for the two observed cavallo destinations, with the bestia relay stage explicitly unresolved. No product PR, version bump or merge exists. #292 stays open for the remaining client acceptance. The clean #286 task worktree and its local branch are retained because this calling operational task is still bound to them; no other task workspace, active proof/backup or shared clone is retired. Any future continuation must recheck the applicable live client work, firewall ownership and actual client connection before another authorized simulation.

Activity

  1. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: Rocky's backed-up managed HTTPS 8446 candidate is ready and remains unapplied.
    Why: The required restart wrapper validates an operating thread on rocky, while this delegated task exists only on bestia.
    So what: The planner needs to provide a rocky-local operating task or obtain an explicit restart-method exception before activation.

    A fresh read-only pre-check found zero active runs, unfinished tools, background rows and held queue rows; the operating task's local thread count is also zero. Current settings still match SHA-256 de4c02c9d20a40590e04f366cf2c6f2d265051a74c9d80b682fda612185a2546: managed HTTPS off, default port 443. The prepared candidate enables HTTPS on 8446 and every unrelated field remains equivalent. Nothing was written to live settings and no restart was requested.

    The required method and local-thread constraint are explicit in the runbook's rocky/CHROMERIA.md and cavallo/CHROMERIA.md restart procedure. After resolving the method, repeat the work checks, preserve fresh settings and Serve backups, activate only the two exposure fields while stopped, verify advertised HTTPS and other ports, and perform the required later health/continuation check.

  2. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: Rocky's managed Tailscale HTTPS is now enabled on 8446 in the same restart that installed Chromeria 8f939c24ea89.
    Why: The #292 candidate was backed up but still unapplied; a restart alone would not enable it.
    So what: The routes owner can reuse this activation and endpoint proof without another rocky restart; complete client-route acceptance remains owned by #292.

    The planner explicitly authorized applying exactly the two candidate fields while Chromeria was stopped and told the routes owner not to restart rocky. A task-only copy of the established restart-and-resume script applied them after graceful shutdown and before relaunch at 2026-10-14T12:12:50Z; installed scripts were unchanged. Compared the saved fresh prior settings with live settings: only tailscaleServeEnabled (true) and tailscaleServePort (8446) changed; all unrelated fields are equivalent.

    Rollback remains ~/.local/state/chromeria-route-backup/20261014T102000Z-https-headless/desktop-settings.json; the additional fresh pre-activation snapshot is desktop-settings.pre-8f939c24.json in that same backup. The prior Serve snapshot is retained there. Current Serve TCP ports are 8443, 8444, 8445 and 8446; every non-8446 TCP mapping is identical to the backup.

    After restart, from bestia at approximately 12:13:53Z:

    • https://rocky.napoleon-sun.ts.net:8446/.well-known/t3/environment: 200.
    • Anonymous https://rocky.napoleon-sun.ts.net:8446/api/orchestration/shell: 401.

    Backend PID 92991, start 12:12:51Z; main PID 92964; health 200. Pre-check found zero active runs/tools/background work, post-check found no missing continuations or held queues, and the restart callback was delivered once. A ten-minute same-process observation and pushed rocky runbook record will follow. No client catalog or complete fallback acceptance is claimed.

  3. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: Rocky's #292 activation and endpoint proof are now in pushed runbook commit 8958552.
    Why: The two approved HTTPS fields needed the stopped interval of this rollout; its single restart also installed 8f939c24ea89.
    So what: The routes owner can continue client-route acceptance using the activated 8446 endpoint and preserved rollback, without another rocky restart.

    Ten-minute follow-up passed: 21 samples over 602.43 s (12:13:52Z to 12:23:54Z), backend PID 92991/start 12:12:51Z unchanged, every health and discovery response 200. HTTPS 8446 discovery returned 200 and anonymous protected API 401 after activation; every unrelated setting and every Serve field/mapping outside 8446 remained equivalent. #292's original backup and the fresh pre-activation settings snapshot are retained. No missing cut-thread continuation or held queue; installed scripts stayed unchanged and task-only restart helpers were retired.

  4. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: The approved cavallo fallback experiment is prepared with a dedicated PF anchor and a detached one-shot guard; no blocking rules have been installed.
    Why: The real desktop currently holds LAN connections to bestia and rocky, while parallel Tailscale HTTPS checks make socket presence alone insufficient to prove priority.
    So what: The implementation task completes guard review, refreshes the client-work check, runs the two temporary failure stages, restores traffic and records actual transitions here and in the runbook.

    Experiment and stopping conditions

    Question: do cavallo's real remote desktop connections recover through Tailscale when only LAN is blocked, and through T3 Connect when both direct route kinds are blocked, then return to LAN?

    Prediction: LAN-only blocks interrupt the existing LAN sockets and produce sustained Tailscale connections; adding numeric Tailscale, managed HTTPS and the known Tailscale IPv6 endpoints leaves only T3 Connect among the required route kinds. A relay/tunnel process must own the corresponding backend connection for relay evidence. A loopback socket or an unrelated public HTTPS socket alone is insufficient. A disconnected app establishes a fallback gap, not a successful relay transition or definite catalog membership.

    Falsifiers: no reconnection, a surviving excluded direct endpoint, a block counter that never changes, PF state bypass, unexpected policy or client-work changes, or transport ownership that cannot be established. Those retain an explicit failed or inconclusive result. No synthetic client is substituted.

    Environment: installed clients on the live three-machine fleet. The source checkout remains clean at 8f939c24ea898e7600c9c93892cb3ad63ad88686; that is source identity, not a claim about bestia's installed build. Rocky's managed HTTPS is 8446, bestia's is 443. Own servers and served-web primary are outside acceptance.

    Artifact: task-private pf-r8/guardian.py, SHA256 284efbe1bada0208f29c03a7e311dc959c2dee9a6dbe5ee3b42ae55257ac4054, plus token-free read-only socket observations. The guard owns only com.apple/000.chromeria292, runs detached as root, backs up disk PF files and relevant live snapshots, arms its monotonic 300-second removal before loading anything, and releases only its own PF reference. No root configuration rewrite, global flush, state deletion, SSH block, app restart, credential issuance or screen use.

    Cavallo's PF is disabled with zero states, two empty Apple child anchors and no starter references. The existing wildcard reaches the dedicated direct child anchor. LAN and combined IPv4/IPv6 rules passed the installed parser without loading. Default pass has no state rule, so the guard refuses any stage if states appear rather than inventing a broader deletion mechanism. The initial disk/live snapshots stay private.

    At 13:22:31-39 UTC the conservative fresh read-only work check found zero human/web/mobile/unknown input on nonterminal runs across the fleet, zero waiting active secret cards and zero Mac nonterminal runs. Bestia's sole pending request was the previously classified asynchronous message request, not a provider callback. Stored provenance cannot distinguish which physical client originated a human turn, so all such inputs are checked. Unsent drafts and new interaction after the snapshot remain outside this check.

    Rocky's desktop NetworkService held only own-loopback Chromeria sockets at 13:22:31 UTC, with no established direct connection to bestia. Its conditional simulation will be skipped unless a fresh observation finds that connection. This does not prove absence of saved routes or a T3 Connect session.

    Observe about 75 seconds per block stage and restoration; remove immediately on an unexpected result. The independent guard limits the temporary rule lifetime to 300 seconds even if SSH or the agent disappears. Inspect client-owned sockets, backend tuples, proxy process ownership and scoped rule counters, retaining the sampling interval and first observed transition times. Restoration must show the task anchor empty, the owned reference released, prior PF status/root policy restored and LAN sockets back.

    Elon record

    Requirements and who asked: The user's updated #292 decision requires remote LAN / Tailscale / T3 Connect fallback proof without a screen, narrow TCP scope, pre-checks, backup, timed removal and restoration.
    Deleted: Own-server and served-web primary work, a new product fix, app restarts, state-ID deletion unsupported by installed PF, broad state kills, root ruleset rewrites and recurring automation.
    Bottleneck: Observe controlled transport transitions on the real clients, then identify which saved route kinds still need the user's supported app UI.
    Checked myself: Current conservative work metadata, exact process-owned LAN tuples, empty PF states/child rules and references, wildcard hook, parser success including IPv6, and source showing parallel route checks and local proxy ambiguity. Guard review and live transitions are still pending.

  5. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: The one-shot cleanup guard is independently approved, but the live client-work pre-check currently prevents the cavallo fallback simulation.
    Why: Fresh metadata at 14:00:22 UTC shows a running web-origin user turn and human steering on bestia; stored provenance cannot identify the physical client, so the conservative check treats them as potentially affected.
    So what: No PF rule or enable reference has been installed; the task waits for a clear pre-check, then runs the already-authorized temporary stages and restoration without another app/server restart.

    The final disposable guardian is SHA256 ea0ca91371ca426daa4d06b540c98dbf56e870bb6ce369fc5d179435ff35cde7, at the existing private pf-r8/guardian.py location. App-owned child lan-first-20261014-pf-guardian-review-r11 returned PASS on this exact hash with all 16 in-memory cases passing and no blocking findings. It covered partial enable-token retention, transient flush/release failure, persistent evidence-write failure, late enable-reference acquisition, and preserving another owner's reference. Earlier candidates were blocked and corrected before installation. This is safety readiness, not route proof.

    The candidate retries cleanup until its exact anchor is empty and its exact owned reference is absent, waits for its captured enable subprocess to terminate before the conclusive reference snapshot, and keeps cleanup independent of evidence writes. Tokens remain only in memory and are never reported. Installed IPv4/IPv6 syntax-only parsing still passes. The nominal monotonic timer is 300 seconds; individual PF calls have bounded timeouts and cleanup retries persist until verified.

    Bestia was restarted by another owner at 13:47:58 UTC, not by this task. The new normal backend is 1493936. At 13:51:23 UTC cavallo's actual NetworkService still had LAN connections to bestia and rocky, corroborated server-side; bestia's LAN connection carried continuous data. Rocky's NetworkService still had only own-loopback Chromeria connections, so no direct bestia connection qualifies for its conditional simulation. Historical catalog/relay membership remains unproved.

    Source checkout remains clean at 8f939c24ea898e7600c9c93892cb3ad63ad88686, branch fix/286-primary-connection-routes, and #286 remains closed as not planned. Private runbook clone remains clean at b8101b47facc1d37d39e38d52e2ad1306cca9701; pull with rebase immediately before the future explicit-path commit. No new machine entry or live PF backup is claimed before installation. The selected guardian, token-free observer, SQL pre-check and prior observations remain task-private for recovery.

    Requirements and who asked: User's screen-free fallback decision requires a clear client-work pre-check, backups, timed cleanup, exact-port blocks and restored traffic; no own-server/served-web primary requirement remains.
    Deleted: All four guard failure paths, broad state deletion, a server/app restart and treating safety review or socket presence as completed fallback proof.
    Bottleneck: A current human turn must finish before the approved client traffic interruption.
    Checked myself: Exact guardian hash, terminal independent PASS and its scope, installed no-load parser results, still-disabled cavallo PF with zero states, post-restart process-owned LAN sockets, and the fresh positive pre-check. No blocks are active.

  6. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: The next approved fallback simulation targets cavallo's existing remote connection to rocky.
    Why: Rocky has no nonterminal runs or pending interactive work; bestia's positive client-work check remains unresolved and its traffic can be excluded from this independent slice.
    So what: The task runs the rocky-only LAN / Tailscale / T3 Connect experiment with the reviewed timed guard, restores and records it, then returns to bestia's pre-check.

    The selected guardian is guardian-rocky-only.py, SHA256 3a66f31097fa292b2f0de613a7313f90e47f681b163a82e67857e50fe761ab84. Independent child lan-first-20261014-pf-rocky-subset-review-r12 returned PASS on this hash. Only bestia's three rule lines were deleted; the surviving rocky rules and the entire cleanup/backup/ownership core are equivalent to the r11 approved guardian with its 16 passing failure cases. Installed syntax-only parsing passed both selected rule sets. No PF mutation has yet occurred.

    Targets are rocky's LAN Chromeria 3773, then its numeric Tailscale 3773 and supported HTTPS 8446, including known Tailscale IPv6. No bestia rule is present. SSH and rocky's other service ports remain outside the match. The dedicated anchor, 300-second nominal monotonic timer, private pre-change backup, refusal to delete states, captured own enable reference and verified cleanup are unchanged. Fresh rocky/cavallo work checks and process-owned connection evidence are required immediately before activation.

    The hypothesis and limits in the earlier preflight still apply to this destination: persistent selected transport must be distinguished from parallel checks, Tailscale Serve from T3 Connect through backend proxy ownership, and disconnection from successful relay fallback. Restore the anchor/reference/PF baseline and watch the actual desktop return to LAN. Record first observed transitions and sampling intervals. No screen, restart, auth issuance or raw catalog change is used.

    Requirements and who asked: User authorized per-destination screen-free fallback proof with safety checks and restoration.
    Deleted: Bestia's endpoints from this invocation because its work check is positive; no broader traffic interruption or state deletion is introduced.
    Bottleneck: Observe rocky's real client fallback while bestia's independent precondition clears or is classified.
    Checked myself: Current destination work metadata, existing cavallo -> rocky LAN socket and server corroboration, selected rule-parser success and exact candidate independent PASS/core equivalence.

  7. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: Cavallo's live client demonstrated LAN, Tailscale HTTPS 8446, T3 Connect and automatic return to LAN to rocky; its proof and rollback are pushed in runbook 2dcc427.
    Why: Exact-port client blocks, actual client sockets, Tailscale/cloudflared backend proxy owners and PF counters distinguish the transport, while catalog reachability alone could not.
    So what: The issue body now records timings, the recovered PF cleanup failure and remaining catalog/phone limits; bestia is the next simulation after a fresh client-work check.

    The issue body's controlled-proof section is the current detailed evidence. Earlier assumptions that cavallo lacks a rocky relay route are superseded by actual relay success. No UI or restart was used. The old guard removed blocking rules but initially retained its own PF enable reference because of an installed-output parser mismatch; manual scoped release restored the original PF state, and the corrected bestia-only guard has independent exact-digest review. This is not saved-route persistence or all-client acceptance.

  8. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: The reviewed bestia-only cavallo firewall simulation is ready after the 14:53:23Z client-work and PF ownership checks.
    Why: No active run contains human/unknown input or an active secret card; the sole pending message request belongs to a completed run. Cavallo has PF disabled, no states/references, no task rules, unchanged root/NAT/disk PF and a stopped previous guard.
    So what: Install the one-shot independently reviewed bestia-only guard, record its private backup, arm timed rollback before the exact-port blocks, observe each fallback and restore.

    Candidate guardian-bestia-only.py SHA-256 d673e4b3d363bf0f77b8adaae1a37954669be583163d955ff51793d128994b7d passed app-owned independent review r13, including the installed PF reference headers and unchanged safety fixes. Scope is only bestia LAN 3773 and known IPv4/IPv6 tailnet 3773/443 from cavallo; rocky and SSH are untouched. The user-authorized guardian has a 300-second monotonic expiry, retries scoped cleanup until verified, never kills states and releases only its own PF enable reference. It refuses nonempty states or changed firewall ownership. Existing client/server agents stay running; no UI, auth issuance, restart or raw catalog/database writes.

    Oracle: cavallo's actual NetworkService socket plus bestia's direct peer or matching tailscaled/cloudflared loopback proxy owner, with PF counters. Expected LAN -> Tailscale -> T3 Connect -> LAN; absent relay is reported as a missing route, not success. Sampling bounds limit timing claims. Saved catalog persistence and phone remain outside this proof.

  9. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: Cavallo used LAN, then Tailscale HTTPS, then returned to LAN to bestia; T3 Connect fallback was not observed under the combined blocks.
    Why: Actual client/server/proxy sockets and PF counters distinguish those routes; stale backend sockets do not establish a working client route, and encrypted catalog membership remains unknown.
    So what: The current issue body records timings, automatic restoration and exact cavallo/phone steps for the planner to pass on; latest runbook proof/rollback is pushed at 7a78100, with independent review in progress.

    The controlled bestia proof section is the detailed current record. Both temporary experiments are restored; no task rules, held PF references, states or guardian processes remain, and prior live/disk policy matches retained backups. Rocky's conditional desktop-to-bestia test was skipped because the actual helper had only own-loopback sockets. This is not all-client acceptance: inspect bestia's relay route/status on cavallo, phone learned routes/order, and the unobserved remote catalogs. Prior 2dcc427 independent findings are success; its minor timing wording is corrected in the new candidate.

  10. lukemaj commented on Oct 14, 2026

    @lukemaj
    ContributorAuthor

    What: Both temporary client firewall experiments are restored, and runbook 7a78100 has independent exact-SHA success.
    Why: Actual cavallo routing proved LAN / Tailscale HTTPS / T3 Connect / LAN to rocky and LAN / Tailscale HTTPS / restored LAN to bestia, with no observed bestia relay fallback; saved catalog and phone evidence remain separate.
    So what: Keep #292 open and pass its exact cavallo/phone steps to the user; inspect bestia relay membership/status, phone learned routes/order, and the other unobserved remote catalogs before claiming the outcome complete.

    Final recheck at 15:14:41Z retained original disabled PF, empty states/references/task rules, unchanged live root/NAT policy and both stopped guardians. Backups/disk comparison, authentication checks, timings, sampling limits and rollback are in the body and reviewed machine records. Review's nonblocking sampling-count and conditional Add T3 Connect notes are incorporated into the current issue proof and UI guidance; no further live intervention follows from them. The conditional rocky -> bestia test was skipped on actual own-loopback-only sockets. #286 remains closed not planned; no product PR or competing headless catalog implementation exists. The canonical continuation handoff in this body is current.

  11. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: The automatic relay-route product fix is owned in fix/292-learn-relay-route, based on current origin/main 503282b9117ac946f637e5a6995e870e04549bba.
    Why: Direct route learning consumes server directEndpoints; it does not add the saved environment’s T3 Connect route.
    So what: Complete the requested Opus design and Sol/Grok design reviews, implement focused proof, then merge only after exact-head independent Sol/Grok success and green CI; deployment and physical fallback proof remain with the planner.

    Workspace: /home/luke/dev/toolboxmd/chromeria-worktrees/292-learn-relay-route. The canonical main checkout and its untracked scripts/__pycache__/ are untouched. No version bump, live configuration change, restart, deployment, browser use, or live database write is authorized by this implementation slice. Closed #286 remains out of scope.

    Upstream first: inspected pingdotgg/t3code main 339179f50a84dc599cce373dbb48f172f182f44e routes, connection startup and relay discovery. Searched PRs/Issues for relay route, learned routes, learn T3 Connect, relay learning, automatic relay, and T3 Connect automatic. Merged #15467/#15468 provide route preference and advertised direct-address learning already present in this fork. Read the complete diff of open #19358: it adds a direct address to an existing relay environment without pairing, the reverse direction of this requirement. No exact automatic relay-learning fix found in this bounded search, so there is no upstream candidate to port.

    Acceptance for this product slice: a saved remote environment gains its existing, account-usable relay route automatically; newly learned relay is last after LAN/Tailscale; signed-out clients do not invent usable relay access; authoritative tunnel removal removes the route; pairing/auth and primary ownership remain unchanged on desktop, web and mobile; no tunnel provisioning or maxTunnels consumption. Focused tests cover positive and reverse transitions. Final live proof remains cavallo’s saved bestia route list plus forced fallback after the planner’s deployment. #292 stays open for that broader acceptance.

    Requirements and who asked: The user explicitly requests automatic relay routes for saved remote environments, the Opus then Sol/Grok design sequence, exact-head independent dual review, green CI and merge without deployment.
    Deleted: Manual Settings enrollment, client tunnel provisioning, server changes unsupported by source evidence, own-server/primary repairs, version bumps and machine changes.
    Bottleneck: Select the source of account-usable relay membership before changing client state; Opus design is running read-only in app-owned task 292-opus-design-r1-20261015.
    Checked myself: Read #292/#286, traced direct route merge, registry persistence/removal, driver priority and DPoP authorization, compared upstream main and the complete related open PR diff, and verified the exclusive worktree base.

  12. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Opus recommends learning existing relay membership from the signed-in account’s tunnel list.
    Why: A server advertisement cannot establish whether the client’s account can use its tunnel.
    So what: Sol and Grok are independently roasting this design before implementation. Existing GitHub routing trust resets remain unchanged as recommended; no human decision is needed to preserve current behavior.

    I've finished the design. Verdict: go. The watcher should key off the signed-in account's tunnel list, not the server's advertisement. One security choice is yours (GitHub routing trust, point 4 under Risks).

    Design for #292: saved remote servers gain their T3 Connect route automatically

    Sources are from the worktree at 503282b911. No files, Issues or PRs were touched.

    Which source decides

    • Server advertisement (rejected). ServerConfig.directEndpoints only carries lan and tailnet (packages/contracts/src/server.ts:666-698). Even with a new "linked" flag, the server can't know whether this client's account can reach it, and using it would need a wire change on every surface.
    • Account tunnel list (chosen). A relay route only works when the client's own account lists that server. The broker authorizes with the client's own cloud session against expectedEnvironmentId (connection/resolver.ts:229-246). listEnvironments returns the whole list, not pages (relay/managedRelay.ts:713-721). The discovery service already lives in the shared connection layer that web, desktop and mobile all use (connection/layer.ts:81-87).

    Representative caller paths

    1. Common case: cavallo opens with bestia saved over LAN. After the account loads, discovery refreshes (relay/discovery.ts:328-341) and lists bestia. The watcher sees bestia saved without a relay route and adds it. insertRoute ranks relay last (routes.ts:117-143), so the order becomes LAN, learned Tailscale, then T3 Connect.
    2. Not signed in, still loading, offline, or discovery failed. Discovery's empty state and an empty account currently look the same (discovery.ts:50-55, 219-243). So the watcher only acts once discovery confirms a successful listing for the current account. Before that it does nothing, and it never removes anything.
    3. Account switch or sign-out. Today's cleanup already strips relay routes on web (apps/web/src/cloud/managedAuth.tsx:50-58) and mobile (CloudAuthProvider.tsx:96, cloud-drafts.ts:45). The watcher compares the account discovery listed against the session's current account and does nothing on a mismatch. That stops it re-adding the old account's routes during cleanup.
    4. Server unlinked from T3 Connect. A complete listing no longer includes it, so the watcher removes its relay route. It only does that when other routes survive (routesAfterRemoving, routes.ts:404-427). A server reachable only through T3 Connect is left alone and is never deleted automatically.
    5. The user tries to remove the relay route. It would be re-added within seconds, so the remove control would lie. Treat it the way learned routes already work (docs/user/remote-access.md:81-83): it can be reordered but not removed. The ways out are signing out, unlinking the server, or removing the machine.
    6. Desktop's own server and the served-web primary. These are skipped by the existing platform-environment guard (registry.ts:563, 612), so they stay out of scope as Primary environments silently discard additional connection routes #286 decided.
    7. Tunnel limit (maxTunnels). Adding a route is a local catalog write, followed by the normal client connect. The tunnel limit only applies when a server links itself or recovers its tunnel, and both use server credentials (infra/relay/src/http/Api.ts:905 and around 1341/1378). Clients create no tunnels.
    8. Pairing and authentication. Nothing changes. There is no pairing code, no bearer token copied, and LAN tokens are untouched.

    Where the code changes go

    • relay/discovery.ts: add listedAccountId to the discovery state. Set it from CloudSession.identity in the same update that stores a successful listing for the current account. Clear it when a refresh starts, on credentials change, when signed out, and on errors. Using the same source as the watcher avoids any token-versus-user-id mismatch.
    • connection/registry.ts: add one method, reconcileRelayRoute(environmentId, relay: Option<RelayConnectionTarget>). All decisions happen inside the per-environment lock:
      • skip platform environments, missing entries, and (for adds) entries marked unsupported;
      • add: reuse register's merge logic (:566-590), but never create an environment, so a machine the user just removed can't come back;
      • remove: call replaceRoutesLocked only when routes remain.
    • connection/layer.ts: add watchAccountRelayRoutes next to watchDiscoveredCompatibility (:19-73), started in the startup block (:88-99). It reacts to discovery and catalog changes and only calls the registry when the relay route's presence doesn't match the listing. It also skips servers where discovery reports a compatibility error, as the button does (CloudEnvironmentConnectList.tsx:151).
    • connection/routes.ts: add a small shared helper meaning "learned or relay", and use it for the remove gate in EnvironmentRoutesList.tsx:124 (web) and EnvironmentRoutesSection.tsx:223 (mobile).
    • Docs: update docs/user/remote-access.md:66-95. The "Add T3 Connect" button stays as a manual retry.

    Tests

    • discovery.test.ts: listedAccountId is empty during refresh, when signed out, on error and after a credentials change, and set after a successful listing.
    • registry.test.ts, using the existing discovery fakes around :794 and :958, synchronized with Deferred rather than sleeps:
      • a LAN-saved environment gets relay appended last, and it is persisted;
      • nothing happens while loading, signed out, on error, or with a stale account;
      • the watcher never creates an environment;
      • an unlisted server loses its relay route but keeps LAN;
      • a relay-only server with routes learned through relay is left untouched;
      • platform and unsupported entries are skipped;
      • sign-out removal still works.
    • routes.test.ts: the remove-gate helper.

    Rejected alternative

    A persisted "relay declined" flag per server, so the relay route could be removed and stay removed. It needs a new field in the shared storage document, two adapter methods, registry plumbing, and a new mobile re-add row (mobile hides saved machines from the relay list, useConnectionController.ts:66-69). Nobody asked to opt one server out while signed in, and learned routes already set the precedent.

    Risks

    1. Strongest: an empty listing read as "no tunnels". Without the listedAccountId gate, an app still loading its account would strip every relay route. Through removeRoute it would also delete relay-only machines along with their cache and drafts (registry.ts:840-863). The account gate plus "never delete an environment" closes this, and the tests above must prove it.
    2. One reconnect per server, once. Adding the route restarts the live session through installEntryLocked. Updating it in place would need a new supervisor API, because usesRelay is fixed when the supervisor starts (supervisor.ts:275).
    3. New servers wait for the next refresh. That is app start, sign-in, the network coming back, or opening Settings. No polling is added.
    4. GitHub routing trust (your decision). Adding or removing the relay route resets that server's GitHub routing permission to off (githubRoutingPermissions.ts:21-27, registry.ts:546-553), exactly as the manual button does today. I recommend keeping that behaviour, so the security model is unchanged. The alternative is to carry the permission over to the account's route.
    5. The remaining Every client uses LAN, then Tailscale, then T3 Connect to every server #292 gap. This won't fix cavallo's failed fallback to bestia if bestia isn't linked to cavallo's account, or if its tunnel is broken. Someone needs to check bestia is in that account's list.

    Elon record

    • Requirements and who asked: the user (Every client uses LAN, then Tailscale, then T3 Connect to every server #292) wants saved remote servers to gain their working T3 Connect route automatically, ordered LAN, Tailscale, T3 Connect, without pairing or new tunnels. Own servers are out of scope (Primary environments silently discard additional connection routes #286).
    • Deleted: the server-advertisement contract change, the persisted decline flag, polling, and updating the live session in place.
    • Bottleneck: saved catalogs never receive relay routes on their own; the manual button is the only path, and mobile has none.
    • Checked myself: the routing and merge code, the registry lock paths, discovery states, web and mobile sign-out cleanup, the remove gates in both route UIs, the unpaginated listing, and where the tunnel limit applies. Not checked: that discovery refreshes on a signed-in cold start; that is inferred from discovery.ts:336-340 and apps/web/src/connection/platform.ts:149.
  13. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Sol and Grok both require a revised design before implementation.
    Why: Account lists include publish-only links, and watcher-only identity checks cannot fence pending writes against sign-out.
    So what: Both reviewers are assessing the revision below under the user’s round-2 blocking rule; implementation has not begun.

    Round 2 revised design, superseding conflicting details of Opus r1:

    1. Keep account list source. Discovery state gains listedSession: Option, the exact stable identity object from CloudSession.identity. Capture before token/list, verify the same object and generation after awaits, publish it atomically with successful complete list. Clear at refresh start, credential invalidation, sign-out, error. Never interpret EMPTY/loading/offline/error as authoritative absence.
    2. Registry owns a no-argument reconcileRelayRoutes effect. It captures CloudSession and RelayEnvironmentDiscovery services; per saved environment, inside the lease lock, rereads live discovery and session. It acts only when listedSession is Some and exactly the current identity, and state is not offline or failed. Thus it never accepts an old caller Option decision and never creates an environment. Missing/platform/unsupported-for-add entries skip. A shared relay reconciliation semaphore also wraps removeRelayEnvironments, with cleanup's snapshot taken AFTER acquiring it: a pending write is drained before cleanup snapshots; a queued stale reconcile sees no current identity. This closes both lease-wait and in-progress persistence/sign-out interleavings. Tests pause both lock acquisition and persistence and then sign out or switch account.
    3. Only cloudflare_tunnel records qualify for presence. An automatic addition further requires that record's validated online status, a present compatible descriptor, and no entry error, after status validation has completed. No add for checking/error/offline, manual, t3_relay, or delayed incompatibility. Existing relay for a listed cloudflare tunnel stays through temporary offline/error. An authoritative missing record or downgrade to manual/t3_relay removes relay and relay-dependent learned routes when independent routes survive. Relay-only entries are retained to avoid silently deleting local data, an explicit exception/follow-up.
    4. New relay uses current saved label and insertRoute, appended last after LAN/Tailscale; repeated discovery does nothing. Existing user reorder remains owned by the user, as both r1 reviewers cleared. replaceRoutesLocked preserves disabled state, resets GitHub routing trust under existing address policy, and rebuilds supervisor once; direct credentials/pairing/auth and mixed-content rules stay unchanged. All clients use shared connection layer; no provider/MCP/wire/server changes. Clients call no linking/provisioning operation, consume no maxTunnels slots.
    5. A shared startup watcher merges discovery/catalog changes and invokes the registry effect with caught per-update logging. Registry layer provides the same memoized discovery layer already exposed by shared startup. Discovery gets an explicit startup refresh to cover an account already active when its subscriber starts, plus existing credential/network triggers. App-active wakeups refresh discovery so remote unlink is learned on returning to app without Settings. No polling.
    6. Keep implementation focused on shared runtime, tests, map PR ref and short remote-access user guidance. Defer UI removal-control semantics, the existing manual Add T3 Connect predicate bug, immediate deregistration-cache invalidation, and retained relay-only unlinked entries to linked follow-up Issues per user's round-2 scope rule. No UI layout/rendering change or new opt-out persistence in this PR. The existing remove action can be relearned by reconciliation; that UX gap is explicitly deferred, not claimed resolved.
      Proof: positive managed/compatible auto-add and persistence after LAN/Tailscale, delayed incompatible/manual/t3_relay no-add, never create unknown/primary, signed-out/loading/error/offline/stale-identity no effects, authoritative removal/downgrade preserving bearer credential, relay-only data protection, startup account already present, failed refresh no deletion, account change during listing and during paused persistence/lock. Use Deferred/stream milestones, no sleeps. Focused route/registry/discovery/auth tests, package typecheck, targeted lint; no browser/server/deploy. Planner staffs cavallo live proof after deployment.
      Adjudication r1: accept both reviewers' managed endpoint and stale-write findings; accept Sol delayed-compatibility finding using stronger health gate. Sol cold-start race retained as real possible subscription ordering and fixed with explicit startup refresh, despite Grok's normal-order cold-start evidence. Grok clarified release-only allocation removal is recoverable and not account unlink, so listed cloudflare/offline routes stay; publish-only downgrade removes them. Existing manual button and removal-control gaps get follow-ups. No unresolved core objection currently known.

    Sol r1:
    Verdict: revise before building. The shared-client approach is sound, but account-list membership alone does not establish a usable relay route. Reviewed source at 503282b9117ac946f637e5a6995e870e04549bba, #292/#286, and the routed procedures; no writes or runtime tests.

    1. Required: exclude publish-only registrations and handle tunnel downgrade.
      Trigger/source: Enable activity publishing without T3 Connect, or disable the tunnel while leaving publishing enabled. linkEnvironment.ts:251 uses provider manual; EnvironmentLinker.ts:290 deprovisions the tunnel but retains the account link. EnvironmentLinks.ts:277 lists every unrevoked link.
      Effect: The proposed watcher adds an unusable relay, or retains one after tunnel removal. The broker rejects nonmanaged endpoints at EnvironmentConnector.ts:322.
      Minimal resolution: Distinguish listed registrations from eligible managed relay routes. Treat an authoritative downgrade as relay removal, preserving independently authenticated direct routes. Cover both transitions.

    2. Required: wait for compatibility discovery before automatic addition.
      Trigger/source: The list returns before a relay’s incompatible status response. discovery.ts:267 publishes entries with availability: "checking" and no status before starting status requests. The proposed button-equivalent check treats missing descriptors as compatible: CloudEnvironmentConnectList.tsx:42.
      Effect: Setting listedAccountId alongside that initial list permits an unusable relay to be persisted. Later skipping the incompatible entry does not undo the addition.
      Minimal resolution: Defer automatic addition until that entry’s compatibility check has settled successfully. Test a delayed incompatible response, rather than only a pre-marked unsupported catalog entry.

    3. Required design clarification: account checks must fence pending mutations.
      Trigger/source: Reconciliation selects account A, then waits on a lease lock or persistence while sign-out proceeds. registry.ts:288 can suspend lock acquisition; removeRelayEnvironments:1004 snapshots only entries already containing relay.
      Effect: A pending addition absent from that snapshot can finish after cleanup, leaving a signed-out client with an unusable relay. A watcher-side account comparison alone does not prevent this.
      Minimal resolution: Bind reconciliation to the captured session identity and invalidate or drain stale work before account cleanup completes. Prove the interleaving with a paused addition followed by sign-out/account switch. Existing DPoP checks prevent unauthorized access; this finding concerns stale route state.

    Two additional round-1 gaps should become linked follow-up Issues if deferred under the later-round rule; I created none under the read-only instruction:

    • Cold-start refresh is not guaranteed. managedRelayAccountChanges:169 drops the initial account emission, and discovery has no unconditional startup refresh. An account already active when discovery subscribes can remain undiscovered until another trigger. Add explicit startup coverage and resolve that ordering.
    • Account deregistration refreshes a different cache. Mobile’s T3ConnectProfilePage.tsx:85 refreshes the profile query manager, not RelayEnvironmentDiscovery. Consequently, deregistration need not promptly reach the proposed removal watcher. Invalidate shared discovery after successful deregistration.

    Cleared: new relay insertion preserves direct-route priority; the broker retains account-scoped DPoP authentication; platform exclusions match #286; this path needs neither tunnel provisioning nor maxTunnels consumption. Preserve the chosen GitHub trust reset. Retaining an unlisted relay-only environment protects local data, but explicitly record that exception to #292’s “removed tunnel removes route” acceptance.

    Grok r1:
    Revise before building. The account-list watcher is the right shape, and relay insertion ranks last, but the sketch can add a route the broker will refuse and can put a relay route back after sign-out.

    Reviewed 503282b9117ac946f637e5a6995e870e04549bba on fix/292-learn-relay-route, read-only. Two findings should change the design. The rest of the checked claims hold.

    Blocking

    1. Sign-out can be undone, and the next refresh will not repair it.

    Trigger: a discovery update starts a reconcile, then the user signs out before that write finishes. Web does this in apps/web/src/cloud/managedAuth.tsx:72-76 and mobile in CloudAuthProvider.tsx:123-127: the session atom is cleared, then removeRelayEnvironments runs on another fiber (registry.ts:1002-1020).

    Source: reconcileRelayRoute(environmentId, relay: Option<...>) receives an add/remove decision made outside the lease lock. The account comparison is described on the watcher, not inside the lock. removeRelayEnvironments is not on the discovery stream, so it can finish, and the in-flight add can run after it.

    Effect: the relay route returns while signed out. A signed-out refresh leaves listedAccountId empty, and the watcher is specified never to remove in that state, so nothing takes the route back off. Relay-only machines stay deleted, because a missing entry is not recreated. A machine that still has LAN or Tailscale keeps a T3 Connect route with no cloud session. authorizeDpop fails closed (authorization/service.ts:366-368); the LAN token is not copied.

    Resolution: inside the per-environment lock, re-read the live session and the confirmed listing and write only if they are the same account. A stale Option must not be enough to write. Test it by holding the lease lock across removeRelayEnvironments, then releasing it.

    2. A listed link is not a usable T3 Connect route.

    Trigger: the account link exists with providerKind manual or t3_relay, or the saved machine is the publish-only link from apps/web/src/cloud/linkEnvironment.ts:251-277. listForUser returns every unrevoked link (EnvironmentLinks.ts:277-307). It does not require a tunnel.

    Source: validateManagedEndpoint refuses anything other than cloudflare_tunnel with a ready allocation (EnvironmentConnector.ts:322-327). connectEnvironment only mints a credential for that endpoint (Api.ts:1064-1083). It does not create a tunnel, and maxTunnels is only on link (Api.ts:905) and server recovery (Api.ts:1341, 1378).

    Effect: the watcher appends a T3 Connect route that connect always refuses with endpoint_provider_not_managed. The new remove gate then makes that route unreovable, same as a learned route. The saved-route button has the same predicate (ConnectionsSettings.tsx:2962-2966), so a manual retry would put it back.

    Resolution: add the route only when the listed endpoint's providerKind is cloudflare_tunnel. Use that same predicate on the button. A listed link of another kind is treated like an unlink: remove the relay route when routesAfterRemoving still leaves a route. Leave a relay-only machine in place, so the environment, cache, and drafts are not deleted.

    Cleared

    Relay cannot be inserted ahead of LAN or Tailscale. insertRoute ranks relay 5, after loopback, LAN, tailnet, VPN, public, and SSH (routes.ts:117-142). An existing relay route that the user already placed first is left where it is.

    Server advertisements still cannot decide this. directEndpoints is only lan and tailnet (server.ts:666-698). Desktop, web, and mobile all start connection/layer.ts, so one watcher covers them. Platform-owned ids, including this desktop's own server and the served-web primary, are skipped at registry.ts:563 and :612.

    Cold start does refresh. The session atom starts empty, the auth effect sets it, and that emits credentials-changed (platform.ts:148-150). Discovery refreshes on that wakeup (discovery.ts:328-340), which discovery.test.ts already covers. Mobile Settings does not refresh on open. It refreshes on pull-to-refresh. Web Connections does, because CloudEnvironmentConnectRows mounts there.

    Unlink removes the row. Tunnel release does not (Api.ts:975-988), so the link stays listed and the route should stay until the server recovers it. Signing out still uses today's removeRelayEnvironments. GitHub routing trust resets when the saved addresses change (githubRoutingPermissions.ts:21-27, registry.ts:546-553). Keeping that for this automatic write matches the current button.

    Mobile does not hide a LAN-saved machine from the cloud list. relayManagedEnvironmentIds hides only machines that already have a relay route (environmentSections.ts:16-30). Registering that row already merges a relay route. The decline flag is still worth rejecting because nobody asked to opt one server out. The reason is not a missing mobile row.

    Drop the compatibility skip, or apply it only after refresh has finished and a descriptor is present. The listing is published at discovery.ts:276 while every status is still empty, and discoveredCompatibilityError of an empty status is null (CloudEnvironmentConnectList.tsx:42-46). That cite is the cloud-list connect button. The saved-route button does not check it. watchDiscoveredCompatibility only disables a one-route relay environment (layer.ts:48-52), so a bad fallback does not turn off a working LAN route.

    Elon record. Requirements and who asked: the user, in #292, wants a saved remote server to gain a working T3 Connect route after LAN and Tailscale, without a new tunnel or a pairing change. Own servers stay out (#286). Deleted: the advertisement contract, the decline flag, polling, and the compatibility skip. Bottleneck: the write must follow a confirmed cloudflare-tunnel listing for the session that is still signed in. Checked myself: route ranks, registry lock and sign-out removal, discovery publish points, both route UIs, listForUser, connector validation, and the client connect path on this SHA.

  14. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Deferred route-lifecycle findings are tracked separately in #360, #361, #362 and #363.
    Why: The user limits blocking findings from design round 2 onward to unusable automatic routes, incorrect relay priority, and supported-client pairing/auth failures.
    So what: Keep this PR focused on automatic account-usable membership; these follow-ups own route-removal controls, manual button eligibility, last-route data preservation and deregistration invalidation respectively.

    #360
    #361
    #362
    #363

    Existing package baseline typecheck also passed, in addition to the 137 focused baseline tests. No browser/server or deployed-client proof is claimed.

  15. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Both required design reviewers passed the revised automatic relay-learning design.
    Why: Managed, compatible health gating and serialized account cleanup resolve the unusable-link and stale-write findings.
    So what: Implementation is proceeding in the owned worktree; exact-head implementation reviews, CI and merge remain pending, with deployment and live proof reserved for the planner.

    Sol round 2:
    PASS for round 2. No blocking finding remains under the three permitted gates. Reviewed the revised design against source at 503282b9117ac946f637e5a6995e870e04549bba, #292/#286, and the routed procedures.

    • Stale writes: The proposed semaphore closes both identified interleavings. Take it before environment lease locks in reconciliation and cleanup, and retain it through persistence and runtime installation. An addition already writing finishes before cleanup snapshots; queued reconciliation reads the cleared session inside the lease lock and skips. Web and mobile both deactivate authentication before cleanup and await cleanup before activating another account.
    • Usable account membership: The stronger health gate resolves the publish-only and delayed-compatibility findings. Connector status checks the account link and managed allocation; server health checks the installed account identity. Requiring validated online status and a compatible descriptor establishes eligibility without provisioning. It cannot guarantee future availability.
    • Priority and authentication: insertRoute places new relay routes after LAN/Tailscale. Both client storage adapters use setRoutesInCatalog, which preserves retained bearer credentials. Existing account-scoped DPoP authorization, pairing, mixed-content protection, and GitHub trust reset remain intact. No tunnel creation or maxTunnels consumption is introduced.

    The accepted nonblocking gaps have linked follow-ups: removal controls #360, manual-button eligibility #361, retained relay-only entries #362, and deregistration invalidation #363. No additional finding.

    Requirements and who asked: User requires automatic usable relay fallback after LAN/Tailscale with supported-client authentication preserved.
    Deleted: No further mechanism is necessary.
    Bottleneck: Implement and prove the specified synchronization and eligibility gates.
    Checked myself: Lock consumers, auth transitions, health/connect authorization, persistence, route ordering, and follow-up records.

    Design verdict only; implementation and runtime proof remain outstanding. No writes or runtime tests performed; workspace remains clean at the reviewed SHA.

    Grok round 2:
    PASS. The revised design does not add an unusable relay route, does not rank a new relay ahead of LAN or Tailscale, and does not change pairing or authentication on web, desktop, or mobile.

    Reviewed 503282b9117ac946f637e5a6995e870e04549bba on fix/292-learn-relay-route, read-only, with #292 and #286. No new follow-up defect. The four items the design already defers stay follow-ups.

    The shared semaphore closes the stale write when the reconcile effect holds it from before each lease wait through the catalog write, and removeRelayEnvironments snapshots only after acquiring that same semaphore. Web and mobile both clear the session atom before cleanup (managedAuth.tsx, CloudAuthProvider.tsx). Inside the lease, a live re-read of CloudSession.identity sees None, so a queued reconcile cannot write. An in-flight write that already passed the check still finishes under the semaphore, and the cleanup snapshot then includes that route and removes it. CloudSession.identity returns the ManagedRelaySession object, and setManagedRelaySession keeps that object for the same account. Reference equality is the same check assertSession already uses. The planned lock-acquisition and persistence pauses cover both interleavings.

    A listed link is not enough to add a route, and the health gate supplies the missing proof without provisioning a tunnel. listForUser returns every unrevoked link, including manual and t3_relay. getEnvironmentStatus reaches validateManagedEndpoint, which rejects anything other than a cloudflare_tunnel with a ready allocation, then returns online only after a verified health response. Discovery stores that as availability: "online" with a descriptor. The design adds only after that status has settled, the descriptor is present, and orchestrationProtocolCompatibilityError is absent, so a checking list and a delayed incompatible response do not persist a route. A manual or t3_relay record fails status and is removed when another route remains. Connect mints a credential for that same managed endpoint. maxTunnels is only on link (Api.ts around 905) and server recovery (around 1341 and 1378).

    insertRoute ranks relay at 5, after loopback, LAN, tailnet, VPN, public, and SSH. A new route is appended. An existing user order is left in place. replaceRoutesLocked persists the relay target through setRoutes and leaves bearer credentials and profiles on the routes it keeps. Relay authorization stays on authorizeDpop. Platform-owned environments stay skipped.

    Elon record. Requirements and who asked: the user, in #292, wants a saved remote server to gain a working T3 Connect route after LAN and Tailscale, with no new tunnel and no pairing change. Own servers stay out under #286. Deleted: advertisement changes, a decline flag, polling, and treating a bare account link as routable. Bottleneck: the catalog write has to follow a confirmed managed, compatible listing for the session that is still signed in. Checked myself: lease and sign-out ordering, session-object identity, status-to-validateManagedEndpoint, route ranks, credential storage, and the client connect path on this SHA.

  16. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Automatic relay-route learning is implemented in PR #364, with green CI and exact-head Sol review success; it is not merged or deployed.
    Why: Required Grok implementation review could not run because Grok Build returned 402 Payment Required: Grok Build usage balance exhausted.
    So what: Restore Grok capacity, run a new Grok review on the current head, and require its findings comment plus review/independent-grok=success before the already-authorized merge; the planner still owns deployment and live fallback proof.

    Canonical product-fix continuation

    Final behavior and proof

    The shared client runtime uses a successful complete tunnel listing tied to the exact live cloud-session identity. Automatic addition requires a cloudflare_tunnel, validated online status and a compatible descriptor. New relay routes append last after direct routes. Sign-out cleanup shares the reconciliation lock and snapshots only after pending automatic writes drain. Authoritative unlink or manual-provider downgrade removes relay and relay-dependent routes when independently authenticated routes remain; relay-only local data is retained (#362). Startup and app-active refresh discover account changes without Settings. No clients create tunnels or consume maxTunnels slots. Primary/own-server behavior and paired bearer/DPoP authentication remain unchanged.

    Focused command on the final rebased head: node_modules/.bin/vp test run with these 10 files, 197 passed:

    • packages/client-runtime/src/connection/routes.test.ts
    • packages/client-runtime/src/connection/registry.test.ts
    • packages/client-runtime/src/connection/resolver.test.ts
    • packages/client-runtime/src/connection/supervisor.test.ts
    • packages/client-runtime/src/relay/discovery.test.ts
    • packages/client-runtime/src/state/threads-atoms.test.ts
    • packages/client-runtime/src/authorization/layer.test.ts
    • apps/web/src/components/cloud/CloudEnvironmentConnectList.test.tsx
    • apps/web/src/cloud/managedAuth.test.ts
    • apps/mobile/src/features/cloud/CloudAuthProvider.test.ts

    Client-runtime/web/mobile package typechecks passed, along with targeted TypeScript lint, format/diff checks, node scripts/fork-features.mjs check, and bash scripts/fork-check.sh --base 8d11fe1261f0dfd74f58a1b1ae8ad7e400905fcb. Current CI is green, including full typecheck, lint, build, web/package/server tests, fork model and release smoke. No repo-wide local checks were run.

    Adversarial proof: removing the cleanup semaphore makes the paused-persistence sign-out case fail with a stale relay in persisted targets; restoring it passes. The first mutation trial exposed insufficient test ordering, corrected with immediate fiber start before retaining this proof. This is isolated behavioral/mutation evidence, not a deployed reproduction.

    Review and remaining gates

    Opus design and Sol/Grok round-2 design verdicts: #292 (comment). Both design roasts initially required managed-link eligibility and stale-write corrections; both passed the revision. Deferred non-core findings are #360, #361, #362 and #363.

    Current exact-head Sol implementation findings: #364 (comment), posted before review/independent-sol=success on 4ab2b153447da4520104af790bd6cec09d3609e6. Grok implementation task 364-grok-implementation-r1-ae55583 failed before a verdict with 402; current review/independent-grok=error accurately retains that unavailable gate. Earlier design verdicts and historical Sol success are not substituted for exact-head review.

    Next required Grok review must be a new delegate_task round for the current candidate, retaining the original brief, prior findings, responses and deferred Issues. Do not continue an old review round through its backing child thread. After Grok success and fresh green CI/current-head checks, merge under delegated authority and retire only this task's eligible workspace/branch. No deployment authority is included.

    Planner-owned post-deploy proof remains cavallo's saved bestia entry showing T3 Connect last and actual fallback reaching it with LAN and Tailscale blocked. Bestia must be a usable tunnel in the client's signed-in account; this implementation cannot invent account access or repair a broken tunnel.

    Requirements and who asked: User requires automatic usable relay fallback, LAN/Tailscale first, preserved supported-client pairing/auth, Opus then Sol/Grok design review, exact-head dual implementation review, green CI and merge without deployment.
    Deleted: Manual enrollment as the required path, tunnel provisioning, advertisement changes, polling, primary-route changes, opt-out state and non-core lifecycle work.
    Bottleneck: Required Grok implementation capacity is unavailable; no merge waiver or account spending is authorized.
    Checked myself: Live current PR/head/statuses/CI, clean pushed worktree, complete changed source and consumers, 197 focused tests, package checks, mutation sensitivity and rebase range-diff.

  17. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Deploy merged main 3ca60f09521d6de7ec14a749f2414805018d57f1 to cavallo, rocky and bestia, in order, then verify #292 and #276.
    Why: The user requests automatic last-priority account relay learning and the proven native busy-session updater policy in the live fleet.
    So what: This authorized implementation task owns manual retention, deployment, live acceptance and runbook records; close acceptance issues only if their criteria are met.

    Post-restart steps, written before bestia activation:

    • Confirm current e5aafd7 baseline and absence of active deploy/swap on all three. Manually retain two newest complete deploy backup sets and newest rollback; preserve active/open files and all live userdata. Record free space and exact cleanup manifest; permanent retention stays on runbook#10.
    • Build from owned clean exact-SHA worktrees. Sign Mac artifact on cavallo and promote it unchanged to rocky. Large copies and TMPDIR stay in task cache, never /tmp. Validate Linux executable imports and isolated archive before bestia. No live-data test server or live Cue.
    • Immediately before each restart inspect running threads, current tools, background tasks and requests. Use chromeria-restart-and-resume on rocky with a maintenance callback. Bestia uses ~/scratch/bestia-chromeria-swap-2026-10-14.sh under a detached user unit after both Macs pass.
    • After bestia activation, check exact installed and /proc binary digest, discovery/health 200, same listening backend after at least 600 seconds, peer links, migration startup and authenticated thread loading, restart continuations and held queues. Roll back only on health failure. Check registered tunnel and fresh boot-service log; stop and report any tunnel failure.
    • On cavallo inspect sanitized saved bestia/rocky route state, relay last. Repeat the scoped timed-self-removing PF-anchor LAN then Tailscale block test to bestia and verify relay and return to LAN. Preserve unrelated firewall state and restore task rules.
    • On bestia inspect Claude/Codex updater results and running-session continuity during active work; record observed outcomes on Provider auto-update never runs on a busy machine: any active run defers the driver #276. Record all client gaps on Every client uses LAN, then Tailscale, then T3 Connect to every server #292 rather than claiming untested mobile acceptance.
    • Per-machine runbook record, pull --rebase immediately before each commit, stage only owned paths and push without force. No planner-thread messages or agent memory.

    Requirements and who asked: User explicitly authorizes this three-host rollout, manual retention, scoped firewall test, active-work updater proof, issue completion and runbook pushes; supports working Promachos harnesses and remote clients.
    Deleted: Reimplementation, permanent cleaner, redundant Mac builds, broader cleanup, live Cue startup, health-independent rollback and unproved acceptance claims.
    Bottleneck: Sequential activation and ten-minute backend stability, then real-client fallback and actual updater observations.
    Checked myself: Live e5aafd7 identities on all machines, no armed Mac staging/restart, no bestia deploy unit, origin/main exact target, prior rollout scripts and today's runbook entries.

  18. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: The bestia post-restart plan includes the user's supported #358 relink command.
    Why: The previous #357 restart released the tunnel and did not restore it; the user reports endpoint 530 and no cloudflared.
    So what: After this rollout's bestia restart, run the supplied product-API relink without exposing tokens, require ok:true, registered tunnel connections and endpoint 200. Stop on invalid_grant or not_authorized; root-cause repair remains with its separate owner. The #292 fallback proof follows successful relink.

  19. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Bestia's candidate is now merged main a94a6d87c46b9b698d7d87201b50ae91453797e6, including #366 as well as #364/#365; both Macs remain on 3ca60f09521d for this round.
    Why: The user requested the new tunnel-recovery fix for bestia and explicitly left already restarting/upgraded Macs for the next round. Rocky was in its active shutdown/swap when that instruction arrived; it was left undisturbed.
    So what: The new Linux archive passed the unchanged executable-import validation, independent emitted-import scan and isolated archive serve smoke. Bestia remains last, after rocky's full stability proof. Inspect automatic registered tunnel connections and the public endpoint first; use the supplied supported relink only if it has not recovered, and record the actual method on #358. No new sign-in or unauthorized account mutation will be attempted.

    Linux archive SHA-256 10d67ea3dc56fcb2eee72536ac10844ab0a1b57fb6ff7f96aea6109753277aae; executable fa67884b5e560f031f5455744a1e6fef63002cdb14ba8e3e9594ca7fa92a1e33. Original unpromoted 3ca60f Linux artifact is superseded. All prior post-restart, health-only rollback, tunnel-error stop, protected-state and no-live-Cue requirements remain.

  20. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: Starting the authorized cavallo-to-bestia transport test with the unchanged reviewed, timed PF guardian.
    Why: Bestia's restored tunnel has four registered connections and a matching public descriptor at HTTP 200; actual desktop fallback remains separate from server reachability.
    So what: This client-only proof can run while the detached unit completes its independent ten-minute local backend observation. The guardian is armed before rules, restores after 300 seconds or an explicit restore request, and touches only bestia's documented Chromeria LAN/Tailscale ports. Any unsafe preflight or changed PF ownership stops the experiment.

    Fresh V2 metadata found only the operating agent run, zero human/unknown active input and zero active secret cards on bestia; cavallo has no nonterminal run/human input/active secret card. The remaining pending message request belongs to a completed historical route task and is not interactive work on an active run. The earlier transient second run finished before this fresh preflight.

    Guardian SHA-256 d673e4b3d363bf0f77b8adaae1a37954669be583163d955ff51793d128994b7d, byte-identical to the reviewed actual-header/lifecycle candidate already used on #292. New root-only evidence directory /private/var/tmp/chromeria292-20261015-a94-bestia; no persistent PF file or service change. It checks root policy, empty states/references, child ownership, and backs up configuration before arming. No state deletion, SSH block or server restart.

    Requirements and who asked: User requests the same timed-self-removing LAN, then Tailscale, then restored LAN fallback proof.
    Deleted: New firewall code/review, broad firewall reset, state deletion, another app restart and an invented saved-catalog claim.
    Bottleneck: Real desktop transport observation; the remaining 600-second backend interval is independently owned by the detached watcher.
    Checked myself: Current artifact/tunnel and account descriptor, fresh client/server work metadata, root PF disabled, exact unchanged guardian digest and prior review, current LAN/Tailscale socket endpoints. Expected result is a new retained T3 Connect connection when both direct paths are blocked, then LAN return; no retained relay connection falsifies that acceptance.

  21. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: The fleet rollout passed, and cavallo's real desktop reached bestia through T3 Connect with LAN and Tailscale blocked, then returned to LAN after restoration.
    Why: Bestia's previously broken tunnel is restored; source/API reachability alone had not established the actual desktop fallback.
    So what: This resolves the previously missing cavallo-to-bestia relay stage. #292 remains open for direct saved-catalog membership/order/persistence inspection, rocky's remote desktop destinations, the physical iPhone and any existing remote web-client acceptance.

    Deployed identities and server proof

    • cavallo and rocky: exact main 3ca60f09521d6de7ec14a749f2414805018d57f1; identical Developer ID signed ASAR SHA-256 4d7e62fcb2148d51b03a91d66104be2a0d779e29ebbc0760be208c1a6d3ce5d7. Backend PIDs 94131 and 78671 respectively stayed unchanged across 21 observations for 601.32 and 601.98 seconds. The user left already restarting/upgraded Macs on this SHA after fix(connect): recover released tunnels after service restarts #366 merged.
    • bestia, last: exact main a94a6d87c46b9b698d7d87201b50ae91453797e6, including fix(connections): learn saved servers T3 Connect routes automatically #364, fix(server): allow proven native updates during active sessions #365 and fix(connect): recover released tunnels after service restarts #366. Validated archive SHA-256 10d67ea3dc56fcb2eee72536ac10844ab0a1b57fb6ff7f96aea6109753277aae; installed plus actual /proc executable fa67884b5e560f031f5455744a1e6fef63002cdb14ba8e3e9594ca7fa92a1e33. Backend 2801447 stayed unchanged across 21 observations for 601.85 seconds, including the client-only PF experiment.
    • Every machine: health/discovery 200, both peer links reachable, successful runMigrations trace, migration 62, three authenticated thread snapshots loaded, and zero missing continuations/held queues. No rollback and no live Cue startup.
    • Bestia advertised actual LAN 10.31.36.187:3773, numeric Tailscale 100.116.0.2:3773 and Tailscale HTTPS 443 in fresh authenticated server.getConfig.
    • Automatic tunnel recovery was not observed on this first upgrade from the old runtime with recovery state already removed. The authorized supported relink restored four registrations and endpoint 200; zero new Tunnel not found afterward. Exact #358 proof and observer correction.

    Actual desktop fallback, 2026-10-15 UTC

    Unchanged reviewed guardian d673e4b3d363bf0f77b8adaae1a37954669be583163d955ff51793d128994b7d; root-only evidence at /private/var/tmp/chromeria292-20261015-a94-bestia. Fresh safety checks had zero human/unknown active input or secret cards; the only pending message request belonged to a completed historical task. PF started disabled with no states/references and unchanged root policy. The 300-second cleanup was armed at 11:30:51.376Z, before rules. Only bestia's documented Chromeria LAN and Tailscale TCP ports were blocked; SSH and rocky were preserved.

    1. Baseline 11:30:58.053Z contained a bestia LAN socket. LAN block applied 11:30:58.768Z. At 11:31:26 and 11:31:53, the same cavallo NetworkService PID 93005 had new bestia Tailscale HTTPS sockets; bestia tailscaled's backend loop 52432 was carrying traffic. Acknowledged backend bytes increased 54,700 → 192,798, received 5,170 → 6,142. The old LAN socket lingered with received bytes fixed at 463 and was not counted as a working route.
    2. LAN + Tailscale blocks applied 11:31:54.682Z, including IPv4 3773/443 and the documented IPv6 3773/443. At 11:32:37 and 11:33:22, the desktop had no direct bestia socket; new public HTTPS sources 64252 and 64254 to 104.26.2.228:443 persisted. Bestia cloudflared PID 2804870's new backend loop 55822 persisted, with acknowledged bytes 131,735 → 196,791, received 4,940 → 6,566. This controlled transition and retained traffic support actual T3 Connect use; process existence or a loopback socket alone was not the oracle. The old tailscaled loop stopped receiving client data and was not counted as a working direct path.
    3. Requested cleanup verified at 11:33:46.526Z. By 11:34:08.734Z, new LAN source 64358 was present; it remained at 11:34:45.208Z, acknowledged bytes 52,616 → 61,471, received 4,172 → 4,974. Return was observed within 22.209 seconds of verified cleanup; exact switch time between samples is unknown. The prior relay backend loop had closed. Native client and backend process identities remained unchanged; rocky connections were preserved.
    4. Independently checked final restoration: PF disabled, zero task rules/states/references, unchanged root/NAT and byte-identical on-disk PF config/anchor files, guardian exited. No PF state deletion or broad flush was used. An empty anchor name may remain as kernel metadata, without rules or persistent config.

    What is still unproved

    • The real fallback proves a usable cavallo→bestia relay route and observed direct-before-relay selection. It does not directly inspect encrypted saved-catalog contents, persisted order, or establish that fix(connections): learn saved servers T3 Connect routes automatically #364 newly added a previously absent route. The on-disk catalog was not decrypted and secrets were not opened. Cavallo's saved bestia/rocky T3 Connect-last metadata inspection remains outstanding.
    • Rocky's saved bestia/cavallo membership/order and actual remote desktop use remain outstanding; its desktop's observed sockets were its own loopback and public account traffic. No invented conditional rocky fallback pass.
    • Physical iPhone catalogs/routes and applicable existing remote saved web clients remain unobserved; no mobile distribution, browser or computer-use pass was performed.

    Manual keep-two deploy backups/keep-one inactive rollback was applied on all three hosts; permanent retention remains open on runbook #10. Rocky's spindump-held older rollback was preserved by rename and not deleted. Runbook deployment records are pushed; final fallback/restoration entry follows. Exact private observations, counters, hashes, helper output and process checks are retained in ~/.cache/chromeria-deploy-3ca60f/.

  22. lukemaj commented on Oct 15, 2026

    @lukemaj
    ContributorAuthor

    What: The verified rollout and cavallo's restored full bestia fallback sequence are recorded in pushed runbook main be6d48cfb3994a9d3c7d9bdc0e04075fc1ca3650.
    Why: The deployment, manual retention, supported tunnel relink, transport evidence and complete PF restoration each need their own live record.
    So what: #292 remains open only with its explicitly recorded remaining acceptance; no saved-catalog order, phone, rocky remote-desktop or remote-web pass is invented.

    Records: cavallo/CHANGES.md, rocky/CHANGES.md, bestia/CHANGES.md. Only these owned paths were staged, with pull --rebase before each commit and ordinary pushes. Exact verified source identities and transport/remaining-proof details: #292 (comment).

    Task finalization: removed only the three clean detached owned build worktrees after artifact preservation and open-reference checks. Signed Mac ZIP and validated Linux archive remain outside those worktrees; two complete deploy DB backup sets plus the immediate e5aafd7 rollback remain per host. Rocky's spindump-held older app is explicitly preserved. Transient deploy unit and PF guardian have exited; no active task PF rules/references/states, no armed swap, no live Cue, no persistent automation change or agent-memory write. Original canonical checkout HEAD and its pre-existing untracked scripts/__pycache__/ are unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions