{
  "dataset": "SMARTFlexDB apo-holo pair table",
  "schema_version": 12,
  "data_file": "smartflexdb_pairs.tsv",
  "generated_utc": "2026-09-22T18:38:28Z",
  "source": {
    "file": "data_20260919b/showcase.json",
    "sha256": "dff04c210c0c879295d3df166f4bb919f03eb6ada37c342bde27a68cd424c4e7"
  },
  "tool_manifest": "/api/versions",
  "tool_manifest_generated_utc": "2026-09-21T06:08:02+00:00",
  "input_list_sha256": "ffd57b81c5a374474449aa114098f3bac01b0a101a9fb387fdf53f798a35ac6f",
  "rows": 1187,
  "rows_by_apo_qualified": {
    "qualified": 1187,
    "unqualified": 0,
    "unjudged": 0
  },
  "changes": {
    "schema_version_from": 11,
    "schema_version_to": 12,
    "date": "2026-09-22",
    "items": [
      "one row per POCKET-LEVEL COMPARISON - one binding pocket against one apo structure it is compared with (was: one row per apo-holo entry and host RNA strand): 1,187 rows instead of 794, every served binding pocket has its own row, and `pocket_rmsd`, `pocket_size`, `hbonds`, `mw`, `logp`, `lig_resseq` and the two motif columns are that binding pocket's own",
      "`ligand` is this binding pocket's own ligand (was: every ligand on the row's host RNA strand, joined with '; '), so the column holds one CCD code",
      "`id` is unchanged (`<binding pocket id>__apo_<APO PDB>`) and is now the row key on its own; group on (holo_pdb, apo_pdb) for the 734 apo-holo entries",
      "sidecar: `row_unit.collapse_is_lossy` and `served_records.binding_pockets_without_a_row` are empty by construction; `row_unit.representative` says there is none",
      "REMOVED at schema_version 11 (2026-09-19): the `apo_role` column (33 -> 32 columns)",
      "REMOVED at schema_version 11 (2026-09-21): the rows of apo structures the sequence check refused"
    ],
    "items_schema_version_11": [
      "column `apo_role` removed (33 -> 32 columns); `holo_rna_chain` moves from column 33 to column 32, every other column keeps its name, meaning and order",
      "`id` is the entry id `<binding pocket id>__apo_<APO PDB>` on every row, the binding pocket's own apo structure included (was the bare binding pocket id, or `<binding pocket id>__alt_<APO PDB>`); /api/pair/{id}, /api/bundle/{id} and /api/thumb/{id} accept it, and the old forms still work",
      "sidecar: `rows_by_apo_role` removed; `rows_by_apo_qualified` is one count per verdict; `served_records.ids_without_a_default_row` replaced by `binding_pockets_without_a_row`; `row_unit.unqualified_apo_states` renamed `unqualified_apo_structures`; `row_unit.alternatives_deduped_by` renamed `apo_deduped_by`; `row_unit.collapse_is_lossy` reports one census, `combinations`; this `changes` block added",
      "rows in ascending order of `id`: a binding pocket's rows together, by apo PDB ID (was: grouped, each group opening with one designated apo structure)",
      "sidecar: `apo_copies_emitted` and `apo_copies_present` removed; the `apo_chain` column note states which chain is used when the apo structure holds the same RNA chain several times",
      "rows whose apo structure failed the sequence check removed (2026-09-21; they were kept and marked `apo_qualified = unqualified`): every row is an entry the site shows, and `apo_qualified` now reads `qualified` or `unjudged`"
    ]
  },
  "row_unit": {
    "unit": "one row per POCKET-LEVEL COMPARISON: one binding pocket against one apo structure",
    "key": [
      "id"
    ],
    "key_columns": [
      "id"
    ],
    "key_note": "`id` is `<binding pocket id>__apo_<APO PDB>` and is unique: the binding pocket before the infix, the apo structure after it. Group on (`holo_pdb`, `apo_pdb`) for the apo-holo ENTRIES of the release, and count distinct binding-pocket ids for the BINDING POCKETS. `holo_chain` (published again as `holo_rna_chain`, equal on every row; measured equal on 434 of 434 served records at emit time) is the host strand the geometry belongs to",
    "definition": "backend/export_dataset.py::plan_rows (one row per served binding pocket and offered apo structure; the same population as /api/pairs)",
    "representative": "none: every served binding pocket has its own row, and every cell is that binding pocket's own",
    "apo_deduped_by": "apo PDB id: a binding pocket has one row per distinct apo structure it is compared with",
    "changed": "2026-08-15 (schema_version 7 -> 8): rows used to be one per served POCKET RECORD, which made this file disagree with the Database table it is downloaded from; 2026-09-14 (schema_version 9 -> 10): re-keyed from (holo_pdb, ligand, apo_pdb) to (holo_pdb, apo_pdb, holo_rna_chain); 2026-09-17: vocabulary only - the (holo_pdb, apo_pdb) pair, formerly called a comparison, is now called an ENTRY, and the row set is unchanged; 2026-09-19 (schema_version 10 -> 11): the row set is unchanged, see `changes`; 2026-09-21: the rows whose apo structure failed the sequence check were removed, see `changes`",
    "unqualified_apo_structures": {
      "ruling": "an apo structure whose sequence-qualification verdict is FALSE is not offered on the Database page or a pair page and has no row in this download (owner ruling 2026-09-21; from 2026-09-13 until then such rows were kept and flagged 'unqualified' in the apo_qualified column)",
      "rule": "pipeline/seq_qualification.py judges it; pipeline/serve_filter.py::seq_unqualified is the serve gate, and it fires on `is False` and nothing else - an UNJUDGED apo structure is not a refused one",
      "read_it_as": "every row is an entry the site shows; no filtering is needed to reproduce the site's entries",
      "entries_not_in_this_file": 23
    },
    "collapse_is_lossy": {
      "note": "no binding pocket shares another's row: the unit is the pocket-level comparison, so every served binding pocket is published with its own values",
      "combinations": {
        "dropped": 0,
        "differ_from_the_row_that_survives": 0,
        "columns_that_move": {}
      }
    }
  },
  "served_records": {
    "served": 434,
    "built": 761,
    "rule": "pipeline/serve_filter.py::serve_hide_reasons",
    "without_a_row": 0,
    "note": "434 served binding pockets, 1187 rows: one row per binding pocket and apo structure it is compared with, so every served binding pocket has a row of its own. The rows cover the 734 apo-holo entries the site shows, over 266 holo structures; the 23 (holo, apo) pairings the sequence check refused have no row",
    "binding_pockets_without_a_row": []
  },
  "row_order": "rows in ascending order of id (<binding pocket id>__apo_<APO PDB>): a binding pocket's rows together, by apo PDB ID",
  "binding_site": {
    "cutoff_angstrom": 8.0,
    "definition": "any ligand heavy-atom contact <= 8.0 A, across EVERY contacting RNA chain"
  },
  "license": "CC-BY-4.0 (derived data); coordinates from the RCSB PDB",
  "read_with": {
    "pandas": "read_csv(path, sep=\"\\t\", comment=\"#\")",
    "R": "read.table(path, sep=\"\\t\", header=TRUE)"
  },
  "filter_state": null,
  "columns": [
    {
      "name": "id",
      "unit": "key",
      "side": "entry",
      "chain_scope": null,
      "note": "the entry id <binding pocket id>__apo_<APO PDB> - this row's binding pocket and its apo structure, and the key of the row (unique). /api/pair/{id} and /api/bundle/{id} accept it; the binding pocket in the id is the one this row measures: since 2026-09-22 every served binding pocket has its own row against every apo structure it is compared with, so no row speaks for another binding pocket (1187 rows in this release)"
    },
    {
      "name": "holo_pdb",
      "unit": "PDBID",
      "side": "holo",
      "chain_scope": "structure"
    },
    {
      "name": "holo_chain",
      "unit": "auth",
      "side": "holo",
      "chain_scope": "host",
      "note": "RNA HOST chain (= holo_rna_chain; at-rest R6)"
    },
    {
      "name": "lig_auth_chain",
      "unit": "auth",
      "side": "holo",
      "chain_scope": "ligand instance",
      "note": "the chain the LIGAND sits on; identical to holo_chain on all 434 served pockets in this release - since the 2026-07-31 host-chain repoint the builder sets the RNA host chain from the ligand's auth chain, so a join on either column attributes the same way"
    },
    {
      "name": "ligand",
      "unit": "CCD",
      "side": "holo",
      "chain_scope": "ligand instance",
      "note": "the CCD code of THIS binding pocket's ligand - one code per row since schema_version 12 (2026-09-22), because a row is one binding pocket. The cell does NOT depend on which apo the row names. The Database page's own CSV has a column of the same name whose row unit is the ENTRY - one (holo_pdb, apo_pdb) - and whose cell lists every ligand of the HOLO STRUCTURE, joined with '; ', so it is a superset of this one (0 of this release's 1187 rows carry more than one code; the unit is one binding pocket, so the column holds a single ligand)"
    },
    {
      "name": "lig_resseq",
      "unit": "auth#",
      "side": "holo",
      "chain_scope": "ligand instance"
    },
    {
      "name": "apo_pdb",
      "unit": "PDBID",
      "side": "apo",
      "chain_scope": "structure"
    },
    {
      "name": "apo_chain",
      "unit": "auth",
      "side": "apo",
      "chain_scope": "host",
      "note": "the apo chain paired to holo_chain by the superposition; where the apo structure holds the same RNA chain several times, the one with the fewest missing residues"
    },
    {
      "name": "rna_type",
      "unit": "class",
      "side": "holo",
      "chain_scope": "host entity",
      "note": "NAKB curated functional class; \"Unannotated\" where NAKB annotates the host entity with none"
    },
    {
      "name": "method",
      "unit": "enum",
      "side": "holo",
      "chain_scope": "structure"
    },
    {
      "name": "resolution",
      "unit": "A",
      "side": "holo",
      "chain_scope": "structure"
    },
    {
      "name": "identity",
      "unit": "%",
      "side": "pair",
      "chain_scope": "ligand auth chain",
      "note": "BLAST pident - ALIGNED REGION ONLY"
    },
    {
      "name": "global_identity",
      "unit": "%",
      "side": "pair",
      "chain_scope": "ligand auth chain",
      "note": "Needleman-Wunsch over DECLARED SEQRES; every mismatch AND gap column counts"
    },
    {
      "name": "holo_len",
      "unit": "nt",
      "side": "holo",
      "chain_scope": "host",
      "note": "RNA-polymer length of the host chain only (gemmi CCD is_nucleic_acid OR the entry's own _entity_poly declaration) - NOT the modeled/SEQRES count the pair page's 3D-incompleteness warning uses"
    },
    {
      "name": "apo_len",
      "unit": "nt",
      "side": "apo",
      "chain_scope": "host",
      "note": "RNA-polymer length of the host chain only (gemmi CCD is_nucleic_acid OR the entry's own _entity_poly declaration) - NOT the modeled/SEQRES count the pair page's 3D-incompleteness warning uses"
    },
    {
      "name": "num_chains",
      "unit": "count",
      "side": "holo",
      "chain_scope": "pocket",
      "note": "RNA chains with a contact <= 8 A"
    },
    {
      "name": "has_protein",
      "unit": "bool",
      "side": "holo",
      "chain_scope": "structure",
      "note": "residue composition (gemmi CCD), amino-acid majority"
    },
    {
      "name": "has_dna",
      "unit": "bool",
      "side": "holo",
      "chain_scope": "structure",
      "note": "carries a MAJORITY-DEOXY chain (gemmi CCD residue composition, strict > 50%) - a minority of 2'-deoxy residues in an RNA oligo does NOT count; the depositor's _entity_poly.type is not used"
    },
    {
      "name": "rmsd",
      "unit": "A",
      "side": "pair",
      "chain_scope": "all pocket chains",
      "note": "POOLED C3' RMSD over the chains in the fit - every <= 8 A pocket chain with a distinct injective apo counterpart - in the one published superposition frame; reduces to the host chain alone wherever the fit had a single chain to solve on, which showcase.json marks fit_mode=host_only (single-chain pockets, pockets whose strands would share one apo chain, and a pocket whose second chain has no injective apo counterpart)"
    },
    {
      "name": "host_rmsd",
      "unit": "A",
      "side": "pair",
      "chain_scope": "host",
      "note": "the ligand host chain (lig_auth_chain) measured IN THE PUBLISHED all-chain frame; == rmsd for a single-chain pocket, larger than host_rmsd_local when the pocket's chains have moved relative to each other"
    },
    {
      "name": "host_rmsd_local",
      "unit": "A",
      "side": "pair",
      "chain_scope": "host",
      "note": "the ligand host chain's OWN best fit (frame-independent) - the successor of the pre-2026-08-05 `host_chain_rmsd` column, which was that same host-only fit. host_rmsd - host_rmsd_local is the inter-chain hinge signal"
    },
    {
      "name": "tm_score",
      "unit": "0-1",
      "side": "pair",
      "chain_scope": "host",
      "note": "US-align"
    },
    {
      "name": "pocket_rmsd",
      "unit": "A",
      "side": "pair",
      "chain_scope": "all pocket chains",
      "note": "RMS C3' shift over the <= 8 A binding-site residues"
    },
    {
      "name": "pocket_size",
      "unit": "count",
      "side": "holo",
      "chain_scope": "all contacting chains",
      "note": "interactions3d rows <= 8 A"
    },
    {
      "name": "hbonds",
      "unit": "count",
      "side": "pair",
      "chain_scope": "all contacting chains",
      "note": "H-BONDED BINDING-SITE RESIDUES (interactions3d rows typed hbond) - NOT the atom-level DSSR donor/acceptor pairs the pair page's Hydrogen-bonds tab lists; that count is len(dssr_hbonds) on /api/pair and differs on 307 of the 404 served records that carry a non-empty dssr_hbonds (larger on 307, smaller on 0); the other 30 carry none, so the tab falls back to these very rows"
    },
    {
      "name": "mw",
      "unit": "Da",
      "side": "ligand",
      "chain_scope": null
    },
    {
      "name": "logp",
      "unit": "--",
      "side": "ligand",
      "chain_scope": null
    },
    {
      "name": "rg_delta",
      "unit": "A",
      "side": "pair",
      "chain_scope": "all pocket chains",
      "note": "rg_holo - rg_apo, each the radius of gyration of the C3' atoms of the apo<->holo ALIGNED CORE of every chain in the superposition fit set, POOLED into one point cloud per state - the same residues `rmsd` is measured over, so the three descriptors describe the same object. On a multi-chain pocket a near-zero value therefore means the whole binding unit kept its SIZE, not that each strand did: an inter-chain rearrangement now enters rg_delta as it already enters rmsd"
    },
    {
      "name": "pocket_motifs",
      "unit": "list",
      "side": "holo",
      "chain_scope": "host",
      "note": "x3dna-dssr motif types whose residues overlap the <= 8 A binding site, \"; \"-joined - the COARSE level, in which every N-way junction is collapsed to the single value \"junction\". THIS is the value the Database facet, the Statistics \"Pocket motifs\" bars and every ?motif= link filter on, so it is the column that reproduces a filtered selection; pocket_motifs_fine carries the subtype"
    },
    {
      "name": "pocket_motifs_fine",
      "unit": "list",
      "side": "holo",
      "chain_scope": "host",
      "note": "the SAME computation with DSSR's raw type kept, so a junction reads \"4-way junction\"; identical to pocket_motifs on a pocket with no junction. A LABEL SET, NOT A PARTITION of the coarse value - measured at emit time over the 434 served binding pockets: the 219 that carry a junction carry 324 subtypes between them, so summing per-subtype counts overcounts the junction population by 105 - count distinct rows. This file's rows are binding-pocket comparisons, so a binding pocket is counted once per apo structure it is compared with: 627 of its 1187 rows carry a junction, 1030 subtypes between them"
    },
    {
      "name": "apo_qualified",
      "unit": "enum",
      "side": "pair",
      "chain_scope": "all pocket chains",
      "note": "the SEQUENCE-QUALIFICATION verdict of THIS ROW's apo structure (pipeline/seq_qualification.py): qualified | unqualified | unjudged - every binding-site chain has a paired apo chain whose 8 A site positions all match, and the two author-declared assemblies carry the same RNA strand count (that half is a WHOLE-ASSEMBLY check, wider than this column's chain scope). UNJUDGED IS NOT UNQUALIFIED: only an explicit refusal is one, and a row this release did not judge must not be read as failing - the serve rule (pipeline/serve_filter.py::seq_unqualified) hides on `is False` and on nothing else. An apo structure the check refused is not offered on the Database page or a pair page and has no row here either (owner ruling 2026-09-21), so every row is an entry the site shows; measured at emit time - of this release's 1187 rows 1187 are qualified, 0 are unqualified and 0 are unjudged"
    },
    {
      "name": "holo_rna_chain",
      "unit": "auth",
      "side": "holo",
      "chain_scope": "host",
      "note": "the third field of this file's ROW KEY. Identical to `holo_chain` on every row by construction (at-rest R6); published under the key's own name so the grouping can be reconstructed from the file. Known redundancy, 2026-09-14"
    }
  ],
  "data_file_sha256": "fdb41b55eb429b9284a83d4eca48ce387a4813fb24c4f36fdc607b9c8b5dc920"
}
