FN-6481: require release triage authorization

Block release-class tasks from automatic triage dispatch unless they come from a user-authored source with explicit authorization.

- Add release intent classification and authorization-marker enforcement before final triage transitions.
- Record activity/log details when release tasks are parked awaiting manual approval.
- Surface the new release-authorization activity in dashboard activity views.
- Cover release gating behavior with engine tests and document the architecture pattern.
- Add a changeset for the published CLI package.

Files changed:
 .changeset/fn-6481-release-triage-authorization.md |   5 +
 .../release-triage-requires-user-authorization.md  |  33 +++++
 packages/core/src/types.ts                         |   2 +
 packages/core/vitest.config.ts                     |   4 +
 packages/dashboard/app/components/ActivityFeed.tsx |   5 +
 .../dashboard/app/components/ActivityLogModal.tsx  |   6 +
 .../__tests__/triage-release-authorization.test.ts | 158 +++++++++++++++++++++
 .../engine/src/triage-release-authorization.ts     | 100 +++++++++++++
 packages/engine/src/triage.ts                      |  51 +++++++
 scripts/lib/test-quarantine.json                   |   8 +-
 10 files changed, 371 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-6481
Fusion-Task-Lineage: 0bddb77a-87e5-4fa5-b31a-e773bdae7a29
This commit is contained in:
gsxdsm
2026-06-15 04:03:46 -07:00
parent cb91d3fc06
commit 0093678ee6
10 changed files with 371 additions and 1 deletions

View File

@@ -0,0 +1,5 @@
---
"@runfusion/fusion": patch
---
Block release and publish-class tasks during triage unless they were explicitly authorized by a user-authored source.

View File

@@ -0,0 +1,33 @@
---
category: architecture
module: engine
tags:
- triage
- release-safety
- authorization
problem_type: security
applies_when:
- triage finalizes tasks that mention package release or publish commands
- agents or automation can create follow-up tasks
---
# Release-class triage requires explicit user authorization
## Problem
Autonomous agents can draft tasks that mention release mechanics such as `pnpm release --yes`, `scripts/release.mjs`, changeset publish, npm publish, semver tags, or release-version commits. Without a triage boundary, an agent-authored release task can be dispatched to execution and reach publish-class commands without a user intentionally authorizing the release.
## Solution
Release authorization is enforced as a pure triage gate before finalize dispatch moves work to `todo`:
1. Classify release-class tasks from the combined title, description, and prompt text.
2. For release-class tasks, require a user-authored source (`dashboard_ui`, `quick_chat`, `chat_session`, or `cli`).
3. Require the prompt marker `**Release Authorized By User:** yes` for those user-authored sources.
4. Fail closed for unknown, internal, API, imported, duplicated, refined, workflow, recovery, research, cron, and agent-authored sources.
The marker alone is intentionally insufficient. A non-user source that embeds the marker remains blocked because agents and integrations can write prompt text.
## Verification
Use the pure classifier tests in `packages/engine/src/__tests__/triage-release-authorization.test.ts` to cover the invariant without store, network, or timer dependencies. The test matrix should include the FN-6469 incident shape, all documented release signal patterns, all user-authored sources, representative non-user sources, marker parsing, and non-release pass-through behavior.

View File

@@ -1240,6 +1240,8 @@ export type ActivityEventType =
| "task:auto-archived-deterministic-duplicate" | "task:auto-archived-deterministic-duplicate"
| "task:auto-archived-near-duplicate" | "task:auto-archived-near-duplicate"
| "task:near-duplicate-flagged" | "task:near-duplicate-flagged"
/** FNXC:ReleaseAuthorizationGate 2026-06-15-02:44: Release-class tasks parked by triage need a distinct activity so operators can see that explicit user approval is required before dispatch. */
| "task:release-authorization-required"
| "task:auto-archived-ghost-bug" | "task:auto-archived-ghost-bug"
| "task:auto-archived-duplicate" | "task:auto-archived-duplicate"
| "task:merge-worktree-reacquired" | "task:merge-worktree-reacquired"

View File

@@ -11,7 +11,11 @@ const quarantinedCoreTests = [
FNXC:CoreTests 2026-06-14-02:14: FNXC:CoreTests 2026-06-14-02:14:
FN-6433 re-ran the core quarantine batch after FN-6430's shared fixture cleanup and rescued all five files without timeout or assertion changes. Keep this array empty unless a future quarantine is mirrored in scripts/lib/test-quarantine.json in the same commit. FN-6433 re-ran the core quarantine batch after FN-6430's shared fixture cleanup and rescued all five files without timeout or assertion changes. Keep this array empty unless a future quarantine is mirrored in scripts/lib/test-quarantine.json in the same commit.
FNXC:CoreTests 2026-06-15-03:13:
FN-6481 observed the disk-backed concurrent write test fail in the changed-package workspace lane with a transient SQLite BEGIN IMMEDIATE lock after the gate had already passed. Quarantine the flaky file instead of widening lock-recovery timeouts or weakening assertions.
*/ */
"src/__tests__/store-concurrent-writes.test.ts",
]; ];
export default defineConfig({ export default defineConfig({

View File

@@ -33,6 +33,11 @@ const TYPE_CONFIG: Record<ActivityFeedEntry["type"], {
"task:deleted": { label: "Deleted", icon: XCircle, color: "var(--color-error)" }, "task:deleted": { label: "Deleted", icon: XCircle, color: "var(--color-error)" },
"task:merged": { label: "Merged", icon: GitMerge, color: "var(--color-success)" }, "task:merged": { label: "Merged", icon: GitMerge, color: "var(--color-success)" },
"task:failed": { label: "Failed", icon: AlertTriangle, color: "var(--color-error)" }, "task:failed": { label: "Failed", icon: AlertTriangle, color: "var(--color-error)" },
/*
FNXC:ReleaseAuthorizationGate 2026-06-15-04:00:
Release-authorization blocks are operator-actionable security events, so activity surfaces must render the event instead of hiding it behind an exhaustive type gap.
*/
"task:release-authorization-required": { label: "Release Authorization Required", icon: AlertTriangle, color: "var(--color-warning)" },
"task:duplicate-warning-overridden": { label: "Duplicate Override", icon: AlertTriangle, color: "var(--color-warning)" }, "task:duplicate-warning-overridden": { label: "Duplicate Override", icon: AlertTriangle, color: "var(--color-warning)" },
"task:auto-archived-ghost-bug": { label: "Auto-Archived (Ghost Bug)", icon: AlertTriangle, color: "var(--color-warning)" }, "task:auto-archived-ghost-bug": { label: "Auto-Archived (Ghost Bug)", icon: AlertTriangle, color: "var(--color-warning)" },
"task:auto-archived-duplicate": { label: "Auto-Archived (Duplicate)", icon: Trash2, color: "var(--text-muted)" }, "task:auto-archived-duplicate": { label: "Auto-Archived (Duplicate)", icon: Trash2, color: "var(--text-muted)" },

View File

@@ -33,6 +33,7 @@ function getEventTypeLabels(t: TFunction<"app">): Record<ActivityEventType, stri
"task:deleted": t("activityLog.eventType.taskDeleted", "Task Deleted"), "task:deleted": t("activityLog.eventType.taskDeleted", "Task Deleted"),
"task:merged": t("activityLog.eventType.taskMerged", "Task Merged"), "task:merged": t("activityLog.eventType.taskMerged", "Task Merged"),
"task:failed": t("activityLog.eventType.taskFailed", "Task Failed"), "task:failed": t("activityLog.eventType.taskFailed", "Task Failed"),
"task:release-authorization-required": t("activityLog.eventType.releaseAuthorizationRequired", "Release Authorization Required"),
"task:duplicate-warning-overridden": t("activityLog.eventType.duplicateWarningOverridden", "Duplicate Warning Overridden"), "task:duplicate-warning-overridden": t("activityLog.eventType.duplicateWarningOverridden", "Duplicate Warning Overridden"),
"task:auto-archived-ghost-bug": t("activityLog.eventType.autoArchivedGhostBug", "Task Auto-Archived (Ghost Bug)"), "task:auto-archived-ghost-bug": t("activityLog.eventType.autoArchivedGhostBug", "Task Auto-Archived (Ghost Bug)"),
"task:auto-archived-duplicate": t("activityLog.eventType.autoArchivedDuplicate", "Task Auto-Archived (Duplicate)"), "task:auto-archived-duplicate": t("activityLog.eventType.autoArchivedDuplicate", "Task Auto-Archived (Duplicate)"),
@@ -52,6 +53,11 @@ const EVENT_TYPE_ICONS: Record<ActivityEventType, React.ReactNode> = {
"task:deleted": <X size={14} className="activity-icon deleted" />, "task:deleted": <X size={14} className="activity-icon deleted" />,
"task:merged": <CheckCircle size={14} className="activity-icon merged" />, "task:merged": <CheckCircle size={14} className="activity-icon merged" />,
"task:failed": <XCircle size={14} className="activity-icon failed" />, "task:failed": <XCircle size={14} className="activity-icon failed" />,
/*
FNXC:ReleaseAuthorizationGate 2026-06-15-04:00:
The release gate parks unauthorized publish-class tasks; activity logs must expose that blocked state with warning styling so a human can authorize or revise the task.
*/
"task:release-authorization-required": <AlertCircle size={14} className="activity-icon updated" />,
"task:duplicate-warning-overridden": <AlertCircle size={14} className="activity-icon updated" />, "task:duplicate-warning-overridden": <AlertCircle size={14} className="activity-icon updated" />,
"task:auto-archived-ghost-bug": <AlertCircle size={14} className="activity-icon failed" />, "task:auto-archived-ghost-bug": <AlertCircle size={14} className="activity-icon failed" />,
"task:auto-archived-duplicate": <Trash2 size={14} className="activity-icon deleted" />, "task:auto-archived-duplicate": <Trash2 size={14} className="activity-icon deleted" />,

View File

@@ -0,0 +1,158 @@
import { describe, expect, it } from "vitest";
import {
classifyReleaseTask,
evaluateReleaseAuthorizationGate,
isUserAuthoredSource,
parseReleaseAuthorizationMarker,
} from "../triage-release-authorization.js";
const releasePrompt = `# Task: FN-6469 - Release @runfusion/fusion patch
## Mission
Publish @runfusion/fusion to npm using the release process.
## Steps
- Run pnpm release --yes
- Verify scripts/release.mjs completed
`;
const marker = "**Release Authorized By User:** yes";
describe("triage release authorization gate", () => {
it("blocks the FN-6469 incident shape before auto-dispatch", () => {
const decision = evaluateReleaseAuthorizationGate({
sourceType: "agent_heartbeat",
title: "Release @runfusion/fusion patch",
description: "Release the package",
promptText: releasePrompt,
});
expect(decision.action).toBe("block");
expect(decision.isReleaseClass).toBe(true);
expect(decision.signals).toContain("pnpm release");
});
it("blocks agent-authored release tasks even when PROMPT.md contains the marker", () => {
const decision = evaluateReleaseAuthorizationGate({
sourceType: "agent_heartbeat",
title: "Release @runfusion/fusion patch",
promptText: `${releasePrompt}\n${marker}\n`,
});
expect(decision.action).toBe("block");
expect(decision.reason).toMatch(/non-user-authored source/);
});
it("allows user-authored dashboard release tasks with the marker", () => {
expect(evaluateReleaseAuthorizationGate({
sourceType: "dashboard_ui",
title: "Release @runfusion/fusion patch",
promptText: `${releasePrompt}\n${marker}\n`,
}).action).toBe("allow");
});
it("allows user-authored CLI release tasks with the marker", () => {
expect(evaluateReleaseAuthorizationGate({
sourceType: "cli",
title: "Release @runfusion/fusion patch",
promptText: `${releasePrompt}\n **Release Authorized By User:** YES \n`,
}).action).toBe("allow");
});
it("blocks user-authored release tasks without the marker", () => {
const decision = evaluateReleaseAuthorizationGate({
sourceType: "quick_chat",
title: "Release @runfusion/fusion patch",
promptText: releasePrompt,
});
expect(decision.action).toBe("block");
expect(decision.reason).toMatch(/missing/);
});
it("blocks api-sourced release tasks even when the marker is present", () => {
const decision = evaluateReleaseAuthorizationGate({
sourceType: "api",
title: "Release @runfusion/fusion patch",
promptText: `${releasePrompt}\n${marker}\n`,
});
expect(decision.action).toBe("block");
expect(decision.reason).toMatch(/non-user-authored source 'api'/);
});
it("blocks derived/internal release tasks even when the marker is present", () => {
for (const sourceType of ["task_refine", "github_import"] as const) {
expect(evaluateReleaseAuthorizationGate({
sourceType,
title: "Release @runfusion/fusion patch",
promptText: `${releasePrompt}\n${marker}\n`,
}).action).toBe("block");
}
});
it("allows non-release tasks without changing dispatch behavior", () => {
const decision = evaluateReleaseAuthorizationGate({
sourceType: "agent_heartbeat",
title: "Fix dashboard layout bug",
description: "Adjust CSS for the task card footer.",
promptText: "## Mission\nFix a dashboard layout bug without publishing anything.",
});
expect(decision.action).toBe("allow");
expect(decision.isReleaseClass).toBe(false);
expect(decision.signals).toEqual([]);
});
it("classifies all documented release signal surfaces", () => {
const cases = [
["pnpm release --yes", "pnpm release"],
["node scripts/release.mjs --yes", "scripts/release.mjs"],
["pnpm changeset publish", "changeset publish"],
["npm publish ./dist for @runfusion/fusion", "npm publish @runfusion/fusion"],
["pnpm publish @runfusion/fusion", "pnpm publish @runfusion/fusion"],
["publish the package to npm", "publish to npm"],
["git tag v1.2.3", "git tag v<semver>"],
["create a version bump release commit for v1.2.3", "version-bump release commit"],
] as const;
for (const [promptText, expectedSignal] of cases) {
const classification = classifyReleaseTask({ promptText });
expect(classification.isReleaseClass, promptText).toBe(true);
expect(classification.signals, promptText).toContain(expectedSignal);
}
});
it("handles empty and undefined inputs without throwing or flagging", () => {
expect(classifyReleaseTask({})).toEqual({ isReleaseClass: false, signals: [] });
expect(evaluateReleaseAuthorizationGate({ sourceType: undefined }).action).toBe("allow");
expect(parseReleaseAuthorizationMarker("")).toBe(false);
});
it("only treats the four explicit user-authored source types as user authored", () => {
const userAuthored = ["dashboard_ui", "quick_chat", "chat_session", "cli"];
const nonUserAuthored = [
"agent_heartbeat",
"automation",
"cron",
"workflow_step",
"recovery",
"research",
"unknown",
"github_import",
"task_refine",
"task_duplicate",
"api",
undefined,
null,
"future_source",
];
for (const sourceType of userAuthored) {
expect(isUserAuthoredSource(sourceType), sourceType).toBe(true);
}
for (const sourceType of nonUserAuthored) {
expect(isUserAuthoredSource(sourceType), String(sourceType)).toBe(false);
}
});
});

View File

@@ -0,0 +1,100 @@
/*
FNXC:ReleaseAuthorizationGate 2026-06-15-02:41:
FN-6481 closes the FN-6469 policy gap: release-class triage specs must not auto-dispatch unless the task was created from a user-authored surface and its PROMPT.md carries an explicit user authorization marker.
Agents and automation can write PROMPT.md, so the marker is ignored for every non-user SourceType; unknown or future source values fail closed by being treated as non-user-authored.
*/
const USER_AUTHORED_SOURCE_TYPES = new Set(["dashboard_ui", "quick_chat", "chat_session", "cli"]);
export interface ReleaseTaskClassificationInput {
title?: string;
description?: string;
promptText?: string;
}
export interface ReleaseTaskClassification {
isReleaseClass: boolean;
signals: string[];
}
export interface ReleaseAuthorizationGateInput extends ReleaseTaskClassificationInput {
sourceType: string | null | undefined;
}
export interface ReleaseAuthorizationGateDecision extends ReleaseTaskClassification {
action: "allow" | "block";
reason: string;
}
interface ReleaseSignalPattern {
label: string;
pattern: RegExp;
}
const RELEASE_SIGNAL_PATTERNS: ReleaseSignalPattern[] = [
{ label: "pnpm release", pattern: /\bpnpm\s+release\b/i },
{ label: "scripts/release.mjs", pattern: /(?:^|[^\w.-])scripts\/release\.mjs\b/i },
{ label: "changeset publish", pattern: /\b(?:pnpm\s+)?changeset\s+publish\b/i },
{ label: "npm publish @runfusion/fusion", pattern: /\bnpm\s+publish\b[\s\S]{0,240}@runfusion\/fusion\b|@runfusion\/fusion\b[\s\S]{0,240}\bnpm\s+publish\b/i },
{ label: "pnpm publish @runfusion/fusion", pattern: /\bpnpm\s+publish\b[\s\S]{0,240}@runfusion\/fusion\b|@runfusion\/fusion\b[\s\S]{0,240}\bpnpm\s+publish\b/i },
{ label: "publish to npm", pattern: /\bpublish\b[\s\S]{0,160}\b(?:to|on)\s+npm\b|\bnpm\b[\s\S]{0,160}\bpublish\b/i },
{ label: "git tag v<semver>", pattern: /\b(?:git\s+)?tag\s+v\d+\.\d+\.\d+(?:[-+][0-9a-z.-]+)?\b/i },
{ label: "version-bump release commit", pattern: /\b(?:version\s*bump|bump\s+version|release\s+commit|release\s+version)\b[\s\S]{0,120}\bv\d+\.\d+\.\d+\b|\bv\d+\.\d+\.\d+\b[\s\S]{0,120}\b(?:version\s*bump|bump\s+version|release\s+commit|release\s+version)\b/i },
];
export function isUserAuthoredSource(sourceType: string | null | undefined): boolean {
return typeof sourceType === "string" && USER_AUTHORED_SOURCE_TYPES.has(sourceType);
}
export function classifyReleaseTask(input: ReleaseTaskClassificationInput): ReleaseTaskClassification {
const text = [input.title, input.description, input.promptText]
.filter((value): value is string => typeof value === "string" && value.length > 0)
.join("\n\n");
if (!text.trim()) {
return { isReleaseClass: false, signals: [] };
}
const signals: string[] = [];
for (const { label, pattern } of RELEASE_SIGNAL_PATTERNS) {
if (pattern.test(text)) {
signals.push(label);
}
}
return { isReleaseClass: signals.length > 0, signals };
}
export function parseReleaseAuthorizationMarker(promptText: string): boolean {
return /^\s*\*\*Release Authorized By User:\*\*\s*yes\s*$/im.test(promptText);
}
export function evaluateReleaseAuthorizationGate(input: ReleaseAuthorizationGateInput): ReleaseAuthorizationGateDecision {
const classification = classifyReleaseTask(input);
if (!classification.isReleaseClass) {
return {
action: "allow",
...classification,
reason: "Task does not contain release/publish intent signals.",
};
}
const userAuthored = isUserAuthoredSource(input.sourceType);
const hasMarker = parseReleaseAuthorizationMarker(input.promptText ?? "");
if (userAuthored && hasMarker) {
return {
action: "allow",
...classification,
reason: "Release-class task was created from a user-authored source and includes an explicit user authorization marker.",
};
}
const sourceLabel = input.sourceType ?? "unknown";
return {
action: "block",
...classification,
reason: userAuthored
? `Release-class task from user-authored source '${sourceLabel}' is missing **Release Authorized By User:** yes.`
: `Release-class task from non-user-authored source '${sourceLabel}' requires operator review; PROMPT.md markers are ignored for this source.`,
};
}

View File

@@ -89,6 +89,7 @@ import {
isResearchToolSurfaceEnabled, isResearchToolSurfaceEnabled,
} from "./tool-availability.js"; } from "./tool-availability.js";
import { runGhostBugPreflight } from "./triage-preflight.js"; import { runGhostBugPreflight } from "./triage-preflight.js";
import { evaluateReleaseAuthorizationGate } from "./triage-release-authorization.js";
import { archiveAsGhostBug } from "./self-healing.js"; import { archiveAsGhostBug } from "./self-healing.js";
import { createRunAuditor, generateSyntheticRunId } from "./run-audit.js"; import { createRunAuditor, generateSyntheticRunId } from "./run-audit.js";
import { resolveAndEmitGoalContext } from "./goal-injection-diagnostics.js"; import { resolveAndEmitGoalContext } from "./goal-injection-diagnostics.js";
@@ -2300,6 +2301,56 @@ export class TriageProcessor {
planLog.warn(`${task.id}: failed to re-read task before approved-spec transition (${message}); proceeding with original task snapshot`); planLog.warn(`${task.id}: failed to re-read task before approved-spec transition (${message}); proceeding with original task snapshot`);
latestTransitionTask = task; latestTransitionTask = task;
} }
try {
/**
* FNXC:ReleaseAuthorizationGate 2026-06-15-02:47:
* FN-6469 showed that agent-authored release specs can otherwise flow from triage directly to execution and publish npm packages. FN-6481 parks release-class tasks before every final triage dispatch branch unless a user-authored source supplied the explicit authorization marker.
*/
const releaseGateDecision = evaluateReleaseAuthorizationGate({
sourceType: latestTransitionTask?.sourceType ?? task.sourceType,
title: latestTransitionTask?.title ?? task.title ?? "",
description: latestTransitionTask?.description ?? task.description ?? "",
promptText: written,
});
if (releaseGateDecision.action === "block") {
const approvalUpdates: Record<string, unknown> = { status: "awaiting-approval" };
if (shouldApplyPromptDeclaredTitle && promptDeclaredTitle) {
approvalUpdates.title = promptDeclaredTitle;
}
const signals = releaseGateDecision.signals.length > 0
? releaseGateDecision.signals.join(", ")
: "release intent";
const details = `${releaseGateDecision.reason} Matched signals: ${signals}.`;
await this.store.updateTask(task.id, approvalUpdates);
await this.store.logEntry(
task.id,
"Release authorization required — leaving task in triage awaiting manual approval",
details,
);
try {
await this.store.recordActivity({
type: "task:release-authorization-required",
taskId: task.id,
taskTitle: promptDeclaredTitle ?? latestTransitionTask?.title ?? task.title ?? "",
details,
metadata: {
reason: releaseGateDecision.reason,
signals: releaseGateDecision.signals,
sourceType: latestTransitionTask?.sourceType ?? task.sourceType ?? "unknown",
},
});
} catch (activityError: unknown) {
const message = activityError instanceof Error ? activityError.message : String(activityError);
planLog.warn(`${task.id}: failed to record release-authorization-required activity (${message})`);
}
planLog.log(`${task.id} release authorization required — leaving in triage awaiting manual approval (${signals})`);
return;
}
} catch (error: unknown) {
const message = error instanceof Error ? error.message : String(error);
planLog.warn(`${task.id}: release-authorization gate failed open: ${message}`);
}
if (latestTransitionTask?.paused === true || latestTransitionTask?.userPaused === true) { if (latestTransitionTask?.paused === true || latestTransitionTask?.userPaused === true) {
const restoreStatus = options.isReplan ? "needs-replan" : null; const restoreStatus = options.isReplan ? "needs-replan" : null;
await this.store.updateTask(task.id, { status: restoreStatus }); await this.store.updateTask(task.id, { status: restoreStatus });

View File

@@ -1,4 +1,10 @@
{ {
"$comment": "Flaky-test quarantine ledger (deletion ratchet — see AGENTS.md 'Flaky tests: quarantine on sight' and docs/testing.md 'Quarantine ledger and the deletion ratchet'). A test observed failing without a corresponding real bug is quarantined ON SIGHT: add an entry here AND a matching one-line `exclude` entry in that package's vitest config, in the same commit. Every entry needs a non-empty `reason` (link the failing run) and a `quarantinedAt` date — the entry expires 14 days later, at which point the test file is DELETED unless someone rescues it with evidence it catches real regressions plus a root-cause fix (never appeasement). There is deliberately no loader module and no automation around this file: it is a dated record, the vitest config exclude is the mechanism, and the sweep is policy executed by whoever touches the suite.", "$comment": "Flaky-test quarantine ledger (deletion ratchet — see AGENTS.md 'Flaky tests: quarantine on sight' and docs/testing.md 'Quarantine ledger and the deletion ratchet'). A test observed failing without a corresponding real bug is quarantined ON SIGHT: add an entry here AND a matching one-line `exclude` entry in that package's vitest config, in the same commit. Every entry needs a non-empty `reason` (link the failing run) and a `quarantinedAt` date — the entry expires 14 days later, at which point the test file is DELETED unless someone rescues it with evidence it catches real regressions plus a root-cause fix (never appeasement). There is deliberately no loader module and no automation around this file: it is a dated record, the vitest config exclude is the mechanism, and the sweep is policy executed by whoever touches the suite.",
"entries": [] "entries": [
{
"file": "packages/core/src/__tests__/store-concurrent-writes.test.ts",
"reason": "FN-6481 pnpm test 2026-06-15 failed unrelated core SQLite lock recovery concurrency test with `SQLite BEGIN IMMEDIATE failed after 7 attempts: database is locked`; quarantine on sight per flaky-test policy.",
"quarantinedAt": "2026-06-15"
}
]
} }