Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
3a28799
feat(ingestion): preserve managed reference pipeline and RAG handover
BigSimmo Oct 14, 2026
9f11b43
fix(ingestion): reconcile pilot source and migration contracts
BigSimmo Oct 14, 2026
a52ee76
docs(ingestion): format generated delivery ownership
BigSimmo Oct 14, 2026
7a5f41f
fix(ci): pin synthetic witness secret-scan finding
BigSimmo Oct 14, 2026
a90da76
fix(ingestion): declare locked extraction dependencies
BigSimmo Oct 14, 2026
f3e3319
Reconcile current main with verified ingestion and Answer fixes
BigSimmo Oct 15, 2026
ca4207b
Format retained ingestion reconciliation records
BigSimmo Oct 15, 2026
308afe8
Reconcile existing provider agreement evidence
BigSimmo Oct 15, 2026
d8e36a0
Preserve landed database history and current clinical changes
BigSimmo Oct 15, 2026
0559cdd
Record hosted worker acceptance and final Answer refusal
BigSimmo Oct 15, 2026
837b935
Recover source-supported summary framing and optional sections
BigSimmo Oct 15, 2026
00c0880
Extract reviewed RAG helpers within unchanged maintainability budgets
BigSimmo Oct 15, 2026
fa6307c
Normalize extracted helper formatting and drop unused import
BigSimmo Oct 15, 2026
0d4a738
Preserve current main safety corrections in ingestion rollout
BigSimmo Oct 15, 2026
3bb8baa
Refresh repository inventory for final ingestion records
BigSimmo Oct 15, 2026
d22345d
Record accepted hosted Answer and actual clipboard with cleanup evidence
BigSimmo Oct 15, 2026
1dee9a1
Use shared polite announcements for administrator pilot status
BigSimmo Oct 15, 2026
2e69952
Merge remote-tracking branch 'origin/main' into codex/ingestion-rag-p…
BigSimmo Oct 15, 2026
f3773e9
fix: retain bounded OCR detail for numerical tables
BigSimmo Oct 15, 2026
cb59830
docs: record aligned ingestion and bounded OCR acceptance
BigSimmo Oct 15, 2026
3839b3a
Merge branch 'main' into codex/ingestion-rag-pilot-handover-20261014
BigSimmo Oct 15, 2026
21804fd
fix(edge): use ts-ignore for Deno .ts import suppressions
claude Oct 15, 2026
8373fdb
fix: Admit headed single-column tables
qodo-code-review[bot] Oct 15, 2026
caaa6b5
fix: Restore compatible document index reset
qodo-code-review[bot] Oct 15, 2026
27dd059
fix: 2 findings — Treat invalid pilot tickets as inactive; Scope pilot i
qodo-code-review[bot] Oct 15, 2026
f5ce178
fix: Accept sources without mandatory layouts
qodo-code-review[bot] Oct 15, 2026
1afd91f
fix: Reject conflicting procedure evidence
qodo-code-review[bot] Oct 15, 2026
9b6b745
fix: Preserve PDF extraction without provenance
qodo-code-review[bot] Oct 15, 2026
db6ce97
fix: Gate alcohol summary rendering
qodo-code-review[bot] Oct 15, 2026
809fb9f
fix: Force nonpersistent pilot responses
qodo-code-review[bot] Oct 15, 2026
0d04325
fix: Log upload cleanup ownership details
qodo-code-review[bot] Oct 15, 2026
fbb9d1a
wip(ingestion-review): fenced reset/deep-memory migration, pilot tick…
claude Oct 15, 2026
44c2af3
test: finish test updates for PR 3546 contract changes
claude Oct 15, 2026
8c759ef
Merge PR 3546 head; keep stricter pilot fallback, undo inverted sourc…
claude Oct 15, 2026
a9c6ab6
fix: undo bot change that let sparse labelled frames count as tables …
claude Oct 15, 2026
549001a
fix: drop bot's whole-chunk negation filter, match 'guidelines', stab…
claude Oct 15, 2026
e9be43c
Merge remote-tracking branch 'origin/main' into claude/ingestion-revi…
claude Oct 15, 2026
334c58b
fix(answer-pilot): refuse scope-, query- and unreadable-ticket matche…
claude Oct 15, 2026
caaaea2
fix(ingestion-sql): null-safe staging ownership and allow extraction_…
claude Oct 15, 2026
2ecbd89
Merge main into PR 3546 branch (resolve migration seal, schema and dr…
claude Oct 15, 2026
2d05bf0
fix: refuse unrestricted document scope when pilot ticket is unusable
gitar-bot Oct 15, 2026
d8d1200
Apply owner decisions on PR 3546 review items
claude Oct 15, 2026
6948557
Merge remote-tracking branch 'origin/codex/ingestion-rag-pilot-handov…
claude Oct 15, 2026
54fdcd6
Judge an All-documents Answer on owner and query when the pilot ticke…
claude Oct 15, 2026
4ba1aad
Queue the import-cycle follow-up through the ledger inbox instead of …
claude Oct 16, 2026
6f54b26
Merge main into PR 3546 branch (seal order and drift manifest after t…
claude Oct 16, 2026
81586a4
Regenerate drift manifest after main merge
claude Oct 16, 2026
578c15d
Keep rag.ts within its line budget
claude Oct 16, 2026
a41e832
Refresh the repo-awareness snapshot
claude Oct 16, 2026
fbacd5d
Merge branch 'main' into codex/ingestion-rag-pilot-handover-20261014
BigSimmo Oct 16, 2026
0d77c26
Drop organisation-map entries that main now places elsewhere
claude Oct 16, 2026
7a0604f
Port Codex f04 fixes: optional TXT layout and fenced bad-row failure
claude Oct 16, 2026
3b797b7
Queue the Codex held-items follow-up through the ledger inbox
claude Oct 16, 2026
afb7f38
Keep the fuller receipt when the same row is observed twice
claude Oct 16, 2026
026f8de
Merge remote-tracking branch 'origin/main' into claude/ingestion-revi…
claude Oct 16, 2026
96b3e0d
Break the two runtime import loops inside PR 3546
claude Oct 16, 2026
e06d43f
Merge remote-tracking branch 'origin/main' into claude/ingestion-revi…
claude Oct 16, 2026
bf88090
Place the receipt-merge test in the answer-engine area
claude Oct 16, 2026
b71c850
Merge remote-tracking branch 'origin/main' into claude/ingestion-revi…
claude Oct 16, 2026
29047e5
Import PyMuPDF by its current name in the table-extraction test
claude Oct 16, 2026
c4cfac3
Move the published-original layout loader out of rag.ts
claude Oct 16, 2026
d712a15
fix: Complete image-free native PDF ingestion
qodo-code-review[bot] Oct 16, 2026
7d5ea74
fix: Reject unsupported backend document admissions
qodo-code-review[bot] Oct 16, 2026
d2082f3
Revert "fix: Reject unsupported backend document admissions"
claude Oct 16, 2026
cc21aa0
Revert "fix: Complete image-free native PDF ingestion"
claude Oct 16, 2026
10c7b1d
Let a confirmed database rejection reach fail-or-retry
claude Oct 16, 2026
3cfad38
Merge main (open shifts follow-up) into the ingestion PR
claude Oct 16, 2026
88835ed
Address CodeRabbit's quick fixes on the ingestion PR
claude Oct 16, 2026
1263ccd
Limit the deep-memory supersede delete to deep-memory rows
claude Oct 16, 2026
f59c5d6
Queue the CodeRabbit items held out of PR 3546
claude Oct 16, 2026
67d98d7
Update a source-shape test and a doc anchor after the merge
claude Oct 16, 2026
b8d1b38
Refresh the drift manifest fingerprint and retry transient database r…
claude Oct 16, 2026
5124c29
Compute the route orphan scan once per mode in the reachability test
claude Oct 16, 2026
6668b99
Treat statement_completion_unknown (40003) as an uncertain outcome
claude Oct 16, 2026
ad07275
Remove legacy deep-memory rows stamped with the committed generation
claude Oct 16, 2026
54f8559
Widen the foreign-section guard to match the legacy deep-memory deletes
claude Oct 16, 2026
6afd8bc
Test the admitted-passage delivery gap on the answer path
claude Oct 16, 2026
ebbee0c
Pin the exact facet delivery gap in the admitted-passage test
claude Oct 16, 2026
af22e72
Merge remote-tracking branch 'origin/main' into claude/ingestion-revi…
claude Oct 16, 2026
445d952
Queue the two PR 3546 database follow-ups in the ledger inbox
claude Oct 16, 2026
f3a6798
Remove the collided upload copy once the recovery sibling is admitted
claude Oct 16, 2026
0865143
Refresh the repo-awareness snapshot for the new decision record
claude Oct 16, 2026
16c0b22
Say the ingestion check samples only the 25 oldest open jobs
claude Oct 16, 2026
580aa95
Bound and explain superseded upload cleanup failures
claude Oct 16, 2026
8cdf07e
Say queue recovery also applies on --yes or an interactive confirm
claude Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions data/repo-awareness-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -2454,6 +2454,11 @@
"section": "decisions",
"catalogued": true
},
{
"path": "docs/decisions/2026-10-16-stuck-final-attempt-uses-existing-recovery.md",
"section": "decisions",
"catalogued": true
},
{
"path": "docs/developer-area-access.md",
"section": "root",
Expand Down Expand Up @@ -23693,6 +23698,14 @@
"outcome": "P2 findings confirmed: complete review corpus omitted legacy/archive rows; fallback UI counts disagreed with rendered groups. Smallest fixes applied; no additional P0-P2 findings in changed scope.",
"checks": "Hosted failure root cause: stale review_state snapshot; focused Vitest first attempt blocked by repository coordinator capacity; local snapshot gate reproduced expected review_state drift."
},
{
"date": "2026-10-16",
"ref": "fix/adversarial-remediation-20261016",
"head": "d5775ec60c00faff2b1a2485c4ee84f53b915a56",
"scope": "Adversarial assessment + parallel fix swarm + post-fix adversarial review across calculators, handover privacy, teaching QR/attendance, EPA magic links, and roster swaps (zero RAG diff)",
"outcome": "All P0/P1/P2 findings fixed and verified; zero RAG files touched",
"checks": "typecheck (10171 files), eslint --max-warnings=0 (33 code files), check:diff-integrity, check:forms-review-sheet, check:source-acquisitions, vitest (14 suites, 344/344 passed)"
},
{
"date": "2026-07-31",
"ref": "codex/moderate-batch-20260730",
Expand Down Expand Up @@ -24957,6 +24970,14 @@
"outcome": "merged origin/main; resolved outstanding-issues against #1508 IDs; kept pre-snapshot wording",
"checks": "check:outstanding-issues,docs:check-links"
},
{
"date": "2026-10-16",
"ref": "feat/backlog-remediation-20261016",
"head": "e526f8a4d5ad00ad05c5b780262b84a5e347938c",
"scope": "prlanded",
"outcome": "PR #3571 squash-merged cleanly into main (e526f8a4d5ad00ad05c5b780262b84a5e347938c); two-dot tree diff against pushed head 7c00d1f35e960dc9ca92f4d6c4d50ccd1242724e is empty.",
"checks": "gh pr view 3571 (MERGED), git rev-list --parents -n 1 e526f8a4d5ad00ad05c5b780262b84a5e347938c (1 parent 24eeea365e782c651047eebf0ecbe9db87e4fd07), git diff --stat e526f8a4d5ad00ad05c5b780262b84a5e347938c 7c00d1f35e960dc9ca92f4d6c4d50ccd1242724e (empty)"
},
{
"date": "2026-07-17",
"ref": "main (origin/main)",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Decision: An upload stuck on its final attempt is cleared by the existing recovery, not a new database fix

- **Status:** decided 2026-10-16
- **Source:** `docs/ingestion-state-machine.md`, find "The owner decided on 2026-10-16 not to add"

An ingestion job whose last attempt ends with an uncertain outcome stays in processing, because the claim step skips jobs that have used all their attempts. The owner chose not to add a database change for this. The 6-hourly ingestion check flags the job when it is among the 25 oldest open jobs, and the existing queue recovery tool resets it. That tool applies at most 20 fixes per run by default, so with a larger backlog it is rerun or given a higher limit.

If this summary and the source ever differ, the source wins.
10 changes: 10 additions & 0 deletions docs/ingestion-state-machine.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,16 @@ was no lease heartbeat at the time of this snapshot, every worker window below a
**Worker (W1)**

- C1: crash after claim → job `processing` until stale reclaim; attempt burned.
- C1a (2026-10-16): on a job's final attempt, an uncertain outcome (a crash, a lost
connection, or SQLSTATE 40003) leaves the job `processing` with no stale reclaim, because
`claim_ingestion_jobs` skips jobs at `max_attempts`. The owner decided on 2026-10-16 not to add
an automatic database recovery for this. The 6-hourly ingestion autopilot reads only the 25
oldest open jobs (`scripts/reindex-health.ts`) and flags a `processing` job among them locked for
more than 30 minutes. A stuck job behind a larger backlog is therefore flagged only once the
older jobs ahead of it clear. Queue recovery (T16) reads every open job but applies at most
`--limit` actions per run (default 20), and changes nothing until confirmed (interactively, or
by `--apply` or `--yes`). With a larger backlog, rerun it or raise `--limit` until the job is
reset.
- C2 (non-atomic only): crash after reset → document has zero index rows and
`D:processing` until reclaim. Steady-state docs are safe (atomic path skips
T3) — but see R15 for how the retry route re-opens this for indexed docs.
Expand Down
59 changes: 59 additions & 0 deletions src/app/api/upload/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
assertTrustedDocumentStoragePath,
createTrustedDocumentAdmission,
dispatchTrustedDocumentAdmission,
releaseSupersededDocumentObject,
TrustedDocumentAdmissionDispatchError,
TrustedDocumentStorageUploadError,
trustedAdmissionDocumentId,
Expand Down Expand Up @@ -172,6 +173,48 @@ async function duplicateUploadResponse(args: {
});
}

// Each cleanup call gets a short deadline so a committed upload is not held open by storage or
// ledger stalls (about 10 s worst case); a timed-out removal falls back to the ledger.
const SUPERSEDED_RELEASE_TIMEOUT_MS = 5_000;

async function releaseSupersededUpload(args: {
ownerId: string;
documentId: string;
supersededPath: string | null;
committedPath: string;
}) {
if (!args.supersededPath) return;
const supersededPath = args.supersededPath;
const supabase = createAdminClient({ timeoutMs: SUPERSEDED_RELEASE_TIMEOUT_MS });
// The admission is already durable, so a failure here is logged and never fails the upload.
const release = await releaseSupersededDocumentObject({
remove: (paths) => supabase.storage.from(env.SUPABASE_DOCUMENT_BUCKET).remove(paths),
queueCleanup: (path) =>
supabase.from("storage_cleanup_jobs").insert({
document_bucket: env.SUPABASE_DOCUMENT_BUCKET,
document_paths: [path],
owner_id: args.ownerId,
status: "pending",
image_bucket: env.SUPABASE_IMAGE_BUCKET,
image_paths: [],
}),
ownerId: args.ownerId,
documentId: args.documentId,
supersededPath,
committedPath: args.committedPath,
}).catch((error: unknown) => ({
outcome: "unrecorded" as const,
failures: [error instanceof Error ? error.message : "release failed"],
}));
if (release.outcome === "unrecorded") {
logger.error("Superseded upload object cleanup failed; object requires manual reconciliation", {
storagePath: supersededPath,
ownerId: args.ownerId,
failures: release.failures,
});
}
}

export async function POST(request: Request) {
let supabase: ReturnType<typeof createAdminClient> | null = null;
let uploadedPath: string | null = null;
Expand Down Expand Up @@ -411,6 +454,7 @@ export async function POST(request: Request) {
return publicErrorResponse(`Upload is paused. ${health.message}`, 503, { code: "upload_unavailable" });

assertUploadNotAborted(request);
const intendedStoragePath = admissionStoragePath;
let storageUpload;
try {
storageUpload = await uploadTrustedDocumentBytes({
Expand All @@ -432,6 +476,9 @@ export async function POST(request: Request) {
throw storageError;
}
uploadedPath = storageUpload.storagePath;
// A collision left an identical object at the intended path; once this request's admission
// commits on the recovery sibling, that object is referenced by nothing.
const supersededStoragePath = storageUpload.collisionRecovered ? intendedStoragePath : null;
if (storageUpload.storagePath !== admissionStoragePath) {
admissionStoragePath = storageUpload.storagePath;
documentPayload = { ...documentPayload, storage_path: admissionStoragePath };
Expand Down Expand Up @@ -475,6 +522,12 @@ export async function POST(request: Request) {
resourceId: documentId,
metadata: { fileType: file.type, fileSize: file.size },
});
await releaseSupersededUpload({
ownerId: uploadOwnerId,
documentId,
supersededPath: supersededStoragePath,
committedPath: admissionStoragePath,
});
return NextResponse.json({ document: recovered.document, job: recovered.job }, { status: 201 });
}
} catch {
Expand Down Expand Up @@ -583,6 +636,12 @@ export async function POST(request: Request) {
// record, not in the durable audit trail.
metadata: { fileType: file.type, fileSize: file.size },
});
await releaseSupersededUpload({
ownerId: uploadOwnerId,
documentId,
supersededPath: supersededStoragePath,
committedPath: admissionStoragePath,
});

return NextResponse.json({ document, job }, { status: 201 });
} catch (error) {
Expand Down
47 changes: 47 additions & 0 deletions src/lib/trusted-document-admission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,53 @@ export async function uploadTrustedDocumentBytes(
return Object.freeze({ storagePath: recoveryPath, collisionRecovered: true });
}

type SupersededObjectRelease = Readonly<{
outcome: "skipped" | "removed" | "queued" | "unrecorded";
failures: readonly string[];
}>;

function releaseFailureMessage(step: string, error: unknown): string {
const message = error instanceof Error ? error.message : isRecord(error) ? String(error.message ?? "") : "";
return `${step}: ${message.slice(0, 200) || "unknown error"}`;
}

/**
* After this request's own admission commits on a recovery sibling, the collided object at the
* intended path is referenced by nothing: the document id is fixed by the correlation id, so no
* other admission for it can commit any more. Remove it, or queue it on the cleanup ledger.
* Never call this before the admission is durable, or for a path the committed row still uses.
*/
export async function releaseSupersededDocumentObject(
args: Readonly<{
remove(paths: string[]): PromiseLike<{ error: { message: string } | null }>;
queueCleanup(path: string): PromiseLike<{ error: { message: string } | null }>;
ownerId: string;
documentId: string;
supersededPath: string;
committedPath: string;
}>,
): Promise<SupersededObjectRelease> {
const supersededPath = assertTrustedDocumentStoragePath(args.ownerId, args.documentId, args.supersededPath);
const committedPath = assertTrustedDocumentStoragePath(args.ownerId, args.documentId, args.committedPath);
if (supersededPath === committedPath) return { outcome: "skipped", failures: [] };
const failures: string[] = [];
try {
const { error } = await args.remove([supersededPath]);
if (!error) return { outcome: "removed", failures };
failures.push(releaseFailureMessage("remove", error));
} catch (error) {
failures.push(releaseFailureMessage("remove", error));
}
try {
const { error } = await args.queueCleanup(supersededPath);
if (!error) return { outcome: "queued", failures };
failures.push(releaseFailureMessage("queue", error));
} catch (error) {
failures.push(releaseFailureMessage("queue", error));
}
return { outcome: "unrecorded", failures };
}

function isRecord(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
Expand Down
72 changes: 72 additions & 0 deletions tests/trusted-document-admission.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { describe, expect, it, vi } from "vitest";
import {
assertTrustedAdministratorAssurance,
createTrustedDocumentAdmission,
releaseSupersededDocumentObject,
dispatchTrustedDocumentAdmission,
toTrustedDocumentAdmissionRpcPayload,
TrustedDocumentAdmissionDispatchError,
Expand Down Expand Up @@ -526,3 +527,74 @@ describe("trusted document Storage upload recovery", () => {
expect(download).not.toHaveBeenCalled();
});
});

describe("superseded collision object release", () => {
const intended = `${administratorId}/documents/${documentId}/guideline.pdf`;
const recovery = `${administratorId}/documents/${documentId}/recovery-cccccccc-cccc-4ccc-8ccc-cccccccccccc-guideline.pdf`;
const ok: { error: null } = { error: null };
const failed = { error: { message: "storage unavailable" } };
type StorageResult = { error: { message: string } | null };
const release = (
remove: (paths: string[]) => PromiseLike<StorageResult>,
queueCleanup: (path: string) => PromiseLike<StorageResult>,
supersededPath = intended,
) =>
releaseSupersededDocumentObject({
remove,
queueCleanup,
ownerId: administratorId,
documentId,
supersededPath,
committedPath: recovery,
});

it("removes the collided object once the recovery sibling is committed", async () => {
const remove = vi.fn(async () => ok);
const queueCleanup = vi.fn();
await expect(release(remove, queueCleanup)).resolves.toEqual({ outcome: "removed", failures: [] });
expect(remove).toHaveBeenCalledWith([intended]);
expect(queueCleanup).not.toHaveBeenCalled();
});

it("queues the object on the cleanup ledger when removal fails or throws", async () => {
for (const remove of [vi.fn(async () => failed), vi.fn(async () => Promise.reject(new Error("network")))]) {
const queueCleanup = vi.fn(async () => ok);
await expect(release(remove, queueCleanup)).resolves.toMatchObject({ outcome: "queued" });
expect(queueCleanup).toHaveBeenCalledWith(intended);
}
});

it("reports an unrecorded object, with both failure reasons, when removal and the ledger fail", async () => {
await expect(
release(
vi.fn(async () => failed),
vi.fn(async () => failed),
),
).resolves.toEqual({
outcome: "unrecorded",
failures: ["remove: storage unavailable", "queue: storage unavailable"],
});
await expect(
release(
vi.fn(async () => failed),
vi.fn(async () => Promise.reject(new Error("db"))),
),
).resolves.toEqual({ outcome: "unrecorded", failures: ["remove: storage unavailable", "queue: db"] });
});

it("never touches the path the committed document still uses", async () => {
const remove = vi.fn();
const queueCleanup = vi.fn();
await expect(release(remove, queueCleanup, recovery)).resolves.toEqual({ outcome: "skipped", failures: [] });
expect(remove).not.toHaveBeenCalled();
expect(queueCleanup).not.toHaveBeenCalled();
});

it("refuses a path outside this document's own storage prefix", async () => {
const remove = vi.fn();
await expect(
release(remove, vi.fn(), `${administratorId}/documents/dddddddd-dddd-4ddd-8ddd-dddddddddddd/guideline.pdf`),
).rejects.toThrow();
expect(remove).not.toHaveBeenCalled();
});
});
18 changes: 18 additions & 0 deletions tests/upload-duplicate-cleanup-ledger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,21 @@ describe("duplicate upload cleanup ledger", () => {
expect(uploadRoute).toMatch(/if \(cleanupLedgerError\) \{[\s\S]*throw new Error\(/);
});
});

describe("superseded collision object cleanup", () => {
it("releases the collided intended-path object only after this request's admission is durable", () => {
const calls = [...uploadRoute.matchAll(/await releaseSupersededUpload\(/g)].map((match) => match.index ?? -1);
expect(calls).toHaveLength(2);
for (const call of calls) {
const durable = uploadRoute.lastIndexOf("durableAdmission = true;", call);
expect(durable, "durable admission precedes the release").toBeGreaterThan(-1);
expect(uploadRoute.slice(durable, call)).not.toContain("catch");
}
expect(uploadRoute).toContain("storageUpload.collisionRecovered ? intendedStoragePath : null");
for (const call of calls) {
const callArgs = uploadRoute.slice(call, uploadRoute.indexOf("});", call));
expect(callArgs).toContain("supersededPath: supersededStoragePath,");
expect(callArgs).toContain("committedPath: admissionStoragePath,");
}
});
});
Loading