# 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. ```sh 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): ```sh 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): ```sh 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-` 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): ```sh 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: ```sh 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` |