COLLECTOR / METRICS CONTRACT REVIEW — newly supplied full source
Review scope: source/Module/PilotCollector.h, PilotCollectorHooks.h, PowerSanity.h, MetricsSnapshot.h, MemoryOptimizedMetricsBuffer.h, LatencyHistogram.hpp; active selector/GA/Lynsyn/aggregator/v35 callsites. Only active code counted; large commented predecessor blocks excluded. Original source was not modified. All line references below are relative to full_code_review/source.

Evidence boundary
This is a review of the supplied source snapshot, not proof that these exact headers built the archived October experiment binaries. The collector embeds source/build flags from externally supplied macros; defaults are unset. The binary hash is of the executable at begin_run, and config hash is of the initial config file. No source-to-binary reproducible-build check is performed here. The existing historical analyses and their source-binding limitations remain separate. No hardware behavior was tested.

MAIN CONCLUSIONS
1. The collector usefully records a selected candidate's frozen values, requested/commanded/readback action fields, per-query lifecycle, and explicit latency exclusion. It does not establish a physically measured action outcome window or actual surrogate admission. This limitation is especially consequential at workload transitions: the collector closes the old query with the new workload's first accepted snapshot, while the GA correctly drops that temporal credit edge.
2. PowerSanity adds range-based sensor admission (0.30–12 W), but does not fix the previously identified Lynsyn arithmetic/window errors, nor establish freshness. The selector's retained accepted-power average can remain valid indefinitely after rejection or outage and is labelled meter-derived in outcome records.
3. The current producer wiring leaves sensor/capture/context provenance incomplete: SoC/meter steady stamps are only declarations, frame-meter producer is absent, input dimensions remain defaults, and the 100-ms context-age contract is logged without an active estimator gate.
4. A sealed manifest proves neither successful I/O nor complete/monotonic query records. Pure-header checks reproduce a successful seal on /dev/full, non-monotonic sequence order with advertised dual streams, and silently missing closure records after bounded-map eviction. CRC and SHA implementations did match the actual normal-case file bytes in the checks.
5. The standalone histogram and circular-metrics helpers have arithmetic and concurrency problems, but no active callsites were found; they must not be attributed to runtime metrics without evidence of use.

A. Actual causal and logging flow
A1. Selector obtains latest finalized aggregator snapshot (EvolutionarySelector_02.h:1033–1138); requires raw.isValid, maps frame/fps/processing latency, smooths accepted power, maps temperature, and sets avg_latency_ms to raw end-to-end latency. The snapshot carries no copied SoC source stamp. getLatestSnapshot runs before stale-frame/provenance checks (711–713, 747–815), so its powerHistory can be updated multiple times from the same raw frame even though that frame feeds at most one GA evolution.
A2. Frame freshness: frameId must be nonzero and greater than lastEvolvedFrameId (747–763). Workload provenance: latest published algorithm processed epoch must equal current GA epoch, processedFrame must be nonzero and >= snapshot.frameId; the post-transition provenance floor is latched (767–815). These are useful gate checks, but they do not prove each constituent sensor sample was acquired after the action's apply time.
A3. Before evolve: telemetry cache publishes current snapshot; if pilotPrevEpoch is nonzero, out=outcome_from(snapshot), outcome_available(old query, prevApplyEnd, now, settings_changed=2, window_basis=0), errors_of(frozen ticket,out), force latency exclusion=3, score, admission. References: selector:816–845. All collector scoring/admission occurs before ga_->evolve(snapshot):847.
A4. Actual surrogate update is conditional: GA:1084–1102 checks surrogateEnabled and hasLastApplied, then observeStarvation for timeout or observe only when creditPreviousAction. Thus the collector's unconditional admission record (selector:840) is not an acknowledgement returned by the surrogate. It does not encode starvation instead of observation, early return, rejection, per-target accepted EMA update, or disabled-surrogate state.
A5. GA stores the selected requested genome (GA:2410–2413), timestamps a pre-Scheduler selection boundary (2414–2417), applies, and exports selected evaluation. After evolve returns, selector copies lastSelectedEvaluation values into a ticket and emits prediction/select/apply (855–897). This preserves the pre-apply selected prediction values; it does NOT independently timestamp prediction completion. prediction_issue is assigned selectNs-1 (887). A missing/bad selection stamp sets selectNs=applyEnd-2 (886), so the prediction_issue stamp is applyEnd-3 under that fallback. Do not interpret the 1-ns gap as measured prediction/selection duration. Values are captured before applying; physical log serialization occurs after evolve.
A6. Ticket/query id is the anticipated next action epoch; action_epoch is uint32 in events, query_id/ticket_id uint64. Recorded model version is the fixed text W-EMA-live (856–857), not a state hash/version changing with every update. ContextMemory mentioned in header comments is not the actual producer: selector constructs tickets from GA last evaluation. Check on captured action-epoch mismatch skips post-evolve events (861–875). An open context is not immediately closed, and subsequent reuse of that anticipated id can cause ordering abort. The source captures support_status/support_count identically for all four targets (871), despite per-target validity being distinct.

B. Prediction/outcome and transition mismatch — HIGH
B1. Collector outcome window is explicitly ASSIGNED, not established from source samples: selector:832–834; PilotCollector:437–442. win_start is previous apply end; win_end is receipt of whichever finalized snapshot the selector accepted. Outcome records omit source frameId, raw sample ids, meter-device interval, and SoC acquisition timestamps; Outcome contains only value/valid/source arrays (PilotCollector:255–259). Settings-change state is explicitly unknown=2. A structural query join therefore cannot establish causal/action-homogeneous measurement membership.
B2. At workload commit selector:437–472 updates GA workload/provenance state but never resets pilotPrevEpoch_. Searching the active file finds only declaration613, reads830–840 and assignment897. GA deliberately clears hasLastApplied_ at490 (487–491 explain the cross-workload credit exclusion). First post-transition snapshot is required to belong to the replacement workload, yet collector:834–840 scores/admit it against the previous workload's frozen ticket; event identity is copied from the old query's context (PilotCollector:511–516). The GA then omits actual observation for that edge because hasLastApplied=false. This is a concrete divergence between trace score/admission semantics and learning semantics; boundary errors need explicit exclusion/closure or evidence-driven reattribution.
B3. Scoring definition mismatch is consciously handled: Hooks:165–166 outcome latency uses avg_inference_ms else processing_latency_ms, whereas selector:1125–1126 and GA:1095–1097 train E2E latency. Selector:838 always sets latency error=NaN, excluded=3; manifest:631 states why. The collector does not support a four-target prediction-calibration result for processing latency; the honest supported scored channels are power/FPS/CPU temperature, subject to other validity constraints.
B4. Admission metadata is corrupted by defaulting: OutcomeAvailable stores start/end/settings_changed/basis; QueryIdentity only retains start/end (PilotCollector:514,644), copied into Admission at515. Admission Event starts with settings_changed=0 and window_basis=0 (275–276). Hence actual runtime outcome unknown-settings=2 becomes admission no-settings-change=0. A probe using established basis=1 also becomes assigned=0. The numerical window bounds survive; provenance flags do not.

C. Sensor range admission, staleness, and the Lynsyn arithmetic review — HIGH
C1. PowerSanity:19–29 admits finite power in [0.30,12.0] W; this is an implemented fixed plausibility assumption, not a hardware-derived proof of physical limits. Lynsyn raw spike rejection uses [0,24] W at274; mean sample uses PowerSanity at313. Aggregator ingress independently applies PowerSanity at530; AdaptiveWeightManager applies it before battery-critical classification at417–418. This materially narrows the earlier risk that gross 22–57W values drive the controller.
C2. It does NOT resolve avg(V)*avg(I) versus mean(VI) or trapezoid boundary/denominator issues. Lynsyn:293–309 averages V and I independently; convertLynsynSampleToPowerStats is applied to that averaged pair; that product is gated, pushed to aggregator and callback at313–323. The raw trapezoid energy and derived trap average are CSV-only fields339–342. Thus a biased product inside [0.30,12] passes; the raw/canonical integral is not what controller admission checks. For example V=[4,6], I=[0.25,0.75] yields product of means=2.5W versus mean products=2.75W, both admitted. Thresholding may also censor windows based on a different estimate from the CSV canonical energy. Bounds do not correct wrong timestamps, crossed window steps, gap interpolation, or accepted stale history.
C3. Selector:1075–1105 chooses raw.avg_power_w_alg if positive, otherwise raw.powerStats.totalPower. If valid, appends to a five-element history; rejected/zero values do not clear or expire history; exported snap.avg_power_w_alg remains the old mean indefinitely. No timestamp accompanies these retained values. Repeated getLatestSnapshot calls occur before stale-frame gate, so history represents up to five reads rather than necessarily five distinct acquisitions or action windows. Across transition, powerHistory is not cleared in active code. Outcome validity only checks finite positive power and hardcodes source_id=1 (Hooks:160); it does not carry latest rejection/outage/freshness, actual power-source type or a PowerSanity decision. require_power_for_evolution only checks this smoothed number against a threshold (selector:1284–1285), so stale positive history can satisfy the gate.
C4. Aggregator pushPowerStats preserves latestPower on rejected input (519–540), and history pruning is triggered by accepted incoming samples (546–549). Any stale fallback downstream is not fixed by range admission alone. This report does not duplicate the parent's full aggregator integration analysis.
C5. Hooks:outcome_from trusts local numerical validity: power>0, FPS>=0, processing latency>0, CPU temp in(0,100). It does not consult snapshot.valid, sensor age, phase identity, target support, or PowerSanity. In isolation a 40W snapshot is marked power-valid despite PowerSanity rejecting40. The real selector normally gates fresh instantaneous power before smoothing, so this is a boundary weakness rather than a demonstrated bypass in that active normal callsite.

D. Provider/clock provenance — HIGH for context-validity claims
D1. Clock::now_ns is steady_clock; controller selected/apply stamps share this family (PilotCollector:72–92, selector:880–896). Wall time and MONOTONIC_RAW are manifest diagnostics only. This is a real improvement over mixing wall/raw clocks for event ordering. Across streams, file order is intended to be serialization order and not global timestamp order. Boundaries have a separate monotonic check502–506, meter479–485, controller508–510.
D2. SoC stamp fields exist but are unwired in the supplied tree: allModulesStatcs:616 poll_steady_ns; MetricsSnapshot:37 soc_sample_ns. No active producer assignment to poll_steady_ns and no mapping to soc_sample_ns were found. selector:826 therefore sets sample_ns=nowNs, temp_basis=0. Logged age is time since selector receipt, excluding prior sensor/aggregator delay; sensor freshness is explicitly unknown. Hooks comment35–37 saying aggregator flush latency is included is not true with a receipt-time stamp.
D3. Meter receipt_steady_ns/device_ts_raw are declared at allModulesStatcs:123–124 but never assigned; PilotCollector::meter_sample is defined461 without an active callsite. Event meter timeline therefore is not produced by the supplied active implementation. Do not infer measured power-window membership from availability of those fields/API alone.
D4. frame_meter.note_frame is only shown as a comment/instruction in Hooks:50–51; no active capture callsite exists anywhere in supplied source. v35:1635 installs a rate provider regardless and1646 warns if empty; collector returns null/unavailable. input_w/input_h are initialized320/240 in Hooks:44 and read by v35:1639 with no writes; notes claim CameraConfig origin but actual default provenance is all that is established.
D5. Context age cap defaults100ms and is written to manifest(PilotCollector:318,627), but no gate consumes it; context_sample's return value is discarded at selector845. Arrival/background/temp/context size are observations, not inputs to the bucket model. Future sample stamps are clamped to age0 (399,408); absent temperature/background providers leave defaults without explicit availability flags. A stale context can be logged and prediction issued without collector abort; that is consistent with observation-only intent but does not substantiate freshness-gated contextual prediction.
D6. FrameRateMeter::rate computes (last frame id-first id)/(last stamp-first stamp), not count of captured frames over the whole requested window (Hooks:63–68). Pure-header example: two frames at1.00s/1.01s inside[0,5s) return100FPS; literal captured count per5s is0.4FPS. It misses leading/trailing quiet time. This is latent while capture hook is absent and would matter once wired.
D7. Background daemon reader receives complete lines and handles trailing fragments correctly in principle (Hooks:93–116). It is optional, does not establish a same-acquisition snapshot across atomics, and no age gate uses its result. The external daemon/source has not been reviewed here.

E. Seal, sequence, durability and lifecycle — HIGH
E1. Normal file CRC and SHA computation are sound in the executed examples: each serialized body CRC verified with Python zlib; final SHA matched hashlib.sha256(actual event bytes). But these are per-line CRCs plus a whole-file digest, not a chained per-event hash or authenticated signature. Manifest/source/build hashes can remain unset/unavailable and the manifest itself is neither signed nor externally anchored (52–56,348–350,624–635). Source path/hash macro cannot be assumed to cover every transitive file or runtime dependency.
E2. I/O fail-open: write_jsonl sends line to events_ then always updates seal_ without checking stream state(603–604); end_run ignores flush/close failure and returns solely !aborted(362–370); manifest creation/write success also ignored(617–635). Probe symlinking events.jsonl to /dev/full returned begin=true,end=true,aborted=false,dropped=0; manifest status=sealed and seal populated. This is a digest of intended serialization, not guaranteed persisted bytes. begin_run also truncates existing events346 and manifest618, so reusing a run directory destroys previous data; append-only applies only within a successful single run.
E3. Crash durability claim is inaccurate: comment375 says writer flushes per batch; writer_loop553–561 only flushes on exit, with no batch flush or fsync. Probe wrote one full query, waited100ms, file size remained0 until end_run. Fatal crash can therefore lose the latest buffered events even after writer consumes the ring. The CRASHED signal handler uses snprintf383 despite claiming async-signal-safe; file create/write/close has no durability barrier and signals do not drain events. Destructor only stops/joins, leaves manifest open339.
E4. Sequence race (advertised API, currently latent without meter hook): sequence counter increment occurs under per-stream mutexes before shared push_mutex (483–484 vs504–505/518–520). Producer A can reserve lower seq, producer B push higher seq first. Two-thread pure-header test using 20,000 workload_enter and20,000 meter_sample calls produced40,002 records with395 decreasing adjacent sequence pairs, yet sealed with dropped0. First examples70→32,114→75,392→391. Sequence uniqueness survives atomic increment; file monotonicity does not. CRC/SHA verified the nonmonotonic file. Fix must allocate seq in the same critical section as enqueue.
E5. Query-map eviction silently loses terminal disposition: check_invariants549–550 erases oldest keys beyond1024 without abort or query_closed. Test1026 contexts ended sealed with2 context ids lacking admission/closure (2052 total events). This contradicts end_run's comment promising explicit disposition for every open query363–365. Ordinary active flow generally has one open query; this is API/exception/backlog robustness, not proof current archived runs hit1024.
E6. Online invariants check only stage adjacency and timestamp nondecrease, not semantic score truth/window bounds/ticket equality/validity consistency (530–551). The pure-header standard probe used query1/ticket99, reversed bounds200→100 and arbitrary errors999; sealed successfully. This is expected for an observation layer if an external verifier enforces contracts, but such a seal alone cannot certify those properties. Admission erases stage state, allowing eventual reuse of a previously completed id.
E7. Global/lifecycle concurrency (coordinated with lifecycle reviewer): Hooks32 is an unsynchronized raw static Collector* read by selector while v35 writes it. v35 ends/seals at1973–1978 before setting shutdown and stopping workers1981–1982. end_run iterates stage_ without ctrl_mutex365 and does not disable producers; emits can race closure/stop/flush. Exception unwinding destroys local collector(v35:1622) before outer catch1989; destructor does not clear global, so live selector may see dangling pointer until stopAll1999. Also dropped_ is plain uint64 modified by different streams484/505/520. These are source-level races; no ThreadSanitizer hardware run was performed.
E8. Begin failure is logged and mission continues without collector(v35:1653–1655); collector abort causes loop break without marking failed(v35:1690–1692), and end_run result is only logged1978. Exit status is failed? failure:success1987. External verification must be mandatory before accepting data; process success is not an evidence-validity verdict.
E9. JSON strings are concatenated without escaping (565–568,576,598,619–635). A run_id containing a double quote produced invalid event JSON and invalid manifest while end_run returnedtrue. Harness currently generates mostly controlled run ids/labels, so this is latent for arbitrary manifest strings/build flags/notes; escaping remains required for a general collector.

F. Dormant helper defects — LOW runtime relevance
F1. MemoryOptimizedMetricsBuffer has no active include/instance/callsite in source; only Integration_Guide.md mentions it. Sum includes valid samples but denominator counts all recent frames(75–79), so8W valid + invalid yields4W. getStats uses(head+1)%CAPACITY for oldest(111); with full capacity3 and timestamps100,200,300 it reports200 rather than100. No age-based eviction exists despite comment32; getters allocate vectors despite fixed-storage design; raw head/size/frame arrays have no synchronization despite lock-free-monitor-reader claim33. These findings should not be used to revise experimental results unless use is established.
F2. LatencyHistogram also has no active callsites. Percentile target=floor(pct/100*count)(51) can be0, yielding first-bin0.5ms even if sole observation100ms; exact probe returnedP95=0.5ms. All>=50ms share overflow bin whose midpoint50.5 is also used for average(35–38,57,73), so same100ms sample mean=50.5ms. Negative/nonfinite samples are unchecked before floating-to-size_t conversion. Concurrent snapshot/reset isn't coherent; total fetch_add uses acquire rather than release, so it does not publish prior bin increment as intended. These are library defects, not evidence that the actual per-frame percentiles used this class.
F3. MetricsSnapshot::hasData returns true for any positive field, without finite checking or timestamp provenance (46–50); computeAggregatedMetrics optionally forms0.6E2E+0.3processing+0.1display(59–63) and sets valid=hasData79. Active selector bypasses that weighted definition by assigning rawE2E to avg_latency_ms1126 and valid=true1135. Do not equate every field named avg_latency_ms across code paths.

G. Checks and artifacts
Executed against original supplied headers only, on x86_64 without hardware. Collector/Hooks/PowerSanity/Histogram probe compiled g++13.3.0 with -std=c++11 -Wall -Wextra -Wpedantic -Werror -pthread. Circular-buffer probe usedC++20 and a test-only empty spdlog header because the header includes spdlog but never calls it; vector/cstdint included by harness. No implementation was replaced. Files: analysis/collector_checks/probe.cpp, buffer_probe.cpp, results.json, and normal/race/eviction/quoted event/manifest examples. Run python3 analysis/collector_checks/verify_recorded_events.py to recheck recorded standard/evict/race event-file CRCs and SHA seals; this is an integrity check with diagnostic counts, not a semantic or historical-run verifier. /dev/full symlink was removed after recording outcome to keep artifacts safe to package. The executable was built under/tmp because the workspace exported a zero-length binary on the first attempt; compile/run checks used actual259232-byte executable thereafter.

Prioritization / claim-safe interpretation
- Retain: selected-evaluation provenance, declared counterfactual requested-vs-commanded-vs-readback distinction, shared steady-clock family, explicit processing-latency scoring exclusion, range-based sensor rejection, per-query order checks, and normal-case CRC/SHA integrity.
- Qualify: source snapshot binding to historical binaries; sealed/dropped0 as a structural checksum outcome only; claimed actual admissions; window membership; phase-boundary scores; meter power freshness/source; context age and arrival/input dimensions; reconstructed prediction issue timestamp.
- Do not infer: four-target calibration, sensor-fresh reduced-context gating, true frame/outcome causal joins, authenticated or durably persisted evidence, or runtime percentile/buffer defects from unused helper headers alone.
