ERL concrete pipeline source review
==================================
Scope: the active definitions in Stage_01/Concretes/{DataConcrete_new.h,AlgorithmConcrete_new.h,AlgorithmConcreteKernels.cu,SdlDisplayConcrete_new.h}, frame types, queue, and optical-flow implementation. File/line references below are relative to Stage_01 unless prefixed with the integration driver name. Large commented predecessor implementations are not evidence of executed behavior. Missing Module orchestration prevents proving final construction, queue capacities, shutdown ordering, build flags, or runtime actuation.

Actual data flow and ownership
------------------------------
1. V4L2 capture allocates and MMAPs driver buffers, queues them (DataConcrete_new.h:595-631), selects and dequeues buffers (1311-1358), and derives dual capture timestamps (1384-1448). Driver clock rejection can fall back to dequeue time; this changes the measured E2E start boundary.
2. USB YUYV: frame holds mapped pointer and shared lifetime guard (1511-1528). No pixel memcpy is made at this step. The guard's final deleter calls queueBuffer(index), which QBUFs the driver buffer (131-138,1650-1682). Its raw DataConcrete* means module lifetime ordering is an external contract.
3. CSI RG10: creates a fresh owned vector, performs CPU raw-to-grayscale-YUYV conversion and resize, then immediately QBUFs raw buffer (1483-1509). The converter uses source stride (1092-1123), nearest-neighbor samples (1172-1178,1254-1263), optional contrast stretching, Y limited to 16..235 and chroma128 (1272-1285). This is conversion/allocation, not end-to-end zero-copy.
4. Capture fans the same shared_ptr into algorithm input and original-display queues (1600-1619), copying handles, not image pixels. Queues are synchronized FIFO; bounded push blocks and stop wakes waiters (SharedQueue.h:123-164,303-310). Exact queue capacities are external.
5. Algorithm worker uses pop_for(50ms), then drains all accumulated input and processes the newest frame (AlgorithmConcrete_new.h:372,400-401,459-467). It deliberately skips frames to limit backlog; it is not lossless FIFO processing. The processing call allocates/resizes a host result vector (774).
6. CPU implementations read input and write output; Gaussian additionally writes an intermediate image (1453-1499), Median gathers local windows (1588-1633), Histogram is serial (1803-1865).
7. GPU implementations explicitly upload the frame Host->Device, execute kernels, copy Device->pinned Host, synchronize stream, and CPU-copy pinned host data into processedBuffer (AlgorithmConcreteKernels.cu:377-389,413-425,449-477). Persistent device/pinned buffers are reused until size grows or algorithm stops (288-328; AlgorithmConcrete_new.h:303-307). This is not GPU zero-copy. Hist additionally copies one minCDF integer D2H and synchronizes mid-pipeline (464-468).
8. Heterogeneous Gaussian reads the continuous split only in that workload. Positive gpuRows uploads the whole frame and weights, launches GPU passes, copies only GPU-owned rows back; CPU serial loops compute remaining rows before a final sync/merge (AlgorithmConcrete_new.h:908-926; AlgorithmConcreteKernels.cu:552-610). Split0 skips kernels, transfers, and resource initialization inside the launcher, even when GPU permission remains enabled. The timing wrapper can still use CUDA events when compiled with __CUDACC__.
9. Normal output wraps std::move(processedBuffer_) in shared vector ownership (AlgorithmConcrete_new.h:951-959). That transfer does not copy pixel storage, but the next frame allocates again because the vector was moved away. AlgorithmStats are merged before normal output queue push (1028-1052). OpticalFlow is an exception with its own earlier push (1876-1885).
10. Display drains original and processed queues independently to latest and retains both (SdlDisplayConcrete_new.h:829-830,926-936,1002-1008). Original and processed panes need not have matching frame IDs. New IDs undergo CPU YUYV->RGB24 conversion and SDL texture update (947-955,1011-1054), then RenderCopy/RenderPresent (966-978). Final host vector/driver guard release occurs when all queue/algorithm/display references are gone.

CPU/GPU dispatch and output-equivalence matrix
---------------------------------------------
Invert / Grayscale / EdgeDetection / GaussianBlur:
  GPU permission is forcibly false locally (AlgorithmConcrete_new.h:791-799); they run CPU methods (814-825). parallelFor can use runtime concurrency (1369-1413). Invert complements every byte including chroma (1416-1418); Grayscale neutralizes odd bytes (1421-1423); EdgeDetection is only a horizontal adjacent difference (1426-1442).
SobelEdge:
  GPU allowed: 3x3 Sobel magnitude (AlgorithmConcreteKernels.cu:67-94).
  GPU disabled or runtime_error: calls CPU EdgeDetection (AlgorithmConcrete_new.h:827-840), not equivalent Sobel. Exact counterexample below.
MedianFilter:
  GPU allowed: median kernel; CPU disabled/failure branch performs actual CPU median, not pass-through (AlgorithmConcrete_new.h:860-885).
  configure accepts only window3/5 (319-330), GPU launcher also validates (AlgorithmConcreteKernels.cu:400-405). Both paths clamp border coordinates, use Y-only median and chroma128 (CPU1588-1633; GPU96-130). Intended integer-equivalent output for valid packed YUYV and supported window; no device execution was performed to establish runtime equivalence. CPU parallelFor honors concurrency; GPU kernel does not use gpu_workload_split.
HistogramEqualization:
  Dispatch uses processHistogramEqualizationCPUZeroCopy (AlgorithmConcrete_new.h:888-905), whose histogram/CDF/remap loops are serial (1803-1865). The similarly named parallel alternative at1716-1800 is not invoked by that dispatch.
  Nonconstant-image mapping uses the same inclusive CDF, first positive CDF, normalization, truncation/clamp, neutral chroma (CPU1822-1863; GPU133-195). Float precision and device behavior still require tests.
  Constant nonzero Y has denom0. CPU preserves input Y (1849-1862); CUDA remap initializes Y0 and never changes it (AlgorithmConcreteKernels.cu:186-195). Therefore CPU/GPU are not output-equivalent for this legal input.
HeterogeneousGaussianBlur:
  If useGPU false, runs standalone CPU Gaussian with sigma=radius (AlgorithmConcrete_new.h:1454-1472).
  If useGPU true, launcher uses sigma=1 for radius<=1 else radius/2 (AlgorithmConcreteKernels.cu:565-572), partitions rows by round(split*height), GPU first rows and CPU remainder (553-558).
  Split0 still runs this alternate CPU Gaussian math, which differs from GPU-disabled fallback. Its host CPU half is serial and does not call parallelFor (486-529,601-604); runtime concurrency does not create multiple workers for it.
  Host heterogeneous horizontal intermediate is float and final result rounded (491,500,522); GPU intermediate is uint8 and results truncate each pass (198-235). Even matching weights do not imply identical outputs across row ownership. Missing GPU halo coverage is a separate stronger correctness issue below.
OpticalFlow_LucasKanade:
  Runs CPU optical flow irrespective of the local useGPU flag, retains previous frame, and emits from second frame onward (AlgorithmConcrete_new.h:930-932,1876-1885). Output is separate int16 vx plane + int16 vy plane (LucasKanadeOpticalFlow.h:166-181), not YUYV, but display treats every frame as YUYV. The flow output is therefore not a meaningful flow visualization under current display interpretation.
Other enum values:
  Mandelbrot, MatrixMultiply, PasswordHash, MultiPipeline, GPUMatrixMultiply and MultiThreadedInvert are listed in AlgorithmConfig.h:300-316, but active processFrameZeroCopy has no cases for them and defaults to memcpy pass-through (AlgorithmConcrete_new.h:934-936). Standalone helper bodies do not make these types dispatched. Whether missing controllers use separate implementations remains unknown.

Confirmed source defects / result-validity limitations
-----------------------------------------------------
P1. Heterogeneous Gaussian GPU horizontal halo is missing at some valid splits.
  Both horizontal and vertical launches share gridY=ceil(gpuRows/16) (AlgorithmConcreteKernels.cu:586-591). Horizontal guard permits y<height, but only launched rows are computed (198-215). Vertical reads clamped y+/-radius from d_tmp (227-230). For h240, split0.8, r5: gpuRows192, horizontal rows0..191; GPU outputs187..191 read intermediate rows192..196 not written by this invocation. Full input H2D does not initialize horizontal d_tmp; init only cudaMallocs it (303). With persistent buffers those reads can be stale, otherwise uninitialized. Full GPU coverage avoids this defect; some non-multiple-of16 splits happen to have sufficient padding. Fix horizontal coverage through min(height,gpuRows+radius) while restricting vertical output to owned rows, then validate boundary pixels and changing splits.
P1. Workload semantics change with device choice.
  Sobel uses entirely different CPU vs GPU equations. HGB uses different sigma/rounding and has split-dependent output. Histogram differs on constant nonzero input. Energy/performance comparisons cannot assume fixed-quality work across these actions. Define one reference output contract and compare every action/fallback against it before benchmarking.
P1. Display repeatedly finalizes retained frame IDs.
  Upload is deduplicated at SdlDisplayConcrete_new.h:947-955, but mergeDisplay is called every render tick with retained lastProcessed ID and a fresh timestamp (978-990). Aggregator review independently confirms successful merge removes pending/frameStarted (SystemMetricsAggregatorConcrete_v3_2.h:459-461); repeated merge then waits configured mergeWaitMs before missing-frame return (286,422-428). ConfigManager normally derives mergeWaitMs from camera timing, with the aggregator enforcing a50ms minimum; its standalone default is2000ms. This code path can stall display for the configured wait when the next render sees no new processed frame. This is source-level conditional behavior, not evidence of observed stalls in a recorded run. Merge only newly presented IDs and make duplicate finalization idempotent/nonblocking.
P1/P2. Frame layout contract is absent.
  ZeroCopyFrameData.h:96-110 stores pointer/size/geometry, no pixel format or row stride; isValid only requires positive size, not width*height*2 (77-84). USB bytesperline is learned (DataConcrete_new.h:495) then omitted from frame construction (1518-1527). Algorithm indexes packed2B/pixel and display does likewise (AlgorithmConcrete_new.h:1426-1442,1803-1865; SdlDisplayConcrete_new.h:1013-1017). Padded USB rows would be interpreted incorrectly; undersized frames can reach algorithm out-of-bounds reads/writes; actual camera layout must be confirmed. Flow format mismatch is already evident from source. Add explicit format/stride/payload validation and adapters.
P2. GPU permission/provenance is not GPU execution proof.
  Runtime enable_gpu enters algoConfig only each tenth processed frame (AlgorithmConcrete_new.h:494-520). Actual dispatch uses local config and CPU-only overrides (779-804). HGB split0 launches no kernel; Sobel/Histogram/Median fallbacks also mean permission can remain true while CPU executes. Sobel/HGB failure changes algoConfig, not local useGPU or runtimeControls (835,922); Median/Histogram failures do not disable GPU permission (873-880,895-900).
  algorithm_observed_generation is published every frame before dispatch (523-555), potentially before the newly published GPU toggle/affinity has been sampled. It establishes generation observation, not full action application. Actual executed backend, fallback reason, gpuRows, CPU worker count, and effective action generation should be logged per frame.
P2. cudaKernelTimeMs is not isolated kernel time.
  It wraps the entire launcher, including allocation when needed, H2D/D2H, sync, pinned-to-vector copies, and CPU share for HGB (AlgorithmConcrete_new.h:1895-1913; launchers above). Non-__CUDACC__ uses wall-clock time. __CUDACC__ branch records events on stream0, whereas work uses dedicated res.stream, ignores event errors and leaks events if launch throws before cleanup (1897-1907). Label whole-call measurement appropriately; add checked events on actual stream around kernels for kernel-only timing.
P2. Capture/display metrics do not prove delivery success.
  Capture ignores push return but sets pushed=true (DataConcrete_new.h:1603-1615); stopped queue returns false (SharedQueue.h:132-134); camera droppedFrames remains0 (1565). Display advances uploaded IDs/counts even if upload skipped and ignores SDL_UpdateTexture errors (947-955,1040-1054); texture creation errors unchecked (904-912). Display FPS is raw count per >=1s window rather than divided by exact elapsed interval and falls back to original rate when processed rate is0 (958-963,989). Fix per-stage attempted/accepted/dropped counters and presentation status.
P2. Camera configuration and applied settings can differ.
  Supporting RG10 selects CSI mode (DataConcrete_new.h:400-410); CSI uses fixed1280x720/60 (419-423), sensor4/bypass0 (458-459); USB requests60FPS (553-558). Camera metrics publish configured sensor/bypass (1559-1560). Validate and log accepted/applied state rather than only intent.
P2. Clock fallback persistence changes E2E boundary.
  A first implausible driver timestamp sets basis Unusable (1408-1419), which is not re-armed by later per-frame rejection (1434-1443); fallback uses dequeue time (1445-1448) until STREAMON resets basis (1022). The incidence requires logs. E2E based on fallback cannot include driver-queued delay.

Conditional safety/integration risks (not observed failures)
-----------------------------------------------------------
- USB guard holds raw DataConcrete* (DataConcrete_new.h:131-138), while close/reconfigure unmap buffers immediately (1729-1740,377-382). If queued/retained USB frames outlive those operations, storage/deleter becomes unsafe. Missing controllers must prove stop, drain/release, then unmap/destruct order.
- Capture uses an ad hoc threshold 4*max(4,numBuffers), not actual bounded queue capacity, before blocking push (1601-1614). stopCapture signals eventfd and joins (957-975), which cannot release a thread blocked inside SharedQueue::push. Deadlock requires unsuitable capacity/shutdown order; exact orchestration is absent.
- configure/setAlgorithmType can mutate configuration and opticalFlowProcessor while threadLoop reads them (AlgorithmConcrete_new.h:317-361 vs dispatch813-937). setAlgorithmType locks metricMutex but dispatch does not share that lock. Concurrent use is a C++ data-race risk; stopped/quiesced use is safe. Missing controllers must establish quiescence.
- Display pairwise conversion assumes an even total pixel count (SdlDisplayConcrete_new.h:1013-1031); size guard requires only2*w*h (1040-1045). An odd pixel count causes one-pixel read/write beyond the sized buffers. Current320x240 geometry is safe; validate even width/format at the boundary.
- Display textures are initialized once and later updated with each frame's dimensions/pitch (904-912,1054). Different accepted camera geometry requires compatible texture recreation by orchestration.
- CPU Gaussian radius<=0 returns without filling output (AlgorithmConcrete_new.h:1463), while HGB launcher passes input through (AlgorithmConcreteKernels.cu:540-544). AlgorithmConfig.validate rejects radius<=0 (446-449), but AlgorithmConcrete.configure itself only validates Median (317-342); risk depends on caller validation.

Dormant integration debt (exclude from active architecture)
---------------------------------------------------------
FrameGrayView.hpp accesses nonexistent ZeroCopyFrameData.format/strideBytes (41-44 versus frame fields96-110). No archive include/call makes it active; do not portray it as the working view/adapter. ZeroCopyFrameData.h uses std::vector without including<vector> (51,110 versus includes8-11), relying on transitive includes. Commented duplicate implementations are noise, not current behavior. Mandelbrot launcher lacks init/resizing (AlgorithmConcreteKernels.cu:620-643) but is not reached by the reviewed active dispatch; flag as dormant API risk, not an active benchmark defect.

Executed checks and required follow-up
--------------------------------------
algorithm_formula_checks.py ran three synthetic CPU-only equation/index checks; all3 passed. Results are in algorithm_formula_checks_results.json. No archive compilation, CUDA execution, camera, or recorded experimental run was used.
- 6x6 vertical luma ramp Y(x,y)=10*y, pixel(2,2): CPU fallback0 vs CUDA Sobel equation80.
- 6x6 constantY73: CPU Histogram73 vs CUDA remap equation0.
- h240/split0.8/r5: GPU output rows187..191 depend on unwritten intermediate rows192..196; full-GPU and zero-GPU coverage controls have no missing GPU halo. The test intentionally does not invent values for uninitialized device memory.
No active dispatch branch or kernel initialization found in the archive removes these three outcomes. Real device equivalence tests should exercise constants, impulses, ramps, saturated patterns, border pixels, window3/5, split0/1/intermediate boundaries, and changing splits on persistent allocations. Compare result bytes or explicit tolerances against one reference and record actual backend/fallback per frame. Runtime tests must also confirm USB row pitch, driver timestamps, queue/backpressure/drop rates, retained-frame lifetime, hot-swap quiescence, and successful SDL presentation.
