Skip to content

[travsr-store] Short-token frequency measures leaf equality, not segment membership (compound member names ground vs abstain by token length) #800

Description

@Abhishek5517

Follow-up from PR #791 review (fixes #778). Not a regression from that PR; a pre-existing asymmetry the short-token frequency fallback narrows but does not close.

Problem

symbol_frequency's short-token fallback (exact_leaf_name_count, for tokens with no >=3-char segment) measures leaf equality: how many definition nodes are named exactly the token at their kind:Qualified.leaf signature. Three different notions of "this token matches this node" are now in play, and leaf equality is the odd one out:

  • exact_leaf_name_count (the short-token fallback) measures leaf equality.
  • the nodes_words_vocab path it falls back from measures segment membership.
  • ident::contains_token, which actually decides whether a node enters anchor_pool in travsr-mcp/src/seed.rs, measures a contiguous segment run.

So whenever a short token appears as a sub-segment of a compound member name rather than as the whole leaf, the frequency measure sees one node while the anchor path admits all of them, and grounding vs abstaining is decided by token length on identically shaped corpora.

Repro

Two identically shaped corpora, compound member names this time (300 method:Widget{i}.user_id plus one class:Id, and 300 method:Widget{i}.user_key plus one class:Key):

freq("id")  2ch = Some(1)     # the leaf of `user_id` is `user_id`, not `id`
freq("key") 3ch = Some(301)   # vocab counts `key` as a segment of `user_key`

contains_token("id",  "method:Widget0.user_id")  = true
contains_token("key", "method:Widget0.user_key") = true

All 300 compound members enter anchor_pool for id, while the frequency measure sees one node. End to end through build_seed_set:

query="id"   freq=1    idf=0.900  anchors=3  confidence=Weak
query="key"  freq=301  idf=0.173  anchors=3  confidence=None

build_ui, open_db, parse_id are common enough shapes for this to bite in practice.

Blast radius

Materially smaller than the original #778 defect: the emitted anchors here are the compound members, so g1 does not escalate and the verdict is Weak rather than Exact. It is grounding-vs-abstaining, not the strongest-trust-signal inversion the PR #791 review blocked on. Worth an issue, not a reason to have held that PR.

Proposed fix

Index 2-char segments in nodes_words_vocab so the segment-membership path can measure short tokens directly. That removes the second scale entirely, is O(1), and subsumes both this fallback and the deferred leaf-name index (see the perf note on PR #791). It is a schema migration either way, so it fits the same follow-up already scoped for the leaf-name index.

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions