From bdc89f914eb43e44120076acd3a4d6def5bb4131 Mon Sep 17 00:00:00 2001 From: Danny Rorabaugh Date: Fri, 16 Oct 2026 14:17:51 -0400 Subject: [PATCH 1/5] Route getDraft and saveDraft through an async repository (#431) AnalysisRepository is the seam a later storage backend replaces: async calls taking and returning only JSON-plain values, with payload reads named per kind (getTokenAnalyses, getPhraseAnalyses, getSegmentAnalyses) and exportAll/replaceAll for callers that still exchange the whole draft. DraftRepository implements it in memory over today's draft envelope and per-book shards, keeping projectStorage's guards: only changed shards are rewritten, the shard journal recovers interrupted saves, and a draft written by a newer build is neither read nor overwritten. It reaches storage only through a KeyValueStorage and imports nothing from PAPI. getDraft and saveDraft keep their contracts and storage calls. The perf harness seeds each tier's draft and saved projects from Node, writing the app's storage files through the repository, so seeding no longer depends on saveDraft or saveAnalysis carrying a whole analysis. perf:shape reads stored drafts through it too. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 + e2e-tests/global-setup-perf.ts | 7 +- e2e-tests/perf-app.ts | 7 +- e2e-tests/tests/perf/app-perf.spec.ts | 33 +- perf/README.md | 1 + perf/paths.ts | 6 + perf/shape/cli.ts | 58 +- perf/storage.ts | 96 +++ .../services/draftRepository.test.ts | 191 ++++++ src/services/draftRepository.ts | 564 ++++++++++++++++++ src/services/projectStorage.ts | 481 ++------------- src/types/analysis-repository.ts | 55 ++ src/types/type-guards.ts | 5 + 13 files changed, 995 insertions(+), 511 deletions(-) create mode 100644 perf/storage.ts create mode 100644 src/__tests__/services/draftRepository.test.ts create mode 100644 src/services/draftRepository.ts create mode 100644 src/types/analysis-repository.ts diff --git a/AGENTS.md b/AGENTS.md index 7d2cc6550..090f080f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -77,6 +77,8 @@ The WebView root component is assigned to `globalThis.webViewComponent` (not exp [src/services/projectStorage.ts](src/services/projectStorage.ts) — owns all `papi.storage` reads and writes for interlinearizer projects. Two serialization queues prevent interleaved read-modify-write races. Tests must call `resetQueuesForTesting()` between tests because module state is not cleared by `resetMocks`. +Drafts are read and written through [AnalysisRepository](src/types/analysis-repository.ts), the seam a later storage backend replaces. [DraftRepository](src/services/draftRepository.ts) implements it in memory over the draft envelope and its per-book shards. It imports nothing from PAPI and reaches storage only through a `KeyValueStorage`, so the perf harness runs it in Node straight over the storage files ([perf/storage.ts](perf/storage.ts)). + ### Components Prefer Platform.Bible's `platform-bible-react` components (`Button`, `Input`, `Textarea`, `Label`, `Switch`, `RadioGroup`, `Popover`, `Tooltip`, etc.) over hand-rolled raw HTML (`