Skip to content

feat(columnkit): implement one trait, inherit the bounded contract (SDK) - #37

Merged
logannye merged 1 commit into
mainfrom
rosalind/act2-columnkit
Jun 2, 2026
Merged

feat(columnkit): implement one trait, inherit the bounded contract (SDK)#37
logannye merged 1 commit into
mainfrom
rosalind/act2-columnkit

Conversation

@logannye

@logannye logannye commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Act 2, the top-scored proposal (audit 46.3; build 10, moat 10, feasibility 9). Turn "extend the substrate" into a first-class SDK. A builder who wants their own per-locus metric — methylation, a coverage/QC track, custom ML features, a star-allele genotyper — would otherwise fork into the raw pileup engine and re-implement, by hand, the whole-genome contig walk, the working-set bound that plan/--enforce admit, and the canonical-JSON + BLAKE3 receipt — silently dropping the soundness invariants.

With ColumnKit they implement one trait and run it through one driver, inheriting all of it for free.

What's new

  • ColumnAnalyzer trait (header / params / on_column) + run_bounded_whole_genome driver (src/call/columnkit.rs). Implement the trait → inherit the same bounded per-contig column stream, the same working-set bound, and the same verifiable receipt the shipped subcommands enjoy.
  • The trait is welded to the kernel: the driver runs the exact same column stream as the shipped features egress, so the estimator that admits a run provably upper-bounds the realized working set of the builder's analyzer too. It's the contract made composable, not a feature bolted beside it.
  • features is now the first ColumnAnalyzer: run_features is refactored onto the driver (FeatureAnalyzer), so the SDK is the production path, not a parallel one — byte-identical output pinned by the golden TSV test. (The audit explicitly warned against the legacy plugin's parallel, non-contract path; this avoids that trap.)
  • examples/columnkit_coverage.rs — a ~25-line custom analyzer that runs and reports its inherited bounded working set. Crate-root re-exports (rosalind::{ColumnAnalyzer, run_bounded_whole_genome, FeatureAnalyzer}) + a README section.
struct CoverageTrack;
impl ColumnAnalyzer for CoverageTrack {
    fn header(&self) -> Option<String> { Some("#contig\tpos\tdepth\n".into()) }
    fn on_column(&mut self, col: &PileupColumn, contig: &str, out: &mut dyn Write) -> io::Result<()> {
        writeln!(out, "{contig}\t{}\t{}", col.locus.pos.0 + 1, col.depth())
    }
}
// ~3 lines of domain logic → bounded memory + determinism + a verifiable receipt, free.

Test plan

  • feature_analyzer_via_driver_equals_the_direct_features_path — driver output byte-identical to the hand-wired path, same bounded working set
  • a_custom_analyzer_inherits_the_bounded_working_set — a custom analyzer's WS is coverage-bounded, independent of read count
  • Golden feature TSV + byte-identical-across-runs tests guard the run_features dogfood (zero behavior change)
  • examples/columnkit_coverage.rs builds and runs
  • Full suite green (31 sections); rustc 0 warnings (incl. examples); additions clippy-clean
  • features re-verified byte-identical across runs, receipt feature_rows intact

Why this matters

No other genomics library can offer "implement this trait, inherit a machine-checkable memory budget + a hash-verifiable receipt" — because none has a memory contract to inherit. This is the move that converts a watching forker into a building one. Next Act-2 candidates: bounded gVCF (42.7), verify-attest signed receipts (43).

🤖 Generated with Claude Code

A builder who wants their own per-locus metric (methylation, coverage/QC, ML
features, a genotyper) would otherwise fork into the raw pileup engine and
re-implement, by hand, the whole-genome contig walk, the working-set bound that
plan/--enforce admit, and the canonical-JSON + BLAKE3 receipt — silently
dropping the soundness invariants.

ColumnKit turns "extend the substrate" into a first-class SDK:
- ColumnAnalyzer trait (header / params / on_column) + run_bounded_whole_genome
  driver (src/call/columnkit.rs). Implement the trait, run it through the
  driver, inherit the SAME bounded per-contig stream + working-set bound +
  receipt the shipped subcommands enjoy.
- The trait is WELDED to the kernel: the driver runs the exact same column
  stream as the shipped features egress, so the estimator that admits a run
  provably upper-bounds the realized working set of the builder's analyzer too.
- features is now the FIRST ColumnAnalyzer: run_features is refactored onto the
  driver (FeatureAnalyzer), so the SDK IS the production path, not a parallel
  one — byte-identical output pinned by the golden TSV test.
- examples/columnkit_coverage.rs: a ~25-line custom analyzer that runs and
  reports its inherited bounded working set. Crate-root re-exports + README.

No other genomics library can offer "implement this trait, inherit a
machine-checkable memory budget + a hash-verifiable receipt" — none has a
memory contract to inherit.

Tests: 2 columnkit unit tests (byte-identical-to-direct-path + custom-analyzer
bounded WS); golden feature TSV guards the dogfood; feature writers take
?Sized writers. Full suite green; rustc 0 warnings; additions clippy-clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@logannye
logannye merged commit 3c4fc1c into main Jun 2, 2026
3 checks passed
@logannye
logannye deleted the rosalind/act2-columnkit branch June 2, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant