Skip to content

fix(ir): namespace advisory entity label IDs from ontology type IDs #702

Description

@DecisionNerd

Problem

Confirmed on current main at 6dc51fa47a9658d26a3f6e51e8a8261aaf9b4b86.

The advisory binder converts an unknown entity label directly from the runtime catalog into TypeId at crates/graphforge-ir/src/binder.rs:4475. Runtime entity IDs start at zero in crates/graphforge-ir/src/catalog.rs:134-160, while ontology type IDs occupy the same raw numeric domain in crates/graphforge-ontology/src/handle.rs:68-77. Relationship runtime IDs are tagged; entity runtime IDs are not.

The first advisory runtime label can therefore alias ontology type 0. A query or write for one label can read or create nodes classified as an unrelated ontology type. This violates the catalog-ID != ontology-ID invariant and can silently corrupt graph semantics.

Objective

Give runtime entity labels and ontology entity types disjoint, durable identities across binding, storage, publication, reopen, and recovery.

Requirements

  • Introduce one authoritative conversion/namespace for runtime entity label IDs, analogous to the existing runtime relationship type conversion.
  • Remove raw TypeId(catalog.intern_label(...).0) construction from the binder and any equivalent path.
  • Preserve deterministic identity across publication and reopen.
  • Define safe handling for existing persisted graphs whose advisory entity values may use the colliding representation: migrate/detect them deterministically or fail explicitly; never silently reinterpret them.
  • Keep Rust authoritative. Python and Node remain thin adapters.
  • Do not change ontology ID meaning or substitute runtime catalog IDs for ontology IDs.

Acceptance Criteria

  • With ontology type Person assigned ID 0, the first advisory label Ghost has a distinct stored and bound identity.
  • MATCH (n:Ghost) cannot return Person nodes solely because their raw numeric IDs coincide.
  • Creating Person and Ghost nodes preserves independent membership before and after reopen.
  • Strict ontology mode behavior and runtime relationship identity remain unchanged.
  • Existing affected persisted state has deterministic migration/detection evidence and no silent cross-classification.
  • Direct Rust-facade coverage exercises bind, create, query, publication, reopen, and recovery; applicable binding acceptance remains green.

BDD Completion Scenarios

Scenario: Advisory and ontology labels remain distinct

Given an ontology whose first entity type is Person
And an advisory query introduces the first runtime label Ghost
When nodes are created and matched through each label
Then each query returns only nodes carrying that label
And the distinction survives publication and reopen.

Scenario: Legacy collision state fails safely

Given persisted state written with a potentially colliding advisory entity representation
When the fixed engine opens or migrates the project
Then it preserves the intended identities or returns an explicit recovery/migration error
And never silently treats one label as another.

Implementation Notes

Likely surfaces: crates/graphforge-ir/src/catalog.rs, crates/graphforge-ir/src/binder.rs, crates/graphforge-storage/src/catalog.rs, ontology/runtime catalog persistence, and facade recovery tests. Audit every raw conversion between RuntimeLabelId, ontology TypeId, and stored node type columns.

Observability

Migration or invalid-state diagnostics may report aggregate counts and identity-domain metadata, but must not log graph properties, UUIDs, or local paths.

Security And Privacy

No new network surface. Treat identity confusion as a data-integrity defect; recovery must fail closed rather than guess.

Testing

Unit-test namespace boundaries and overflow/reserved-domain handling. Add direct bind/create/query/reopen/recovery regressions with ontology ID 0 and the first advisory label. Use deterministic fixtures; no skips, sleeps, retries, or weakened assertions. Run targeted checks and exact-head CI.

Documentation

Update runtime catalog/ontology identity architecture documentation if the encoded representation or compatibility contract changes.

Non-Goals

  • Merging runtime catalog IDs with ontology IDs.
  • Renumbering ontology types without an explicit compatibility design.
  • Moving entity classification into Python or Node.

Related Issues

  • Parent tracker will be attached through GitHub's native sub-issue relationship.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcoreCore source code changesplannerChanges to query planner

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions