import type { FixCluster } from "../fix/cluster.js"; import type { ResolvedConfig } from "../types.js"; /** Which side of the fix a frame is a picture of. */ export type FrameSide = "before" | "after"; export interface Frame { /** Relative to the issue's folder, e.g. `img/pre/web-app-root--dark.png`. */ path: string; route: string; /** "web", or the device platform. Absent on frames frozen before devices were recorded. */ platform?: string; formFactor: string; scheme: string; state?: string; /** When this frame was frozen. */ at: string; /** * The shot this is a copy of, and the hash of its pixels at freeze time. * What lets a never-ruled issue be verified against the defect as filed * rather than against whatever the workspace holds now. Absent on frames * frozen before these were recorded; both are recovered from the file. */ shotId?: string; hash?: string; } export interface FrameSet { schema: 2; before: Frame[]; after: Frame[]; } /** Where this frame is on disk, wherever the issue's folder is right now. */ export declare function frameAbsPath(resolved: ResolvedConfig, id: string, f: Frame): string; /** * The frame in the two path forms the page needs: `path` relative to the * project's `.lookout/` (which is how the ui's routes serve it, `issues/...` * distinguishing it from a workspace shot), and `absPath` for whoever wants * the file itself. */ export declare function frameServedPath(resolved: ResolvedConfig, id: string, f: Frame): { path: string; absPath: string; }; /** The frames kept for this issue, or an empty set. */ export declare function loadFrames(resolved: ResolvedConfig, id: string): Promise; /** * Freeze this issue's current workspace views as one side of the comparison. * * `before` is written once PER VIEW. A view already frozen keeps the pixels it * was filed against, so an issue re-verified three times still shows the defect * as filed rather than as the last attempt left it; a view the cluster only * gained later is frozen now, at the save that filed the finding on it, which * is that view's own filing moment. Freezing once per ISSUE instead would leave * every later view with no picture at all, and the card draws what is frozen. * * `after` is rewritten whole every time it is taken, because the only thing * worth keeping there is the frame that actually cleared the issue. * * Returns the side as it now stands, which is empty when there was nothing to * copy: a code-channel issue has no screenshots at all, and a frame whose file * has been cleaned out of the workspace cannot be frozen after the fact. */ export declare function freezeFrames(resolved: ResolvedConfig, cluster: FixCluster, side: FrameSide): Promise; /** * The pre-fix frames for this issue, frozen now if nothing has frozen them yet. * * Called from every backlog save, which is what makes "every issue has a * picture of its own defect" a property of the system rather than a thing * `verify-fix` happens to do on its way past. A save runs after the capture the * findings were judged from, so the files it copies are the defect's own * pixels, and it is a no-op from the second save onwards. * * One case is skipped, and only one: an issue that has nothing frozen at all * AND has already spent a fix attempt. That is the retroactive case, an issue * filed before lookout froze anything, and its frames in the workspace are of * unknown vintage, because something has claimed to change that screen since. * Copying them now would file a picture of somebody's fix under a label saying * "the defect". Those issues report no pre-fix frame, which is true, and * `backlog check` lists them. * * An issue that IS frozen keeps taking new views as it gains them, whatever it * has spent, because a view's first frame is the pixels its own finding was * filed against however late in the issue's life that finding arrived. */ export declare function ensureBeforeFrames(resolved: ResolvedConfig, cluster: FixCluster): Promise;