Merge branch 'main'
ci / build and test (push) Successful in 2m3s
ci / android head (push) Successful in 3m21s
ci / desktop nightly (push) Successful in 45s
ci / api image (push) Successful in 33s

Two of main's changes land in files this branch rewrote, and both needed carrying
across by hand rather than by the merge.

The phone's nav staying up on Connections with nothing running is a fourth input
to RefreshChrome, which this branch had already given two more — whether hosts are
ticked and whether the host editor is filling the screen. They compose: the rail
and the bottom bar now ask (pages || connectPage) && !editing, so a page-shaped
terminal surface keeps its way off the screen and the editor still takes the whole
display.

The key question under the host's move panel is the harder one, because this
branch deleted the panel it was added to. The connect card is gone and the phone's
only route to a move is the action bar, so leaving the merge to take this side
would have removed a capability main had just shipped — silently, since nothing
would fail to build. It is asked in the action bar's own picker instead, in two
shapes fewer than the desktop's: one host, because which key to carry is a fact
about one machine and a selection of six has six answers, and a move rather than a
copy, because taking the key out from under an original that is staying put would
leave that original unable to connect. BindingOfTheMovingHost splits into
MovableBindingOf so both heads answer it the same way from different panels.

Main also fixed a real trap in the same commit — a host that only inherited its
key from its group arrived in the destination naming nothing at all, because the
group stays behind — and the batch move had the same bug for the same reason. It
goes through Detached now, which is where that fix lives.

The carried host is written as the carry left it rather than being detached again,
which is the one thing worth measuring: the key takes a new id over there, so a
run that rebuilt the payload from the row would send the machine across naming a
tombstone. Both directions are pinned, along with the rule about which shapes the
question is asked in at all.
This commit is contained in:
2026-08-06 09:30:00 +02:00
20 changed files with 2530 additions and 113 deletions
@@ -158,6 +158,28 @@
<TextBlock Classes="body" Text="{Binding ChosenHostVaultPanelNote}" />
<!--
◆ THE KEY. A binding resolves across vaults, so the host goes on working here whichever way this
is answered — but the vault it has just joined holds one key, and a host whose own key stayed
behind is one its new colleagues cannot connect with.
Drawn only for a move of exactly one host, which is the only shape the question has an answer in:
which key to carry is a fact about one machine, and a copy that took the key away would leave the
original unable to connect. See VaultViewModel.BringsTheChosenBindingAlong.
Unticked, because moving a key into a team's vault hands it to everybody who holds that vault's
key: a disclosure is chosen, never defaulted into. The line under it is the count of what else
uses that key, which is the difference between an obvious yes and an obvious no.
-->
<CheckBox IsChecked="{Binding BringsTheChosenBindingAlong}" MinHeight="44"
IsVisible="{Binding HasAChosenBindingToBring}">
<TextBlock Classes="mono" FontSize="11.5" TextWrapping="Wrap"
Text="{Binding ChosenBindingToBringQuestion}" />
</CheckBox>
<TextBlock Classes="body" TextWrapping="Wrap"
IsVisible="{Binding HasAChosenBindingToBring}"
Text="{Binding ChosenBindingToBringNote}" />
<Grid ColumnDefinitions="*,8,*">
<Button Grid.Column="0" Classes="primary" Height="44"
Content="{Binding ChosenHostVaultPanelVerb}"