Files
archy/docs/INPLACE-OS-OTA-MIGRATION-20261103.md

31 KiB
Raw Permalink Blame History

In-place OS updater migration — 2026-11-03

Current activation result (supersedes preparation-only status below)

Real no-ISO transition demonstrated in a disposable installed Debian system: the accepted 2.0.0-alpha+uat backend was running before bootstrap, the protected D09 owner was installed/admitted/activated, its real worker applied the complete reviewed Debian transaction, and the actual 2.0.1-alpha candidate became healthy. This is no longer a file-copy-only test. Production signature approval and actual Framework/Yaya installation are not claimed. The current deployed Framework layout still has the concrete custody prerequisite described below.

Final os-bootstrap-native-r7 and os-bootstrap-postboot-r7 both report exit 0. Earlier os-bootstrap-native-r4 and os-bootstrap-native-r5 also report guest exit 0 under /home/archipelago/Reports/opencode-full-release-20261029/. They use accepted backend SHA256 2cf004fcc7f207c65b3bbd1eac248f8c9556ec1cd0ec139011fb4b1e1ef96494 and independently built candidate 59e0a2091011e0770365ab5c61505d73abef59cdf3f284afa7b6aa1000d9c248. The native candidate source inventory is fca2e13e421523a9a3cc2940e7285a4c3b7e7c1b4af3913ad2b332b7dce9bea8; its frozen Cargo.toml declares 2.0.1-alpha. Native artifact execution is not replaced with Python in these native attempts. A subprocess inside the management unit invokes the real D09 client; this is not dashboard/browser OTA acceptance. The accepted old artifact is tied to source 33d61e94053f3b3dd1fb0d38026122cd6d9648b7, whose tree was canonically accepted as c32a925647eab63ba0f1cac7e6bd135b857d5b7b; the original UAT archive and embedded source receipt were independently hash-checked before injecting the old executable into the disposable disk.

Actual effects: 12 package upgrades plus new linux-image-6.12.115+deb13.1-amd64=6.12.115-2, zero removals, through the fixed full-suite solver and real package locks/APT/libapt/dpkg. Three Debian pockets and four components were authenticated by the executor. Status reached PREPARE → DOWNLOAD → VERIFIED → APPLY_INTENT → VERIFY → REBOOT_REQUIRED; the candidate reached D09 AWAITING_OBSERVATION. Native node key/public key, passwd/group/shadow and synthetic wallet/identity/stopped-uninstalled canaries were preserved. A forward wallet-canary write survived refused bootstrap replay. Full app/container preservation and native terminal observer completion are not inferred from these canaries.

The release-authentication substitution is explicit: a QEMU-only exact-manifest native fixture verifier and preappointed fixture verifier custody. No production signing key was used, no production verifier was changed, and production signature approval is false in every result. Actual production first custody must retain the already appointed native release-root verifier, or independently established protected verifier custody; arbitrary downloaded scripts cannot appoint it.

Actual-installed custody prerequisite

Framework inventory framework-installed-migration-inventory-r1.json, lines 8510–8519, records /var/lib/archipelago as UID/GID1000, mode0755, dev65024 inode2. The executor ROOT used by r4/r5/r7, /var/lib/archipelago/os-update, is beneath an application-owned ancestor. Root-custody checks correctly refuse that actual layout. Do not chown the application's data root or weaken secure(). Executor coordination requests a root-controlled sibling /var/lib/archipelago-os-update (also outside application data rollback), or a separately qualified custody transition. At that checkpoint bootstrap read the fixed ROOT literal from the hash-verified executor package without executing it and recognized those two ABI locations, with exact policy hashes and existing-authority checks at both. It never silently relocates a ledger. The fixture will match the recorded UID1000 data-root ownership when the executor adopts the sibling. r4/r5/r7 used a root-owned data-root model and do not close this installed-layout gap.

Executor continuation now fixes ROOT to /var/lib/archipelago-os-update, adds protected-parent/live-path/journal continuity checks, and refuses any legacy entry without explicit root migration/reconciliation. Bootstrap policy accepts only the new ABI. Real isolated UID1000 custody integration passed 15 checks and actual package closure passed, retaining c01_uplink.py. See /home/archipelago/Reports/OS-OTA-CUSTODY-PATH-20261103.md for exact paths and receipts. This corrects the source custody blocker; a fresh exact new-root native artifact/boot run is still required, and the r4/r5/r7 evidence above is unchanged.

The recorded Framework administrator setup also explicitly says old privileges were not retired. Before production bootstrap, the separately owned guarded isolation/exclusion procedure must establish that the service/runtime cannot rewrite root custody through inherited administrative capabilities. The pinned D09 exclusion evidence is a prerequisite, not something this helper manufactures. An independently verified login alone does not prove that exclusion. Yaya's separate administrator receipt is not the Framework recreation exception.

Boot qualification progression

BIOS/GRUB on the same updated r4 disk actually booted 6.12.115+deb13.1-amd64, Debian build 6.12.115-2, retaining the old .107 boot files and forward data. Fresh externally anchored D09 readmission reactivated the candidate without another OS APPLY_INTENT. Initial postboot observer attempts exposed a fixture binding-field error, then a real bootstrap sandbox omission: the owner could not open its exact OS executor lock. Read-only kernel/package/ preservation verification passed outside the owner. The bootstrap-owned policy now includes that lock file (not the whole OS state root). r6 exposed a separate fixture issue: printing the entire kernel provenance map to the slow serial console left the intentionally partial frontend/runtime fixture alive long enough for the real candidate watchdog to submit AUTOMATIC_FAILURE. Reactivation correctly refused the outstanding notice; it was not deleted or reset. The fixture now keeps full provenance in evidence files and prints a bounded digest/phase summary.

Final r7 passed the actual owner callback with os_postboot_verified: true and POSTBOOT_CONFIRMED. Boot ID c5fcea58-759b-4315-9ef4-906b1da36141; running kernel 6.12.115+deb13.1-amd64, build Debian 6.12.115-2. The same disk booted through BIOS/GRUB (no direct-kernel substitute). Old .107 image/initrd, actual native identity, principal files and the forward-written wallet canary remained exact. There was one OS APPLY_INTENT, and the candidate received a fresh invocation through authenticated D09 readmission against history retained outside the guest. OS postboot confirmation is not native terminal/UI observation or routine Automatic-NTS boot acceptance. None of the failed attempts was relabelled.

Current no-reinstall support matrix

Route / starting state Evidence and current disposition
Root-custody-qualified Debian 13 amd64 fixture, accepted old native → new candidate Passed real bootstrap, D09 owner/client/worker, 13-package transaction, actual BIOS/GRUB new-kernel boot and authenticated owner postboot confirmation; disposable auth adapter only
Legacy installed dashboard OTA self-installs its privileged owner Not supported by this evidence; use the independent one-time administrator path
One-time independent administrator bootstrap Implemented and exercised; pinned artifact/source/plan/backend/helper inputs, existing access, writer exclusion and custody required before admission
Actual recorded Framework UID1000-owned data root / old privileges retained Blocked prerequisite, not an ISO requirement: fix executor state custody and qualify service/runtime exclusion through the existing migration lane; do not chown data or relax checks
Yaya No installed transition qualification here; independently revalidate inventory/access/maintenance authority; Framework recreation exception does not transfer
Existing D09/OS ledger or interrupted bootstrap/activation Refused; exact external reconciliation/readmission required; no state reset or financial rollback
Future native OTA with an installed qualified owner Can request an independently admitted authenticated plan through D09; it does not gain generic root, appoint its own maintenance authority or bypass postboot checks
Production signing / immutable candidate install / physical UAT Open; no signing, publication, physical-node apt/migration/reboot or commits performed
Bookworm, arm64, vendor kernels, Debian major upgrades, UEFI No qualification claimed by this amd64 trixie/BIOS fixture; retain the executor contract's explicit limitations

The administrator requirement is installation/admission of a privileged trust boundary using existing separately verified access, not reinstalling Debian or inventing new node identities. Production first verifier custody uses the already appointed native release-root verifier. Maintenance exclusion must be established and later reconciled by its appointed owner. Subsequent D09 requests can come from native OTA; the old software is not presumed able to grant itself these privileges. Fresh external postboot authority in this fixture is distinct from mandatory manual confirmation on every future boot; the existing trusted automatic recovery delegation must be qualified separately, not replaced here.

Verification commands and final receipts

Source checks: 19 tests passed; Python compile checks and scoped git diff --check passed. Exact runtime bootstrap/activation/activation-fixture bytes in the r7 source inventory match the current worktree hashes below.

python3 -B -m unittest discover -s scripts/tests -p 'test_os_updater*.py' -v

Recorded durable disposable activation command (use fresh unit/output names for another run; existing evidence is never overwritten):

sudo systemd-run --unit=os-bootstrap-native-20261103-r7 \
  --property=CPUQuota=200% --property=MemoryMax=8G --property=MemorySwapMax=0 \
  /usr/bin/python3 -B /home/archipelago/Projects/archy-uat-publication-20261031/scripts/tests/qualify_os_updater_activation.py \
  --baseline /home/archipelago/Reports/opencode-full-release-20261029/os-bootstrap-vm-r1 \
  --output /home/archipelago/Reports/opencode-full-release-20261029/os-bootstrap-native-r7 \
  --native-artifact /home/archipelago/Reports/opencode-full-release-20261029/os-ota-native-candidate-r1 \
  --accepted-payload /home/archipelago/Reports/opencode-full-release-20261029/uat-all-ngit-package/payload.tar

sudo systemd-run --unit=os-bootstrap-postboot-20261103-r7 \
  --property=CPUQuota=200% --property=MemoryMax=8G --property=MemorySwapMax=0 \
  /usr/bin/python3 -B /home/archipelago/Projects/archy-uat-publication-20261031/scripts/tests/qualify_os_updater_boot.py \
  --wait-applied 1800 \
  --applied /home/archipelago/Reports/opencode-full-release-20261029/os-bootstrap-native-r7 \
  --output /home/archipelago/Reports/opencode-full-release-20261029/os-bootstrap-postboot-r7

Heavy operations take /tmp/opencode/release-heavy.lock inside the limited job. No Framework/Yaya contact was made. Fixtures use owned disks, no writable host shares, and preserve prior attempts. All this lane's test jobs have completed.

Paths below are relative to /home/archipelago/Reports/opencode-full-release-20261029/:

Final evidence SHA256
os-bootstrap-native-r7/result.json 7bf3e9335847d8960a39a65ccc50f6da202ed37ab421824cbce596cda15e3433
os-bootstrap-native-r7/source-sha256.json (complete exercised package inventory) c1b3b72b94ffcba1f6a8bc6005df0b07bc39fca1f388cfa547310cce223fbe0c
os-bootstrap-native-r7/activation/os-ota-stage/bootstrap-result.json 00712469749fe1691222d83868606b2d257af976dfd54923f8809f1416107382
os-bootstrap-postboot-r7/result.json 92166a6c9b6c6f64a32e1ace3f328d3a95378c48368d7fac19c667ff43ac200d
os-bootstrap-postboot-r7/boot/os-ota-stage/bootstrap-postboot-result.json 7e5d47164362a01cbb299db5a30275619a3948b25ce62bc8c580c6cb99b08c28
Current lane source SHA256
scripts/os_updater_activate.py 00a0cac5c8076a9a8d3700697bf120f4076a1734e9a745278bce944b00262717
scripts/os_updater_bootstrap.py 1bafbec2436b240f72d531f4658d0d5274058a1bb80cdac08543cbad4781fc6c
scripts/tests/os_updater_activation_guest.py d86a49ada972ac5d9c3a1e23f3b32ed25166e85cfb90df577bd7ec1460e74177
scripts/tests/os_updater_postboot_guest.py 59d06bb0b6c2c7adea389ffefc59fbeb9c2b4845753be7743daf76b910c83f6c
scripts/tests/os_updater_baseline_guest.py 5cee577f2caf75a8c1a6d4f18cb38ed4ce5e5df9124b187bbc19e23517ba6c6c
scripts/tests/qualify_os_updater_bootstrap.py be7e81697a61dff2266eae855b6746ada318ab479fd04b5bd7a7b2eb1267b5fd
scripts/tests/qualify_os_updater_activation.py 7147a79c1f36aa1531535aa5f53625ef9aa98fd0ee5fb8a63694bdbc77e4552c
scripts/tests/qualify_os_updater_boot.py 4c065e3e64101b179801619e07ec1ee4ef27453dd9ec6db428abb490869f24d7
scripts/tests/test_os_updater_activate.py f61d358d6a88db3939444e8051f5c77d998c84a9aab2165b19ebe2f61c2b9862
scripts/tests/test_os_updater_bootstrap.py 02bdb238154e671eb65ac2dc9519b4fcfb813b3707171f4abc64639911ad516e
docs/system-level-ota-design.md d478f6488a5c2ffffe0cc67c27774a2aac1f64946b30bb4ea180a2d9da492544

The executor contract is now available at docs/OS-OTA-CONTRACT-20261103.md. scripts/os_updater_activate.py implements one-shot activation through the actual pinned D09 provisioner and lifecycle owner. It does not construct its own D09 ledger, issue APPLY directly or replace the OS executor. Local bootstrap/activation guard tests and real installed-VM results are recorded separately. The earlier preparation-only checkpoint and its hashes remain historical evidence, not current source pins.

Activation independently pins its approval and helper, the complete protected package inventory, exact current/new backend, D09 admission/workspace helper, OS plan/manifest/verifier and preservation inputs. It rechecks the independent administrator and service principals, machine ID, access receipts and externally drained manager. All unattended package-writer units must already be inactive and masked. Bootstrap does not create/change principals, keys, privileges or timer policy. Production prerequisites (including python3-apt) must already be installed through separately qualified authority.

It journals durable intent before installation, publishes the exact OS plan, supplies the provisioner's fixed incoming OS input set, invokes --install-package then --admission, starts the actual lifecycle owner and submits grant A once. A pending systemd start is observed through the owner's protected ledger without resubmitting it. Any failed/interrupted activation or existing D09/OS transaction is refused on re-entry. Package files may have been installed before interruption; the intent remains for independent reconciliation, not automatic retry or rollback. There is no financial-data restore path.

The new activation approval has exactly version: 1, prepared_sha256, package_root, package_files (complete relative-path → SHA256 map), admission_sha256, os_inputs (plan.json/manifest.json/preservation.json → SHA256), helper_sha256 (os_updater_activate.py), and owner_dropin_sha256 (the fixed bootstrap-owned service policy). The additive 55-os-bootstrap.conf permits only the two real dpkg lock files, the OS executor lock and OS transaction status directory to be writable inside the owner sandbox. Existing policy is never overwritten. Approval and package must be in independently established root custody. Before calling activation, the externally appointed coordinator supplies protected D09 incoming old/new/restore snapshots, exclusion and admission under /var/lib/archipelago-d09/incoming, and the exact native release-root verifier at /usr/libexec/archipelago-os-release-verifier. No existing-version updater is assumed able to appoint those authorities itself.

Prospective independently authorized administrator command (not run on a node):

sudo /usr/bin/python3 -I -B /root/reviewed/os_updater_activate.py \
  --approval /root/reviewed/activation-approval.json \
  --approval-sha256 "$INDEPENDENTLY_APPROVED_ACTIVATION_SHA256"

Successful bootstrap reports D09_PREREQUISITE_ACTIVATED, not OS completion. Subsequent updates use the admitted native D09 path and authenticated OS plan. The OS stage, postboot confirmation, existing installed-data migration and physical/operator acceptance remain separately evidenced gates.

Read-only recorded access clarification: framework-admin-completed.json reports existing archipelago-admin UID1001 with fresh SSH/root access and password recovery verified, old effective sudo rules unchanged, old privileges not retired and no cutover. yaya-admin-verified.json separately reports fresh key-only SSH, UID1001, sudo-root and its existing route working. Those receipts mean a newly created account is not inherently required for this bootstrap: use and freshly revalidate existing independent access. They are historical observations, not permission to mutate either node now. Yaya's admin receipt does not grant the Framework-only container-recreation exception or authorize an OS maintenance run.

Historical preparation-only checkpoint

Superseded preparation-only scope and original source/evidence hashes

The following sections retain the earlier checkpoint and original hashes. They are superseded by the current activation results and custody gates above.

Answer at that checkpoint

An ISO reinstall is not inherently required for Debian/kernel updates or for installing a protected updater on an existing Debian installation. However, the actual deployed Archipelago → protected OS owner → OS transaction transition is NOT yet qualified. A one-time independent-administrator bootstrap is the proposed bridge when the old OTA path cannot safely install its own privileged owner. Administrator work and reinstalling the machine are different operations.

This lane delivered an inert preparation helper and ten filesystem/control tests, not a supported live migration or a successful OS transaction. There is no activation command in the helper. No no-reinstall acceptance is inferred from copying code. The OS executor contract was not available at this checkpoint.

Worktree: /home/archipelago/Projects/archy-uat-publication-20261031. No GSD, delegation, live contact/change, apt, reboot, signing, publication or commit was performed. Tests are small unprivileged temporary-directory tests; no heavy shared resource or build/VM lock was needed.

Recorded deployed state, not a new live probe

Sources under /home/archipelago/Reports/:

  • OPENCODE-UAT-20261031.md: Framework accepted native/dashboard source 33d61e94053f3b3dd1fb0d38026122cd6d9648b7, canonically merged at c32a925647eab63ba0f1cac7e6bd135b857d5b7b with the same tree. Installed backend SHA256 2cf004fcc7f207c65b3bbd1eac248f8c9556ec1cd0ec139011fb4b1e1ef96494; payload SHA256 f7563b5e509280782adebb7b75608e45bd5628fa53c58dbccf83ceb954fd4be1. This is the accepted 2.0.0-alpha UAT baseline, not the dirty candidate tree. A Git commit ID is not the executable hash or the source-inventory SHA256.
  • opencode-full-release-20261029/FRAMEWORK-INSTALLED-MIGRATION-20261103.md: installed C01/D09 roots absent; two nonempty legacy pending rows, fourteen explicit uninstalls, data on a distinct filesystem, actual rootless overlay storage and subordinate IDs. Do not reinterpret absent D09 as empty app data. Python 3.13 shared library/GI prerequisites are missing for new owner machinery.
  • framework-installed-migration-inventory-r1.json in that report directory: read-only collector exit 0, hostname framework-pt, observed kernel 6.12.113+deb13-amd64, boot ID b9aa6a8a-08ec-47bf-b6f4-774a57ae4d3f. This timestamped receipt cannot establish current quiescence, independent recovery access or transaction eligibility.
  • AUTHORITY.md: Framework alone has guarded container-recreation and separate administrator exceptions. Existing access must be verified before any old shared-account privilege retirement. Neither exception automatically covers Yaya. The root query in the inventory is not proof of a separate working admin.

Inspected git show c32a925...:core/archipelago/src/update.rs: accepted apply and rollback already route through D09; retained historical copy code is explicitly not an admitted activation route. Unknown components are skipped by that legacy copy implementation. Shipping an owner file in a runtime archive is therefore not a verified bootstrap. Current package-d09-c01.py generates deterministic owner files with hashes, but is not an authentication or admission authority. provision-d09-lifecycle.py --install-package requires external management drain, refuses existing authority, installs multiple paths and enables a service; --admission separately pins prerequisite, release, exclusion and old/new/restore objects. It must not be casually called from the old updater or substituted with this inert helper. Existing C01/D09 migration/provision files were not edited.

No-reinstall support matrix

Starting state / route Current evidence Status / required action
Accepted Framework UAT, no C01/D09 owner; dashboard OTA only Accepted source requires D09; recorded authority absent Automatic bootstrap unverified; do not claim supported
Same node, independent admin + authenticated pinned inputs Inert preparation helper and ten tests Proposed in-place bridge; actual installation/activation/OS transaction still blocked
Framework guarded C01 migration Separate lane has nonempty-history/layout work; qualification incomplete Preserve its full migration/admission gates; do not replace it
Yaya No equivalent installed-state transition qualified in this lane Reinventory separately; no inherited Framework recreation/admin-split permission
Any existing D09 binding or ledger / OS ledger Helper refuses all, including apparently terminal ledgers External authoritative reconciliation required; never delete/reinitialize to proceed
Interrupted bootstrap Pending generation retained; retry refused Independent reconciliation, no automatic cleanup/replay
Kernel/Debian package change after bootstrap No composed actual OS transaction run Not qualified; executor transaction/recovery/reboot gates remain
Debian major-version upgrade No compatibility or upgrade qualification Unsupported by this work; no blanket no-reinstall promise
Missing administrator access or untrusted privileged base No safe custody established Access/recovery intervention needed; no claim that an ISO is necessarily required

Helper contract (preparation only)

scripts/os_updater_bootstrap.py requires effective root and a protected administrator-provided approval file whose exact SHA256 arrived through an independent authenticated channel. A digest downloaded alongside an untrusted payload is NOT authentication. Root-owned bytes alone are not maintainer approval. The helper, approval, payload and all ancestors must already have root custody; the production reader rejects writable ancestors, symlinks and file hardlinks. It never executes payload bytes or invokes a package manager/service manager.

The strict JSON approval has these fields:

  • schema: 1, machine_id_sha256: exact /etc/machine-id bytes, including newline.
  • current: version, source_sha256, backend_sha256. An independent reviewed source/build receipt must establish the version/source ↔ executable relation; the helper hashes installed /usr/local/bin/archipelago, not updater state.
  • candidate: same keys. Here source_sha256 is SHA256 of the files map encoded as sorted compact JSON (sort_keys=True, separators=(',', ':')). Backend hash is a pinned future activation input; it is not installed by this helper.
  • admin: positive distinct uid, service_uid, access_receipt_sha256. The independently verified access receipt must also occur in observations. This records external verification; it does not itself log in or check sudoers.
  • observations: root-relative path → exact SHA256 of protected inventory/access receipts, reread before staging. Receipts must be freshly issued at cutover; hashing a stale receipt cannot establish current access or writer exclusion.
  • files: flat safe filename → SHA256, maximum 256 files. All source bytes are reread and checked; control filenames are reserved. No archive extraction, symlinks, arbitrary destination paths, financial databases or data restore.

Supported comparison grammar is intentionally limited to numeric MAJOR.MINOR.PATCH-alpha[+uat]; candidate numeric version must strictly increase. Same-version, malformed-channel and downgrade inputs refuse. This is not a general SemVer or Debian package-version comparator.

Under its own exclusive lock, the helper refuses existing D09 authority and the provisional OS ledger path. It durably writes a new pending-<approval-sha256> directory containing exact code, approval and control, then atomically renames it to /var/lib/archipelago-os-bootstrap/prepared. Its state is explicitly PREPARED_NOT_ACTIVATED. Interrupted directories and existing prepared objects are retained/refused. No installed code, units, permissions, wallets, identities, app storage or financial data are rolled back or replaced. This is atomic generation preparation, not atomic active-owner installation.

Commands and execution boundaries

Completed locally (10 passed, zero failed):

python3 -B -m unittest discover -s scripts/tests -p test_os_updater_bootstrap.py -v
git diff --check -- scripts/os_updater_bootstrap.py scripts/tests/test_os_updater_bootstrap.py docs/system-level-ota-design.md

Prospective preparation only, from independently verified administrator access, after deploying reviewed root-owned inputs; not run on any installed node:

sudo /usr/bin/python3 -I /root/reviewed/os_updater_bootstrap.py \
  --approval /root/reviewed/bootstrap-approval.json \
  --approval-sha256 "$INDEPENDENTLY_APPROVED_SHA256" \
  --payload /root/reviewed/os-owner-payload

For a qualified disposable realm, --root /root/disposable-old-installation redirects preparation paths only. It does not create isolation, perform a real OS transaction or supply production custody evidence. Do not use a target root containing symlink/bind aliases to installed-node data. There is intentionally no proposed live activation, rollback or apt command before the executor contract.

Tests cover inert atomic visibility and preservation, interrupted write/retry, all listed authority blockers, source/backend/inventory drift, approval mismatch, non-root rejection, root-custody refusal, shared admin, traversal, duplicate JSON, same-version/downgrade and candidate source-map mismatch. Successful-path tests explicitly emulate root custody using mocks in temporary directories; these do not qualify privileged installation, namespace exclusion or actual old binaries.

OS-OTA-CONTRACT handoff and remaining exit gates

At inspection, OS-OTA-CONTRACT-20261103.md was absent both in /Reports/ and /Reports/opencode-full-release-20261029/. The status integration coordination note requests that contract and proposes signed-manifest component os-update-plan.json. That name is a proposal, not an accepted executor ABI. No worker, wire, core update or existing C01 migration/provision source was edited. The independently progressing Reports/OS-OTA-INSTALLED-QUALIFICATION-20261103.md now records a prepared real ext4 Debian guest and the same missing-contract dependency. Its baseline preparation is not an OS transaction pass. A handoff at Reports/INPLACE-OS-OTA-MIGRATION-20261103.md points that lane to this bootstrap schema for the required old-artifact → bootstrap → actual executor composition.

Executor/coordinator must settle and qualify:

  1. Actual OS-owner entrypoint/module set, unit, control and ledger locations, authenticated plan/inspect grammar and its lock. The helper's provisional /var/lib/archipelago-os-update/ledger.json is not an established executor contract. Reconcile all actual blocker paths before any activation.
  2. Atomic installation and control activation against pinned current version/source/executable, exact immutable candidate bytes and actual required Python/GI dependencies. Production package authenticity and source/build provenance are still gates; no unsigned candidate gets implicit fleet trust.
  3. Integrate the executor's real lock and current authoritative ledger checks; preparation's lock does not exclude D09/OS writers. Revalidate observations, operator access, runtime retirement and source bytes at activation time.
  4. Disposable old-installation replay using the accepted native artifact and nonempty representative preserved state, then the real new updater/owner and actual Debian package/kernel transaction. Test interrupted bootstrap, failed owner activation, concurrent requests, stale/altered plan, downgrade, apt/dpkg interruption and authoritative recovery; include reboot/boot selection where required. A stub executor, copied files or mocked package manager cannot pass.
  5. Explicit code-only recovery before OS mutation; after package mutation, use executor-owned reconciliation/recovery. Never advertise reversal of arbitrary maintainer scripts or restore old financial databases. Keep external ledger history and consumed grants outside the code rollback domain.
  6. Exact immutable-artifact qualification and separately authorized installed Framework acceptance, preserving its access/wallets/identities/persistent data and stop/uninstall decisions. Yaya requires its own inventory/authority gates. Use the shared /tmp/opencode/release-heavy.lock protocol for heavy fixtures.

Until these pass, the precise answer is “in-place migration is the intended route, possibly with one administrator bootstrap; actual deployed no-reinstall OS OTA support remains unverified.” This report does not close release UAT.

Source and evidence SHA256 at this checkpoint

Other lanes may subsequently change inspected dependencies; these are point-in-time pins, not a frozen composed candidate. No file below was signed or published here.

Input SHA256
scripts/os_updater_bootstrap.py bb57ca43cd247be79a5b32f635c98dc10f2e20e0ee14dedfab4dfdd630cc08c6
scripts/tests/test_os_updater_bootstrap.py 02bdb238154e671eb65ac2dc9519b4fcfb813b3707171f4abc64639911ad516e
docs/system-level-ota-design.md 3c877c3651b0bc06732c8a5bfed674a1f7b608ea5d2b181f3e4bae354902159f
inspected scripts/package-d09-c01.py 7f897936d245cdc85d21884a9133399ed8d7e1fa7515117f4e89cef90f58cbb5
inspected scripts/provision-d09-lifecycle.py 061af2fea666e80b117b89d812a3fd82bad802a34626d45bf84a343ac1481d61
inspected current core/archipelago/src/update.rs 0215858a23e1699fb0e2a0f80d8fc56d46782724aa7f6d23fad84087ac03648c
AUTHORITY.md 2f050dae0f5f33ad08e63c5a634a8974fb1b1ffaf295133a9a814de8dfa67410
FRAMEWORK-INSTALLED-MIGRATION-20261103.md cf602e41ad9c5e04ec42153d7f953d88f584a603b5db6bf50f889315fe9fb43e
framework-installed-migration-inventory-r1.json 4da8843aa6150c67105928fd4f84daae5405af74add08a2eb98f8730566876b2
OPENCODE-UAT-20261031.md 1334a25d79b8ef4a7bdba8ac3cf6d217449c050eecf6f551e49ce42d9ea547b3