Modification-pool detection for specs/039 (pools.csv, default-inert) - #100
Merged
Merged
Conversation
…sion pools found at NODE level (the loop A->F->B->R->A must exist, so uuid-separated copies are not re-merged); base = resting form (the modified side is the product of the donor-consuming direction: ATP/GTP/SAM/acetyl-CoA/NAD+/Ub; else more components; else more modified residues). Additive files; network unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- get_interconversion_pairs: each reaction's only non-small-molecule input is the source form and only output the other form (ubiquitin allowed as a co-substrate), and the two forms share a reference entity. Excludes enzyme binding cycles (E + S -> E:S), release, degradation and two-form reactions, which were 78 of the 102 shipped pools. - find_pools: a reaction node converting two form pairs is dropped with its loops (its node would be written by two fluxes); counted in stats. - orientation: residues first (as pre-registered), then donor, then components (specs/039 amendment 1); undecided pools counted as ties. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…nt 2) A consumer weighs an intrinsic (uncatalysed) step beside a catalysed one for the same pair; the equal split made SOS1 KO read RAS:GTP 0.53 (Fable review). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t 2) Detection now follows one reference entity R through every R-step (a reaction whose exactly one input and exactly one output contain R, both at stoichiometry 1, and differ) instead of one-reaction A <-> B pairs, so a cycle curated as bind / modify / release (RAS:GTP + GAP -> RAS:GTP:GAP -> RAS:GDP + GAP; S -> S:E -> S*:E -> S* -> S*:P -> S:P -> S) is one pool. Neo4j: get_reaction_participants (inputs, outputs, catalysts per reaction), get_form_profiles (proteins, modification signature per R = residues on R's leaves + small molecules of the complex R's leaf sits in through sets, slots, components, residues; cached across pathways), get_set_descendants. r_steps computes the steps and whether each is enzyme-driven (a catalyst or joining input containing a protein and not R; a catalyst that is a form of R is self-catalysis, non-enzyme). get_interconversion_pairs and get_form_modification_counts are replaced. Node level (find_pools): the R-graph is built from reaction nodes whose R-containing input and output nodes map to the step's forms; per R, a strongly connected set with >= 2 forms and >= 2 signatures is a pool (one signature is a carrier loop); states are the fewest-slot forms per signature, the rest intermediates; transitions are simple paths state -> intermediates* -> another state of <= 6 steps, longer dropped and counted; base state by residues, donor, components (ties counted); pools identical for co-travelling proteins are one pool, a node claimed by two different pools is removed from both and everything recomputed; carriers are the enzyme free-form nodes with the release reaction nodes that produce them. A pool with more than 20,000 uuid paths (the copies per step multiply through a shared intermediate) is dropped and counted. Files: pools.csv (pool_id,node_uuid,stable_id,role,is_base), pool_transitions.csv (pool_id,path_id,step,source_uuid,target_uuid, reaction_uuid,reaction_stid,enzyme_driven — the step's flag; a path is enzyme-driven if any step is), pool_carriers.csv (pool_id,carrier_uuid, release_reaction_uuid); all written even when empty. The log reports pools, states, intermediates, paths, multi-step pools, dropped long paths, shared nodes, ties, carriers, carrier loops, merged proteins and autocatalysis by source form / product form / other form. tests/test_pools.py: 12 tests (RAS shape with GEF, self-catalysed hydrolysis and GAP bind-release; six-form ring; an enzyme's own loop is not a pool; shared-node drop; co-travelling merge; path cap; orientation and ties; set member mapping; stoichiometry). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ontract) A path is now its NODE sequence plus the reaction stId at each step. The reaction nodes of that stId between the step's two nodes (variant and set copies) are the step's parallel copies, one row each in pool_transitions.csv: rows sharing (pool_id, path_id, step) have the same source_uuid, target_uuid, reaction_stid and enzyme_driven and differ in reaction_uuid. A consumer reads a step as the mean of its copies and a path as the product of its steps, which equals the sum over the uuid paths the previous commit enumerated (RAF: 48 bind copies x 48 release copies were 2,304 two-step paths; now one path of 96 rows). Different reactions between the same two nodes stay different paths (GEF exchange beside intrinsic exchange), because each is weighed on its own as enzyme-driven or not. POOL_PATH_BUDGET is kept as a guard on the path count; nothing hits it now (before: HRR and EGFR pool1 did). The log adds the step-copy row count. Interpretations of the pre-registered rule, accepted by the deltasignal side and recorded here: - "a catalyst or joining input containing a protein other than R" is read as containing a protein and NOT containing R, so the set p21 RAS:GTP catalysing intrinsic hydrolysis is self-catalysis (non-enzyme) for each RAS member; - "the complex whose direct children include R's leaf" looks through set membership (R97 puts RAS in a set inside p21 RAS:GTP); GAPs in RAS:GTP:GAP get an empty signature, as the derivation checked; - enzyme_driven is written per step; a path is enzyme-driven if any step is; - co-travelling reference entities with identical pools (paralogs of one set) are one pool, counted as merged; only DIFFERENT pools sharing a node trigger the shared-node drop; - states and intermediates on no kept path are omitted and counted; a candidate whose kept states have fewer than two signatures is dropped; - a variant node's proteins are its parent's non-set proteins plus its chosen members'; its signature is the parent's; - the base rule's residues are summed over all leaves (amendment 1 as written), not R's leaves only. tests/test_pools.py: 13 tests; the new one asserts that two reaction nodes of one stId collapse into one path with one row per copy while an intrinsic exchange beside the GEF stays a separate path. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…g paths counted whole Pre-arm review of specs/039 amendment 2 found two generator defects. 1. States from annotation-dependent signatures. Activated FGFR4 <-> FGFR4:PLCG1 <-> FGFR4:p-4Y-PLCG1 (R-HSA-5654743) was a three-state pool of FGFR4, and EGF:p-EGFR:p-ERBB2 / :PLCG1 / p-ERBB2 heterodimers:PTK6 (R-HSA-1227986) three states of ERBB2, because a bound partner's phosphorylation is a signature change for the partner and the receptor's forms differed only by what was bound. Rule (amendment 3): the CORE of a strongly connected set is the proteins every form of it carries; a form is eligible to be a state only if its proteins are exactly the core (small molecules allowed); states are per signature among those; the set is a pool only if its core-only forms carry >= 2 signatures; every other form is an intermediate. An enzyme's own loop has one core-only form, so it is not a pool, as before. On the pools039b build: 5654743 dropped; 1227986 now has two states (p-6Y-EGFR:p-6Y,Y1112-ERBB2 base, p-7Y,Y1112-ERBB2) with the PLCG1 and PTK6 complexes as intermediates; the other 39 pools unchanged. 2. A carrier that is a node of another pool (R-HSA-74752: SHC1's carrier Insulin:p-6Y-IR is the receptor pool's intermediate) is no longer a carrier: nodes any pool manages (states, intermediates, step reaction nodes) are excluded from every carrier list and counted (carrier_conflicts; 1 on the build). 3. long_paths_dropped counts dropped paths (state -> ... -> state over 6 steps), not truncated prefixes. tests/test_pools.py: 15 tests. The shared-node fixture is now two genuine pools (X and Y both phosphorylated inside X:Y); new tests cover the FGFR4 shape (not a pool) against the receptor-phosphorylated shape (a pool), the carrier conflict, and whole-path counting. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…reused loop variables) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detects each protein's modification pool once, at generation time, for deltasignal specs/039 (
DS_CYCLE_MODE=balance). DeltaSignal ignores the three new files by default. The rule was measured and not adopted (deltasignal specs/039 has the numbers), so this PR adds data, not behaviour.Output: every pathway gets
pools.csv,pool_transitions.csvandpool_carriers.csv, written even when empty.Detection (per reference protein R, at uuid level):
Catalog (build 20260928-0115_bdaed8e_pools039d): 40 pools in 18 pathways, 7 of them multi-step. The networks themselves are unchanged (same node and edge counts).
Tests:
tests/test_pools.pyhas 15 tests. Full suite: 1086 passed; the one failure is the MHC ratio test, which already fails on main and is unrelated.ruffis clean.Review: four adversarial end-to-end reviews before any arm, each against the real bundle. Every defect they found is fixed.
Detection was implemented mostly by a Fable 5.1 subagent, against the pre-registered contract in deltasignal specs/039.
🤖 Generated with Claude Code