docs(confidence-engine): define v0.60 investigation storage contract

This commit is contained in:
2026-09-03 17:35:55 +01:00
parent 2df026d024
commit 06a200bb03
+66
View File
@@ -178,6 +178,72 @@ Reconstruct CU when canonical meaning or eligible evidence set changes — NOT w
- The `≤5` processing bound observed during development was an experimental apparatus constraint, NOT a product requirement. Six Open Questions surfacing is legitimate product output, not a formulation defect.
- Evidence discipline: what proves useful in live experimentation must be captured at provenance level, not as test diary entries that become operational constraints.
## v0.60 — Multi-Investigation Storage Contract Decision
Completed on branch `feature/multi-investigation-storage-v0.60`. Bounded architecture/contract decision task following v0.60 audit. Zero production changes. Documentation-only decision checkpoint.
### 1. Contract ownership
**Decision:** `lib/storage/investigation-storage.js` is the application-facing persistence boundary. It defines the contract whose semantics (not just signatures) are immutable across provider implementations. Consumers import only from this module.
`lib/storage/providers/local-storage.js` remains one concrete provider implementation behind the contract, not an application import target.
**Invariant:** No consumer imports `providers/local-storage` directly.
### 2. Durable Investigation identity
**Decision:** Canonical Investigation carries a durable `id` field.
| Property | Value |
|---|---|
| ID allocation owner | Application (not storage contract) |
| Allocation timing | On create new, before any persistence call |
| Mutable after creation | NO |
| Route `[id]` represents same identity | YES — direct round-trip: app sets → route reads → storage uses |
### 3. Minimum contract operations
Five semantic operations. No speculative additions.
| # | Operation | Input | Output | Product use |
|---|---|---|---|---|
| 1 | `listInvestigations()` | — | `InvestigationSummary[]` (lightweight) | Portfolio renders index/list |
| 2 | `loadInvestigation(id)` | durable ID string | `Investigation \| null` | Investigation/Report page hydration |
| 3 | `createEmptyInvestigation()` | — | `{ id: string }` | "+ Create new investigation" |
| 4 | `saveInvestigation(id, investigation)` | ID + full snapshot | void | Autosave, Report generation, all writes |
| 5 | `restartInvestigation(id)` | durable Investigation ID | void (reasoning state cleared) | "Restart this investigation" |
**Explicitly rejected:** search, pagination, sorting, sync, merge, transactions, history, report versions, sharing, permissions, accounts. No existing product behaviour requires them.
### 4. Portfolio listing returns lightweight metadata
`listInvestigations()` returns summaries, not full snapshots. Minimum information:
- `id` — navigation target
- `scenario` (or title framing) — card text
- `updatedAt` — freshness display
- `investigationRevision` — revision metadata
- Report existence and `generatedFromRevision` — "Current" / "Update available" indicator
Full Investigation loads separately via `loadInvestigation(id)` on navigation.
### 5. Restart = reset reasoning state, NOT remove
Restart clears reasoning state (findings, questions, report) within the Investigation but preserves the Investigation's durable identity and container. The Investigation remains visible in Portfolio listing as a named item with cleared state.
A separate "Delete investigation" UI is not required by current MVP. Contract-level `removeInvestigation(id)` is acceptable for future use but has no product owner yet.
### 6. Create new investigation flow
User clicks "+ Create new investigation" → app allocates durable ID (crypto.randomUUID or equivalent, library choice deferred) → persist an empty Investigation under that ID immediately → navigate to `/investigations/{id}` → existing Investigations untouched. Empty Investigation is persisted on creation so it appears in Portfolio; user can return later or abandon with container remaining visible.
### 7. localStorage ≠ contract
The storage contract accepts/returns domain-level Investigation objects keyed by `id`. How each provider maps those to its storage mechanism is implementation detail. Contract does not dictate key scheme, row schema, or collection structure.
### 8. Synchronization separate
Storage contract = persistence only. Not synchronization. No sync-specific fields (syncStatus, remoteId, dirtyFlags, lastSyncedAt) belong in the Investigation shape during this increment. Decisions here do not prevent future sync — the Investigation object carries its own durable ID sufficient for identity resolution.
## Next restart point
Consult `docs/design-evolution/README.md` for progressive loading of product reasoning and provenance chronology; load the relevant chapter only when a specific historical question requires it.