Skip to content

fix(post-merge #456 + #455): EMPTY guard + use crate::nars::InferenceType + EdgePair carrier + async syntax#457

Merged
AdaWorldAPI merged 1 commit into
mainfrom
fix/post-merge-pearl-junction-empty-guard
Jun 3, 2026
Merged

fix(post-merge #456 + #455): EMPTY guard + use crate::nars::InferenceType + EdgePair carrier + async syntax#457
AdaWorldAPI merged 1 commit into
mainfrom
fix/post-merge-pearl-junction-empty-guard

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to PR #456 (NiblePath utilities + Pearl-junction classifier) + PR #455 (dn_redis key-shape protocol doc). Both merged with bot comments that didn't make it into the original PRs; this is the post-merge cleanup landing all four in one commit.

What's fixed

pearl_junction.rs (PR #456 follow-ups — 3 of 4 bot findings)

  1. Empty-path sentinel guard (Codex P2 + CodeRabbit Major)

    NiblePath::EMPTY is the crate's "no route" sentinel — used for out-of-range root() calls and uninitialised handles. The previous classifier treated matching empties as a real shared term, so two unresolved edges could spuriously classify as Chain / Fork / Collider depending on which EMPTY positions matched. Added a has_empty() guard at the top of the classifier; any EMPTY endpoint forces Unrelated.

    Three new tests cover the cases:

    • Both edges fully empty
    • Exactly one EMPTY endpoint in each of the four positions
    • NiblePath::root(0xFF) (out-of-range basin returning EMPTY) classifying as Unrelated
  2. Use canonical crate::nars::InferenceType (CodeRabbit Major — duplication-map drift)

    Dropped the local NarsRule enum from pearl_junction.rs. Replaced PearlJunction::nars_rule() -> Option<NarsRule> with PearlJunction::inference_type() -> Option<InferenceType> using the canonical crate::nars::InferenceType (which already has Deduction / Induction / Abduction plus Revision / Synthesis). Avoids the second-taxonomy drift class — the duplication-map rule the contract crate exists to prevent.

  3. EdgePair carrier struct + classify() method (CodeRabbit Major)

    Added pub struct EdgePair { s1, o1, s2, o2 } + EdgePair::new() + EdgePair::classify() method. The free function classify_junction is preserved as a thin one-line wrapper around EdgePair::classify for back-compat with PR feat(hhtl + pearl_junction): NiblePath utility methods + Pearl-junction figure classifier #456 callers; new code should prefer EdgePair::new(...).classify().

    Idiomatic Rust API + makes downstream code reading more natural ("classify this edge pair" reads more clearly than a 4-arg free function).

DN_REDIS_KEY_SHAPE_PROTOCOL.md (PR #455 critical follow-up)

  1. async fn vs missing .await syntax error (CodeRabbit Critical)

    The LanceBackend::execute() code example used .await inside a non-async function — "This will not compile." Marked the snippet as rust,ignore (it's illustrative pseudocode, not a doctest), declared the helper function as async fn, and added a comment explaining the elision was the cause of the CodeRabbit critical on PR docs: dn_redis is a key-shape protocol + Rust command type model #455.

What's NOT in this PR

  • Does NOT add new junction types or change the existing taxonomy
  • Does NOT change the dog/cat/mammal anti-swap guard test (it stays as the canonical example, ported to use EdgePair::new(...).classify())
  • Does NOT change classify_junction's public signature (preserved as a thin wrapper)
  • Does NOT modify any consumer outside the contract crate

Verification

The post-merge state lands these changes on top of the merged #456 commit. Tests cover:

Local cargo check of the contract crate again blocked on the workspace's /tmp/ndarray sibling path (same as PR #456); upstream CI verifies.

Provenance

Summary by CodeRabbit

  • Refactor

    • Refactored junction classification logic with improved handling for edge cases
    • Updated graph contract API with new carrier type and inference type support
  • Documentation

    • Updated executor documentation examples to correctly reflect async execution patterns

…Type + EdgePair carrier + async syntax

Three follow-up corrections after PR #456 merged with unaddressed bot
comments + one critical syntax-error correction after PR #455 merged.

=== pearl_junction.rs (PR #456 follow-ups) ===

1. Empty-path sentinel guard (codex P2 + CodeRabbit major on PR #456)

NiblePath::EMPTY is the crate's "no route" sentinel - used for
out-of-range root() calls + uninitialised handles. The classifier
previously treated matching empties as a real shared term, which
would spuriously classify two unresolved edges as Chain / Fork /
Collider depending on which EMPTY positions matched. Added a
has_empty() guard at the top of the classifier; any EMPTY endpoint
forces Unrelated.

Three new tests covering:
- both edges fully empty
- exactly one EMPTY endpoint in each of the four positions
- NiblePath::root(0xFF) (out-of-range basin returning EMPTY)
  classifying as Unrelated

2. Use crate::nars::InferenceType instead of local NarsRule
(CodeRabbit major - duplication-map drift)

Dropped the local NarsRule enum from pearl_junction.rs. Replaced
PearlJunction::nars_rule() -> Option<NarsRule> with
PearlJunction::inference_type() -> Option<InferenceType> where
InferenceType is the canonical crate::nars::InferenceType (which
already has Deduction / Induction / Abduction plus Revision /
Synthesis). Avoids the second-taxonomy drift class.

3. EdgePair carrier struct + classify() method (CodeRabbit major)

Added pub struct EdgePair { s1, o1, s2, o2 } + EdgePair::new() +
EdgePair::classify() method. The free function classify_junction
is preserved as a thin one-line wrapper around EdgePair::classify
for back-compat with #456 callers; new code should prefer
EdgePair::new(...).classify().

Idiomatic Rust API + makes downstream code reading more natural
("classify this edge pair" reads more clearly than a 4-arg free
function).

=== DN_REDIS_KEY_SHAPE_PROTOCOL.md (PR #455 critical follow-up) ===

CodeRabbit critical on PR #455: the LanceBackend execute() code
example used .await inside a non-async function - "This will not
compile." Fixed by declaring the helper function as async fn.

Net: closes the 4 bot findings on #456 + the 1 critical bot finding
on #455 that landed despite being flagged. No new dependencies; no
breaking changes; backward-compatible classifier surface preserved.
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8fef4d7b-29e5-4e0a-a86d-a0b9eb1737e1

📥 Commits

Reviewing files that changed from the base of the PR and between 65756b9 and 5e3740c.

📒 Files selected for processing (2)
  • crates/lance-graph-contract/src/pearl_junction.rs
  • docs/DN_REDIS_KEY_SHAPE_PROTOCOL.md

📝 Walkthrough

Walkthrough

This PR refactors the pearl junction classifier to explicitly guard NiblePath::EMPTY sentinel values, preventing spurious classification results. It introduces EdgePair as a public carrier type with const classification methods, replaces the nars_rule/NarsRule API with inference_type() returning Option<InferenceType>, updates all tests to the new API, and extends coverage with sentinel guard and const-context tests. A separate documentation example for the Redis executor is corrected to reflect async method signature.

Changes

Pearl Junction Classifier Refactor

Layer / File(s) Summary
Module documentation and EMPTY sentinel contract
crates/lance-graph-contract/src/pearl_junction.rs
Module documentation is expanded with "Empty-path sentinel handling" section and Unrelated variant doc comment is updated to explicitly describe NiblePath::EMPTY behavior.
EdgePair type and classification implementation
crates/lance-graph-contract/src/pearl_junction.rs
EdgePair public struct with const fn new() and const fn classify() is introduced. EdgePair::classify() applies EMPTY endpoint guard, then performs ordered shared-identity checks (Chain, ChainRev, Fork, Collider, Unrelated). PearlJunction::inference_type() maps junction variants to InferenceType. Legacy classify_junction() becomes const wrapper over EdgePair::classify().
Test updates and EMPTY sentinel coverage
crates/lance-graph-contract/src/pearl_junction.rs
All junction tests refactored to use EdgePair::new(...).classify() and assert inference_type() mappings. Existing Chain, ChainRev, Fork, and Collider tests verify classification and inference type. Extended coverage includes deterministic order-of-checks test, const-context classification test, and EMPTY sentinel guard tests for all-empty, single-empty, and out-of-range NiblePath::root cases.

Redis Executor Documentation

Layer / File(s) Summary
Redis executor async signature documentation
docs/DN_REDIS_KEY_SHAPE_PROTOCOL.md
Backend executor example is updated from synchronous fn execute(...) to async fn execute(...), with added commentary noting the earlier async omission and compile issue.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

  • AdaWorldAPI/lance-graph#456: Main PR that refactors the pearl junction classifier, replacing the free function classify_junction/nars_rule/NarsRule API with EdgePair::classify()/inference_type() and adding the NiblePath::EMPTY guard to junction categorization.

Poem

🐰 A path once empty now stands guard,
With EdgePairs that choose their card—
Chain, Fork, Collider dancing through,
Inference types both fresh and true!
Sentinels caught, tests shine bright,
The classifier's reborn just right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: EMPTY guard addition, replacement of local NarsRule with crate::nars::InferenceType, introduction of EdgePair carrier type, and async syntax fix in documentation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/post-merge-pearl-junction-empty-guard

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

@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: 5e3740cd90

ℹ️ 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".

/// Sources the canonical [`crate::nars::InferenceType`] enum rather than
/// introducing a parallel taxonomy (per CodeRabbit review on PR #456
/// — avoid the duplication-map drift class).
pub const fn inference_type(self) -> Option<InferenceType> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the existing NARS rule API

For any downstream consumer already using the public PR #456 API, replacing PearlJunction::nars_rule() with inference_type() and removing NarsRule makes imports and method calls fail to compile, even though this contract crate is explicitly consumed outside this repository and the free classifier function is retained for backward compatibility. Keep a deprecated compatibility method and alias/conversion while directing new callers to the canonical InferenceType API.

Useful? React with 👍 / 👎.

@AdaWorldAPI AdaWorldAPI merged commit 063f7df into main Jun 3, 2026
6 checks passed
AdaWorldAPI added a commit that referenced this pull request Jun 3, 2026
…type()

CodeRabbit caught that the deprecated nars_rule() shim duplicated the
Chain/ChainRev/Fork/Collider → Deduction/Induction/Abduction mapping
that already lives in the canonical inference_type() method.

Two-source mappings drift. If a future PR ever extends the junction
taxonomy or refines a mapping (e.g. Pearl figure → NARS rule discount
calibration), maintainers would have to update both sites and the v1
+ v2 APIs could disagree silently for downstream consumers.

This commit routes nars_rule() through inference_type() so the v1
shim is a transparent projection:

  match self.inference_type() {
      Some(InferenceType::Deduction) => Some(NarsRule::Deduction),
      Some(InferenceType::Induction) => Some(NarsRule::Induction),
      Some(InferenceType::Abduction) => Some(NarsRule::Abduction),
      Some(InferenceType::Revision) | Some(InferenceType::Synthesis) | None => None,
  }

Revision + Synthesis are NOT junction-derivable (no Pearl junction
maps to either), so those arms return None defensively even though
they are unreachable in practice given the Chain/ChainRev/Fork/
Collider/Unrelated exhaustion.

The existing tests (deprecated_nars_rule_matches_inference_type,
deprecated_nars_rule_none_when_unrelated, from_nars_rule_lifts_to_
inference_type) all continue to pass with the routed shim — the
observable behavior is identical; only the source of truth is
consolidated.

The CodeRabbit comment references the same learnings note that codex
P1 #457 cited: 'When a PR ships v2-feature work with v1 API backward-
compat shims, expect codex review to flag any v1 accessor that
hasn't been routed through the canonical mapping. Resolve before
merge; don\'t defer.'

Provenance: CodeRabbit review on PR #458.
AdaWorldAPI added a commit that referenced this pull request Jun 3, 2026
…d-shim

fix(codex P1 #457): restore deprecated NarsRule + nars_rule() for back-compat
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant