Skip to content

Drop the LNG_BOUNDARY_LEAF_REUSE escape hatch - #93

Merged
adamjohnwright merged 2 commits into
mainfrom
chore/drop-boundary-leaf-reuse-flag
Sep 21, 2026
Merged

adamjohnwright merged 2 commits into
mainfrom
chore/drop-boundary-leaf-reuse-flag

Conversation

@adamjohnwright

@adamjohnwright adamjohnwright commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

First item in the flag-cleanup queue (deltasignal specs/020-variant-node-sharing/cleanup-plan.md): a flag expires once the question it was added to ask has been answered.

The question, and the answer

LNG_BOUNDARY_LEAF_REUSE=any restored the pre-fix behaviour, where a boundary-decomposition leaf could reuse a node the root complex reaches downstream. That welds a cycle Neo4j never had: root complex -> reactions -> ... -> produced protein -> (assembly) -> root complex. On the v97 catalog, 1,994 of the 2,077 cycle-carrying assembly edges had exactly that shape.

TP53 strongly connected component 836 nodes → 56
DSB Repair 1,127 → ~290
curator held-out (conditioned) +173, p < 1e-4
false-change errors 1,437 → 1,150
experimental axis +3

Full record: deltasignal specs/018-derived-edge-loops/research.md. The gain is 94% concentrated in DSB Repair and is mostly DOWN→NORMAL corrections, which is stated there rather than hidden.

Why the name stays as an error

Deleting the lookup outright would let a stale LNG_BOUNDARY_LEAF_REUSE=any in a shell, a compose file or an old benchmark script be silently ignored — the run would measure the default while the operator believed it was measuring the old mode. That is the silent-input bug class this project has hit four times (DS #40-43), and the reproduction commands in specs/016-019 are exactly the scripts most likely to carry a stale value.

So the variable is still read, and setting it to anything raises, naming the spec:

LNG_BOUNDARY_LEAF_REUSE was removed: boundary leaves never reuse a node
the root complex can reach. See deltasignal specs/018-derived-edge-loops.

Tests

The two mode tests are replaced by one that asserts that error for three values, including both that used to be valid. The four behavioural tests are unchanged and still pass, including the invariant that no assembly source is reachable from its own complex.

check result
tests/test_boundary_leaf_reuse.py 5 passed
full suite 1020 passed, 1 pre-existing MHC failure
ruff check src/ bin/ clean
mypy src/ clean

The ruff format gap on this file predates the change and is repo-wide (15 files); reformatting here would bury a 10-line diff.

🤖 Generated with Claude Code

adamjohnwright and others added 2 commits September 21, 2026 15:06
…rror

The flag existed to ask one question -- does refusing to reuse a node the root
complex can reach lose anything? -- and that question is answered: held-out
+173 conditioned, p<1e-4, false change 1437->1150 (deltasignal specs/018). A
flag whose question is settled is a second code path nobody measures.

Removing it outright would make a stale LNG_BOUNDARY_LEAF_REUSE=any in an
environment or a benchmark script silently measure the default while the
operator believed they were measuring the old mode -- exactly the silent-input
bug class this project has hit four times. So the name is kept as a rejection:
setting it to anything raises, naming the spec. The two mode tests are replaced
by one that asserts that error for three values, including the two that used to
be valid.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adversarial review of the diff found the guard was decorative on both halves.

It had NO runtime coverage. Its only test asserted that a string appeared in
inspect.getsource(), which passes whether or not the guard runs -- mutating it
to `if False and ...` left the whole suite green, and exporting the flag and
running the suite gave the baseline result, because no test reaches that line.
Replaced with a shared _reject_removed_env() helper, unit-tested with
monkeypatch and pytest.raises across five values including "0" and "".

And it could not stop a run even when it fired. bin/create-pathways.py catches
every per-pathway exception, counts it, and returns None -- so a stale flag
meant every pathway raised, nothing was written, the PREVIOUS catalog stayed on
disk, and the shell saw exit 0. A benchmark reading that directory would have
silently scored the old catalog. Now checked once at the top of main() before
any work, and the command exits 1 if any pathway failed. Six other error paths
in main() also returned 0 on failure; all now exit 1.

All three mutations are caught by the new tests: dead guard body, missing
entry-point call, and restored exit-0-on-failure.

The error message also claimed a guarantee the code does not provide. _succ is
a snapshot taken before the emission loop and is not updated as this function
appends its own assembly edges, so a later root complex can still be handed a
leaf that an earlier one made reachable. The reviewer constructed the weld.
That bug is PRE-EXISTING and identical on both sides of this flag removal, so
the comment and message now state the rule precisely rather than overclaiming;
fixing it changes emitted networks and would invalidate the measurement this
rule rests on, so it is tracked separately.

Also: a conftest clears removed names for the whole suite (this diff otherwise
turned a stale export into 10 spurious failures, up from 1), unused monkeypatch
fixtures dropped, and PIPELINE_SETTINGS.md gains a removed-flags table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@adamjohnwright

Copy link
Copy Markdown
Contributor Author

Adversarial review of the diff found the guard was decorative on both halves, and both are fixed in f5cf852.

It had no runtime coverage. The only test asserted a string appeared in inspect.getsource(), which passes whether or not the guard runs. Reproduced twice: mutating it to if False and ... left the suite green, and exporting the flag and running the suite gave the baseline result. No test reached the line. Replaced with a shared _reject_removed_env() helper, unit-tested with pytest.raises across five values including "0" and "".

It could not stop a run even when it fired. bin/create-pathways.py catches every per-pathway exception, counts it and returns None, so a stale flag meant every pathway raised, nothing was written, the previous catalog stayed on disk, and the shell saw exit 0 — a benchmark globbing that directory would have scored the old catalog. Now checked once at the top of main() before any database work, and the command exits 1 if any pathway failed. Six other error paths in main() also returned 0 on failure; all now exit 1.

Three mutations are now caught: dead guard body, missing entry-point call, restored exit-0-on-failure.

One finding deliberately not fixed here. _succ is snapshotted before the emission loop and never updated as the function appends its own assembly edges, so a later root complex can be handed a leaf an earlier one made reachable. The reviewer constructed that weld and it is real — but it is pre-existing and identical on both sides of this flag removal, and fixing it changes emitted networks, which would invalidate the measurement this rule rests on. The comment and error message now state the rule precisely instead of overclaiming, and the bug is tracked separately.

Also: a conftest clears removed names suite-wide (this diff otherwise turned a stale export into 10 spurious failures, up from 1), unused fixtures dropped, and a removed-flags table added to PIPELINE_SETTINGS.md.

CI green against head f5cf852: ruff, test 3.10/3.11/3.12.

adamjohnwright added a commit that referenced this pull request Sep 21, 2026
…n fail

Guard now routes through the shared, tested _reject_removed_env() from #93,
so a stale LNG_SHARE_VARIANT_NODES is rejected at process entry before any
database work and the command exits non-zero. The previous guard had no
runtime coverage at all: its only test asserted a string appeared in
inspect.getsource(), which passed with the guard mutated to `if False and ...`
and broke the moment the guard was refactored. Deleted; tests/test_removed_
env_flags.py now parametrizes over both removed names.

Three factual corrections to the docstring:

- The summary line said "one key per (entity, REACTOME reaction, role)". That
  is FALSE and a reader acting on it would break Phase 2, which looks entities
  up by VIRTUAL reaction. The key is unchanged; the shared thing is the VALUE.
- "-83 and -117 held-out" was wrong on both numbers. specs/016 P12 gives min
  over copies -85 held-out (p 0.0021) and max over copies -322 (p<0.0001);
  -117 is a DSB-Repair-only ACCURACY delta, not a held-out figure.
- The size result now carries the caveat the spec insists on: the -34.6% node
  figure flatters it (no-op in 47 of 92 pathways, median mover 6.7%), the
  -21.5% edge figure is the conservative read, and the zero held-out net comes
  from conditioning that drops 4,094 non-comparable cases while both axes fall
  slightly unconditioned.

The two boundary tests asserted a mechanism that cannot occur -- the variant
cache could only ever store the boundary uuid, so deleting the skip left every
uuid identical. They now assert on the shared/distinct stats, which is what
actually distinguishes the implementations, and the mutation is caught.

Re-verified after all edits: 1500 randomized inputs give 0 differences against
main's share_variants=True path, and HDR (799/3,123) and DNA Repair
(4,756/14,487) reproduce the measured catalog exactly.

Fingerprint honesty: only LNG_EMIT_ONE_SIDED is a genuine cache gap; the other
two are read inside a function that re-runs every time, so they buy provenance
at the cost of a re-fetch. Kept deliberately, now documented as such.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@adamjohnwright
adamjohnwright merged commit 6046689 into main Sep 21, 2026
4 checks passed
@adamjohnwright
adamjohnwright deleted the chore/drop-boundary-leaf-reuse-flag branch September 21, 2026 20:34
adamjohnwright added a commit that referenced this pull request Sep 21, 2026
…tral) (#94)

* Drop the LNG_BOUNDARY_LEAF_REUSE escape hatch; setting it is now an error

The flag existed to ask one question -- does refusing to reuse a node the root
complex can reach lose anything? -- and that question is answered: held-out
+173 conditioned, p<1e-4, false change 1437->1150 (deltasignal specs/018). A
flag whose question is settled is a second code path nobody measures.

Removing it outright would make a stale LNG_BOUNDARY_LEAF_REUSE=any in an
environment or a benchmark script silently measure the default while the
operator believed they were measuring the old mode -- exactly the silent-input
bug class this project has hit four times. So the name is kept as a rejection:
setting it to anything raises, naming the spec. The two mode tests are replaced
by one that asserts that error for three values, including the two that used to
be valid.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Variant-node sharing is now unconditional; close the cache-fingerprint gap

Phase 1 keyed entity uuids on the VIRTUAL reaction, so a participant common to
every variant of a Reactome reaction was photocopied once per set-member
combination. Keying on the Reactome reaction instead is what the data says;
the flag existed only to measure that the correction costs nothing.

Measured on the 92-pathway catalog (deltasignal specs/020):

  nodes             108,229 -> 70,738   (-34.6%)
  edges             285,497 -> 224,189  (-21.5%)
  pathways gaining cyclic nodes            0   (does not undo specs/018)
  predictions changed        29 of 24,100 (0.12%, 3 pathways)
  held-out net, both axes                  0   (zero discordant cases)
  false change             1,150 -> 1,150

Verified that the new default reproduces the measured catalog exactly: HDR
799 nodes / 3,123 edges and DNA Repair 4,756 / 14,487, identical to the
flagged run.

Setting LNG_SHARE_VARIANT_NODES now raises rather than being ignored, so a
stale value in a benchmark script cannot silently measure something else.

Also adds LNG_BOUNDARY_EXPANSION, LNG_COMPOSITION_EDGES and LNG_EMIT_ONE_SIDED
to _FINGERPRINTED_ENV. All three change emitted content, and the list comment
already promised that flipping any fingerprinted flag invalidates stale caches
"silently reusing a network built under the old setting" -- which is exactly
what these three could do.

Docstring fix: the BCDX2 example is 6 reactions, not 5.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Make the removed-flag guard actually stop a run, and test it for real

Adversarial review of the diff found the guard was decorative on both halves.

It had NO runtime coverage. Its only test asserted that a string appeared in
inspect.getsource(), which passes whether or not the guard runs -- mutating it
to `if False and ...` left the whole suite green, and exporting the flag and
running the suite gave the baseline result, because no test reaches that line.
Replaced with a shared _reject_removed_env() helper, unit-tested with
monkeypatch and pytest.raises across five values including "0" and "".

And it could not stop a run even when it fired. bin/create-pathways.py catches
every per-pathway exception, counts it, and returns None -- so a stale flag
meant every pathway raised, nothing was written, the PREVIOUS catalog stayed on
disk, and the shell saw exit 0. A benchmark reading that directory would have
silently scored the old catalog. Now checked once at the top of main() before
any work, and the command exits 1 if any pathway failed. Six other error paths
in main() also returned 0 on failure; all now exit 1.

All three mutations are caught by the new tests: dead guard body, missing
entry-point call, and restored exit-0-on-failure.

The error message also claimed a guarantee the code does not provide. _succ is
a snapshot taken before the emission loop and is not updated as this function
appends its own assembly edges, so a later root complex can still be handed a
leaf that an earlier one made reachable. The reviewer constructed the weld.
That bug is PRE-EXISTING and identical on both sides of this flag removal, so
the comment and message now state the rule precisely rather than overclaiming;
fixing it changes emitted networks and would invalidate the measurement this
rule rests on, so it is tracked separately.

Also: a conftest clears removed names for the whole suite (this diff otherwise
turned a stale export into 10 spurious failures, up from 1), unused monkeypatch
fixtures dropped, and PIPELINE_SETTINGS.md gains a removed-flags table.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Address the diff review: real guard, correct docstring, tests that can fail

Guard now routes through the shared, tested _reject_removed_env() from #93,
so a stale LNG_SHARE_VARIANT_NODES is rejected at process entry before any
database work and the command exits non-zero. The previous guard had no
runtime coverage at all: its only test asserted a string appeared in
inspect.getsource(), which passed with the guard mutated to `if False and ...`
and broke the moment the guard was refactored. Deleted; tests/test_removed_
env_flags.py now parametrizes over both removed names.

Three factual corrections to the docstring:

- The summary line said "one key per (entity, REACTOME reaction, role)". That
  is FALSE and a reader acting on it would break Phase 2, which looks entities
  up by VIRTUAL reaction. The key is unchanged; the shared thing is the VALUE.
- "-83 and -117 held-out" was wrong on both numbers. specs/016 P12 gives min
  over copies -85 held-out (p 0.0021) and max over copies -322 (p<0.0001);
  -117 is a DSB-Repair-only ACCURACY delta, not a held-out figure.
- The size result now carries the caveat the spec insists on: the -34.6% node
  figure flatters it (no-op in 47 of 92 pathways, median mover 6.7%), the
  -21.5% edge figure is the conservative read, and the zero held-out net comes
  from conditioning that drops 4,094 non-comparable cases while both axes fall
  slightly unconditioned.

The two boundary tests asserted a mechanism that cannot occur -- the variant
cache could only ever store the boundary uuid, so deleting the skip left every
uuid identical. They now assert on the shared/distinct stats, which is what
actually distinguishes the implementations, and the mutation is caught.

Re-verified after all edits: 1500 randomized inputs give 0 differences against
main's share_variants=True path, and HDR (799/3,123) and DNA Repair
(4,756/14,487) reproduce the measured catalog exactly.

Fingerprint honesty: only LNG_EMIT_ONE_SIDED is a genuine cache gap; the other
two are read inside a function that re-runs every time, so they buy provenance
at the cost of a re-fetch. Kept deliberately, now documented as such.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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