Orchestrata Ultimate › Plans › graph-rename-plan

Graph Rename Plan — eradicate neo4j vocabulary, technology- and platform-agnostic

Source: plans/graph-rename-plan.md at 8a2cb42ad · last changed 2026-07-27 · first committed 2026-07-27 · 409 lines.

Prose pending.

Plan text

Graph Rename Plan — eradicate neo4j vocabulary, technology- and platform-agnostic

Status: DRAFT — awaiting Mohamed's ratification Date: 2026-07-27 · Session 255 Directive (verbatim): "you must rename neo4j to graph, I want graph, technology and platform agnostic" Execution model: Claude Opus 5 orchestrates (NO edits), work delegated to Kimi (IRC), MiniMax M3, and Claude subagents in this window.


1. Diagnosis — where we are and why

1.1 Current state (measured 2026-07-27 11:47)

Fact Value
Suite 1451 / 1455 pass (362 s), report reports/run-tests-phase51-final.json
Branch master, in sync with origin at 0dc0af6b (Neo4j containers destroyed + Terraform pruned)
Working tree 107 dirty files — the uncommitted KG_* env-seam wave + gw→slot vocabulary fix
Infrastructure Neo4j servers GONE (4 containers destroyed, irreversible). One orchgraph cluster: coordinators 10.92.53.160/.109/.198 (bolt 7691), test node 10.92.53.167:7687, no auth anywhere
Live services gateway + kernel restarted and running on KG_* env alone — verified against production

1.2 The 4 remaining failures — all one defect class

Every failure is a test pinning a retired string against code already renamed. Zero production failures.

Module Site Root cause
tests/scripts/test_health_check.py :336–349 asserts "NEO4J_PASSWORD" in stdout; check now reports Missing KG_ROUTING_URI
tests/scripts/test_repair_divergent_volk_aliases.py :210–235 asserts "No Neo4j URI configured" + old configured_uris key expectations; script now says No graph URI configured — set KG_ROUTING_URI or KG_URI and reads KG keys
tests/scripts/test_kg_query_parity.py :56–378 calls _resolve(..., "NEO4J_URI", ...) — a parameter the resolver no longer takes. Deeper: the script's purpose (Neo4j↔orchgraph parity) died with the migration
tests/scripts/test_diagnose_test_failure.py :348–352 vs scripts/diagnose_test_failure.py:371 asserts "NEO4J CONSTRAINTS:" header — stale name and a real gap: per-slot orchkg_w<N> databases have 0 constraints while production orchkg has 78, so the section is honest-but-empty on workers

1.3 Why this has taken >1 day (honest accounting)

  1. Three entangled waves executed serially in one window: physical decommission (irreversible, careful), env-seam retirement (NEO4J_*→KG_*, ~92 files), and vocabulary (gw→slot).
  2. Every verification cycle is a ~6-minute full suite (1455 modules, real infra, kernel gRPC preflight, six gates).
  3. Two self-inflicted regressions from half-applied renames (the gw→slot rename broke 4 unrenamed Redis slot parsers → 54 failures → diagnose → fix → re-run). The lesson is encoded below: every rename task owns all references to its symbols, verified by a zero-refs gate, not by eyeball.
  4. Live verification (gateway/kernel restarts, production graph queries) is not skippable (RUL-012) and is serial.

The fix for the timeline is parallelism: disjoint task packages, multiple agents, serialized merges, one authoritative gate at the end.

1.4 Remaining neo4j footprint (measured)


2. Naming policy (the rules every agent applies)

  1. Project-owned vocabulary becomes graph. Module names, class names, function names, error strings, report headers, CLI help, env-check messages, doc prose describing current infrastructure.
  2. The PyPI package neo4j stays. from neo4j import GraphDatabase is the Bolt driver library — an external name. It remains, confined behind the access layer. Never touch an import of the neo4j package itself.
  3. Adapters are named for the protocol, not the vendor. core/graph/adapters/neo4j_{async,sync}.py wrap the Bolt driver → become bolt_{async,sync}.py, classes BoltAsyncRepository/BoltSyncRepository. Bolt is spoken by Neo4j, Memgraph, and orchgraph alike — that IS the technology-agnostic name for a driver adapter.
  4. Env keys stay KG_*. KG_ROUTING_URI, KG_URI, KG_DATABASE, KG_ENGINE, KG_WORKER_COUNT contain no vendor name; they were the agnostic seam this whole migration built. No churn.
  5. Historical prose stays. Comments/docstrings explaining the decommission ("retired with the Neo4j containers on 2026-07-27") are history, not live-infra claims — keep them. Session-numbered historical docs (docs/session-157-*.md) keep their period wording.
  6. KG_ENGINE values stay engine names ("memgraph"). Selecting an engine is the one place technology names are the correct vocabulary.

Grep acceptance gate per package (what "done" means): in every file the package owns, grep -in 'neo4j' matches ONLY: (a) import neo4j/from neo4j driver lines, (b) historical prose referencing the decommission/migration, (c) neo4j:// URI scheme literals (the routing scheme the driver defines — external, like the package name).


3. Execution model

3.1 Roles

3.2 Sequencing

P0 (land pending wave on feat/graph-rename, push)      ← gate for everything
   ├── P1  core access layer          (Claude subagent A)   ─┐
   ├── P2  knowledge_graph package    (Claude subagent B)    │ parallel,
   ├── P3  orchestrator + kernel audit (Kimi #1)             │ disjoint
   ├── P4  session/memory/harness     (MiniMax #1)           │ ownership
   ├── P5  scripts family + 3 failing tests (MiniMax #2)     │
   └── P6  retire migration one-shots (Kimi #2)             ─┘
P7 (tests/config 676 refs + .env.example + docs + LEVEL0)   ← after P1–P6 merge
FINAL GATE (full suite 1455/1455 + rulings gates) → merge to master → push → wiki/session close

Merge queue order: P6 → P1 → P2 → P3 → P4 → P5 → P7. Orchestrator merges into feat/graph-rename one at a time, running each package's targeted tests post-merge. A branch that conflicts is rebased by its owner (or a spawned subagent), never by the orchestrator's hands.

3.3 Worktree protocol (Kimi / MiniMax — MANDATORY preamble in every brief)

cd ~/workspace/orchestrata-ultimate-architecture
git fetch origin
git worktree add -b task/<PKG-ID> ../wt-<PKG-ID> origin/feat/graph-rename
cd ../wt-<PKG-ID>
ln -sfn ../orchestrata-ultimate-architecture/.venv .venv     # share the main venv
export PYTHONPATH=$(pwd)/src                                  # editable .pth points at main repo

3.4 Rename mechanics (all agents)

Use the AST toolkit, not sed, for symbol renames:

python scripts/serialize_codebase_ast.py refs <OldName>                       # before: map the blast radius
python scripts/serialize_codebase_ast.py rename --old <Old> --new <New> --kind class   # dry-run
python scripts/serialize_codebase_ast.py rename --old <Old> --new <New> --kind class --apply

File renames: git mv old.py new.py, then fix every importer (grep old module path repo-wide — your package owns ALL of them, including tests and generated tests). Zero-refs check afterwards: python scripts/serialize_codebase_ast.py refs <OldName> must return nothing, and grep -rn --include='*.py' '<old_module_path>' src scripts tests rtm must return nothing.


4. Task packages

P0 — Land the pending wave (orchestrator + gates; prerequisite for all)

The 107-file KG_* wave exists only in the main working tree. Worktrees branch from origin/* — without P0 every delegated task edits a stale base and the work no-ops. (Learned the hard way; recorded in memory worktree-base-is-origin-master.)

  1. git checkout -b feat/graph-rename (master stays clean at 0dc0af6b).
  2. Run the deterministic review gates (RUL-008): ruff check src tests scripts, python scripts/audit_test_purity.py, python scripts/test_isolation_audit.py, python scripts/architecture_checker.py, python scripts/serialize_codebase_ast.py standards, python scripts/serialize_codebase_ast.py check-deps. Gate failures → delegated to a lint-fixer/builder subagent, NOT fixed by the orchestrator.
  3. Commit the wave (message documents: env-seam retirement, slot rename, 1451/1455 with the 4 vocabulary failures explicitly listed as in-flight → fixed by P2/P5/P6 below). Push.

P1 — Core graph access layer (Claude subagent A — highest blast radius)

Owns: src/orchestrata_ultimate/core/neo4j_factory.py, core/graph/repository.py, core/graph/adapters/neo4j_async.py, core/graph/adapters/neo4j_sync.py, ALL importers of these modules/symbols (82 files import neo4j_factory; 64 files reference Neo4jSyncRepository, 26 Neo4jAsyncRepository), and their test modules.

Old New
core/neo4j_factory.py core/graph_factory.py
core/graph/adapters/neo4j_async.py core/graph/adapters/bolt_async.py
core/graph/adapters/neo4j_sync.py core/graph/adapters/bolt_sync.py
class Neo4jAsyncRepository class BoltAsyncRepository
class Neo4jSyncRepository class BoltSyncRepository
tests/core/test_neo4j_factory.py tests/core/test_graph_factory.py
tests/generated_core/test_neo4j_factory_generated.py test_graph_factory_generated.py
tests/core/graph/test_neo4j_async_repository.py test_bolt_async_repository.py
tests/core/graph/test_neo4j_sync_repository.py test_bolt_sync_repository.py
tests/generated_core/test_graph_adapters_neo4j_{async,sync}_generated.py ..._bolt_{async,sync}_generated.py

Function names inside graph_factory (resolve_uri, resolve_kg_database, NO_AUTH, _resolve_auth) are already agnostic — keep. Keep the historical error-string prose explaining NEO4J_URI's retirement (it is accurate history; §2.5).

Investigation item (report, then act): core/graph/repository.py has _BACKENDS = {"neo4j": ...} and _DEFAULT_BACKEND = "neo4j". Determine every caller that passes/receives a backend key (grep create_graph_repository, create_async_graph_repository, backend/engine kwargs, KG_ENGINE consumers: conftest.py, neo4j_factory.py, knowledge_graph/sync.py, start_test_services.py, sweep_test_pollution.py, validate_env.py, kg_schema.py, code-review.py, diagnose_test_failure.py, sync_ast_to_neo4j.py). Rename the backend key "neo4j" → "bolt" only if no external config/env value supplies "neo4j"; if one does, accept both and log the alias for later removal. KG_ENGINE values themselves stay per §2.6.

Trap: do NOT touch from neo4j import ... driver lines; the adapters keep importing the driver. Docstrings referencing "an existing neo4j.Driver" refer to the driver class — keep.

Verify: targeted pytest on all renamed test modules + tests/core/graph/ + a sample of the biggest importers (tests/knowledge_graph/test_kg_sync.py, tests/gateway/test_config.py); zero-refs + grep gates (§2, §3.4).

P2 — knowledge_graph package (Claude subagent B)

Owns: knowledge_graph/neo4j_client.py, neo4j_node_mixins.py, sync.py, config.py, all importers of their symbols, matching tests.

Old New
knowledge_graph/neo4j_client.py knowledge_graph/graph_client.py
knowledge_graph/neo4j_node_mixins.py knowledge_graph/graph_node_mixins.py
class Neo4jClient (42 files) class GraphClient
class Neo4jNodeCreationMixin class GraphNodeCreationMixin
class Neo4jFileQueryMixin class GraphFileQueryMixin
class Neo4jSyncer (30 files, in sync.py) class GraphSyncer
class Neo4jConfig (in knowledge_graph/config.py, 31 files mention the name) class GraphClientConfig
tests/knowledge_graph/test_neo4j_client_coverage.py test_graph_client_coverage.py
tests/knowledge_graph/test_neo4j_node_mixins.py test_graph_node_mixins.py
tests/knowledge_graph/test_knowledge_neo4j.py test_knowledge_graph_client.py
tests/knowledge_graph/test_code_intelligence_neo4j.py test_code_intelligence_graph.py
tests/knowledge_graph/test_real_neo4j_knowledge.py test_real_graph_knowledge.py
tests/knowledge_graph/test_neo4j_sync_integration.py test_graph_sync_integration.py
tests/knowledge_graph/test_neo4j_transient_error_regression.py test_graph_transient_error_regression.py

TRAP — duplicate class name: there are TWO Neo4jConfig classes: knowledge_graph/config.py:50 (yours → GraphClientConfig) and orchestrator/neo4j_audit.py:81 (P3's → GraphAuditConfig). A name-match rename would merge them. Resolve refs per-import-site (refs + check the import path), never by bare token. Coordinate: you rename ONLY references importing from knowledge_graph.

Internal method/helper names mentioning neo4j inside these files (e.g. _neo4j_* helpers, _is_transient_error comments) → graph/protocol-neutral equivalents where they name the server; driver-API references stay.

Verify: the whole tests/knowledge_graph/ directory targeted (parallel per-module in one command), zero-refs + grep gates.

P3 — Orchestrator + kernel audit (Kimi)

Owns: orchestrator/neo4j_audit.py, orchestrator/fact_neo4j.py, kernel/audit/writers.py (one class), their importers + tests.

Old New
orchestrator/neo4j_audit.py (26 refs) orchestrator/graph_audit.py
class Neo4jConfig (audit-local, :81) class GraphAuditConfig
class Neo4jAuditTrail (:157) class GraphAuditTrail
orchestrator/fact_neo4j.py (4 refs) orchestrator/fact_graph.py
_increment_neo4j_failures / get_neo4j_failure_count _increment_graph_failures / get_graph_failure_count
class Neo4jAuditWriter (kernel/audit/writers.py:237, 6 refs) class GraphAuditWriter
tests/orchestrator/test_neo4j_audit_behavioral.py test_graph_audit_behavioral.py
tests/orchestrator/test_fact_neo4j.py test_fact_graph.py
tests/integration/test_neo4j_audit_integration.py test_graph_audit_integration.py
tests/generated_orchestrator/test_neo4j_audit_generated.py test_graph_audit_generated.py
tests/generated_orchestrator/test_fact_neo4j_generated.py test_fact_graph_generated.py

Same duplicate-Neo4jConfig trap as P2, from the other side: rename ONLY references that import from orchestrator.neo4j_audit/orchestrator.graph_audit. Also sweep orchestrator/fact_store.py, fact_manager.py, neo4j_audit importers listed by grep -rln 'neo4j_audit\|fact_neo4j' src tests scripts.

Verify: tests/orchestrator/ audit+fact modules, tests/kernel/test_audit_*, tests/integration/test_graph_audit_integration.py; zero-refs + grep gates.

P4 — Session, memory, harness stores (MiniMax M3 #1)

Owns: session/neo4j_store.py, memory/cold_store.py, harness/history.py, importers + tests.

Old New
session/neo4j_store.py (11 refs) session/graph_store.py
class Neo4jSessionStore class GraphSessionStore
class Neo4jMemoryStore (memory/cold_store.py:55, 5 refs) class GraphMemoryStore
class Neo4jHistoryTracker (harness/history.py:208) class GraphHistoryTracker
tests/session/test_session_neo4j_store.py test_session_graph_store.py
tests/session/test_neo4j_store_extended.py test_graph_store_extended.py
tests/session/test_session_neo4j_store_coverage.py test_session_graph_store_coverage.py
tests/session/test_kg_sync_real_neo4j.py test_kg_sync_real_graph.py
tests/generated_recovery/test_session_neo4j_store.py test_session_graph_store_recovery.py (avoid duplicate basename with tests/session twin)

Also sweep session/kg_sync/, session/kg_context.py, session/sync.py, kernel/session_manager.py, memory/memory_engine.py for neo4j-named locals/strings (the env keys were already migrated; this is identifier/prose vocabulary).

Verify: tests/session/ store+sync modules, tests/memory/test_cold_store*.py, tests/harness/test_history.py; zero-refs + grep gates.

P5 — Scripts family + the 3 failing script-tests (MiniMax M3 #2)

Owns: the server-named scripts, their tests, and three of the four current failures.

Old New
scripts/neo4j_query.py scripts/graph_query.py
scripts/neo4j_test_preflight.py scripts/graph_test_preflight.py
scripts/sync_architecture_to_neo4j.py scripts/sync_architecture_to_graph.py
scripts/sync_ast_to_neo4j.py scripts/sync_ast_to_graph.py
scripts/sync_traces_to_neo4j.py scripts/sync_traces_to_graph.py
rtm/scripts/sync_ast_to_neo4j.py rtm/scripts/sync_ast_to_graph.py
scripts/migrate_neo4j_canonical.py scripts/canonical_conformance.py — NOT a one-shot: 14 live files import its canonical-schema helpers (knowledge_graph/{schema,sync,canonical_schema}.py, backfill_thread_links.py, repair_divergent_volk_aliases.py, check_kg_connectivity.py, +tests). Rename + update all 14 importers
tests/scripts/test_neo4j_query.py / test_neo4j_query_cypher.py test_graph_query.py / test_graph_query_cypher.py
tests/scripts/test_neo4j_test_preflight.py test_graph_test_preflight.py
tests/scripts/test_sync_{architecture,ast,traces}_to_neo4j.py ..._to_graph.py
tests/scripts/test_migrate_neo4j_canonical.py test_canonical_conformance.py

Failure fixes (root-caused in §1.2):

  1. tests/scripts/test_health_check.py:336–349 — the dropped-key test now drops KG_ROUTING_URI and asserts "KG_ROUTING_URI" in result.stdout.
  2. tests/scripts/test_repair_divergent_volk_aliases.py:210–235 — rewrite configured_uris expectations to the KG keys the script now reads (see scripts/repair_divergent_volk_aliases.py:83,217–222); assert the new message "No graph URI configured".
  3. scripts/diagnose_test_failure.py:371 — header NEO4J CONSTRAINTS: → GRAPH CONSTRAINTS:; fix tests/scripts/test_diagnose_test_failure.py:348,352 to the new header. Real gap: on per-slot orchkg_w<N> databases the constraint list is empty (production orchkg has 78) — the section must print GRAPH CONSTRAINTS: (none on database <name>) when empty so the report never silently omits the section, and the test asserts the header on whichever database the run targets, not a row count.

Also update every cross-reference to the renamed script paths: grep 'neo4j_query\|neo4j_test_preflight\|sync_ast_to_neo4j\|sync_traces_to_neo4j\|sync_architecture_to_neo4j\|migrate_neo4j_canonical' across src scripts tests rtm docs .claude — includes scripts/gen_level0.py (the "Query:" line), scripts/check_kg_connectivity.py, scripts/kg_dialect_preflight.py (P6 may delete it — coordinate via merge order: P6 merges FIRST, so re-fetch before finishing), AGENTS.md/docs mentions are P7's EXCEPT the literal script-path strings inside scripts/*.py which are yours. Fix the stale --uri bolt://10.92.53.13:7687 docstring examples in backfill_thread_links.py, check_kg_connectivity.py, kg_schema.py, sync_traces_to_graph.py → routing URI neo4j://10.92.53.160:7691 (scheme literal is fine per §2 gate).

Verify: all renamed test modules + test_health_check.py, test_repair_divergent_volk_aliases.py, test_diagnose_test_failure.py, test_backfill_thread_links.py, test_check_kg_connectivity.py; zero-refs + grep gates.

P6 — Retire the migration one-shots (Kimi — merges FIRST)

The migration is complete and irreversible; these tools' inputs (the Neo4j servers) no longer exist. Renaming a tool that can never run again is polish on a corpse — delete (git history retains them).

Delete (script + its test):

Tangles to resolve (measured, not optional):

Verify: tests/core/graph/test_retry.py + tests/scripts/test_benchmark_code_intel.py pass; grep -rln 'kg_query_parity\|kg_dialect_preflight\|import_neo4j_to_memgraph\|migrate_kg_to_orchgraph\|gen_kg_migration_inventory\|purge_legacy_orphans' src scripts tests rtm → empty.

P7 — Test-config fields, .env.example, docs, LEVEL0 (Claude subagent C — after P1–P6 merge)

Owns: the widest mechanical sweep + the doc surfaces.

  1. tests/config.py field rename (676 references across tests): NEO4J_URI→GRAPH_URI, NEO4J_USERNAME→GRAPH_USERNAME, NEO4J_PASSWORD→GRAPH_PASSWORD, NEO4J_DATABASE→GRAPH_DATABASE, TEST_NEO4J_*→TEST_GRAPH_*. Keep the existing validation_alias values (KG_ROUTING_URI, KG_UNUSED_*, KG_DATABASE) exactly — they are the env seam and are already agnostic. Update every settings.NEO4J_* / TestSettings().NEO4J_* reference; word-boundary precise (\bNEO4J_URI\b), then ruff check tests + grep -rn 'NEO4J_' tests → only historical comments remain.
  2. tests/infrastructure/__init__.py: NEO4J_USERNAME/NEO4J_PASSWORD consts → GRAPH_* (+ importers).
  3. .env.example: delete lines 22–24, 34–37 block, 60–62, 65–74 (NEO4J_*, GW fleet, dead IPs 10.92.53.11/.13/.14/.19); document the real seam: KG_ROUTING_URI, KG_URI, KG_DATABASE, KG_ENGINE, KG_WORKER_COUNT, TEST_MEMGRAPH_URI + test node 10.92.53.167. Mirror the live .env key-for-key (values placeholdered).
  4. Docs (current-state only; historical session docs keep period wording): INFRASTRUCTURE.md, AGENTS.md, docs/DIAGNOSTIC_PLAYBOOK.md, docs/development-and-testing.md, docs/environment-replication.md, docs/vizint.md, docs/memgraph-ha-cluster.md, docs/session-and-kg-sync.md, docs/SESSION_CONTEXT.md, docs/diagrams/environment-physical.dot — remove destroyed-fleet references, rename script paths to their P5 names, NEO4J_* keys → KG_*.
  5. scripts/gen_level0.py final vocabulary pass, regenerate docs/LEVEL0.md, and python scripts/gen_level0.py --check → 0.
  6. Leftover sweep: grep -rin 'neo4j' src scripts tests rtm docs .claude --include='*.py' --include='*.md' --include='*.dot' — classify every remaining hit against the §2 gate (driver import / historical / neo4j:// scheme); fix everything else. Include src/orchestrata_ultimate/prolog/test_schedule.pl.

Verify: full tests/scripts/test_gen_level0.py, tests/core/test_claude_hooks_config.py, a targeted run of the 20 most-affected test modules, gen_level0 --check, grep gate.


5. Final gate & close-out (orchestrator)

  1. All packages merged into feat/graph-rename.
  2. Authoritative full suite — python scripts/run_tests.py with kernel required (never --skip kernel), JSON via redirect (> reports/run-tests-graph-rename.json — --json is store_true), exit code captured bare (never through a pipe). Required: 1455/1455.
  3. Rulings gates: ruff, purity/isolation audits, architecture_checker.py, standards, check-deps, rulings_lint.py, pyright_ratchet.py, gen_level0 --check.
  4. Repo-wide acceptance grep (§2) — every hit classified allowed.
  5. Live verification (RUL-012): gateway + kernel restart clean under systemd; one production query through scripts/graph_query.py against orchkg.
  6. Reviewer subagent pass over the merged diff (RUL-008), fixes delegated.
  7. Merge feat/graph-rename → master, push (glab credential-helper path, not the stale GITLAB_TOKEN).
  8. Wiki page update + wiki-kimi validate + index + wiki-rag-ingest; memory-file updates (orchestrata-graph-infra, AST/tooling references); session CLI work-log, handoff, end.

6. Decision log (Mohamed may veto any of these before dispatch)

# Decision Rationale
D1 The PyPI neo4j driver import stays; everything project-owned becomes graph The package name is external; orchgraph speaks its protocol
D2 Bolt adapters named bolt_* / Bolt*Repository, not graph_* Every adapter is "a graph adapter" — protocol naming is the agnostic truth
D3 Env keys stay KG_*; KG_ENGINE values stay engine names Already vendor-free; churn adds risk, no clarity
D4 Six migration one-shots DELETED, not renamed (P6) Their inputs were destroyed; git history preserves them
D5 migrate_neo4j_canonical.py RENAMED (canonical_conformance.py), not deleted 14 live importers of its schema helpers — it is load-bearing
D6 Historical prose keeps the word Neo4j History is not a live-infra claim
D7 tests/config.py field names become GRAPH_* (676 refs, P7) Field names are project vocabulary; aliases already point at KG_*