Document trash, collections, thumbnails, and the UI direction
Specs for the work that follows: soft delete via a MOVE that preserves the remote id, the collection tree and smart collections, the thumbnail store, and the derived-state folder. Adds two design documents. ui-refinement.md names the structural gaps between the v0.1 UI and something that feels like a photo editor. view-composition.md proposes a view controller for the display layer, against the 500-line run() that has become one by accretion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -269,6 +269,49 @@ UI; the core is unaware presentation varies.
|
||||
|
||||
Adding an operation therefore requires no UI change (FR-DEV-3c) unless it needs a new `WidgetKind`.
|
||||
|
||||
### 4.3a The presentation contract
|
||||
|
||||
The division of labour, stated once so neither side drifts:
|
||||
|
||||
> **The core declares capabilities and hints. The frontend composes.**
|
||||
|
||||
The core says what a parameter *is* (`ParamKind`), what an operation would
|
||||
*like* (`Presentation`), and what a widget inherently *demands*
|
||||
(`WidgetDemand`). It never says what is drawn, where it sits, how wide it is,
|
||||
or whether it is currently visible. Those are compositional decisions and they
|
||||
belong to whoever knows the window, the input modality and the platform —
|
||||
which is never the core.
|
||||
|
||||
**Hints are plural and ordered.** `Presentation.widgets` is a list of
|
||||
`WidgetKind` in descending preference. The frontend walks it and takes the
|
||||
first it both implements and can afford. Falling off the end is not an error:
|
||||
every parameter remains an individually addressable scalar, so plain sliders
|
||||
are always the final fallback and the edit still works — merely more tediously.
|
||||
That fallback is why curve points are scalars rather than an opaque blob.
|
||||
|
||||
**Demands describe the control, not the screen.** A hint may carry what the
|
||||
widget inherently needs — two-dimensional direct manipulation, precision
|
||||
pointing, a minimum useful number of simultaneous values. It must never carry
|
||||
pixels, breakpoints, DPI, or a platform name. `min_width: 240px` in a
|
||||
descriptor is the core making a layout decision, and a core that reasons about
|
||||
pixels will eventually be wrong about a display it never saw. The frontend maps
|
||||
demands onto its own thresholds; those thresholds live in `dr-ui` and may
|
||||
differ per platform without the core knowing.
|
||||
|
||||
**Presentation state is derived, never transmitted.** Whether a section is
|
||||
collapsed, whether a group contains a modified value, where a heading falls —
|
||||
all of it is computed frontend-side from capabilities plus current values. The
|
||||
core exposing a `group_modified` flag or a `starts_group` marker would be the
|
||||
core deciding the panel has groups at all, which is a composition decision. The
|
||||
frontend has the descriptors and the values; that is sufficient to derive any
|
||||
of it.
|
||||
|
||||
**The test.** A second frontend — a CLI, a test harness, a differently-shaped
|
||||
mobile UI — must be able to consume the same capability output and compose
|
||||
something entirely different, without the core changing. If a core change
|
||||
would be needed to lay something out differently, the boundary has been
|
||||
crossed.
|
||||
|
||||
---
|
||||
|
||||
## 5. GPU architecture
|
||||
@@ -444,10 +487,51 @@ mechanism rather than a last resort.
|
||||
| Version | UUID | everything |
|
||||
| Remote file | `oc:fileid` | server-side rename/move |
|
||||
| Cache entry | `(version, kind, resolution, graph_hash)` | — |
|
||||
| Person | UUID | rename, merge, re-index |
|
||||
|
||||
Content-hash identity is what makes FR-CAT-9's reconnection work: a moved file is recognised rather
|
||||
than re-imported, and a server-side move is not a re-download of 80 MB.
|
||||
|
||||
A person's identity is their UUID, never their name: renaming "Mum" to "Sarah" must not create a
|
||||
second person, and two devices that name the same face independently must be mergeable rather than
|
||||
duplicated (FR-CULL-12). Same reasoning as collections, same mechanism.
|
||||
|
||||
### 6.4 People and faces
|
||||
|
||||
Specified by FR-CULL-8 … FR-CULL-12 and NFR-SEC-5. Sketched here because the split across the trust
|
||||
boundary is an architectural decision, not a schema detail.
|
||||
|
||||
**Three entities.** A `face` is a detection: an image, a box, landmarks, a detector confidence, and
|
||||
an embedding. A `person` is a UUID and a name. `face_person` links them, carrying a calibrated
|
||||
probability and — critically — a **confirmed** flag separating what the user asserted from what the
|
||||
system guessed.
|
||||
|
||||
That flag is the whole design. Suggestions are derived data and may be recomputed at will; a
|
||||
confirmation is a user judgement and is never overwritten by a later inference pass. Conflating them
|
||||
would mean a model upgrade silently rewriting the user's own labelling, which is the kind of loss
|
||||
this architecture exists to prevent.
|
||||
|
||||
**Where each part lives, and why they differ:**
|
||||
|
||||
| Data | Home | Rebuildable | Rationale |
|
||||
|---|---|---|---|
|
||||
| Embeddings, boxes, landmarks | Catalog only | Yes — re-index | Expensive but reproducible. ARCH §6.12: derived data belongs in the disposable index. |
|
||||
| Cluster assignments, suggestions | Catalog only | Yes | Inference output; changes whenever the model or calibration does. |
|
||||
| Confirmed person name on an image | **Sidecar** | **No** | A human judgement, same class as a rating or keyword (FR-CAT-8). Must survive catalog deletion. |
|
||||
| Person entity (UUID, name) | Catalog, synced | No | The merge identity; travels with collections under FR-CAT-7's rules. |
|
||||
|
||||
The asymmetry is deliberate: deleting the catalog costs an afternoon of re-indexing and loses nothing
|
||||
the user typed. That is the same bargain §6.12 already makes everywhere else.
|
||||
|
||||
**Detection runs on proxies, not originals.** FR-CULL-8 pins this to the FR-CULL-2 preview ladder, so
|
||||
face indexing consumes the same artefacts the grid already built rather than forcing RAW decodes. The
|
||||
consequence for §5's GPU budget is that face inference competes with thumbnailing, not with
|
||||
rendering, and NFR-ARCH-2's priority classes already express that.
|
||||
|
||||
**Embeddings never enter the diagnostics or crash paths** (NFR-SEC-5). This is a structural
|
||||
exclusion, not a redaction rule: NFR-OPS-1's bundle is assembled from an allowlist, so a new table
|
||||
does not silently become uploadable by existing.
|
||||
|
||||
---
|
||||
|
||||
## 7. Concurrency
|
||||
@@ -1000,6 +1084,7 @@ Full rationale in [requirements.md §8](requirements.md). Summary:
|
||||
| D10 | Single adaptive interface | Decided |
|
||||
| D11 | Product positioning | Decided |
|
||||
| D12 | Scope versus pace | **Open** |
|
||||
| D13 | Face inference runtime and model licensing | **Open** |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user