The library

Rendered from docs/reports/2026-09-25_software-only-rescope-plan-review.md; the markdown file is the record.

  1. Critical — The fold fallback permits generator leakage. Step 4 prioritizes speaker grouping over generator grouping. Different speakers produced by the same generator can therefore cross folds. Existing hearsay.probe.cv_groups groups spoof clips by generator and bona fide clips by speaker. Preserve whole-generator holdouts, enforce applicable speaker/duplicate constraints, and explicitly report when missing metadata prevents those guarantees.

  2. Critical — Shared folds alone do not make stacking validation clean. The plan does not distinguish training OOF rows from an untouched outer validation split. Existing scripts/train_probe.py selects layers and fits calibration using training OOF labels; those calibrated outputs are not automatically out-of-fold for stacking. Specify where feature selection, calibration, imputation, and fusion are fitted, require fold-local fitting for exported OOF predictions, and evaluate fusion on separate held-out groups.

  3. Critical — safe_run can raise while handling a detector failure. name = getattr(...) occurs outside the protected calls; a property can raise, and names such as None or "" make construction of the fallback DetectorResult raise. Validate registry names, resolve names inside the protected boundary, and use a guaranteed-valid fallback name. Add tests for invalid names and a raising name property.

  4. Critical — The native-rate exception bypasses the loader contract. ctx.memo only caches arbitrary work; it does not define decoding, sample-rate metadata, channel handling, scaling, or error behavior. Meanwhile, CLAUDE.md retains “16 kHz mono everywhere.” Either defer native-rate support or define an explicitly owned loader API and update both contracts, with conversion tests. Adding an MP4 case does not cover this new path.

  5. Critical — Fusion inputs remain unspecified at the teammate boundary. A valid DetectorResult may have empty features, while the architecture says fusion consumes logit/LLR features rather than score. Sorted detector names do not establish feature names or column order. Define the required fusion output per detector, stable column schema, endpoint handling when converting probabilities to logits, and all-detectors-missing fallback before teammates implement against this contract.

  6. Critical — Verification never produces the required submission artifact. Adding the detector pipeline contract still ends with tests and a commit, without a fresh TSV and submissions/log.csv row. Not editing submission.py does not verify submission availability. Add an end-to-end invocation through the existing scorer/writer, using a unique output path and recording validation provenance; explicitly identify any missing-data blocker.

  7. Suggestion — The revised standing failures conflate class imbalance with metric prior. Pinning π_synth = 0.3 does not address skewed training data or folds containing only one class. Preserve explicit class-count checks, training weighting/sampling policy, and minimum per-class fold support. Likewise, specify a physical-replay validation source; generic codec/noise augmentation does not establish phone-speaker robustness.

  8. Suggestion — C2 does not actually disable hashing. With frozen=True and eq=True, unsafe_hash=False still generates __hash__; calling it fails on the dictionary field. Set __hash__ = None explicitly if unhashability is intended, and test that behavior.

  9. Suggestion — Mutable features can bypass result validation. Copying the input dictionary prevents caller-dictionary aliasing, but result.features itself remains mutable. A detector can insert NaN or nested values after construction, and safe_run accepts the result unchanged. Revalidate/copy features at the acceptance boundary and test post-construction mutation.

  10. Suggestion — Ownership and delay gates need concrete resolution. Detector owners, Docker owner, and final sender remain unnamed despite replacing the shared contract. Also, “shift every gate by the delay” conflicts with absolute submission backstops and C10’s fixed fallback times. Assign named owners and state which gates may move, with hard cutoffs that preserve Sunday’s deadline.