nim-chat-poc/cleanup/04-cycles.md
Arseniy Klempner a018b24db6
cleanup: 8-agent code-quality pass post-squash summary
Reports for each of the 8 cleanup agents (DRY, types, unused, cycles,
weak-types, try/except, legacy, slop) recording verdicts + applied
changes + deferred items, plus the consolidated SUMMARY.md.

End-of-pass local sim ALL 15 PASSED.
2026-05-28 14:22:39 -06:00

116 lines
7.2 KiB
Markdown

# Cleanup 04 — Circular Import / Dependency Cycles
Agent 04 of 8. Scope: cycles introduced or worsened by this session in `CLEANUP_SCOPE.md` files. Tooling: manual `rg`/`grep` over `^import` lines (madge n/a for this Nim/Rust/C++ stack).
## Research notes — import graph of in-scope clusters
### Cluster A — `waku_mix/logos_core_client.nim` ↔ plugin
```
logos_core_client.nim
-> mix_rln_spam_protection/group_manager {.all.}
-> mix_rln_spam_protection/types {.all.}
-> mix_rln_spam_protection/rln_interface
-> mix_rln_spam_protection/onchain_group_manager (NEW: re-exports ExternalMerkleProof)
mix_rln_spam_protection/onchain_group_manager.nim
-> ./types ./constants ./rln_interface ./group_manager
(zero references to waku_mix / nwaku / logos-chat)
mix_rln_spam_protection/{group_manager,types,rln_interface}.nim
-> only sibling plugin modules + std/chronos/results/chronicles/stew
```
`rg 'logos_core_client|waku_mix' vendor/nwaku/vendor/mix-rln-spam-protection-plugin/` → 0 hits.
### Cluster B — `rln_gifter/` four-file cluster
```
rpc.nim -> std/options (leaf)
rpc_codec.nim -> std/options, ../../common/protobuf, ./rpc
protocol.nim -> std/[options,sets], chronos/results/..., ../../node/peer_manager/peer_manager,
../../waku_core, ./rpc, ./rpc_codec
client.nim -> std/options, results, chronos, bearssl/rand, libp2p/stream/connection,
../../node/peer_manager, ../../waku_core, ../../utils/requests, ./rpc, ./rpc_codec
```
Topological order: `rpc` < `rpc_codec` < {`protocol`, `client`}. `protocol` and `client` are siblings; neither imports the other. Strict DAG.
### Cluster C — callers of the new symbols
```
node_factory.nim -> logos_core_client (alias mix_lez_client)
-> mix_rln_spam_protection/onchain_group_manager (direct)
-> rln_gifter/protocol, rln_gifter/client (direct)
src/chat/delivery/waku_client.nim
-> waku/waku_mix/logos_core_client as mix_lez_client
-> waku/waku_rln_relay/rln_gifter/{client,protocol}
-> mix_rln_spam_protection/{onchain_group_manager,rln_interface,spam_protection}
```
Both callers use `OnchainLEZGroupManager`, `FetchRootsCallback`, `FetchProofCallback`,
`MembershipIndex` via the `onchain_group_manager.X` qualifier. The direct plugin import is
necessary, not redundant with the `logos_core_client` re-export (which only re-exports
`ExternalMerkleProof`).
## Critical assessment
| Candidate | Verdict | Reason |
|-------------------------------------------------------------------------------------------------------------|-----------|--------|
| `logos_core_client` -> `onchain_group_manager` -> ... -> `logos_core_client` | SPURIOUS | Plugin has zero references to nwaku/waku_mix. Forward edge only. |
| Plugin's `onchain_group_manager` reaching back into nwaku via new accessors (proofRoot/getPollInterval) | SPURIOUS | New procs operate on plugin-local state and types; no nwaku imports added. |
| rln_gifter `protocol` <-> `client` mutual import | SPURIOUS | Neither imports the other; both depend only on `rpc`/`rpc_codec`. |
| rln_gifter `rpc_codec` <-> `rpc` | SPURIOUS | `rpc_codec` -> `rpc` only; `rpc.nim` imports only `std/options`. |
| `node_factory` importing both `mix_lez_client` and `onchain_group_manager` (redundant?) | SPURIOUS | Caller uses multiple plugin-only symbols; re-export covers only `ExternalMerkleProof`. |
| `waku_client.nim` (outer) similar dual import | SPURIOUS | Same reason as node_factory. |
| "typed as pointer to break a cyclic import" workaround marker (logos_core_client.nim:53) | OBSOLETE COMMENT | The pointer is the FFI callback ABI to C++ (`setGroupManagerRef(gm: pointer)`); cycle is no longer the real reason. Plugin doesn't import logos_core_client, so a typed ref *would* compile. But the opaque `pointer` is correct as an FFI boundary type; only the comment is misleading. |
## Recommendations
1. No real cycles to break. Import graph in scope is a clean DAG.
2. (Doc-only, deferred) Re-word `logos_core_client.nim:53` comment from "typed as pointer to break a cyclic import" to "typed as opaque pointer for the C++ FFI callback boundary". Strictly cosmetic; not worth a commit churn on this load-bearing file during cleanup pass. Suggested for whoever next edits that region.
3. The `ExternalMerkleProof` re-export from `logos_core_client` is genuinely useful for downstream consumers that don't already need the broader `onchain_group_manager` surface — but both current callers (`node_factory`, outer `waku_client`) need the broader surface anyway and can drop reliance on the re-export. Not worth changing; the re-export is harmless.
## Applied
No code changes. Mirrors verified byte-identical post agents 01-03:
```
3c3bd2e20ffa315e37a9c86c2002f8bbe5095e5e33e1df7c805cc41db5552d4c vendor/nwaku/waku/waku_mix/logos_core_client.nim
3c3bd2e20ffa315e37a9c86c2002f8bbe5095e5e33e1df7c805cc41db5552d4c vendor/logos-lez-rln/logos-delivery/waku/waku_mix/logos_core_client.nim
3c3bd2e20ffa315e37a9c86c2002f8bbe5095e5e33e1df7c805cc41db5552d4c vendor/logos-lez-rln/logos-delivery-module/vendor/logos-delivery/waku/waku_mix/logos_core_client.nim
```
Re-validation after agents 01 (`bytesToHexUpper` extraction), 02 (type
consolidation no-op), and 03 (drop dead `hexToBytes32LE` + stale imports):
- Plugin (`mix-rln-spam-protection-plugin/`) still has zero references to
`logos_core_client` / `waku_mix` — agents 01/03 only touched the nwaku
side, never the plugin side. Edge direction preserved.
- `rln_gifter/` four-file cluster topology unchanged: `rpc` < `rpc_codec`
< {`protocol`, `client`} remains a clean DAG; no sibling cross-import.
- Agent 03's unused-import removals (`std/sequtils` from `protocol.nim`,
`waku_peer_store` from `protocol.nim`, `sharding` from
`waku_mix_coordination.nim`, `std/algorithm` from `logos_core_client`)
only reduce dependency surface — none introduced a new edge.
- C++ header graph: `liblogos_rln_module_api.h` (chat-module +
delivery-module + logos-rln-module copies) includes only outward-facing
`logos_api*.h` / `logos_mode.h` / `logos_object.h`. No back-edges from
any included header to its consumers. Plugin source files form the
expected unidirectional chain `*_plugin.cpp -> *_plugin.h ->
*_module_interface.h -> interface.h`. Clean DAG.
Updated note also retracts the prior deferred "comment rewording at
`logos_core_client.nim:53`" item — the live file's comment (lines 53-57)
already explains the `pointer` as a cross-thread GC isolation
workaround, not a cycle workaround. Stale wording already gone.
No commits at any of the 5 repo levels.
## Deferred
- None. `madge` not applicable to Nim/Rust/C++ stack; manual `^import` /
`^#include` survey across the in-scope file set is sufficient and was
run twice (initial pass + post-01/02/03 re-validation).