[UI updates 6/6] Add Settings confirmation, reconnect and retained drafts - #18
Open
srctl wants to merge 1 commit into
Open
[UI updates 6/6] Add Settings confirmation, reconnect and retained drafts#18srctl wants to merge 1 commit into
srctl wants to merge 1 commit into
Conversation
This was referenced Sep 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the Settings update flow with exact confirmation, durable request reconciliation, cancellation, multi-tab status, reconnect/reauthentication returning to Updates, and bounded per-tab composer draft retention without replay.
Layer 6 of 6 replacing original PR #11. Base:
review/ui-updates-05-supervision. Merge in the order below; after each lower PR merges, retarget the next PR to main. If lower layers are squash/rebase merged, reconcile descendant branch ancestry before proceeding; do not merge the original monolithic PR.Incremental scope: Settings/navigation, update notices and admission-aware controls, draft/state helpers, auth return navigation, draft/navigation tests, and both reusable browser/native acceptance harnesses. This top tree is byte-for-byte identical to original PR #11 head 57fb9ae. The existing matched rendered desktop/mobile screenshots and complete operator guidance remain below, with their original fixture labels and qualification limits.
Diff: 15 files changed, 1381 insertions(+), 6 deletions(-).
Verification at this cumulative head:
57fb9ae27ae602baba28d68e96af817208c89bdd; existing supported-platform evidence and limitations apply only to that complete tree.Preserved operator guidance, matched screenshots and acceptance records · Full evidence and limits · Recovery boundaries
Stack and merge order:
Original PR #11 cannot be the bounded top layer without changing its head: the new cohesive commits are not ancestors of its preserved head, and GitHub's merge-base comparison would include the original large implementation diff. Its history, review discussion, operator guidance and all 16 verified attachments are preserved. No docs/evidence are recommitted.
Additional final checks passed: repository lint, production native-auth smoke (with inherited Nitro host/port overrides cleared), and all site checks (types, six tests, marketing/docs builds).
Original implementation description and evidence, preserved verbatim below. Its aggregate diff/test statements describe the original complete implementation, not this layer alone.
Enrolled packaged installations can now confirm a release in Settings, drain existing work, update under a separately supervised helper, reconnect, and restore the previous release and matching data when candidate startup fails. This implements approved design phases 1–3 from
7415789(0.1.40), including its coding-job protection/recovery behavior. Design PR #10 remains separate.The temporary blanket activation gate is removed after supported-path qualification. Initial support remains explicitly enrolled Ubuntu 24.04 Linux x64/systemd/local ext4 installations with gate-aware compatible packages. Native recent passkeys, strict origin/CSRF, pinned release/artifact identity and digests, compatibility, fixed service authority and work/recovery gates remain enforced. HTTP cannot enroll, repair, choose commands/paths/units, or grant privileges.
The helper and current CLI share kernel locking and fence old CLIs. Durable idempotency/journals, boot and candidate gates, full protected data snapshots, pre-commit pair rollback, and explicit post-commit manual repair preserve recovery evidence. Active or uncertain workers defer without replay/forced termination. Settings supports exact confirmation, truthful status, cancellation, multi-tab reconciliation, reconnect/reauthentication and retained drafts.
Acceptance found and fixed transient SQLite staging contention, recovery startup validation between renames, referenced-asset/auth readiness checks, a privileged environment-file hazard, repair socket timeout/stale status, and expired-session return navigation. Test-harness setup/retry failures are documented separately and excluded from completed acceptance totals.
Verification:
pnpm check: 202 tests, native-auth smoke, six site tests, lint/types, app/CLI/marketing/docs builds.Full evidence, artifact hashes, operation IDs and limitations · Operator setup/recovery/retention
All lifecycle/enrollment/reboot testing used a private disposable QEMU guest. No live host Roost configuration/data/service was changed, and no release was published. Fixtures kept production TLS/hostname/digest/compatibility checks enabled with a pinned guest-only test CA. No paid infrastructure, merge or deployment.
Limits: Chromium keyboard/AX and mobile viewport evidence does not replace physical screen-reader/Safari/device testing. Remote worker races use isolated transport fixtures; actual missing-worker observation is covered, while live Herdr jobs would require a disposable endpoint, credentials and authorized model quota. QMP guest resets are not physical drive power-loss tests. Other distributions/filesystems, arbitrary external writers and universal/post-commit rollback are not promised. Updates cause downtime. The PR awaits coordinator-controlled review.
Actual rendered matched screenshots, same screen/state and viewport:
Actual native-auth/real-helper private-release fixtures (desktop 1440 × 1000; mobile 390 × 844):
Earlier API-fixture confirmation views (not end-to-end lifecycle evidence)
Reviewability cleanup: all 19 newly added documentation/evidence files (including 16 PNGs and 551 text lines) are removed from the final code diff. All 16 original images were uploaded through the documented GitHub CLI attachment feature and downloaded again with HTTP 200,
image/png, successful PNG decoding and byte-for-byte SHA-256 matches before replacing the image references. Original labels, matched viewports and fixture distinctions are retained. Full-page reauthentication desktop images are 1440 × 1018 from a 1440 × 1000 viewport.The final diff is 62 files, 7,118 added lines and 47 deleted lines (previously 81 / 7,669 / 47). Production code, all regression tests and all three reusable browser/native/systemd lifecycle harnesses are unchanged. The harnesses assert confirmation, reconciliation, drafts, auth, service and recovery behavior; their optional screenshots do not make them disposable capture helpers. Cleanup verification checks documentation preservation, attachment integrity, link targets and diff scope; the previously reported implementation/VM tests were not rerun for this documentation-only cleanup.
Complete operator guidance and original acceptance records are preserved below. The immutable commit links above remain archival references, so recovery/setup instructions and original evidence remain available independently of this PR body.
Operator setup, recovery and retention — full preserved guidance
UI self-updates
The supervised update path is enabled for the supported, explicitly enrolled
installation contract below. Native passkey authorization, pinned compatible
releases, fixed-unit authority, work quiescence and durable recovery checks remain
mandatory. HTTP cannot enroll an installation or grant service-control privileges.
Enrollment is an explicit operator action.
The implementation starts from
7415789(0.1.40), including its coding-jobprotection and recovery changes. It follows the
approved design revision;
design PR #10 is separate from this PR.
Initial supported contract
Only explicitly enrolled, packaged Linux x64 installations on Ubuntu 24.04,
systemd and persistent local ext4 storage are supported.
The application unit must match Roost's generated unit, with only the updater
startup drop-in. Custom hooks, additional overrides, noncanonical/shared writable
installation paths (the installation root must be mode 0700), externally managed deployments and other service managers
are unsupported. Source installations show their external-management reason in
Settings and cannot activate an update.
Both the previous and candidate packages must include the startup gate and a
compatible
compatibility.json: updater protocol 1, app/auth schema input rangesand output versions, complete managed-data snapshots, unchanged excluded state,
and the same bundled Codex version. Packages predating this contract, including
the original 0.1.40 release, need a normal operator-managed upgrade to a gate-aware
release before enrollment. Merely adding a manifest to an old binary is unsafe.
Bundled Node and Codex must execute on the host; changed Codex versions require
terminal maintenance and separate compatibility review. No external model API
connection is required for candidate health.
The installation user is a trust boundary. Same-user arbitrary code can access
its installation, data and private helper socket. Independent operator service
changes, external writers and remote effects are outside the recovery guarantee.
Updates cause downtime; they do not provide universal recovery or undo external
actions such as messages, commits or remote provisioning.
Operator enrollment
Do this only during an authorized maintenance window, using a packaged,
gate-aware release. These commands are documentation, not automatic deployment:
roost auth setup --origin https://your-roost-host # Register the native passkey using the private link before relying on UI controls. roost updates enroll roost updates statusEnrollment verifies installation identity/layout, Python 3 with Linux
SO_PEERCRED, systemd, ext4 and the application unit. It requires interactiveoperator sudo authorization and installs root-owned files:
/etc/systemd/system/roost-UID-updater.service, running as the installationuser, pinned to the enrolled release's Node/CLI outside the app control group;
/etc/systemd/system/roost-UID.service.d/updater.conf, ordering startup afterthe helper; the application CLI reads its private startup gate as the installation user;
/etc/sudoers.d/roost-UID-updater, allowing only noninteractive/usr/bin/systemctl start roost-UID.serviceand/usr/bin/systemctl stop roost-UID.service.HTTP has no enrollment, repair, shell, path, URL or unit-control operation.
The daemon verifies that it is the fixed helper unit's main PID; it cannot be run
as an unsupervised CLI subprocess. The helper accepts bounded protocol messages on
ROOST_HOME/updates/helper.sock,mode 0600, through a separately supervised Python peer-credential bridge. Only
its own UID is accepted. The socket and operation directories are private.
Enrollment leaves
ROOST_HOME/operation.lockas a permanent legacy CLI fence.Do not delete it as a stale PID file. Current CLI setup/update/start/stop and
the helper share a kernel
flockdomain,updater.lock; enrolled updates andstart/stop route through the helper. Enrolled
roost updateprints the offer;roost update --version EXACT_VERSIONexplicitly confirms it. Never unlink that kernel lock file either.updater-owner.jsonrecords PID, boot ID and process-start ticks for diagnostics;it may be stale after exit and never grants ownership. A separate lifetime
updater-supervisor.lockprevents a second helper invocation from replacing theactive socket or changing its gate; it never replaces the shared transaction lock.
flock(util-linux),Python 3, findmnt and systemd/sudo are required on the initial platform.
Repeating enrollment with the same pinned helper is supported after partial
setup. Re-enrolling from a different release refuses to replace a running helper.
Helper upgrades are separate operator maintenance: finish/recover all operations,
stop the app and helper, review the new helper's protocol compatibility, then
replace the pinned helper unit and enrollment metadata under the installation
lock. There is intentionally no automatic helper upgrade or uninstall command.
Do not remove the legacy fence while any older CLI can access this installation.
For a private repository, provision a read-only release credential explicitly as
ROOST_HOME/updates/github-token, a regular installation-user-owned file, mode0600, at most 1024 bytes. Restart only the helper during authorized idle
maintenance to load a changed credential. It is never returned to the browser or
inherited from the web process. API requests cannot redirect that credential;
artifact redirects permit only GitHub's fixed release asset hosts without the
authorization header.
Transaction and recovery
Settings checks the configured repository's published stable release. The offer
pins repository, release ID, asset ID, version, SHA-256 digest, size and expiry.
“Published” is not a promise of compatibility: downloaded manifests, schemas and
bundled runtime execution are checked before stopping. A same-publisher API digest
detects replacement/corruption, not publisher compromise. Missing digests, changed
identities, downgrade/equal versions, drafts/prereleases and expired offers fail.
Downloads, metadata, request bodies, redirects and extraction are bounded.
Extraction accepts regular files/directories only, rejects links, devices, path
escapes, duplicates and unsupported extensions, and caps expanded bytes and files.
Activation requires exact version confirmation and a native passkey session less
than five minutes old, exact Origin/host, JSON, a session-bound CSRF token and a
bounded idempotency key. Session validity is rechecked after reading the body.
Acceptance is journaled/fsynced before acknowledgement. Repeating the accepted
key returns its operation; changing its actor/offer/version conflicts. Once
accepted, session expiry does not cancel recovery. No lost response triggers an
automatic POST retry.
The helper holds the installation lock across staging, drain, stop, snapshot,
activation, probe and commit. It blocks new conversation/steering/automation/
delegation/coding claims transactionally while continuing existing coding-worker
observation. Running, missing, unknown, stale or identity-uncertain workers defer
the update. Review status alone is insufficient: idle identity must be verified
and fresh. Queued jobs remain queued. In-flight requests, login, desktop viewers/
actions and background tasks must finish before stopping. The five-minute drain
deadline never authorizes forced termination or replay. Cancellation is durable
before the stop boundary; a later cancel request is refused.
After closing all writers, the helper stops the exact service and verifies its
control group empty. The complete
datatree (both SQLite stores, sidecars,managed files/memory/workspaces) is copied, integrity/digest checked and fsynced.
Config is retained alongside the snapshot for diagnosis/operator recovery.
Symlinks, hard links, special files and nested mounts are rejected rather than
silently excluded. Capacity checks reserve staged bytes, snapshot/restore space
and inode headroom. Snapshot permissions are reduced to owner-only access.
Snapshots are secrets; they can contain credentials and conversation content.
The candidate starts behind a capability-bound gate that blocks ordinary HTTP,
auth writes, worker claims, login and external effects. A two-minute probe checks
expected version/operation, app and auth database integrity/schema, packaged
assets and worker initialization. A durable commit precedes opening admission.
A previously stopped CLI installation is probed but returned to stopped state.
Before commit, failure restores a verified copy of the snapshot and selects the
matching previous release. Candidate data is retained separately as
failed-data;the original snapshot remains untouched. Recovery resumes interrupted pointer/
data renames and re-probes the previous version behind the gate. After commit,
automatic recovery never restores old data or discards new work. Missing/corrupt
evidence, an unexpected pointer or failed recovery keeps maintenance closed.
Boot recovery runs in the pinned helper; the app also rejects startup without
current-boot readiness and a valid open/verification gate.
The helper validates stable installation ownership before recovery without
requiring a readable candidate contract or an already-present
datadirectory:those may be broken or between renames. Full layout and compatibility validation
still applies to enrollment and every new activation.
Status, reconnect and repair
The searchable Settings section shows actual phases, blockers and downloaded
bytes, never invented percentages. It supports cancellation, deferral, recent
authentication, cached outage messaging, multi-tab observation and manual asset
reload while preserving the route. Polling backs off after disconnection. An
unconfirmed response stays pending until its request key matches durable status
or the operator explicitly dismisses it after inspection. A closed app cannot
serve fresh progress; the browser says it is reconnecting.
An expired or revoked session disables update actions and shows a sign-in link
that returns to Updates after native passkey authentication. The return destination
is fixed; this flow does not accept an arbitrary redirect URL.
After native reauthentication, read-only key lookup can recover an earlier
operation even if another tab has since completed a later update. Historical
results never replace the current installation's admission state.
Unsubmitted composer text and uploaded attachment references are retained in
bounded browser-local storage, separately per tab and conversation. Sending
clears that tab's draft; reload never submits it. Storage failure is surfaced.
Do not rely on browser drafts as a backup, and use a trusted browser profile.
Mutating submit controls pause during drain while read/navigation and deliberate
stop controls remain available; server barriers enforce the admission decision.
The independent terminal diagnostic command works even when the app/socket is down:
It reports the fixed units, installation, gate, advisory lock owner, phases and
matching snapshot locations under
ROOST_HOME/updates/OPERATION_UUID/.Do not publish those directories or raw data/config files. Retain journals,
snapshot.json,snapshot/, saved config,failed-data/and both releases whileinvestigating. Never guess a snapshot or delete a lock to resume service.
For an intact manual-recovery operation, after fixing the underlying problem,
the terminal-only repair retries the recorded decision with explicit version:
The helper rejects the wrong decision/version. Repair cannot bypass failed
snapshot integrity or resurrect corrupt/missing journals; those require manual
forensic recovery from independently verified backups with the app stopped.
After commit, no automatic “restore previous data” option is offered.
Repair can take several minutes while copying data or probing startup. Its
private transport waits up to ten minutes; service start/stop waits up to two
minutes. If the connection ends first, inspect
roost updates status --id ...and the journal before repeating anything. A lost response does not cancel the
helper's work. Status requests remain available while repair is running.
Retention is conservative: no automatic deletion of operations, snapshots,
failed data, or retained releases. Operators may archive old terminal operations
only during idle maintenance after keeping the last verified recovery pair and
the helper's pinned release. Never reclaim the only recovery pair to make an
update fit. Large installations may need operator-managed backup/update instead.
Startup tokens are read from the private gate by the application CLI after it is
running as the installation user. The systemd drop-in contains only dependency
ordering; it does not make privileged systemd read a user-writable environment
file. HTTP cannot choose a token, environment file, service unit or command.
An operation's owner-only
diagnostic.jsonretains a bounded failure reason forterminal inspection. Browser status exposes only sanitized recovery messages.
If storage itself fails, diagnostics may be unavailable; retain the journal,
snapshot and service logs rather than deleting evidence.
Verification and qualification
See verification evidence for matched rendered
screenshots, exact test results, disposable VM setup and scope limitations. The
normal helper permits the qualified installation path; unsupported environments,
missing enrollment/authentication and incompatible releases remain blocked.
Acceptance evidence, artifact hashes, fixture setup and limitations — full preserved record
UI self-update acceptance evidence
PR #11 implements phases 1–3 of the approved design, starting from
7415789(0.1.40), including that baseline's coding protection/recovery changes. Design
PR #10 is separate; this implementation does not assume it merged.
The supported enrolled path is enabled. The temporary blanket qualification gate
has been removed after real systemd/reboot acceptance. The final native-browser
update and rollback below used the normal production build, with no qualification
transform or override. Capability, enrollment, compatibility, work and native-auth
checks remain mandatory.
All service, enrollment, update, rollback and reboot experiments ran in a private
disposable VM. No live Roost service, configuration, credentials or data was
enrolled, restarted or updated. No release was published. Private fixture keys,
guest disk images and raw logs are excluded from the PR.
Matched rendered screenshots
Actual Chromium screenshots, isolated empty data, light theme, device scale 1.
Baseline
7415789and this branch both show/settings, searchsoftware update,at identical viewports. Full-page image height follows the content. Baseline has
no matching setting; the source build now gives its external-management reason.
Matched expired-session state, same Updates card scrolled to its actions, using
controlled API responses at the same desktop/mobile viewports. The change adds
an actionable native sign-in link and disables mutations until reauthentication.
Actual native-auth/real-helper lifecycle with private release fixtures:
Earlier
confirmation-fixture-*.pngimages use deterministic API responses andare labeled API-fixture views. They are not end-to-end lifecycle evidence. No
image is a mockup.
Actual authenticated lifecycle
7488215c-f28a-44a6-bf12-c157ebc7e462bd9ca65b-2754-448d-bf65-6db1bf745a12Both runs preserved the original data sentinel, used exactly one activation POST,
reconnected across the real service outage, retained drafts across reload/closed
tabs, and returned to Updates after a second native passkey login. Rollback
retained the candidate-written sentinel separately in
failed-dataand restoredthe original data with release 0.1.202. Both services finished active with admission open.
Normal helper SHA-256:
f5972432b9a0ab1e3da14dbe5860b1edbef9d38232754cf7505d8f8df8f7ffe8.Recovered production app entry SHA-256 (matches local normal build):
831b567646703829727d29a504479acc31ab8ef382a5b2346934aef8564d05d1.Test TLS certificate SHA-256:
999304dc18fce0a235a1ed8b0d8984e519114cdfe563f9489c31bfa7524513e2.cca2f9dd83d160cfdce63acdfdedd6a8e80d55e37bd73be290dfe403f2d8a7a74f482bcebd6ed87db7cdf57d1c307d90cd5a58a95651796380dfeb396b897e81These are local fixture versions, not published Roost releases. Both bundle
Node 24.15.0 and Codex 0.153.4; the bad candidate deliberately throws after
writing its sentinel. The healthy candidate uses the checked production app.
scripts/test-updates-native-browser.mjsuses Chromium's native WebAuthn virtualauthenticator to sign real login challenges with a credential registered through
native setup. It sends actual
Origin/CSRF-protected requests to the production API and enrolled helper. Its
only update-response interception delivers the real acceptance POST, verifies HTTP 202,
then drops that response. It does not mock authentication, update status, artifact
validation or service control. The test checks durable request reconciliation,
multiple tabs, desktop/mobile drafts, explicit reauthentication, historical key
lookup after a new session, keyboard focus/Escape/Enter, the accessibility tree,
and absence of any replayed prompt or update POST.
Private local fixtures use built compatible packages with test version manifests
and real SHA-256/size metadata. A private HTTPS server inside the disposable
container answers the fixed GitHub API and release-asset hostnames. Only the
guest maps those hostnames to the fixture server and trusts its generated test
CA through a root-owned helper override. TLS verification, production hostname,
redirect, artifact digest/identity and compatibility checks remain enabled.
Nothing was uploaded to GitHub releases or an external fixture service.
The initial native path passed 0.1.49 success and 0.1.50 startup rollback using a
test-only qualified helper build. The final results above repeat the supported
path with the normal production build, after removing the temporary qualification
gate; no build transform or runtime override is used for that final run.
Real service authority and lifecycle faults
The app runs as guest UID 1000 (
ubuntu) without general sudo or sudo-groupmembership. Its only noninteractive authority is the generated exact app-unit
start/stop rule. The authenticated test administrator is a separate guest user.
Policy checks deny root shell/id, app restart and unrelated-unit start. A separate
real SO_PEERCRED check rejected guest root and accepted the app UID against the
same stable helper process, distinguishing peer authorization from file access. A root-only
canary plus an app-user symlink at the obsolete
start.envpath verified thatprivileged systemd no longer reads an app-writable environment file.
kept the app stopped, retained its data and left the helper active. CLI
start/stop used the private helper route. A standalone/duplicate helper was
rejected without replacing its socket or gate. These retained checks precede
the final normal-build native acceptance and are not counted as new runs.
group were stopped cleanly; elapsed time was 6.28 seconds, the group was empty,
and the independently supervised helper survived.
rolled back. A separately malformed auth database also rolled back. Both
restored the previous release and matching data before reopening admission.
rollback probes to fail. The updater retained manual recovery and did not kill
the unrelated listener. After the test operator removed that fixture listener,
explicit CLI repair restored the verified previous pair.
Restoring its known original bytes was an explicit test-operator action.
diagnostics. Restoring the known snapshot bytes and requesting explicit CLI
repair recovered the old pair and retained failed candidate data.
7415789CLIand the current CLI refused setup, update, start and stop races. Current CLI
auth recovery also refused. No additional operation, app restart or auth
configuration change occurred.
A separate normal-production helper test committed the candidate, wrote new data,
then made its startup fail. Recovery kept the committed release/data and closed
admission for manual recovery; it did not restore an old snapshot. After the
operator restored the known entry bytes, explicit
repair --decision resumecompleted, retained the new data and cleared the stale public failure message.
Operation:
bdb3296b-c1f1-4381-b158-9237b546b571.Journal, activation and boot boundaries
42 distinct boundaries × two real interruption mechanisms = 84 completed cases:
42 actual helper SIGKILLs and 42 actual guest reboots. See the
audited boundary table for every trigger, operation and result.
This includes journal transitions before/after commit, pointer replacement,
shutdown/startup, snapshot completion, both data renames and rollback activation,
including rename-before-directory-fsync windows.
The boundary driver uses the real systemd adapter, snapshots, kernel locks and
recovery engine; only staging is replaced with preinstalled private fixtures.
Independent native lifecycle tests above exercise the actual download/staging
path. Rollback-boundary tests inject candidate readiness rejection to reach the
required boundary without redundantly repeating the real two-minute health
failure tests. Markers include run/operation UUID, phase, process PID, guest boot
ID and timestamp. SIGKILL cases require systemd's recorded signal 9. Reboot cases
require a QMP RESET event and a changed guest boot ID. Both require a terminal
journal and the expected release/data/admission/service state before counting.
Not every trigger is a different recovery algorithm: several pre-stop journal
boundaries share old-release preservation, and several pre-commit boundaries
share matching-pair restore. Repeated setup/debug attempts are excluded from
unique-case totals. One unsynced private preinstalled fixture lost its candidate
contract on reset. That attempt was excluded, exposed a real recovery-startup
validation defect, and was recovered with the fix while retaining its evidence.
Subsequent fixture setup explicitly fsyncs before the audited reset.
Automated and storage checks
pnpm checkpassed: 202 tests, native-auth smoke test, six site tests,Biome lint/format, TypeScript, and application/CLI/marketing/docs production builds.
Rendered browser checks passed at desktop and mobile sizes. The native-browser
runs above are additional actual-guest acceptance, not mocked API checks.
The final native run initially exposed transient SQLite schema-read contention
while the old app was still serving. That pre-stop operation failed safely,
leaving its release/data available. Schema reads now use a bounded five-second
busy timeout. A real cross-process regression failed before the fix and passes
for transient locks on both databases and persistent-lock refusal. The final
normal-helper lifecycle was rerun with rebuilt, newly pinned artifacts after
that fix; the failed preparation attempt is excluded from successful totals. A separate
harness retry initially matched an older operation for the same version before
its new acceptance returned. Matching now requires the accepted operation UUID.
That accepted update completed successfully after the browser closed, but its
incomplete browser run is excluded; fresh fixture versions exercise the entire
corrected browser flow above.
The real post-commit repair case exposed an 18-second socket cutoff even though
repair eventually succeeded. Fixed, action-specific bounded transport budgets
now cover service control and repair, while status stays responsive. A real
socket regression delays repair for 21 seconds and requires concurrent status
within five seconds. Successful repair also clears its stale public error while
retaining private diagnostics; that regression failed before the fix and passed
after it.
A separate real ext4 guest filesystem verified a killed SQLite writer's committed
WAL and a 16 MiB workspace snapshot. Actual block/inode headroom exhaustion
refused snapshot creation with no partial snapshot. A separate temporary-root
stress run copied and verified 536,923,050 bytes across 2,053 entries, including a
512 MiB workspace file. Deterministic I/O fault injection at the filesystem
boundary covers snapshot/restore copy and fsync failures and a post-rename
acceptance fsync failure; assertions confirm the injection was reached and check
pairing, admission, retained data and manual-recovery evidence.
Release tests cover offline/429/private-token failure, changed offers/assets,
missing/mismatched digests, identity/tag/platform/protocol/schema/Codex mismatch,
exact runtime output, bad ABI, archive limits/traversal/links/devices, credential
stripping on redirects, and compatibility of both the candidate and rollback
release with the actual database snapshot. Existing schema-upgrade tests cover
legacy v8/v9 shapes, preservation and repeatability; newer schemas are refused.
Authorization tests cover no native auth, recent/expired/revoked sessions,
Origin/host/CSRF, bounded fields/queries/bodies, GET mutation rejection and
revocation during streamed request reading. Kernel-lock/socket tests cover
concurrent owners, SIGKILL release, fixed peer UID and legacy CLI fencing.
The actual native-browser cancellation and five-minute deferral tests used an
inert, identity-uncertain coding-worker record. The real observer's timestamps
continued advancing while admission was closed. Both preserved the app PID and
created no prompt inputs or reports. The test-only record was then removed.
Work tests keep existing observations running while claims/submissions stop.
They cover active/missing/unknown/stale/changed identities, cancellation and
follow-up recovery, admission closing during launch/follow-up preparation,
post-shutdown uncertainty, chat/steering, queued automations, expiry and exactly
one catch-up after downtime. No model API or paid worker is used by these tests.
Disposable runner and limits
QEMU 8.2.2 with TCG boots Ubuntu 24.04.4 amd64, systemd 255, local ext4, 1 GiB
RAM and two virtual CPUs. The Docker container drops all capabilities, uses
no-new-privileges, and has no host mounts/devices or exposed host ports. Itsmemory limit is 4 GiB. The private guest disk was grown from 8 to 16, then 20 GiB for
retained fixtures; only the disposable guest filesystem was resized, using
QEMU’s documented block_resize command.
Superseded fixture archives were removed; metadata, journals, snapshots and guest releases
were retained.
The official Noble image's SHA-256 was checked:
d0fe84bb5f80853425fa6be28e2c106f30104c3cfe8611933f2e65c9b63f0e30.Generated test keys and strict pinned SSH host-key checking were used throughout.
Guest-only optional cloud/package services were disabled to reduce emulation
boot noise; Roost, SSH, network and storage services remained real.
Automated accessibility evidence is Chromium keyboard/focus behavior, its
accessibility tree and mobile viewport rendering. Physical screen-reader use,
VoiceOver/Safari and additional mobile browsers require those devices and a
manual assistive-technology pass; they are not claimed here. Remote working/idle
worker and submission races use isolated transport/runtime fixtures. The native
browser test uses actual missing-worker observation and deferral, without paid
model calls or live remote jobs. A live Herdr integration run would require a
disposable endpoint, credentials and authorized model quota.
QMP resets exercise an actual guest reboot and filesystem recovery, not a physical
drive's power-loss characteristics. Copy/fsync failures are deterministic injected
I/O errors; block/inode exhaustion is real. No claim is made for arbitrary hardware
failure or untested distributions/filesystems. No additional infrastructure or
release publication is needed to reproduce the completed narrow-path tests.
These results qualify the documented narrow installation contract, not arbitrary
Linux distributions, custom units, filesystems, publisher compromise, external
writers/effects, physical-device power-loss behavior or later application bugs.
Updates cause downtime. Automatic recovery never promises to undo post-commit
work. Snapshot and journal corruption remain explicit operator recovery cases.
Audited interruption boundaries — full preserved record
Audited interruption boundaries
Each cell is a completed disposable test, with its terminal result and operation UUID.
Separate triggers may share a recovery algorithm; repeated debugging runs are excluded.
All reboot entries include an observed QMP RESET and a changed boot ID. All SIGKILL entries
include systemd signal-9 evidence and a newly written helper readiness file.
acceptedf08e8063-b21e-4d17-b7dd-495a204c309c)0d65e99e-ad48-4566-a87a-4f67119f8366)staged7400cea9-8f6c-49ec-b011-f3a5e8a401d7)05476adf-4c1c-43d3-972b-e234fa0489af)drainingabbe0189-21a8-465f-91a0-46781720a2f8)b98ff028-48e3-47c2-9711-a212956af5b9)stoppingc6238d99-a44f-4a33-a6aa-c351c7f5de26)7a76614e-f5c5-4867-b655-f7b49656f66f)service-stoppedc10ba423-1827-4f9a-a531-7f23c4639738)7bc45ef1-6bc5-4921-95c7-811d7c492394)snapshot-completece27ce9a-3499-4f07-9c0a-7f0421d38fbe)d1188f51-d28b-4d7e-9902-f08359083609)activating6e4a0797-cc52-4c46-b187-e1276552edca)27934845-5ee4-47d8-b3d1-4ecd404d18b7)pointer-renamed-before-syncf082588b-840d-494f-8f8e-37b0842e1194)0e1ff6d3-2332-4651-8945-40891a055fe5)pointer-renamed30af7103-c08a-466a-9fc0-f5b5cf2ae443)bb03c38d-dac7-4ddc-a044-e9a51150ce92)verifyingdf54e456-bf5d-4a5b-b804-0f725030509e)2d4729b8-b96c-402b-9635-260b0e9b8f19)service-startedbd595f27-4d62-4fff-9bb1-b8355e453e99)8df857aa-6286-4ea9-ba65-cf12c69f4899)before-journal-staged4569be4d-bef8-4904-8ca7-3009d6bb5d65)7b8bbd5c-8dca-4ef7-912f-2dc694a29194)before-journal-draining1abe9d9b-189e-4f90-9f36-0015951f3f0d)313472d6-d33c-49a1-8dcb-9c313009911e)before-journal-stopping976f1d43-3c19-4412-b171-7587ed4a4e85)f92070ea-8c56-42c1-b3df-272f3d684cc5)before-journal-snapshot-complete604c84de-b8fd-499e-a053-cde4d0b99760)974cf536-45bb-43ef-be6f-3837a8e48341)before-journal-activating70721c3d-e06b-47ee-9291-22523f7f7109)c63fd846-713f-4573-b123-cecabbd283a5)before-journal-verifyingd4dbf5ab-5d81-46df-b85b-a785071ea361)ca42de76-27c3-4383-ba50-e69fe41a4798)before-journal-committedb5bba1b6-bdeb-420b-a815-8c03b51e9434)bf77fd6b-80f1-44ae-acd7-f376710383c9)committed805402e3-dc88-47c0-be13-113c456f6df3)cf022d06-601f-46d7-833f-4687b3153eae)admission-open28bd96e1-25c7-46ea-8966-83d6851f8d1b)1c9142d3-a4c0-45c1-b3eb-de0b10632545)before-journal-succeededc10d8ec7-0572-47b9-bea8-c2b26ebaa53f)c2e65ca4-5910-47b7-bd10-270a0f2457bf)succeededc4c771fe-74da-42bb-a30a-a1f3c955eaa1)cf8e8f02-f836-4ada-b448-1e7f4beca26f)before-journal-restoring51bfd931-8756-4620-8f63-663a8e6c67e6)ebca0912-cd10-4daf-9b54-2574d494ca2b)restoring297fa737-4641-460d-bd24-fa7d9074e04b)7c256561-e0ac-4f4c-af70-f5c19e4a4939)failed-data-renamed-before-sync1b25f6c4-994c-4be2-af15-f40d6ef1f834)e0bf5237-cd7a-42db-ba22-12b34a3ad30d)failed-data-renamedf06b82d8-a463-442b-9949-aba5e5118bf5)36e1d31d-bff6-4a81-aaaa-e86433e84893)restored-data-renamed-before-sync7852fe25-afe7-4edd-8b1c-309737536b4b)03cc326e-d57a-4a3a-8708-394f7d70335b)restored-data-renamed9064b438-99d4-42f6-a148-4f4824b3e82f)23770fc0-7b1d-42cc-8191-0aff450396d7)before-journal-rolled-back4b118b7f-69f9-49cb-97d7-8ba2a1941ce7)1c10fa0c-c7c4-4f5e-9a30-71914706ccaa)rolled-back5a6cfa44-5bd5-4940-8af2-23e9f940b3f4)70d6c7e1-a18b-4b0b-aa47-5fc1cd723120)before-journal-accepted72675633-2d9d-49ce-a389-642fd4814060)66834ed9-12a5-465b-9301-2ccedcba6480)before-journal-failedea958297-d997-49a6-abab-86893dff693a)fb6e0338-5036-4dd3-9bff-c58623d89651)failed57a6ce3f-f80f-4174-a09b-72f682f25174)e5b66a6f-183d-4464-90a8-c573d7c32b4a)before-journal-cancelled2731d147-4bf9-4d7f-972f-f1b6683cca8b)73e1004f-254c-4b3e-8241-f524818c5fac)cancelled4bc0887f-ec07-4bf6-8bc3-092ebdaa7cbf)6d467419-79af-47e4-b089-c291a22b889f)before-journal-deferred8470a096-b665-4f69-a769-ba7d619d93eb)34eecb7e-b1dd-437f-a440-b5ea98ce9151)deferred4687d3cc-3c37-451d-8e83-3c4fd4f5d559)2a4fffa0-8d98-4302-a1af-319516075009)before-journal-manual-recovery0d35886f-f782-4efe-b19d-920cdfc9f938)4acb17eb-a34e-4226-9a30-a2345091a3f9)manual-recovery359c5cda-caca-4cd0-9924-420381691020)7b972ebe-d2e8-4cbe-9502-5b850ed640fb)rollback-pointer-renamed-before-sync004f471a-276a-497a-bedf-d043d4a5a8c8)027efc05-9af3-47da-96b2-768a06166170)rollback-pointer-renamedddfa87f4-fcf5-4dbe-9067-e3cac7c0a866)d1f82a68-4a79-4d45-8aaa-72e301875a67)rollback-service-startedb306674f-2084-445a-8db8-fdada8e2eddb)79c24730-d861-4fe4-bee6-9fa46217374e)