Skip to content

feat: condition chip sync (two-way merge, opt-in)#43

Merged
cortexuvula merged 13 commits into
masterfrom
feat/condition-chip-sync
Jul 3, 2026
Merged

feat: condition chip sync (two-way merge, opt-in)#43
cortexuvula merged 13 commits into
masterfrom
feat/condition-chip-sync

Conversation

@cortexuvula

Copy link
Copy Markdown
Owner

Summary

Adds an opt-in setting that synchronizes "known condition" chip presets between the office server and remote clients via two-way merge with per-item last-write-wins and tombstones. Default off — each machine keeps its own list unless the user opts in.

Design

Spec: docs/superpowers/specs/2026-07-03-condition-chip-sync-design.md
Plan: docs/superpowers/plans/2026-07-03-condition-chip-sync.md

What changed

Backend (Rust)

  • New ConditionChip type (crates/core) — struct with deterministic UUID v5 ID from normalized text (case/whitespace-insensitive)
  • New condition_chips table (migration m010) — id, text, updated_at, deleted_at (tombstones)
  • New ConditionChipsRepo (crates/db) — CRUD + the core merge_incoming LWW function (9 tests covering all merge scenarios: remote-newer, local-newer, tombstone-wins, re-add-after-tombstone, tie-break, idempotency, pruning)
  • New server API (sharing_vocab_api.rs) — GET /v1/condition-chips + POST /v1/condition-chips/sync on the existing vocab_port
  • New ConditionsRemote HTTP client — mirrors templates_remote, gates on pairing + vocab port
  • 4 new Tauri commands — list/add/remove/sync with dispatch (local DB vs server based on setting + pairing)
  • New sync_condition_chips setting — defaults false, opt-in

Frontend (Svelte 5)

  • Rewired ConditionChips.svelte — loads from Tauri commands instead of settings blob, graceful fallback to defaults
  • New toggle in Sharing settings — "Sync known condition chips with the server"
  • 9 component tests — verifies load, add, remove, graceful degradation

Side improvement

  • Fixed vitest config to enable Svelte 5 component rendering (was a known gap — existing component tests noted "if a jsdom + Svelte transformer is added, replace with full render tests")

How it works

  1. Off by default: Each machine keeps its own chip list (current behavior)
  2. Opt-in: User toggles "Sync known condition chips" in Settings → Sharing
  3. Push on edit: Adding/removing a chip writes locally first (instant UI), then pushes to server in background
  4. Pull on connect: On app launch, pulls server list and merges
  5. Two-way merge: Per-item LWW — same condition on two machines converges to one row. Tombstones prevent ghost reappearance. Re-adding a tombstoned condition works (newer timestamp resurrects)
  6. Graceful degradation: Sync failures never block the UI — local state is always correct

Test results

  • cargo test -p medical-core --lib condition_chip — 5 pass
  • cargo test -p medical-db --lib condition_chips — 9 pass
  • cargo test -p medical-db --lib migrations — 21 pass
  • cargo clippy --workspace — clean
  • npm run check — 0 errors, 0 warnings
  • npx vitest run — 416 tests pass (full suite)

Commits (11 tasks, TDD)

Each commit is a self-contained task with its own tests, following the subagent-driven development workflow with spec + quality review per task.

Two-way merge with per-item LWW + tombstones. Opt-in setting.
Approved across all design sections (data model, merge algorithm,
API layer, frontend integration, error handling, testing).
Add render-level Vitest tests for ConditionChips.svelte covering:
- defaults render while the backend list loads
- custom chips load from listConditionChips on mount
- add flow calls addConditionChip with trimmed text (incl. dedup/empty guards)
- remove flow calls removeConditionChip and reflects the returned list
- graceful degradation: defaults survive list/add/remove failures

This is the first true component-render test in the repo. Enabling it
required two vitest.config.ts changes (documented inline):
- resolve.conditions: ['browser'] so bare  imports resolve to the
  client build (has mount()), not the server build
- environmentOptions.jsdom.consumer = 'client' so vite-plugin-svelte emits
  client components for jsdom tests

The test file opts into jsdom via a file pragma so the default 'node'
environment used by all other tests is unaffected. Full suite (48 files,
416 tests) still passes.

Adds @testing-library/svelte as a dev dependency.
@cortexuvula cortexuvula merged commit 973bc42 into master Jul 3, 2026
5 of 6 checks passed
@cortexuvula cortexuvula deleted the feat/condition-chip-sync branch July 3, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant