/** * The issue registry: which six-digit id belongs to which root cause. * * Clustering is deterministic, so the KEY of an issue can always be recomputed * from its findings. The ID cannot: it was drawn at random the first time that * key was seen. This module is the one place that draw happens, and the one * place the mapping is read. * * It lives apart from `backlog/lib.ts` so that module stays pure data and * transitions, and apart from `fix/cluster.ts` so clustering stays a pure * function of findings. Minting is the only operation here that writes. */ import type { Backlog, IssueRecord } from "../backlog/lib.js"; import { type ClusterOptions, type FixCluster } from "../fix/cluster.js"; /** Cluster key to issue id, which is what `clusterFindings` needs. */ export declare function issueIdsByKey(backlog: Backlog): Record; export declare function issueByKey(backlog: Backlog, key: string): IssueRecord | undefined; export declare function issueById(backlog: Backlog, id: string): IssueRecord | undefined; /** * Give every root cause in the backlog an id, and return the ones just minted. * * Idempotent, and deliberately blind to status: a finding adjudicated by-design * years ago still has a folder somebody may open, so it keeps its number. Ids * are never pruned and never reused, so this only ever grows. * * Called from both load and save. On load it repairs a backlog written before * ids existed; on save it covers whatever the merge just added. */ export declare function reconcileIssues(backlog: Backlog, now: string, rng?: () => number): IssueRecord[]; /** Every status an issue can be in and still be worth looking at: all of them. */ export declare const ALL_STATUSES: readonly ["open", "blocked", "fixed", "by-design"]; /** * The backlog's issues, with their ids resolved. Every caller that clusters * goes through here, so nobody has to remember to pass the registry in. */ export declare function issuesOf(backlog: Backlog, opts?: ClusterOptions): FixCluster[]; /** One issue by its six-digit id. */ export declare function findIssue(backlog: Backlog, id: string, opts?: ClusterOptions): FixCluster | undefined; /** What happened when somebody asked to file an issue away, or bring it back. */ export type ArchiveOutcome = { ok: true; record: IssueRecord; reason: "fixed" | "intentional"; } | { ok: false; why: string; }; /** * File an issue away. * * Not a verdict on the defect: lookout reached that already, and nothing here * touches a finding's status. This is a person saying they have seen the * outcome and want it off the board, so the only thing it refuses is archiving * work that is still open. Hiding a live defect is the one failure mode an * archive has, and it is worth one guard even though the button that calls this * is only drawn on settled issues. * * Idempotent: archiving an archived issue is what somebody double-clicking * means, not an error. */ export declare function archiveIssue(backlog: Backlog, id: string, now: string): ArchiveOutcome; /** Put an archived issue back on the board. The undo for the button above. */ export declare function unarchiveIssue(backlog: Backlog, id: string): ArchiveOutcome;