Files
goodbuddy/docs/architecture/desktop-storage-direction.md
T
mesalogo d80d42b032 feat(storage): move desktop SQLite ownership into a storage utility process
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.
2026-10-06 15:40:18 +08:00

389 lines
29 KiB
Markdown

# Desktop Storage And Concurrent Execution
## Decision and delivery
Updated 2026-10-05 against `2be57492`. The user selected one complete architecture
delivery for PERF-15/PERF-16 and the necessary performance guards. This document
supersedes the earlier proposal to leave full migration for a later discussion.
The integrated migration and acceptance are not complete. The implemented storage
foundation, production composition and remaining acceptance work are recorded in
[Storage Foundation Integration](./desktop-storage-foundation.md).
Local fixes in `b90ff50f` remain the measured starting point.
Deliver the integrated design in one candidate, with normal product workflows and
concurrent acceptance passing together. Internal implementation dependencies do
not create separate partial product deliveries. A worker-only prototype, an async
facade over Main SQL, or a dual-write transition does not meet completion criteria.
This document owns architecture and scope. [Performance principles](./performance-principles.md)
own normative budgets and concurrency rules; [concurrent acceptance](../quality/concurrent-desktop-acceptance.md)
owns reproducible workloads and evidence. The [roadmap](../roadmap/product-performance-experience-improvement-plan.md)
tracks status, and the [local repair record](../review/kiss-local-fixes-2026-10-05.md)
preserves earlier measurements. Migration completion requires new acceptance evidence.
## Requirements
| ID | Required outcome |
| --- | --- |
| SA-01 | Desktop Main does not open or query business SQLite, directly or through a helper. |
| SA-02 | Complete domain transactions execute under one write owner per database. |
| SA-03 | Multiple projects, conversations and subtasks progress without unrelated global waits. |
| SA-04 | Requests, event buffers, result payloads and caches have bounded lifetimes and capacity. |
| SA-05 | Persistence, ordering, cancellation, recovery and user interaction semantics are preserved. |
| SA-06 | Startup, process failure and shutdown have one tested ownership path. |
| SA-07 | Static guards and concurrent production-path tests enforce the architecture. |
| SA-08 | GoodBuddy eliminates unnecessary intermediate disk writes and duplicate full outputs; necessary temporary resources have explicit ownership and cleanup. |
## Responsibilities
```mermaid
flowchart TB
UI[Renderer: domain stores and visible views] <--> MAIN[Main: trusted IPC and lifecycle]
MAIN <--> STORAGE[Storage utilityProcess: domain operations and write owners]
STORAGE <--> READ[Existing bounded read workers]
MAIN <--> RUNTIME[Runtime hosts and compute workers]
MAIN <--> AGENT[Remote Agent]
```
- Renderer retains presentation, local interaction state and disposable visible-data
caches. Domain selectors subscribe narrowly. Hidden views retain required state,
not continuous full rendering or whole-history refreshes.
- Main retains windows, trusted sender/schema checks, OS APIs, credential decryption,
network/runtime orchestration and process lifecycle. SQL, large result assembly,
hashing and bulk attachment file work do not execute on its event loop.
- One desktop storage utility process owns the existing business database files and
exposes typed asynchronous domain operations. Keep synchronous SQLite inside this
dedicated environment where it simplifies transaction correctness.
- Reuse bounded read-only workers for expensive reads. They open only after upgrade,
read committed WAL snapshots, and do not run initialization or recovery. Storage
owns their lifecycle; a project or conversation does not create a new worker.
- Parsing, OCR, embedding and Runtime execution retain their existing hosts. Network
requests and model execution must not run inside storage transactions or hold the
storage write queue. This work does not relocate browser-dependent OCR engines.
- Remote Agent databases remain remote. Changes to desktop storage must preserve
remote replay, controller ownership and commit-before-ACK.
One write owner means exclusive business-write authority, not necessarily one OS
thread for all reads. Startup upgrades and existing maintenance/checkpoint workers
must be explicitly owned and excluded from competing business writes. Keep their
current bounded mechanisms where valid; do not create independent writers per domain.
## Ownership inventory
Inventory records current owners; destinations below are targets, not implementation facts.
| Surface | Current entry | Required destination |
| --- | --- | --- |
| `assistant.sqlite` | `src/main/assistant/assistant-database.ts`, constructed in Main | Storage service: conversations, tasks/events, activity, notes metadata, channels, supervision and timing persistence |
| `knowledge.sqlite` | `src/main/knowledge/knowledge-service.ts` and `knowledge-database.ts` | Storage service: schema, writes and external metadata; existing workers for costly reads |
| `conversation-attachments.sqlite` and referenced files | `src/main/conversation-attachment-storage.ts` | Storage service: references, adoption, reconciliation and bounded file IO |
| Document-result persistent lookup and note bodies | `document-result-storage.ts`, `magic-notes` storage | Async domain access to associated files; preserve original directories and reference semantics |
| Local remote-runtime binding DB | `src/main/remote-agent/managed-remote-execution-services.ts` | Storage service: transactional binding transitions and uniqueness |
| Native terminal / DS Web model-call ledgers | `native-terminal-client.ts`, `native-dsh-web-client.ts` instantiate `AgentModelCallLedger` | Storage service manages desktop ledger files under the existing client lifecycle; Main retains model/credential routing |
| Read, checkpoint and upgrade connections | `readonly-query-worker.ts`, `assistant-storage-worker.ts` | Service-owned steady-state reads/checkpoints; exclusive upgrade execution before readiness |
| Supervision manifest writer | `readonly-query-worker.ts` supervision mode and `SupervisionReviewStore` | Reuse scanning and manifest logic, but route its business mutations through the same write owner as publication; remove independent writer authority |
| Remote Agent journal, owners, prompts and ledger | `src/agent-daemon/daemon.ts`, `runtime-composition.ts` | Existing remote ownership, unchanged by desktop connection migration |
| Encrypted JSON settings and transient runtime caches | Existing settings/runtime services | Keep existing appropriate owners; async settings do not move merely to match a diagram |
An import scan must also find `openPrivateSqliteDatabase` and transitive constructors:
an implementation under `agent-daemon` can still open SQLite when called in desktop
Main. Do not weaken shared Agent code or relocate remote databases as a side effect.
Preserve existing database names, table formats, IDs, paths, scopes and durability
settings. Process relocation alone does not require a schema bump. Necessary schema
changes follow the [migration guide](../development/database-migrations.md).
## Existing work and consolidation
This inventory was checked against production callers on 2026-10-05. Reuse means
preserving working algorithms and contracts, not claiming their current transport,
cancellation or close semantics already meet the target. Implement the replacement
at the existing seam and remove superseded callers in the same delivery.
| Existing mechanism | Reuse or extend | Retire or avoid |
| --- | --- | --- |
| [ReadonlyQueryReader](../../src/main/readonly-query-reader.ts), [worker handlers](../../src/main/readonly-query-worker.ts) | Reuse request correlation, named operations, errors, lazy lifecycle and reader handlers; adapt the outer utility transport and strengthen typed operations, readiness, byte bounds and settlement-aware close | No second equivalent storage RPC client or admission queue; remove production infrastructure fallback through `readWithFallback`, not legitimate owner-local transaction reads |
| [Startup storage](../../src/main/assistant-storage-startup.ts), [upgrade worker](../../src/main/assistant-storage-worker.ts) | Preserve migration algorithms, progress, retry and cancellation; move SQL preflight into the storage-owned exclusive startup path | Remove Main SQL preflight and competing upgrade launch ownership; do not add a new migration framework |
| [Checkpoint and supervision connections](../../src/main/assistant/assistant-database.ts), [review store](../../src/main/assistant/supervision-review-store.ts) | Reuse PASSIVE checkpoint and manifest scan/revision algorithms; make checkpoint exit awaited and manifest writes owner-controlled | No second maintenance service or independent business writer hidden in a read-worker entry |
| [EmbeddingIndexRepository](../../src/main/knowledge/embedding-index-coordinator.ts), [binding store interface](../../src/main/agent/runtime-session-binding-store.ts), [activity repository](../../src/main/assistant/activity-history-repository.ts) | Reuse domain interfaces and transaction algorithms; adapt the desktop backing implementation and async callers | Do not add remote object proxies or duplicate repositories; Promise-returning methods are not proof of off-Main execution |
| [RemoteEventBatcher](../../src/main/remote-event-batcher.ts) | Extend existing batching with awaited persistence/flush and pending-plus-in-flight bounds; update recovery, background and interactive IPC consumers | No second durable event coalescer, receipt ledger or retry queue; no ACK or forwarding before commit |
| [AgentModelCallLedger](../../src/agent-daemon/agent-model-gateway.ts), [terminal client](../../src/main/agent/native-terminal-client.ts), [DS Web client](../../src/main/agent/native-dsh-web-client.ts) | Preserve schema, claim/deduplication and uncertain outcomes; desktop access becomes awaited storage operations | Do not relocate remote Agent ledgers; remove desktop concrete synchronous opens and early directory deletion |
| [Utility transport](../../src/main/knowledge/embedding-utility-transport.ts), [Harness readiness](../../src/main/agent/deepseek-harness-utility-launcher.ts), [shutdown helpers](../../src/main/shutdown.ts) | Reuse fork/entry/exit adapters and phased application shutdown; add storage readiness and drain at those seams | No new generic process supervisor, duplicate shutdown path or copied Harness streaming/version protocol |
| [Runtime controller](../../src/main/agent/runtime-controller.ts), [selected runtimes](../../src/main/agent/selected-runtime-manager.ts), [remote backend](../../src/agent-daemon/runtime-acp-backend.ts) | Keep request ownership, session reuse and retirement; inspect remaining global open/prepare/close waits with healthy peers | No second Runtime pool or global execution manager; the prior route-cleanup fix does not prove every global wait is gone |
| [Subagent scheduler](../../src/main/assistant/subagent-scheduler.ts), [supervision model pool](../../src/main/assistant/supervision-model-pool.ts), [review admission](../../src/main/assistant/supervisor-service.ts) | Retain task slots, review single-flight and per-model-call pool as distinct existing scopes; extend capacity/settlement tests where needed | Do not merge ordinary chat into the supervision pool or create another task state machine/provider scheduler |
The current ordinary reader removes a cancelled request from `pending` before worker
settlement, and `close()` provides no exit barrier. Supervision waits longer and can
substitute cancellation for a successful result. Extend these semantics to
represent actual execution and committed outcomes; do not copy them unchanged into
the storage client and call its capacity or shutdown complete.
Supervision's temporary scan table belongs to one SQLite connection. Retain the
bounded scan, transfer only bounded manifest data to its write owner, and preserve
initialization/resume invariants. Existing 200-row commits run in synchronous loops;
they do not themselves yield an execution turn. Yield at safe existing batch boundaries
without dividing final atomic publication or introducing a general scheduler.
Renderer consolidation stays within existing domains:
- [Conversation store](../../src/renderer/src/conversation-store.ts) and
[persistence](../../src/renderer/src/conversation-persistence.ts) already own ordered
deltas, save serialization, history requests and quit flushing. Extend those paths,
not a second `conversation-sync` queue. Its current React-aware integration is not
a reason to introduce another store library.
- [Activity sync](../../src/renderer/src/activity-sync.ts) owns paging, pending writes
and retry; [task sync](../../src/renderer/src/task-sync.ts) owns task/artifact refresh.
Tighten projections and retention there. A resolved flush that caught an error and
requeued data is not a durable success barrier; extend its explicit completion
semantics where dependent reads or shutdown require persistence.
- [Live messages](../../src/renderer/src/live-message-store.ts),
[public event buffering](../../src/main/agent-event-buffer.ts), and
[terminal batching](../../src/renderer/src/terminal-output-batcher.ts) serve distinct
display stages. Keep them separate from durable remote batching and avoid an
additional universal event bus or a second coalescing delay.
- Retain domain cache owners: [keep-alive](../../src/renderer/src/keep-alive-cache.ts),
[Markdown](../../src/renderer/src/markdown-render-cache.ts),
[channel status](../../src/renderer/src/channel-status-store.ts), and
[Supervisor scope reads](../../src/renderer/src/SupervisionStories.tsx).
Preserve pinned-pane exceptions and scope/revision guards; strengthen bounds at
their existing owners.
Runtime session behavior remains authoritative in the
[reuse design](../features/assistant-workbar/runtime-process-reuse-technical-design.md).
[Task timing](../features/task-and-job/technical-design.md) and
[supervision model scheduling](../features/conversation-supervision/technical-design.md)
retain their existing semantics. Ending an elapsed-time segment on abort does not
release an execution slot before cleanup; do not unify these clocks or restore
historical timing scans/statistics workers during this migration.
Completion includes a removal inventory tied to the table above: old Main opens,
external live-store factories, production sync fallbacks, obsolete transport callers
and independent business writers have no production references. Remove only the
superseded implementations, not valid in-owner synchronous algorithms, remote stores,
released-data compatibility or historical test evidence. No permanent dual path or
unused compatibility wrapper is part of the delivery.
## Operation boundary
Reuse repository algorithms behind domain operations: save conversation changes,
commit remote events, publish a review, adopt attachment references, or transition
a runtime binding. Public renderer IPC can keep its current shape while Main awaits
the storage client. No generic SQL endpoint or function serialization is introduced.
Existing transaction callbacks and returned live repository objects stay inside the
owner. Replace their external use with typed inputs/results. In particular,
`readSnapshot`, Knowledge publication callbacks and Supervisor store factories must
not be transported or accept an asynchronous callback that outlives a sync transaction.
The channel extends the request/handler and utility-adapter seams identified above,
correlates requests/results and carries named operations,
serializable arguments, cancellation and readiness/failure. Reuse installed Electron
transport patterns; do not add a general RPC dependency, persisted transport sequence,
protocol negotiation or a service discovery layer for this bundled child process.
Validate actual transport behavior for buffers, Maps and errors; use DTOs. Live classes,
subscriptions and handles remain with their owners. Errors retain usable codes and causes
without credentials or user content in diagnostic logs.
Queries return the requested projection. Lists use summaries/pages; source bodies,
tool outputs and attachments load through detail paths. Large results must not be
JSON-assembled in Main or copied through several caches. Existing source records are
not truncated to satisfy a latency check. A read transaction ends before posting its
reply so a slow consumer cannot keep a WAL snapshot open.
## Concurrency and ordering
Keep ordering at the smallest required scope. A conversation's persisted sequence
and a database's commits remain ordered; independent model waits, sessions and
read requests do not share a global long-running lock. Runtime process reuse retains
per-binding/session/operation identity; cancelling one request must not stop its peers.
Use existing finite concurrency and batch mechanisms before adding scheduling code.
Apply capacity to queued bytes as well as operation count where payload size varies.
When a queue fills, wait or report the existing actionable busy/error state; never
silently discard user messages, tool results or acknowledged events. Obsolete read
refreshes and display progress can coalesce; persisted evidence cannot. Preserve one
bounded batch of work before yielding so other admitted producers can progress;
change scheduling only where concurrent measurements demonstrate starvation.
Heavy reads use the read workers and leave necessary writes able to progress. UI/control
requests must not wait behind model networking, import parsing or route cleanup.
Control processing must not depend on acquiring another execution slot. This is a
resource-boundary rule, not a mandate for a new global priority scheduler.
For long publications, compute immutable data before the write transaction when
possible, then validate current database preconditions inside the transaction and
commit the complete result/checkpoint atomically. Do not await models, filesystem
callbacks or IPC while holding a write transaction. An atomic publication cannot be
split into externally visible partial commits to improve timing. Worker relocation
does not eliminate the single-writer bottleneck: acceptance measures queue wait and
commit time, as well as Main responsiveness.
## Persistence and cancellation
| Operation | Required completion meaning |
| --- | --- |
| Cached UI preference/read | Synchronous memory access is allowed; cache ownership and invalidation are explicit |
| Existing coalesced local saves | Preserve current flush semantics and expose the existing flush barrier to dependent reads/exit |
| Remote event batch | Persist event/checkpoint under existing durability, then notify/ACK; enqueueing is not commit |
| Channel outbox / runtime ledger | Preserve duplicate-dispatch prevention and uncertain-outcome handling; no blind retry after lost replies |
| Review publication | Facts, result status and checkpoints commit together or roll back together |
Abort removes queued work before dispatch. In-flight work reaches a defined safe
point and reports its actual outcome; capacity is released only after settlement or
confirmed host exit. Caller cancellation, operation termination and resource release
are distinct observations, not three new persistent product states.
`worker_threads` SharedArrayBuffer cancellation must not be assumed to cross
`utilityProcess` IPC. Reuse it only within verified thread boundaries. A message
cannot interrupt synchronous SQL while the receiver is blocked. Keep SQL/transaction
units bounded, check cancellation between safe units, and report a completed commit
as committed even if cancellation arrived too late. Do not terminate a shared storage
process to cancel one request or promise instantaneous rollback of a committed write.
Filesystem adoption and SQL references are not automatically one atomic transaction.
Preserve existing staging, adoption and reconciliation order with async file APIs.
Do not delete originals or release protected in-flight files early; do not introduce
a cross-database transaction engine or recovery journal.
## Lifecycle and failure
Main starts and supervises one storage process using existing utility-process
patterns. Process spawn is not readiness: required migrations, connection opening
and startup recovery must finish before storage-dependent operations are accepted.
Show the existing startup/upgrade progress and retry UI. Render the application shell
when safe without marking unavailable data as an empty successful result.
After process loss, reject affected pending requests with bounded diagnostics, stop
admitting writes, confirm exit and close transport resources before replacement.
The existing user retry/reopen lifecycle can re-establish storage readiness. Read-only
work can be repeated when requested. For writes without a response, consult existing
task/event/result identities and deduplication before claiming failure or retrying;
model dispatch marked uncertain must not be sent again automatically. No Main SQL
fallback, silent empty database, second durable receipt ledger or unbounded restart loop.
Shutdown stops producers and new admission, cancels unnecessary reads, drains required
writes, closes readers/checkpoints/connections, and observes storage process exit.
Extend the existing phased shutdown and deadline, including explicit storage failure
reporting; existing settled-error helpers alone do not prove a successful drain. Native client ledger
directories are removed only after their connection is closed. Upgrade/maintenance
requires exclusive ownership before changing files, following the existing maintenance
path; it cannot open an extra Main business connection.
## Output and temporary resource ownership
This work is included in the same architecture delivery. The [source investigation](./runtime-storage.md#output-and-temporary-file-investigation)
records current producers and persistence gaps. Scope is GoodBuddy-created material;
third-party MCP/Runtime internals and user workspaces are not cleanup targets.
Decide content ownership before choosing a temporary directory. Ordinary requests,
responses, concatenation and short outputs stay in bounded memory. Where an existing
record or artifact already contains complete content, pass its reference and read pages
from that owner. Do not write a temporary copy merely to cross IPC or call MCP.
Current tool events often contain only previews. Preserve full paging access by adapting
the existing `PagedOutputStore` interface to the storage/attachment owner: output that
must outlive bounded in-memory capture has one backing content object, with events
carrying previews and its reference. Write directly to that backing object; do not spool
to Temp and later copy the same bytes to another full-output store. Reuse existing file
adoption/reference/release operations and paged reads, without a second output database,
generic blob service or durable transport journal. Final answers, previews and full
stdout/stderr remain distinct data.
The storage object's retention follows its consumer. Call-only output is released when
its existing owner no longer needs paging; content referenced by persisted history is
released through that history's existing reference cleanup. Being stored by the storage
service does not make every intermediate output permanent. Keep small call-only output
in memory and preserve existing model limits. Avoid adding whole-output copies to events
or retaining all concurrent streams in an unbounded buffer. Size alone does not justify
an additional temporary copy.
The replacement must specify the complete-content reference and byte cursor through
process, search, subagent and `output_read` paths before removing the old file backend.
Inspect remote mapping separately: it does not use the local process spool and cannot
recover omitted bytes from already-pruned Agent events. Preserve supported remote
content/ACK semantics; this work does not promise new full-history capture from third-party
runtimes. Remove the old spool creation and synchronous Main paging only once the shared
replacement preserves the existing full-output contract.
### Necessary temporary material
External CLI configuration, plugin modules and atomic replacement/install staging may
still require files. Reuse environment/in-memory configuration when already supported;
otherwise keep the actual external contract. Atomic sibling files and installer staging
stay on their required filesystem under their existing owner, not a forced central root.
For disposable runtime launch material, pass a root from application initialization
through existing constructors; create it lazily:
```text
<userData>/temp/goodbuddy-runtime/<appVersion>/<runId>/
goodbuddy-runtime-launch/
```
Add purpose directories only for evidenced necessary files. Do not precreate process,
search or subagent output trees. User-visible disposable roots retain `goodbuddy-`
prefixes. Tests use `<repository>/temp/goodbuddy-<task>-<runId>/`; remote resources use
GoodBuddy-owned prefixed roots on the Host. Do not modify global `TEMP` or relocate
third-party histories/caches through an indiscriminate environment override.
The creator removes partial creations on failure. Existing service shutdown closes
children/handles and then releases its resources. Startup, including the next upgrade,
reclaims obsolete owned run directories after the existing single-instance check and
verification that no owning child remains active. Version/run IDs identify candidates;
they do not establish inactivity. Reuse process ownership checks, with only the minimal
owner information needed to identify surviving children; do not create a lease service.
Cleanup runs in bounded background work and cannot delay the first screen with a full
filesystem scan. Failed deletion leaves the known directory available to retry.
Legacy OS-Temp prefixes require an explicit list of layouts, creator and inactivity
evidence. Reclaim confirmed obsolete instances, preserve ambiguous/live directories,
and report the remaining scope. Never delete arbitrary `goodbuddy-*`, `.tmp` or `.partial`
paths by age. Existing installer/reference reconciliation retains its own roots and
rules; no global garbage collector, cleanup ledger or user-data migration is introduced.
## KISS constraints
- Keep Electron, TypeScript, SQLite and existing provider/runtime integrations.
- Add the one storage utility process, not processes per project/session/subtask.
- Reuse reader, checkpoint, parser, batching and lifecycle mechanisms where appropriate.
- Keep credentials/OS integration in Main; storage receives only required business data.
- Do not add general schedulers, distributed transactions, durable RPC journals,
compatibility readers for unshipped intermediates, new approval gates or user modes.
- Synchronous cache reads and pure calculations need not become RPC calls.
- The runtime host, database driver and UI framework are not replaced as incidental work.
## VS Code reference
VS Code demonstrates service separation, asynchronous execution, lazy activation,
cached state and coordinated close. Its application/profile/workspace storage is
owned by Electron Main, uses async `@vscode/sqlite3`, and batches cached key/value
writes. GoodBuddy retains `DatabaseSync` in a dedicated execution environment because
its relational history, graph queries and durable event acknowledgements differ.
Do not copy full-state memory loading or empty-store recovery into business history.
Sources reviewed on 2026-10-05, upstream main; no same-machine benchmark is claimed:
- [Connection ownership](https://github.com/microsoft/vscode/blob/main/src/vs/platform/storage/electron-main/storageMain.ts)
- [SQLite backend](https://github.com/microsoft/vscode/blob/main/src/vs/base/parts/storage/node/storage.ts)
- [Cache and flush lifecycle](https://github.com/microsoft/vscode/blob/main/src/vs/base/parts/storage/common/storage.ts)
- [Extension hosts](https://code.visualstudio.com/api/advanced-topics/extension-host)
## One-delivery completion
SA-01 through SA-08 must pass together under the [acceptance matrix](../quality/concurrent-desktop-acceptance.md).
All listed desktop owners, normal/background/error/cancel/exit callers, and native
client ledger paths must use the final boundary. Remove the superseded Main openings,
direct storage access and synchronous fallbacks, including helper-based bypasses.
No feature-disable workaround or loss of user interaction counts as completion.
Run production UI-to-storage tests, existing full validators, old-data integrity and
concurrent before/after measurements; validate affected desktop-to-Agent behavior on
the shared Linux x64 Host. Native platform CI verifies process startup, SQLite and
packaged entry/resource paths. Follow the release runbook for production builds and
packaged-app checks, including measurement runs.
The acceptance record must report latency, throughput, backlog and resource cleanup,
including failures. A responsive UI with stalled background commits is not success.
No target implementation, new performance baseline or migration completion is claimed
by this documentation update.