#1794·codegraph

#1790 drops every identifier-rooted member call, not just built-in collections — 8 tests red on main

Author: bompusCreated Sep 8, 2026Updated Sep 15, 2026

de5adba (#1790) makes codegraph_explore, callers, impact and Steps lose the callee of any a.b.c() call whose chain is rooted at a project identifier. Eight of this repo's own tests fail on main because of it.

Bisect

Same worktree, same bun install, __tests__/{ui-steps-cross-tier,ui-steps-api-servers,nextjs,react-native-bridge}.test.ts:

commit result
2f8cce5 base 90 passed
7be699c #1785 90 passed
b8d46d1 #1788 90 passed
72c1ff1 #1789 90 passed
de5adba #1790 8 failed, 82 passed

de5adba re-run back-to-back after its parent in the same checkout, so this is not install state. Node v24.16.0, Windows 11, vitest run.

Failing tests

nextjs.test.ts > nextjs: end to end > a page's Steps picture fires from its load, crosses to the server action, and draws the pages it leads to as boundaries
nextjs.test.ts > nextjs: end to end > an endpoint anchors as any server route does
react-native-bridge.test.ts > React Native cross-platform pairing — end to end > links the Android (@ReactMethod) and iOS (RCT_EXPORT_METHOD) impls of a JS-called method
ui-steps-api-servers.test.ts > in the code's order > reads an Express handler as it is written, helper and all
ui-steps-api-servers.test.ts > Express > draws the handler's database write, the queue job, the email, and the 201 — after the middleware
ui-steps-api-servers.test.ts > Express > walks an inline handler as the route itself, into the service's read and its 404
ui-steps-cross-tier.test.ts > the Steps picture across the tiers > draws the route as a boundary the form crosses to (⇢), and enters it on request
ui-steps-cross-tier.test.ts > the Steps picture across the tiers > a server action called from a client component is a crossing to the server, by its directive

Representative assertion — ui-steps-cross-tier.test.ts:461:

expect(effect(p, 'database')?.effect?.by.name).toBe('createUserAction')
AssertionError: expected undefined to be 'createUserAction'

Cause

src/extraction/tree-sitter.ts replaces tsJsChainRoot with isUnresolvedTsJsChain:

function isUnresolvedTsJsChain(node: SyntaxNode, source: string): boolean {
  let cur: SyntaxNode | null = node;
  while (cur && TS_JS_CHAIN_RECEIVER_TYPES.has(cur.type)) {
    cur = getChildByField(cur, 'object');
  }
  return !!cur && cur.type === 'identifier' && getNodeText(cur, source) !== 'window';
}

The old gate suppressed a member call only when the chain was rooted in TS_JS_HOST_GLOBAL_ROOTS (chrome, document, Math, …). The new one suppresses every identifier-rooted chain except window. db.users.insert(x), queue.add(job), mailer.send(msg) and res.status(201) now emit no call at all, so Steps effects have no by and cross-tier boundaries are not drawn.

The comment #1790 removed had recorded the opposite judgement for exactly this case:

A chain rooted at a project value (window.MyNs.run(), store.getState().act(), ref.value.m()) keeps the bare name — those targets are real, and dropping them would cost far more recall than the mis-bind costs precision.

#1566 wants holder.values.get() unresolved because the property type is unknown. That is a subset of what the predicate now matches: a chain is being treated as untyped whenever it is identifier-rooted, which is the common case for project objects, not the exception.

Repro

git checkout de5adba
bun install --frozen-lockfile
node node_modules/vitest/vitest.mjs run __tests__/ui-steps-cross-tier.test.ts \
  __tests__/ui-steps-api-servers.test.ts __tests__/nextjs.test.ts \
  __tests__/react-native-bridge.test.ts

Reverting de5adba restores 90/90 on those four files, and ts-chained-receiver.test.ts plus resolution.test.ts stay green at 296/296 with #1792 (cece072) also applied.

Not proposed as the fix — narrowing the predicate back toward the #1566 case (an inferred-collection receiver) rather than all identifier roots looks like the direction, but I have not measured which narrowing keeps #1566 green without costing the recall above.