Skip to content

feat(audit): store per-scene channel identity (dye/fluor/excitation/emission) across all reader paths #61

Description

@ferrinm

What to build

Project per-channel identity into per_scene[i].channels in the convert audit and into the corresponding inspect().scenes[i] block so downstream ingest can populate BigQuery channel_fluorophores (and, where the source encodes it, channel_targets) from the audit alone.

Scope

Today the LIF extract_channels result lands in OME-XML and omero but not in the audit — the audit only carries channel_count. CZI/ND2/OME-TIFF readers already expose channel identity via reader.ome_metadata.images[0].pixels.channels, but it also never reaches the audit.

Emit one common shape in the audit for all reader paths (LIF, CZI, ND2, default). One dict per channel, in acquisition order, with these keys — omit any that can't be extracted (never invent values):

{
  "channels": [
    {
      "index": 0,
      "name": "DAPI",
      "fluor": "DAPI",
      "excitation_nm": 405,
      "emission_low_nm": 420,
      "emission_high_nm": 480
    }
  ]
}

The exact key names and file-vs-scene placement come from ADR-0007 — follow the ADR's decision if it diverges from the sketch above.

Reader-path notes

  • LIF — reuse zarrmony.metadata.lif_channels.extract_channels output; the identity dicts already have the right fields. Add a projection that strips zarrmony-internal fields (like detector) if the ADR shape excludes them.
  • CZI/ND2/default — project from reader.ome_metadata.images[0].pixels.channels (each is an ome_types.model.Channel with name, fluor, excitation_wavelength, emission_wavelength). Handle emission bands vs single wavelength — if only a single emission_wavelength is given, populate emission_nm (or leave emission_low_nm/emission_high_nm unset per ADR).
  • Fail-safe pattern from feat(lif): extract objective lens metadata (magnification, NA, immersion) into audit + OME-XML #52: any extraction failure omits channels for that scene rather than crashing conversion.

Acceptance criteria

  • per_scene[i].channels populated on: LIF fixture (Stellaris), CZI fixture, ND2 fixture, OME-TIFF fixture.
  • inspect() output includes the same channels block per scene.
  • Missing/undeterminable fields → key omitted; extraction failure → channels key absent, no crash.
  • Cross-format consistency: same key names and value types across LIF/CZI/ND2/default.
  • AUDIT_SCHEMA_VERSION bumped.
  • CHANGELOG entry under a minor version bump.

Blocked by

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestready-for-agentTriaged and ready for an agent to implement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions