refactor(pangraph): derive block and node ids from genome names - #199
Conversation
#199. refactor(pangraph): derive block and node ids from genome names
OverviewClick to expandBlock and node ids are now derived from a hash of the genome name rather than from the input record index, so two independently built graphs are id-disjoint by construction and ObservedThe diff matches its description: ids are name-seeded, the relabeling machinery is deleted, and Blocking issuesOne correctness item where a documented guarantee exceeds what the code provides. 🔴 F1. A genome-name hash collision within a build is unguarded, and the docs state it cannot happen [click to expand]
The doc comments assert the opposite: Effect: for Suggestions:
Non-blocking issuesLatent robustness, test, and convention items. Fix if time allows. 🟡 F2. Two node-id derivation schemes coexist; the unnamed-path path reintroduces order dependence [click to expand]
Effect: production callers are migrated to Suggestions:
🟡 F3. `renumber_paths` dropped the reference-consistency checks `relabel` performed [click to expand]The removed Effect: a malformed input graph (node to missing block, or block alignment to missing node) that previously produced a clear error during merge can now reach Suggestions:
🟡 F4. Id uniqueness now depends on a 64-bit hash truncated to `usize` [click to expand]
Effect: on a 32-bit build, materially higher (still small) collision probability and reproducibility drift across platforms. No effect on 64-bit targets, but nothing asserts the target width. Suggestions:
🟡 F5. Simplify golden node-id constants are SUT-derived, and `graph.nodes` is unasserted [click to expand]
Effect: the whole-graph equality cannot detect a change in the id-derivation inputs; the concatenated node map is unverified in the simplify path. Suggestions:
🟡 F6. The new id-derivation surface lacks direct tests [click to expand]
Effect: the core order-independence mechanism has no fast, isolated regression guard, and one fixture forms a parallel untested implementation of the seeding rule. Suggestions:
🟡 F7. Merge collision error misattributes a genuine hash collision to legacy graphs [click to expand]The collision error attributes any shared id to pre-1.4 graphs and instructs "Rebuild the input graphs with the current version" [src]. Preliminary checks already reject shared names, so a collision at this point is either an old-version graph or a true 64-bit hash collision between distinct names. For the latter, rebuilding reproduces the same name-derived ids and the same collision, so the advice is unactionable. Effect: a user hitting a real hash collision receives misleading advice and cannot resolve the failure by following it. Suggestions:
🟡 F8. Hardcoded unreleased version `1.4` in a user-facing error and a doc comment [click to expand]The merge collision error states "Identifiers are derived from genome names since version 1.4" [src], and the same Effect: if the next release is not numbered Suggestions:
🔵 F9. `path.seed()` re-hashes the genome name per node on the reweave hot path [click to expand]
Effect: redundant string hashing whose count scales with total node count; small next to the per-block consensus copy, but reducible. Suggestions: memoize the seed once per path (a non-serialized 🔵 F10. Robustness and test-scaffolding nits [click to expand]
Suggestions: derive the two singleton ids from distinguished inputs if the equal-integer assumption is undesirable; assert the error type; collect offending pairs before asserting; key the helper on 🔵 F11. Prose nits [click to expand]The merge error message joins two clauses with a semicolon [src]; the CHANGELOG entry ends in a hollow participial clause ("enforcing order-independence") that restates the prior clause [src]; the Suggestions: split the semicolon into two sentences; drop the participial tail; split the doc paragraph; normalize the reference generator output rather than hand-editing the file. Author-trackedItems the author documented in the PR description alongside the change. 🟡 F12. Alignment output non-determinism fix (acknowledged) [click to expand]Author documented: the PR description states this branch "fixes a pre-existing bug this exposed: alignment hits were collected in thread completion order ( Author's assessment: the fix replaces Reviewer assessment: the fix is correct and complete.
Validation summaryValidation checks [click to expand]
NotesClick to expand
|
Follow-up to #197, which introduced the
mergecommand.This PR introduces a simplification to the code, removing the need to re-id block and nodes to avoid hash collisions.
Node and block ids were initially seeded from FASTA record numerical index (1,2,3...). This created potential hash collisions when merging different graphs and required re-indexing the blocks.
PR #197 introduced the requirement for all FASTA record names to be non-empty and unique. This creates a more elegant solution to our problem: include the path name instead of numerical index in the hashes, so that id collisions are avoided. This also has a very nice side effect: removes order dependence. In fact before this PR node and block ids depended on the order of the sequences in the fasta file.
Also fixes a pre-existing bug this exposed: alignment hits were collected in thread completion order (
par_bridge), so repeated runs on the same input could produce different graphs.