Skip to content

Commit a40ee25

Browse files
committed
Publish the Release A transition archive
1 parent ebfd0ec commit a40ee25

4 files changed

Lines changed: 58 additions & 13 deletions

File tree

.github/workflows/release.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,13 @@ jobs:
4848
set -euo pipefail
4949
mkdir -p dist/package
5050
cp "target/${{ matrix.target }}/release/fabric" dist/package/fabric
51-
cp "target/${{ matrix.target }}/release/fabric-sync" dist/package/fabric-sync
52-
chmod 755 dist/package/fabric dist/package/fabric-sync
51+
chmod 755 dist/package/fabric
5352
archive="dist/fabric-${{ matrix.target }}.tar.gz"
54-
tar -czf "$archive" -C dist/package fabric fabric-sync
53+
# Release A is the reader-only transition. Step 7 restores the pair.
54+
tar -czf "$archive" -C dist/package fabric
5555
members="$(tar -tzf "$archive")"
56-
if [[ "$members" != $'fabric\nfabric-sync' ]]; then
57-
echo "release archive must contain exactly fabric and fabric-sync" >&2
56+
if [[ "$members" != "fabric" ]]; then
57+
echo "transition archive must contain exactly fabric" >&2
5858
printf 'archive members:\n%s\n' "$members" >&2
5959
exit 1
6060
fi

docs/fabric-sync-process-plan.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,31 @@ Before the transition release, run one rollback through the actual production
418418
service on Linux and macOS. Use hetz first and Silber second. Record every
419419
observed state and any manual cleanup. Do not use Bluey for this exercise.
420420

421+
Test the recovery route from the actor who will use it before each deliberate
422+
outage. A reachable host and an open SSH port do not prove that the actor can
423+
log in. Fabric is the only working route to hetz for every agent and for
424+
Silber.cos. If Fabric fails there and cannot recover itself, Nathan must recover
425+
hetz personally. Silber.cos has local shell access on Silber and can repair that
426+
machine by hand.
427+
428+
Both production rollback exercises passed on 2026-09-05 at exact main
429+
`ebfd0ec`. On hetz, the broken pair installed at 03:33:02Z. The systemd reader
430+
restored exact main at 03:34:00Z, and Fabric answered externally at 03:34:14Z.
431+
The observer depended on Fabric because no agent or Silber.cos could complete
432+
an SSH login. The exercise then restored fleet build `0.2.1+48208e4`.
433+
434+
On Silber, the broken pair installed at 03:46:14Z. The launchd reader restored
435+
exact main on disk at 03:47:18Z. The control socket answered at 03:47:27Z. The
436+
transient job and plist disappeared, and the reader removed the new companion.
437+
Local shell observation stayed available. The exercise then restored fleet
438+
build `0.2.1+48208e4`. Doctor passed on both hosts after the exercises.
439+
440+
The deployed `48208e4` reader also received the exact paired archive in an
441+
isolated home. It accepted the checksum, then refused the archive because it
442+
expected exactly one `fabric` member. It changed no executable or staging file.
443+
This clean refusal enforces the Release A order for that deployed reader. It is
444+
not a property of the Release A pair-aware reader.
445+
421446
Add each future real-machine test to this named list when the test is added.
422447
The measurement-only ignored tests are not release gates unless this list names
423448
them.
@@ -432,7 +457,10 @@ The process-boundary release needs all of these results:
432457
- The bridge keeps at least 90 percent of embedded content throughput during the
433458
fixed 10-minute comparison. A larger loss stops activation and reopens the
434459
transport decision with Nathan.
435-
- The release archive and updater verify a matched binary pair.
460+
- The Release A archive contains exactly `fabric`. The deployed `48208e4`
461+
reader refuses a paired archive without changing the machine.
462+
- Step 7 restores an archive with exactly `fabric` and `fabric-sync`. The
463+
updater verifies that matched pair.
436464

437465
This plan changes where sync executes. It does not claim that the connection
438466
cache caused Nathan's earlier pauses, and it does not optimize sync memory.

now.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ status, `fabric status`, `fabric sync ls`, and doctor show that runtime. A
4242
configured entry remains visible when the daemon is down. The embedded engine
4343
remains the production owner.
4444

45-
The current change adds a detached macOS update supervisor. Launchd owns it
46-
before the updater renames the first binary. It survives terminal loss and
47-
sleep, then removes its job after success or rollback.
45+
PR #164 added a detached macOS update supervisor. PR #165 added pair-aware,
46+
fail-closed rollback. PR #166 made real launchd and systemd tests exercise that
47+
reader. All three changes are merged.
4848

4949
The fleet build `0.2.1+48208e4` has only single-binary supervisor logic. The
5050
rollback runs this old binary on purpose because it is the machine's known-good
@@ -61,6 +61,22 @@ The Release A reader must handle OS service state as well as binary paths. It
6161
must restart both old services when a companion rollback exists. It must remove
6262
the companion service when the old release had no companion.
6363

64+
Both production rollback exercises passed on 2026-09-05 at exact main
65+
`ebfd0ec`. Hetz restored exact main 58 seconds after the broken pair installed,
66+
and Fabric answered externally after 72 seconds. Silber restored exact main on
67+
disk after 64 seconds, and its control socket answered after 73 seconds. Both
68+
hosts returned to fleet build `0.2.1+48208e4`, and both doctors passed.
69+
70+
Fabric is the only working route to hetz for every agent and for Silber.cos.
71+
An open SSH port did not provide a usable login. Nathan must personally recover
72+
hetz if Fabric cannot recover itself. Test the recovery actor's route before
73+
every deliberate outage. Silber.cos has local shell access on Silber.
74+
75+
The release workflow must publish a fabric-only Release A archive. The deployed
76+
`48208e4` reader cleanly refused a paired archive in isolation and changed no
77+
file. Step 7 restores paired archives after Release A reaches every machine.
78+
Do not tag current main until the workflow has this transition shape.
79+
6480
The local library suite passed 499 tests with five measurements ignored. The
6581
binary suite passed 19 tests, and the update contract passed eight tests. The
6682
five-second latency property measured 502 records, seven scans, a 10.001166 ms

src/update.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -638,10 +638,11 @@ fn generation_is_current(home: &crate::config::FabricHome, generation: &str) ->
638638

639639
/// Check that the daemon came back, and put the old binary back if it did not.
640640
///
641-
/// THIS EXISTS BECAUSE NOTHING OUTSIDE THE MACHINE CAN FIX IT. If a bad binary
642-
/// takes the daemon down, `fabric exec` stops working, and the tool that would
643-
/// repair the machine is the tool that just broke it. On hetz and droppy there
644-
/// is still ssh. On a travelling laptop there may be nothing for days.
641+
/// THIS EXISTS BECAUSE THE RECOVERY ACTOR MAY HAVE NO WORKING ROUTE. If a bad
642+
/// binary takes the daemon down, `fabric exec` stops working, and the tool that
643+
/// would repair the machine is the tool that just broke it. The route must be
644+
/// tested before a deliberate outage. Do not infer that an open SSH port means
645+
/// the recovery actor can log in.
645646
///
646647
/// It cannot run in the updating process either: on Linux that process lives
647648
/// inside the service's own cgroup and dies with the restart. So it is scheduled

0 commit comments

Comments
 (0)