fix(server): let Git observation measurements reach their summary

Startup discovery queues a refresh beyond the old 250 ms wait. Wait for Git command quiescence at phase boundaries so idle measurements exclude startup work, and pass the observer to healthy teardown before measuring degraded polling.
This commit is contained in:
paseo-bot[bot]
2026-10-19 00:50:05 +02:00
parent dc7bed417a
commit 3166730e36
2 changed files with 46 additions and 3 deletions
@@ -12,6 +12,7 @@ import {
import {
startGitCommandMetrics,
stopGitCommandMetrics,
waitForGitCommandMetricsIdle,
type GitCommandMetricsSnapshot,
} from "../src/utils/run-git-command.js";
import { CheckoutDiffManager } from "../src/server/checkout-diff-manager.js";
@@ -160,6 +161,7 @@ async function measurePhase(input: {
serviceMetrics.workspaceRefreshQueuedCount === 0
);
}, "observation queue to drain");
await waitForGitCommandMetricsIdle({ quietMs: 1_500, timeoutMs: 8_000 });
} finally {
metrics = stopGitCommandMetrics();
}
@@ -243,7 +245,9 @@ async function main(): Promise<void> {
healthy.watcher.subscriptions.size === 2,
"healthy bootstrap",
);
await sleep(250);
// Linux startup discovery schedules a one-second debounced refresh even
// after subscriptions are ready. Keep that work in the bootstrap phase.
await waitForGitCommandMetricsIdle({ quietMs: 1_500, timeoutMs: 8_000 });
const bootstrapMetrics = stopGitCommandMetrics();
const bootstrapServiceMetrics = healthy.service.getMetrics();
phases.bootstrap = {
@@ -342,6 +346,7 @@ async function main(): Promise<void> {
diffManager = null;
await closeMeasuredService({
service: healthy.service,
observer: healthy.watcher.observer,
subscriptions: healthy.watcher.subscriptions,
});
healthy = null;
@@ -357,7 +362,9 @@ async function main(): Promise<void> {
degraded.service.getMetrics().workspaceObservationSetupInFlightCount === 0,
"degraded bootstrap",
);
await sleep(250);
// Linux startup discovery schedules a one-second debounced refresh even
// after subscriptions are ready. Keep that work in the bootstrap phase.
await waitForGitCommandMetricsIdle({ quietMs: 1_500, timeoutMs: 8_000 });
const degradedBootstrapMetrics = stopGitCommandMetrics();
const degradedBootstrapServiceMetrics = degraded.service.getMetrics();
phases.degradedBootstrap = {
@@ -1,5 +1,7 @@
import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
import { execFileSync } from "node:child_process";
import { execFile, execFileSync } from "node:child_process";
import { promisify } from "node:util";
import { fileURLToPath } from "node:url";
import { tmpdir } from "node:os";
import path from "node:path";
import pino from "pino";
@@ -522,3 +524,37 @@ test("a late Git-ignored tree is pruned while tracked changes still notify consu
rmSync(tempDir, { recursive: true, force: true });
}
}, 15_000);
test("Git observation measurement separates startup from idle and reaches its degraded summary", async () => {
const script = fileURLToPath(
new URL("../../scripts/measure-git-observation.ts", import.meta.url),
);
const { stdout } = await promisify(execFile)(process.execPath, ["--import", "tsx", script], {
timeout: 30_000,
maxBuffer: 1024 * 1024,
});
const summary = stdout
.split("\n")
.find((line) => line.startsWith("GIT_OBSERVATION_MEASUREMENT "));
expect(summary).toBeTypeOf("string");
const report = JSON.parse(summary!.slice("GIT_OBSERVATION_MEASUREMENT ".length));
expect(Object.keys(report.phases)).toEqual([
"bootstrap",
"legacyFullRefreshReference",
"idle",
"activeDiff",
"editBurst",
"ignoredStorm",
"degradedBootstrap",
"degradedWatcher",
]);
expect(report.phases.idle.gitCommands).toBe(0);
expect(report.phases.ignoredStorm.gitCommands).toBe(0);
expect(report.phases.bootstrap.producers.structural).toBeGreaterThanOrEqual(1);
expect(report.phases.activeDiff.producers.worktree).toBeGreaterThanOrEqual(1);
expect(report.phases.editBurst.producers.worktree).toBeLessThanOrEqual(2);
expect(report.phases.degradedWatcher.producers.worktree).toBeGreaterThanOrEqual(1);
for (const phase of Object.values(report.phases) as Array<{ queueAfter: unknown }>) {
expect(phase.queueAfter).toEqual({ inFlight: 0, queued: 0 });
}
}, 35_000);