Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/lucky-jars-refactor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hashintel/petrinaut": patch
---

Split the optimizations provider's reconnect policy, transport-error handling, and stored-run bookkeeping into their own modules, and turn the attach loop's failure handling into one pure decision function. No behavioural change.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* The detached runs this tab may re-attach to after a reload, recorded in
* sessionStorage as a JSON object mapping run id to its manifest and creation
* time. Session-scoped on purpose β€” a run belongs to the tab that started it.
*
* When storage is unavailable (e.g. Petrinaut runs in a sandboxed iframe with
* an opaque origin) every helper degrades to a no-op: reload re-attachment is
* lost, while in-page reconnection keeps working.
*/

import type { PetrinautOptimizationInput } from "@hashintel/petrinaut-core";

export const ACTIVE_RUNS_STORAGE_KEY = "petrinaut:active-optimization-runs";

export type StoredActiveRun = { input: unknown; createdAt: number };

export const readStoredActiveRuns = (): Record<string, StoredActiveRun> => {
try {
const raw = sessionStorage.getItem(ACTIVE_RUNS_STORAGE_KEY);
if (!raw) {
return {};
}
const parsed: unknown = JSON.parse(raw);
if (
typeof parsed !== "object" ||
parsed === null ||
Array.isArray(parsed)
) {
return {};
}
const runs: Record<string, StoredActiveRun> = {};
for (const [runId, value] of Object.entries(parsed)) {
if (typeof value === "object" && value !== null && "input" in value) {
const createdAt = (value as { createdAt?: unknown }).createdAt;
runs[runId] = {
input: (value as { input: unknown }).input,
createdAt: typeof createdAt === "number" ? createdAt : Date.now(),
};
}
}
return runs;
} catch {
// Unavailable or corrupted storage; see the module comment.
return {};
}
};

const writeStoredActiveRuns = (runs: Record<string, StoredActiveRun>): void => {
try {
sessionStorage.setItem(ACTIVE_RUNS_STORAGE_KEY, JSON.stringify(runs));
} catch {
// Unavailable storage or exceeded quota; see the module comment.
}
};

export const storeActiveRun = (
runId: string,
input: PetrinautOptimizationInput,
): void => {
const runs = readStoredActiveRuns();
runs[runId] = { input, createdAt: Date.now() };
writeStoredActiveRuns(runs);
};

export const removeStoredActiveRun = (runId: string): void => {
const runs = readStoredActiveRuns();
if (runId in runs) {
delete runs[runId];
writeStoredActiveRuns(runs);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { sirModel } from "@hashintel/petrinaut-core/examples";

import { PetrinautOptimizationContext } from "../optimization-context";
import { ACTIVE_RUNS_STORAGE_KEY } from "./active-run-storage";
import {
OptimizationsContext,
type OptimizationsContextValue,
Expand Down Expand Up @@ -414,9 +415,7 @@ describe("OptimizationsProvider", () => {
// does not prove the server acted (some hosts fire-and-forget), so the
// next reload's re-attach settles the run's true fate instead.
expect(cancelledRunIds).toEqual(["run-3"]);
expect(
sessionStorage.getItem("petrinaut:active-optimization-runs"),
).toContain("run-3");
expect(sessionStorage.getItem(ACTIVE_RUNS_STORAGE_KEY)).toContain("run-3");
});

it("lets Remove cancel a possibly-live run after a terminal error", async () => {
Expand Down Expand Up @@ -487,7 +486,7 @@ describe("OptimizationsProvider", () => {

it("re-attaches to stored runs after a reload, rebuilding from a full replay", async () => {
sessionStorage.setItem(
"petrinaut:active-optimization-runs",
ACTIVE_RUNS_STORAGE_KEY,
JSON.stringify({ "run-5": { input, createdAt: 123 } }),
);
const cursors: number[] = [];
Expand Down Expand Up @@ -522,17 +521,15 @@ describe("OptimizationsProvider", () => {
// The best was rebuilt locally from the replayed trial.
expect(optimization.best?.trial).toBe(0);
// The settled run was forgotten so the next reload doesn't re-attach.
expect(sessionStorage.getItem("petrinaut:active-optimization-runs")).toBe(
"{}",
);
expect(sessionStorage.getItem(ACTIVE_RUNS_STORAGE_KEY)).toBe("{}");
});

it("settles a replayed cancellation as cancelled rather than failed", async () => {
// The give-up path cancels a possibly-live run and deliberately keeps its
// stored entry, expecting the next reload to settle it. That replay must
// report Cancelled β€” not a failed run offering Retry.
sessionStorage.setItem(
"petrinaut:active-optimization-runs",
ACTIVE_RUNS_STORAGE_KEY,
JSON.stringify({ "run-6": { input, createdAt: 123 } }),
);
const capability: PetrinautOptimization = {
Expand All @@ -559,14 +556,12 @@ describe("OptimizationsProvider", () => {
expect(optimization.errorCategory).toBeNull();
// The trial applied before the cancellation is still part of the record.
expect(optimization.trials).toHaveLength(1);
expect(sessionStorage.getItem("petrinaut:active-optimization-runs")).toBe(
"{}",
);
expect(sessionStorage.getItem(ACTIVE_RUNS_STORAGE_KEY)).toBe("{}");
});

it("silently drops a stored run the service no longer knows", async () => {
sessionStorage.setItem(
"petrinaut:active-optimization-runs",
ACTIVE_RUNS_STORAGE_KEY,
JSON.stringify({ "run-6": { input, createdAt: 123 } }),
);
const capability: PetrinautOptimization = {
Expand All @@ -583,9 +578,7 @@ describe("OptimizationsProvider", () => {
const getValue = renderProvider(capability);

await waitFor(() => expect(getValue().optimizations).toHaveLength(0));
expect(sessionStorage.getItem("petrinaut:active-optimization-runs")).toBe(
"{}",
);
expect(sessionStorage.getItem(ACTIVE_RUNS_STORAGE_KEY)).toBe("{}");
});

it("treats a retryable NodeAPI error event as a dropped connection and reconnects", async () => {
Expand Down Expand Up @@ -789,7 +782,7 @@ describe("OptimizationsProvider", () => {

it("does not duplicate restored runs under StrictMode double-mounting", async () => {
sessionStorage.setItem(
"petrinaut:active-optimization-runs",
ACTIVE_RUNS_STORAGE_KEY,
JSON.stringify({ "run-12": { input, createdAt: 123 } }),
);
const capability: PetrinautOptimization = {
Expand Down
Loading
Loading