Skip to content

breaking: distinguishable lookup misses + unified caller/callee shapes across backends (audit B/D) #249

Description

@rahlk

PROBLEM

Across all backends, a lookup MISS is observationally identical to a legitimate empty result — the silent false-empty that makes audit results untrustworthy. This is the behavioral (API-contract) half of the 2026-07-09 lookup audit; the mechanical lookup bugs are fixed on 1.x separately, but making misses DISTINGUISHABLE changes observable behavior and therefore lands in the 2.0.0 breaking batch alongside #200.

FINDINGS (audit classes B/D)

  • B1: python local codeanalyzer.py:622 / neo4j :348 — miss and hit-with-no-callers both yield empty caller_details; the local backend omits target_method on miss (an undocumented, accidental discriminator; Neo4j mirrors it).
  • B2: typescript codeanalyzer.py:278 — _resolve_signature falls back to the composed guess f"{class_or_sig}.{member}"; a typo becomes a nonexistent signature and flows through to caller_details: [] with no error.
  • B3: typescript codeanalyzer.py:412 (get_calling_lines), :422 (get_call_targets) — no existence check; unknown signature indistinguishable from never-called.
  • B4: typescript/neo4j/neo4j_backend.py:458/:468 — no existence check; also asymmetric _module IN $mods scoping (callers filtered, callees not) — a multi-app correctness bug in its own right.
  • C4: java get_all_callers/get_all_callees miss returns bare {} while a hit returns caller_details + target_method/source_method — hit and miss have different KEY SETS (KeyError for consumers).
  • D1: get_class_call_graph parity divergence — python local :688 returns [] when the class is unknown even with a valid method signature; python neo4j :376 ignores the class argument entirely when a method signature is given. Same inputs, different answers per backend.

FIX DIRECTION (to be finalized in the batch; keystone-aligned)

  • One documented miss contract for every lookup-parameterized accessor across all languages and backends: an explicit, discriminable miss (raise a typed error, or a stable found: false marker — decide once, apply everywhere), replacing empty-shaped lies.
  • Unify caller/callee return shapes cross-language in the same pass as breaking: unify CRUD operation return shapes across languages #200 (CRUD shapes) — same release, same migration-guide section.
  • Fix B4's module-scoping asymmetry and D1's backend divergence as part of the unification.
  • The 2.1.0 query core's rich diagnostics (ChainTypeError philosophy) is the end-state; this issue brings the legacy surface to minimum honesty in 2.0.0.

Sibling of #200 in the 2.0.0 breaking batch (Epic D #193). Interlock: the F1 oracle (#239) must record these miss shapes as known-ambiguous, not golden.

Part of #238

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingBreaking ChangesbugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions