Skip to content

Gate merges on Kani, unblock kani-full, and fix reconciliation write-back ordering (#202) - #227

Open
leynos wants to merge 19 commits into
mainfrom
issue-202-no-kani-harness-gates-a-merge-make-kani-runs-in-no-workflow-and-make-kani-full-is-blocked
Open

Gate merges on Kani, unblock kani-full, and fix reconciliation write-back ordering (#202)#227
leynos wants to merge 19 commits into
mainfrom
issue-202-no-kani-harness-gates-a-merge-make-kani-runs-in-no-workflow-and-make-kani-full-is-blocked

Conversation

@leynos

@leynos leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

This branch makes Kani verification an actual merge gate and unblocks the
nightly full tier, closing the gap where no Kani harness gated any merge and
make kani-full could not complete. Along the way, the investigation exposed
and fixed a genuine production defect in insertion-commit reconciliation.

Closes #202.

The branch delivers four pieces of work:

  1. A pull-request Kani gate. The path-filtered
    .github/workflows/kani-pr.yml
    workflow runs make kani on pull requests when Kani harnesses, the
    modules under proof, the Makefile, or the Cargo dependency graph change,
    with pinned actions, a 30-minute timeout, and cancellation of superseded
    runs. The fast tier in the Makefile now also
    runs both minimum-spanning-tree (MST) harnesses.

  2. A production bug fix. Hand-tracing the three-node reconciliation
    harness exposed an ordering defect: removed-edge reconciliation ran
    before the origin's neighbour-list write-back, so base-layer connectivity
    healing against the entry node could be clobbered by the write-back,
    leaving a dangling reverse edge that violates the bidirectional-links
    invariant.
    chutoro-core/src/hnsw/insert/commit.rs
    now writes the origin's list back before removed-edge reconciliation, and
    the regression test isolation_replacement_keeps_bidirectionality
    demonstrates the failure against the previous ordering.

  3. A tractable harness suite. make kani-full was blocked by harnesses
    past the CBMC state-space cliff: symbolic HashSet hashing in
    connectivity healing, three deterministic multi-node harnesses that could
    not conclude within 15–20 minute budgets, and a reconciled-update helper
    that chained the whole commit machinery into one intractable formula.
    The healing visited-set is now a bounded linear scan under #[cfg(kani)],
    the deterministic harnesses are retired in favour of exact unit-test
    twins, and the no-self-loop and neighbour-uniqueness invariants are
    proved on the ensure_reverse_edge surface with per-level two-node
    harnesses. make kani-full now verifies all seventeen harnesses in
    under eighteen minutes, within the nightly 120-minute budget.

  4. A validated MST model boundary. The sequential Kani model for
    parallel Kruskal is now compiled under cfg(test) as well and backed by
    exhaustive equivalence tests against the production Rayon implementation
    over every edge subset of one-to-four-node complete graphs, four weight
    schemes, both harness input encodings, and the error paths.

Review walkthrough

Validation

  • make kani: all six fast-tier harnesses VERIFICATION:- SUCCESSFUL.
  • make kani-full: seventeen harnesses across chutoro-core and
    chutoro-providers-dense, all successful, 17m50s wall clock including
    Kani compilation (nightly budget is 120 minutes).
  • Full deterministic gate suite (check-fmt, lint incl. Whitaker, typecheck,
    nextest, markdownlint, nixie): all green; 1094 tests passed, 1 skipped.
  • coderabbit review --agent --base main: review completed with zero
    findings across all twenty-one changed files.

Notes

  • The three retired harnesses were fully deterministic (no kani::any), so
    their proof value over a unit test was only the absence of undefined
    behaviour along one concrete path — a path each now-passing unit twin
    executes in milliseconds. The tractability rules learnt here (no standard
    hash collections on Kani-reachable paths, no symbolic index positions,
    narrow proof surfaces) are recorded in the developers' guide.
  • The verify_dense_simd_* harnesses and the distance harnesses were
    already tractable and are unchanged.

References

Summary by Sourcery

Make Kani verification a pull-request merge gate, restore a tractable full verification tier, and correct HNSW reconciliation ordering that could violate bidirectional connectivity.

New Features:

  • Add a path-filtered pull-request Kani workflow that runs the practical verification tier as a merge gate.
  • Include the MST proofs in the fast Kani tier and validate the bounded MST verification model against the production implementation with exhaustive equivalence tests.

Bug Fixes:

  • Fix HNSW reconciliation ordering so connectivity healing is preserved and bidirectional links are not left dangling after neighbour replacement.

Enhancements:

  • Restructure HNSW Kani proofs around tractable bounded surfaces and replace deterministic, intractable harnesses with focused unit-test coverage.
  • Use Kani-specific lightweight constructors and bounded data structures to make the full verification suite complete reliably.
  • Add reconciliation observability through healing and orphan-scrub metrics and tracing.

Build:

  • Pin the Kani verifier through a shared version file used by the Makefile and CI workflow.

CI:

  • Add workflow contract tests covering action pins, Kani path coverage, fast-tier consistency, and the pull-request gate configuration.

Documentation:

  • Document the Kani CI policy, proof tractability guidelines, MST model boundary, and strengthened insertion connectivity guarantees.

Tests:

  • Add regression tests for reconciliation bidirectionality, deferred scrubs, visited-set semantics, and MST model equivalence.

Chores:

  • Add repository code-health rules.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Gate relevant pull requests with path-filtered make kani verification.
  • Include both MST harnesses in the fast tier.
  • Unblock make kani-full and run 17 harnesses within the nightly budget.
  • Use bounded collections, focused invariant proofs, and unit-test twins to reduce Kani and CBMC costs.
  • Fix insertion-commit ordering so updated neighbour lists are written before removed-edge reconciliation.
  • Add regression tests for bidirectional connectivity and deferred scrubbing.
  • Add exhaustive equivalence tests between the sequential MST model and the production implementation.
  • Add structured reconciliation logging and configuration-specific Kani helpers.
  • Document the verification policy and tractability rules in the Kani ADR, developer guide, Kani hypothesis-testing report, and design document.
  • Add workflow contract tests for triggers, path filters, permissions, cancellation, timeouts, pinned actions, Kani version locking, and the gating command.

Walkthrough

Changes

Formal verification

Layer / File(s) Summary
HNSW reconciliation and bounded proofs
chutoro-core/src/hnsw/...
Move removed-edge reconciliation after neighbour-list write-back. Add Kani-safe graph constructors and collections. Narrow invariant proofs and add bidirectionality regression tests.
Bounded MST model and equivalence tests
Makefile, chutoro-core/src/mst/...
Add a bounded sequential Kruskal model, Kani-specific forest storage, structural and minimality harnesses, and exhaustive equivalence tests.
Kani CI and verification policy
.github/workflows/kani-pr.yml, docs/..., tests/workflow_contracts/kani_pr_test.py
Run make kani on relevant pull requests. Add workflow contract tests. Document fast and nightly tiers and Kani constraints.

Suggested labels: Issue

Poem

Run Kani on each change,
Check forest edges in order,
Heal reverse links,
Gate proofs through CI,
Keep bounded models clear.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 5 warnings)

Check name Status Explanation Resolution
Testing (Overall) ❌ Error Add tests for the Kani-only VisitedSet: no kani::proof reaches ConnectivityHealer, while normal tests use the HashSet alias; no contract test checks the new MST commands in make kani. Add a Kani harness that drives base-layer healing and a workflow-contract test that parses Makefile and requires both MST harness commands.
Docstring Coverage ⚠️ Warning Docstring coverage is 70.69% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 58 functions across 8 files. (2 skipped: 2 unsupported.) Write docstrings for the functions missing them to satisfy the coverage threshold.
User-Facing Documentation ⚠️ Warning The PR changes production HNSW insertion reconciliation, affecting observable search connectivity, but docs/users-guide.md is unchanged and does not document the reciprocal-link guarantee. Add a concise HNSW insertion note to docs/users-guide.md that documents preserved bidirectional links and the resulting search-connectivity behaviour.
Developer Documentation ⚠️ Warning The new cfg(kani) sequential Kruskal model and bounded forest representation appear only in developers-guide; design documents and ADR-002 do not record this MST model boundary. Add an ADR addendum and design-section update covering the MST Kani model, bounds, cfg-specific representation, and exhaustive equivalence-test boundary.
Testing (Compile-Time / Ui) ⚠️ Warning The PR adds extensive cfg(kani)/cfg(test) compilation branches and a Kani-only public representation, but adds no trybuild or dedicated compile-time fixture; new tests are runtime proofs and workfl... Add focused trybuild or equivalent configuration compile tests for normal, cfg(test), and cfg(kani) surfaces. Assert that each intended API and representation compiles in its supported configuration.
Observability ⚠️ Warning The PR changes production HNSW commit behaviour and reliability, but adds only debug logs; repository metrics cover cache/session paths, not reconciliation outcomes. Add bounded reconciliation metrics for healing and orphan scrubs, with finite labels or separate names and no node-ID labels. Expose them through the existing metrics feature.
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed Accept the title because it identifies issue #202 and accurately summarises the workflow, Kani, and reconciliation changes.
Description check ✅ Passed Accept the description because it clearly explains the Kani gate, full-suite work, reconciliation fix, tests, and documentation.
Linked Issues check ✅ Passed Accept the changes because they address issue #202 by adding the PR gate, adding MST harnesses, unblocking kani-full, and documenting the policy.
Out of Scope Changes check ✅ Passed Accept the scope because the tests, model validation, workflow contracts, logging, and documentation directly support the Kani and reconciliation objectives.
Module-Level Documentation ✅ Passed All changed Rust modules have leading //! documentation, and new Python module kani_pr_test.py has a detailed module docstring covering purpose, use, and workflow relationships.
Testing (Unit And Behavioural) ✅ Passed Added HNSW regression, eviction, scrub, error, and bidirectionality tests; exhaustive MST model equivalence and error tests; CI-run workflow contract tests cover the new gate.
Testing (Property / Proof) ✅ Passed Accept: Kani proofs cover HNSW invariants and all bounded MST edge selections; exhaustive model-equivalence tests cover every complete-graph subset up to four nodes, with only valid-state assumptions.
Unit Architecture ✅ Passed New graph attachment and commit paths expose mutation through &mut receivers and Result returns; new MST accessors and model queries are read-only, with no hidden I/O, clock, network, or fallibility.
Domain Architecture ✅ Passed The diff keeps changes in HNSW/MST domain modules, with Kani logic cfg-gated and no new HTTP, SQL, filesystem, transport, or adapter coupling; tracing follows existing core usage.
Security And Privacy ✅ Passed The diff adds no secrets or sensitive data. The PR workflow uses read-only contents, SHA-pinned actions, no persisted credentials, and logs only operation metadata, level, and counts.
Performance And Resource Use ✅ Passed Production paths retain bounded HNSW degrees and HashSet healing; the only new linear-scan Vec is cfg(kani), while MST model/tests use fixed 4-node/6-edge bounds and CI has a 30-minute timeout.
Concurrency And State ✅ Passed Accept the change: &mut Graph plus insert_mutex/RwLock serialize commits; ordering regression tests, exhaustive MST equivalence tests, and workflow cancellation tests cover changed state paths.
Architectural Complexity And Maintainability ✅ Passed Accept: Kani-only seams isolate real solver constraints, shared validation removes duplication, and the bounded MST model has documented scope plus exhaustive equivalence tests; no dependencies or...
Rust Compiler Lint Integrity ✅ Passed Keep the check passing: the diff adds no broad unused-code suppressions or clone calls, narrows test helpers with cfg(test), removes stale Kani helpers, and uses one justified item-level expectation.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-202-no-kani-harness-gates-a-merge-make-kani-runs-in-no-workflow-and-make-kani-full-is-blocked

Warning

Your free Security trial is over. An organization admin can activate billing to continue.


Comment @coderabbitai help to get the list of available commands.

codescene-access[bot]

This comment was marked as outdated.

leynos added 6 commits August 24, 2026 16:18
Add the PR workflow, bring MST proofs into the practical suite, and
remove formatted construction failures from the Kani setup paths.
The full HNSW reconciliation proof remains under investigation.
`ConnectivityHealer` tracked visited nodes with `std::collections::HashSet`,
whose randomised SipHash seed becomes symbolic under Kani. The 3-node
bidirectional reconciliation harness is the only harness that reaches the
healer (via the base-layer isolation path), which made it intractable and
blocked `make kani-full`. Substitute a bounded linear-scan visited set under
`#[cfg(kani)]`; production builds keep the `HashSet`.

Close the MST modelling boundary: compile the sequential Kani Kruskal model
under `cfg(test)` with a cfg-independent `ModelForest` result, and add an
exhaustive equivalence suite comparing it against the production Rayon
implementation over every edge subset of one-to-four-node complete graphs,
four weight schemes, both harness input encodings, and the error cases.

Record both authoring rules in the developers' guide Kani CI policy: no
standard hash collections on Kani-reachable paths, and every sequential
model must carry exhaustive finite-state equivalence tests.
Hand-tracing the three-node bidirectional reconciliation Kani harness
exposed a production defect in the insertion commit path. When a staged
update removes a neighbour whose only base-layer edge was to the origin,
the connectivity healer links the isolated node back to the entry node.
With the entry being the origin itself, healing consulted the stale
pre-write-back neighbour list, and the subsequent write-back clobbered
the healed edge, leaving a dangling reverse edge and violating the
bidirectional-links invariant. A new regression test demonstrates the
failure against the previous ordering.

Reorder `CommitApplicator::apply_neighbour_updates` (and the mirrored
Kani helper) so added-edge reconciliation and the origin's write-back
run before removed-edge reconciliation; healing then observes the final
origin state. Deferred scrubs still run once per batch after all
updates.

Route the eviction harness through the lean `_for_kani` constructors so
it cannot reach `format!`-based production error paths, and drop the
unused `push_if_absent` harness helper.
Three deterministic HNSW harnesses drove the full commit machinery on
three- and four-node graphs and could not conclude within practical
budgets, even after removing symbolic hashing from connectivity healing:
the three-node reconciliation harness exceeded twenty minutes in
symbolic execution alone, and the three-node commit-path harness
exceeded a fifteen-minute solving budget with Kissat. A deterministic
harness explores one concrete path, so its value over a unit test is
only the absence of undefined behaviour along that path.

Retire `verify_bidirectional_links_reconciliation_3_nodes_1_layer`,
`verify_bidirectional_links_commit_path_3_nodes`, and
`verify_eviction_deferred_scrub_reciprocity`, replacing each with an
exact unit-test twin in the commit test suite alongside the existing
regression test for the write-back ordering defect the reconciliation
harness exposed. Keep the nondeterministic two-node reconciliation and
four-node invariant harnesses as the bounded proofs, and drop the
helpers only the retired harnesses used.

Record the tractability rule and the retirement rationale in the
developers' guide and the hypothesis document.
…ull (#202)

The no-self-loop and neighbour-uniqueness harnesses drove
`apply_reconciled_update_for_kani`, which chained added-edge
reconciliation, list write-back, removed-edge reconciliation with its
base-layer healing cascade, and deferred scrubs in one formula. The
harnesses timed out at twenty minutes even on a two-node graph with a
concrete origin and level, so the helper itself is past the tractable
CBMC state space at any bound.

Remove the helper and prove both invariants on the production
`EdgeReconciler::ensure_reverse_edge` surface instead: per-level
two-node proofs with nondeterministic forward-edge seeding, each
verifying in under seventy seconds with Kissat. Replace the `HashSet`
in the uniqueness assertion with a linear scan so the assertion path
stays free of symbolic SipHash state.

With this restructure `make kani-full` completes: seventeen harnesses
across chutoro-core and chutoro-providers-dense verify in under
eighteen minutes of wall clock, within the nightly 120-minute budget.
Record the tractability rules and the run in the developers' guide,
the hypothesis document, and ADR-002.
The github-actions dependency bump on main moved nightly-kani.yml to
shared-actions setup-rust f4764be. The pull-request Kani workflow
mirrors the nightly provisioning, so update its pin to match.
@leynos
leynos force-pushed the issue-202-no-kani-harness-gates-a-merge-make-kani-runs-in-no-workflow-and-make-kani-full-is-blocked branch from cc845d0 to decb24b Compare August 24, 2026 14:21
The automatic merge of docs/developers-guide.md during the rebase onto
main left two consecutive blank lines before the "Kani CI policy"
section, which markdownlint rejects (MD012).
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review August 24, 2026 14:31
@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please investigate the cause of the following issue using codegraph exploration and research, identify a fix and provide an AI coding agent prompt for the fix:

Run make kani
  make kani
  shell: /usr/bin/bash -e {0}
  env:
    CARGO_TERM_COLOR: always
    CARGO_INCREMENTAL: 0
    CARGO_PROFILE_DEV_DEBUG: 0
    RUST_BACKTRACE: short
    RUSTFLAGS: -D warnings
    CARGO_UNSTABLE_SPARSE_REGISTRY: true
    CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
    UV_PYTHON_INSTALL_DIR: /home/runner/work/_temp/uv-python-dir
    UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
    SCCACHE_PATH: /opt/hostedtoolcache/sccache/0.17.0/x64/sccache
    ACTIONS_CACHE_SERVICE_V2: on
    ACTIONS_RESULTS_URL: https://results-receiver.actions.githubusercontent.com/
    ACTIONS_RUNTIME_TOKEN: ***
LD_LIBRARY_PATH="/home/runner/.kani/kani-0.67.0/toolchain/lib:" cargo kani -p chutoro-core --default-unwind 4 --harness verify_bidirectional_links_smoke_2_nodes_1_layer
Kani Rust Verifier 0.67.0 (cargo plugin)
   Compiling proc-macro2 v1.0.101
   Compiling libc v0.2.176
   Compiling unicode-ident v1.0.19
   Compiling crossbeam-utils v0.8.21
   Compiling cfg-if v1.0.4
   Compiling zerocopy v0.8.27
   Compiling crossbeam-epoch v0.9.18
   Compiling quote v1.0.40
   Compiling rayon-core v1.13.0
   Compiling parking_lot_core v0.9.12
   Compiling syn v2.0.106
   Compiling once_cell v1.21.3
   Compiling crossbeam-deque v0.8.6
   Compiling getrandom v0.2.16
   Compiling scopeguard v1.2.0
   Compiling foldhash v0.2.0
   Compiling rand_core v0.6.4
   Compiling allocator-api2 v0.2.21
   Compiling thiserror v2.0.17
   Compiling smallvec v1.15.1
   Compiling equivalent v1.0.2
   Compiling hashbrown v0.16.0
   Compiling lock_api v0.4.14
   Compiling tracing-core v0.1.34
   Compiling ppv-lite86 v0.2.21
   Compiling either v1.15.0
   Compiling hashbrown v0.14.5
   Compiling rand_chacha v0.3.1
   Compiling pin-project-lite v0.2.16
   Compiling rayon v1.11.0
   Compiling rand v0.8.5
   Compiling dashmap v6.1.0
   Compiling lru v0.16.3
   Compiling tracing-attributes v0.1.30
   Compiling thiserror-impl v2.0.17
   Compiling tracing v0.1.41
   Compiling chutoro-core v0.1.0 (/home/runner/work/chutoro/chutoro/chutoro-core)
error: function `assert_no_edge` is never used
Error:   --> chutoro-core/src/hnsw/insert/test_helpers.rs:35:15
   |
35 | pub(super) fn assert_no_edge(graph: &Graph, origin: usize, target: usize, level: usize) {
   |               ^^^^^^^^^^^^^^
   |
   = note: `-D dead-code` implied by `-D warnings`
   = help: to override `-D warnings` add `#[allow(dead_code)]`

error: struct `TestHelpers` is never constructed
Error:   --> chutoro-core/src/hnsw/insert/test_helpers.rs:47:19
   |
47 | pub(super) struct TestHelpers<'graph> {
   |                   ^^^^^^^^^^^

error: multiple associated items are never used
Error:    --> chutoro-core/src/hnsw/insert/test_helpers.rs:52:19
    |
 51 | impl<'graph> TestHelpers<'graph> {
    | -------------------------------- associated items in this implementation
 52 |     pub(super) fn new(graph: &'graph mut Graph) -> Self {
    |                   ^^^
...
 60 |     pub(super) fn heal_reachability(&mut self, max_connections: usize) {
    |                   ^^^^^^^^^^^^^^^^^
...
 89 |     pub(super) fn try_connect_unreachable_node(
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
131 |     pub(super) fn collect_reachable(&self, entry: usize) -> Vec<bool> {
    |                   ^^^^^^^^^^^^^^^^^
...
149 |     pub(super) fn first_reachable_with_capacity(
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
168 |     pub(super) fn first_reachable(&self, visited: &[bool]) -> Option<usize> {
    |                   ^^^^^^^^^^^^^^^
...
179 |     pub(super) fn enforce_bidirectional_all(&mut self, max_connections: usize) {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^
...
192 |     pub(super) fn collect_edges(&self) -> Vec<(usize, usize, usize)> {
    |                   ^^^^^^^^^^^^^
...
202 |     pub(super) fn heal_or_remove_edge(&mut self, ctx: &UpdateContext, target: usize) {
    |                   ^^^^^^^^^^^^^^^^^^^
...
226 |     pub(super) fn validate_all_edges_reciprocal(&self, max_connections: usize) {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: function `process_weight_group` is never used
Error:    --> chutoro-core/src/mst/mod.rs:265:4
    |
265 | fn process_weight_group(
    |    ^^^^^^^^^^^^^^^^^^^^

error: function `is_mst_complete` is never used
Error:    --> chutoro-core/src/mst/mod.rs:281:4
    |
281 | fn is_mst_complete(
    |    ^^^^^^^^^^^^^^^

error: function `prepare_edge_list` is never used
Error:    --> chutoro-core/src/mst/mod.rs:289:4
    |
289 | fn prepare_edge_list<'a>(
    |    ^^^^^^^^^^^^^^^^^

error: struct `ConcurrentUnionFind` is never constructed
Error:   --> chutoro-core/src/mst/union_find.rs:19:19
   |
19 | pub(super) struct ConcurrentUnionFind {
   |                   ^^^^^^^^^^^^^^^^^^^

error: multiple associated items are never used
Error:    --> chutoro-core/src/mst/union_find.rs:27:19
    |
 26 | impl ConcurrentUnionFind {
    | ------------------------ associated items in this implementation
 27 |     pub(super) fn new(node_count: usize) -> Self {
    |                   ^^^
...
 45 |     pub(super) fn components(&self) -> usize {
    |                   ^^^^^^^^^^
...
 49 |     pub(super) fn try_union(&self, left: usize, right: usize) -> Result<bool, MstError> {
    |                   ^^^^^^^^^
...
 84 |     fn lock_root(&self, index: usize) -> Result<std::sync::MutexGuard<'_, ()>, MstError> {
    |        ^^^^^^^^^
...
 96 |     fn union_roots(&self, left_root: usize, right_root: usize) -> Result<bool, MstError> {
    |        ^^^^^^^^^^^
...
112 |     fn is_root(&self, node: usize) -> bool {
    |        ^^^^^^^
...
116 |     fn find(&self, node: usize) -> usize {
    |        ^^^^

error: function `lock_order` is never used
Error:    --> chutoro-core/src/mst/union_find.rs:136:4
    |
136 | fn lock_order(first: usize, second: usize) -> (usize, usize) {
    |    ^^^^^^^^^^

error: function `choose_parent_child` is never used
Error:    --> chutoro-core/src/mst/union_find.rs:144:4
    |
144 | fn choose_parent_child(
    |    ^^^^^^^^^^^^^^^^^^^

error: methods `edges` and `component_count` are never used
Error:   --> chutoro-core/src/mst/kani_model.rs:38:19
   |
35 | impl ModelForest {
   | ---------------- methods in this implementation
...
38 |     pub(super) fn edges(&self) -> &[MstEdge] { &self.edges[..self.edge_count] }
   |                   ^^^^^
...
42 |     pub(super) fn component_count(&self) -> usize { self.component_count }
   |                   ^^^^^^^^^^^^^^^

error: could not compile `chutoro-core` (lib) due to 11 previous errors
error: Failed to execute cargo (exit status: 101). Found 11 compilation errors.
make: *** [Makefile:96: kani] Error 1
Error: Process completed with exit code 2.

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

chutoro-core/src/hnsw/kani_proofs/invariants.rs:

What lead to degradation?

The module contains 2 functions with similar structure: check_neighbour_uniqueness_at_level,check_no_self_loops_at_level

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

chutoro-core/src/mst/kani_harness.rs:

What lead to degradation?

The module contains 2 functions with similar structure: is_valid_forest,is_valid_forest

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

chutoro-core/src/mst/kani_model.rs:

What lead to degradation?

The module contains 2 functions with similar structure: sort_edges_for_kani,sort_forest_edges_for_kani

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Complex Method

chutoro-core/src/mst/kani_model.rs: kruskal_model

What lead to degradation?

kruskal_model has a cyclomatic complexity of 12, threshold = 9

Why does this problem occur?

A Complex Method has a high cyclomatic complexity. The recommended threshold for the Rust language is a cyclomatic complexity lower than 9.

How to fix it?

There are many reasons for Complex Method. Sometimes, another design approach is beneficial such as a) modeling state using an explicit state machine rather than conditionals, or b) using table lookup rather than long chains of logic. In other scenarios, the function can be split using EXTRACT FUNCTION. Just make sure you extract natural and cohesive functions. Complex Methods can also be addressed by identifying complex conditional expressions and then using the DECOMPOSE CONDITIONAL refactoring.

Helpful refactoring examples

To get a general understanding of what this code health issue looks like - and how it might be addressed - we have prepared some diffs for illustrative purposes.

SAMPLE

# complex_method.js
 function postItem(item) {
   if (!item.id) {
-    if (item.x != null && item.y != null) {
-      post(item);
-    } else {
-      throw Error("Item must have x and y");
-    }
+    // extract a separate function for creating new item
+    postNew(item);
   } else {
-    if (item.x < 10 && item.y > 25) {
-      put(item);
-    } else {
-      throw Error("Item must have an x and y value between 10 and 25");
-    }
+    // and one for updating existing items
+    updateItem(item);
   }
 }
+
+function postNew(item) {
+  validateNew(item);
+  post(item);
+}
+
+function updateItem(item) {
+  validateUpdate(item);
+  put(item);
+}
+

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

chutoro-core/src/hnsw/insert/commit/tests/deferred_scrub.rs:

What lead to degradation?

The module contains 2 functions with similar structure: commit_path_reconciliation_keeps_bidirectionality,eviction_deferred_scrub_keeps_reciprocity

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@coderabbitai coderabbitai Bot added the Issue label Aug 24, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6873caf626

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread chutoro-core/src/mst/kani_harness.rs
Comment thread docs/developers-guide.md
@sourcery-ai

sourcery-ai Bot commented Aug 24, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR makes Kani a path-filtered pull-request merge gate, fixes a production reconciliation ordering defect that could leave dangling reverse edges, restructures HNSW proofs to complete within CI budgets, and adds an exhaustively tested bounded sequential model for Kani verification of the Rayon MST implementation.

Sequence diagram for corrected HNSW reconciliation ordering

sequenceDiagram
    participant CommitApplicator
    participant EdgeReconciler
    participant Graph
    participant ConnectivityHealer

    CommitApplicator->>EdgeReconciler: reconcile_added_edges(ctx, next)
    CommitApplicator->>Graph: write origin neighbour list
    CommitApplicator->>EdgeReconciler: reconcile_removed_edges(ctx, previous, next)
    EdgeReconciler->>ConnectivityHealer: ensure_base_connectivity(...)
    ConnectivityHealer->>Graph: heal connectivity against entry node
    EdgeReconciler-->>CommitApplicator: preserve bidirectional links
Loading

Flow diagram for tractable Kani verification tiers

flowchart TD
    Change[Relevant code or proof change]
    Fast[make kani]
    Full[make kani-full]
    Narrow[Narrow bounded proofs]
    Model[Sequential MST model]
    Equivalence[Exhaustive model equivalence tests]
    Unit[Deterministic unit-test twins]
    Success[Verification completes within CI budget]

    Change --> Fast
    Fast --> Narrow
    Fast --> Model
    Model --> Equivalence
    Change --> Full
    Full --> Narrow
    Full --> Unit
    Equivalence --> Success
    Unit --> Success
Loading

File-Level Changes

Change Details Files
Added Kani as a path-filtered pull-request merge gate and expanded the fast verification tier.
  • Added a pinned-action GitHub Actions workflow with cancellation, read-only permissions, and a 30-minute timeout.
  • Updated make kani to include both MST harnesses.
  • Documented fast versus nightly Kani policy and operational constraints.
.github/workflows/kani-pr.yml
Makefile
docs/developers-guide.md
docs/adr-002-adoption-of-kani-formal-verification.md
Fixed insertion reconciliation ordering so connectivity healing cannot be overwritten by origin write-back.
  • Moved removed-edge reconciliation after the origin neighbour list is persisted.
  • Added regression coverage for isolation replacement and bidirectionality, plus deferred-scrub unit-test twins.
  • Added graph-wide bidirectional-link assertions for reconciliation tests.
chutoro-core/src/hnsw/insert/commit.rs
chutoro-core/src/hnsw/insert/commit/tests/mod.rs
chutoro-core/src/hnsw/insert/commit/tests/deferred_scrub.rs
Restructured HNSW Kani harnesses and construction paths to keep proofs tractable while retaining targeted invariant coverage.
  • Replaced Kani-reachable HashSet usage with a bounded linear-scan visited set.
  • Added lean Kani-only graph and parameter constructors that avoid formatted production errors.
  • Retired intractable deterministic commit, reconciliation, and eviction harnesses in favour of unit-test twins.
  • Replaced broad commit-path invariant harnesses with per-level two-node proofs over ensure_reverse_edge for no-self-loop and neighbour-uniqueness properties.
  • Added the MST harnesses to the fast tier and simplified their bounded inputs.
chutoro-core/src/hnsw/graph/core.rs
chutoro-core/src/hnsw/insert/connectivity.rs
chutoro-core/src/hnsw/insert/mod.rs
chutoro-core/src/hnsw/kani_proofs/bidirectional.rs
chutoro-core/src/hnsw/kani_proofs/eviction.rs
chutoro-core/src/hnsw/kani_proofs/invariants.rs
chutoro-core/src/hnsw/kani_proofs/mod.rs
chutoro-core/src/hnsw/params.rs
chutoro-core/src/mst/kani_harness.rs
Introduced and exhaustively validated a bounded sequential model for the Rayon MST implementation.
  • Added a fixed-size sequential Kruskal model for Kani and test builds.
  • Switched Kani MST execution to the model while leaving production builds on Rayon.
  • Compared model and production results across all edge subsets of one-to-four-node complete graphs, four weight schemes, both deselection encodings, and representative error cases.
chutoro-core/src/mst/kani_model.rs
chutoro-core/src/mst/mod.rs
chutoro-core/src/mst/tests/kani_model_equivalence.rs
chutoro-core/src/mst/tests/mod.rs
Recorded the verification investigation, proof-boundary decisions, and successful full-tier validation.
  • Documented causes of Kani non-completion, model-boundary requirements, and harness tractability rules.
  • Recorded successful fast-tier and full-tier verification results and the corrected reconciliation defect.
docs/kani-full-hnsw-hypothesis-testing.md
docs/adr-002-adoption-of-kani-formal-verification.md
docs/developers-guide.md

Assessment against linked issues

Issue Objective Addressed Explanation
#202 Run the fast make kani harness suite as a pre-merge pull-request gate when relevant proof code, production modules, build configuration, or dependencies change.
#202 Unblock make kani-full so the full Kani harness tier completes successfully within the nightly workflow's time budget.
#202 Decide and document the MST harness tier and the resulting Kani CI policy, including whether MST proofs run in the fast tier or remain nightly-only.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

coderabbitai[bot]

This comment was marked as resolved.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 250000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline chutoro-core/src/mst/kani_harness.rs --items all
printf '\n--- is_valid_forest definitions and callers ---\n'
rg -n -A70 -B12 '\b(is_valid_forest|verify_mst_)' chutoro-core/src/mst/kani_harness.rs
printf '\n--- MinimumSpanningForest configuration and accessors ---\n'
ast-grep outline chutoro-core/src/mst/mod.rs --items all --match 'MinimumSpanningForest|parallel_kruskal'
rg -n -A60 -B15 '\b(struct MinimumSpanningForest|impl MinimumSpanningForest|fn edges|fn component_count)' chutoro-core/src/mst/mod.rs
printf '\n--- cfg(kani) references in MST sources ---\n'
rg -n -C3 '#\[cfg\((not\()?kani\)\]' chutoro-core/src/mst

Length of output: 15305


@leynos

chutoro-core/src/mst/kani_harness.rsis_valid_forest

Suppress this finding. The two is_valid_forest definitions are configuration-specific implementations of one contract. The #[cfg(not(kani))] implementation uses a dynamically sized Vec<usize>. The #[cfg(kani)] implementation rejects graphs larger than four nodes and uses [usize; 4]. This bound is required by the Kani model.

Do not extract shared parent-storage logic. A shared abstraction would either introduce dynamic allocation into the Kani-reachable path or add indirection that obscures the verification bound. The current duplication is limited to the union-find loop. It keeps the production implementation unrestricted and the proof implementation bounded. This matches MinimumSpanningForest, which also uses separate dynamic and fixed-size representations by configuration.

Paste this suppression text into CodeScene:

The two `is_valid_forest` functions are mutually exclusive `cfg` implementations of the same validation contract. The non-Kani implementation uses a dynamically sized `Vec<usize>` for arbitrary graph sizes. The Kani implementation rejects graphs larger than four nodes and uses `[usize; 4]` to keep the proof model bounded and to avoid allocator and panic-path modelling.

Do not merge these implementations. A shared storage abstraction would add proof-path complexity or reintroduce dynamic allocation into the Kani build. The small duplicated union-find loop keeps the Kani bound explicit and preserves the required separation between unrestricted production execution and bounded formal verification.

You are interacting with an AI system.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai please create new GitHub issues for the following:

1. Enforce the target != origin precondition in EdgeReconciler::ensure_reverse_edge The latent self-loop is one refactor away from being real: any future staging or trimming change that lets the origin slip into a next list writes a self-loop silently, and the invariant checkers only catch it in tests. A debug_assert!(target != ctx.origin) plus an early return false guard costs nothing on the hot path and turns a silent corruption into a loud one. Acceptance: guard added, a unit test exercising the degenerate call, and the 2-node no-self-loop proofs re-verified (they'd then prove the guard, not just the happy path).

2. Decide and document the upper-layer isolation policy Healing is base-layer-only by design, so an evicted node can legitimately hold an empty neighbour list at level ≥ 1. That's defensible (search descends through the entry, so upper-layer isolation degrades recall, not reachability) — but it's currently folklore, not documented policy. Either record it as a deliberate invariant-exclusion in the design doc's invariants section, or implement upper-layer healing. I'd recommend the former; the issue is the forcing function to make it explicit.

3. Property-test the commit-batch sequencing class the bug came from The write-back ordering defect was a sequencing bug in batch update application, found by hand-trace. Its unit twin pins one instance; the class is "any batch of staged updates containing an isolation transition maintains bidirectionality after commit". A proptest generating small batches of updates (including neighbour removals that isolate nodes, with the entry as origin) and asserting check_all afterwards would catch reorderings of this machinery generally. This is the highest-leverage regression net for the code most recently proven fragile.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="leynos/chutoro"
pr_number="227"

printf '%s\n' '=== Relevant current symbols ==='
ast-grep outline chutoro-core/src/hnsw/insert/reconciliation.rs --items all --view expanded
ast-grep outline chutoro-core/src/hnsw/insert/commit.rs --items all --view expanded
rg -n -C3 \
  '\b(ensure_reverse_edge|reconcile_removed_edges|apply_deferred_scrubs|check_all)\b' \
  chutoro-core/src/hnsw/insert \
  chutoro-core/src/hnsw \
  docs/chutoro-design.md

printf '%s\n' '=== Originating PR comment URL ==='
gh api --paginate "repos/$repo/issues/$pr_number/comments?per_page=100" \
  --jq '.[] | select(.user.login == "leynos" and (.body | contains("please create new GitHub issues for the following"))) | .html_url' \
  | tail -n 1

Length of output: 26194


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="leynos/chutoro"
assignee="leynos"
pr_url="https://github.com/leynos/chutoro/pull/227"
comment_url="https://github.com/leynos/chutoro/pull/227#issuecomment-5400755118"

create_issue() {
  local title="$1"
  local body_file="$2"

  gh issue create \
    --repo "$repo" \
    --assignee "$assignee" \
    --title "$title" \
    --body-file "$body_file"
}

issue_one_body="$(mktemp)"
issue_two_body="$(mktemp)"
issue_three_body="$(mktemp)"
trap 'rm -f "$issue_one_body" "$issue_two_body" "$issue_three_body"' EXIT

cat >"$issue_one_body" <<EOF
## Summary

Enforce the \`target != ctx.origin\` precondition in \`EdgeReconciler::ensure_reverse_edge\`.

## Rationale

\`EdgeReconciler::ensure_reverse_edge\` in \`chutoro-core/src/hnsw/insert/reconciliation.rs\` currently accepts a target equal to \`ctx.origin\`. A future staging or trimming change could put the origin in a \`next\` list. The reconciler would then silently write a self-loop. Existing invariant checks detect this after the fact in tests.

## Required changes

- Add \`debug_assert!(target != ctx.origin)\`.
- Add an early \`return false\` when \`target == ctx.origin\`.
- Preserve existing behaviour for valid reverse-edge requests.
- Add a unit test for the degenerate call. Verify that the method returns \`false\` and does not create a self-loop.
- Re-verify the two-node no-self-loop Kani proofs. The proofs must cover the new guard as well as the valid reconciliation path.

## Acceptance criteria

- \`ensure_reverse_edge\` rejects \`target == ctx.origin\`.
- The degenerate unit test passes.
- The two two-node no-self-loop Kani harnesses verify.
- The normal test suite remains green.

## Backlinks

- Source PR: $pr_url
- Requesting comment: $comment_url
- Requested by: @$assignee
EOF

cat >"$issue_two_body" <<EOF
## Summary

Decide and document the upper-layer isolation policy for HNSW insertion reconciliation.

## Rationale

Connectivity healing is intentionally limited to the base layer. An evicted node can therefore have an empty neighbour list at level 1 or above. This may reduce recall, but it does not remove base-layer reachability because search descends from the entry point. This behaviour is not currently an explicit design policy.

## Required decision

Select one policy:

1. Document upper-layer isolation as a deliberate invariant exclusion.
2. Implement upper-layer healing.

The recommended policy is option 1. Record the decision in the HNSW invariants section of \`docs/chutoro-design.md\`. State that base-layer reachability is required, upper-layer isolation is permitted after eviction, and the expected search-quality trade-off.

If the decision is to implement upper-layer healing, define the required invariants, update reconciliation behaviour, and add focused tests.

## Acceptance criteria

- The repository contains an explicit upper-layer isolation policy.
- The policy states whether upper-layer isolation is permitted.
- The policy explains why the base layer and upper layers have different requirements.
- Tests and invariants match the selected policy.

## Backlinks

- Source PR: $pr_url
- Requesting comment: $comment_url
- Requested by: @$assignee
EOF

cat >"$issue_three_body" <<EOF
## Summary

Add a property test for commit-batch sequencing when a staged update isolates a node.

## Rationale

The write-back ordering defect in \`chutoro-core/src/hnsw/insert/commit.rs\` was a sequencing defect in batch update application. The existing unit regression test pins one topology. It does not cover the broader class: a batch of staged updates containing an isolation transition must preserve graph invariants after commit.

## Required changes

Add a \`proptest\` for small staged-update batches in the HNSW insertion commit test surface.

The generator must include neighbour removals that can isolate nodes. Use the entry node as an update origin. Apply the complete commit batch. Then assert \`index.invariants().check_all()\` after the commit.

Keep generated graph sizes and batch sizes small enough for deterministic CI execution. Include shrinking-friendly diagnostics that identify the generated updates and failing topology.

## Affected areas

- \`chutoro-core/src/hnsw/insert/commit.rs\`
- \`chutoro-core/src/hnsw/insert/commit/tests/\`
- \`chutoro-core/src/hnsw/invariants/mod.rs::HnswInvariants::check_all\`

## Acceptance criteria

- A property test generates small commit batches with isolation transitions.
- The test applies each batch through the production commit path.
- The test asserts \`check_all()\` after each completed batch.
- The test exercises removal and deferred-scrub sequencing.
- The test runs in the normal CI test suite.

## Backlinks

- Source PR: $pr_url
- Requesting comment: $comment_url
- Requested by: @$assignee
EOF

printf 'Issue 1: %s\n' "$(create_issue 'Enforce the no-self-loop precondition in EdgeReconciler::ensure_reverse_edge' "$issue_one_body")"
printf 'Issue 2: %s\n' "$(create_issue 'Decide and document the HNSW upper-layer isolation policy' "$issue_two_body")"
printf 'Issue 3: %s\n' "$(create_issue 'Property-test HNSW commit-batch sequencing for isolation transitions' "$issue_three_body")"

Length of output: 5505


@leynos Created and assigned the follow-up issues:

  1. #232 Enforce the no-self-loop precondition in EdgeReconciler::ensure_reverse_edge
  2. #233 Decide and document the HNSW upper-layer isolation policy
  3. #234 Property-test HNSW commit-batch sequencing for isolation transitions

🧠 Learnings used
Learnt from: leynos
URL: https://github.com/leynos/chutoro/pull/227

Timestamp: 2026-08-24T17:46:08.712Z
Learning: In `leynos/chutoro`, Kani HNSW proofs intentionally target the bounded `ensure_reverse_edge_for_kani` surface. The full reconciled-update proof timed out even with two nodes and concrete origin and level. Broader graph-topology property suites cover varied insertion orders and configurations. The Kani helper assumes deduplicated neighbour lists because commit-path staging maintains that production precondition.

You are interacting with an AI system.

The verifier version was restated in the pull-request workflow, the
workflow contract test, and the developers' guide, while the Makefile
derived it from whichever Kani happened to be installed. A bump needed
four coordinated edits that nothing checked, and the Makefile could
silently disagree with CI.

Record the pin once in `tools/kani/VERSION`, matching both the existing
Verus convention in `tools/verus/VERSION` and the default version-file
location `prover-tools kani install` reads. The Makefile derives
`KANI_VERSION` from that file, the workflow interpolates it, the guide
points at it, and the pin file itself triggers the gate when it changes.
Bumping Kani is now one line.

Rework the workflow contracts to assert shapes and relationships instead
of specific values, so routine pin bumps cannot fail the build for no
defect:

- Derive the Kani surface from the tree and assert the path filter covers
  every harness, rather than pinning an exact filter list. A harness added
  in a new location now fails until the filter follows.
- Assert the pull-request timeout is strictly tighter than the nightly
  tier, read from the nightly workflow, rather than asserting 30.
- Assert the install step derives the version from the pin file and
  carries no version literal, rather than asserting a version.

Add a repository-wide contract covering every workflow: each external
action reference must be pinned to a full commit SHA, and any action used
in more than one workflow must resolve to the same SHA everywhere. That
catches a partially applied Dependabot bump without naming a SHA.

Each new assertion was mutation-tested: diverging one shared-actions pin,
unpinning an action to a tag, dropping a harness path filter, and raising
the pull-request timeout above the nightly budget each fail the suite.
codescene-access[bot]

This comment was marked as outdated.

CodeScene repeatedly asks for abstractions that this branch measured to
break bounded verification: unifying the two insertion sorts in the MST
model, decomposing `kruskal_model`, and bundling harness edge arguments
into a struct together took `make kani-full` from 17/17 harnesses
verified to `kissat: maximum variable index exceeded` with none verified.
Generic and struct-wrapped constructs inflate the CBMC formula, so proof
code stays concrete and monomorphic by design. Without a scoped rule set
each pull request relitigates that thread by thread.

Add rule sets covering only the six bounded-proof files: the HNSW proof
modules, the MST harness and model, and the dense SIMD proofs. Duplication,
primitive obsession, and excess-argument rules are disabled there, each
with the rationale recorded inline. `Complex Method` is down-weighted to
0.3 rather than disabled, because it is a critical rule and genuine
complexity growth should still surface in review.

The globs deliberately exclude `kani_model_equivalence.rs` and the
`kani_nightly_gate` files, which carry `kani` in the name but are ordinary
Rust under no solver constraint; a broad `**/kani_*.rs` glob would have
relaxed rules on all three. Scope is asserted against `git ls-files`:
exactly the six proof surfaces match, and nothing else.

Separately, flatten `_iter_uses` in the action-pin contract test into a
generator plus a mapping helper. That finding is in ordinary test code
under no solver constraint, so it is fixed rather than suppressed.
@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

tests/workflow_contracts/action_pins_test.py

Comment on lines +49 to +61

def _iter_uses(document: object) -> list[str]:
    """Return every ``uses:`` value anywhere in a parsed workflow."""
    found: list[str] = []
    if isinstance(document, dict):
        for key, value in document.items():
            if key == "uses" and isinstance(value, str):
                found.append(value)
            else:
                found.extend(_iter_uses(value))
    elif isinstance(document, list):
        for item in document:
            found.extend(_iter_uses(item))
    return found

❌ New issue: Bumpy Road Ahead
_iter_uses has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is 2 blocks per function

@@ -1,4 +1,7 @@
//! Kani harnesses for minimum-spanning-forest invariants.
//! Fast-tier Kani harnesses for minimum-spanning-forest invariants.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai Addressed in 90a22c1, by scoping the rule rather than changing the code.

This module is Kani bounded-proof code. The primitive arguments are load-bearing: bundling the harness edge arguments into a TriangleEdge struct, together with unifying the two bounded insertion sorts and decomposing kruskal_model, was measured to take make kani-full from 17/17 harnesses verified to kissat: maximum variable index exceeded with none verified. Struct-wrapped and generic constructs inflate the CBMC formula past the SAT solver's variable-index limit.

.codescene/code-health-rules.json now disables Primitive Obsession, Code Duplication, and Excess Number of Function Arguments for the six bounded-proof files only, with the rationale recorded inline and in the Kani CI policy section of docs/developers-guide.md. Complex Method is down-weighted to 0.3 rather than disabled, since it is a critical rule and real complexity growth should still surface.

The globs exclude kani_model_equivalence.rs and the kani_nightly_gate files, which carry kani in the name but are ordinary Rust under no solver constraint. Scope is asserted against git ls-files: exactly the six proof surfaces match.

Comment thread tests/workflow_contracts/action_pins_test.py Outdated
codescene-access[bot]

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

The complete-graph sweep emits each undirected pair at most once, so it
never reached the model's deduplication path and never probed the bounds
of its domain. Both are reachable by real callers: the six-edge budget
counts canonical edges before deduplication, so repeats are in-domain.

Cover deduplication with identical repeats, a repeat differing only in
sequence, a reversed orientation that canonicalizes onto an existing
edge, a same-pair pair differing in weight that must not be merged, and
duplicates sitting exactly at the six-edge budget. The model and
production agree throughout.

Pin the contract boundary as well: beyond four nodes or six canonical
edges the model reports an invariant violation while production
succeeds. That divergence is the modelling contract, so widening a
harness past those bounds now fails loudly rather than silently
verifying a truncated graph.

Deliberately not asserted: that disabling the model's deduplication
changes its output. It does not, because the union-find cycle check
already rejects a repeated edge, so deduplication mirrors production
without being observable in the forest. Mutation testing confirms the
suite still detects the mutations that do matter: raising the node
bound, reversing the sort order, and deduplicating too aggressively
each fail it.
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

Cover the Kani visited-set substitute in normal CI: the linear-scan set
that replaces `HashSet` under `cfg(kani)` is now `LinearVisitedSet`,
compiled under `cfg(test)` as well, with rstest cases asserting its
insert semantics match `HashSet` across unique, duplicate, and empty
sequences. A direct proof was attempted first and measured intractable:
a two-node harness driving `ConnectivityHealer::ensure_base_connectivity`
timed out after twenty minutes in symbolic execution, matching the
earlier finding that the healer's iterative work queue is past the CBMC
cliff, so the harness was removed rather than left to re-block the
nightly sweep.

Add a fast-tier contract test deriving every proof name from the MST
harness module and asserting the Makefile's kani target runs each, so
the documented tier decision cannot drift; dropping a harness command
fails the suite.

Emit bounded reconciliation metrics behind the metrics feature:
healed-node and orphan-scrub counters with a base or upper layer label
and no node identifiers, described at index construction following the
session conventions.

Document the reciprocal-link insertion guarantee in the users' guide,
record the MST Kani model boundary and its equivalence-test closure in
the design document and ADR-002, and add docstrings across the
diff-touched reconciliation, proof, model, and test-helper functions.
@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Responding to the pre-merge check rows, reconciled against head 326fd18:

Testing (Overall) — actioned, with one measured substitution. The row asked for a Kani harness driving base-layer healing plus a contract test for the MST commands in make kani. The contract test is done: tests/workflow_contracts/kani_fast_tier_test.py derives every proof name from the MST harness module and asserts the Makefile's kani: target runs each, so the tier cannot drift (mutation-tested: deleting a harness command fails the suite). The healing harness was built and measured rather than dismissed: a two-node proof driving ConnectivityHealer::ensure_base_connectivity timed out after twenty minutes without leaving symbolic execution (2,590 aborted paths), matching the earlier finding that the healer's iterative work queue is past the CBMC cliff at any scale. A harness that cannot verify would re-block the nightly sweep this PR unblocks, so the substitute is direct test coverage: the Kani visited set is now LinearVisitedSet, compiled under cfg(test) as well, with rstest cases asserting its insert semantics match HashSet across unique, duplicate, and empty sequences. The healing path is covered by the base-layer healing unit tests, which run the shared production code in both configurations.

Docstring Coverage — actioned. Added docstrings across the diff-touched functions: the reconciliation methods, the connectivity healer entry points, the Kani proof helpers and MST model internals, the commit-test fixtures and helpers, the equivalence-test cases, and the parameters Default impl (commit 326fd18).

User-Facing Documentation — actioned. docs/users-guide.md now carries an "Insertion guarantees" subsection under "Working with CpuHnsw directly", documenting the reciprocal-link guarantee and the resulting search-connectivity behaviour, with a pointer to the verification policy.

Developer Documentation — actioned. The design document now records the MST Kani model boundary after Figure 2 (four-node/six-edge bounds, the fixed [MstEdge; 3] representation versus production's vector, preserved ordering and selection semantics, loud out-of-domain failure), and ADR-002's 2026-08-24 section and change-control list record the model and its equivalence-test closure.

Testing (Compile-Time / UI) — dismissed as impossible for the Kani half, with the equivalent already gating. Unchanged from the previous two rounds: trybuild runs the normal rustc, which cannot compile cfg(kani) code — those surfaces require the Kani compiler. The compile-time coverage for the Kani configuration is the gate itself: make kani compiles every cfg(kani) surface on pull requests and fails on any compile error, now with RUSTFLAGS=-D warnings verified locally. The cfg(test) surface is compiled by cargo test/cargo check --all-targets in CI, and the normal surface by every build. A trybuild fixture would duplicate those compilers' work for the configurations it can reach and be silently unable to reach the one it cannot.

Observability — actioned. Reconciliation now emits bounded metrics through the existing metrics feature alongside the tracing events: chutoro.hnsw.reconciliation.healed_nodes_total (nodes re-linked after isolation) and chutoro.hnsw.reconciliation.orphan_scrubs_total labelled layer=base|upper — finite labels, no node identifiers — described at index construction following the session metric conventions.

Validation at 326fd18: 695 unit tests, 20 workflow-contract tests, fmt, clippy + Whitaker, typecheck, markdownlint, nixie, and RUSTFLAGS="-D warnings" make kani (6/6 verified) all pass.

codescene-access[bot]

This comment was marked as outdated.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== revision ==='
git rev-parse --short HEAD
git status --short

printf '%s\n' '=== relevant file discovery ==='
fd -HI '^(kani_fast_tier_test|action_pins_test|connectivity|kani_harness|kani_model|kani-full-hnsw-hypothesis-testing)\.(py|rs|md)$' \
  tests chutoro-core docs 2>/dev/null || true

printf '%s\n' '=== workflow contract and Makefile Kani tier ==='
ast-grep outline tests/workflow_contracts/kani_fast_tier_test.py --items all --view expanded 2>/dev/null || true
rg -n -C4 'kani:|kani-full:|verify_mst|kani_fast_tier|harness|MST' \
  Makefile tests/workflow_contracts/kani_fast_tier_test.py chutoro-core/src/mst/kani_harness.rs 2>/dev/null || true

printf '%s\n' '=== Kani visited-set definition, gates, and tests ==='
ast-grep outline chutoro-core/src/hnsw/insert/connectivity.rs --items all --view expanded 2>/dev/null || true
rg -n -C5 \
  'LinearVisitedSet|VisitedSet|HashSet|cfg\(test\)|rstest|ensure_base_connectivity|base.*healing' \
  chutoro-core/src/hnsw/insert chutoro-core/src/hnsw 2>/dev/null || true

printf '%s\n' '=== metrics and tracing ==='
rg -n -C5 \
  'healed_nodes_total|orphan_scrubs_total|metrics::|counter!|layer.*(base|upper)|reconcile_removed_edges|apply_deferred_scrubs' \
  chutoro-core/src/hnsw/insert docs 2>/dev/null || true

printf '%s\n' '=== documentation statements ==='
rg -n -C4 \
  'Insertion guarantees|reciprocal|Kani.*model|four.node|six.edge|MstEdge|2026-08-24|change.control|verification policy' \
  docs/users-guide.md docs/chutoro-design.md docs/adr-002-adoption-of-kani-formal-verification.md 2>/dev/null || true

printf '%s\n' '=== doc comments in claimed Rust surfaces ==='
rg -n -C1 '^\s*///' \
  chutoro-core/src/hnsw/insert/{reconciliation.rs,connectivity.rs} \
  chutoro-core/src/hnsw/kani_proofs/invariants.rs \
  chutoro-core/src/mst/{kani_model.rs,kani_harness.rs} \
  chutoro-core/src/hnsw/insert/commit/tests \
  chutoro-core/src/mst/tests/kani_model_equivalence.rs \
  chutoro-core/src/hnsw/params.rs 2>/dev/null || true

Length of output: 202568


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== current revision ==='
git rev-parse --short HEAD

printf '%s\n' '=== fast-tier workflow contract ==='
nl -ba tests/workflow_contracts/kani_fast_tier_test.py | sed -n '1,260p'
printf '%s\n' '=== Makefile targets ==='
rg -n -A35 -B3 '^(kani|kani-full|test-workflow-contracts):' Makefile

printf '%s\n' '=== visited-set configuration and tests ==='
nl -ba chutoro-core/src/hnsw/insert/connectivity.rs | sed -n '1,110p'
nl -ba chutoro-core/src/hnsw/insert/connectivity.rs | sed -n '285,350p'
printf '%s\n' '=== all direct base-healing test callers ==='
rg -n -C3 '\bensure_base_connectivity\s*\(' chutoro-core/src

printf '%s\n' '=== documented direct-healing proof measurement ==='
rg -n -C5 \
  '2,590|2590|ensure_base_connectivity|timed out|timeout|LinearVisitedSet' \
  docs/developers-guide.md docs/kani-full-hnsw-hypothesis-testing.md \
  chutoro-core/src/hnsw/insert/connectivity.rs

printf '%s\n' '=== metrics documentation context ==='
rg -n -C5 \
  'healed_nodes_total|orphan_scrubs_total|session metric|metrics feature|metrics' \
  docs/users-guide.md docs/developers-guide.md docs/chutoro-design.md \
  chutoro-core/src/hnsw/insert/reconciliation.rs

Length of output: 1649


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== fast-tier workflow contract ==='
cat -n tests/workflow_contracts/kani_fast_tier_test.py | sed -n '1,260p'
printf '%s\n' '=== Makefile targets ==='
rg -n -A35 -B3 '^(kani|kani-full|test-workflow-contracts):' Makefile

printf '%s\n' '=== visited-set configuration and tests ==='
cat -n chutoro-core/src/hnsw/insert/connectivity.rs | sed -n '1,110p'
cat -n chutoro-core/src/hnsw/insert/connectivity.rs | sed -n '285,350p'
printf '%s\n' '=== all direct base-healing callers ==='
rg -n -C3 '\bensure_base_connectivity\s*\(' chutoro-core/src

printf '%s\n' '=== documented direct-healing proof measurement ==='
rg -n -C5 \
  '2,590|2590|ensure_base_connectivity|timed out|timeout|LinearVisitedSet' \
  docs/developers-guide.md docs/kani-full-hnsw-hypothesis-testing.md \
  chutoro-core/src/hnsw/insert/connectivity.rs

printf '%s\n' '=== metrics documentation context ==='
rg -n -C5 \
  'healed_nodes_total|orphan_scrubs_total|session metric|metrics feature|metrics' \
  docs/users-guide.md docs/developers-guide.md docs/chutoro-design.md \
  chutoro-core/src/hnsw/insert/reconciliation.rs

Length of output: 41474


@leynos Mark the actioned rows as resolved at HEAD 326fd18.

  • Testing (Overall): Keep the measured substitution. tests/workflow_contracts/kani_fast_tier_test.py derives the MST verify_* harness names from chutoro-core/src/mst/kani_harness.rs and asserts that Makefile kani: runs every one. The target includes both MST harnesses.

  • Healing coverage: Keep the LinearVisitedSet semantic tests. LinearVisitedSet is compiled under cfg(any(kani, test)). Its rstest cases compare unique, duplicate, single, and empty insertion sequences against HashSet.

    State the configuration boundary precisely. Normal unit tests execute ConnectivityHealer::ensure_base_connectivity with VisitedSet = HashSet<usize>. Kani builds compile VisitedSet = LinearVisitedSet, but the active Kani harnesses do not execute the healing path. The direct-healing harness timeout makes the semantic substitute test the appropriate coverage for the Kani-specific collection.

  • Docstring coverage: Accept the additions. The inspected reconciliation, connectivity, Kani proof, MST model, commit-test, equivalence-test, and parameter surfaces contain the stated Rustdoc coverage.

  • User-facing and developer documentation: Accept the additions. docs/users-guide.md contains the insertion guarantees section. docs/chutoro-design.md and docs/adr-002-adoption-of-kani-formal-verification.md define the bounded MST model, its equivalence-test closure, and the PR Kani gate.

  • Compile-time coverage: Accept the dismissal. make kani is the required compilation gate for cfg(kani). Normal Rust compilation cannot validate Kani-only APIs.

  • Observability: Accept the implementation. EdgeReconciler::reconcile_removed_edges increments chutoro.hnsw.reconciliation.healed_nodes_total. EdgeReconciler::apply_deferred_scrubs increments chutoro.hnsw.reconciliation.orphan_scrubs_total with only layer=base|upper.

Amend the observability statement. The inspected documentation does not contain either reconciliation metric identifier. Do not state that index-construction documentation describes these metrics unless a separate documentation location exists. State that the source implements the metrics under the existing metrics feature and follows the existing finite-label convention.

Treat the reported runtime validation as branch-reported. Source inspection passed. This environment cannot independently run the test, lint, or Kani commands.


✏️ Learnings added
Learnt from: leynos
URL: https://github.com/leynos/chutoro/pull/227

Timestamp: 2026-08-24T21:14:06.415Z
Learning: In `leynos/chutoro`, `chutoro-core/src/hnsw/insert/connectivity.rs` uses `HashSet<usize>` as `VisitedSet` in normal and test builds, while Kani builds alias `VisitedSet` to `LinearVisitedSet`. `LinearVisitedSet` also compiles under `cfg(test)` so rstest cases can compare its insertion semantics with `HashSet`; this does not execute `ConnectivityHealer::ensure_base_connectivity` with the Kani-specific alias. Active Kani harnesses compile but do not execute the healing path because a direct two-node healing harness is intractable.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: leynos
URL: https://github.com/leynos/chutoro/pull/227

Timestamp: 2026-08-24T17:46:08.712Z
Learning: In `leynos/chutoro`, Kani HNSW proofs intentionally target the bounded `ensure_reverse_edge_for_kani` surface. The full reconciled-update proof timed out even with two nodes and concrete origin and level. Broader graph-topology property suites cover varied insertion orders and configurations. The Kani helper assumes deduplicated neighbour lists because commit-path staging maintains that production precondition.

Learnt from: leynos
URL: https://github.com/leynos/chutoro/pull/227

Timestamp: 2026-08-24T17:46:08.712Z
Learning: In `leynos/chutoro`, `cfg(kani)` compilation is validated by the `make kani` pull-request gate because Kani-specific APIs require the Kani compiler and cannot be compiled by normal-rustc `trybuild`. Normal and test configurations are covered separately by workspace checks and tests.

You are interacting with an AI system.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 24, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

tests/workflow_contracts/kani_fast_tier_test.py

Comment on lines +39 to +52

def kani_target() -> str:
    """Return the recipe body of the Makefile's ``kani:`` target."""
    lines = MAKEFILE_PATH.read_text(encoding="utf-8").splitlines()
    body: list[str] = []
    in_target = False
    for line in lines:
        if re.match(r"^kani:", line):
            in_target = True
            continue
        if in_target:
            if line.startswith("\t"):
                body.append(line)
            else:
                break

❌ New issue: Bumpy Road Ahead
kani_target has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is 2 blocks per function

@coderabbitai

This comment was marked as resolved.

Replace the stateful line loop in the fast-tier contract fixture with a
single multiline regular expression that matches the first `kani:`
header and captures its consecutive tab-indented recipe lines, stopping
at the first non-recipe line. One assertion now covers both a missing
target and an empty recipe, with the message unchanged.

Behaviour is preserved and probed: the first target wins, `kani-full:`
is not mistaken for `kani:`, capture stops at the first non-tab line,
an end-of-file recipe without a trailing newline is kept, and emptying
the real recipe fails the suite with the expected message. The returned
string is byte-identical to the previous join for the current Makefile.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gates Failed
Enforce advisory code health rules (1 file with Complex Method)

Our agent can fix these. Install it.

Gates Passed
5 Quality Gates Passed

Reason for failure
Enforce advisory code health rules Violations Code Health Impact
kani_model.rs 1 advisory rule 9.88 Suppress

See analysis details in CodeScene

Absence of Expected Change Pattern

  • chutoro/chutoro-core/src/hnsw/graph/core.rs is usually changed with: chutoro/chutoro-core/src/hnsw/node.rs

Quality Gate Profile: Pay Down Tech Debt
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No quality gates enabled for this code.

@leynos

leynos commented Aug 25, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message in a code block that I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Complex Method

chutoro-core/src/mst/kani_model.rs: kruskal_model

What lead to degradation?

kruskal_model has a cyclomatic complexity of 12, threshold = 9

Why does this problem occur?

A Complex Method has a high cyclomatic complexity. The recommended threshold for the Rust language is a cyclomatic complexity lower than 9.

How to fix it?

There are many reasons for Complex Method. Sometimes, another design approach is beneficial such as a) modeling state using an explicit state machine rather than conditionals, or b) using table lookup rather than long chains of logic. In other scenarios, the function can be split using EXTRACT FUNCTION. Just make sure you extract natural and cohesive functions. Complex Methods can also be addressed by identifying complex conditional expressions and then using the DECOMPOSE CONDITIONAL refactoring.

Helpful refactoring examples

To get a general understanding of what this code health issue looks like - and how it might be addressed - we have prepared some diffs for illustrative purposes.

SAMPLE

# complex_method.js
 function postItem(item) {
   if (!item.id) {
-    if (item.x != null && item.y != null) {
-      post(item);
-    } else {
-      throw Error("Item must have x and y");
-    }
+    // extract a separate function for creating new item
+    postNew(item);
   } else {
-    if (item.x < 10 && item.y > 25) {
-      put(item);
-    } else {
-      throw Error("Item must have an x and y value between 10 and 25");
-    }
+    // and one for updating existing items
+    updateItem(item);
   }
 }
+
+function postNew(item) {
+  validateNew(item);
+  post(item);
+}
+
+function updateItem(item) {
+  validateUpdate(item);
+  put(item);
+}
+

@coderabbitai

This comment was marked as resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

No Kani harness gates a merge: make kani runs in no workflow and make kani-full is blocked

3 participants