diff --git a/bun.lock b/bun.lock
index 3aecd2a9b..11f4abeeb 100644
--- a/bun.lock
+++ b/bun.lock
@@ -14,9 +14,10 @@
"@simplewebauthn/browser": "13.3.0",
"@simplewebauthn/server": "13.3.2",
"@tailwindcss/typography": "^0.5.20",
+ "@tanstack/db": "0.6.17",
"@tanstack/query-core": "5.101.4",
- "@tanstack/query-db-collection": "^1.2.1",
- "@tanstack/react-db": "^0.1.95",
+ "@tanstack/query-db-collection": "1.2.1",
+ "@tanstack/react-db": "0.1.95",
"@tanstack/react-form": "^1.33.3",
"@tanstack/react-query": "^5.101.4",
"@tanstack/react-router": "^1.170.18",
diff --git a/bunfig.toml b/bunfig.toml
index 4de6cdc6e..822bc082e 100644
--- a/bunfig.toml
+++ b/bunfig.toml
@@ -14,5 +14,5 @@ coveragePathIgnorePatterns = [
]
[serve.static]
-plugins = ["bun-plugin-tailwind", "./scripts/reactCompilerPlugin.ts"]
+plugins = ["./scripts/reactCompilerPlugin.ts", "bun-plugin-tailwind"]
environment = "PUBLIC_*"
diff --git a/docs/api/endpoints.md b/docs/api/endpoints.md
index f55e9acaf..dd29cc583 100644
--- a/docs/api/endpoints.md
+++ b/docs/api/endpoints.md
@@ -13,7 +13,9 @@ route files under `backend/src/routes/` for exact validation details.
| Method | Path | Purpose |
| ------ | ------------------------- | ------------------------------------------------------ |
| `GET` | `/api/health/live` | Public web-process liveness. |
+| `HEAD` | `/api/health/live` | Bodyless public web-process liveness probe. |
| `GET` | `/api/health/ready` | Public activation readiness; `503` when not ready. |
+| `HEAD` | `/api/health/ready` | Bodyless readiness probe with the same status as GET. |
| `GET` | `/api/health/diagnostics` | Authenticated readiness details and dependency status. |
| `GET` | `/api/sessions` | Normalized session snapshot from Gateway. |
@@ -200,6 +202,13 @@ already-running execution finishes cooperatively.
| `POST` | `/api/backup` | Creates config backup. |
| `POST` | `/api/restart` | Queues an OpenClaw Gateway restart and waits for its persisted result. |
+## Dashboard Settings
+
+| Method | Path | Purpose |
+| ------ | --------------- | ------------------------------------------------------------- |
+| `GET` | `/api/settings` | Reads Dashboard preferences plus current Gateway connection. |
+| `PUT` | `/api/settings` | Updates the validated Dashboard preference subset atomically. |
+
## Files, Config Files, Logs, Media
| Method | Path | Purpose |
@@ -210,8 +219,9 @@ already-running execution finishes cooperatively.
| `GET` | `/api/config-files` | Lists OpenClaw config files. |
| `GET` | `/api/config-files/*` | Reads a config file under OpenClaw root. |
| `PUT` | `/api/config-files/*` | Writes a config file under OpenClaw root. |
-| `GET` | `/api/logs/info` | Lists log files/metadata. |
-| `GET` | `/api/logs/content` | Reads log content. |
+| `GET` | `/api/logs/dashboard` | Reads the bounded Dashboard service log tail. |
+| `GET` | `/api/logs/openclaw/files` | Lists readable OpenClaw log files and metadata. |
+| `GET` | `/api/logs/openclaw/content` | Reads a bounded tail from one allowlisted OpenClaw log file. |
| `GET` | `/api/media` | Serves or safely previews media bytes from OpenClaw media roots. |
| `GET` | `/api/chat/media/outgoing/*` | Proxies an exact managed Gateway media path with backend-held auth. |
@@ -232,31 +242,33 @@ upstream download metadata.
## Docker
-| Method | Path | Purpose |
-| -------- | ------------------------------------------------ | ----------------------------------------- |
-| `GET` | `/api/docker/containers` | Lists containers. |
-| `GET` | `/api/docker/containers/:containerId` | Reads container details. |
-| `POST` | `/api/docker/containers/:containerId/action` | Queues a container start/stop/restart. |
-| `GET` | `/api/docker/containers/:containerId/logs` | Reads container logs. |
-| `POST` | `/api/docker/exec/start` | Queues a worker-owned container exec job. |
-| `GET` | `/api/docker/exec/:jobId` | Reads persisted exec output/state. |
-| `POST` | `/api/docker/exec/:jobId/stop` | Requests exec cancellation. |
-| `GET` | `/api/docker/images` | Lists images. |
-| `DELETE` | `/api/docker/images/:imageId` | Queues image deletion. |
-| `GET` | `/api/docker/volumes` | Lists volumes. |
-| `DELETE` | `/api/docker/volumes/:volumeName` | Queues volume deletion. |
-| `POST` | `/api/docker/prune` | Queues a Docker prune target. |
-| `POST` | `/api/docker/stack/action` | Queues a Compose stack action. |
-| `GET` | `/api/docker/updater/services` | Lists managed update services. |
-| `GET` | `/api/docker/updater/events` | Lists update events. |
-| `POST` | `/api/docker/updater/run` | Queues an updater scan. |
-| `POST` | `/api/docker/updater/services/:serviceId/update` | Queues one managed service update. |
+| Method | Path | Purpose |
+| -------- | ------------------------------------------------ | ------------------------------------------- |
+| `GET` | `/api/docker/containers` | Lists containers. |
+| `GET` | `/api/docker/containers/stats` | Reads the current container stats snapshot. |
+| `GET` | `/api/docker/containers/:containerId` | Reads container details. |
+| `POST` | `/api/docker/containers/:containerId/action` | Queues a container start/stop/restart. |
+| `GET` | `/api/docker/containers/:containerId/logs` | Reads container logs. |
+| `POST` | `/api/docker/exec/start` | Queues a worker-owned container exec job. |
+| `GET` | `/api/docker/exec/:jobId` | Reads persisted exec output/state. |
+| `POST` | `/api/docker/exec/:jobId/stop` | Requests exec cancellation. |
+| `GET` | `/api/docker/images` | Lists images. |
+| `DELETE` | `/api/docker/images/:imageId` | Queues image deletion. |
+| `GET` | `/api/docker/volumes` | Lists volumes. |
+| `DELETE` | `/api/docker/volumes/:volumeName` | Queues volume deletion. |
+| `POST` | `/api/docker/prune` | Queues a Docker prune target. |
+| `POST` | `/api/docker/stack/action` | Queues a Compose stack action. |
+| `GET` | `/api/docker/updater/services` | Lists managed update services. |
+| `GET` | `/api/docker/updater/events` | Lists update events. |
+| `POST` | `/api/docker/updater/run` | Queues an updater scan. |
+| `POST` | `/api/docker/updater/services/:serviceId/update` | Queues one managed service update. |
## Pull Requests And Deployments
| Method | Path | Purpose |
| ------ | -------------------------------------------- | ---------------------------------------------------------- |
| `GET` | `/api/pull-requests` | Lists Dashboard PRs. |
+| `POST` | `/api/pull-requests/stacks` | Creates one reviewed native GitHub PR stack. |
| `POST` | `/api/pull-requests/:number/approve` | Queues merge, optionally followed by deploy. |
| `POST` | `/api/pull-requests/:number/reject` | Queues reject/close. |
| `POST` | `/api/pull-requests/:number/review-approval` | Queues review approval. |
diff --git a/docs/architecture/greenfield-rewrite.md b/docs/architecture/greenfield-rewrite.md
index 2be4053ff..8a6ed53f9 100644
--- a/docs/architecture/greenfield-rewrite.md
+++ b/docs/architecture/greenfield-rewrite.md
@@ -1,9 +1,11 @@
# Greenfield Rewrite Blueprint
-> **Status:** implementation started. The rewrite is built beside the current production
-> implementation and targets a fresh database with no compatibility layer.
+> **Status:** implementation active. Phase 0 evidence is complete and Phase 2 is complete for its
+> stated server scope; the remaining foundation, browser, domain, Gateway/chat, privileged,
+> hardening, and cutover phases are incomplete. The rewrite is built beside the current
+> production implementation and targets a fresh database with no compatibility layer.
>
-> **Audit date:** 2026-08-04. Package versions and the Bun canary snapshot in this document
+> **Audit date:** 2026-08-06. Package versions and the Bun canary snapshot in this document
> are point-in-time facts. They are rechecked during an explicit candidate-promotion round,
> not for ordinary feature or review commits.
diff --git a/docs/architecture/greenfield-rewrite/application-architecture.md b/docs/architecture/greenfield-rewrite/application-architecture.md
index c93a544da..a9c361455 100644
--- a/docs/architecture/greenfield-rewrite/application-architecture.md
+++ b/docs/architecture/greenfield-rewrite/application-architecture.md
@@ -283,6 +283,29 @@ protocol again. Current-production Gateway/chat/session/agent/cron code supplies
not protocol authority. The consolidated controls and executable evidence are in the
[Phase 2 threat model](../../security/greenfield-phase-two-threat-model.md).
+### Current-protocol Control UI projections
+
+The 2026-08-06 OpenClaw audit separates protocol authority from Control UI projection through 23
+hash-pinned, redacted distribution artifacts. The current behavior informs Phase 4, but Dashboard
+must re-audit the installed source and use a typed protocol adapter rather than scrape, import, or
+mirror Control UI implementation details:
+
+- plan/checklist state is projected from generic `agent` events and retained only on the active
+ in-flight run; it is not a durable plan record or a dedicated plan RPC;
+- companion ask is labeled with `operator.read` upstream but starts new compute and is constrained
+ by process-local TTL and concurrency caps. Dashboard treats it as an explicit compute action,
+ preserves those bounded semantics, and does not cache it as read-only state;
+- the background-task ledger supports list, detail, and cancellation. Cancellation is a write/admin
+ operation, can lose a race to normal completion, and must expose that result instead of claiming
+ a task was stopped; and
+- `cancelled` and `timed_out` remain distinct protocol states even when a presentation groups both
+ with failures.
+
+The Phase 4 browser surface exposes the active plan/checklist, companion ask, and background-task
+details/cancellation through that adapter, with authorization and race behavior covered by recorded
+fixtures. These projections complement the persistent Dashboard chat journal; they do not make
+ephemeral OpenClaw in-flight state durable by inference.
+
### Raw HTTP exists only for protocol edges
The explicit raw-route registry owns requests whose semantics are HTTP rather than domain RPC:
@@ -343,12 +366,20 @@ constant failure markers.
The web `ApplicationRuntime` merges the realtime pump and one process-scoped authentication-work
service into the same `ManagedRuntime`. That authentication service owns separate bounded admission
and active-work semaphores for Gateway verification, password/Argon2 work, TOTP AES/HMAC work, and
-WebAuthn parsing/signature verification, plus a scoped fiber set for work that outlives an interrupted caller. Queued cancellation releases
-admission immediately; active non-cooperative work retains its permit until settlement. Promise-
-facing adapters fold typed capacity into explicit domain throttling outcomes, while Gateway
+WebAuthn parsing/signature verification, plus a scoped fiber set for work that outlives an
+interrupted caller. Queued cancellation releases admission immediately; active non-cooperative
+work retains its permit until settlement. Promise-facing adapters fold typed capacity into
+explicit domain throttling outcomes, while Gateway
capacity, deadline, and unavailable tags are exhaustively translated before the tRPC procedure
maps the resulting domain outcome. No request creates or disposes a runtime.
+The same `ManagedRuntime` coordinates listener shutdown. An external `stop(true)` request crosses
+the Promise-facing composition boundary as an abort signal; Effect owns the graceful-stop fiber,
+deadline/force race, tagged stop and timeout failures, separately bounded force attempt, and
+settlement of the original graceful operation before the runtime scope is disposed. A rejected
+graceful stop receives one bounded best-effort force attempt while preserving the initiating
+failure. No second runtime or manual timer/`Promise.race` shutdown system is created.
+
## Realtime Architecture
### One browser stream
@@ -417,11 +448,14 @@ an explicit local runtime state machine for active work:
- `chat_runtime_snapshots` stores the latest compact projection needed for fast restart
recovery.
-Gateway token/thinking/tool deltas are coalesced into small ordered batches before a SQLite
-transaction and SSE emission. The design never performs one durable commit per token. A final
-Gateway history fetch reconciles the runtime projection without duplicating messages. On
-restart, Dashboard restores the snapshot and remaining journal, reconnects to Gateway, and
-reconciles again.
+Gateway token and thinking deltas are coalesced into ordered 150 ms batches before a SQLite
+transaction and SSE emission. The interval matches the audited OpenClaw source throttle and is the
+smallest candidate that meets the measured write-rate, visual-delay, and crash-window policy for
+one, four, and eight concurrent runs. Tool/item boundaries, terminal deltas, cancellation, and
+completion flush immediately; the design never performs one durable commit per token. A final
+Gateway history fetch reconciles the runtime projection without duplicating messages. On restart,
+Dashboard restores the snapshot and remaining journal, reconnects to Gateway, and reconciles
+again.
This state machine must retain all current behavior: token streaming, thinking and tool row
ordering, tool failure scoping, final-message reconciliation, cancel/retry, concurrent sends,
@@ -447,6 +481,41 @@ small connection store may expose SSE/Gateway health without owning domain data.
own reducer/state-machine store because its ordered transient events must survive route changes
and reconnects. It is not combined with general server cache state.
+### Browser Effect boundary
+
+Effect is available in the browser, but the same selective boundary applies as on the server.
+TanStack and React continue to own rendering, server-state caches, normalized collections,
+forms, URL state, and ordinary component state. Effect owns browser work only when asynchronous
+lifetimes are themselves part of the correctness contract: scoped subscriptions or streams,
+coordinated cancellation, bounded queues/concurrency, explicit retry/backoff, multi-step uploads,
+and tagged operational failures.
+
+The first browser feature that needs such orchestration creates one browser-composition runtime
+and disposes it during application/test teardown. Hooks and renders never create runtimes, fibers,
+or duplicate retry loops. An Effect service publishes stable snapshots into the owning TanStack
+Store, Query, or collection boundary; it does not become a second domain-state cache. Simple tRPC
+query functions, Valibot parsing, reducers, deterministic state transitions, and individual event
+handlers remain ordinary TypeScript. Existing tRPC/TanStack cancellation and retry behavior is
+reused rather than wrapped merely because a function is asynchronous.
+
+### Evaluated browser dependency candidates
+
+The following registry/documentation review was performed on 2026-08-06. It records candidates,
+not blanket installation approval. Every adopted pre-1.0 package is exact-pinned and requalified in
+the vertical slice that first needs it; competing libraries are not shipped together.
+
+| Candidate | Current decision |
+| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `react-resizable-panels` `4.12.2` | Likely adoption for accessible chat, file, log, and terminal split panes. Add it only with the first real pane layout, keyboard/focus tests, bounded persisted sizes, responsive fallback, and teardown evidence. |
+| TanStack Markdown `0.0.13` | Alpha replacement candidate for the current `react-markdown`/remark/rehype chain. Before adoption, replay the complete chat/report/file corpus and verify the required GFM subset, accumulated AI streaming, unsafe HTML/URL handling, deterministic rendering, and bundle delta. |
+| TanStack Highlight `0.0.10` | Alpha companion candidate for Markdown and code/file previews. Qualify the explicit language registry, embedded-language fidelity, line/range annotations, escaping, themes, and bundle delta against the current `react-syntax-highlighter`/`refractor` surface. Adopt Markdown and Highlight independently. |
+| TanStack Charts + React adapter `0.6.5` | Preferred typed/accessibility candidate for Phase 3 metrics, but still pre-alpha. Compare representative time-series, categorical, tooltip, resize, keyboard, theme, export, and high-point-count cases against Recharts before selecting exactly one renderer. |
+| Recharts `3.10.1` | Mature fallback if the TanStack Charts spike fails. Its larger dependency surface, including Redux infrastructure, must be justified by concrete parity or stability evidence; it is not installed alongside TanStack Charts. |
+| TanStack Pacer / React Pacer `0.21.1`/`0.22.1` | Beta candidate only for repeated browser timing needs such as observable debounce, throttle, and UI batching. Server/process concurrency remains Effect-owned. The transitive `@tanstack/pacer-lite` used by TanStack DB is not an application API or reason to add the full package. |
+| Motion `13.0.0` | Optional later dependency for complex gesture, shared-layout, or interruptible animation parity. CSS/Tailwind remains the default; any adoption uses the current `motion` entry point, route-level code splitting, and reduced-motion tests rather than a direct legacy `framer-motion` import. |
+| `react-refresh` `0.18.0` | Not an application/runtime dependency. A future qualified custom HMR development path may own it as build tooling; the selected production AOT build does not ship it. |
+| SWR `2.5.0` | Rejected. It duplicates tRPC/TanStack Query remote-state ownership and would introduce a second cache, retry policy, and invalidation model. |
+
### What Query Collections are for
A TanStack DB Query Collection is the bridge from a TanStack Query snapshot to a normalized,
@@ -463,9 +532,12 @@ It is not used merely because data came from the server:
- form drafts stay in TanStack Form; and
- chat runtime events stay in the dedicated chat store/state machine.
-Collections are created once per `QueryClient` and hidden behind a small Dashboard adapter
-because TanStack DB is still pre-1.0. The package is exact-pinned. A server snapshot always
-wins over conflicting speculative collection state.
+Collections are created once per `QueryClient` and cache key and hidden behind a small Dashboard
+adapter because TanStack DB is still pre-1.0. The exact-qualified package set is
+`@tanstack/db@0.6.17`, `@tanstack/query-db-collection@1.2.1`,
+`@tanstack/react-db@0.1.95`, and `@tanstack/query-core@5.101.4`. Route teardown disposes only the
+route subscription; it does not destroy and recreate an asynchronous collection under the same
+cache key. A server snapshot always wins over conflicting speculative collection state.
### Component and route rules
diff --git a/docs/architecture/greenfield-rewrite/implementation-plan.md b/docs/architecture/greenfield-rewrite/implementation-plan.md
index 12dc17a05..a6039251e 100644
--- a/docs/architecture/greenfield-rewrite/implementation-plan.md
+++ b/docs/architecture/greenfield-rewrite/implementation-plan.md
@@ -17,6 +17,10 @@ compatibility migration inside it.
**Exit gate:** every architecture risk marked mandatory below has a passing executable spike.
+**Status (2026-08-06): complete.** Exact-candidate qualification, source-derived parity, and the
+eight executable spikes below pass. This closes evidence selection only; Phase 1 foundation and
+the remaining rewrite phases are still incomplete.
+
### Phase 1: foundation
- create source boundaries, configuration, logging, errors, contract registry, Drizzle/native
@@ -84,30 +88,37 @@ Given the current chat, auth, worker, delivery, and host-integration surface, th
**50–80 focused engineer-days**, not a small transport refactor. Automation can reduce elapsed
time, but it cannot remove the qualification, security, restore, and parity gates.
-## Mandatory Spikes and Open Decisions
-
-The target choices are fixed unless one of these tests disproves the underlying assumption:
-
-1. **Bun full-stack build:** verify React Compiler-first transforms, Tailwind, lazy chunks,
- source maps, CSP, asset hashes, precompression, and bundle budgets. Then select exactly one
- production build path.
-2. **tRPC SSE on exact Bun:** verify credentials, aborts, tracked resume, error shapes,
- reverse-proxy behavior, deploy reconnect, and slow-consumer memory.
-3. **SQLite outbox latency:** measure adaptive polling with web/worker processes under chat and
- job load. Keep the database authoritative; change only the wakeup mechanism if latency or
- I/O misses the target.
-4. **Chat batching:** determine the smallest durable delta interval that preserves current
- visual streaming while bounding SQLite writes and restart loss.
-5. **TanStack DB adapter:** prove snapshot replacement, direct batch writes, query-cache
- synchronization, optimistic-conflict handling, and route teardown without duplicate rows.
-6. **Drizzle on Bun SQLite:** verify sync transactions, prepared statements, the `sql` tagged
- template, partial/unique indexes, generated migrations, Valibot row schemas, native-client
- access, and query plans on the exact pinned Drizzle version and resolved Bun qualification
- candidate.
-7. **Bun canary shutdown:** verify graceful SSE, Gateway, prepared-statement, worker lease, and
- child-process cleanup under systemd stop/restart.
-8. **Resource budgets:** measure build/test and representative privileged jobs in cgroups before
- finalizing service/job limits.
+## Mandatory Spikes and Decisions
+
+All eight Phase 0 spikes have executable evidence on the audited Bun candidate. Their selected
+outcomes remain normative unless a later runtime or dependency qualification disproves them:
+
+1. **Passed — Bun full-stack build:** use one compiler-first Bun HTML ahead-of-time production
+ build. Tailwind, lazy chunks, CSP, hashes, precompression, source-map policy, and bundle budgets
+ pass in the mechanism fixture and actual frontend build; there is no fallback build path.
+2. **Passed — tRPC SSE on exact Bun:** credentials, cancellation, tracked resume, typed errors,
+ proxy/TLS streaming, rolling reconnect, and bounded slow-consumer behavior pass.
+3. **Passed — SQLite outbox latency:** separate web and worker processes deliver a WAL-backed
+ durable outbox without gaps or duplicates, classify observed busy/locked outcomes, and recover an
+ expired claim after hard worker termination.
+4. **Passed — chat batching:** use ordered 150 ms token/thinking batches. One, four, and eight
+ concurrent runs meet the selected write/delay policy, while tool/item, terminal, cancel, and
+ completion boundaries flush immediately.
+5. **Passed — TanStack DB adapter:** the exact-pinned local adapter proves snapshot replacement,
+ direct batch writes, query-cache synchronization, optimistic-conflict resolution, forwarded
+ cancellation, and subscription teardown without duplicate rows.
+6. **Passed — Drizzle on Bun SQLite:** synchronous transactions, prepared-statement lifetime,
+ native access, constraints/indexes/query plans, schema validation, migrations, checkpoint,
+ backup, restore, and integrity pass on the exact candidate.
+7. **Passed — Bun canary shutdown:** two service generations prove readiness withdrawal, SSE and
+ Gateway closure, prepared-statement/database disposal, worker-lease recovery, process-group
+ cleanup, WAL recovery, and bounded Effect-owned graceful-to-force listener shutdown.
+8. **Passed — resource budgets:** capped sequential build, test, SQLite, chat, shutdown, and child
+ cancellation runs complete without high/max/OOM events, memory pressure, or leaked resources.
+
+The exact candidate qualification additionally covers raw RFC 6455 continuation and fragmented
+UTF-8 reassembly, protocol/application size closes, deterministic cancellation, and explicit
+absence of reconnect. The source-derived inventory accounts for 156 HTTP operations plus `/ws`.
The OpenClaw audit is deliberately point-in-time. The Phase 2 one-shot verifier records the
installed `2026.7.2-beta.7 (dabe191)` protocol-v4 behavior, but it does not qualify persistent
@@ -163,7 +174,7 @@ not package memory alone:
- [`bun test`](https://bun.com/docs/test)
- [Full-stack development server and HTML imports](https://bun.com/docs/bundler/fullstack)
- [Official canary release asset](https://github.com/oven-sh/bun/releases/tag/canary)
-- [Latest audited Bun commit](https://github.com/oven-sh/bun/commit/43783cedd5653fa29bb9ac83df34633eae10fe75)
+- [Latest audited Bun commit](https://github.com/oven-sh/bun/commit/17d6843606d76620cb55d31424d7fb0aed51c367)
### tRPC and validation
@@ -195,6 +206,14 @@ not package memory alone:
- [TanStack Form validation](https://tanstack.com/form/latest/docs/framework/react/guides/validation)
- [TanStack Store React quick start](https://tanstack.com/store/latest/docs/framework/react/quick-start)
- [TanStack Virtual](https://tanstack.com/virtual/latest/docs/introduction)
+- [TanStack Pacer](https://tanstack.com/pacer/latest/docs/overview)
+- [TanStack Markdown](https://tanstack.com/markdown/latest/docs/overview)
+- [TanStack Highlight](https://tanstack.com/highlight/latest/docs/overview)
+- [TanStack Charts](https://tanstack.com/charts/latest/docs/overview)
+- [Recharts](https://www.npmjs.com/package/recharts)
+- [React Resizable Panels](https://www.npmjs.com/package/react-resizable-panels)
+- [Motion for React](https://motion.dev/docs/react)
+- [SWR](https://swr.vercel.app/)
### Database, security, and tooling
diff --git a/docs/architecture/greenfield-rewrite/progress.md b/docs/architecture/greenfield-rewrite/progress.md
index 66c6dd10a..25ebeb4d3 100644
--- a/docs/architecture/greenfield-rewrite/progress.md
+++ b/docs/architecture/greenfield-rewrite/progress.md
@@ -9,7 +9,7 @@ closes a phase; dated entries below provide the evidence, not a second status so
| Phase | Status | Current evidence and remaining gate |
| ----------------------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| 0 — Evidence and qualification | In progress | Bun/SQLite/tRPC/SSE and production-shaped realtime evidence passes; frontend build, TanStack DB, full shutdown, chat batching, and measured resource-budget spikes remain. |
+| 0 — Evidence and qualification | Complete | All eight mandatory spikes pass on exact Bun revision `17d6843606d76620cb55d31424d7fb0aed51c367`, including build, transport, database/outbox, browser data, chat batching, shutdown, parity, OpenClaw source audit, and capped resource evidence. |
| 1 — Foundation | In progress | Server composition, migrations, contracts, raw HTTP policy, realtime outbox, and the current generated-doc subset exist; browser/worker roots, complete import enforcement, complete generated references, and release/rollback closure remain. |
| 2 — Trust and transport | Complete for the stated server scope | Authentication, MFA, WebAuthn, automation credentials, audit, authenticated renewable SSE, one-shot native Gateway bootstrap verification, and the consolidated [threat model](../../security/greenfield-phase-two-threat-model.md) have executable evidence. Browser UI and production cutover remain later gates. |
| 3 — Core operator domains | Started | Monitoring transaction/schema foundations exist; task, agent, report, incident, notification, schedule/job, cache/metrics procedures and browser parity are not complete. |
@@ -586,11 +586,69 @@ closes a phase; dated entries below provide the evidence, not a second status so
wrong-ID/contradictory frames, exact mismatch classification, header and URL secrecy,
deterministic absence of retry after `startup-sidecars`, native connection refusal,
close-confirmed terminal races, redaction, timeout, and real HTTP-to-Effect-to-socket
- cancellation with zero user/session/audit/rate-limit publication. Raw continuation-frame
- qualification remains an explicit Phase 0 gate. The consolidated
+ cancellation with zero user/session/audit/rate-limit publication. Phase 0 now separately
+ qualifies raw continuation frames and fragmented-message behavior. The consolidated
[Phase 2 threat model](../../security/greenfield-phase-two-threat-model.md) maps the complete
authentication, MFA, WebAuthn, automation, SSE, migration, and Gateway evidence to misuse cases
and residual risks.
- This closes Phase 2 only for its documented server-side scope. It does not claim full native
persistent Gateway qualification. Phase 4 must re-audit the then-installed OpenClaw source and
protocol before implementing persistent connection, event recovery, sessions, chat, or cron.
+
+### 2026-08-06 — Phase 0 evidence and qualification closed
+
+- Bun `1.4.0-canary.1+17d684360`, full revision
+ `17d6843606d76620cb55d31424d7fb0aed51c367`, passes qualification typecheck and the complete
+ qualification suite: 151 tests, 758 assertions, zero failures, and 31 files. This is the exact
+ audited candidate for the round, not a repository-wide source-revision pin.
+- The selected frontend path is one compiler-first Bun HTML AOT build. Executable fixture and
+ actual-build evidence cover Tailwind, lazy chunks, fail-closed inline event/style/base and
+ URL-bearing attribute CSP policy, hashes, precompression, absent production source maps, and
+ bundle budgets. The exact-pinned TanStack DB adapter covers snapshot replacement, direct batch
+ writes, query-cache synchronization, optimistic conflicts, cancellation, and
+ route-subscription teardown.
+- File-backed WAL evidence uses separate web and worker processes and covers reader/writer and
+ writer/writer behavior, observed busy/locked classification, no-gap/no-duplicate outbox delivery,
+ hard-kill claim recovery, savepoints, prepared-statement disposal, checkpoint, backup, restore,
+ and integrity. Chat qualification selects 150 ms ordered token/thinking batches for one, four,
+ and eight concurrent runs, with immediate tool/item, terminal, cancel, and completion flushes.
+ Source inputs are read through held no-follow descriptors with deterministic shrink, growth,
+ overwrite, and requested-path replacement rejection.
+- Raw RFC 6455 tests cover continuation reassembly, a UTF-8 code point split across three frames,
+ orphan/interleaved-fragment `1002` closes, invalid-length and 64 KiB application-bound `1009`
+ closes, deterministic cancellation/close, partial writes, native refusal, and exactly one
+ connection attempt without reconnect.
+- The two-generation shutdown test withdraws readiness before cleanup, closes SSE and the local
+ Gateway connection, disposes the statement and WAL database, recovers the worker lease, reaps its
+ owned child with bounded SIGTERM-to-SIGKILL escalation, and restarts on the same database without
+ a leak. The candidate's
+ intentional keep-alive behavior requires a scoped Effect graceful-stop fiber followed by a
+ separately bounded force escalation; the candidate records `listener-force-stopped` and closes
+ every owned resource. Stream cancellation is separately bounded so a non-cooperative Fetch body
+ cannot block older scope finalizers. The production listener now uses the same process
+ `ManagedRuntime` for its tagged graceful/deadline/force orchestration, including explicit force
+ requests, original-fiber settlement, and best-effort containment after graceful rejection; a
+ stop failure preserves runtime services until terminal supervisor containment.
+- Source-derived parity now accounts for all 156 current HTTP operations plus `/ws`. The OpenClaw
+ audit pins 23 redacted source/protocol/UI artifacts for installed `2026.7.2-beta.7 (dabe191)`,
+ including the generic-event, ephemeral plan/checklist projection, compute-starting companion ask,
+ and background-task list/detail/cancel semantics. These are Phase 4 adapter requirements, not an
+ invitation to scrape the Control UI.
+ The route-tree source parser accepts only the reviewed recursive `addChildren` grammar and
+ accounts for every child identifier regardless of naming suffix.
+- The exact-candidate capped resource matrix passes without `high`, `max`, `oom`, or `oom_kill`
+ memory events, memory pressure, or leaked process, unit, or temporary state:
+
+ | Scenario | Peak memory (bytes) | Elapsed (ms) | Peak tasks |
+ | --------------------- | ------------------: | -----------: | ---------: |
+ | Frontend build | 650,104,832 | 14,793 | 19 |
+ | Representative tests | 248,758,272 | 2,222 | 18 |
+ | SQLite outbox/restore | 101,896,192 | 1,218 | 20 |
+ | Chat batching | 42,676,224 | 97 | 12 |
+ | Complete shutdown | 128,774,144 | 3,133 | 25 |
+ | Child-process cancel | 117,194,752 | 1,531 | 24 |
+
+- Phase 0 is complete, but the rewrite is not: Phase 1 remains in progress with browser/worker
+ roots, complete import enforcement, complete generated references, immutable release/rollback,
+ and end-to-end empty-database web/worker delivery still open. Final production load, restore,
+ cutover, and legacy-removal evidence remains in Phase 6.
diff --git a/docs/architecture/greenfield-rewrite/runtime-and-delivery.md b/docs/architecture/greenfield-rewrite/runtime-and-delivery.md
index 7c6044438..842816337 100644
--- a/docs/architecture/greenfield-rewrite/runtime-and-delivery.md
+++ b/docs/architecture/greenfield-rewrite/runtime-and-delivery.md
@@ -11,9 +11,9 @@
| Repository channel | `canary` |
| Required runtime version | `1.4.0` |
| Running production release runtime | `1.4.0-canary.1+e82022145` |
-| Audited qualification candidate | `1.4.0-canary.1+43783cedd` |
-| Audited full revision | `43783cedd5653fa29bb9ac83df34633eae10fe75` |
-| Audited commit date | 2026-08-03 22:02:12 UTC |
+| Audited qualification candidate | `1.4.0-canary.1+17d684360` |
+| Audited full revision | `17d6843606d76620cb55d31424d7fb0aed51c367` |
+| Audited commit date | 2026-08-06 00:27:30 UTC |
The audited revision is evidence for this qualification round, not a repository-wide pin.
Normal CI resolves the `canary` channel and runs the complete gate set. Release creation then
@@ -42,7 +42,7 @@ the Bun HTML pipeline, but workspace files and media retain explicit, policy-che
### Mandatory canary qualification
-Before the new repository baseline is locked, run the following in an isolated, memory-capped
+Before promoting a new repository baseline, run the following in an isolated, memory-capped
environment against the exact candidate binary:
1. Fetch-adapter query and mutation tests, including cookies, aborts, response headers, and
@@ -58,10 +58,43 @@ environment against the exact candidate binary:
6. `bun test --isolate` tests for fake timers, leaked handles, deterministic shutdown, and
bounded concurrency.
-The current one-shot Phase 2 verifier qualifies complete text `MessageEvent` delivery only. Raw
-continuation-frame reassembly and fragmented-message behavior remain an explicit open Phase 0
-native-WebSocket gate and must be qualified against the then-current Bun candidate before the
-repository baseline is locked.
+The 2026-08-06 qualification round passes on exact revision
+`17d6843606d76620cb55d31424d7fb0aed51c367`: qualification typecheck passes, and the full suite
+reports 151 tests, 758 assertions, and zero failures across 31 files. Its executable evidence
+includes:
+
+- compiler-first Bun HTML AOT output with Tailwind, lazy chunks, fail-closed inline-code and
+ URL-bearing-attribute CSP checks, hashes, precompression, no production source maps, and
+ enforced bundle budgets;
+- Fetch/tRPC/SSE cancellation, resume, proxy, rolling-restart, and slow-consumer behavior;
+- raw RFC 6455 continuation reassembly with a UTF-8 code point split across frames, protocol-close
+ `1002`, application-bound `1009`, a 64 KiB limit, deterministic close, and exactly one connection
+ attempt without reconnect;
+- WAL SQLite with separate web and worker processes, actual busy/locked behavior, durable outbox
+ delivery and lease recovery, statement disposal, checkpoint, backup, restore, and integrity;
+- the exact-pinned TanStack DB adapter, snapshot/cache synchronization, batch writes, optimistic
+ conflict handling, cancellation, and route-subscription teardown;
+- 150 ms chat-delta batching for one, four, and eight concurrent runs with immediate boundary and
+ terminal flushes;
+- a two-generation shutdown with readiness withdrawal, SSE and Gateway closure, statement and
+ database disposal, bounded non-cooperative stream cancellation, worker-lease recovery,
+ child-process-group cleanup, WAL recovery, and no leaked process; and
+- source-derived parity for 156 current HTTP operations plus `/ws`, together with 23 hash-pinned,
+ redacted OpenClaw protocol and Control UI audit artifacts.
+
+The candidate intentionally makes `server.stop(false)` wait for idle keep-alive connections. The
+shutdown qualification therefore uses an Effect-scoped graceful-stop fiber with a bounded wait and
+a separately bounded `server.stop(true)` escalation. The exact candidate records
+`listener-force-stopped`, then closes SSE and every owned resource without a leak; the event model
+permits exactly one graceful or forced terminal outcome.
+
+The candidate resource checks also pass without `high`, `max`, `oom`, or `oom_kill` memory
+events, memory pressure, or leaked process, unit, or temporary state. The dated
+[Phase 0 progress record](progress.md#2026-08-06--phase-0-evidence-and-qualification-closed)
+owns the authoritative resource measurements.
+
+These measurements qualify the mechanisms and current limits; Phase 6 still owns final
+production-shaped load, restore, and cutover evidence.
`.bun-version` selects the `canary` channel through the official `setup-bun` action. The serving
process enforces Bun `1.4.0`, while the runtime revision remains diagnostic until release creation
@@ -100,17 +133,12 @@ const server = Bun.serve({
});
```
-The preferred frontend build uses Bun's HTML entrypoint and ahead-of-time production build.
-The React Compiler plugin must run before other Babel transforms, followed by Bun and the
-Tailwind plugin. Because Bun still labels the full-stack development server as work in
-progress, phase 0 must choose one proven build mode:
-
-- preferred: Bun HTML import/full-stack entry with an AOT production build; or
-- if the qualification fails: explicit browser and server `Bun.build` entrypoints.
-
-Only the selected mode is implemented. There is no production fallback or duplicate build
-path. In either case, the release contains prebuilt assets, hashes, compressed variants,
-source-map policy, and a manifest; production never compiles the frontend on request.
+Phase 0 selects Bun's HTML entrypoint with an ahead-of-time production build. The production
+devtools stub runs first when present, React Compiler then runs before Tailwind, and no runtime
+full-stack development server is part of delivery. The executable fixture and actual frontend
+build prove lazy chunks, CSP-compatible external assets, content hashes, absent production source
+maps, precompressed variants, and bundle budgets. There is no production fallback or duplicate
+build path: releases contain prebuilt assets and production never compiles the frontend on request.
## Configuration From Scratch
diff --git a/docs/generated/packages-and-runtime.md b/docs/generated/packages-and-runtime.md
index 4b3ccced4..4567acd0e 100644
--- a/docs/generated/packages-and-runtime.md
+++ b/docs/generated/packages-and-runtime.md
@@ -23,9 +23,10 @@
| `@simplewebauthn/browser` | `13.3.0` | `13.3.0` | runtime |
| `@simplewebauthn/server` | `13.3.2` | `13.3.2` | runtime |
| `@tailwindcss/typography` | `^0.5.20` | `0.5.20` | runtime |
+| `@tanstack/db` | `0.6.17` | `0.6.17` | runtime |
| `@tanstack/query-core` | `5.101.4` | `5.101.4` | runtime |
-| `@tanstack/query-db-collection` | `^1.2.1` | `1.2.1` | runtime |
-| `@tanstack/react-db` | `^0.1.95` | `0.1.95` | runtime |
+| `@tanstack/query-db-collection` | `1.2.1` | `1.2.1` | runtime |
+| `@tanstack/react-db` | `0.1.95` | `0.1.95` | runtime |
| `@tanstack/react-form` | `^1.33.3` | `1.33.3` | runtime |
| `@tanstack/react-query` | `^5.101.4` | `5.101.4` | runtime |
| `@tanstack/react-router` | `^1.170.18` | `1.170.18` | runtime |
diff --git a/package.json b/package.json
index a02aef397..c3cf3450d 100644
--- a/package.json
+++ b/package.json
@@ -56,9 +56,10 @@
"@simplewebauthn/browser": "13.3.0",
"@simplewebauthn/server": "13.3.2",
"@tailwindcss/typography": "^0.5.20",
+ "@tanstack/db": "0.6.17",
"@tanstack/query-core": "5.101.4",
- "@tanstack/query-db-collection": "^1.2.1",
- "@tanstack/react-db": "^0.1.95",
+ "@tanstack/query-db-collection": "1.2.1",
+ "@tanstack/react-db": "0.1.95",
"@tanstack/react-form": "^1.33.3",
"@tanstack/react-query": "^5.101.4",
"@tanstack/react-router": "^1.170.18",
diff --git a/qualification/browser/queryCollectionAdapter.test.ts b/qualification/browser/queryCollectionAdapter.test.ts
new file mode 100644
index 000000000..5bc3d2b59
--- /dev/null
+++ b/qualification/browser/queryCollectionAdapter.test.ts
@@ -0,0 +1,256 @@
+import { describe, expect, test } from "bun:test";
+
+import { QueryClient } from "@tanstack/query-core";
+
+import {
+ createQualificationQueryCollection,
+ QualificationCollectionConflictError,
+ type QualificationPersistedUpdate,
+} from "./queryCollectionAdapter";
+
+interface QualificationItem {
+ id: string;
+ label: string;
+ version: number;
+}
+
+const collectionKey = ["qualification", "items"] as const;
+
+describe("TanStack DB Query Collection adapter qualification", () => {
+ test("replaces snapshots and synchronizes direct batches with Query cache", async () => {
+ const queryClient = createQueryClient();
+ let authoritative: QualificationItem[] = [
+ { id: "a", label: "server-a", version: 1 },
+ { id: "b", label: "server-b", version: 1 },
+ ];
+ const adapter = createQualificationQueryCollection({
+ id: "qualification-items",
+ queryClient,
+ queryKey: collectionKey,
+ fetchSnapshot: () => Promise.resolve(structuredClone(authoritative)),
+ });
+
+ try {
+ await adapter.preload();
+ expect(project(adapter.rows())).toEqual(authoritative);
+ expect(cachedItems(queryClient)).toEqual(authoritative);
+
+ adapter.applyBatch([
+ {
+ type: "upsert",
+ value: { id: "a", label: "delta-a", version: 2 },
+ },
+ { type: "delete", id: "b" },
+ {
+ type: "upsert",
+ value: { id: "c", label: "delta-c", version: 1 },
+ },
+ ]);
+ const deltaRows = [
+ { id: "a", label: "delta-a", version: 2 },
+ { id: "c", label: "delta-c", version: 1 },
+ ];
+ expect(project(adapter.rows())).toEqual(deltaRows);
+ expect(cachedItems(queryClient)).toEqual(deltaRows);
+
+ authoritative = [{ id: "a", label: "server-wins", version: 3 }];
+ await adapter.refetchAuthoritative();
+ expect(project(adapter.rows())).toEqual(authoritative);
+ expect(cachedItems(queryClient)).toEqual(authoritative);
+ } finally {
+ await adapter.dispose();
+ }
+ });
+
+ test("lets the authoritative refetch win an optimistic version conflict", async () => {
+ const queryClient = createQueryClient();
+ const persistence = Promise.withResolvers
+ Loaded from a route-shaped lazy chunk.
+
',
+ "utf8"
+ );
+ await assertSelfHostedFrontendHtml(indexPath);
+
+ for (const html of [
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '',
+ '