From 5f3676bda5b6a6c7a7e39a72a2a5aa4d3d18be10 Mon Sep 17 00:00:00 2001 From: Adam Wright Date: Thu, 10 Sep 2026 15:09:38 -0400 Subject: [PATCH] Add CLAUDE.md pointing at the specs rather than restating them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo had no CLAUDE.md, so an agent starting cold rediscovered the same traps each time: regenerating into a populated directory is a silent no-op because pre-fingerprint caches get adopted, PYTHONHASHSEED must be set before the interpreter starts, output/ is gitignored so those tests skip in CI, and more than one "the generator drops X" investigation has ended in the artifact being from a different Reactome release than the database. Now that spec-kit is in use the why belongs in specs/NNN-name/, so this file carries current state and pointers only. docs/DESIGN_DECISIONS.md and docs/UUID_DESIGN.md stay where they are: representational semantics are current state, not feature history. Also records the division of labour that keeps getting relitigated — the generator represents pathways as curators authored them, DeltaSignal decides how to process that — and the A/B protocol the benchmark needs, since non-converged solves return different values for a structurally identical network. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e06407d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,84 @@ +# CLAUDE.md + +Guidance for Claude Code working in this repository. + +This repo is the **upstream** of DeltaSignal: it reads Reactome from Neo4j and +emits the logic-network TSV/CSV that `~/gitroot/deltasignal` consumes. The +division of labour is deliberate — **the generator represents pathways the way +curators authored them; DeltaSignal decides how to process that +representation.** Do not push modelling choices upstream into the generator. + +## Where design decisions live + +This repo uses spec-kit. **`specs/NNN-name/` is the record of why** — what was +measured, what was rejected, and the numbers. This file carries only current +state; per-feature results belong in that feature's `research.md`, not here. +Before changing generation behaviour, read the spec for the last feature that +touched it rather than re-deriving from the code. + +- `specs/001-validator-fidelity/` — the validator must be able to fail. +- `specs/002-break-apart-memo/` — the memo returned components where the + function returned combinations, so a repeated Complex degraded into "any + one of my subunits". +- `specs/003-bridge-cofactor-guard/` — cofactor guard on diagram bridges. +- `.specify/memory/constitution.md` — principles the specs are checked + against. +- `docs/DESIGN_DECISIONS.md`, `docs/UUID_DESIGN.md`, + `docs/ARCHITECTURE.md` — durable representational semantics (Complex vs + EntitySet, the two decomposition layers, uuid scheme). These are current + state, not history, and stay where they are. +- Behaviour that is not yet a spec is tracked as GitHub issues on + `reactome/logic-network-generator`. + +## Running + +Configuration is `.env` (see `.env.example`); `NEO4J_URL`, `NEO4J_USER`, +`NEO4J_PASSWORD` reach the connector via `load_dotenv`. + +```bash +poetry run python bin/create-pathways.py --pathway-id R-HSA-69620 +poetry run python bin/create-pathways.py --pathway-list pathways.tsv +poetry run python bin/create-pathways.py --top-level-pathways +``` + +Tests are tiered; the default tier needs no database: + +```bash +poetry run pytest -m "not database and not integration" +poetry run pytest -m integration # needs output/ from a prior run +poetry run pytest -m database # needs a running Reactome Neo4j +``` + +See `README.md` for the full CLI and `PIPELINE_SETTINGS.md` for the +`LNG_*` switches. + +## Traps that have cost real time + +- **Regenerating into a populated directory can be a silent no-op.** + Pre-fingerprint caches have no fingerprint, so `_cache_is_reusable` adopts + them and reproduces the old networks while reporting success. `rm -rf + /*/cache` before any regeneration you intend to be real. This + has invalidated an A/B before. +- **`PYTHONHASHSEED` must be set before the interpreter starts** or output is + not reproducible; `bin/create-pathways.py` re-execs itself to enforce it. + `LNG_ALLOW_NONDETERMINISM=1` opts out. +- **`output/` is gitignored.** Tests that read it skip in CI, so a local + failure there is not necessarily a CI failure — and a CI pass is not + evidence those tests ran. +- **Version skew is the first thing to check, not the last.** More than one + "the generator drops X" investigation has ended in the artifact being from + a different Reactome release than the database being queried. +- Credentials can reach logs through py2neo's own exception reprs; + `src/credential_redaction.py` scrubs at the output boundary. Do not + reintroduce per-call-site redaction — it was proven insufficient. + +## Validating changes against DeltaSignal + +Generation changes are only meaningful if they move accuracy, and the +benchmark is noisy in a specific way: uuid4 node ids are minted fresh per +build, dict order follows them, and that sets solve order inside a cyclic +component — so **a non-converged solve returns different values for a +structurally identical network.** Any A/B must (1) build both arms from the +same catalog directory or report the network-hash overlap, (2) give a +per-pathway net breakdown, and (3) count changed predictions where both arms +converged. See `~/gitroot/deltasignal/specs/002-upregulation-propagation/quickstart.md`.