Current status
Partially implemented: TargetColumnsBuilder now owns mutable construction and consumes itself in seal, producing TargetColumns. Public callers cannot query an unsealed arena or seal one twice.
seal now rejects DecoyPolicy::Force when stored decoys remain (ForceWithStoredDecoys). The previous hole producing derived variants over shipped decoys is closed. Readers still perform the actual filtering; seal does not compact rows.
Remaining work
TargetTable::Mzpaf { geom, frag_intens } still stores intensities outside the geometry. Readers/builders accumulate the sidecar in parallel by convention. The shared builder should own both so row insertion, shard merging, and filtering cannot desynchronize them.
With ownership unified, seal can implement the Force drop itself. Reader-side decoys.accepts(...) can remain an early parse-cost optimization, rather than being required for successful sealing. Preserve labels, m/z, intensities, source IDs, and competition groups together during compaction.
Decide the concrete API around the existing TargetColumnsBuilder; no second builder split is needed. Geometry-only inputs must remain supported without synthesized intensities.
Acceptance criteria
- Structural alignment between fragment geometry and optional intensities at insertion/merge/seal.
Force drops shipped decoy rows at seal even if a reader did not prefilter them.
- Tests cover compaction with source IDs, competition groups, and intensity sidecars, plus geometry-only inputs.
- All registry readers and the prediction sink use the shared ownership contract.
Separate decisions
The write-only structured-modification columns and charge embedded in seq_mod still warrant review, but are not prerequisites for sidecar ownership. Avoid bundling sequence representation or result-identity redesign into this change.
Related #111 validates the scoring-library boundary and protects it with immutable accessors; it does not move ownership into the shared builder. #97 handles capability/degradation reporting and execution planning.
Current status
Partially implemented:
TargetColumnsBuildernow owns mutable construction and consumes itself inseal, producingTargetColumns. Public callers cannot query an unsealed arena or seal one twice.sealnow rejectsDecoyPolicy::Forcewhen stored decoys remain (ForceWithStoredDecoys). The previous hole producing derived variants over shipped decoys is closed. Readers still perform the actual filtering; seal does not compact rows.Remaining work
TargetTable::Mzpaf { geom, frag_intens }still stores intensities outside the geometry. Readers/builders accumulate the sidecar in parallel by convention. The shared builder should own both so row insertion, shard merging, and filtering cannot desynchronize them.With ownership unified, seal can implement the
Forcedrop itself. Reader-sidedecoys.accepts(...)can remain an early parse-cost optimization, rather than being required for successful sealing. Preserve labels, m/z, intensities, source IDs, and competition groups together during compaction.Decide the concrete API around the existing
TargetColumnsBuilder; no second builder split is needed. Geometry-only inputs must remain supported without synthesized intensities.Acceptance criteria
Forcedrops shipped decoy rows at seal even if a reader did not prefilter them.Separate decisions
The write-only structured-modification columns and charge embedded in
seq_modstill warrant review, but are not prerequisites for sidecar ownership. Avoid bundling sequence representation or result-identity redesign into this change.Related #111 validates the scoring-library boundary and protects it with immutable accessors; it does not move ownership into the shared builder. #97 handles capability/degradation reporting and execution planning.