openclaw/scripts/full-release-flake-classification.d.mts
Peter Steinberger f34c2a21db
feat(release): let a release lead record an exact-job flake instead of blocking publication (#161515)
* feat(release): accept exact-job recorded flakes in release validation

A release lead can classify one failed Normal CI job of a Full Release
Validation run as a flake through the trusted classification workflow. The
receipt binds the exact job id and attempt, CI child run, FRV parent run and
attempt, and Release SHA, and carries a tracking issue or PR plus a reason.
Release Decision, the manifest, the publisher's live re-derivation, the step
summary, and the GitHub release notes tail treat it as a visible advisory.
Required classes and every other child stay blocking.

* docs(release): fold recorded flakes into the shared release boundaries

* fix(release): scope flake receipt discovery to the CI child run

* fix(release): require main lineage for flake receipt producers

* test(release): copy the flake classification module into tooling fixtures

* fix(release): keep advisory-only release notes verifiable
2026-09-30 04:31:07 +00:00

68 lines
2 KiB
TypeScript

export type FlakeClassification = {
schema: "openclaw.frv-flake-classification.v1";
parentRunId: string;
parentRunAttempt: number;
child: "normalCi";
childRunId: string;
childRunAttempt: number;
targetSha: string;
jobId: string;
jobName: string;
jobUrl: string;
conclusion: "failure" | "timed_out";
trackingUrl: string;
reason: string;
classifiedBy: string;
receiptRunId: string;
receiptRunAttempt: number;
};
export type FlakeJob = {
name: string;
status: string;
conclusion: string;
id?: number | string;
html_url?: string;
url?: string;
acceptedRunAttempt?: number;
run_attempt?: number;
};
export type FlakeChild = { key: string; runId: string; jobs: FlakeJob[] };
export type FlakeBinding = {
child?: FlakeChild;
parentRunId?: string;
parentRunAttempt?: number;
targetSha?: string;
};
export type FlakeGateEntry = { name: string; result: string; selected: boolean | string };
export type FlakeEvidence = {
flakeClassifications?: FlakeClassification[];
gateEntries?: FlakeGateEntry[];
};
export type FlakeApi = (
path: string,
options?: { format?: "json" | "text" | "bytes"; maxBytes?: number; signal?: AbortSignal },
) => Promise<unknown>;
export const RECORDED_FLAKE_DENIED_JOB_PATTERNS: readonly RegExp[];
export function isClassifiableFlakeJob(name: unknown): boolean;
export function validateFlakeClassification(
receipt: unknown,
expected?: FlakeBinding,
): FlakeClassification;
export function parseFlakeGateEntries(log: string): FlakeGateEntry[];
export function validateFlakeGateEntries(entries: unknown): FlakeGateEntry[];
export function recordFlakeClassification(options: {
inputs: Record<string, unknown>;
env?: NodeJS.ProcessEnv;
api?: FlakeApi;
}): Promise<FlakeClassification>;
export function loadFlakeClassifications(
options: FlakeBinding & {
repo?: string;
child: FlakeChild;
parentRunId: string;
parentRunAttempt: number;
targetSha: string;
api?: FlakeApi;
signal?: AbortSignal;
},
): Promise<FlakeEvidence>;