# Cleanup 05 — weak types ## Research notes Grep across in-scope files for `pointer`, `void*`, `\bany\b`, `\bunknown\b`, `cast[`. ### Nim weak-type sites | Site | Kind | File | |---|---|---| | `rlnGroupManager: pointer` (module global) | type erasure | `vendor/nwaku/waku/waku_mix/logos_core_client.nim:52` + L5 mirror | | `setGroupManagerRef(gm: pointer)` | param erasure | same files :77 | | `cast[GroupManager](gm)` | re-typing back | same files :112 | | `cast[pointer](lezGm)` (3 call sites) | call-site erasure | `node_factory.nim:194` (nwaku + L5), `src/chat/delivery/waku_client.nim:338` | | `cast[ptr FetchResult](userData)` (×2) | C callback userData | `logos_core_client.nim:181, 212` | | `cast[cstring](methodCopy/paramsCopy)` | `allocShared0` → `cstring` | `logos_core_client.nim:266-267` | | `RlnFetchCallback userData: pointer` / `fetcherData: pointer` | C ABI | `logos_core_client.nim:28-33` | No `void*`, no `any`/`unknown` (Nim doesn't have those keywords in that sense). No other `cast[…]` in in-scope Nim. ### Rust FFI weak-type sites (`lez-rln-ffi/src/lib.rs`) `*const u8` / `*mut u8` paired with explicit `len`/array-size; `unsafe { from_raw_parts(...) }` blocks reconstituting slices/fixed arrays (e.g. `&*(ptr as *const [u8; 32])`). All occurrences are inside `#[no_mangle] extern "C"` functions — they ARE the C ABI surface. ## Critical assessment | Site | Verdict | |---|---| | `rlnGroupManager: pointer` global | **Justified — keep `pointer`, fix comment.** The original comment claims "break a cyclic import"; Agent 04 already confirmed no real import cycle exists (`logos_core_client.nim` directly imports `onchain_group_manager`). The Agent 04 hand-off also claimed `setGroupManagerRef` is the C++ FFI ABI — wrong: grep across the tree shows it has only three Nim callers and zero C/C++ callers. The actual reason `pointer` is correct here: the global is touched under `rlnFetcherLock` from threads other than the one that sets it (`callRlnFetcherAsync` spawns dedicated threads via `createThread`, and the C++ plugin invokes setters from its own thread). Storing a Nim `ref` in such a global subjects it to ORC/GC interference across thread boundaries. Erasing to `pointer` is the standard Nim pattern for cross-thread handle storage. | | `setGroupManagerRef(gm: pointer)` + `cast[pointer](lezGm)` call sites + `cast[GroupManager](gm)` | **Justified consequence of the global's type.** If the storage is `pointer`, the setter must be `pointer` and the getter must `cast` back. Nothing to win by replacing the call-site `cast[pointer](lezGm)` with a one-liner converter. | | `cast[ptr FetchResult](userData)` | **Justified — standard C-callback userData pattern.** `userData` is a `pointer` opaque payload by C ABI; the cast back is the only way to recover the typed `FetchResult`. | | `cast[cstring](allocShared)` | **Justified.** `allocShared0` returns `pointer`; we need a `cstring` view of the buffer to pass through the C ABI. | | `pointer` in `RlnFetchCallback`/`RlnFetcherFunc` (`callbackData`, `userData`, `fetcherData`) | **Justified — C ABI.** These are `{.cdecl.}` callbacks invoked from C. | | Rust `*const u8` / `*mut u8` + `unsafe { from_raw_parts }` in `lez-rln-ffi/src/lib.rs` | **Justified — C ABI surface.** Every site is inside an `extern "C"` function. Tightening to `&[u8]` would break the FFI signature consumed by C++ in `logos-rln-module` (out of scope). The `unsafe { &*(ptr as *const [u8; 32]) }` already tightens what it can (raw ptr → typed fixed-array ref) immediately after entry. | ## Recommendations The only fixable issue is the **misleading comment** on `rlnGroupManager: pointer`. Rewrite it to reflect the true reason (cross-thread storage avoiding GC tracking). The pointer type itself stays; the casts stay. No new Nim/Rust types are introduced — wrapping `pointer` in an opaque typed handle would not prevent any bug (the same module owns the only writer and the only reader, and the cast target type is unambiguous). ## Applied - L5 `vendor/logos-lez-rln/logos-delivery` — commit `6e377054` on `feat/sim-rln-gifter-auth-debug` - `waku/waku_mix/logos_core_client.nim`: replace `## …break a cyclic import…` doc-comment with accurate 4-line rationale. - L2 `vendor/nwaku` — commit `9ce6dee9` on `feat/sim-rln-gifter-auth` - Same change, mirrored. L1 (outer `logos-chat`), L3, L4 not touched (no candidates required fixing in-scope). ### Verify - `make liblogoschat` — built OK (exit 0). - `make liblogosdelivery` (under `vendor/logos-lez-rln/logos-delivery`) — built OK (exit 0). - Simulation skipped: this commit is comment-only; no codegen, no runtime path, no symbol surface change. The build success above is sufficient. Main session can run the fallback sim if it wants confirmation. ## Deferred - None. Every weak-type site was assessed and found justified except for the misleading comment, which has been corrected. - The `OnchainLEZGroupManager`/`GroupManager` typed-wrapper idea (an opaque `distinct pointer` handle) was considered and rejected: it would buy zero safety (the same module is the only writer/reader) and would force every call site through a converter without removing the underlying erasure. ## Re-validation pass (Agent 05, sequential 8-agent run) Re-walked the in-scope file list after agents 01-04. Confirmed: - `vendor/nwaku/waku/waku_mix/logos_core_client.nim`: 05B fixes present in code (`setGroupManagerRef*(lezGm: OnchainLEZGroupManager)`, `cast[OnchainLEZGroupManager](gm)` in `setRlnIdentity`, accurate cross-thread-storage comment on the `pointer` global). Both casts at the global boundary remain justified. - `library/declare_lib.nim` + `library/api/client_api.nim`: every `pointer` is C-ABI callback userData. Justified — no change. - C++ `void*` / `QVariant` in `chat_module_plugin.h`, `delivery_module_plugin.cpp`, `liblogos_rln_module_api.h`: all dictated by Qt-Remote-Objects `invokeRemoteMethod` (returns `QVariant`) and the nwaku C callback signature (`(int, const char*, size_t, void*)`). Already wrapped by `liblogos_rln_module_api.h` helpers where a typed view is possible. No further tightening without breaking the QtRO/FFI surface. - Rust `*const u8` in `lez-rln-ffi`: every site inside `extern "C"`. C ABI, not fixable. No new edits applied this pass. Nothing to commit. Builds not re-run — no code changed.