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.
97 lines
5.2 KiB
Markdown
97 lines
5.2 KiB
Markdown
# Desktop Runtime Storage Integration
|
|
|
|
S05 domain implementation and production composition, 2026-10-05. This supplies
|
|
the runtime domain for the [desktop storage foundation](./desktop-storage-foundation.md).
|
|
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 existing `RuntimeSessionBindingStore`
|
|
interface plus named ledger lifecycle and transition operations.
|
|
- `runtimeStorageMethods`: the explicit host dispatch allowlist.
|
|
- `DesktopStorageRuntimeOwner.open(userDataPath)`: creates the sole binding owner
|
|
at `remote-runtime-bindings.sqlite`. Await it before publishing storage readiness.
|
|
Native ledgers open lazily at their existing paths through `openLedger(id, path)`.
|
|
- `createDesktopRuntimeStorageAdapters(call)`: Main adapters returning
|
|
`bindingStore` and `openModelCallLedger`. `call` has the same domain/method/tuple
|
|
shape as `DesktopStorageClient.call`, restricted to the `runtime` domain.
|
|
- `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:
|
|
|
|
```ts
|
|
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.
|