mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
fix: carry the retry work onto the new editor pipeline
Rebased onto main after 5a squash-merged, which also brought #7581's rewrite of the upload chain. Where that moved first, this follows it: - The AI escalation decision belongs to the local-pass engine now, so the localPassFailed gate and its store helper go. A pass that produces no verdict leaves the file eligible and a reload retries it, which is #7581's answer to what that gate was for. - uploadChain.ts went the same way: main already orders the chain, as orderedRewritingCategories, and keeps its own nextUploadCategory. The policy retry resumes off main's ordering instead. An annotating policy is no longer in the chain, so a retry of one re-runs just that policy. - aiEnabled was threaded through the retry path only to reach the chain ordering, which no longer takes it, so it goes from all three hooks. - Test fixtures move from sources: ["editor"] to the runsOnEditor flag that replaced it. The unlock hold-back is ported onto main's dispatch loop unchanged.
This commit is contained in:
@@ -811,8 +811,6 @@ describe("retrying an attended policy run", () => {
|
||||
{ policyId: "pol-1", fileId: "f-1" },
|
||||
expect.any(File),
|
||||
"f-unlocked",
|
||||
// No app-config above this render, so the engine reads as off and Classification drops out.
|
||||
false,
|
||||
);
|
||||
// And with the prefixed notification id, never a raw failure id.
|
||||
expect(reportNotificationResolved).toHaveBeenCalledWith("failure:evt-1");
|
||||
@@ -841,7 +839,6 @@ describe("retrying an attended policy run", () => {
|
||||
{ policyId: "pol-1", fileId: "f-1" },
|
||||
expect.any(File),
|
||||
null,
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -459,12 +459,5 @@ export function useNotificationActions(): ClientActionRegistry {
|
||||
VIEW_FILE: viewFile,
|
||||
VIEW_IN_PROCESSOR: viewInProcessor,
|
||||
};
|
||||
}, [
|
||||
canOpenHere,
|
||||
openInWorkbench,
|
||||
fileContext,
|
||||
fileStore,
|
||||
navigate,
|
||||
t,
|
||||
]);
|
||||
}, [canOpenHere, openInWorkbench, fileContext, fileStore, navigate, t]);
|
||||
}
|
||||
|
||||
@@ -84,24 +84,6 @@ describe("policyRunStore", () => {
|
||||
expect(isDispatched("security", "f1")).toBe(true);
|
||||
});
|
||||
|
||||
it("a browser-local run does not claim the (policy, file) dispatch key", () => {
|
||||
// The local classification heuristic records a run for the same (classification, file) pair
|
||||
// the server escalation is keyed on. If that claimed the key, the auto-run would read
|
||||
// "already dispatched" and never ask the AI - which killed escalation entirely.
|
||||
recordRunStart(
|
||||
rec({
|
||||
runId: "local-classification-f1-1",
|
||||
categoryId: "classification",
|
||||
fileId: "f1",
|
||||
target: "local",
|
||||
browserLocal: true,
|
||||
status: "RUNNING",
|
||||
}),
|
||||
);
|
||||
expect(getRun("local-classification-f1-1")).toBeDefined();
|
||||
expect(isDispatched("classification", "f1")).toBe(false);
|
||||
});
|
||||
|
||||
it("a real backend run still claims the dispatch key", () => {
|
||||
recordRunStart(rec({ runId: "srv-1", categoryId: "classification" }));
|
||||
expect(isDispatched("classification", "f1")).toBe(true);
|
||||
|
||||
+1
@@ -23,6 +23,7 @@ vi.mock("@app/hooks/usePolicies", () => ({
|
||||
status: "active",
|
||||
backendId: "backend-sec",
|
||||
runOn: "upload",
|
||||
runsOnEditor: true,
|
||||
order: 0,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -438,6 +438,16 @@ function applyOutputName(
|
||||
: `${base}_${outputName}${ext}`;
|
||||
}
|
||||
|
||||
/** Next upload policy in the chain, or undefined if last or no longer eligible. */
|
||||
function nextUploadCategory(
|
||||
orderedUploadCategories: string[],
|
||||
categoryId: string,
|
||||
): string | undefined {
|
||||
const index = orderedUploadCategories.indexOf(categoryId);
|
||||
if (index < 0) return undefined;
|
||||
return orderedUploadCategories[index + 1];
|
||||
}
|
||||
|
||||
async function reconcileServerRuns(
|
||||
policies: PoliciesByCategory,
|
||||
): Promise<void> {
|
||||
|
||||
@@ -151,7 +151,6 @@ describe("useResolutionContinuation", () => {
|
||||
{ policyId: "pol-1", fileId: "f-locked" },
|
||||
expect.any(File),
|
||||
"f-unlocked",
|
||||
true,
|
||||
);
|
||||
expect(refreshNotificationsNow).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -25,18 +25,13 @@ const RESOLUTION_TOOLS: Record<string, string> = {
|
||||
};
|
||||
|
||||
export function useResolutionContinuation(): (run: SucceededToolRun) => void {
|
||||
return useCallback(
|
||||
(run: SucceededToolRun) => {
|
||||
void continueResolutions(run);
|
||||
},
|
||||
[],
|
||||
);
|
||||
return useCallback((run: SucceededToolRun) => {
|
||||
void continueResolutions(run);
|
||||
}, []);
|
||||
}
|
||||
|
||||
/** Best-effort: a continuation that cannot happen leaves the row where it already was. */
|
||||
async function continueResolutions(
|
||||
run: SucceededToolRun,
|
||||
): Promise<void> {
|
||||
async function continueResolutions(run: SucceededToolRun): Promise<void> {
|
||||
try {
|
||||
if (!(await couldResolveAnything(run))) return;
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ describe("rechainPolicyOnDocument", () => {
|
||||
|
||||
it("submits bytes the caller already holds, still under the original reference", async () => {
|
||||
await expect(
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked", false),
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked"),
|
||||
).resolves.toEqual({
|
||||
ok: true,
|
||||
tracked: true,
|
||||
@@ -146,7 +146,7 @@ describe("rechainPolicyOnDocument", () => {
|
||||
|
||||
it("attributes the run to the adopted document, not the one the failure named", async () => {
|
||||
// Two references: the failure's to the server so a repeat folds on, the adopted one to the store.
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked", false);
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked");
|
||||
|
||||
expect(runStoredPolicy).toHaveBeenCalledWith("pol-1", [unlocked], "f-1");
|
||||
expect(getRun("run-1")).toMatchObject({ fileId: "f-unlocked" });
|
||||
@@ -156,7 +156,7 @@ describe("rechainPolicyOnDocument", () => {
|
||||
it("runs untracked rather than filing the output against the wrong document, and admits it", async () => {
|
||||
// No workspace id, so recording it would version the encrypted original instead.
|
||||
await expect(
|
||||
rechainPolicyOnDocument(target, unlocked, null, false),
|
||||
rechainPolicyOnDocument(target, unlocked, null),
|
||||
).resolves.toEqual({ ok: true, tracked: false });
|
||||
|
||||
expect(runStoredPolicy).toHaveBeenCalled();
|
||||
@@ -169,7 +169,7 @@ describe("rechainPolicyOnDocument", () => {
|
||||
});
|
||||
|
||||
await expect(
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked", false),
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked"),
|
||||
).resolves.toEqual({
|
||||
ok: false,
|
||||
reason: "rejected",
|
||||
@@ -183,7 +183,7 @@ describe("rechainPolicyOnDocument", () => {
|
||||
});
|
||||
|
||||
await expect(
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked", false),
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked"),
|
||||
).resolves.toEqual({
|
||||
ok: false,
|
||||
reason: "rejected",
|
||||
@@ -195,7 +195,7 @@ describe("rechainPolicyOnDocument", () => {
|
||||
runStoredPolicy.mockRejectedValue(new Error("Network Error"));
|
||||
|
||||
await expect(
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked", false),
|
||||
rechainPolicyOnDocument(target, unlocked, "f-unlocked"),
|
||||
).resolves.toEqual({
|
||||
ok: false,
|
||||
reason: "rejected",
|
||||
@@ -215,7 +215,8 @@ describe("rechainPolicyOnDocument rejoining the chain", () => {
|
||||
configured: true,
|
||||
status: "active",
|
||||
runOn: "upload",
|
||||
sources: ["editor"],
|
||||
sources: [],
|
||||
runsOnEditor: true,
|
||||
order,
|
||||
};
|
||||
}
|
||||
@@ -254,7 +255,7 @@ describe("rechainPolicyOnDocument rejoining the chain", () => {
|
||||
};
|
||||
completedRun("run-w", "watermark", "f-upload", "f-1");
|
||||
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked", false);
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked");
|
||||
|
||||
expect(runStoredPolicy).toHaveBeenCalledWith("pol-1", [unlocked], "f-1");
|
||||
});
|
||||
@@ -266,7 +267,7 @@ describe("rechainPolicyOnDocument rejoining the chain", () => {
|
||||
security: uploadPolicy("pol-1", 1),
|
||||
};
|
||||
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked", false);
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked");
|
||||
|
||||
// Filed under the resumed policy's category, so security still runs on watermark's output.
|
||||
expect(runStoredPolicy).toHaveBeenCalledWith("pol-w", [unlocked], "f-1");
|
||||
@@ -283,7 +284,7 @@ describe("rechainPolicyOnDocument rejoining the chain", () => {
|
||||
security: uploadPolicy("pol-1", 1),
|
||||
};
|
||||
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked", false);
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked");
|
||||
|
||||
expect(runStoredPolicy).toHaveBeenCalledWith("pol-1", [unlocked], "f-1");
|
||||
});
|
||||
@@ -295,7 +296,7 @@ describe("rechainPolicyOnDocument rejoining the chain", () => {
|
||||
security: { ...uploadPolicy("pol-1", 1), runOn: "export" },
|
||||
};
|
||||
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked", false);
|
||||
await rechainPolicyOnDocument(target, unlocked, "f-unlocked");
|
||||
|
||||
expect(runStoredPolicy).toHaveBeenCalledWith("pol-1", [unlocked], "f-1");
|
||||
});
|
||||
|
||||
@@ -53,12 +53,7 @@ export async function rechainPolicyOnDocument(
|
||||
document: File,
|
||||
workspaceFileId: string | null,
|
||||
): Promise<PolicyRerunOutcome> {
|
||||
return submit(
|
||||
target,
|
||||
document,
|
||||
workspaceFileId,
|
||||
resumePointFor(target),
|
||||
);
|
||||
return submit(target, document, workspaceFileId, resumePointFor(target));
|
||||
}
|
||||
|
||||
/** Which policy a retry should actually run, and the category to file its run under. */
|
||||
|
||||
Reference in New Issue
Block a user