Main no longer opens desktop business SQLite. A single utility-process
storage owner holds the Assistant, Knowledge, attachment, document-result,
remote-binding and native model-ledger databases and runs whole domain
transactions; Main and Runtime callers use explicit async domain operations.
- Remove the Main readWithFallback path and the supervision worker's
separate business write connection; manifests are scanned read-only and
committed by the sole writer.
- Remote events are ACKed only after commit; process loss reports
unconfirmed writes instead of replaying them.
- Use native utilityProcess messaging with one in-flight bound (32) and
ordered waiting instead of capacity rejection and retries.
- Start the storage process before the window so startup overlaps.
- Keep short tool output in memory and store full output once in owned
storage; paging, branching, restart and deletion reuse that copy.
- Put required runtime launch files under goodbuddy-prefixed owned temp
directories and reclaim confirmed stale ones; stop writing duplicate
parsed.md.
- Add lint guards for SQLite ownership and architecture, concurrency
acceptance fixtures, and maintenance/architecture documentation.
Validation: typecheck and lint pass. Alternating baseline (edf019aa) vs
candidate runs show no regression on single-session, C01, C02, C04 and a
5-minute C06; Main p99 drops from ~21 ms to ~16.7 ms under concurrency.
Fresh portable copy (1.75M events) upgrade content unchanged; real-model
output paging passes with 4 external requests. Full npm test runs had
1-9 different timing-sensitive failures per run that pass when rerun.
Not covered: C03 review publication, C07 source body, app-level C05.
5.2 KiB
Desktop Runtime Storage Integration
S05 domain implementation and production composition, 2026-10-05. This supplies the runtime domain for the desktop storage foundation. The current composition passes the storage-owned binding store and model-call ledger factory to Main runtime services. Full desktop migration and performance acceptance remain incomplete.
Integration API
src/main/desktop-storage-runtime-operations.ts exports:
DesktopStorageRuntimeOperations: the existingRuntimeSessionBindingStoreinterface plus named ledger lifecycle and transition operations.runtimeStorageMethods: the explicit host dispatch allowlist.DesktopStorageRuntimeOwner.open(userDataPath): creates the sole binding owner atremote-runtime-bindings.sqlite. Await it before publishing storage readiness. Native ledgers open lazily at their existing paths throughopenLedger(id, path).createDesktopRuntimeStorageAdapters(call): Main adapters returningbindingStoreandopenModelCallLedger.callhas the same domain/method/tuple shape asDesktopStorageClient.call, restricted to theruntimedomain.DesktopStorageRuntimeOwner.close(): closes remaining native ledgers and the binding database. The outer storage owner must first drain admitted operations. This method is not part of the external domain allowlist.
The storage-core integration adds runtime: DesktopStorageRuntimeOperations to
DesktopStorageDomains, initializes one runtime owner from the existing user-data
directory, and dispatches allowed runtime methods against that owner. Include its
close in the storage owner's release path, including startup failure. No new RPC
client, SQL endpoint, admission queue or process is needed.
After registering the domain, Main composition is:
await storage.ready
const runtimeStorage = createDesktopRuntimeStorageAdapters(
(domain, method, args) => storage.call(domain, method, args)
)
// ManagedRemoteExecutionServices options:
// bindingStore: runtimeStorage.bindingStore
// The former userDataPath option is removed; the host owns that path.
// NativeClientCoordinator, NativeTerminalClient and NativeDshWebClientService options:
// openModelCallLedger: runtimeStorage.openModelCallLedger
ManagedRemoteExecutionServices borrows the binding interface and does not close
it on disposal. Native clients stop their producers and proxy, await their ledger
close, then delete launch material. DS Web retains native history. A failed or
unconfirmed close retains files and propagates the error. A lost open reply also
retains files because the host may still own the connection. Shutdown must stop
native/remote producers before closing the shared storage client.
Ordering And Ownership
The shared ModelCallLedger type allows synchronous or Promise-returning methods;
the concrete AgentModelCallLedger stays synchronous and remains the remote
Agent's owner. Schema, database names, call identities, retention and transaction
algorithms are unchanged.
AgentModelGateway awaits claim before provider dispatch, complete before returning
the response, delivered before resolving the delivery acknowledgement, and
outcome-unknown before reporting provider failure. Cancellation while claim is
pending does not dispatch after claim completes. Persistence rejection propagates;
the gateway does not replay a provider request after an unconfirmed write.
Validation
The final focused run passed 113 tests across eight files, with 11 existing opt-in cases skipped. It included the official DS Web process using standard Node, binding uniqueness/rotation/cursor persistence, concrete ledger reopen and uncertain outcomes, delayed/rejected persistence, and both native clients' close ordering.
desktop-storage-runtime-operations.test.ts also builds real Electron fixtures.
The production native terminal loopback gateway uses Main adapters and the real
DesktopStorageClient/transport to reach a utility-process runtime owner, then
closes its ledger before removing launch files. Production core registration is
covered by src/main/index.ts; the fixture remains focused on the runtime domain.
Its model response is local and deterministic, with no external provider call.
The shared gateway was separately validated on the pinned Linux x64 test Host via
the existing lifecycle harness rebuilt from current source. OpenCode ran a bounded
tool command in a dedicated /root/tmp/gb-lifecycle-* workspace. Desktop detached,
the test Agent was promoted, the controller resumed, and the prompt completed.
There were exactly 2 real text-provider calls, both HTTP 200, 0 image calls,
33 persisted event entries, 17 checkpoints, and successful replay deduplication.
The old test daemon retired; final owned process count was zero. The harness removed
its remote directories. Local artifacts were isolated in
temp/goodbuddy-ledger-upgrade and cleaned after validation.
Scoped ESLint and git diff --check passed. The current composition supplies
bindingStore to ManagedRemoteExecutionServices and openModelCallLedger to
the native coordinator. Whole-application acceptance, packaged cross-platform
checks and concurrent performance measurements are not established by these
focused tests.