Summary
#1740 (closed COMPLETED, 2026-07-09) fixed calls inside anonymous arrow callbacks by attributing them to the enclosing function. That works — but only when an enclosing named function exists. When the nearest enclosing scope is itself anonymous, no calls edge is emitted at all.
#1740's own wording covers this case — "Nothing is emitted — not attributed to the enclosing function, not to the module node" — and the module-node half looks unimplemented.
This hits test files hardest, because it("…", async () => { … }) is exactly the shape with no named parent. Those are also the files you most want in a blast-radius answer.
Minimal repro
target.ts:
export function target(x: number) { return x; }
named-parent.ts — anonymous arrow, but inside a named function:
import { target } from "./target.js";
export function makeApp() {
register("/a", async (c) => { return target(c); });
}
declare function register(p: string, h: (c: number) => unknown): void;
anon-parent.ts — byte-identical call, nearest enclosing scope is anonymous:
import { target } from "./target.js";
it("does the thing", async () => {
register("/a", async (c) => { return target(c); });
});
declare function it(n: string, f: () => unknown): void;
declare function register(p: string, h: (c: number) => unknown): void;
graphify extract . --code-only
graphify affected "target()" --depth 2
Actual
- makeApp() [calls] named-parent.ts:L4
- anon-parent.ts [imports] anon-parent.ts:L1
- named-parent.ts [imports] named-parent.ts:L1
named-parent.ts gets a calls edge. anon-parent.ts gets only an imports edge — no calls edge exists for its identical call.
Expected
A calls edge for anon-parent.ts too, attributed to the module node when no named enclosing symbol is available.
What it cost on a real codebase
graphify affected "requireFamilyMemberHono()" --depth 1 returned 21 of the 25 source files containing a real call site. The four misses were all test files whose calls sit directly inside it(...):
packages/api/src/auth.test.ts
packages/api/src/auth.mcp.test.ts
packages/api/src/mcp/observability.test.ts
packages/api/src/mcp/token-revoke.integration.test.ts
The contrast is clean — auth.integration.test.ts:141 and auth.test.ts:134 are the same statement, const result = await requireFamilyMemberHono(c); inside app.get("/test", async (c) => {…}). The first is wrapped in function makeApp() and was found; the second sits in an anonymous it(...) and was not.
Why it matters
The result isn't empty, it's partial, and a partial answer is indistinguishable from a complete one. affected returns 21 confident, correct, well-formatted rows and silently omits four — so the failure mode is acting on it, not noticing it.
Environment
- graphify 0.9.50
- Python 3.14.5, macOS arm64
- TypeScript 5.x
Summary
#1740 (closed COMPLETED, 2026-07-09) fixed calls inside anonymous arrow callbacks by attributing them to the enclosing function. That works — but only when an enclosing named function exists. When the nearest enclosing scope is itself anonymous, no
callsedge is emitted at all.#1740's own wording covers this case — "Nothing is emitted — not attributed to the enclosing function, not to the module node" — and the module-node half looks unimplemented.
This hits test files hardest, because
it("…", async () => { … })is exactly the shape with no named parent. Those are also the files you most want in a blast-radius answer.Minimal repro
target.ts:named-parent.ts— anonymous arrow, but inside a named function:anon-parent.ts— byte-identical call, nearest enclosing scope is anonymous:Actual
named-parent.tsgets acallsedge.anon-parent.tsgets only animportsedge — nocallsedge exists for its identical call.Expected
A
callsedge foranon-parent.tstoo, attributed to the module node when no named enclosing symbol is available.What it cost on a real codebase
graphify affected "requireFamilyMemberHono()" --depth 1returned 21 of the 25 source files containing a real call site. The four misses were all test files whose calls sit directly insideit(...):The contrast is clean —
auth.integration.test.ts:141andauth.test.ts:134are the same statement,const result = await requireFamilyMemberHono(c);insideapp.get("/test", async (c) => {…}). The first is wrapped infunction makeApp()and was found; the second sits in an anonymousit(...)and was not.Why it matters
The result isn't empty, it's partial, and a partial answer is indistinguishable from a complete one.
affectedreturns 21 confident, correct, well-formatted rows and silently omits four — so the failure mode is acting on it, not noticing it.Environment