GDS activation as hygiene signals
Goal
Turn the de-noised CALLS graph into reviewer signals by activating the GDS algorithms Community edition already ships (WCC / Bridges / SCC / articulation / Leiden) plus a custom Cypher phase-order cycle check. Each signal is COMPUTED and materialized on :Symbol here; surfacing them as intel-query.sh subcommands is the sibling query-primitives section’s job.
Dependency
- Consumes the de-noised CALLS graph delivered by
calls-resolution-precision(s-1209f1e9): GDS projections run over CALLS edges with zero non-callable-kind edges and arity-recovered homonyms. - Declared as
hint_needs:in route state. s-1209f1e9 is route-order section 2, this is section 4 — a valid forward edge per linear-DAG INV-19. - Running these algorithms over the pre-de-noise graph re-introduces the extend-collision and homonym false edges as false hygiene signals.
Compute-vs-wrap boundary (with query-primitives s-9fb83bc7)
- gds-activation (this section) COMPUTES the GDS signals and writes each as a property on
:Symbolnodes (the materialized graph-enrichment surface). - query-primitives (s-9fb83bc7, w-ae23d73a) WRAPS those materialized signals as
intel-query.sh dead-code/intel-query.sh layering-checksubcommands and feeds them into the phase-2.5-graph-recon pre-pass. - query-primitives’ dead-code and layering-check primitives consume THIS section’s materialized GDS signals: their unblock-point is s-4e62453e (this section), not the raw de-noised walking-skeleton at s-1209f1e9. The query-primitives body (s-9fb83bc7) reflects this — its Implementation Sketch and w-ae23d73a reference s-4e62453e as the predecessor that materializes the signals they wrap.
- This section’s success criterion (sc-89902b3f) asserts pytest + live-graph property materialization, NOT an
intel-query.sh layering-check / dead-codecommand-probe — those subcommands are query-primitives deliverables that do not exist at this section’s close.
Reference-delta — gds_enrich.py must be EXTENDED
intel_repo/neo4j/gds_enrich.pyruns ONLY PageRank / betweenness / Leiden under GDS 2.13.x.- The WCC / Bridges / SCC / articulation projections named in the work items are valid GDS-CE algorithms but are NOT yet wired there.
- This section EXTENDS
gds_enrich.pywith the new per-algorithm projections and property writes; it does not assume they already exist. - Verify the deployed GDS-CE algorithm catalogue at implementation start before committing each projection.
Implementation Sketch
Materialize a Symbol.crate property via the existing path classifier, then project per-algorithm GDS graphs over a test/doc-filtered node set: WCC from a defined root-set (dead code), Bridges/SCC across the crate property (layering), articulation/betweenness (blast radius), Leiden spanning crates (scattered knowledge), and a custom-Cypher SCC-based phase-order cycle check. Each maps to a reviewer signal and writes a property onto :Symbol.
Pre-work decision 1 — test/doc projection filter (load-bearing)
Roughly half the ori symbol corpus is test/doc-path (50.5% at last graph sync — recompute by bucketing every :Symbol {repo: 'ori'} node through intel_repo/neo4j/path_class.py:_is_test_or_doc_path (the same predicate metrics.py Score B + hotspot apply) and dividing the test/doc-classified count by the total; re-confirm against the live graph at implementation start). An unfiltered GDS projection drowns every reviewer signal in test-fixture noise. Filter the projection node set with the existing intel_repo/neo4j/path_class.py:_is_test_or_doc_path predicate (already used by metrics.py Score B + hotspot) BEFORE WCC (dead-code), Leiden (scattered-knowledge), and articulation (blast-radius). Apply a Leiden post-filter that drops communities dominated by test symbols so scattered-knowledge surfaces production clusters.
Pre-work decision 2 — WCC dead-code root-set (load-bearing)
- WCC-from-roots dead-code detection requires the root set to be
@mainentry points pluspub-exported entry points. - Without that explicit root-set, symbols reachable only from un-chosen roots become false-positive dead code.
- Define the root-set as
@main+pubfunction entry points; the WCC component holding NO root symbol is the dead-code candidate set.
Pre-work decision 3 — Symbol.crate must use the robust classifier (not a path split)
Deriving Symbol.crate from a hardcoded split(file,'/')[1] is layout-sensitive: a leading prefix or a moved crate root silently mis-buckets every symbol and corrupts Bridges/SCC layering detection. Use path_class.py with a defined crate-bucket allowlist; leaf-classify or EXCLUDE non-layer buckets (test/doc/generated) before the layering projection runs.
Pre-work decision 4 — phase-order ordering uses gds.dag.topologicalSort; cycle detection stays custom Cypher
- GDS-CE 2.13.x DOES ship a native topological-sort procedure —
gds.dag.topologicalSort.stream(alongsidegds.dag.longestPath.stream), confirmed in the deployed catalogue viaCALL gds.list(). gds.dag.topologicalSortyields a topological ORDERING over a presumed-acyclic graph; it is not itself a cycle detector. Use it to produce the crate-layer ordering signal.- Phase-order CYCLE detection (the reviewer signal that flags a layering back-edge) still requires a custom Cypher SCC/path check over the crate-layer DAG — a topo-sort does not report the offending back-edge.
- Confirm the deployed GDS-CE catalogue at implementation start before committing each procedure.
Work Items
Every work item below authors its slice of the pytest coverage in intel_repo/tests/test_gds_enrich_unit.py (success criterion sc-89902b3f) — extending the existing module test, NOT a new file under neo4j/ (the GDS tests live in intel_repo/tests/) — BEFORE the projection/Cypher code it tests — tests precede code per the TDD discipline, so no work item closes implementation-only. The shared coverage spans projection lifecycle (project -> run -> write -> drop), the test/doc projection filter, the WCC root-set, and the per-algorithm candidate ceilings; each item contributes the assertions for the signal it materializes. A dedicated test-authoring work_item is the canonical WBS shape for sc-89902b3f — minting that route node is a plan-engine operation, surfaced in the editor handoff.
- Materialize a Symbol.crate property via
path_class.pywith a crate-bucket allowlist (NOTsplit(file,'/')[1]), excluding non-layer buckets, so GDS can project a layer dimension robustly under layout changes. - WCC-from-roots (
@main+pubentry-point root-set) over the test/doc-filtered de-noised CALLS graph -> dead-code candidates; root-holding components are live, root-less components are candidates. - Bridges / SCC-across-the-crate-property over the layer-bucketed projection -> layering-violation detection.
- Blast-radius ranking over the test/doc-filtered projection, written as a
:Symbolblast-radius property. betweenness is ALREADY computed bygds_enrich.py(per the Reference-delta above — it already runs PageRank / betweenness / Leiden), so it needs only a re-run over the filtered/de-noised projection, NOT fresh wiring; articulation-points is the genuinely new GDS-CE projection to add here. - Two distinct mechanisms (per Pre-work decision 4), each writing its own reviewer property onto
:Symbol: (a) Leiden-spanning-crates with a test-community post-filter -> scattered-knowledge (a GDS-CE projection); (b) phase-order validation —gds.dag.topologicalSort(native GDS-CE, available now) produces the crate-layer ordering, with a custom SCC/path Cypher check over the crate-layer DAG for the cycle detection topo-sort does not itself report. These two mechanisms are tracked under one work-item node here; splitting them into separate route nodes is a route-substrate change owned by the plan engine (surfaced in the editor handoff).
References
intel_repo/neo4j/gds_enrich.py (EXTEND with WCC/Bridges/SCC/articulation projections + property writes); intel_repo/neo4j/path_class.py (_is_test_or_doc_path projection filter + crate-bucket classifier); intel_repo/neo4j/metrics.py (Score B / hotspot filter precedent); .claude/rules/missions.md (per-crate layering constraints); query-primitives s-9fb83bc7 (downstream query-surface wrapper).