fix(ui): within-pass progress for the C fn-pointer linking pass (#1300)

Follow-up to #1299: the per-pass bar still parked on one number while a
single long pass ran — on C-heavy repos that's the fn-pointer dispatch
pass, which sweeps every C/C++ file four times (typedefs, registrations,
field propagation, dispatch sites) and dominates the linking phase.

The pass now reports a real fraction of its dominant work
(scannedFiles / files×4, at the same per-16-files cadence as its
cooperative yield), and the orchestrator surfaces instrumented passes'
fractions as fractional steps, throttled to whole-percent movement so
the UI message volume stays bounded. The mechanism is opt-in per pass —
any synthesizer that a real repo shows parking the bar can adopt the
same callback.

Verified on the 1,342-file C repo from the report: the linking bar now
moves through 88→89→90 where it previously sat at 88 for the whole
pass; graph byte-identical (50,520 nodes / 148,232 edges).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-07-15 20:05:35 -05:00
committed by GitHub
co-authored by Claude Fable 5
parent ad5300a601
commit 246aee8373
4 changed files with 71 additions and 9 deletions
+28
View File
@@ -366,4 +366,32 @@ void setup(int *L) {
const edges = await load();
expect(edges.length).toBe(0);
});
// This is the pass that parks the "Linking dynamic dispatch" bar on C-heavy
// repos, so it reports a within-pass fraction of its file sweeps. Pin that
// the fractions arrive, stay in (0, 1], and never go backwards.
it('reports a monotonic within-pass progress fraction over its file sweeps', async () => {
// Enough files to cross the per-16-files reporting cadence several times
// across the four file sweeps.
for (let i = 0; i < 33; i++) write(`f${i}.c`, `void fn${i}(void) { }\n`);
const cg = await CodeGraph.init(dir, { silent: true });
await cg.indexAll();
const { cFnPointerDispatchEdges } = await import('../src/resolution/c-fnptr-synthesizer');
const fractions: number[] = [];
await cFnPointerDispatchEdges(
(cg as any).queries,
(cg as any).resolver.context,
async () => {},
(f: number) => fractions.push(f)
);
cg.close?.();
expect(fractions.length).toBeGreaterThanOrEqual(4);
for (const f of fractions) {
expect(f).toBeGreaterThan(0);
expect(f).toBeLessThanOrEqual(1);
}
for (let i = 1; i < fractions.length; i++) {
expect(fractions[i]!).toBeGreaterThanOrEqual(fractions[i - 1]!);
}
});
});