Files
buzz/desktop/src/app/navigation/commitGuardedNavigation.ts
Max Lampert 705899b6cb fix(desktop): guard-gated traces, on-disk log cap, honest projects benchmark
Address the three findings from the 2026-08-24 re-review of #6455, plus
one finding from a follow-up adversarial review:

- The switch trace now opens inside commitGuardedNavigation, only after
  the navigation guard accepts — a refused click can no longer leave an
  orphan trace that a later history navigation would settle with
  inflated time. The commit flow is extracted and dependency-injected;
  new unit tests pin guard ordering and the refusal→history-back case.
- The perf-log 4 KiB cap now bounds bytes on disk: one byte is reserved
  for the newline writeln! appends. New boundary test measures the file.
- The channel↔Projects benchmark gates readiness on a new
  data-projects-hydrating marker (driven by the surface's query fan via
  isLoading, so disabled queries never wedge it) instead of the shell
  header, verifies member inflation on both inflated channels, uses a
  prefixed ready-selector for general, and reports each switch direction
  as its own median so a one-leg regression cannot hide.
- A settle wait that hits its 5s deadline while the render is still
  pending now records with settleWaitTruncated instead of posing as an
  honest settled paint — the >deadline tail is what the tracer exists
  to expose. Also removes the dead ChannelSwitchFetchTrace type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Max Lampert <maxwell@squareup.com>
2026-08-26 12:34:09 -07:00

52 lines
1.7 KiB
TypeScript

import {
allowNavigation,
type GuardedNavigation,
} from "@/app/navigation/navigationGuard";
import { beginChannelSwitchTrace } from "@/shared/lib/channelSwitchPerf";
/**
* commitGuardedNavigation runs the shared commit flow for app navigations:
* skip same-destination no-ops (unless forced or carrying a router-state
* update), consult the navigation guard, then navigate. A same-href
* navigation that writes state — e.g. setting or clearing the search
* highlight — must still commit, or the state never lands. When
* `traceChannelId` is set, the channel-switch
* trace opens only after the guard accepts — a refused click must not leave
* an orphan trace that a later history navigation (deliberately untraced)
* would settle with the refused click's inflated wall time. Returns whether
* the navigation was performed. `deps` exists for unit tests.
*/
export async function commitGuardedNavigation(
input: {
currentHref: string;
nextHref: string;
force?: boolean;
guardedTarget: GuardedNavigation;
hasStateUpdate?: boolean;
traceChannelId?: string;
navigate: () => Promise<unknown>;
},
deps: {
allow?: typeof allowNavigation;
beginTrace?: typeof beginChannelSwitchTrace;
} = {},
): Promise<boolean> {
const allow = deps.allow ?? allowNavigation;
const beginTrace = deps.beginTrace ?? beginChannelSwitchTrace;
if (
input.currentHref === input.nextHref &&
!input.force &&
!input.hasStateUpdate
) {
return false;
}
if (!allow(input.guardedTarget)) {
return false;
}
if (input.traceChannelId !== undefined) {
beginTrace(input.traceChannelId);
}
await input.navigate();
return true;
}