Skip to content

fasta_lake.entrapment_stages#

fasta_lake.entrapment_stages #

Entrapment injection-stage registry.

Where entrapment enters the pipeline decides what its FDP measures. This module is the single source of truth for the stage vocabulary, and it deliberately uses the names the run scripts and figure loaders already use so nothing downstream breaks.

The canonical chain

::

stage 0  lake build
stage 1  cohort evidence filter   (de novo peptides admit sequences to the lake)
stage 1.5 cluster97               (MMseqs2 --min-seq-id 0.97 -c 0.8 --cov-mode 0)
stage 2  per-sample extraction    (de novo string matching = "selection")
stage 3  parsimony / razor
stage 4  SAGE search

Four injection points exist in this repository, each verified against the run script that implements it. They are ordered here from earliest to latest, which is also from hardest to easiest for an entrapment sequence to survive.

prelake Entrapment is concatenated into the input lake, before the cohort evidence filter. It must then survive evidence filtering, clustering, per-sample selection, parsimony and the search. This is the fullest construction test -- entrapment faces every curation step a real sequence faces. Implemented by projects/nearneighbour_entrapment_2026-07-20/scripts/ 00b_build_lakes.sh (cat TARGET_FASTA TAGGED > lake_NN.fasta), consumed by 01_evidence_cluster.sh.

prebuild Entrapment is concatenated onto the already-clustered lake and the result is re-clustered at 97%, so entrapment must also survive clustering -- it can be absorbed into a target cluster, or absorb targets into itself. It does not face the cohort evidence filter. Implemented by projects/masters_circularity_F1/scripts/inject_prep.sh:54-56 and projects/entrapment_rerun_2026-07-09/scripts/01_prebuild_prep.sh (mmseqs easy-cluster over the augmented lake).

preselect Entrapment is concatenated onto the already-clustered lake with no re-clustering. It faces per-sample selection, parsimony and the search. Cluster97 is upstream of this injection point, not downstream. Implemented by masters_circularity_F1/scripts/f1b_prep.sh:25-26 and the preselect arm of inject_prep.sh.

appended Entrapment is concatenated onto the finished per-sample database after parsimony, so it enters the search untested by any curation step. Its FDP measures ordinary search/scoring error, not construction error. Implemented by inject_persample.sh:72-74 and 03_appended_sage.sh.

Why the distinction matters

prebuild and preselect are not the same stage under two names: they differ by whether entrapment had to survive clustering. Collapsing them loses the strongest construction claim available. prelake is strictly earlier than both.

Numbers are deliberately absent from this module. Stage metadata describes the design; measured FDPs belong to a run's output record, not to the schema.

EntrapmentStage dataclass #

One injection point and what its FDP therefore estimates.

Source code in fasta_lake/entrapment_stages.py
@dataclass(frozen=True)
class EntrapmentStage:
    """One injection point and what its FDP therefore estimates."""

    name: str
    order: int
    injection_point: str
    faces: tuple[str, ...]
    measures: str
    is_construction_test: bool
    description: str
    reference_script: str

    def as_metadata(self) -> dict:
        """Serialisable metadata for embedding in a manifest or FDP record."""
        d = asdict(self)
        d["faces"] = list(self.faces)
        return d

as_metadata #

as_metadata() -> dict

Serialisable metadata for embedding in a manifest or FDP record.

Source code in fasta_lake/entrapment_stages.py
def as_metadata(self) -> dict:
    """Serialisable metadata for embedding in a manifest or FDP record."""
    d = asdict(self)
    d["faces"] = list(self.faces)
    return d

normalize_stage #

normalize_stage(stage: str) -> str

Map an accepted spelling onto a canonical stage name.

Raises ValueError on anything unrecognised -- the stage determines what a number means and is never guessed.

Source code in fasta_lake/entrapment_stages.py
def normalize_stage(stage: str) -> str:
    """Map an accepted spelling onto a canonical stage name.

    Raises ``ValueError`` on anything unrecognised -- the stage determines what a
    number means and is never guessed.
    """
    if stage in ENTRAPMENT_STAGES:
        return stage
    if stage in STAGE_ALIASES:
        return STAGE_ALIASES[stage]
    raise ValueError(
        f"Unknown entrapment stage {stage!r}. Valid stages, earliest injection "
        f"point first: {', '.join(VALID_ENTRAPMENT_STAGES)}"
    )

get_stage #

get_stage(stage: str) -> EntrapmentStage

Look up a stage, accepting aliases.

Source code in fasta_lake/entrapment_stages.py
def get_stage(stage: str) -> EntrapmentStage:
    """Look up a stage, accepting aliases."""
    return ENTRAPMENT_STAGES[normalize_stage(stage)]

stages_comparable #

stages_comparable(a: str, b: str) -> bool

True only when two stages are the same injection point.

Two construction stages are still not interchangeable: prebuild entrapment had to survive clustering and preselect entrapment did not, so their FDPs are not the same quantity.

Source code in fasta_lake/entrapment_stages.py
def stages_comparable(a: str, b: str) -> bool:
    """True only when two stages are the same injection point.

    Two construction stages are still not interchangeable: ``prebuild`` entrapment
    had to survive clustering and ``preselect`` entrapment did not, so their FDPs
    are not the same quantity.
    """
    return normalize_stage(a) == normalize_stage(b)