Bring the outstanding register up to 0.16.0
Five things in it were no longer true of the tree: - FR-DSP-4 said "Unbuilt" and that nothing tracked a provisional frame. 0.15.0 finished it: the settle debounce in ui/dr-ui/src/refine.rs, the draft flag reaching the histogram (canvas-draft, Levels.provisional), and the 150 ms fade of the last draft (app.slint's canvas-previous). - The note that dedup.rs is re-import detection stood alone. FR-CAT-11a is now built beside it: dr_catalog::duplicates, dr_ui::duplicates and the Duplicate originals review. - Culling counted three unbuilt clauses and named two. - Section 6 still counted zero @tr( and five accessible-* lines, figures from before 2026-08-30. The launch screen is converted (build.rs holds the mechanism, no .po exists), 127 accessible-* lines sit across eleven files, and ui_controls_are_accessible.rs holds the structure. - Section 11 said nothing of the panorama was built. It was, the same week; FR-MRG-9, NFR-MRG-1 and NFR-MRG-2 are what carry no tag. A new section 4a lists what the develop, mask and keyboard work left open, so that its closed clauses are not looked for: FR-UI-5's wheel on sliders, FR-RAW-2's second decoder, mask-editing M2's remainder, and FR-DEV-17's deliberate blind spot for range and region parts. The Android paragraph now says develop is zero-copy there since TD-1 was paid off, and that the APK carries the manual.
This commit is contained in:
+93
-33
@@ -28,6 +28,12 @@ Android memory pressure and lost-root recovery (FR-PLAT-AND-5, FR-PLAT-AND-2), i
|
||||
recorded where it appears rather than deleted, because a requirement that is *half* met is the
|
||||
one most likely to be reported as closed.
|
||||
|
||||
**Swept again on 2026-09-26, for 0.16.0.** Progressive refinement (FR-DSP-4) and the panorama
|
||||
(§3.11) were built and are struck below; consolidating duplicate originals (FR-CAT-11a) now sits
|
||||
beside re-import detection; the accessibility and localisation counts in §6 had not been read
|
||||
against the tree since 2026-08-30 and are replaced; and §4a records what the develop and keyboard
|
||||
work of 0.15.0 and 0.16.0 left open.
|
||||
|
||||
---
|
||||
|
||||
## 1. Plugins — post-v1 since 2026-09-19
|
||||
@@ -80,8 +86,8 @@ somebody reads the matrix.
|
||||
|
||||
## 2. Culling — the stated differentiator, half built
|
||||
|
||||
[D11](requirements.md) names culling "the core differentiator". FR-CULL-1, -2, -3, -4 and -8 through
|
||||
-12 are built. Three are not.
|
||||
[D11](requirements.md) names culling "the core differentiator". FR-CULL-1 through -5 and -8 through
|
||||
-13 are built. Two are not.
|
||||
|
||||
**FR-CULL-3 — Raw-truth overlays. Built, all three bullets.** Focus peaking is
|
||||
`core/dr-gpu/src/focus.rs` and `ui/dr-ui/src/peaking.rs`; the raw histogram and the raw clipping
|
||||
@@ -115,8 +121,13 @@ labels — that comment was a forward reference and is now simply wrong, rather
|
||||
And `dr_catalog::bursts::choose_representative` is written and tested but bound to no gesture, so
|
||||
today the only override is expanding the burst.
|
||||
|
||||
`core/dr-catalog/src/dedup.rs` remains a different thing: re-import detection under FR-CAT-11,
|
||||
matching a file against one already catalogued, not two photographs against each other.
|
||||
Neither is deduplication, which is about one file held twice rather than two frames that look
|
||||
alike. `core/dr-catalog/src/dedup.rs` is re-import detection under FR-CAT-11, matching a file on
|
||||
a card against one already catalogued. Its other half, FR-CAT-11a, is built since 0.16.0:
|
||||
`core/dr-catalog/src/duplicates.rs` groups the copies a library already holds (same root, camera,
|
||||
capture instant and size), `ui/dr-ui/src/duplicates.rs` proves each group the same by digest and
|
||||
compares their edits, and a group is folded onto one survivor with the others trashed in one
|
||||
transaction, from the Duplicate originals review in the sidebar and in Settings.
|
||||
|
||||
**FR-CULL-6 — Compare and survey.** Absent. No side-by-side view, no synchronised zoom or pan.
|
||||
This is the one of the four with no adjacent machinery at all, and it is also the one that most
|
||||
@@ -166,10 +177,15 @@ Two measurements say it costs more than it saves on the interactive path. Neithe
|
||||
about the export path or about a device under memory pressure, which is where the case for it
|
||||
actually lives — and that is spike S6, which has not run.
|
||||
|
||||
**FR-DSP-4 — Progressive refinement.** Unbuilt. FR-DSP-1's proxy rendering and TD-4's
|
||||
quarter-resolution base are adjacent and are not it: both are fixed choices about what resolution to
|
||||
compute at, where FR-DSP-4 asks for a first frame that is deliberately cheap and a second that
|
||||
replaces it. Nothing tracks a "this frame is provisional" state.
|
||||
**FR-DSP-4 — Progressive refinement. Built in 0.15.0.** While a gesture moves the canvas renders
|
||||
a half-resolution draft, and the sharp frame lands once, 120 ms after the last movement: the
|
||||
decision is `ui/dr-ui/src/refine.rs`, a debounce whose every draft re-arms the settle timer, driven
|
||||
through simulated timelines in its tests. The draft flag reaches the interface (`canvas-draft`,
|
||||
`Levels.provisional`), so the histogram dims while it describes a frame older than the one on
|
||||
screen, and the last draft is kept and faded out over 150 ms when the sharp frame arrives, so
|
||||
refinement is not a swap. Draft frames themselves date from 2026-08-09; what this entry missed,
|
||||
and 0.15.0 finished, was a settle that waited for the gesture to stop, a provisional state the
|
||||
interface could see, and a refinement that was not a jarring swap.
|
||||
|
||||
**NFR-RES-2 — Images larger than GPU memory.** Half answered. NFR-R8's "decide explicitly" was
|
||||
decided on 2026-09-19: there is no CPU render pipeline, the degraded mode is the viewer on
|
||||
@@ -181,11 +197,42 @@ settle both this and FR-DSP-2, and there is no evidence it has run.
|
||||
|
||||
---
|
||||
|
||||
## 4a. Develop, masks and the keyboard — what the 0.15.0 and 0.16.0 work left open
|
||||
|
||||
Most of what these two releases built closed a clause outright, and is listed here only so that
|
||||
nobody looks for it below: perspective correction (FR-DEV-20, Vertical and Horizontal in Compose),
|
||||
the crop that says when it orphans a mask (FR-DEV-17), intersection as a third mask join
|
||||
(FR-DEV-19a), the keyboard vocabulary for develop (FR-DEV-16, met and held by `gestures-check` in
|
||||
both directions), colour labels set, shown and filtered (NFR-A11Y-3's first example), the RAW
|
||||
decoder behind a trait (FR-RAW-2), and duplicate originals (FR-CAT-11a, §2 above). What they left:
|
||||
|
||||
- **FR-UI-5's pointer half.** Keys cover navigation, rating and common adjustments in every view,
|
||||
and judging works in develop on the open photograph; but no develop slider takes the scroll
|
||||
wheel, which the clause names. Its status note in the register says so rather than rounding up.
|
||||
- **FR-RAW-2's second decoder.** The trait is built and a stub decoder is proved to reach the
|
||||
scan, the preview ladder and export without a caller changing; LibRaw itself (D2) is not
|
||||
built, and S7 is what would say when it is needed.
|
||||
- **FR-DEV-19's M2 remainder** ([mask-editing.md §11](mask-editing.md)). The panel's Add, Subtract
|
||||
and Intersect buttons join a painted part only, so an intersection with a gradient or a range is
|
||||
painted where the mask should survive; per-part distance fields and folding two layers are
|
||||
unbuilt. From M1, the brush has no ring drawn on the photograph and a layer's whole stroke
|
||||
history is redrawn per dab.
|
||||
- **FR-DEV-17's blind spot, by design.** A layer that adds a range or a region selection is never
|
||||
reported, because the check has no label map to measure it with (`dr_pipeline::orphan`); a
|
||||
false alarm on the common path would teach the notice to be dismissed unread.
|
||||
|
||||
The desktop's scrollbars (the develop column, the grid, the sidebar, Settings, the film list and
|
||||
the help sheet) are drawn only where `dr_plat::is_touch_first()` is false; on Android the lists
|
||||
still scroll by flick alone, which is deliberate rather than outstanding.
|
||||
|
||||
---
|
||||
|
||||
## 5. Android beyond running, and Flatpak
|
||||
|
||||
The Android app is not a stub — it builds an APK, runs the whole application, unpacks bundled face
|
||||
models, and has been measured on a tablet ([faces.md §12.1](faces.md),
|
||||
[technical-debt.md TD-1](technical-debt.md)). What is missing is the platform contract around it.
|
||||
models, has been measured on a tablet ([faces.md §12.1](faces.md)), and since 0.15.0 draws the
|
||||
develop view zero-copy as the desktop does ([technical-debt.md TD-1](technical-debt.md), paid off).
|
||||
It carries the manual and opens it in a WebView. What is missing is the platform contract around it.
|
||||
|
||||
**FR-PLAT-AND-1 is untagged, and what it was tagged for was intent rather than code.**
|
||||
The requirement demands that library access be obtained *exclusively* through the Storage Access
|
||||
@@ -267,21 +314,29 @@ fixes users will need — is unaddressed, and there is no update mechanism of an
|
||||
|
||||
## 6. Accessibility and internationalisation — the hard half is done and the easy half is not
|
||||
|
||||
**NFR-A11Y-1 — Localisation.** `@tr(` appears **zero** times across 14,482 lines of Slint. That
|
||||
number overstates the problem, because the part that is genuinely architectural was got right:
|
||||
`LocalizedKey` keeps display strings out of `core/` entirely, every operation publishes a key rather
|
||||
than a label, and `labels::resolve` is the single point where a key becomes text. What that single
|
||||
point does, however, is a hardcoded English `match` in Rust source — so changing a translation
|
||||
requires a recompile, which is the one thing the requirement explicitly forbids. There is no message
|
||||
catalogue in any format, no locale-resolution rule, and no decision recorded about RTL.
|
||||
**NFR-A11Y-1 — Localisation.** One screen of twenty-eight Slint files is converted: the launch
|
||||
screen wraps its strings in `@tr(`, and `ui/dr-ui/build.rs` records the mechanism — Slint's bundled
|
||||
translations, a `.po` per language under `ui/dr-ui/lang/`, extracted with `slint-tr-extractor` —
|
||||
and why bundling rather than gettext (Android has no path a `.mo` could sit at). No `.po` exists
|
||||
yet, so every build is the original English, and the rest of the interface (about 23,600 lines of
|
||||
markup) is unwrapped. The part that is genuinely architectural was got right: `LocalizedKey` keeps
|
||||
display strings out of `core/` entirely, every operation publishes a key rather than a label, and
|
||||
`labels.rs` is the single point where a key becomes text — but that point is a hardcoded English
|
||||
`match`, and `build.rs` says the Rust-side mechanism is not built. Two things the requirement asks
|
||||
remain against it even when the conversion is finished: a bundled translation is compiled in, so
|
||||
changing one still needs a rebuild, which the clause forbids; and there is no locale-resolution rule
|
||||
and no decision recorded about RTL.
|
||||
|
||||
The work left is therefore smaller than it looks and entirely mechanical: a catalogue format, a load
|
||||
path behind `resolve`, and `@tr(` around the Slint literals. The design it needs already exists.
|
||||
|
||||
**NFR-A11Y-2 — Accessibility.** `accessible-*` appears five times in the whole interface, all five
|
||||
on one control — the parameter slider in `adjust.slint` — and nothing is set from the Rust side at
|
||||
all. Everything else in eighteen Slint files is unnamed to AT-SPI and TalkBack. The requirement's own
|
||||
caveat, that Slint's Android accessibility needs verifying, is spike S13, which has not run.
|
||||
**NFR-A11Y-2 — Accessibility. Tagged, and half tested.** `accessible-*` properties now appear on
|
||||
some 127 lines across eleven Slint files — the shared controls in `widgets.slint` and
|
||||
`controls.slint`, every slider, the rail, the grid's cells (named by file), the rating stars, the
|
||||
labels and the duplicates review — and `ui/dr-ui/tests/ui_controls_are_accessible.rs` fails when a
|
||||
shared control stops declaring its role or a slider is added without a name. The manual's recording
|
||||
scripts find every control they press through the same names (`dr_ui::automation`), so a control a
|
||||
screen reader cannot name is also one the manual cannot record. What is unchecked is stated in the
|
||||
test: whether the words are good, and whether Android exposes any of it — spike S13, which has not
|
||||
run. The requirement's other two clauses are debt with entries of their own: platform font scaling
|
||||
([TD-7](technical-debt.md)) and WCAG AA contrast ([TD-6](technical-debt.md)).
|
||||
|
||||
**NFR-A11Y-3 — Colour-independent status.** Built, and now asserted. The clipping readout pairs a
|
||||
marker that appears or disappears with a figure in words; the rating strip is a solid star against
|
||||
@@ -453,18 +508,23 @@ whether something *should* be built — which is the opposite of the order §9 a
|
||||
|
||||
---
|
||||
|
||||
## 11. Merging — specified 2026-09-19, nothing built
|
||||
## 11. Merging — the panorama built, three clauses open
|
||||
|
||||
§3.11 was written on 2026-09-19 under D18, undeferring the panorama from §7 and leaving HDR merge
|
||||
and focus stacking there with their data model decided. Eleven `FR-MRG` clauses and two `NFR-MRG`
|
||||
figures entered the register at once with no code behind any of them, which is why the coverage
|
||||
figure fell from 83.0% to 77.2% on the same day — a specification, not a regression.
|
||||
and focus stacking there with their data model decided. Its clauses entered the register with no
|
||||
code behind them, which is why the coverage figure fell from 83.0% to 77.2% on that day — and the
|
||||
panorama was then built in the same week: alignment, projections, the chunked composite written as
|
||||
a DNG beside its sources, the auto-crop and the model's border fill.
|
||||
[panorama.md](panorama.md) §11 and §13 are where it stands.
|
||||
|
||||
[panorama.md](panorama.md) is the design, and its §10 is the order of work. Nothing starts before
|
||||
**S15**: whether rawler reads back a linear DNG the application writes, whether XFeat loads under
|
||||
tract at a fixed shape, whether the working-space texture can be tapped where FR-MRG-2 needs it,
|
||||
and what a chunked blend of a 100 MP composite costs on the tablet. The first two are a day each
|
||||
and either can change the design, which is the reason they come first.
|
||||
Three clauses carry no tag:
|
||||
|
||||
- **FR-MRG-9 — the tablet.** Android runs the same code, but the stated ceiling on frame count and
|
||||
source resolution, refused with a message rather than an out-of-memory kill, is not set.
|
||||
- **NFR-MRG-1 — merge latency.** Measured on the desktop and inside its 60 s (panorama.md §11);
|
||||
the tablet's figure is S15.4's open half, and nothing asserts either per commit.
|
||||
- **NFR-MRG-2 — reproducible merges.** Nothing checks that the same sources and settings give a
|
||||
byte-identical composite.
|
||||
|
||||
## 12. D12, which governed all of the above
|
||||
|
||||
|
||||
Reference in New Issue
Block a user