diff --git a/docs/architecture.md b/docs/architecture.md index 2c5e4f2..279c110 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1099,6 +1099,13 @@ architecture; everything else assumes they pass. Decisions treated as fixed because reversing them is expensive. Each is evidence-backed. +> **On the numbering.** The subsections below are numbered **6.1–6.13**, not 12.x. They were §6 +> when this document was first written, and every `ARCH §6.n` citation in `requirements.md`, in +> `docs/*.md` and in source comments names them by those numbers. Renumbering would break several +> hundred citations for no gain, so the numbers stay: `ARCH §6.1` means the first constraint here, +> and never §6.1 of the data architecture above, which is cited as *§6 Data architecture* or by +> its title. + ### 6.1 GPU results never round-trip through the CPU darktable identifies this as their single biggest bottleneck: OpenCL output returns to the GTK diff --git a/docs/requirements.md b/docs/requirements.md index 6eca050..500fe8a 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -77,7 +77,7 @@ R1 is therefore stated as a bounded tolerance — a defined maximum per-pixel de ΔE2000 for colour or ULPs at the working precision. **The threshold must be fixed before spike S9**, because S9 both validates R1 and calibrates what the achievable tolerance actually is. -Where genuine bit-identity is required — cache keys, edit-graph hashing (§5.2 invariant 3) — it +Where genuine bit-identity is required — cache keys, edit-graph hashing (ARCH §3.4, ARCH §6.13) — it applies to *integer* operations on CPU-side state, which are deterministic, never to GPU float results. @@ -202,7 +202,7 @@ in the catalog when it was trashed and the path it came from; restore moves it b Permanent delete removes the file first and the catalog row second, and a delete of something already gone counts as success. -A flag alone would not survive invariant 5.2.4: the catalog is rebuildable from sources, so a +A flag alone would not survive ARCH §6.12 (the catalog is a rebuildable index): the catalog is rebuildable from sources, so a rescan would find every "deleted" file still in the library and re-index it. The folder is the durable fact and the row is the convenience — which also means the scanner shall exclude the trash folder, and that a user can recover by hand without DarkRoom. Derived data keyed on the file @@ -310,7 +310,7 @@ pub trait Operation: Send + Sync { /// Parameter values → GPU work. No UI types cross this boundary. fn encode(&self, enc: &mut ComputeEncoder, ctx: &TileContext); - /// Identity for cache invalidation (see §5.2 invariant 3). + /// Identity for cache invalidation (see ARCH §3.4, ARCH §6.13). fn params_hash(&self) -> u64; } @@ -345,7 +345,7 @@ pub enum WidgetKind { ``` **The pipeline crate shall not depend on the UI toolkit.** Descriptors carry data, never widgets. -This keeps the edit chain testable headless (see §9's golden-image tests, which must link no UI) +This keeps the edit chain testable headless (see §8's golden-image tests, which must link no UI) and is what allows one operation to render differently on touch and desktop. **FR-DEV-3b — Frontend presentation mapping.** The frontend maps `ParamKind` to a concrete control @@ -413,8 +413,9 @@ within 0.06 in linear sRGB; the baked lookup's interpolation error stays under o value; and the shader agrees with the CPU model, which agrees in turn with an independent reference implementation. -**Open:** how the chosen stock persists. Sidecar parameters are `f32` and the stock list is -data-driven, so neither an index nor a name fits the existing shape. +*Resolved 2026-09-19:* the chosen stock persists **by id** in its own sidecar field, not as a +parameter — `core/dr-pipeline/src/sidecar.rs` records why an index was rejected (installing a +profile would silently change which film every existing photograph was developed on). **FR-DEV-3g — AI denoise.** Learned denoising operating in the raw domain, ideally jointly with demosaic. @@ -1155,7 +1156,7 @@ mandatory. - **Evidence beside the frame** (added 2026-09-19) — FR-CULL-13's signals, readable at a glance without leaving the mode or opening the frame - **The last import as a scope** (added 2026-09-19) — the set a culling session most often starts - from, reachable in one step and counted, expressed as a term of the §5 selector language rather + from, reachable in one step and counted, expressed as a term of the selector language (ARCH §9.2) rather than as a special collection **FR-CULL-5 — Burst and near-duplicate grouping.** Group frames by capture-time proximity and image @@ -1177,7 +1178,7 @@ mobile. Gesture and rating targets must not overlap. **FR-CULL-13 — Evidence, never verdicts.** Added 2026-09-19; numbered after the people clauses because it governs them too. Everything the app computes about a frame in aid of culling is -**evidence**: shown beside the frame, filterable and sortable through the §5 selector language, +**evidence**: shown beside the frame, filterable and sortable through the selector language (ARCH §9.2), and — within a burst — permitted to *propose* which frame represents the group. The signals are the raw histogram, clipping and focus (FR-CULL-3), burst membership (FR-CULL-5), and per-face eye state and head pose (FR-CULL-8a). The list grows by adding to it, never by adding a second kind of @@ -1291,7 +1292,7 @@ as derived data under FR-CULL-12: matters, groups and children and events, a turned head is the decision and averted eyes are often the better frame. -Both are terms in the §5 selector language (FR-CULL-11) — "everyone's eyes open", "facing the +Both are terms in the selector language (ARCH §9.2, FR-CULL-11) — "everyone's eyes open", "facing the camera" — composable with a person and with every other term. Both feed FR-CULL-13's evidence and may propose a burst representative (FR-CULL-5); neither may set a rating or a flag. @@ -1347,7 +1348,7 @@ Confirmation is explicit. A face is either **suggested** (the system's inference (the user's judgement), and the two are never conflated in storage or in display. Suggestions may be recomputed freely; confirmations are user data and are never overwritten by a later inference pass. -**FR-CULL-11 — People as a selector term.** A person shall be a term in the §5 selector language, +**FR-CULL-11 — People as a selector term.** A person shall be a term in the selector language (ARCH §9.2), composable with every other term. This is the requirement that pays for the subsystem, and it is nearly free once FR-CULL-10 exists: @@ -1704,7 +1705,7 @@ the class where it was expressed. Everything the photographer produced or navigated to is a different matter, and none of it may be touched by a resize. That is the list in the criterion, and it is the testable half. -**Performance regressions fail the build.** §9's benchmark suite runs per-commit; a regression +**Performance regressions fail the build.** §8's benchmark suite runs per-commit; a regression beyond a stated tolerance is a build failure, not a notification. Performance work rots otherwise. ### 4.2 Reliability @@ -1729,7 +1730,7 @@ ARCH §6.6 already anticipates one migration (folder ETags); there will be other exist before the first one. **NFR-R6 — Corruption recovery.** On failing an integrity check at startup, the app offers restore -from the NFR-R2 backup, and failing that, rebuild from sources plus sidecars per invariant 5.2.4. +from the NFR-R2 backup, and failing that, rebuild from sources plus sidecars per ARCH §6.12. FR-CAT-8 is what makes that second path real for local-only users. **NFR-R7 — GPU device loss.** The GPU layer treats device loss as an expected event (ARCH §6.10): detect @@ -1953,7 +1954,7 @@ more in a colour-grading application than in most software. Entity definitions, invariants, and all architectural constraints are specified in [architecture.md](architecture.md) — §3 (core abstractions), §6 (data architecture), and -§11 (architectural constraints). +§12 (architectural constraints — whose subsections keep their original 6.x numbers, so `ARCH §6.1` in this document means §12's first constraint, not §6.1 of the data architecture). Requirements in this document that depend on an architectural guarantee cite it inline. The constraints most load-bearing for testability are: @@ -1970,7 +1971,7 @@ constraints most load-bearing for testability are: ## 6. Decisions Rationale, evidence, and the eliminated alternatives are recorded in -[architecture.md §12](architecture.md). Outcomes only: +[architecture.md §13](architecture.md). Outcomes only: | # | Decision | Outcome | |---|---|---| @@ -2173,12 +2174,12 @@ collides with four things this document says. aligned by the similarity the face subsystem already fits between two landmark sets and blended by the membrane heal already shipped. It reopens `spot-removal.md`'s non-goal that the source is "a patch from the same photograph", which would be revised deliberately, not quietly. -2. **§5.1, single-source `Image`.** The real one. §7 defers panorama, HDR and focus stacking on the +2. **ARCH §6.3, single-source `Image`.** The real one. §7 defers panorama, HDR and focus stacking on the grounds that the schema cannot express an image derived from several sources. This is that case in a milder form — the output is still frame A, but A's sidecar now names B — and it brings the rules the tiers already have: B's original must be present to render A (FR-NC-6c: visible and priced before starting), trashing B must know A depends on it (FR-CAT-15), and `Version::merge` - has never seen a cross-reference. Reopening §5.1 for this reopens it for the three deferred + has never seen a cross-reference. Reopening ARCH §6.3 for this reopens it for the three deferred rows at once, which is the argument for doing it once and properly rather than for this alone. 3. **Tone.** The source patch goes through A's chain, not B's — B demosaiced and run through A's parameters to the head of the detail chain, then sampled. A second small pipeline at proxy @@ -2233,7 +2234,7 @@ note where deferring now constrains the design later. | Deferred | Note | |---|---| | Tethered shooting | — | -| Panorama and HDR merge | **Keep the schema open** — these produce images derived from multiple sources, which §5.1's single-source `Image` cannot express. | +| Panorama and HDR merge | **Keep the schema open** — these produce images derived from multiple sources, which ARCH §6.3's single-source `Image` cannot express. | | Focus stacking | Same provenance consideration. | | Cross-frame face repair ("best take") | A face from a neighbouring frame of the same burst, aligned by its landmarks and blended by FR-DEV-8's heal. Mechanically a spot whose source is another photograph; **the same multi-source schema question as the two rows above, arriving early** — D17. Deferred rather than refused, with its non-goals fixed now: never automatic, geometry not corrected, source frame declared in sidecar, history and export. | | Gaze and eye-contact estimation | Every open gaze model read on 2026-09-19 is trained on Gaze360, MPIIGaze or ETH-XGaze, all research-only, and Gaze360's licence restricts *models trained on it* by name — the InsightFace situation again (D13). Head pose from the five landmarks is the proxy (FR-CULL-8a). Revisit when weights with a clean data chain exist; iris offset within the eye crop is the licence-free fallback if the proxy proves too weak. | @@ -2271,7 +2272,7 @@ note where deferring now constrains the design later. | Cancellation (NFR-ARCH-3) | Assert every long-running operation observes cancellation within the stated bound, including in-flight GPU work. | | Layer separation (ARCH §6.5a) | CI dependency-tree assertion: no `core/*` crate may transitively depend on a UI toolkit. | | Operation self-description (FR-DEV-3c) | A test operation added to the registry appears in a generated panel with no frontend change. | -| Adaptive layout (§3.5) | Snapshot tests at each breakpoint, and a resize test asserting no state loss across a layout-class transition. | +| Adaptive layout (§3.5) | Snapshot tests at each breakpoint, and a resize test asserting no loss of *photographic* state across a layout-class transition — NFR-P11's list, with panel disclosure exempt as that clause says. | | Touch targets (FR-UI-3) | Automated check that interactive elements meet the 44pt minimum in touch modality. | | Export sizing (FR-EXP-3) | Per-mode dimension assertions, including aspect preservation, fill-crop centring, and the upscale-disabled fallback. | | Identity calibration (FR-CULL-9) | Reliability diagram over a hand-labelled corpus: stated probability against observed match rate, asserted within tolerance across the range — not a single accuracy figure, which would hide exactly the miscalibration this tests for. Plus a static assertion that no comparison thresholds a raw similarity. | @@ -2321,7 +2322,7 @@ this revision it was unstated. this app category before designing around it is far cheaper than discovering it at submission. **S9 moved to Tier 1** because it does not merely test R1 — it *calibrates* it. R1's tolerance -threshold cannot be fixed sensibly without knowing the real cross-vendor deviation, and the §9 +threshold cannot be fixed sensibly without knowing the real cross-vendor deviation, and the §8 golden-image strategy depends on that number. Test S1 on Mesa/AMD, Intel, and NVIDIA proprietary drivers, under both X11 and Wayland. FD-based