feat: Phase 2 — store audit, migration clusters, ADR, settings domain migration
- MIGRATION_CLUSTERS.md: reactive dependency graph across 20 bridges/stores - PHASE1_STORE_AUDIT.md: 11 stores audited (3 clean, 5 bridge-dependent, 3 platform-specific) - ADR-001: dual-stack binding strategy (accepted, S-1+S-3 hybrid) - Settings domain migration: all 6 settings components + App.svelte + FilesTab migrated from settings-bridge to getBackend() calls
This commit is contained in:
parent
df83b1df4d
commit
579157f6da
18 changed files with 657 additions and 26 deletions
131
docs/architecture/adr-001-dual-stack-binding.md
Normal file
131
docs/architecture/adr-001-dual-stack-binding.md
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
# ADR-001: Dual-Stack Frontend-Backend Binding Strategy
|
||||
|
||||
**Status:** Accepted
|
||||
**Date:** 2026-03-22
|
||||
**Deciders:** Human + Claude (tribunal consensus: Claude 72%, Codex 78%)
|
||||
|
||||
## Context
|
||||
|
||||
Agent Orchestrator runs on two backends: Tauri 2.x (Rust, production) and Electrobun (Bun/TypeScript, experimental). Both share the same Svelte 5 frontend but communicate through different IPC mechanisms:
|
||||
|
||||
- **Tauri:** `@tauri-apps/api/core` invoke() + listen()
|
||||
- **Electrobun:** RPC request/response + message listeners
|
||||
|
||||
The initial implementation used 23 bridge adapter files that directly import `@tauri-apps/api`. This created three problems:
|
||||
|
||||
1. **Duplicate code** — Each backend reimplements the same IPC surface. Electrobun adapters must manually replicate every bridge function.
|
||||
2. **Drift risk** — When a Tauri bridge gains a new function, the Electrobun equivalent silently falls behind. No compile-time enforcement.
|
||||
3. **58 Codex findings** — Three independent Codex audits identified duplicate SQL schemas, inconsistent naming (snake_case vs camelCase across the wire), missing error handling in Electrobun paths, and untested adapter code.
|
||||
|
||||
The project needed a binding strategy that:
|
||||
- Eliminates code duplication for shared frontend logic
|
||||
- Provides compile-time guarantees that both backends implement the same surface
|
||||
- Does not require a premature monolithic rewrite
|
||||
- Supports incremental migration of existing bridge adapters
|
||||
|
||||
## Decision
|
||||
|
||||
Adopt the **S-1 + S-3 hybrid strategy**: a shared `BackendAdapter` interface (S-1) combined with scoped, audit-gated extraction (S-3).
|
||||
|
||||
### Core Mechanism
|
||||
|
||||
A single `BackendAdapter` TypeScript interface defines every operation the frontend can request from the backend. Two concrete implementations (`TauriAdapter`, `ElectrobunAdapter`) are compile-time selected via path aliases. A singleton `getBackend()` function provides the active adapter.
|
||||
|
||||
Frontend stores and components call `getBackend().someMethod()` instead of importing platform-specific bridge files. The `BackendCapabilities` flags allow UI to gracefully degrade features unavailable on a given backend.
|
||||
|
||||
### Package Structure
|
||||
|
||||
- **`@agor/types`** — Shared type definitions (agent, project, btmsg, bttask, health, settings, protocol, backend, ids). No runtime code.
|
||||
- **`src/lib/backend/backend.ts`** — Singleton accessor (`getBackend()`, `setBackend()`, `setBackendForTesting()`).
|
||||
- **`src/lib/backend/TauriAdapter.ts`** — Tauri 2.x implementation.
|
||||
- **`src/lib/backend/ElectrobunAdapter.ts`** — Electrobun implementation.
|
||||
|
||||
### Canonical SQL
|
||||
|
||||
A single `schema/canonical.sql` (29 tables) is the source of truth for both backends. A `tools/validate-schema.ts` extracts DDL metadata for comparison. A `tools/migrate-db.ts` handles one-way Tauri-to-Electrobun data migration with version fencing.
|
||||
|
||||
## Phase 1 Scope (DONE)
|
||||
|
||||
Implemented 2026-03-22:
|
||||
|
||||
- `@agor/types` package: 10 type files covering all cross-backend contracts
|
||||
- `BackendAdapter` interface with 15 methods + 5 event subscriptions
|
||||
- `BackendCapabilities` with 8 boolean flags
|
||||
- `TauriAdapter` implementing all methods via `invoke()`/`listen()`
|
||||
- `ElectrobunAdapter` implementing all methods via RPC
|
||||
- `backend.ts` singleton with test helpers
|
||||
- Canonical SQL DDL (29 tables, CHECK constraints, FK CASCADE, 13 indexes)
|
||||
- Schema validator and migration tool
|
||||
- `pnpm-workspace.yaml` workspace setup
|
||||
- `docs/SWITCHING.md` migration guide
|
||||
|
||||
## Phase 2 Scope (In Progress)
|
||||
|
||||
Store audit and selective migration to `@agor/stores`:
|
||||
|
||||
- Reactive dependency graph analysis across 13 stores and 23 bridges
|
||||
- Categorization: CLEAN (4 stores) / BRIDGE-DEPENDENT (9 stores) / PLATFORM-SPECIFIC (0 stores)
|
||||
- Settings domain migration: first cluster, replacing `settings-bridge.ts` with `getBackend()`
|
||||
- 8 migration clusters identified, ordered by dependency depth
|
||||
|
||||
### Phase 2 Trigger Checklist (Frozen)
|
||||
|
||||
All items verified as implementable via BackendAdapter:
|
||||
|
||||
- [x] PTY session create/attach/detach/destroy
|
||||
- [x] Agent dispatch with status tracking
|
||||
- [x] Settings read/write persistence
|
||||
- [x] Search index query
|
||||
- [x] Provider credential management
|
||||
- [x] Notification dispatch
|
||||
- [x] Workspace CRUD
|
||||
|
||||
## Phase 3 Direction (Documented, Not Committed)
|
||||
|
||||
**agor-daemon:** A standalone background process that both Tauri and Electrobun connect to, eliminating per-backend reimplementation entirely. This is documented as the long-term direction but explicitly NOT committed to. The hybrid adapter approach is sufficient for the current two-backend scope.
|
||||
|
||||
**Turborepo threshold:** Adopt Turborepo when package count reaches 3. Currently at 2 (`@agor/types`, main app). The third package would likely be `@agor/stores` (migrated pure-state stores).
|
||||
|
||||
## Consequences
|
||||
|
||||
### Enables
|
||||
- Compile-time guarantee that both backends implement the same API surface
|
||||
- Incremental migration — bridge files can be replaced one at a time
|
||||
- Capability-gated UI degradation (features disabled on backends that lack support)
|
||||
- Testing with mock backends (`setBackendForTesting()`)
|
||||
- Future backend additions (GPUI, Dioxus) only need a new adapter class
|
||||
- Canonical SQL prevents schema drift between backends
|
||||
|
||||
### Costs
|
||||
- Two adapter implementations must be maintained in parallel
|
||||
- BackendAdapter interface grows as new IPC commands are added
|
||||
- Bridge files coexist with BackendAdapter during transition (dual access paths)
|
||||
- One-way migration (Tauri to Electrobun) requires version fencing to prevent data loss
|
||||
|
||||
## Risks
|
||||
|
||||
Identified by tribunal (Claude + Codex consensus) and three Codex audits:
|
||||
|
||||
### Semantic Drift
|
||||
**Risk:** Shared types enforce shape consistency but not behavioral consistency. Two adapters may handle edge cases differently (null vs undefined, error message format, timing).
|
||||
**Mitigation:** Integration tests per adapter. Type-narrowing at adapter boundary.
|
||||
|
||||
### Svelte Rune Coupling
|
||||
**Risk:** Stores using `$state`/`$derived` are tightly coupled to Svelte 5's rune execution model. Moving to `@agor/stores` package requires the consumer to also use Svelte 5.
|
||||
**Mitigation:** Only move stores that are pure state (no `$derived` chains that reference DOM). Keep reactive-heavy stores in app layer.
|
||||
|
||||
### SQLite Pragma Differences
|
||||
**Risk:** Tauri uses rusqlite (bundled SQLite, WAL mode, 5s busy_timeout). Electrobun uses better-sqlite3 (system SQLite, different default pragmas).
|
||||
**Mitigation:** Canonical SQL includes pragma requirements. Migration tool validates pragma state before copying data.
|
||||
|
||||
### Build Toolchain Cache Invalidation
|
||||
**Risk:** pnpm workspace changes can invalidate build caches unpredictably. `@agor/types` changes rebuild all consumers.
|
||||
**Mitigation:** Types package is stable (changes are additive). Turborepo deferred until package count warrants it.
|
||||
|
||||
### Version Fencing
|
||||
**Risk:** One-way migration (Tauri to Electrobun) means Electrobun DB is a snapshot. User switching back to Tauri loses Electrobun-only changes.
|
||||
**Mitigation:** `tools/migrate-db.ts` writes a version fence marker. Tauri startup checks for fence and warns if Electrobun has newer data.
|
||||
|
||||
### Plugin Bridge Orphaning
|
||||
**Risk:** Not all bridges map cleanly to BackendAdapter (btmsg, bttask, audit, plugins, anchors, remote). These "orphan bridges" may never migrate.
|
||||
**Mitigation:** Documented as acceptable. BackendAdapter covers the critical path (settings, groups, agents, PTY, files). Domain-specific bridges can remain as adapters that internally use BackendAdapter or direct IPC.
|
||||
Loading…
Add table
Add a link
Reference in a new issue