Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
82 lines
2.8 KiB
TypeScript
82 lines
2.8 KiB
TypeScript
import { Profiler, type ReactNode } from "react";
|
|
|
|
// Render-budget test infrastructure for the agent GUI refactor
|
|
// (docs/architecture/agent-gui-refactor-plan.md, section 5.2 item 3).
|
|
//
|
|
// Performance work is accepted when a budget test goes green, not when more
|
|
// memoization is added. Feature-module slices wrap their components with a
|
|
// probe and assert commit counts for typical interactions, for example:
|
|
//
|
|
// const probe = createRenderBudgetProbe();
|
|
// render(probe.wrap("composer", <Composer />));
|
|
// probe.reset();
|
|
// await user.type(input, "hello");
|
|
// probe.assertRenderBudget({ composer: 3, transcript: 0 });
|
|
//
|
|
// This module is test-only infrastructure. It must not be exported from the
|
|
// package public entry points.
|
|
|
|
export interface RenderBudgetProbe {
|
|
/** Wrap a component subtree so its React commits are counted under `id`. */
|
|
wrap(id: string, node: ReactNode): ReactNode;
|
|
/** Commits observed for `id` since creation or the last `reset()`. */
|
|
renderCount(id: string): number;
|
|
/** Zero all counters, typically right before the measured interaction. */
|
|
reset(): void;
|
|
/**
|
|
* Assert an upper bound of commits per probe id. Ids wrapped but not listed
|
|
* are ignored; listing an id that was never wrapped fails the assertion so
|
|
* budgets cannot silently rot when components are renamed.
|
|
*/
|
|
assertRenderBudget(budgetByProbeId: Record<string, number>): void;
|
|
}
|
|
|
|
export function createRenderBudgetProbe(): RenderBudgetProbe {
|
|
const commitCountByProbeId = new Map<string, number>();
|
|
const wrappedProbeIds = new Set<string>();
|
|
|
|
const handleRender = (id: string) => {
|
|
commitCountByProbeId.set(id, (commitCountByProbeId.get(id) ?? 0) + 1);
|
|
};
|
|
|
|
return {
|
|
assertRenderBudget(budgetByProbeId) {
|
|
const failures: string[] = [];
|
|
for (const [id, budget] of Object.entries(budgetByProbeId)) {
|
|
if (!wrappedProbeIds.has(id)) {
|
|
failures.push(
|
|
`probe "${id}" is asserted but was never wrapped; update the budget test to match the component tree`
|
|
);
|
|
continue;
|
|
}
|
|
const count = commitCountByProbeId.get(id) ?? 0;
|
|
if (count > budget) {
|
|
failures.push(
|
|
`probe "${id}" rendered ${count} time(s), budget is ${budget}`
|
|
);
|
|
}
|
|
}
|
|
if (failures.length > 0) {
|
|
throw new Error(
|
|
`render budget exceeded:\n${failures.map((line) => `- ${line}`).join("\n")}\n` +
|
|
"Fix the subscription granularity at its source instead of raising the budget."
|
|
);
|
|
}
|
|
},
|
|
renderCount(id) {
|
|
return commitCountByProbeId.get(id) ?? 0;
|
|
},
|
|
reset() {
|
|
commitCountByProbeId.clear();
|
|
},
|
|
wrap(id, node) {
|
|
wrappedProbeIds.add(id);
|
|
return (
|
|
<Profiler id={id} onRender={handleRender}>
|
|
{node}
|
|
</Profiler>
|
|
);
|
|
}
|
|
};
|
|
}
|