fix(cursor): addresses Phase 4/4.5 review findings

Restores the legacy stdout/stderr auth-pattern fallback in
checkCursorAgentAvailability() that the plan's Task 2 Step 4
required but the implementation had dropped. Threads an optional
deps parameter through checkCursorConnectionIfNeeded() so its
error branch is reachable in tests, and switches both it and the
manual-refresh route to exhaustive switch statements over the
renewal result. Adds a short-lived host-keyed dedup cache around
tryIdeAuth() so multiple due Cursor connections sharing a host
don't each open the same state.vscdb file in one sweep tick.
Adds opportunistic eviction to the manual-refresh cooldown map,
an outer try/catch to the availability route for defense-in-depth
consistency with the plan's other routes, and corrects a stale
JSDoc claim about the /login route's auth check. Documents the
now-empirically-confirmed agent-cli-state.json schema mismatch
found while validating against a real cursor-agent install.
This commit is contained in:
Will Gordon
2026-07-31 20:53:01 -04:00
committed by diegosouzapw
parent 6448f02b33
commit 41121078ab
8 changed files with 335 additions and 94 deletions

View File

@@ -7,6 +7,26 @@
* is the precedent this component follows), and this directory's own
* __tests__/phase1d.test.tsx for the createRoot/act mounting convention.
*/
// NOTE ON WHICH CONFIG DISCOVERS THIS FILE (kept as a `//` block — see why
// below): unlike tests/unit/ui/use-provider-connections-cursor-refresh.test.tsx
// and tests/unit/ui/connectionsSearchFilter.test.tsx (which had to relocate
// out of their __tests__/ directories because vitest.mcp.config.ts's
// src/app/(dashboard)/**/__tests__/**/*.test.tsx glob spells out the
// (dashboard) path segment literally, which tinyglobby parses as an (empty)
// extglob group — matching nothing), THIS file's location IS correct per the
// plan: vitest.config.ts's glob (src/app/**/dashboard/providers/**/__tests__/
// **/*.test.tsx) never spells out (dashboard) literally — its ** wildcard
// swallows that segment regardless of its literal name — so it matches here
// without hitting the same bug. That means this file is collected only by
// vitest.config.ts (`npm run test:vitest:ui`), NOT by vitest.mcp.config.ts
// (`npm run test:vitest`) — confirmed via a direct `vitest list` probe
// against both configs. Both jobs are CI-blocking (`test:vitest:ui` was
// promoted from advisory to blocking per ci.yml's own comment, PR #7127),
// so this is a coverage-attribution quirk, not a real CI gap — this file
// still runs and gates merges, just via the sibling config.
// (This note is a `//` block, not part of the /** */ JSDoc above, because
// the glob patterns it quotes contain a literal `*/` sequence that would
// otherwise terminate a block comment early.)
import React from "react";
import { act } from "react";
import { createRoot, hydrateRoot } from "react-dom/client";

View File

@@ -28,6 +28,17 @@ const MANUAL_REFRESH_COOLDOWN_MS = 30_000;
*/
const lastManualRefreshAttemptAt = new Map<string, number>();
/** Opportunistic eviction — no separate timer needed since this route is
* already called on every manual-refresh click; keeps the map from growing
* unbounded across the lifetime of the process as connections are added/removed. */
function evictExpiredManualRefreshAttempts(now: number): void {
for (const [connectionId, attemptedAt] of lastManualRefreshAttemptAt) {
if (now - attemptedAt >= MANUAL_REFRESH_COOLDOWN_MS) {
lastManualRefreshAttemptAt.delete(connectionId);
}
}
}
/**
* POST /api/providers/[id]/refresh-cursor
* Manually trigger a Cursor session renewal attempt (nudge `cursor-agent`,
@@ -57,8 +68,11 @@ export async function POST(_request: Request, { params }: { params: Promise<{ id
);
}
const now = Date.now();
evictExpiredManualRefreshAttempts(now);
const lastAttempt = lastManualRefreshAttemptAt.get(connection.id) ?? 0;
const elapsedMs = Date.now() - lastAttempt;
const elapsedMs = now - lastAttempt;
if (elapsedMs < MANUAL_REFRESH_COOLDOWN_MS) {
const retryAfterMs = MANUAL_REFRESH_COOLDOWN_MS - elapsedMs;
return NextResponse.json(
@@ -74,7 +88,7 @@ export async function POST(_request: Request, { params }: { params: Promise<{ id
}
// Set immediately before invoking renewCursorConnection() — regardless of
// outcome — so rapid repeated clicks are throttled either way.
lastManualRefreshAttemptAt.set(connection.id, Date.now());
lastManualRefreshAttemptAt.set(connection.id, now);
return await runCursorRenewalExclusive(connection.id, async () => {
const result = await renewCursorConnection({
@@ -82,35 +96,44 @@ export async function POST(_request: Request, { params }: { params: Promise<{ id
machineId: connection.providerSpecificData?.machineId as string | null | undefined,
});
if (result.status === "renewed") {
const now = new Date().toISOString();
const update = buildCursorRenewedUpdate(connection, result, now);
await updateProviderConnection(connection.id, update);
return NextResponse.json({
success: true,
connectionId: connection.id,
provider: "cursor",
expiresAt: update.expiresAt as string,
refreshedAt: now,
});
switch (result.status) {
case "renewed": {
const nowIso = new Date().toISOString();
const update = buildCursorRenewedUpdate(connection, result, nowIso);
await updateProviderConnection(connection.id, update);
return NextResponse.json({
success: true,
connectionId: connection.id,
provider: "cursor",
expiresAt: update.expiresAt as string,
refreshedAt: nowIso,
});
}
case "unchanged": {
return NextResponse.json({
success: true,
unchanged: true,
connectionId: connection.id,
provider: "cursor",
expiresAt: connection.expiresAt ?? null,
refreshedAt: new Date().toISOString(),
message: "Cursor session is already current — no newer token found on this host.",
});
}
case "error": {
return NextResponse.json(
{
error: "Token refresh failed — provider returned no new token",
details: result.error,
},
{ status: 502 }
);
}
default: {
const _exhaustive: never = result;
throw new Error(`Unhandled CursorRenewalResult status: ${JSON.stringify(_exhaustive)}`);
}
}
if (result.status === "unchanged") {
return NextResponse.json({
success: true,
unchanged: true,
connectionId: connection.id,
provider: "cursor",
expiresAt: connection.expiresAt ?? null,
refreshedAt: new Date().toISOString(),
message: "Cursor session is already current — no newer token found on this host.",
});
}
return NextResponse.json(
{ error: "Token refresh failed — provider returned no new token", details: result.error },
{ status: 502 }
);
});
} catch (error) {
return NextResponse.json(

View File

@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { getCachedCursorAgentAvailability } from "@/lib/cursor/renewal";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
/**
* GET /api/providers/cursor/agent-availability
@@ -19,13 +20,29 @@ import { getCachedCursorAgentAvailability } from "@/lib/cursor/renewal";
* LOCAL_ONLY (see `LOCAL_ONLY_API_PREFIXES` in
* `src/server/authz/routeGuard.ts`), so `managementPolicy` already enforces
* auth + loopback before this handler runs, matching the sibling
* `/api/providers/[id]/refresh` and `/api/providers/[id]/login` routes
* (neither perform their own in-route auth check either).
* `/api/providers/[id]/refresh` route (also no in-route auth check). The
* other sibling, `/api/providers/[id]/login`, does call
* `requireManagementAuth()` itself — redundant given `managementPolicy`'s
* enforcement, but not incorrect.
*
* 🔒 LOCAL_ONLY — spawns `cursor-agent status --format json` via
* `checkCursorAgentAvailability()` (Hard Rules #15 + #17).
*/
export async function GET() {
const { available } = await getCachedCursorAgentAvailability();
return NextResponse.json({ cursorAgentAvailable: available });
try {
const { available } = await getCachedCursorAgentAvailability();
return NextResponse.json({ cursorAgentAvailable: available });
} catch (error) {
// checkCursorAgentAvailability() currently swallows all realistic errors
// internally (spawn failures, unparseable output) — this catch is
// defense-in-depth consistency with the rest of this plan's routes, not
// a currently-reachable path.
return NextResponse.json(
{
cursorAgentAvailable: false,
error: sanitizeErrorMessage(error instanceof Error ? error.message : String(error)),
},
{ status: 500 }
);
}
}

View File

@@ -1,3 +1,4 @@
import { homedir } from "os";
import { sanitizeErrorMessage } from "@omniroute/open-sse/utils/error";
import { createKeyedMutex } from "@/shared/utils/keyedMutex";
import { resolveCursorAgentBinary, runCursorAgent } from "@/lib/providerModels/cursorAgent";
@@ -96,10 +97,15 @@ export async function checkCursorAgentAvailability(): Promise<{
return { available: parsed.isAuthenticated === true, binaryPath: binary };
} catch {
// Unparseable/empty output (e.g. an older CLI release predating
// `--format json` support on `status`). Fail closed: absent a
// parseable, positive confirmation, treat as unavailable rather than
// risk nudging an unconfirmed session.
return { available: false, binaryPath: binary };
// `--format json` support on `status`). Fall back to the same legacy
// auth-detection convention `cursorAgent.ts` already uses for
// `--list-models`/`--model --help`: absent an explicit "not
// authenticated" signal in stdout/stderr, treat the binary as available.
const combined = `${result.stdout}\n${result.stderr}`;
if (/Authentication required|Not logged in/i.test(combined)) {
return { available: false, binaryPath: binary };
}
return { available: true, binaryPath: binary };
}
}
@@ -131,6 +137,35 @@ export async function getCachedCursorAgentAvailability(): Promise<{
return result;
}
const IDE_AUTH_DEDUP_TTL_MS = 5_000;
let cachedIdeAuthCall: {
home: string;
promise: ReturnType<typeof tryIdeAuth>;
expiresAt: number;
} | null = null;
/**
* Collapses duplicate tryIdeAuth() calls — each of which opens and queries
* the host's Cursor state.vscdb — across multiple Cursor connections that
* become due for renewal in the same sweep tick. Mirrors
* getCachedCursorAgentAvailability()'s short-TTL cache pattern above; keyed
* by homedir() since that determines which physical file(s) tryIdeAuth()
* would probe. Only wraps the REAL tryIdeAuth() — renewCursorConnection()'s
* `deps.tryIdeAuth` test override bypasses this cache entirely (a test mock
* isn't reading a real shared file, so there is nothing to dedup).
*/
function dedupedTryIdeAuth(): ReturnType<typeof tryIdeAuth> {
const home = homedir();
const now = Date.now();
if (cachedIdeAuthCall && cachedIdeAuthCall.home === home && cachedIdeAuthCall.expiresAt > now) {
return cachedIdeAuthCall.promise;
}
const promise = tryIdeAuth();
cachedIdeAuthCall = { home, promise, expiresAt: now + IDE_AUTH_DEDUP_TTL_MS };
return promise;
}
export type CursorRenewalResult =
| {
status: "renewed";
@@ -175,7 +210,7 @@ export async function renewCursorConnection(
checkCursorAgentAvailability?: typeof checkCursorAgentAvailability;
}
): Promise<CursorRenewalResult> {
const resolveIdeAuth = deps?.tryIdeAuth ?? tryIdeAuth;
const resolveIdeAuth = deps?.tryIdeAuth ?? dedupedTryIdeAuth;
const resolveAgentAuth = deps?.tryAgentAuth ?? tryAgentAuth;
const resolveAvailability = deps?.checkCursorAgentAvailability ?? checkCursorAgentAvailability;

View File

@@ -171,16 +171,24 @@ export function cursorDbCandidatePaths(
* login (the official curl-installer convention).
* 2. `~/.cursor/agent-cli-state.json` — a second candidate this codebase's
* own `src/shared/services/cliRuntime.ts` (`CLI_TOOLS.cursor.paths.state`)
* already lists but did not previously probe for auth. Its schema is
* UNVERIFIED against a real authenticated install; if it lacks a usable
* `accessToken` string field, this candidate is skipped gracefully.
* already lists but did not previously probe for auth. If it lacks a
* usable `accessToken` string field, this candidate is skipped
* gracefully.
*
* KNOWN LIMITATION: some `cursor-agent` releases may store the access/refresh
* token in the OS keychain instead of a locally-readable file. When neither
* candidate above yields a token, this function correctly reports
* `{found: false}` even if `cursor-agent status` reports the CLI as
* authenticated — this is a documented, accepted gap (see the renewal plan's
* "Trade-offs Accepted" section), not a silent bug.
* "Trade-offs Accepted" section), not a silent bug. Confirmed, not just
* hypothetical: empirically validated against a real, authenticated
* `cursor-agent` install (v2026.07.23, Homebrew Cask `cursor-cli`) on
* 2026-07-31 — that install's `~/.cursor/agent-cli-state.json` exists but its
* actual schema is `{version, hasShownAgentCommandTip,
* hasClearedLegacyStatsigFields}`, with no `accessToken` field at all, while
* `cursor-agent status --format json` reported `isAuthenticated: true`. This
* candidate is correctly skipped for that install; the graceful-degradation
* fallback below is confirmed correct, not a gap in this specific case.
*/
export async function tryAgentAuth(): Promise<{
found: boolean;

View File

@@ -27,37 +27,63 @@ export async function checkCursorConnectionIfNeeded(params: {
logError: (message: string, ...args: any[]) => void;
getConnectionLogLabel: (conn: { name?: string; email?: string; id?: string }) => string;
logPrefix: string;
/** Testability seam forwarded verbatim to renewCursorConnection() — mirrors
* the deps param Task 2 added there, so tests can force a {status:"error"}
* result without a mock.module() shim. */
deps?: Parameters<typeof renewCursorConnection>[1];
}): Promise<void> {
const { conn, now, buildRefreshFailureUpdate, log, logWarn, getConnectionLogLabel, logPrefix } =
params;
const {
conn,
now,
buildRefreshFailureUpdate,
log,
logWarn,
logError,
getConnectionLogLabel,
logPrefix,
deps,
} = params;
await runCursorRenewalExclusive(conn.id, async () => {
const result = await renewCursorConnection({
accessToken: conn.accessToken,
machineId: conn.providerSpecificData?.machineId ?? null,
});
if (result.status === "renewed") {
await updateProviderConnection(conn.id, buildCursorRenewedUpdate(conn, result, now));
log(
`${logPrefix} ✓ Cursor session renewed for ${getConnectionLogLabel(conn)} (source: ${result.source})`
);
return;
}
const message =
result.status === "error"
? `Cursor session renewal failed: ${result.error}`
: "Cursor session unchanged — no newer token found on this host.";
await updateProviderConnection(
conn.id,
buildRefreshFailureUpdate(conn, now, {
errorCode: "cursor_session_stale",
lastErrorType: "cursor_session_stale",
lastError: message,
testStatus: "active",
})
const result = await renewCursorConnection(
{
accessToken: conn.accessToken,
machineId: conn.providerSpecificData?.machineId ?? null,
},
deps
);
logWarn(`${logPrefix} ✗ Cursor session stale for ${getConnectionLogLabel(conn)}: ${message}`);
switch (result.status) {
case "renewed": {
await updateProviderConnection(conn.id, buildCursorRenewedUpdate(conn, result, now));
log(
`${logPrefix} ✓ Cursor session renewed for ${getConnectionLogLabel(conn)} (source: ${result.source})`
);
return;
}
case "unchanged":
case "error": {
const message =
result.status === "error"
? `Cursor session renewal failed: ${result.error}`
: "Cursor session unchanged — no newer token found on this host.";
await updateProviderConnection(
conn.id,
buildRefreshFailureUpdate(conn, now, {
errorCode: "cursor_session_stale",
lastErrorType: "cursor_session_stale",
lastError: message,
testStatus: "active",
})
);
const logFn = result.status === "error" ? logError : logWarn;
logFn(`${logPrefix} ✗ Cursor session stale for ${getConnectionLogLabel(conn)}: ${message}`);
return;
}
default: {
const _exhaustive: never = result;
throw new Error(`Unhandled CursorRenewalResult status: ${JSON.stringify(_exhaustive)}`);
}
}
});
}

View File

@@ -76,6 +76,8 @@ if (process.env.FAKE_CURSOR_AGENT_HANG === "1") {
process.stdout.write(JSON.stringify({ status: "unauthenticated", isAuthenticated: false }));
} else if (mode === "garbage") {
process.stdout.write("not json output at all");
} else if (mode === "legacy-unauthenticated") {
process.stderr.write("Error: Not logged in. Run 'cursor-agent login' to authenticate.");
}
}
`;
@@ -195,9 +197,20 @@ describe("checkCursorAgentAvailability", () => {
assert.equal(result.binaryPath, binaryPath);
});
it("reports available:false (does not throw) on unparseable/legacy-style stdout", async () => {
it("reports available:true (legacy-authenticated) on unparseable stdout with no auth-required signal", async () => {
// Mirrors fetchCursorAgentModels()'s legacy fallback convention in
// cursorAgent.ts: an older CLI release predating `--format json` support
// on `status` still produces some non-JSON output, but absent an
// explicit "not authenticated" signal, the binary is treated as available.
process.env.FAKE_CURSOR_AGENT_STATUS_MODE = "garbage";
const result = await checkCursorAgentAvailability();
assert.equal(result.available, true);
assert.equal(result.binaryPath, binaryPath);
});
it("reports available:false (legacy-unauthenticated) when unparseable stdout/stderr matches the auth-required pattern", async () => {
process.env.FAKE_CURSOR_AGENT_STATUS_MODE = "legacy-unauthenticated";
const result = await checkCursorAgentAvailability();
assert.equal(result.available, false);
assert.equal(result.binaryPath, binaryPath);
});
@@ -380,6 +393,20 @@ describe("renewCursorConnection", () => {
fs.writeFileSync(path.join(authDir, "auth.json"), JSON.stringify({ accessToken }));
}
async function updateIdeToken(accessToken: string): Promise<void> {
const { openDatabaseAsync } = await import("@/lib/db/adapters/driverFactory");
const dbPath = path.join(
tmpHome,
"Library/Application Support/Cursor/User/globalStorage/state.vscdb"
);
const db = await openDatabaseAsync(dbPath);
db.prepare("INSERT OR REPLACE INTO itemTable (key, value) VALUES (?, ?)").run(
"cursorAuth/accessToken",
accessToken
);
db.close();
}
it("(a) cursor-agent unavailable + IDE re-scrape finds a new token -> renewed via cursor-ide", async () => {
process.env.FAKE_CURSOR_AGENT_STATUS_MODE = "unauthenticated"; // cursor-agent "unavailable"
await writeIdeToken("new-ide-token", "machine-1");
@@ -520,6 +547,52 @@ describe("renewCursorConnection", () => {
source: "cursor-ide",
});
});
it("(g) dedupes tryIdeAuth() across near-simultaneous calls (PERF-001): a stale cached result is served within the TTL, then a fresh one after it expires", async (t) => {
// Simulates multiple Cursor connections becoming due for renewal in the
// same sweep tick: renewCursorConnection() is called back-to-back for
// the SAME host, so the second call must reuse the first's in-flight/
// recently-resolved tryIdeAuth() result rather than re-opening
// state.vscdb — this is a resource-usage guard (PERF-001), not a
// correctness fix. Uses fake timers on `Date` (same technique as
// getCachedCursorAgentAvailability's TTL test) since renewal.ts's dedup
// cache is keyed on Date.now(), not a mockable timer/interval.
t.mock.timers.enable({ apis: ["Date"] });
process.env.FAKE_CURSOR_AGENT_STATUS_MODE = "unauthenticated"; // skip the nudge; isolate the IDE-cache behavior
await writeIdeToken("token-A", "machine-a");
const first = await renewCursorConnection({ accessToken: "old-token" });
assert.deepEqual(first, {
status: "renewed",
accessToken: "token-A",
machineId: "machine-a",
source: "cursor-ide",
});
// Underlying file now has a NEW token, but a second call within the TTL
// must still observe the CACHED "token-A" — proven by comparing against
// current.accessToken: "token-A" (the first result) reads as unchanged
// only if the cache is actually being served instead of a fresh re-scrape.
await updateIdeToken("token-B");
t.mock.timers.tick(2000); // well within the 5s dedup TTL
const second = await renewCursorConnection({ accessToken: "token-A" });
assert.deepEqual(
second,
{ status: "unchanged" },
"expected the cached (stale) tryIdeAuth() result, not a fresh state.vscdb read"
);
// Past the TTL, the next call must re-open the file and observe "token-B".
t.mock.timers.tick(4000); // cumulative 6s, past the 5s TTL
const third = await renewCursorConnection({ accessToken: "token-A" });
assert.deepEqual(third, {
status: "renewed",
accessToken: "token-B",
machineId: "machine-a",
source: "cursor-ide",
});
});
});
describe("buildCursorRenewedUpdate", () => {

View File

@@ -33,6 +33,7 @@ process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../src/lib/db/core.ts");
const providersDb = await import("../../src/lib/db/providers.ts");
const tokenHealthCheck = await import("../../src/lib/tokenHealthCheck.ts");
const tokenHealthCheckCursor = await import("../../src/lib/tokenHealthCheckCursor.ts");
async function resetStorage() {
core.resetDbInstance();
@@ -271,28 +272,66 @@ test('checkConnection: Cursor "unchanged" result marks cursor_session_stale, sta
});
});
test(
'checkConnection: Cursor "error" result -> DB update shape',
{
skip:
"Same root-cause testability gap as tests/unit/cursor-renewal.test.ts's original " +
"case (d), one level up: checkCursorConnectionIfNeeded() (src/lib/tokenHealthCheckCursor.ts) " +
"calls the real renewCursorConnection() with NO deps override, so there is no way to force " +
'it to return {status:"error"} from here (tryIdeAuth()/tryAgentAuth() never throw for real — ' +
"verified in Task 1/2's tests — and this harness has no mock.module() support). " +
"renewCursorConnection()'s OWN error-mapping (sanitizeErrorMessage wiring) is already " +
"covered directly in tests/unit/cursor-renewal.test.ts's case (d), using its deps seam. " +
"The remaining untested surface is narrowly this file's message-building line " +
"(`Cursor session renewal failed: ${result.error}`) plus the cursor_session_stale/testStatus:" +
'"active" override — both of which ARE exercised by the "unchanged" test above via the ' +
"identical buildRefreshFailureUpdate call site (only the interpolated message text differs). " +
"Flagged to the team lead/reviewer: forwarding an optional deps param from " +
"checkCursorConnectionIfNeeded() through to its internal renewCursorConnection() call " +
"(mirroring the seam already added to renewCursorConnection() itself for Task 2) would close " +
"this specific gap with a small, additive change.",
},
async () => {}
);
test('checkCursorConnectionIfNeeded: Cursor "error" result -> DB update shape (via the deps testability seam)', async () => {
await resetStorage();
const id = await createCursorConnection({
accessToken: "old-token",
tokenExpiresAt: NEAR_EXPIRY_ISO,
expiresAt: NEAR_EXPIRY_ISO,
});
// Closes the gap the skipped test above used to document: checkCursorConnectionIfNeeded()
// now forwards an optional `deps` param straight through to renewCursorConnection() (mirroring
// the seam Task 2 added there), so this can force a {status:"error"} result directly instead
// of going through tokenHealthCheck.checkConnection(), which has no deps param of its own.
const rawMessage =
"Failed to read Cursor IDE database at " +
"/Users/secret-user/project/src/lib/cursor/tokenExtractor.ts:284:15 - permission denied";
const throwingTryIdeAuth = async (): Promise<never> => {
throw new Error(rawMessage);
};
const throwingTryAgentAuth = async (): Promise<never> => {
throw new Error(rawMessage);
};
const errors: string[] = [];
const warnings: string[] = [];
const now = new Date().toISOString();
await tokenHealthCheckCursor.checkCursorConnectionIfNeeded({
conn: await freshConn(id),
now,
buildRefreshFailureUpdate: tokenHealthCheck.buildRefreshFailureUpdate,
log: () => {},
logWarn: (message: string) => warnings.push(message),
logError: (message: string) => errors.push(message),
getConnectionLogLabel: (c) => String(c.email ?? c.id ?? "unknown"),
logPrefix: "[test]",
deps: {
tryIdeAuth: throwingTryIdeAuth,
tryAgentAuth: throwingTryAgentAuth,
checkCursorAgentAvailability: async () => ({ available: false, binaryPath: null }),
},
});
const updated = await freshConn(id);
assert.equal(updated.errorCode, "cursor_session_stale");
assert.equal(updated.lastErrorType, "cursor_session_stale");
assert.match(updated.lastError as string, /Cursor session renewal failed:/);
assert.equal(
updated.testStatus,
"active",
"must NOT be terminal — future sweeps must keep retrying"
);
assert.ok(updated.lastHealthCheckAt);
assert.equal(errors.length, 1, "the error branch must log via logError, not logWarn");
assert.equal(warnings.length, 0);
assert.ok(
!errors[0].includes("/Users/secret-user"),
`raw absolute path must not survive sanitization, got: ${errors[0]}`
);
});
// ============================================================================
// Step 1: buildRefreshFailureUpdate's overrides param — DB-shape-adjacent proof