diff --git a/core/dr-gpu/examples/local.rs b/core/dr-gpu/examples/local.rs index 3385ca4..d47fba3 100644 --- a/core/dr-gpu/examples/local.rs +++ b/core/dr-gpu/examples/local.rs @@ -335,6 +335,7 @@ fn render_stack( ColourSpace::Srgb, stack, &SpotSet::new(), + &[], ); adjust .render_masked(source, &shader, ow, oh, Some(array)) diff --git a/core/dr-gpu/src/adjust.rs b/core/dr-gpu/src/adjust.rs index 0a2d2e7..f94c437 100644 --- a/core/dr-gpu/src/adjust.rs +++ b/core/dr-gpu/src/adjust.rs @@ -1845,7 +1845,21 @@ mod tests { fused_blocks += usize::from(point); } - // The count the loop above accumulated, plus framing — which emits a + // The lens corrections, which are the third kind of block. They are + // not in `descriptors` — they rewrite coordinates rather than + // transform a colour, so they are not operations — and they run ahead + // of the fetch rather than in either stage the loop above sorts into. + let mut warp_blocks = 0; + for desc in g.warp_descriptors() { + let id = desc.id.0; + assert!( + shader.source.contains(&format!("---- warp: {id} ----")), + "{id} was armed above and did not reach the shader" + ); + warp_blocks += 1; + } + + // The counts the loops above accumulated, plus framing — which emits a // stage of its own rather than an operation block and is not in // `descriptors`. Asserted as well as the per-operation exclusive-or // because the two catch different faults: the XOR catches an operation @@ -1853,7 +1867,7 @@ mod tests { // in the chain asked for. assert_eq!( shader.source.matches("---- ").count(), - fused_blocks + 1, + fused_blocks + warp_blocks + 1, "the fused shader carries a block nothing in the chain asked for" ); assert!( diff --git a/core/dr-gpu/tests/local_adjustments.rs b/core/dr-gpu/tests/local_adjustments.rs index 35aa88c..c7dfb08 100644 --- a/core/dr-gpu/tests/local_adjustments.rs +++ b/core/dr-gpu/tests/local_adjustments.rs @@ -72,6 +72,7 @@ fn render_at( ColourSpace::Srgb, stack, &SpotSet::new(), + &[], ); let mut masks = MaskPass::new(ctx).expect("mask pass"); diff --git a/core/dr-gpu/tests/masked_outputs.rs b/core/dr-gpu/tests/masked_outputs.rs index 28e6e5d..7e2b2aa 100644 --- a/core/dr-gpu/tests/masked_outputs.rs +++ b/core/dr-gpu/tests/masked_outputs.rs @@ -90,6 +90,7 @@ fn render_at(ctx: &GpuContext, stack: &MaskStack, out: u32) -> Vec { ColourSpace::Srgb, stack, &SpotSet::new(), + &[], ); let mut adjust = AdjustPass::new(ctx); adjust @@ -108,6 +109,7 @@ fn render_unmasked(ctx: &GpuContext, stack: &MaskStack, out: u32) -> Vec { ColourSpace::Srgb, stack, &SpotSet::new(), + &[], ); let mut adjust = AdjustPass::new(ctx); adjust.render(&source, &shader, out, out).expect("render"); @@ -230,6 +232,7 @@ fn render_gradient(ctx: &GpuContext, stack: &MaskStack, w: u32, h: u32) -> Vec(0.5)"), + crate::operation::sample_source(false, false).contains("p / aspect + vec2(0.5)"), "the sampler's return to texture coordinates moved" ); } diff --git a/core/dr-pipeline/src/graph.rs b/core/dr-pipeline/src/graph.rs index 3a9a2e6..344ded0 100644 --- a/core/dr-pipeline/src/graph.rs +++ b/core/dr-pipeline/src/graph.rs @@ -120,6 +120,20 @@ pub struct EditGraph { /// *where* an adjustment applies, and a spot says where a piece of the /// photograph comes from. spots: SpotSet, + /// The lens corrections that rewrite coordinates: distortion and lateral + /// chromatic aberration (`docs/architecture.md` §5.2). + /// + /// Apart from `ops` for the fourth time, and this one is not about shape + /// but about direction. Every [`Operation`] is a function from colour to + /// colour, and these run *before* a colour exists: they decide which + /// source pixel is read, and CA decides it three times over. See + /// [`crate::lens`] for why that cannot be expressed as an operation. + /// + /// Beside [`Self::framing`] in every way that matters — the two compose + /// into one coordinate map, and neither can be applied without the other's + /// result — but held separately because framing also changes the output's + /// dimensions, which a warp never does. + warps: Vec>, } /// TRACES: FR-DEV-3f @@ -164,6 +178,16 @@ impl EditGraph { masks: Arc::new(MaskStack::new()), film: None, spots: SpotSet::new(), + // Distortion first, then CA, and the order is the correction's + // rather than a preference. Each warp receives the position the + // previous one produced, and lateral CA is a magnification about + // the optical axis of the *undistorted* frame — measured on a + // barrel-distorted one it would be fitted to a radius the lens + // profile does not describe. + warps: vec![ + Box::new(crate::ops::Distortion::new()), + Box::new(crate::ops::Aberration::new()), + ], } } @@ -248,6 +272,18 @@ impl EditGraph { self.ops.iter().map(|o| o.descriptor()).collect() } + /// Descriptors for the coordinate-domain lens corrections, in order. + /// + /// The counterpart to [`Self::descriptors`] and split from it for the same + /// reason framing is absent there: a warp emits its own block in the + /// generated shader rather than a colour fragment, so the codegen tests + /// that count `---- ` markers have to know which kind they are counting. + /// A UI wanting everything still reads [`Self::capabilities`], where all + /// three kinds arrive together and indistinguishably (FR-DEV-3a). + pub fn warp_descriptors(&self) -> Vec> { + self.warps.iter().map(|w| w.descriptor()).collect() + } + /// TRACES: FR-DEV-3a | FR-DEV-3c /// Everything a UI needs to build its controls. /// @@ -286,6 +322,39 @@ impl EditGraph { } }); + // The lens corrections first, matching where they sit in the shader: + // they rewrite the coordinate before any colour is fetched, so nothing + // below them can be judged until they are right. It also puts the + // three optical corrections together in the panel — these two and the + // vignetting node, which is an ordinary operation and arrives above + // through `ops`. + let warps = self.warps.iter().map(|w| { + let desc = w.descriptor(); + OpCapability { + id: desc.id, + label: desc.label, + active: w.is_active(), + params: desc + .params + .iter() + .map(|p| ParamCapability { + id: p.id, + label: p.label, + kind: p.kind.clone(), + default: p.default, + value: w.param(p.id), + facet: p.facet, + }) + .collect(), + // No preferred widget. A distortion amount and the two CA + // scales are ordinary scalars, and plain sliders — the + // fallback every frontend implements — are the right control + // for them. + presentation: None, + attributes: desc.attributes.clone(), + } + }); + // Framing last, matching where it sits in the pipeline: the crop is // decided after the image looks right, not before. let desc = self.framing.descriptor(); @@ -314,7 +383,7 @@ impl EditGraph { attributes: desc.attributes.clone(), }; - ops.chain(std::iter::once(framing)).collect() + warps.chain(ops).chain(std::iter::once(framing)).collect() } /// Set a parameter, clamping to the descriptor's declared range. @@ -362,6 +431,11 @@ impl EditGraph { // nothing to register (FR-DEV-3c). ops: _, framing: _, + // Reached through `capabilities` with the other two. A warp's + // parameters are ordinary scalars once they are in that list, so + // the sidecar, the clipboard and the undo stack carry them with + // nothing registered anywhere (FR-DEV-3c). + warps: _, masks, film, spots, @@ -440,6 +514,20 @@ impl EditGraph { return; } + // The warps, before the operations. Their ids cannot collide with an + // operation's — `ops/` and the warp list are disjoint by construction, + // and `declared_parity` asserts the chain is exactly what `ops/` + // declares — so the order is for readability rather than precedence. + if let Some(warp) = self.warps.iter_mut().find(|w| w.descriptor().id == op) { + let descriptor = warp.descriptor(); + let Some(desc) = descriptor.param(param) else { + log::warn!("unknown parameter {param} on {op}; ignoring"); + return; + }; + warp.set_param(param, desc.clamp(value)); + return; + } + let Some(operation) = self.ops.iter_mut().find(|o| o.descriptor().id == op) else { // A sidecar naming an operation this build does not have. The // rest of the edit must still apply. @@ -465,6 +553,9 @@ impl EditGraph { .param(param) .map(|_| self.framing.param(param)); } + if let Some(warp) = self.warps.iter().find(|w| w.descriptor().id == op) { + return warp.descriptor().param(param).map(|_| warp.param(param)); + } self.ops .iter() .find(|o| o.descriptor().id == op) @@ -478,6 +569,11 @@ impl EditGraph { op.set_param(p.id, p.default); } } + for warp in &mut self.warps { + for p in &warp.descriptor().params { + warp.set_param(p.id, p.default); + } + } self.framing.reset(); // Masks go too, and this is why `apply` can be a replacement rather // than an overlay: a sidecar with no mask blocks means an edit with no @@ -542,7 +638,14 @@ impl EditGraph { /// graph renders to the screen and to a file in the same breath, and the /// two want different answers. pub fn compose_for(&self, output: dr_types::ColourSpace) -> ComposedShader { - compose_full(&self.ops, &self.framing, output, &self.masks, &self.spots) + compose_full( + &self.ops, + &self.framing, + output, + &self.masks, + &self.spots, + &self.warps, + ) } /// TRACES: FR-DSP-1 @@ -637,6 +740,22 @@ impl EditGraph { u64::from(crate::operation::canonical_bits(self.framing.param(p.id))), ); } + // The warps belong to the geometry key, not the colour one: they decide + // which source pixel a colour is read from, so a cached *result* of + // this stage is wrong the moment one moves. Hashed by id as well as by + // value, so two warps swapping their amounts is not the same edit. + for warp in &self.warps { + let descriptor = warp.descriptor(); + geometry = hash_bytes(geometry, descriptor.id.0.as_bytes()); + for p in &descriptor.params { + geometry = hash_bytes(geometry, p.id.0.as_bytes()); + geometry = mix( + geometry, + u64::from(crate::operation::canonical_bits(warp.param(p.id))), + ); + } + } + // The view rect is not a parameter and not in the structure key — it // is not an edit (see `Framing::view`). It is still an input to every // rendered pixel, so a cache that ignored it would show the wrong part @@ -823,20 +942,106 @@ mod tests { assert_ne!(first.uniforms, second.uniforms); } + /// The whole point of putting the warps in `capabilities`: everything that + /// walks that list carries them, with nothing registered anywhere. + #[test] + fn a_warp_is_carried_by_the_machinery_it_never_told_about_itself() { + use crate::ops::{aberration, distortion}; + + let mut g = EditGraph::default_chain(); + g.set_param(distortion::ID, distortion::AMOUNT, 40.0); + g.set_param(aberration::ID, aberration::RED, 25.0); + + assert_eq!(g.param(distortion::ID, distortion::AMOUNT), Some(40.0)); + assert_eq!(g.param(aberration::ID, aberration::RED), Some(25.0)); + + // Through the same capture/apply the sidecar, the clipboard and the + // undo stack all use. + let state = g.state(); + let mut restored = EditGraph::default_chain(); + // No film in this graph, so nothing is owed; the result is asserted + // rather than dropped because ignoring it elsewhere would leave a + // photograph rendering without its stock. + assert_eq!(restored.set_state(&state), FilmRebake::NotNeeded); + + assert_eq!( + restored.param(distortion::ID, distortion::AMOUNT), + Some(40.0), + "a distortion correction did not survive a state round trip, so \ + reopening the photograph would silently drop it" + ); + assert_eq!(restored.param(aberration::ID, aberration::RED), Some(25.0)); + } + + /// A warp is an edit, so `reset` has to reach it. It did not until the + /// loop was added: a reset that left the lens corrections standing would + /// mean "back to the file as it is" quietly did not mean that. + #[test] + fn resetting_the_graph_neutralises_the_warps() { + use crate::ops::distortion; + + let mut g = EditGraph::default_chain(); + g.set_param(distortion::ID, distortion::AMOUNT, 40.0); + g.reset(); + + assert_eq!(g.param(distortion::ID, distortion::AMOUNT), Some(0.0)); + } + + /// The warps belong to the geometry key, not the colour one. + /// + /// A tile cache keyed on geometry holds the *result* of the coordinate + /// stage. Moving a distortion slider changes which source pixel every + /// output pixel reads, so a cache that did not notice would keep drawing + /// the previous correction — visibly, and only where it had already + /// cached. + #[test] + fn a_warp_moves_the_geometry_key_and_leaves_the_others_alone() { + use crate::operation::Affects; + use crate::ops::distortion; + + let mut g = EditGraph::default_chain(); + let before = g.invalidation(); + g.set_param(distortion::ID, distortion::AMOUNT, 40.0); + let after = g.invalidation(); + + assert_ne!( + before.of(Affects::Geometry), + after.of(Affects::Geometry), + "a distortion change must invalidate the geometry stage" + ); + assert_eq!( + before.of(Affects::Colour), + after.of(Affects::Colour), + "and must not invalidate the colour stage, which it does not touch" + ); + } + #[test] fn capabilities_describe_every_operation_and_parameter() { // The UI builds its whole panel from this. Anything missing here is // something the UI would have to hardcode. let g = EditGraph::default_chain(); let caps = g.capabilities(); - // Every operation, plus framing — which is not an operation and so - // is absent from `descriptors`, but must still reach the panel. - assert_eq!(caps.len(), g.descriptors().len() + 1); + // Every operation, plus everything that is *not* an operation and so + // is absent from `descriptors`: the framing, and the coordinate-domain + // lens corrections. All of them have parameters a photographer sets, + // so all of them have to reach the panel — and the panel is forbidden + // from naming any of them (FR-DEV-3a), which leaves this list as the + // only way they can arrive. + assert_eq!(caps.len(), g.descriptors().len() + g.warps.len() + 1); assert!( caps.iter().any(|c| c.id == crate::framing::ID), "framing must appear in the capability list, or the UI cannot \ build a crop control without naming it" ); + for warp in &g.warps { + let id = warp.descriptor().id; + assert!( + caps.iter().any(|c| c.id == id), + "{id} must appear in the capability list, or its correction is \ + in the shader with no control anywhere that can reach it" + ); + } for cap in &caps { assert!(!cap.params.is_empty(), "{} exposes no parameters", cap.id); diff --git a/core/dr-pipeline/src/operation.rs b/core/dr-pipeline/src/operation.rs index 0e58330..ed0d837 100644 --- a/core/dr-pipeline/src/operation.rs +++ b/core/dr-pipeline/src/operation.rs @@ -510,6 +510,11 @@ pub fn compose_with_framing( output, &MaskStack::new(), &crate::spot::SpotSet::new(), + // No lens corrections. This entry point exists for callers that have + // an operation chain and nothing else — the codegen tests, and the + // export path before it grew a graph — and a warp is not something a + // caller can hold without one. + &[], ) } @@ -531,7 +536,13 @@ pub fn compose_full( output: ColourSpace, masks: &MaskStack, spots: &crate::spot::SpotSet, + warps: &[Box], ) -> ComposedShader { + // The lens corrections, composed into one coordinate transform. Beside + // `framing` because they are the other half of the same stage: framing + // says which part of the source this output pixel comes from, and a warp + // says where the lens put it once it got there. + let warp = crate::lens::compose_warps(warps); // Active *point* operations. A neighbourhood operation is filtered out // here rather than asked for a fragment it cannot write: it reads pixels // it is not writing, so it belongs to the detail stage that runs after @@ -636,6 +647,19 @@ pub fn compose_full( ); uniform_values.extend_from_slice(&framing.uniforms()); + // The warps, immediately after framing and before any operation, matching + // where they sit in the shader. Slot order is emission order and nothing + // addresses a slot by number, so this only has to be consistent with + // itself — but keeping it in pipeline order is what makes the generated + // struct readable next to the generated body. + uniform_fields.push_str(&warp.uniform_fields); + uniform_values.extend_from_slice(&warp.uniforms); + for h in &warp.helpers { + if !helpers.iter().any(|existing| existing.name == h.name) { + helpers.push(*h); + } + } + for op in &active { let id = op.descriptor().id.0; let prefix = sanitise(id); @@ -702,17 +726,35 @@ pub fn compose_full( // The coordinate stage: output pixel -> source position -> colour. Emitted // ahead of the operation fragments, which receive the sampled `c`. - let prologue = format!( - "{}\n{}", - framing.wgsl_prologue(), - sample_source(framing.needs_interpolation()) - ); - let sampler_helper = if framing.needs_interpolation() { - BILINEAR_HELPER + // A warp puts an output pixel between source pixels exactly as a free + // angle does, so either one forces the interpolating sampler. Asking + // framing alone — which is what this did before the warps existed — would + // have nearest-neighboured a distortion correction on an unstraightened + // frame, and the aliasing would have looked like a bad profile. + let interpolate = framing.needs_interpolation() || warp.is_active(); + + // Declared ahead of the warp block, which assigns to them. They enter + // equal to `p` so that a chain mixing a splitting warp with a + // non-splitting one still carries every earlier correction into the red + // and blue paths — a distortion correction must move all three channels, + // and only the CA that follows it may move them apart. + let channel_positions = if warp.splits_channels { + "\n // Per-channel source positions, for the lateral CA correction.\n\ + \x20 var p_r = p;\n\ + \x20 var p_b = p;\n" } else { "" }; + let prologue = format!( + "{}{}{}\n{}", + framing.wgsl_prologue(), + channel_positions, + warp.body, + sample_source(interpolate, warp.splits_channels) + ); + let sampler_helper = if interpolate { BILINEAR_HELPER } else { "" }; + // The tail, and it is the whole of the difference between the two output // modes. Everything above — the prologue, the fragments, the mask layers, // the camera matrix — is emitted identically either way, so an operation @@ -1049,7 +1091,51 @@ fn encode_output(c: vec3) -> vec3 {{ /// Split out because it is the join between the coordinate stage and the /// colour stage, and because the choice it makes — an exact integer load, or /// a filtered sample — is the one thing the free-angle case changes. -pub(crate) fn sample_source(interpolate: bool) -> &'static str { +pub(crate) fn sample_source(interpolate: bool, splits_channels: bool) -> &'static str { + if splits_channels { + // Lateral chromatic aberration is a per-channel radial magnification, + // so red and blue are fetched from positions green is not — which is + // the whole reason a warp is not an `Operation`. By the time a colour + // reaches an operation the three channels have been sampled together + // and the divergence is gone. + // + // Green never moves. It is the reference the other two are scaled + // about, so a correction that is wrong still leaves one channel sharp + // rather than softening all three. + return " // Back to texture coordinates, once per channel. + let uv_src = p / aspect + vec2(0.5); + let uv_r = p_r / aspect + vec2(0.5); + let uv_b = p_b / aspect + vec2(0.5); + + // Tested on green alone, not on all three. + // + // The three positions differ by a fraction of a pixel at any correction a + // real lens needs, so testing each would only let the outermost row of the + // frame disagree with itself about whether it exists — which draws a + // coloured fringe along the edge, the exact artefact this is here to + // remove. `sample_bilinear` clamps its own texel indices, so red and blue + // land on the edge pixel rather than out of bounds. + if (any(uv_src < vec2(0.0)) || any(uv_src >= vec2(1.0))) { + textureStore(output, vec2(gid.xy), vec4(0.0, 0.0, 0.0, 1.0)); + return; + } + + // TRACES: FR-DEV-3f + // Where this pixel sits on the *source*, in source pixels. Green's + // position, since that is the one that did not move. + let source_px = uv_src * vec2(src_dims); + let radius = length(p) / (0.5 * length(aspect)); + + // Three fetches, one channel kept from each. Two thirds of the work is + // discarded, which is why `Warp::splits_channels` exists: with no CA in + // the chain the single-sample path below is emitted instead. + var c = vec3( + sample_bilinear(uv_r, src_dims).r, + sample_bilinear(uv_src, src_dims).g, + sample_bilinear(uv_b, src_dims).b, + ); +"; + } if interpolate { " // Back to texture coordinates. let uv_src = p / aspect + vec2(0.5); @@ -1427,6 +1513,136 @@ mod tests { } } + use crate::lens::Warp as _; + + /// A neutral warp list must leave the shader exactly as it was. + /// + /// The property the whole `is_active` filter exists for: an unedited + /// photograph keeps the integer `textureLoad` path, and pays nothing — + /// not a bilinear fetch, not a uniform slot, not a recompile — for + /// corrections nobody has asked for. + #[test] + fn warps_at_neutral_change_nothing_at_all() { + let ops = crate::ops::chain(); + let framing = Framing::new(); + + let without = compose_full( + &ops, + &framing, + ColourSpace::Srgb, + &MaskStack::new(), + &crate::spot::SpotSet::new(), + &[], + ); + let with_neutral = compose_full( + &ops, + &framing, + ColourSpace::Srgb, + &MaskStack::new(), + &crate::spot::SpotSet::new(), + &[ + Box::new(crate::ops::Distortion::new()) as Box, + Box::new(crate::ops::Aberration::new()), + ], + ); + + assert_eq!(without.source, with_neutral.source); + assert_eq!(without.structure_hash, with_neutral.structure_hash); + assert_eq!(without.uniforms, with_neutral.uniforms); + assert!( + !without.source.contains("sample_bilinear"), + "an unwarped, unstraightened frame must keep the integer load path" + ); + } + + /// Distortion alone samples once; chromatic aberration samples three times. + /// + /// `splits_channels` is the whole reason for this test. Lateral CA fetches + /// red and blue from positions green is not, and paying that everywhere + /// would triple the texture bandwidth of the common case — a distortion + /// correction with no CA, which is most lens profiles. + #[test] + fn only_chromatic_aberration_splits_the_channels() { + let compose_with = |warps: Vec>| { + compose_full( + &crate::ops::chain(), + &Framing::new(), + ColourSpace::Srgb, + &MaskStack::new(), + &crate::spot::SpotSet::new(), + &warps, + ) + .source + }; + + let mut distortion = crate::ops::Distortion::new(); + distortion.set_param(crate::ops::distortion::AMOUNT, 40.0); + let only_distortion = compose_with(vec![Box::new(distortion)]); + + assert!( + only_distortion.contains("---- warp: distortion ----"), + "an active distortion must reach the shader" + ); + assert!( + only_distortion.contains("sample_bilinear"), + "a warp puts output pixels between source pixels, so it forces \ + the interpolating sampler even on an unstraightened frame" + ); + assert!( + !only_distortion.contains("var p_r"), + "distortion moves all three channels together and must not pay \ + for the per-channel path" + ); + + let mut ca = crate::ops::Aberration::new(); + ca.set_param(crate::ops::aberration::RED, 25.0); + let with_ca = compose_with(vec![Box::new(ca)]); + + assert!(with_ca.contains("var p_r"), "CA needs per-channel positions"); + assert_eq!( + with_ca.matches("sample_bilinear(").count(), + // Three fetches in the body, plus the helper's own definition. + 4, + "CA must fetch each channel from its own position" + ); + } + + /// An active warp is a different shader and must not reuse the cached one. + /// + /// Covered by `hash_source` rather than by anything warp-specific — the + /// body is written into the source — but asserted because the alternative + /// failure is silent: the correction would simply never appear, exactly as + /// a zoom did before `Framing::structure_key` gained its last bit. + #[test] + fn arming_a_warp_recompiles_but_moving_its_slider_does_not() { + let compose_at = |amount: f32| { + let mut d = crate::ops::Distortion::new(); + d.set_param(crate::ops::distortion::AMOUNT, amount); + compose_full( + &crate::ops::chain(), + &Framing::new(), + ColourSpace::Srgb, + &MaskStack::new(), + &crate::spot::SpotSet::new(), + &[Box::new(d) as Box], + ) + }; + + let neutral = compose_at(0.0); + let armed = compose_at(40.0); + let further = compose_at(70.0); + + assert_ne!( + neutral.structure_hash, armed.structure_hash, + "arming a warp adds a block to the shader and must recompile" + ); + assert_eq!( + armed.structure_hash, further.structure_hash, + "its magnitude is a uniform, so a drag must not recompile" + ); + assert_ne!(armed.uniforms, further.uniforms); + } + #[test] fn structure_hash_ignores_values_but_tracks_the_op_set() { // The property the shader cache depends on: moving a slider must not diff --git a/docs/traceability.md b/docs/traceability.md index 29df6eb..3bd7515 100644 --- a/docs/traceability.md +++ b/docs/traceability.md @@ -10,7 +10,7 @@ Denominators are parsed from [`requirements.md`](requirements.md) at run time, n | Metric | Value | |---|---| | Source files scanned | 335 | -| TRACES tags found | 1086 | +| TRACES tags found | 1087 | | Requirements defined | 180 | | Requirements covered | 127 | | **Coverage** | **70.6%** (127/180) | @@ -45,7 +45,7 @@ _None._ | FR-CAT-5 | [`core/dr-catalog/src/keywords.rs:1`](../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:1171`](../core/dr-catalog/src/schema.rs#L1171), [`core/dr-catalog/src/schema.rs:668`](../core/dr-catalog/src/schema.rs#L668), [`core/dr-decode/src/lib.rs:285`](../core/dr-decode/src/lib.rs#L285), [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-pipeline/src/sidecar.rs:137`](../core/dr-pipeline/src/sidecar.rs#L137), [`ui/dr-ui/src/collections_ui.rs:1579`](../ui/dr-ui/src/collections_ui.rs#L1579), [`ui/dr-ui/src/collections_ui.rs:1685`](../ui/dr-ui/src/collections_ui.rs#L1685), [`ui/dr-ui/src/collections_ui.rs:1734`](../ui/dr-ui/src/collections_ui.rs#L1734), [`ui/dr-ui/src/collections_ui.rs:238`](../ui/dr-ui/src/collections_ui.rs#L238), [`ui/dr-ui/src/collections_ui.rs:335`](../ui/dr-ui/src/collections_ui.rs#L335), [`ui/dr-ui/src/collections_ui.rs:87`](../ui/dr-ui/src/collections_ui.rs#L87), [`ui/dr-ui/src/library.rs:4180`](../ui/dr-ui/src/library.rs#L4180), [`ui/dr-ui/src/library_ui.rs:713`](../ui/dr-ui/src/library_ui.rs#L713), [`ui/dr-ui/src/library_ui.rs:7677`](../ui/dr-ui/src/library_ui.rs#L7677), [`ui/dr-ui/src/library_ui.rs:7688`](../ui/dr-ui/src/library_ui.rs#L7688), [`ui/dr-ui/src/library_ui.rs:7701`](../ui/dr-ui/src/library_ui.rs#L7701), [`ui/dr-ui/src/library_ui.rs:7716`](../ui/dr-ui/src/library_ui.rs#L7716), [`ui/dr-ui/src/library_ui.rs:7725`](../ui/dr-ui/src/library_ui.rs#L7725), [`ui/dr-ui/ui/app.slint:349`](../ui/dr-ui/ui/app.slint#L349), [`ui/dr-ui/ui/app.slint:571`](../ui/dr-ui/ui/app.slint#L571), [`ui/dr-ui/ui/library.slint:1350`](../ui/dr-ui/ui/library.slint#L1350), [`ui/dr-ui/ui/library.slint:1374`](../ui/dr-ui/ui/library.slint#L1374), [`ui/dr-ui/ui/library.slint:1427`](../ui/dr-ui/ui/library.slint#L1427), [`ui/dr-ui/ui/library.slint:19`](../ui/dr-ui/ui/library.slint#L19), [`ui/dr-ui/ui/library.slint:4101`](../ui/dr-ui/ui/library.slint#L4101) | | FR-CAT-6 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/keywords.rs:1`](../core/dr-catalog/src/keywords.rs#L1), [`core/dr-catalog/src/lib.rs:1`](../core/dr-catalog/src/lib.rs#L1), [`core/dr-catalog/src/query.rs:1`](../core/dr-catalog/src/query.rs#L1), [`core/dr-catalog/src/rating.rs:1`](../core/dr-catalog/src/rating.rs#L1), [`core/dr-catalog/src/schema.rs:668`](../core/dr-catalog/src/schema.rs#L668), [`core/dr-types/src/place.rs:1`](../core/dr-types/src/place.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`core/dr-types/src/settings.rs:64`](../core/dr-types/src/settings.rs#L64), [`core/dr-types/src/time.rs:67`](../core/dr-types/src/time.rs#L67), [`core/dr-types/src/time.rs:90`](../core/dr-types/src/time.rs#L90), [`ui/dr-ui/src/library.rs:246`](../ui/dr-ui/src/library.rs#L246), [`ui/dr-ui/src/library.rs:4656`](../ui/dr-ui/src/library.rs#L4656), [`ui/dr-ui/src/library_ui.rs:389`](../ui/dr-ui/src/library_ui.rs#L389), [`ui/dr-ui/src/library_ui.rs:470`](../ui/dr-ui/src/library_ui.rs#L470), [`ui/dr-ui/src/library_ui.rs:6407`](../ui/dr-ui/src/library_ui.rs#L6407), [`ui/dr-ui/src/library_ui.rs:6460`](../ui/dr-ui/src/library_ui.rs#L6460), [`ui/dr-ui/src/library_ui.rs:7817`](../ui/dr-ui/src/library_ui.rs#L7817), [`ui/dr-ui/ui/app.slint:361`](../ui/dr-ui/ui/app.slint#L361), [`ui/dr-ui/ui/app.slint:571`](../ui/dr-ui/ui/app.slint#L571), [`ui/dr-ui/ui/app.slint:874`](../ui/dr-ui/ui/app.slint#L874), [`ui/dr-ui/ui/library.slint:111`](../ui/dr-ui/ui/library.slint#L111), [`ui/dr-ui/ui/library.slint:1537`](../ui/dr-ui/ui/library.slint#L1537), [`ui/dr-ui/ui/library.slint:4101`](../ui/dr-ui/ui/library.slint#L4101), [`ui/dr-ui/ui/settings.slint:150`](../ui/dr-ui/ui/settings.slint#L150) | | FR-CAT-7 | [`core/dr-catalog/src/collections.rs:1`](../core/dr-catalog/src/collections.rs#L1), [`core/dr-catalog/src/merge.rs:1`](../core/dr-catalog/src/merge.rs#L1), [`core/dr-catalog/src/sync.rs:1`](../core/dr-catalog/src/sync.rs#L1), [`core/dr-types/src/selector.rs:1`](../core/dr-types/src/selector.rs#L1), [`ui/dr-ui/src/collections_ui.rs:1073`](../ui/dr-ui/src/collections_ui.rs#L1073), [`ui/dr-ui/src/collections_ui.rs:117`](../ui/dr-ui/src/collections_ui.rs#L117), [`ui/dr-ui/src/collections_ui.rs:1552`](../ui/dr-ui/src/collections_ui.rs#L1552), [`ui/dr-ui/src/collections_ui.rs:1598`](../ui/dr-ui/src/collections_ui.rs#L1598), [`ui/dr-ui/src/collections_ui.rs:1848`](../ui/dr-ui/src/collections_ui.rs#L1848), [`ui/dr-ui/src/collections_ui.rs:1913`](../ui/dr-ui/src/collections_ui.rs#L1913), [`ui/dr-ui/src/collections_ui.rs:1973`](../ui/dr-ui/src/collections_ui.rs#L1973), [`ui/dr-ui/src/collections_ui.rs:1`](../ui/dr-ui/src/collections_ui.rs#L1), [`ui/dr-ui/src/collections_ui.rs:2963`](../ui/dr-ui/src/collections_ui.rs#L2963), [`ui/dr-ui/src/collections_ui.rs:365`](../ui/dr-ui/src/collections_ui.rs#L365), [`ui/dr-ui/src/collections_ui.rs:569`](../ui/dr-ui/src/collections_ui.rs#L569), [`ui/dr-ui/src/collections_ui.rs:965`](../ui/dr-ui/src/collections_ui.rs#L965), [`ui/dr-ui/src/derived_sync.rs:1`](../ui/dr-ui/src/derived_sync.rs#L1), [`ui/dr-ui/src/library.rs:4461`](../ui/dr-ui/src/library.rs#L4461), [`ui/dr-ui/src/library.rs:4487`](../ui/dr-ui/src/library.rs#L4487), [`ui/dr-ui/src/library.rs:4542`](../ui/dr-ui/src/library.rs#L4542), [`ui/dr-ui/src/library_ui.rs:2686`](../ui/dr-ui/src/library_ui.rs#L2686), [`ui/dr-ui/src/library_ui.rs:4083`](../ui/dr-ui/src/library_ui.rs#L4083), [`ui/dr-ui/src/library_ui.rs:4834`](../ui/dr-ui/src/library_ui.rs#L4834), [`ui/dr-ui/ui/app.slint:352`](../ui/dr-ui/ui/app.slint#L352), [`ui/dr-ui/ui/app.slint:566`](../ui/dr-ui/ui/app.slint#L566), [`ui/dr-ui/ui/app.slint:595`](../ui/dr-ui/ui/app.slint#L595), [`ui/dr-ui/ui/collections.slint:4`](../ui/dr-ui/ui/collections.slint#L4), [`ui/dr-ui/ui/library.slint:1317`](../ui/dr-ui/ui/library.slint#L1317), [`ui/dr-ui/ui/library.slint:2886`](../ui/dr-ui/ui/library.slint#L2886), [`ui/dr-ui/ui/library.slint:4079`](../ui/dr-ui/ui/library.slint#L4079), [`ui/dr-ui/ui/library.slint:993`](../ui/dr-ui/ui/library.slint#L993) | -| FR-CAT-8 | [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:346`](../core/dr-pipeline/src/graph.rs#L346), [`core/dr-pipeline/src/graph.rs:385`](../core/dr-pipeline/src/graph.rs#L385), [`core/dr-pipeline/src/ops/curve.rs:137`](../core/dr-pipeline/src/ops/curve.rs#L137), [`core/dr-pipeline/src/ops/curve.rs:656`](../core/dr-pipeline/src/ops/curve.rs#L656), [`core/dr-pipeline/src/sidecar.rs:1048`](../core/dr-pipeline/src/sidecar.rs#L1048), [`core/dr-pipeline/src/sidecar.rs:1714`](../core/dr-pipeline/src/sidecar.rs#L1714), [`core/dr-pipeline/src/sidecar.rs:94`](../core/dr-pipeline/src/sidecar.rs#L94), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`core/dr-pipeline/tests/tone_curve.rs:34`](../core/dr-pipeline/tests/tone_curve.rs#L34), [`ui/dr-ui/src/develop.rs:1922`](../ui/dr-ui/src/develop.rs#L1922), [`ui/dr-ui/src/develop.rs:4157`](../ui/dr-ui/src/develop.rs#L4157), [`ui/dr-ui/src/develop.rs:4186`](../ui/dr-ui/src/develop.rs#L4186), [`ui/dr-ui/src/develop.rs:4938`](../ui/dr-ui/src/develop.rs#L4938), [`ui/dr-ui/src/develop.rs:4992`](../ui/dr-ui/src/develop.rs#L4992), [`ui/dr-ui/src/develop.rs:5094`](../ui/dr-ui/src/develop.rs#L5094), [`ui/dr-ui/src/export.rs:799`](../ui/dr-ui/src/export.rs#L799), [`ui/dr-ui/src/lib.rs:1082`](../ui/dr-ui/src/lib.rs#L1082), [`ui/dr-ui/src/lib.rs:1598`](../ui/dr-ui/src/lib.rs#L1598), [`ui/dr-ui/src/lib.rs:2088`](../ui/dr-ui/src/lib.rs#L2088), [`ui/dr-ui/src/lib.rs:2223`](../ui/dr-ui/src/lib.rs#L2223), [`ui/dr-ui/src/lib.rs:634`](../ui/dr-ui/src/lib.rs#L634), [`ui/dr-ui/src/library.rs:1923`](../ui/dr-ui/src/library.rs#L1923), [`ui/dr-ui/src/library.rs:492`](../ui/dr-ui/src/library.rs#L492), [`ui/dr-ui/src/library.rs:539`](../ui/dr-ui/src/library.rs#L539), [`ui/dr-ui/src/library.rs:576`](../ui/dr-ui/src/library.rs#L576), [`ui/dr-ui/src/library.rs:823`](../ui/dr-ui/src/library.rs#L823), [`ui/dr-ui/src/library_ui.rs:6043`](../ui/dr-ui/src/library_ui.rs#L6043), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) | +| FR-CAT-8 | [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/graph.rs:415`](../core/dr-pipeline/src/graph.rs#L415), [`core/dr-pipeline/src/graph.rs:459`](../core/dr-pipeline/src/graph.rs#L459), [`core/dr-pipeline/src/ops/curve.rs:137`](../core/dr-pipeline/src/ops/curve.rs#L137), [`core/dr-pipeline/src/ops/curve.rs:656`](../core/dr-pipeline/src/ops/curve.rs#L656), [`core/dr-pipeline/src/sidecar.rs:1048`](../core/dr-pipeline/src/sidecar.rs#L1048), [`core/dr-pipeline/src/sidecar.rs:1714`](../core/dr-pipeline/src/sidecar.rs#L1714), [`core/dr-pipeline/src/sidecar.rs:94`](../core/dr-pipeline/src/sidecar.rs#L94), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`core/dr-pipeline/tests/tone_curve.rs:34`](../core/dr-pipeline/tests/tone_curve.rs#L34), [`ui/dr-ui/src/develop.rs:1922`](../ui/dr-ui/src/develop.rs#L1922), [`ui/dr-ui/src/develop.rs:4157`](../ui/dr-ui/src/develop.rs#L4157), [`ui/dr-ui/src/develop.rs:4186`](../ui/dr-ui/src/develop.rs#L4186), [`ui/dr-ui/src/develop.rs:4938`](../ui/dr-ui/src/develop.rs#L4938), [`ui/dr-ui/src/develop.rs:4992`](../ui/dr-ui/src/develop.rs#L4992), [`ui/dr-ui/src/develop.rs:5094`](../ui/dr-ui/src/develop.rs#L5094), [`ui/dr-ui/src/export.rs:799`](../ui/dr-ui/src/export.rs#L799), [`ui/dr-ui/src/lib.rs:1082`](../ui/dr-ui/src/lib.rs#L1082), [`ui/dr-ui/src/lib.rs:1598`](../ui/dr-ui/src/lib.rs#L1598), [`ui/dr-ui/src/lib.rs:2088`](../ui/dr-ui/src/lib.rs#L2088), [`ui/dr-ui/src/lib.rs:2223`](../ui/dr-ui/src/lib.rs#L2223), [`ui/dr-ui/src/lib.rs:634`](../ui/dr-ui/src/lib.rs#L634), [`ui/dr-ui/src/library.rs:1923`](../ui/dr-ui/src/library.rs#L1923), [`ui/dr-ui/src/library.rs:492`](../ui/dr-ui/src/library.rs#L492), [`ui/dr-ui/src/library.rs:539`](../ui/dr-ui/src/library.rs#L539), [`ui/dr-ui/src/library.rs:576`](../ui/dr-ui/src/library.rs#L576), [`ui/dr-ui/src/library.rs:823`](../ui/dr-ui/src/library.rs#L823), [`ui/dr-ui/src/library_ui.rs:6043`](../ui/dr-ui/src/library_ui.rs#L6043), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1) | | FR-CAT-9 | [`core/dr-catalog/src/cache.rs:1`](../core/dr-catalog/src/cache.rs#L1), [`core/dr-catalog/src/scan.rs:1`](../core/dr-catalog/src/scan.rs#L1), [`core/dr-catalog/src/schema.rs:725`](../core/dr-catalog/src/schema.rs#L725), [`core/dr-catalog/src/walk.rs:1022`](../core/dr-catalog/src/walk.rs#L1022), [`core/dr-catalog/src/walk.rs:162`](../core/dr-catalog/src/walk.rs#L162), [`core/dr-catalog/src/walk.rs:1`](../core/dr-catalog/src/walk.rs#L1), [`core/dr-catalog/src/walk.rs:435`](../core/dr-catalog/src/walk.rs#L435), [`core/dr-catalog/src/walk.rs:728`](../core/dr-catalog/src/walk.rs#L728), [`core/dr-sync-nextcloud/src/desktop_client.rs:30`](../core/dr-sync-nextcloud/src/desktop_client.rs#L30), [`core/dr-sync/src/error.rs:113`](../core/dr-sync/src/error.rs#L113), [`core/dr-sync/src/reachability.rs:1`](../core/dr-sync/src/reachability.rs#L1), [`core/dr-sync/src/scan.rs:175`](../core/dr-sync/src/scan.rs#L175), [`core/dr-sync/src/scan.rs:464`](../core/dr-sync/src/scan.rs#L464), [`core/dr-types/src/lib.rs:122`](../core/dr-types/src/lib.rs#L122), [`ui/dr-ui/src/develop.rs:3544`](../ui/dr-ui/src/develop.rs#L3544), [`ui/dr-ui/src/develop.rs:3587`](../ui/dr-ui/src/develop.rs#L3587), [`ui/dr-ui/src/library.rs:1242`](../ui/dr-ui/src/library.rs#L1242), [`ui/dr-ui/src/library.rs:1295`](../ui/dr-ui/src/library.rs#L1295), [`ui/dr-ui/src/library.rs:1326`](../ui/dr-ui/src/library.rs#L1326), [`ui/dr-ui/src/library.rs:1431`](../ui/dr-ui/src/library.rs#L1431), [`ui/dr-ui/src/library.rs:161`](../ui/dr-ui/src/library.rs#L161), [`ui/dr-ui/src/library.rs:1883`](../ui/dr-ui/src/library.rs#L1883), [`ui/dr-ui/src/library.rs:1959`](../ui/dr-ui/src/library.rs#L1959), [`ui/dr-ui/src/library.rs:266`](../ui/dr-ui/src/library.rs#L266), [`ui/dr-ui/src/library.rs:4764`](../ui/dr-ui/src/library.rs#L4764), [`ui/dr-ui/src/library.rs:576`](../ui/dr-ui/src/library.rs#L576), [`ui/dr-ui/src/library.rs:807`](../ui/dr-ui/src/library.rs#L807), [`ui/dr-ui/src/library.rs:823`](../ui/dr-ui/src/library.rs#L823), [`ui/dr-ui/src/library.rs:877`](../ui/dr-ui/src/library.rs#L877), [`ui/dr-ui/src/library_ui.rs:1318`](../ui/dr-ui/src/library_ui.rs#L1318), [`ui/dr-ui/src/library_ui.rs:1909`](../ui/dr-ui/src/library_ui.rs#L1909), [`ui/dr-ui/src/library_ui.rs:1953`](../ui/dr-ui/src/library_ui.rs#L1953), [`ui/dr-ui/src/library_ui.rs:1969`](../ui/dr-ui/src/library_ui.rs#L1969), [`ui/dr-ui/src/library_ui.rs:2063`](../ui/dr-ui/src/library_ui.rs#L2063), [`ui/dr-ui/src/library_ui.rs:284`](../ui/dr-ui/src/library_ui.rs#L284), [`ui/dr-ui/src/library_ui.rs:2925`](../ui/dr-ui/src/library_ui.rs#L2925), [`ui/dr-ui/src/library_ui.rs:317`](../ui/dr-ui/src/library_ui.rs#L317), [`ui/dr-ui/src/library_ui.rs:325`](../ui/dr-ui/src/library_ui.rs#L325), [`ui/dr-ui/src/library_ui.rs:3363`](../ui/dr-ui/src/library_ui.rs#L3363), [`ui/dr-ui/src/library_ui.rs:3585`](../ui/dr-ui/src/library_ui.rs#L3585), [`ui/dr-ui/src/library_ui.rs:3863`](../ui/dr-ui/src/library_ui.rs#L3863), [`ui/dr-ui/src/library_ui.rs:3951`](../ui/dr-ui/src/library_ui.rs#L3951), [`ui/dr-ui/src/library_ui.rs:4134`](../ui/dr-ui/src/library_ui.rs#L4134), [`ui/dr-ui/src/library_ui.rs:4248`](../ui/dr-ui/src/library_ui.rs#L4248), [`ui/dr-ui/src/library_ui.rs:523`](../ui/dr-ui/src/library_ui.rs#L523), [`ui/dr-ui/src/library_ui.rs:586`](../ui/dr-ui/src/library_ui.rs#L586), [`ui/dr-ui/src/library_ui.rs:6505`](../ui/dr-ui/src/library_ui.rs#L6505), [`ui/dr-ui/src/library_ui.rs:6620`](../ui/dr-ui/src/library_ui.rs#L6620), [`ui/dr-ui/src/presets.rs:453`](../ui/dr-ui/src/presets.rs#L453), [`ui/dr-ui/src/presets.rs:465`](../ui/dr-ui/src/presets.rs#L465), [`ui/dr-ui/src/sidecar_cache.rs:1`](../ui/dr-ui/src/sidecar_cache.rs#L1), [`ui/dr-ui/tests/export_ignores_the_viewport.rs:1`](../ui/dr-ui/tests/export_ignores_the_viewport.rs#L1) | | FR-CULL-1 | [`core/dr-decode/src/preview.rs:121`](../core/dr-decode/src/preview.rs#L121) | | FR-CULL-10 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:376`](../core/dr-catalog/src/schema.rs#L376), [`core/dr-catalog/src/schema.rs:554`](../core/dr-catalog/src/schema.rs#L554), [`core/dr-face/src/assign.rs:1`](../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../core/dr-face/src/neighbours.rs#L1), [`core/dr-types/src/settings.rs:117`](../core/dr-types/src/settings.rs#L117), [`ui/dr-ui/src/develop.rs:121`](../ui/dr-ui/src/develop.rs#L121), [`ui/dr-ui/src/develop.rs:130`](../ui/dr-ui/src/develop.rs#L130), [`ui/dr-ui/src/develop.rs:196`](../ui/dr-ui/src/develop.rs#L196), [`ui/dr-ui/src/develop.rs:2154`](../ui/dr-ui/src/develop.rs#L2154), [`ui/dr-ui/src/develop.rs:689`](../ui/dr-ui/src/develop.rs#L689), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity.rs:1`](../ui/dr-ui/src/identity.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/src/lib.rs:2195`](../ui/dr-ui/src/lib.rs#L2195), [`ui/dr-ui/ui/identity.slint:1`](../ui/dr-ui/ui/identity.slint#L1) | @@ -58,28 +58,28 @@ _None._ | FR-CULL-8 | [`core/dr-catalog/src/face_shard.rs:1`](../core/dr-catalog/src/face_shard.rs#L1), [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:487`](../core/dr-catalog/src/schema.rs#L487), [`core/dr-catalog/src/schema.rs:513`](../core/dr-catalog/src/schema.rs#L513), [`core/dr-catalog/src/schema.rs:554`](../core/dr-catalog/src/schema.rs#L554), [`core/dr-face/src/align.rs:291`](../core/dr-face/src/align.rs#L291), [`ui/dr-ui/examples/face_native.rs:1`](../ui/dr-ui/examples/face_native.rs#L1), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/faces.rs:330`](../ui/dr-ui/src/faces.rs#L330), [`ui/dr-ui/src/faces.rs:346`](../ui/dr-ui/src/faces.rs#L346), [`ui/dr-ui/src/identity_ui.rs:540`](../ui/dr-ui/src/identity_ui.rs#L540), [`ui/dr-ui/src/lib.rs:1256`](../ui/dr-ui/src/lib.rs#L1256), [`ui/dr-ui/src/library.rs:2985`](../ui/dr-ui/src/library.rs#L2985), [`ui/dr-ui/src/library.rs:3077`](../ui/dr-ui/src/library.rs#L3077), [`ui/dr-ui/src/library.rs:3298`](../ui/dr-ui/src/library.rs#L3298), [`ui/dr-ui/src/library.rs:3434`](../ui/dr-ui/src/library.rs#L3434), [`ui/dr-ui/src/library.rs:3470`](../ui/dr-ui/src/library.rs#L3470), [`ui/dr-ui/ui/settings.slint:419`](../ui/dr-ui/ui/settings.slint#L419), [`ui/dr-ui/ui/settings.slint:82`](../ui/dr-ui/ui/settings.slint#L82) | | FR-CULL-9 | [`core/dr-catalog/src/faces.rs:1`](../core/dr-catalog/src/faces.rs#L1), [`core/dr-catalog/src/schema.rs:554`](../core/dr-catalog/src/schema.rs#L554), [`core/dr-face/src/assign.rs:1`](../core/dr-face/src/assign.rs#L1), [`core/dr-face/src/neighbours.rs:1`](../core/dr-face/src/neighbours.rs#L1), [`core/dr-types/src/settings.rs:117`](../core/dr-types/src/settings.rs#L117), [`ui/dr-ui/src/faces.rs:1`](../ui/dr-ui/src/faces.rs#L1), [`ui/dr-ui/src/identity_ui.rs:1`](../ui/dr-ui/src/identity_ui.rs#L1), [`ui/dr-ui/ui/identity.slint:283`](../ui/dr-ui/ui/identity.slint#L283) | | FR-DEV-1 | [`core/dr-pipeline/src/graph.rs:1`](../core/dr-pipeline/src/graph.rs#L1), [`core/dr-pipeline/src/sidecar.rs:1`](../core/dr-pipeline/src/sidecar.rs#L1) | -| FR-DEV-2 | [`core/dr-pipeline/src/operation.rs:389`](../core/dr-pipeline/src/operation.rs#L389) | -| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:2203`](../core/dr-gpu/src/adjust.rs#L2203), [`core/dr-gpu/src/adjust.rs:651`](../core/dr-gpu/src/adjust.rs#L651), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/tests/tone_curve.rs:1`](../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/framing.rs:177`](../core/dr-pipeline/src/framing.rs#L177), [`core/dr-pipeline/src/framing.rs:234`](../core/dr-pipeline/src/framing.rs#L234), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-pipeline/src/framing.rs:753`](../core/dr-pipeline/src/framing.rs#L753), [`core/dr-pipeline/src/graph.rs:170`](../core/dr-pipeline/src/graph.rs#L170), [`core/dr-pipeline/src/graph.rs:578`](../core/dr-pipeline/src/graph.rs#L578), [`core/dr-pipeline/src/mask.rs:151`](../core/dr-pipeline/src/mask.rs#L151), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:516`](../core/dr-pipeline/src/operation.rs#L516), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:635`](../core/dr-pipeline/src/ops/curve.rs#L635), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/sidecar.rs:1048`](../core/dr-pipeline/src/sidecar.rs#L1048), [`core/dr-pipeline/src/sidecar.rs:158`](../core/dr-pipeline/src/sidecar.rs#L158), [`core/dr-pipeline/src/sidecar.rs:1714`](../core/dr-pipeline/src/sidecar.rs#L1714), [`core/dr-pipeline/src/sidecar.rs:1774`](../core/dr-pipeline/src/sidecar.rs#L1774), [`core/dr-pipeline/tests/tone_curve.rs:1`](../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:850`](../core/dr-segment/src/refine.rs#L850), [`ui/dr-ui/src/develop.rs:103`](../ui/dr-ui/src/develop.rs#L103), [`ui/dr-ui/src/develop.rs:1506`](../ui/dr-ui/src/develop.rs#L1506), [`ui/dr-ui/src/develop.rs:165`](../ui/dr-ui/src/develop.rs#L165), [`ui/dr-ui/src/develop.rs:1922`](../ui/dr-ui/src/develop.rs#L1922), [`ui/dr-ui/src/develop.rs:2136`](../ui/dr-ui/src/develop.rs#L2136), [`ui/dr-ui/src/develop.rs:2154`](../ui/dr-ui/src/develop.rs#L2154), [`ui/dr-ui/src/develop.rs:2168`](../ui/dr-ui/src/develop.rs#L2168), [`ui/dr-ui/src/develop.rs:2190`](../ui/dr-ui/src/develop.rs#L2190), [`ui/dr-ui/src/develop.rs:2336`](../ui/dr-ui/src/develop.rs#L2336), [`ui/dr-ui/src/develop.rs:2434`](../ui/dr-ui/src/develop.rs#L2434), [`ui/dr-ui/src/develop.rs:328`](../ui/dr-ui/src/develop.rs#L328), [`ui/dr-ui/src/develop.rs:365`](../ui/dr-ui/src/develop.rs#L365), [`ui/dr-ui/src/develop.rs:3855`](../ui/dr-ui/src/develop.rs#L3855), [`ui/dr-ui/src/develop.rs:3885`](../ui/dr-ui/src/develop.rs#L3885), [`ui/dr-ui/src/develop.rs:3951`](../ui/dr-ui/src/develop.rs#L3951), [`ui/dr-ui/src/develop.rs:3965`](../ui/dr-ui/src/develop.rs#L3965), [`ui/dr-ui/src/develop.rs:4157`](../ui/dr-ui/src/develop.rs#L4157), [`ui/dr-ui/src/develop.rs:4817`](../ui/dr-ui/src/develop.rs#L4817), [`ui/dr-ui/src/develop.rs:4938`](../ui/dr-ui/src/develop.rs#L4938), [`ui/dr-ui/src/develop.rs:5094`](../ui/dr-ui/src/develop.rs#L5094), [`ui/dr-ui/src/develop.rs:5230`](../ui/dr-ui/src/develop.rs#L5230), [`ui/dr-ui/src/develop.rs:5274`](../ui/dr-ui/src/develop.rs#L5274), [`ui/dr-ui/src/develop.rs:5324`](../ui/dr-ui/src/develop.rs#L5324), [`ui/dr-ui/src/develop.rs:588`](../ui/dr-ui/src/develop.rs#L588), [`ui/dr-ui/src/develop.rs:649`](../ui/dr-ui/src/develop.rs#L649), [`ui/dr-ui/src/develop.rs:795`](../ui/dr-ui/src/develop.rs#L795), [`ui/dr-ui/src/develop.rs:842`](../ui/dr-ui/src/develop.rs#L842), [`ui/dr-ui/src/develop.rs:871`](../ui/dr-ui/src/develop.rs#L871), [`ui/dr-ui/src/lib.rs:1696`](../ui/dr-ui/src/lib.rs#L1696), [`ui/dr-ui/src/lib.rs:2498`](../ui/dr-ui/src/lib.rs#L2498), [`ui/dr-ui/src/lib.rs:2694`](../ui/dr-ui/src/lib.rs#L2694), [`ui/dr-ui/src/lib.rs:2866`](../ui/dr-ui/src/lib.rs#L2866), [`ui/dr-ui/src/lib.rs:2930`](../ui/dr-ui/src/lib.rs#L2930), [`ui/dr-ui/src/lib.rs:2984`](../ui/dr-ui/src/lib.rs#L2984), [`ui/dr-ui/src/lib.rs:389`](../ui/dr-ui/src/lib.rs#L389), [`ui/dr-ui/src/lib.rs:432`](../ui/dr-ui/src/lib.rs#L432), [`ui/dr-ui/src/lib.rs:455`](../ui/dr-ui/src/lib.rs#L455), [`ui/dr-ui/src/library.rs:539`](../ui/dr-ui/src/library.rs#L539), [`ui/dr-ui/src/masks_ui.rs:249`](../ui/dr-ui/src/masks_ui.rs#L249), [`ui/dr-ui/src/masks_ui.rs:41`](../ui/dr-ui/src/masks_ui.rs#L41), [`ui/dr-ui/src/masks_ui.rs:884`](../ui/dr-ui/src/masks_ui.rs#L884), [`ui/dr-ui/src/masks_ui.rs:998`](../ui/dr-ui/src/masks_ui.rs#L998), [`ui/dr-ui/src/presets.rs:394`](../ui/dr-ui/src/presets.rs#L394), [`ui/dr-ui/src/segmentation.rs:116`](../ui/dr-ui/src/segmentation.rs#L116), [`ui/dr-ui/src/segmentation.rs:330`](../ui/dr-ui/src/segmentation.rs#L330), [`ui/dr-ui/src/segmentation.rs:346`](../ui/dr-ui/src/segmentation.rs#L346), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476), [`ui/dr-ui/src/segmentation.rs:504`](../ui/dr-ui/src/segmentation.rs#L504), [`ui/dr-ui/ui/adjust.slint:547`](../ui/dr-ui/ui/adjust.slint#L547), [`ui/dr-ui/ui/adjust.slint:666`](../ui/dr-ui/ui/adjust.slint#L666), [`ui/dr-ui/ui/app.slint:150`](../ui/dr-ui/ui/app.slint#L150), [`ui/dr-ui/ui/app.slint:196`](../ui/dr-ui/ui/app.slint#L196), [`ui/dr-ui/ui/app.slint:2046`](../ui/dr-ui/ui/app.slint#L2046), [`ui/dr-ui/ui/app.slint:984`](../ui/dr-ui/ui/app.slint#L984), [`ui/dr-ui/ui/masks.slint:612`](../ui/dr-ui/ui/masks.slint#L612) | -| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:194`](../core/dr-pipeline/src/descriptor.rs#L194), [`core/dr-pipeline/src/descriptor.rs:234`](../core/dr-pipeline/src/descriptor.rs#L234), [`core/dr-pipeline/src/descriptor.rs:258`](../core/dr-pipeline/src/descriptor.rs#L258), [`core/dr-pipeline/src/descriptor.rs:313`](../core/dr-pipeline/src/descriptor.rs#L313), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:24`](../core/dr-pipeline/src/graph.rs#L24), [`core/dr-pipeline/src/graph.rs:251`](../core/dr-pipeline/src/graph.rs#L251), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/graph.rs:59`](../core/dr-pipeline/src/graph.rs#L59), [`core/dr-pipeline/src/mask.rs:1108`](../core/dr-pipeline/src/mask.rs#L1108), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`core/dr-pipeline/src/ops/curve.rs:319`](../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop.rs:1403`](../ui/dr-ui/src/develop.rs#L1403), [`ui/dr-ui/src/lib.rs:749`](../ui/dr-ui/src/lib.rs#L749), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../ui/dr-ui/tests/ui_names_no_operation.rs#L1) | +| FR-DEV-2 | [`core/dr-pipeline/src/operation.rs:403`](../core/dr-pipeline/src/operation.rs#L403) | +| FR-DEV-3 | [`core/dr-gpu/src/adjust.rs:2217`](../core/dr-gpu/src/adjust.rs#L2217), [`core/dr-gpu/src/adjust.rs:651`](../core/dr-gpu/src/adjust.rs#L651), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/tests/tone_curve.rs:1`](../core/dr-gpu/tests/tone_curve.rs#L1), [`core/dr-pipeline/src/coverage.rs:122`](../core/dr-pipeline/src/coverage.rs#L122), [`core/dr-pipeline/src/coverage.rs:1`](../core/dr-pipeline/src/coverage.rs#L1), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/framing.rs:177`](../core/dr-pipeline/src/framing.rs#L177), [`core/dr-pipeline/src/framing.rs:234`](../core/dr-pipeline/src/framing.rs#L234), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-pipeline/src/framing.rs:753`](../core/dr-pipeline/src/framing.rs#L753), [`core/dr-pipeline/src/graph.rs:194`](../core/dr-pipeline/src/graph.rs#L194), [`core/dr-pipeline/src/graph.rs:681`](../core/dr-pipeline/src/graph.rs#L681), [`core/dr-pipeline/src/mask.rs:151`](../core/dr-pipeline/src/mask.rs#L151), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:535`](../core/dr-pipeline/src/operation.rs#L535), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:210`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L210), [`core/dr-pipeline/src/ops/curve.rs:100`](../core/dr-pipeline/src/ops/curve.rs#L100), [`core/dr-pipeline/src/ops/curve.rs:1`](../core/dr-pipeline/src/ops/curve.rs#L1), [`core/dr-pipeline/src/ops/curve.rs:219`](../core/dr-pipeline/src/ops/curve.rs#L219), [`core/dr-pipeline/src/ops/curve.rs:635`](../core/dr-pipeline/src/ops/curve.rs#L635), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:1`](../core/dr-pipeline/src/ops/noise_reduction.rs#L1), [`core/dr-pipeline/src/ops/noise_reduction.rs:273`](../core/dr-pipeline/src/ops/noise_reduction.rs#L273), [`core/dr-pipeline/src/sidecar.rs:1048`](../core/dr-pipeline/src/sidecar.rs#L1048), [`core/dr-pipeline/src/sidecar.rs:158`](../core/dr-pipeline/src/sidecar.rs#L158), [`core/dr-pipeline/src/sidecar.rs:1714`](../core/dr-pipeline/src/sidecar.rs#L1714), [`core/dr-pipeline/src/sidecar.rs:1774`](../core/dr-pipeline/src/sidecar.rs#L1774), [`core/dr-pipeline/tests/tone_curve.rs:1`](../core/dr-pipeline/tests/tone_curve.rs#L1), [`core/dr-segment/src/refine.rs:850`](../core/dr-segment/src/refine.rs#L850), [`ui/dr-ui/src/develop.rs:103`](../ui/dr-ui/src/develop.rs#L103), [`ui/dr-ui/src/develop.rs:1506`](../ui/dr-ui/src/develop.rs#L1506), [`ui/dr-ui/src/develop.rs:165`](../ui/dr-ui/src/develop.rs#L165), [`ui/dr-ui/src/develop.rs:1922`](../ui/dr-ui/src/develop.rs#L1922), [`ui/dr-ui/src/develop.rs:2136`](../ui/dr-ui/src/develop.rs#L2136), [`ui/dr-ui/src/develop.rs:2154`](../ui/dr-ui/src/develop.rs#L2154), [`ui/dr-ui/src/develop.rs:2168`](../ui/dr-ui/src/develop.rs#L2168), [`ui/dr-ui/src/develop.rs:2190`](../ui/dr-ui/src/develop.rs#L2190), [`ui/dr-ui/src/develop.rs:2336`](../ui/dr-ui/src/develop.rs#L2336), [`ui/dr-ui/src/develop.rs:2434`](../ui/dr-ui/src/develop.rs#L2434), [`ui/dr-ui/src/develop.rs:328`](../ui/dr-ui/src/develop.rs#L328), [`ui/dr-ui/src/develop.rs:365`](../ui/dr-ui/src/develop.rs#L365), [`ui/dr-ui/src/develop.rs:3855`](../ui/dr-ui/src/develop.rs#L3855), [`ui/dr-ui/src/develop.rs:3885`](../ui/dr-ui/src/develop.rs#L3885), [`ui/dr-ui/src/develop.rs:3951`](../ui/dr-ui/src/develop.rs#L3951), [`ui/dr-ui/src/develop.rs:3965`](../ui/dr-ui/src/develop.rs#L3965), [`ui/dr-ui/src/develop.rs:4157`](../ui/dr-ui/src/develop.rs#L4157), [`ui/dr-ui/src/develop.rs:4817`](../ui/dr-ui/src/develop.rs#L4817), [`ui/dr-ui/src/develop.rs:4938`](../ui/dr-ui/src/develop.rs#L4938), [`ui/dr-ui/src/develop.rs:5094`](../ui/dr-ui/src/develop.rs#L5094), [`ui/dr-ui/src/develop.rs:5230`](../ui/dr-ui/src/develop.rs#L5230), [`ui/dr-ui/src/develop.rs:5274`](../ui/dr-ui/src/develop.rs#L5274), [`ui/dr-ui/src/develop.rs:5324`](../ui/dr-ui/src/develop.rs#L5324), [`ui/dr-ui/src/develop.rs:588`](../ui/dr-ui/src/develop.rs#L588), [`ui/dr-ui/src/develop.rs:649`](../ui/dr-ui/src/develop.rs#L649), [`ui/dr-ui/src/develop.rs:795`](../ui/dr-ui/src/develop.rs#L795), [`ui/dr-ui/src/develop.rs:842`](../ui/dr-ui/src/develop.rs#L842), [`ui/dr-ui/src/develop.rs:871`](../ui/dr-ui/src/develop.rs#L871), [`ui/dr-ui/src/lib.rs:1696`](../ui/dr-ui/src/lib.rs#L1696), [`ui/dr-ui/src/lib.rs:2498`](../ui/dr-ui/src/lib.rs#L2498), [`ui/dr-ui/src/lib.rs:2694`](../ui/dr-ui/src/lib.rs#L2694), [`ui/dr-ui/src/lib.rs:2866`](../ui/dr-ui/src/lib.rs#L2866), [`ui/dr-ui/src/lib.rs:2930`](../ui/dr-ui/src/lib.rs#L2930), [`ui/dr-ui/src/lib.rs:2984`](../ui/dr-ui/src/lib.rs#L2984), [`ui/dr-ui/src/lib.rs:389`](../ui/dr-ui/src/lib.rs#L389), [`ui/dr-ui/src/lib.rs:432`](../ui/dr-ui/src/lib.rs#L432), [`ui/dr-ui/src/lib.rs:455`](../ui/dr-ui/src/lib.rs#L455), [`ui/dr-ui/src/library.rs:539`](../ui/dr-ui/src/library.rs#L539), [`ui/dr-ui/src/masks_ui.rs:249`](../ui/dr-ui/src/masks_ui.rs#L249), [`ui/dr-ui/src/masks_ui.rs:41`](../ui/dr-ui/src/masks_ui.rs#L41), [`ui/dr-ui/src/masks_ui.rs:884`](../ui/dr-ui/src/masks_ui.rs#L884), [`ui/dr-ui/src/masks_ui.rs:998`](../ui/dr-ui/src/masks_ui.rs#L998), [`ui/dr-ui/src/presets.rs:394`](../ui/dr-ui/src/presets.rs#L394), [`ui/dr-ui/src/segmentation.rs:116`](../ui/dr-ui/src/segmentation.rs#L116), [`ui/dr-ui/src/segmentation.rs:330`](../ui/dr-ui/src/segmentation.rs#L330), [`ui/dr-ui/src/segmentation.rs:346`](../ui/dr-ui/src/segmentation.rs#L346), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476), [`ui/dr-ui/src/segmentation.rs:504`](../ui/dr-ui/src/segmentation.rs#L504), [`ui/dr-ui/ui/adjust.slint:547`](../ui/dr-ui/ui/adjust.slint#L547), [`ui/dr-ui/ui/adjust.slint:666`](../ui/dr-ui/ui/adjust.slint#L666), [`ui/dr-ui/ui/app.slint:150`](../ui/dr-ui/ui/app.slint#L150), [`ui/dr-ui/ui/app.slint:196`](../ui/dr-ui/ui/app.slint#L196), [`ui/dr-ui/ui/app.slint:2046`](../ui/dr-ui/ui/app.slint#L2046), [`ui/dr-ui/ui/app.slint:984`](../ui/dr-ui/ui/app.slint#L984), [`ui/dr-ui/ui/masks.slint:612`](../ui/dr-ui/ui/masks.slint#L612) | +| FR-DEV-3a | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/descriptor.rs:194`](../core/dr-pipeline/src/descriptor.rs#L194), [`core/dr-pipeline/src/descriptor.rs:234`](../core/dr-pipeline/src/descriptor.rs#L234), [`core/dr-pipeline/src/descriptor.rs:258`](../core/dr-pipeline/src/descriptor.rs#L258), [`core/dr-pipeline/src/descriptor.rs:313`](../core/dr-pipeline/src/descriptor.rs#L313), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:24`](../core/dr-pipeline/src/graph.rs#L24), [`core/dr-pipeline/src/graph.rs:287`](../core/dr-pipeline/src/graph.rs#L287), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/graph.rs:59`](../core/dr-pipeline/src/graph.rs#L59), [`core/dr-pipeline/src/mask.rs:1108`](../core/dr-pipeline/src/mask.rs#L1108), [`core/dr-pipeline/src/operation.rs:232`](../core/dr-pipeline/src/operation.rs#L232), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365), [`core/dr-pipeline/src/ops/curve.rs:319`](../core/dr-pipeline/src/ops/curve.rs#L319), [`ui/dr-ui/src/develop.rs:1403`](../ui/dr-ui/src/develop.rs#L1403), [`ui/dr-ui/src/lib.rs:749`](../ui/dr-ui/src/lib.rs#L749), [`ui/dr-ui/tests/ui_names_no_operation.rs:1`](../ui/dr-ui/tests/ui_names_no_operation.rs#L1) | | FR-DEV-3b | [`core/dr-pipeline/src/descriptor.rs:258`](../core/dr-pipeline/src/descriptor.rs#L258), [`core/dr-pipeline/src/framing.rs:395`](../core/dr-pipeline/src/framing.rs#L395), [`core/dr-pipeline/src/graph.rs:59`](../core/dr-pipeline/src/graph.rs#L59), [`core/dr-pipeline/src/operation.rs:365`](../core/dr-pipeline/src/operation.rs#L365) | -| FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:251`](../core/dr-pipeline/src/graph.rs#L251), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/mask.rs:1108`](../core/dr-pipeline/src/mask.rs#L1108), [`ui/dr-ui/src/develop.rs:5903`](../ui/dr-ui/src/develop.rs#L5903) | -| FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:104`](../core/dr-gpu/src/adjust.rs#L104), [`core/dr-gpu/src/adjust.rs:1079`](../core/dr-gpu/src/adjust.rs#L1079), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/src/adjust.rs:986`](../core/dr-gpu/src/adjust.rs#L986), [`core/dr-gpu/tests/capture_sharpen.rs:434`](../core/dr-gpu/tests/capture_sharpen.rs#L434), [`core/dr-gpu/tests/detail_stage.rs:242`](../core/dr-gpu/tests/detail_stage.rs#L242), [`core/dr-gpu/tests/local_contrast.rs:558`](../core/dr-gpu/tests/local_contrast.rs#L558), [`core/dr-gpu/tests/noise_reduction.rs:556`](../core/dr-gpu/tests/noise_reduction.rs#L556), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/graph.rs:617`](../core/dr-pipeline/src/graph.rs#L617), [`core/dr-pipeline/src/operation.rs:32`](../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:389`](../core/dr-pipeline/src/operation.rs#L389), [`core/dr-pipeline/src/operation.rs:53`](../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../core/dr-pipeline/src/operation.rs#L71) | -| FR-DEV-3e | [`core/dr-decode/src/base_curve.rs:145`](../core/dr-decode/src/base_curve.rs#L145), [`core/dr-decode/src/base_curve.rs:158`](../core/dr-decode/src/base_curve.rs#L158), [`core/dr-decode/src/base_curve.rs:1`](../core/dr-decode/src/base_curve.rs#L1), [`core/dr-decode/src/base_curve.rs:267`](../core/dr-decode/src/base_curve.rs#L267), [`core/dr-decode/src/base_curve.rs:347`](../core/dr-decode/src/base_curve.rs#L347), [`core/dr-decode/src/base_curve.rs:55`](../core/dr-decode/src/base_curve.rs#L55), [`core/dr-decode/src/lib.rs:121`](../core/dr-decode/src/lib.rs#L121), [`core/dr-decode/src/lib.rs:708`](../core/dr-decode/src/lib.rs#L708), [`core/dr-decode/src/lib.rs:748`](../core/dr-decode/src/lib.rs#L748), [`core/dr-decode/src/profile.rs:102`](../core/dr-decode/src/profile.rs#L102), [`core/dr-decode/src/profile.rs:151`](../core/dr-decode/src/profile.rs#L151), [`core/dr-decode/src/profile.rs:1`](../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:235`](../core/dr-decode/src/profile.rs#L235), [`core/dr-decode/src/profile.rs:286`](../core/dr-decode/src/profile.rs#L286), [`core/dr-decode/src/profile.rs:343`](../core/dr-decode/src/profile.rs#L343), [`core/dr-decode/src/profile.rs:458`](../core/dr-decode/src/profile.rs#L458), [`core/dr-decode/src/profile.rs:492`](../core/dr-decode/src/profile.rs#L492), [`core/dr-decode/src/profile.rs:630`](../core/dr-decode/src/profile.rs#L630), [`core/dr-gpu/src/adjust.rs:37`](../core/dr-gpu/src/adjust.rs#L37), [`core/dr-gpu/src/adjust.rs:967`](../core/dr-gpu/src/adjust.rs#L967), [`core/dr-gpu/src/demosaic.rs:121`](../core/dr-gpu/src/demosaic.rs#L121), [`core/dr-gpu/src/demosaic.rs:86`](../core/dr-gpu/src/demosaic.rs#L86), [`core/dr-gpu/tests/base_curve.rs:1`](../core/dr-gpu/tests/base_curve.rs#L1), [`core/dr-pipeline/src/operation.rs:1529`](../core/dr-pipeline/src/operation.rs#L1529), [`core/dr-pipeline/src/operation.rs:1610`](../core/dr-pipeline/src/operation.rs#L1610), [`core/dr-pipeline/src/operation.rs:1635`](../core/dr-pipeline/src/operation.rs#L1635), [`core/dr-pipeline/src/operation.rs:1650`](../core/dr-pipeline/src/operation.rs#L1650), [`core/dr-pipeline/src/operation.rs:1674`](../core/dr-pipeline/src/operation.rs#L1674), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:440`](../core/dr-pipeline/src/operation.rs#L440), [`core/dr-pipeline/src/operation.rs:450`](../core/dr-pipeline/src/operation.rs#L450), [`core/dr-pipeline/src/operation.rs:600`](../core/dr-pipeline/src/operation.rs#L600) | -| FR-DEV-3f | [`core/dr-film/src/bake.rs:271`](../core/dr-film/src/bake.rs#L271), [`core/dr-film/src/bake.rs:62`](../core/dr-film/src/bake.rs#L62), [`core/dr-film/src/boolean_grain.rs:1`](../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:139`](../core/dr-gpu/src/adjust.rs#L139), [`core/dr-gpu/src/adjust.rs:196`](../core/dr-gpu/src/adjust.rs#L196), [`core/dr-gpu/src/adjust.rs:357`](../core/dr-gpu/src/adjust.rs#L357), [`core/dr-gpu/src/adjust.rs:483`](../core/dr-gpu/src/adjust.rs#L483), [`core/dr-gpu/src/adjust.rs:77`](../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:191`](../core/dr-gpu/tests/film_sim.rs#L191), [`core/dr-gpu/tests/film_sim.rs:1`](../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-pipeline/src/graph.rs:102`](../core/dr-pipeline/src/graph.rs#L102), [`core/dr-pipeline/src/graph.rs:125`](../core/dr-pipeline/src/graph.rs#L125), [`core/dr-pipeline/src/graph.rs:325`](../core/dr-pipeline/src/graph.rs#L325), [`core/dr-pipeline/src/operation.rs:1065`](../core/dr-pipeline/src/operation.rs#L1065), [`core/dr-pipeline/src/operation.rs:1111`](../core/dr-pipeline/src/operation.rs#L1111), [`core/dr-pipeline/src/operation.rs:1529`](../core/dr-pipeline/src/operation.rs#L1529), [`core/dr-pipeline/src/operation.rs:296`](../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:153`](../core/dr-pipeline/src/ops/film_sim.rs#L153), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:331`](../core/dr-pipeline/src/ops/film_sim.rs#L331), [`core/dr-pipeline/src/ops/film_sim.rs:43`](../core/dr-pipeline/src/ops/film_sim.rs#L43), [`core/dr-pipeline/src/ops/film_sim.rs:87`](../core/dr-pipeline/src/ops/film_sim.rs#L87), [`core/dr-pipeline/src/ops/film_sim.rs:92`](../core/dr-pipeline/src/ops/film_sim.rs#L92), [`core/dr-pipeline/src/sidecar.rs:113`](../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:169`](../core/dr-pipeline/src/sidecar.rs#L169), [`core/dr-pipeline/src/sidecar.rs:2060`](../core/dr-pipeline/src/sidecar.rs#L2060), [`core/dr-pipeline/src/sidecar.rs:2136`](../core/dr-pipeline/src/sidecar.rs#L2136), [`core/dr-pipeline/src/sidecar.rs:535`](../core/dr-pipeline/src/sidecar.rs#L535), [`core/dr-pipeline/src/sidecar.rs:662`](../core/dr-pipeline/src/sidecar.rs#L662), [`core/dr-pipeline/src/sidecar.rs:794`](../core/dr-pipeline/src/sidecar.rs#L794), [`core/dr-pipeline/src/state.rs:100`](../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop.rs:3602`](../ui/dr-ui/src/develop.rs#L3602), [`ui/dr-ui/src/develop.rs:3619`](../ui/dr-ui/src/develop.rs#L3619), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:3669`](../ui/dr-ui/src/develop.rs#L3669), [`ui/dr-ui/src/develop.rs:3678`](../ui/dr-ui/src/develop.rs#L3678), [`ui/dr-ui/src/develop.rs:3781`](../ui/dr-ui/src/develop.rs#L3781), [`ui/dr-ui/src/develop.rs:4194`](../ui/dr-ui/src/develop.rs#L4194), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/lib.rs:2472`](../ui/dr-ui/src/lib.rs#L2472), [`ui/dr-ui/src/lib.rs:682`](../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/lib.rs:740`](../ui/dr-ui/src/lib.rs#L740), [`ui/dr-ui/src/library.rs:530`](../ui/dr-ui/src/library.rs#L530), [`ui/dr-ui/src/library.rs:778`](../ui/dr-ui/src/library.rs#L778), [`ui/dr-ui/src/presets.rs:402`](../ui/dr-ui/src/presets.rs#L402), [`ui/dr-ui/ui/adjust.slint:1072`](../ui/dr-ui/ui/adjust.slint#L1072), [`ui/dr-ui/ui/adjust.slint:996`](../ui/dr-ui/ui/adjust.slint#L996), [`ui/dr-ui/ui/app.slint:2647`](../ui/dr-ui/ui/app.slint#L2647), [`ui/dr-ui/ui/app.slint:712`](../ui/dr-ui/ui/app.slint#L712) | +| FR-DEV-3c | [`core/dr-pipeline/ops/exposure.yaml:1`](../core/dr-pipeline/ops/exposure.yaml#L1), [`core/dr-pipeline/src/graph.rs:287`](../core/dr-pipeline/src/graph.rs#L287), [`core/dr-pipeline/src/graph.rs:46`](../core/dr-pipeline/src/graph.rs#L46), [`core/dr-pipeline/src/mask.rs:1108`](../core/dr-pipeline/src/mask.rs#L1108), [`ui/dr-ui/src/develop.rs:5903`](../ui/dr-ui/src/develop.rs#L5903) | +| FR-DEV-3d | [`core/dr-gpu/src/adjust.rs:104`](../core/dr-gpu/src/adjust.rs#L104), [`core/dr-gpu/src/adjust.rs:1079`](../core/dr-gpu/src/adjust.rs#L1079), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/adjust.rs:84`](../core/dr-gpu/src/adjust.rs#L84), [`core/dr-gpu/src/adjust.rs:986`](../core/dr-gpu/src/adjust.rs#L986), [`core/dr-gpu/tests/capture_sharpen.rs:434`](../core/dr-gpu/tests/capture_sharpen.rs#L434), [`core/dr-gpu/tests/detail_stage.rs:242`](../core/dr-gpu/tests/detail_stage.rs#L242), [`core/dr-gpu/tests/local_contrast.rs:558`](../core/dr-gpu/tests/local_contrast.rs#L558), [`core/dr-gpu/tests/noise_reduction.rs:556`](../core/dr-gpu/tests/noise_reduction.rs#L556), [`core/dr-pipeline/src/framing.rs:314`](../core/dr-pipeline/src/framing.rs#L314), [`core/dr-pipeline/src/graph.rs:720`](../core/dr-pipeline/src/graph.rs#L720), [`core/dr-pipeline/src/operation.rs:32`](../core/dr-pipeline/src/operation.rs#L32), [`core/dr-pipeline/src/operation.rs:403`](../core/dr-pipeline/src/operation.rs#L403), [`core/dr-pipeline/src/operation.rs:53`](../core/dr-pipeline/src/operation.rs#L53), [`core/dr-pipeline/src/operation.rs:71`](../core/dr-pipeline/src/operation.rs#L71) | +| FR-DEV-3e | [`core/dr-decode/src/base_curve.rs:145`](../core/dr-decode/src/base_curve.rs#L145), [`core/dr-decode/src/base_curve.rs:158`](../core/dr-decode/src/base_curve.rs#L158), [`core/dr-decode/src/base_curve.rs:1`](../core/dr-decode/src/base_curve.rs#L1), [`core/dr-decode/src/base_curve.rs:267`](../core/dr-decode/src/base_curve.rs#L267), [`core/dr-decode/src/base_curve.rs:347`](../core/dr-decode/src/base_curve.rs#L347), [`core/dr-decode/src/base_curve.rs:55`](../core/dr-decode/src/base_curve.rs#L55), [`core/dr-decode/src/lib.rs:121`](../core/dr-decode/src/lib.rs#L121), [`core/dr-decode/src/lib.rs:708`](../core/dr-decode/src/lib.rs#L708), [`core/dr-decode/src/lib.rs:748`](../core/dr-decode/src/lib.rs#L748), [`core/dr-decode/src/profile.rs:102`](../core/dr-decode/src/profile.rs#L102), [`core/dr-decode/src/profile.rs:151`](../core/dr-decode/src/profile.rs#L151), [`core/dr-decode/src/profile.rs:1`](../core/dr-decode/src/profile.rs#L1), [`core/dr-decode/src/profile.rs:235`](../core/dr-decode/src/profile.rs#L235), [`core/dr-decode/src/profile.rs:286`](../core/dr-decode/src/profile.rs#L286), [`core/dr-decode/src/profile.rs:343`](../core/dr-decode/src/profile.rs#L343), [`core/dr-decode/src/profile.rs:458`](../core/dr-decode/src/profile.rs#L458), [`core/dr-decode/src/profile.rs:492`](../core/dr-decode/src/profile.rs#L492), [`core/dr-decode/src/profile.rs:630`](../core/dr-decode/src/profile.rs#L630), [`core/dr-gpu/src/adjust.rs:37`](../core/dr-gpu/src/adjust.rs#L37), [`core/dr-gpu/src/adjust.rs:967`](../core/dr-gpu/src/adjust.rs#L967), [`core/dr-gpu/src/demosaic.rs:121`](../core/dr-gpu/src/demosaic.rs#L121), [`core/dr-gpu/src/demosaic.rs:86`](../core/dr-gpu/src/demosaic.rs#L86), [`core/dr-gpu/tests/base_curve.rs:1`](../core/dr-gpu/tests/base_curve.rs#L1), [`core/dr-pipeline/src/operation.rs:1762`](../core/dr-pipeline/src/operation.rs#L1762), [`core/dr-pipeline/src/operation.rs:1843`](../core/dr-pipeline/src/operation.rs#L1843), [`core/dr-pipeline/src/operation.rs:1868`](../core/dr-pipeline/src/operation.rs#L1868), [`core/dr-pipeline/src/operation.rs:1883`](../core/dr-pipeline/src/operation.rs#L1883), [`core/dr-pipeline/src/operation.rs:1907`](../core/dr-pipeline/src/operation.rs#L1907), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/operation.rs:454`](../core/dr-pipeline/src/operation.rs#L454), [`core/dr-pipeline/src/operation.rs:464`](../core/dr-pipeline/src/operation.rs#L464), [`core/dr-pipeline/src/operation.rs:625`](../core/dr-pipeline/src/operation.rs#L625) | +| FR-DEV-3f | [`core/dr-film/src/bake.rs:271`](../core/dr-film/src/bake.rs#L271), [`core/dr-film/src/bake.rs:62`](../core/dr-film/src/bake.rs#L62), [`core/dr-film/src/boolean_grain.rs:1`](../core/dr-film/src/boolean_grain.rs#L1), [`core/dr-film/src/boolean_grain.rs:78`](../core/dr-film/src/boolean_grain.rs#L78), [`core/dr-film/src/grain.rs:140`](../core/dr-film/src/grain.rs#L140), [`core/dr-film/src/grain.rs:1`](../core/dr-film/src/grain.rs#L1), [`core/dr-film/src/grain.rs:302`](../core/dr-film/src/grain.rs#L302), [`core/dr-film/src/grain.rs:79`](../core/dr-film/src/grain.rs#L79), [`core/dr-film/src/lib.rs:160`](../core/dr-film/src/lib.rs#L160), [`core/dr-film/src/lib.rs:1`](../core/dr-film/src/lib.rs#L1), [`core/dr-film/src/profile.rs:100`](../core/dr-film/src/profile.rs#L100), [`core/dr-film/src/profile.rs:142`](../core/dr-film/src/profile.rs#L142), [`core/dr-film/src/profile.rs:182`](../core/dr-film/src/profile.rs#L182), [`core/dr-film/src/profile.rs:259`](../core/dr-film/src/profile.rs#L259), [`core/dr-film/src/profile.rs:502`](../core/dr-film/src/profile.rs#L502), [`core/dr-film/src/profile.rs:73`](../core/dr-film/src/profile.rs#L73), [`core/dr-gpu/src/adjust.rs:139`](../core/dr-gpu/src/adjust.rs#L139), [`core/dr-gpu/src/adjust.rs:196`](../core/dr-gpu/src/adjust.rs#L196), [`core/dr-gpu/src/adjust.rs:357`](../core/dr-gpu/src/adjust.rs#L357), [`core/dr-gpu/src/adjust.rs:483`](../core/dr-gpu/src/adjust.rs#L483), [`core/dr-gpu/src/adjust.rs:77`](../core/dr-gpu/src/adjust.rs#L77), [`core/dr-gpu/tests/film_sim.rs:191`](../core/dr-gpu/tests/film_sim.rs#L191), [`core/dr-gpu/tests/film_sim.rs:1`](../core/dr-gpu/tests/film_sim.rs#L1), [`core/dr-pipeline/src/graph.rs:102`](../core/dr-pipeline/src/graph.rs#L102), [`core/dr-pipeline/src/graph.rs:139`](../core/dr-pipeline/src/graph.rs#L139), [`core/dr-pipeline/src/graph.rs:394`](../core/dr-pipeline/src/graph.rs#L394), [`core/dr-pipeline/src/operation.rs:1137`](../core/dr-pipeline/src/operation.rs#L1137), [`core/dr-pipeline/src/operation.rs:1165`](../core/dr-pipeline/src/operation.rs#L1165), [`core/dr-pipeline/src/operation.rs:1211`](../core/dr-pipeline/src/operation.rs#L1211), [`core/dr-pipeline/src/operation.rs:1762`](../core/dr-pipeline/src/operation.rs#L1762), [`core/dr-pipeline/src/operation.rs:296`](../core/dr-pipeline/src/operation.rs#L296), [`core/dr-pipeline/src/operation.rs:310`](../core/dr-pipeline/src/operation.rs#L310), [`core/dr-pipeline/src/ops/film_sim.rs:129`](../core/dr-pipeline/src/ops/film_sim.rs#L129), [`core/dr-pipeline/src/ops/film_sim.rs:153`](../core/dr-pipeline/src/ops/film_sim.rs#L153), [`core/dr-pipeline/src/ops/film_sim.rs:1`](../core/dr-pipeline/src/ops/film_sim.rs#L1), [`core/dr-pipeline/src/ops/film_sim.rs:331`](../core/dr-pipeline/src/ops/film_sim.rs#L331), [`core/dr-pipeline/src/ops/film_sim.rs:43`](../core/dr-pipeline/src/ops/film_sim.rs#L43), [`core/dr-pipeline/src/ops/film_sim.rs:87`](../core/dr-pipeline/src/ops/film_sim.rs#L87), [`core/dr-pipeline/src/ops/film_sim.rs:92`](../core/dr-pipeline/src/ops/film_sim.rs#L92), [`core/dr-pipeline/src/sidecar.rs:113`](../core/dr-pipeline/src/sidecar.rs#L113), [`core/dr-pipeline/src/sidecar.rs:169`](../core/dr-pipeline/src/sidecar.rs#L169), [`core/dr-pipeline/src/sidecar.rs:2060`](../core/dr-pipeline/src/sidecar.rs#L2060), [`core/dr-pipeline/src/sidecar.rs:2136`](../core/dr-pipeline/src/sidecar.rs#L2136), [`core/dr-pipeline/src/sidecar.rs:535`](../core/dr-pipeline/src/sidecar.rs#L535), [`core/dr-pipeline/src/sidecar.rs:662`](../core/dr-pipeline/src/sidecar.rs#L662), [`core/dr-pipeline/src/sidecar.rs:794`](../core/dr-pipeline/src/sidecar.rs#L794), [`core/dr-pipeline/src/state.rs:100`](../core/dr-pipeline/src/state.rs#L100), [`core/dr-pipeline/src/state.rs:115`](../core/dr-pipeline/src/state.rs#L115), [`core/dr-pipeline/src/state.rs:60`](../core/dr-pipeline/src/state.rs#L60), [`ui/dr-ui/src/develop.rs:3602`](../ui/dr-ui/src/develop.rs#L3602), [`ui/dr-ui/src/develop.rs:3619`](../ui/dr-ui/src/develop.rs#L3619), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:3669`](../ui/dr-ui/src/develop.rs#L3669), [`ui/dr-ui/src/develop.rs:3678`](../ui/dr-ui/src/develop.rs#L3678), [`ui/dr-ui/src/develop.rs:3781`](../ui/dr-ui/src/develop.rs#L3781), [`ui/dr-ui/src/develop.rs:4194`](../ui/dr-ui/src/develop.rs#L4194), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/lib.rs:2472`](../ui/dr-ui/src/lib.rs#L2472), [`ui/dr-ui/src/lib.rs:682`](../ui/dr-ui/src/lib.rs#L682), [`ui/dr-ui/src/lib.rs:740`](../ui/dr-ui/src/lib.rs#L740), [`ui/dr-ui/src/library.rs:530`](../ui/dr-ui/src/library.rs#L530), [`ui/dr-ui/src/library.rs:778`](../ui/dr-ui/src/library.rs#L778), [`ui/dr-ui/src/presets.rs:402`](../ui/dr-ui/src/presets.rs#L402), [`ui/dr-ui/ui/adjust.slint:1072`](../ui/dr-ui/ui/adjust.slint#L1072), [`ui/dr-ui/ui/adjust.slint:996`](../ui/dr-ui/ui/adjust.slint#L996), [`ui/dr-ui/ui/app.slint:2647`](../ui/dr-ui/ui/app.slint#L2647), [`ui/dr-ui/ui/app.slint:712`](../ui/dr-ui/ui/app.slint#L712) | | FR-DEV-3h | [`core/dr-decode/src/lib.rs:404`](../core/dr-decode/src/lib.rs#L404), [`core/dr-decode/src/preview.rs:29`](../core/dr-decode/src/preview.rs#L29), [`core/dr-pipeline/src/framing.rs:1067`](../core/dr-pipeline/src/framing.rs#L1067), [`core/dr-pipeline/src/framing.rs:328`](../core/dr-pipeline/src/framing.rs#L328), [`core/dr-pipeline/src/framing.rs:498`](../core/dr-pipeline/src/framing.rs#L498), [`core/dr-types/src/lib.rs:339`](../core/dr-types/src/lib.rs#L339), [`core/dr-types/src/lib.rs:447`](../core/dr-types/src/lib.rs#L447), [`core/dr-types/src/lib.rs:459`](../core/dr-types/src/lib.rs#L459), [`core/dr-types/src/lib.rs:475`](../core/dr-types/src/lib.rs#L475), [`ui/dr-ui/src/develop.rs:140`](../ui/dr-ui/src/develop.rs#L140), [`ui/dr-ui/src/develop.rs:2353`](../ui/dr-ui/src/develop.rs#L2353), [`ui/dr-ui/src/segmentation.rs:476`](../ui/dr-ui/src/segmentation.rs#L476) | | FR-DEV-4 | [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:351`](../core/dr-gpu/src/lib.rs#L351), [`ui/dr-ui/ui/crop.slint:1`](../ui/dr-ui/ui/crop.slint#L1) | -| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:346`](../core/dr-pipeline/src/graph.rs#L346), [`core/dr-pipeline/src/graph.rs:385`](../core/dr-pipeline/src/graph.rs#L385), [`core/dr-pipeline/src/history.rs:102`](../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/develop.rs:4239`](../ui/dr-ui/src/develop.rs#L4239), [`ui/dr-ui/src/develop.rs:4252`](../ui/dr-ui/src/develop.rs#L4252), [`ui/dr-ui/src/develop.rs:4264`](../ui/dr-ui/src/develop.rs#L4264), [`ui/dr-ui/src/develop.rs:4280`](../ui/dr-ui/src/develop.rs#L4280), [`ui/dr-ui/src/develop.rs:4312`](../ui/dr-ui/src/develop.rs#L4312), [`ui/dr-ui/src/develop.rs:4316`](../ui/dr-ui/src/develop.rs#L4316), [`ui/dr-ui/src/develop.rs:4335`](../ui/dr-ui/src/develop.rs#L4335), [`ui/dr-ui/src/develop.rs:4351`](../ui/dr-ui/src/develop.rs#L4351), [`ui/dr-ui/src/develop.rs:738`](../ui/dr-ui/src/develop.rs#L738), [`ui/dr-ui/src/labels.rs:12`](../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:225`](../ui/dr-ui/src/labels.rs#L225), [`ui/dr-ui/src/lib.rs:1631`](../ui/dr-ui/src/lib.rs#L1631), [`ui/dr-ui/src/lib.rs:1674`](../ui/dr-ui/src/lib.rs#L1674), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/src/lib.rs:2668`](../ui/dr-ui/src/lib.rs#L2668), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) | +| FR-DEV-5 | [`core/dr-pipeline/src/graph.rs:415`](../core/dr-pipeline/src/graph.rs#L415), [`core/dr-pipeline/src/graph.rs:459`](../core/dr-pipeline/src/graph.rs#L459), [`core/dr-pipeline/src/history.rs:102`](../core/dr-pipeline/src/history.rs#L102), [`core/dr-pipeline/src/history.rs:110`](../core/dr-pipeline/src/history.rs#L110), [`core/dr-pipeline/src/history.rs:127`](../core/dr-pipeline/src/history.rs#L127), [`core/dr-pipeline/src/history.rs:184`](../core/dr-pipeline/src/history.rs#L184), [`core/dr-pipeline/src/history.rs:1`](../core/dr-pipeline/src/history.rs#L1), [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:234`](../core/dr-pipeline/src/history.rs#L234), [`core/dr-pipeline/src/history.rs:293`](../core/dr-pipeline/src/history.rs#L293), [`core/dr-pipeline/src/history.rs:479`](../core/dr-pipeline/src/history.rs#L479), [`core/dr-pipeline/src/history.rs:489`](../core/dr-pipeline/src/history.rs#L489), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`core/dr-pipeline/src/history.rs:86`](../core/dr-pipeline/src/history.rs#L86), [`core/dr-pipeline/src/state.rs:1`](../core/dr-pipeline/src/state.rs#L1), [`core/dr-pipeline/src/state.rs:75`](../core/dr-pipeline/src/state.rs#L75), [`ui/dr-ui/src/develop.rs:3631`](../ui/dr-ui/src/develop.rs#L3631), [`ui/dr-ui/src/develop.rs:4209`](../ui/dr-ui/src/develop.rs#L4209), [`ui/dr-ui/src/develop.rs:4239`](../ui/dr-ui/src/develop.rs#L4239), [`ui/dr-ui/src/develop.rs:4252`](../ui/dr-ui/src/develop.rs#L4252), [`ui/dr-ui/src/develop.rs:4264`](../ui/dr-ui/src/develop.rs#L4264), [`ui/dr-ui/src/develop.rs:4280`](../ui/dr-ui/src/develop.rs#L4280), [`ui/dr-ui/src/develop.rs:4312`](../ui/dr-ui/src/develop.rs#L4312), [`ui/dr-ui/src/develop.rs:4316`](../ui/dr-ui/src/develop.rs#L4316), [`ui/dr-ui/src/develop.rs:4335`](../ui/dr-ui/src/develop.rs#L4335), [`ui/dr-ui/src/develop.rs:4351`](../ui/dr-ui/src/develop.rs#L4351), [`ui/dr-ui/src/develop.rs:738`](../ui/dr-ui/src/develop.rs#L738), [`ui/dr-ui/src/labels.rs:12`](../ui/dr-ui/src/labels.rs#L12), [`ui/dr-ui/src/labels.rs:231`](../ui/dr-ui/src/labels.rs#L231), [`ui/dr-ui/src/lib.rs:1631`](../ui/dr-ui/src/lib.rs#L1631), [`ui/dr-ui/src/lib.rs:1674`](../ui/dr-ui/src/lib.rs#L1674), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/src/lib.rs:2668`](../ui/dr-ui/src/lib.rs#L2668), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) | | FR-DEV-6 | [`core/dr-pipeline/src/preset.rs:1`](../core/dr-pipeline/src/preset.rs#L1), [`core/dr-pipeline/src/preset.rs:381`](../core/dr-pipeline/src/preset.rs#L381), [`core/dr-pipeline/src/preset.rs:414`](../core/dr-pipeline/src/preset.rs#L414), [`core/dr-pipeline/src/starter.rs:1`](../core/dr-pipeline/src/starter.rs#L1), [`core/dr-preset-xmp/src/lib.rs:1`](../core/dr-preset-xmp/src/lib.rs#L1), [`core/dr-types/src/settings.rs:272`](../core/dr-types/src/settings.rs#L272), [`ui/dr-ui/src/develop.rs:4151`](../ui/dr-ui/src/develop.rs#L4151), [`ui/dr-ui/src/develop.rs:4172`](../ui/dr-ui/src/develop.rs#L4172), [`ui/dr-ui/src/lib.rs:1598`](../ui/dr-ui/src/lib.rs#L1598), [`ui/dr-ui/src/lib.rs:2283`](../ui/dr-ui/src/lib.rs#L2283), [`ui/dr-ui/src/lib.rs:2312`](../ui/dr-ui/src/lib.rs#L2312), [`ui/dr-ui/src/library.rs:1923`](../ui/dr-ui/src/library.rs#L1923), [`ui/dr-ui/src/library.rs:492`](../ui/dr-ui/src/library.rs#L492), [`ui/dr-ui/src/library.rs:520`](../ui/dr-ui/src/library.rs#L520), [`ui/dr-ui/src/library_ui.rs:3185`](../ui/dr-ui/src/library_ui.rs#L3185), [`ui/dr-ui/src/library_ui.rs:3585`](../ui/dr-ui/src/library_ui.rs#L3585), [`ui/dr-ui/src/library_ui.rs:554`](../ui/dr-ui/src/library_ui.rs#L554), [`ui/dr-ui/src/preset_store.rs:1`](../ui/dr-ui/src/preset_store.rs#L1), [`ui/dr-ui/src/presets.rs:1`](../ui/dr-ui/src/presets.rs#L1), [`ui/dr-ui/src/presets.rs:664`](../ui/dr-ui/src/presets.rs#L664), [`ui/dr-ui/src/presets.rs:698`](../ui/dr-ui/src/presets.rs#L698), [`ui/dr-ui/ui/adjust.slint:740`](../ui/dr-ui/ui/adjust.slint#L740), [`ui/dr-ui/ui/adjust.slint:767`](../ui/dr-ui/ui/adjust.slint#L767), [`ui/dr-ui/ui/adjust.slint:801`](../ui/dr-ui/ui/adjust.slint#L801), [`ui/dr-ui/ui/app.slint:1599`](../ui/dr-ui/ui/app.slint#L1599), [`ui/dr-ui/ui/app.slint:2736`](../ui/dr-ui/ui/app.slint#L2736), [`ui/dr-ui/ui/app.slint:784`](../ui/dr-ui/ui/app.slint#L784), [`ui/dr-ui/ui/app.slint:795`](../ui/dr-ui/ui/app.slint#L795), [`ui/dr-ui/ui/library.slint:1564`](../ui/dr-ui/ui/library.slint#L1564), [`ui/dr-ui/ui/library.slint:1570`](../ui/dr-ui/ui/library.slint#L1570), [`ui/dr-ui/ui/library.slint:4117`](../ui/dr-ui/ui/library.slint#L4117), [`ui/dr-ui/ui/library.slint:4132`](../ui/dr-ui/ui/library.slint#L4132), [`ui/dr-ui/ui/presets.slint:105`](../ui/dr-ui/ui/presets.slint#L105), [`ui/dr-ui/ui/presets.slint:113`](../ui/dr-ui/ui/presets.slint#L113), [`ui/dr-ui/ui/presets.slint:19`](../ui/dr-ui/ui/presets.slint#L19), [`ui/dr-ui/ui/presets.slint:276`](../ui/dr-ui/ui/presets.slint#L276), [`ui/dr-ui/ui/presets.slint:297`](../ui/dr-ui/ui/presets.slint#L297), [`ui/dr-ui/ui/presets.slint:5`](../ui/dr-ui/ui/presets.slint#L5), [`ui/dr-ui/ui/presets.slint:60`](../ui/dr-ui/ui/presets.slint#L60), [`ui/dr-ui/ui/settings.slint:101`](../ui/dr-ui/ui/settings.slint#L101), [`ui/dr-ui/ui/settings.slint:557`](../ui/dr-ui/ui/settings.slint#L557) | | FR-DEV-7 | [`core/dr-pipeline/src/history.rs:214`](../core/dr-pipeline/src/history.rs#L214), [`core/dr-pipeline/src/history.rs:499`](../core/dr-pipeline/src/history.rs#L499), [`core/dr-pipeline/src/history.rs:526`](../core/dr-pipeline/src/history.rs#L526), [`ui/dr-ui/src/develop.rs:4280`](../ui/dr-ui/src/develop.rs#L4280), [`ui/dr-ui/src/develop.rs:4312`](../ui/dr-ui/src/develop.rs#L4312), [`ui/dr-ui/src/lib.rs:1682`](../ui/dr-ui/src/lib.rs#L1682), [`ui/dr-ui/src/lib.rs:2668`](../ui/dr-ui/src/lib.rs#L2668), [`ui/dr-ui/ui/history.slint:1`](../ui/dr-ui/ui/history.slint#L1) | -| FR-DEV-8 | [`core/dr-gpu/src/detail.rs:405`](../core/dr-gpu/src/detail.rs#L405), [`core/dr-gpu/src/detail.rs:623`](../core/dr-gpu/src/detail.rs#L623), [`core/dr-gpu/tests/detail_instances.rs:1`](../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:410`](../core/dr-pipeline/src/detail.rs#L410), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:469`](../core/dr-pipeline/src/detail.rs#L469), [`core/dr-pipeline/src/detail.rs:555`](../core/dr-pipeline/src/detail.rs#L555), [`core/dr-pipeline/src/graph.rs:114`](../core/dr-pipeline/src/graph.rs#L114), [`core/dr-pipeline/src/graph.rs:192`](../core/dr-pipeline/src/graph.rs#L192), [`core/dr-pipeline/src/graph.rs:686`](../core/dr-pipeline/src/graph.rs#L686), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:554`](../core/dr-pipeline/src/operation.rs#L554), [`core/dr-pipeline/src/sidecar.rs:185`](../core/dr-pipeline/src/sidecar.rs#L185), [`core/dr-pipeline/src/sidecar.rs:354`](../core/dr-pipeline/src/sidecar.rs#L354), [`core/dr-pipeline/src/sidecar.rs:674`](../core/dr-pipeline/src/sidecar.rs#L674), [`core/dr-pipeline/src/sidecar.rs:810`](../core/dr-pipeline/src/sidecar.rs#L810), [`core/dr-pipeline/src/sidecar.rs:864`](../core/dr-pipeline/src/sidecar.rs#L864), [`core/dr-pipeline/src/sidecar.rs:894`](../core/dr-pipeline/src/sidecar.rs#L894), [`core/dr-pipeline/src/spot.rs:115`](../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop.rs:2505`](../ui/dr-ui/src/develop.rs#L2505), [`ui/dr-ui/src/develop.rs:2543`](../ui/dr-ui/src/develop.rs#L2543), [`ui/dr-ui/src/develop.rs:2608`](../ui/dr-ui/src/develop.rs#L2608), [`ui/dr-ui/src/develop.rs:2691`](../ui/dr-ui/src/develop.rs#L2691), [`ui/dr-ui/src/develop.rs:2705`](../ui/dr-ui/src/develop.rs#L2705), [`ui/dr-ui/src/develop.rs:825`](../ui/dr-ui/src/develop.rs#L825), [`ui/dr-ui/src/labels.rs:53`](../ui/dr-ui/src/labels.rs#L53), [`ui/dr-ui/src/lib.rs:1703`](../ui/dr-ui/src/lib.rs#L1703), [`ui/dr-ui/src/lib.rs:2786`](../ui/dr-ui/src/lib.rs#L2786), [`ui/dr-ui/src/lib.rs:394`](../ui/dr-ui/src/lib.rs#L394), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/adjust.slint:832`](../ui/dr-ui/ui/adjust.slint#L832), [`ui/dr-ui/ui/app.slint:140`](../ui/dr-ui/ui/app.slint#L140), [`ui/dr-ui/ui/app.slint:1949`](../ui/dr-ui/ui/app.slint#L1949), [`ui/dr-ui/ui/app.slint:2124`](../ui/dr-ui/ui/app.slint#L2124), [`ui/dr-ui/ui/app.slint:2548`](../ui/dr-ui/ui/app.slint#L2548), [`ui/dr-ui/ui/icons.slint:338`](../ui/dr-ui/ui/icons.slint#L338), [`ui/dr-ui/ui/spots.slint:172`](../ui/dr-ui/ui/spots.slint#L172), [`ui/dr-ui/ui/spots.slint:48`](../ui/dr-ui/ui/spots.slint#L48), [`ui/dr-ui/ui/spots.slint:5`](../ui/dr-ui/ui/spots.slint#L5) | -| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:2126`](../core/dr-gpu/src/adjust.rs#L2126), [`core/dr-gpu/src/adjust.rs:2203`](../core/dr-gpu/src/adjust.rs#L2203), [`core/dr-gpu/src/adjust.rs:2288`](../core/dr-gpu/src/adjust.rs#L2288), [`core/dr-gpu/src/adjust.rs:54`](../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:172`](../core/dr-gpu/src/lib.rs#L172), [`core/dr-gpu/src/lib.rs:192`](../core/dr-gpu/src/lib.rs#L192), [`core/dr-gpu/src/lib.rs:70`](../core/dr-gpu/src/lib.rs#L70), [`core/dr-gpu/src/lib.rs:93`](../core/dr-gpu/src/lib.rs#L93), [`core/dr-gpu/tests/capture_sharpen.rs:200`](../core/dr-gpu/tests/capture_sharpen.rs#L200), [`core/dr-gpu/tests/detail_stage.rs:328`](../core/dr-gpu/tests/detail_stage.rs#L328), [`core/dr-gpu/tests/local_contrast.rs:264`](../core/dr-gpu/tests/local_contrast.rs#L264), [`core/dr-gpu/tests/noise_reduction.rs:378`](../core/dr-gpu/tests/noise_reduction.rs#L378), [`core/dr-pipeline/src/detail.rs:136`](../core/dr-pipeline/src/detail.rs#L136), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/graph.rs:548`](../core/dr-pipeline/src/graph.rs#L548), [`core/dr-pipeline/src/graph.rs:578`](../core/dr-pipeline/src/graph.rs#L578), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:659`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L659), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:971`](../core/dr-pipeline/src/ops/local_contrast.rs#L971), [`core/dr-pipeline/src/ops/noise_reduction.rs:700`](../core/dr-pipeline/src/ops/noise_reduction.rs#L700), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop.rs:3139`](../ui/dr-ui/src/develop.rs#L3139), [`ui/dr-ui/src/develop.rs:4606`](../ui/dr-ui/src/develop.rs#L4606), [`ui/dr-ui/src/develop.rs:5448`](../ui/dr-ui/src/develop.rs#L5448), [`ui/dr-ui/src/develop.rs:5482`](../ui/dr-ui/src/develop.rs#L5482), [`ui/dr-ui/src/lib.rs:890`](../ui/dr-ui/src/lib.rs#L890), [`ui/dr-ui/src/lib.rs:93`](../ui/dr-ui/src/lib.rs#L93), [`ui/dr-ui/src/lib.rs:949`](../ui/dr-ui/src/lib.rs#L949) | +| FR-DEV-8 | [`core/dr-gpu/src/detail.rs:405`](../core/dr-gpu/src/detail.rs#L405), [`core/dr-gpu/src/detail.rs:623`](../core/dr-gpu/src/detail.rs#L623), [`core/dr-gpu/tests/detail_instances.rs:1`](../core/dr-gpu/tests/detail_instances.rs#L1), [`core/dr-gpu/tests/spot_removal.rs:1`](../core/dr-gpu/tests/spot_removal.rs#L1), [`core/dr-pipeline/src/detail.rs:410`](../core/dr-pipeline/src/detail.rs#L410), [`core/dr-pipeline/src/detail.rs:434`](../core/dr-pipeline/src/detail.rs#L434), [`core/dr-pipeline/src/detail.rs:469`](../core/dr-pipeline/src/detail.rs#L469), [`core/dr-pipeline/src/detail.rs:555`](../core/dr-pipeline/src/detail.rs#L555), [`core/dr-pipeline/src/graph.rs:114`](../core/dr-pipeline/src/graph.rs#L114), [`core/dr-pipeline/src/graph.rs:216`](../core/dr-pipeline/src/graph.rs#L216), [`core/dr-pipeline/src/graph.rs:805`](../core/dr-pipeline/src/graph.rs#L805), [`core/dr-pipeline/src/operation.rs:330`](../core/dr-pipeline/src/operation.rs#L330), [`core/dr-pipeline/src/operation.rs:579`](../core/dr-pipeline/src/operation.rs#L579), [`core/dr-pipeline/src/sidecar.rs:185`](../core/dr-pipeline/src/sidecar.rs#L185), [`core/dr-pipeline/src/sidecar.rs:354`](../core/dr-pipeline/src/sidecar.rs#L354), [`core/dr-pipeline/src/sidecar.rs:674`](../core/dr-pipeline/src/sidecar.rs#L674), [`core/dr-pipeline/src/sidecar.rs:810`](../core/dr-pipeline/src/sidecar.rs#L810), [`core/dr-pipeline/src/sidecar.rs:864`](../core/dr-pipeline/src/sidecar.rs#L864), [`core/dr-pipeline/src/sidecar.rs:894`](../core/dr-pipeline/src/sidecar.rs#L894), [`core/dr-pipeline/src/spot.rs:115`](../core/dr-pipeline/src/spot.rs#L115), [`core/dr-pipeline/src/spot.rs:151`](../core/dr-pipeline/src/spot.rs#L151), [`core/dr-pipeline/src/spot.rs:1`](../core/dr-pipeline/src/spot.rs#L1), [`core/dr-pipeline/src/spot.rs:207`](../core/dr-pipeline/src/spot.rs#L207), [`core/dr-pipeline/src/spot.rs:387`](../core/dr-pipeline/src/spot.rs#L387), [`core/dr-pipeline/src/spot.rs:472`](../core/dr-pipeline/src/spot.rs#L472), [`core/dr-pipeline/src/spot.rs:582`](../core/dr-pipeline/src/spot.rs#L582), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`core/dr-pipeline/src/state.rs:103`](../core/dr-pipeline/src/state.rs#L103), [`core/dr-pipeline/tests/spot_sidecar.rs:1`](../core/dr-pipeline/tests/spot_sidecar.rs#L1), [`core/dr-pipeline/tests/spots.rs:1`](../core/dr-pipeline/tests/spots.rs#L1), [`ui/dr-ui/src/develop.rs:2505`](../ui/dr-ui/src/develop.rs#L2505), [`ui/dr-ui/src/develop.rs:2543`](../ui/dr-ui/src/develop.rs#L2543), [`ui/dr-ui/src/develop.rs:2608`](../ui/dr-ui/src/develop.rs#L2608), [`ui/dr-ui/src/develop.rs:2691`](../ui/dr-ui/src/develop.rs#L2691), [`ui/dr-ui/src/develop.rs:2705`](../ui/dr-ui/src/develop.rs#L2705), [`ui/dr-ui/src/develop.rs:825`](../ui/dr-ui/src/develop.rs#L825), [`ui/dr-ui/src/labels.rs:53`](../ui/dr-ui/src/labels.rs#L53), [`ui/dr-ui/src/lib.rs:1703`](../ui/dr-ui/src/lib.rs#L1703), [`ui/dr-ui/src/lib.rs:2786`](../ui/dr-ui/src/lib.rs#L2786), [`ui/dr-ui/src/lib.rs:394`](../ui/dr-ui/src/lib.rs#L394), [`ui/dr-ui/src/spots_ui.rs:19`](../ui/dr-ui/src/spots_ui.rs#L19), [`ui/dr-ui/src/spots_ui.rs:1`](../ui/dr-ui/src/spots_ui.rs#L1), [`ui/dr-ui/src/spots_ui.rs:265`](../ui/dr-ui/src/spots_ui.rs#L265), [`ui/dr-ui/ui/adjust.slint:832`](../ui/dr-ui/ui/adjust.slint#L832), [`ui/dr-ui/ui/app.slint:140`](../ui/dr-ui/ui/app.slint#L140), [`ui/dr-ui/ui/app.slint:1949`](../ui/dr-ui/ui/app.slint#L1949), [`ui/dr-ui/ui/app.slint:2124`](../ui/dr-ui/ui/app.slint#L2124), [`ui/dr-ui/ui/app.slint:2548`](../ui/dr-ui/ui/app.slint#L2548), [`ui/dr-ui/ui/icons.slint:338`](../ui/dr-ui/ui/icons.slint#L338), [`ui/dr-ui/ui/spots.slint:172`](../ui/dr-ui/ui/spots.slint#L172), [`ui/dr-ui/ui/spots.slint:48`](../ui/dr-ui/ui/spots.slint#L48), [`ui/dr-ui/ui/spots.slint:5`](../ui/dr-ui/ui/spots.slint#L5) | +| FR-DSP-1 | [`core/dr-gpu/src/adjust.rs:2140`](../core/dr-gpu/src/adjust.rs#L2140), [`core/dr-gpu/src/adjust.rs:2217`](../core/dr-gpu/src/adjust.rs#L2217), [`core/dr-gpu/src/adjust.rs:2302`](../core/dr-gpu/src/adjust.rs#L2302), [`core/dr-gpu/src/adjust.rs:54`](../core/dr-gpu/src/adjust.rs#L54), [`core/dr-gpu/src/adjust.rs:770`](../core/dr-gpu/src/adjust.rs#L770), [`core/dr-gpu/src/lib.rs:172`](../core/dr-gpu/src/lib.rs#L172), [`core/dr-gpu/src/lib.rs:192`](../core/dr-gpu/src/lib.rs#L192), [`core/dr-gpu/src/lib.rs:70`](../core/dr-gpu/src/lib.rs#L70), [`core/dr-gpu/src/lib.rs:93`](../core/dr-gpu/src/lib.rs#L93), [`core/dr-gpu/tests/capture_sharpen.rs:200`](../core/dr-gpu/tests/capture_sharpen.rs#L200), [`core/dr-gpu/tests/detail_stage.rs:328`](../core/dr-gpu/tests/detail_stage.rs#L328), [`core/dr-gpu/tests/local_contrast.rs:264`](../core/dr-gpu/tests/local_contrast.rs#L264), [`core/dr-gpu/tests/noise_reduction.rs:378`](../core/dr-gpu/tests/noise_reduction.rs#L378), [`core/dr-pipeline/src/detail.rs:136`](../core/dr-pipeline/src/detail.rs#L136), [`core/dr-pipeline/src/detail.rs:524`](../core/dr-pipeline/src/detail.rs#L524), [`core/dr-pipeline/src/graph.rs:651`](../core/dr-pipeline/src/graph.rs#L651), [`core/dr-pipeline/src/graph.rs:681`](../core/dr-pipeline/src/graph.rs#L681), [`core/dr-pipeline/src/ops/capture_sharpen.rs:1`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L1), [`core/dr-pipeline/src/ops/capture_sharpen.rs:659`](../core/dr-pipeline/src/ops/capture_sharpen.rs#L659), [`core/dr-pipeline/src/ops/local_contrast.rs:1`](../core/dr-pipeline/src/ops/local_contrast.rs#L1), [`core/dr-pipeline/src/ops/local_contrast.rs:971`](../core/dr-pipeline/src/ops/local_contrast.rs#L971), [`core/dr-pipeline/src/ops/noise_reduction.rs:700`](../core/dr-pipeline/src/ops/noise_reduction.rs#L700), [`core/dr-pipeline/src/spot.rs:673`](../core/dr-pipeline/src/spot.rs#L673), [`ui/dr-ui/src/develop.rs:3139`](../ui/dr-ui/src/develop.rs#L3139), [`ui/dr-ui/src/develop.rs:4606`](../ui/dr-ui/src/develop.rs#L4606), [`ui/dr-ui/src/develop.rs:5448`](../ui/dr-ui/src/develop.rs#L5448), [`ui/dr-ui/src/develop.rs:5482`](../ui/dr-ui/src/develop.rs#L5482), [`ui/dr-ui/src/lib.rs:890`](../ui/dr-ui/src/lib.rs#L890), [`ui/dr-ui/src/lib.rs:93`](../ui/dr-ui/src/lib.rs#L93), [`ui/dr-ui/src/lib.rs:949`](../ui/dr-ui/src/lib.rs#L949) | | FR-DSP-3 | [`core/dr-gpu/tests/frame_budget.rs:101`](../core/dr-gpu/tests/frame_budget.rs#L101), [`core/dr-gpu/tests/local_contrast.rs:329`](../core/dr-gpu/tests/local_contrast.rs#L329), [`core/dr-pipeline/src/ops/local_contrast.rs:447`](../core/dr-pipeline/src/ops/local_contrast.rs#L447) | | FR-DSP-5 | [`core/dr-gpu/tests/frame_budget.rs:101`](../core/dr-gpu/tests/frame_budget.rs#L101), [`core/dr-gpu/tests/zoom_resolution.rs:135`](../core/dr-gpu/tests/zoom_resolution.rs#L135), [`core/dr-gpu/tests/zoom_resolution.rs:166`](../core/dr-gpu/tests/zoom_resolution.rs#L166), [`core/dr-gpu/tests/zoom_resolution.rs:1`](../core/dr-gpu/tests/zoom_resolution.rs#L1), [`core/dr-gpu/tests/zoom_resolution.rs:216`](../core/dr-gpu/tests/zoom_resolution.rs#L216) | -| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:483`](../core/dr-pipeline/src/operation.rs#L483), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop.rs:3169`](../ui/dr-ui/src/develop.rs#L3169), [`ui/dr-ui/src/develop.rs:6876`](../ui/dr-ui/src/develop.rs#L6876), [`ui/dr-ui/src/lib.rs:1659`](../ui/dr-ui/src/lib.rs#L1659), [`ui/dr-ui/src/lib.rs:3169`](../ui/dr-ui/src/lib.rs#L3169) | +| FR-DSP-6 | [`core/dr-pipeline/src/operation.rs:497`](../core/dr-pipeline/src/operation.rs#L497), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`ui/dr-ui/src/develop.rs:3169`](../ui/dr-ui/src/develop.rs#L3169), [`ui/dr-ui/src/develop.rs:6876`](../ui/dr-ui/src/develop.rs#L6876), [`ui/dr-ui/src/lib.rs:1659`](../ui/dr-ui/src/lib.rs#L1659), [`ui/dr-ui/src/lib.rs:3169`](../ui/dr-ui/src/lib.rs#L3169) | | FR-DSP-7 | [`core/dr-gpu/src/histogram.rs:147`](../core/dr-gpu/src/histogram.rs#L147), [`core/dr-gpu/src/histogram.rs:1`](../core/dr-gpu/src/histogram.rs#L1), [`core/dr-gpu/src/histogram.rs:281`](../core/dr-gpu/src/histogram.rs#L281), [`core/dr-gpu/src/histogram.rs:50`](../core/dr-gpu/src/histogram.rs#L50), [`core/dr-gpu/src/shaders/histogram.wgsl:1`](../core/dr-gpu/src/shaders/histogram.wgsl#L1), [`ui/dr-ui/src/develop.rs:3218`](../ui/dr-ui/src/develop.rs#L3218), [`ui/dr-ui/src/develop.rs:6550`](../ui/dr-ui/src/develop.rs#L6550), [`ui/dr-ui/src/develop.rs:6582`](../ui/dr-ui/src/develop.rs#L6582), [`ui/dr-ui/src/develop.rs:749`](../ui/dr-ui/src/develop.rs#L749), [`ui/dr-ui/src/histogram.rs:1`](../ui/dr-ui/src/histogram.rs#L1), [`ui/dr-ui/src/lib.rs:1769`](../ui/dr-ui/src/lib.rs#L1769), [`ui/dr-ui/src/lib.rs:373`](../ui/dr-ui/src/lib.rs#L373), [`ui/dr-ui/ui/app.slint:74`](../ui/dr-ui/ui/app.slint#L74), [`ui/dr-ui/ui/histogram.slint:168`](../ui/dr-ui/ui/histogram.slint#L168), [`ui/dr-ui/ui/histogram.slint:1`](../ui/dr-ui/ui/histogram.slint#L1) | | FR-DSP-8 | [`platform/dr-plat/src/display.rs:1`](../platform/dr-plat/src/display.rs#L1), [`platform/dr-plat/src/display/icc.rs:1`](../platform/dr-plat/src/display/icc.rs#L1), [`platform/dr-plat/src/display/wayland.rs:1`](../platform/dr-plat/src/display/wayland.rs#L1), [`platform/dr-plat/src/display/x11.rs:1`](../platform/dr-plat/src/display/x11.rs#L1), [`ui/dr-ui/src/develop.rs:3115`](../ui/dr-ui/src/develop.rs#L3115), [`ui/dr-ui/src/develop.rs:3169`](../ui/dr-ui/src/develop.rs#L3169), [`ui/dr-ui/src/develop.rs:6876`](../ui/dr-ui/src/develop.rs#L6876), [`ui/dr-ui/src/develop.rs:6922`](../ui/dr-ui/src/develop.rs#L6922), [`ui/dr-ui/src/develop.rs:6941`](../ui/dr-ui/src/develop.rs#L6941), [`ui/dr-ui/src/develop.rs:856`](../ui/dr-ui/src/develop.rs#L856), [`ui/dr-ui/src/display_ui.rs:192`](../ui/dr-ui/src/display_ui.rs#L192), [`ui/dr-ui/src/display_ui.rs:1`](../ui/dr-ui/src/display_ui.rs#L1), [`ui/dr-ui/src/display_ui.rs:325`](../ui/dr-ui/src/display_ui.rs#L325), [`ui/dr-ui/src/display_ui.rs:346`](../ui/dr-ui/src/display_ui.rs#L346), [`ui/dr-ui/src/display_ui.rs:379`](../ui/dr-ui/src/display_ui.rs#L379), [`ui/dr-ui/src/lib.rs:1620`](../ui/dr-ui/src/lib.rs#L1620), [`ui/dr-ui/src/lib.rs:1659`](../ui/dr-ui/src/lib.rs#L1659), [`ui/dr-ui/src/lib.rs:3082`](../ui/dr-ui/src/lib.rs#L3082), [`ui/dr-ui/src/lib.rs:3169`](../ui/dr-ui/src/lib.rs#L3169), [`ui/dr-ui/ui/app.slint:1797`](../ui/dr-ui/ui/app.slint#L1797), [`ui/dr-ui/ui/app.slint:53`](../ui/dr-ui/ui/app.slint#L53), [`ui/dr-ui/ui/settings.slint:124`](../ui/dr-ui/ui/settings.slint#L124), [`ui/dr-ui/ui/settings.slint:794`](../ui/dr-ui/ui/settings.slint#L794) | | FR-EXP-1 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) | -| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:153`](../core/dr-export/src/lib.rs#L153), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:53`](../core/dr-export/src/lib.rs#L53), [`core/dr-gpu/src/adjust.rs:2436`](../core/dr-gpu/src/adjust.rs#L2436), [`core/dr-pipeline/src/graph.rs:538`](../core/dr-pipeline/src/graph.rs#L538), [`core/dr-pipeline/src/graph.rs:592`](../core/dr-pipeline/src/graph.rs#L592), [`core/dr-pipeline/src/operation.rs:483`](../core/dr-pipeline/src/operation.rs#L483), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:713`](../core/dr-types/src/settings.rs#L713), [`ui/dr-ui/src/develop.rs:6941`](../ui/dr-ui/src/develop.rs#L6941), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) | +| FR-EXP-2 | [`core/dr-export/src/encode.rs:1`](../core/dr-export/src/encode.rs#L1), [`core/dr-export/src/error.rs:26`](../core/dr-export/src/error.rs#L26), [`core/dr-export/src/icc.rs:1`](../core/dr-export/src/icc.rs#L1), [`core/dr-export/src/lib.rs:153`](../core/dr-export/src/lib.rs#L153), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/lib.rs:53`](../core/dr-export/src/lib.rs#L53), [`core/dr-gpu/src/adjust.rs:2450`](../core/dr-gpu/src/adjust.rs#L2450), [`core/dr-pipeline/src/graph.rs:634`](../core/dr-pipeline/src/graph.rs#L634), [`core/dr-pipeline/src/graph.rs:695`](../core/dr-pipeline/src/graph.rs#L695), [`core/dr-pipeline/src/operation.rs:497`](../core/dr-pipeline/src/operation.rs#L497), [`core/dr-types/src/colour.rs:1`](../core/dr-types/src/colour.rs#L1), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:713`](../core/dr-types/src/settings.rs#L713), [`ui/dr-ui/src/develop.rs:6941`](../ui/dr-ui/src/develop.rs#L6941), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-3 | [`core/dr-export/src/lib.rs:182`](../core/dr-export/src/lib.rs#L182), [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/size.rs:136`](../core/dr-export/src/size.rs#L136), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`core/dr-export/src/size.rs:25`](../core/dr-export/src/size.rs#L25), [`core/dr-export/src/size.rs:84`](../core/dr-export/src/size.rs#L84), [`core/dr-types/src/settings.rs:1`](../core/dr-types/src/settings.rs#L1), [`core/dr-types/src/settings.rs:758`](../core/dr-types/src/settings.rs#L758), [`core/dr-types/src/settings.rs:766`](../core/dr-types/src/settings.rs#L766), [`core/dr-types/src/settings.rs:782`](../core/dr-types/src/settings.rs#L782), [`core/dr-types/src/settings.rs:851`](../core/dr-types/src/settings.rs#L851), [`core/dr-types/src/settings.rs:879`](../core/dr-types/src/settings.rs#L879), [`core/dr-types/src/settings.rs:890`](../core/dr-types/src/settings.rs#L890), [`core/dr-types/src/settings.rs:896`](../core/dr-types/src/settings.rs#L896), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1), [`ui/dr-ui/src/settings_ui.rs:207`](../ui/dr-ui/src/settings_ui.rs#L207), [`ui/dr-ui/src/settings_ui.rs:220`](../ui/dr-ui/src/settings_ui.rs#L220), [`ui/dr-ui/src/settings_ui.rs:235`](../ui/dr-ui/src/settings_ui.rs#L235), [`ui/dr-ui/src/settings_ui.rs:565`](../ui/dr-ui/src/settings_ui.rs#L565), [`ui/dr-ui/ui/settings.slint:697`](../ui/dr-ui/ui/settings.slint#L697), [`ui/dr-ui/ui/settings.slint:707`](../ui/dr-ui/ui/settings.slint#L707) | | FR-EXP-4 | [`core/dr-export/src/lib.rs:1`](../core/dr-export/src/lib.rs#L1), [`core/dr-export/src/sharpen.rs:1`](../core/dr-export/src/sharpen.rs#L1), [`core/dr-export/src/size.rs:1`](../core/dr-export/src/size.rs#L1), [`ui/dr-ui/src/settings_ui.rs:1`](../ui/dr-ui/src/settings_ui.rs#L1) | | FR-EXP-5 | [`ui/dr-ui/src/settings_store.rs:1`](../ui/dr-ui/src/settings_store.rs#L1) | diff --git a/ui/dr-ui/src/labels.rs b/ui/dr-ui/src/labels.rs index 1610c89..5121fef 100644 --- a/ui/dr-ui/src/labels.rs +++ b/ui/dr-ui/src/labels.rs @@ -154,6 +154,12 @@ fn catalogued(key: &str) -> Option<&'static str> { // one for what it corrects means the two can sit in the same panel // without either having to be renamed to make room. "op.vignetting" => "Lens Vignetting", + // "Chromatic Aberration", not the "Aberration" `derive` would give. + // The bare word names a whole family of lens defects — coma, spherical, + // astigmatism — and this operation corrects exactly one of them. Under + // it sit sliders called "Red" and "Blue", which only make sense once + // the heading has said what is being separated. + "op.aberration" => "Chromatic Aberration", // Parameters "param.temperature" => "Temperature",