openclaw/scripts/full-release-validation-policy.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

191 lines
6.7 KiB
TypeScript

export const MAX_RELEASE_ARTIFACT_BYTES: number;
export const WINDOWS_NODE_CI_ADVISORY: {
readonly id: "windows-node-ci";
readonly child: "normalCi";
readonly jobNamePattern: RegExp;
readonly aggregateJob: "checks-windows";
};
interface ReleaseAdvisoryJobBase {
child: "normalCi";
job: string;
conclusion: string;
runId: string;
url: string;
}
export type ReleaseAdvisoryJob = ReleaseAdvisoryJobBase &
(
| { class: "windows-node-ci" }
| {
class: "recorded-flake";
jobId: string;
trackingUrl: string;
reason: string;
receiptRunId: string;
}
);
export function releaseChildClassificationEvidence(child: ReleaseRecord): ReleaseRecord;
export function releaseAdvisoryJobs(children: ReleaseRecord[]): ReleaseAdvisoryJob[];
export function validateReleaseManifestAdvisoryJobs(manifest: unknown): ReleaseAdvisoryJob[];
export const SPLIT_CHANGELOG_EVIDENCE_REUSE_POLICY: "split-changelog-release-v1";
export function isSplitChangelogEvidenceDelta(paths: unknown, version: unknown): boolean;
export function classifyReleaseChangelogEvidenceComparison(
comparison: unknown,
identity: { baseSha: string; version?: unknown },
): { changedPaths: string[]; policy: string };
export function serializeReleaseArtifact(payload: unknown): string;
export function buildReleaseValidationManifest(input: {
plan: ReleaseRecord;
drain?: ReleaseRecord;
context: ReleaseRecord;
}): ReleaseRecord;
export function assertReleasePublicationKnownBudget(
plan: ReleaseRecord,
context: ReleaseRecord,
): void;
export function normalizeReleaseCoveragePolicy(
input: ReleaseRecord,
): "npm-beta-v1" | "npm-stable-v1" | undefined;
export function validateReleaseCoveragePolicyBinding(
plan: ReleaseRecord | undefined,
validationInputs?: ReleaseRecord,
): void;
export function normalizeReleaseTelegramWaiver(input: ReleaseRecord): string;
export function releaseWaivedIntegrationChannels(input: ReleaseRecord): string[];
export function validateReleaseTelegramWaiverBinding(
plan: ReleaseRecord | undefined,
validationInputs?: ReleaseRecord,
): void;
export interface ReleaseRecord {
[key: string]: unknown;
}
export interface ReleaseChild extends ReleaseRecord {
key: string;
runAttempt: number | null;
runId: string;
}
export interface ReleaseExecutionPlan extends ReleaseRecord {
sha256: string;
sourceAdmissionContract?: "1";
sourceAdmission?: import("./full-release-publication-contract.mjs").PublicationSourceFact | null;
publicationAdmissionContract?: "1";
publicationAdmission?:
| import("./full-release-publication-contract.mjs").PublicationAdmission
| null;
children: ReleaseChild[];
evidenceReuse: ReleaseRecord;
gates: ReleaseRecord[];
}
export interface ReleaseStateArtifact extends ReleaseRecord {
blockers: ReleaseRecord[];
children: Record<string, ReleaseRecord>;
errors: ReleaseRecord[];
parentRunAttempt: number;
sourceParentRunAttempt: number;
state: string;
}
export interface ReleaseChildSpec {
dispatchName: string;
displayName: string;
key: string;
parentJobName: string;
rerunGroups: string[];
suffix: string;
workflow: string;
}
export type ReleaseGhTransportErrorClass = "ambiguous" | "hard" | "transient";
export function classifyReleaseGhTransportError(error: unknown): ReleaseGhTransportErrorClass;
export function isReleaseGhArtifactMissingError(error: unknown): boolean;
export function releaseChildSpec(key: string): ReleaseChildSpec;
export function releaseChildSpecs(): ReleaseChildSpec[];
export function planReleaseChildRerun(input: {
childKey: string;
jobs: ReleaseRecord[];
}):
| { failed: string[]; mode: "failed-jobs" }
| { failed: string[]; mode: "producer"; producer: string };
export function validateReleaseChildRunProvenance(
run: ReleaseRecord,
expected?: ReleaseRecord,
): {
dispatchActor: string;
effectiveRunAttempt: number;
repository: string;
triggeringActor: string;
};
export function validateReleaseChildDispatchBinding(input: ReleaseRecord): void;
export function buildReleaseExecutionPlan(input: ReleaseRecord): {
children: ReleaseChild[];
gates: ReleaseRecord[];
};
export function buildReleaseExecutionPlanArtifact(input: ReleaseRecord): ReleaseExecutionPlan;
export function validateReleaseExecutionPlanArtifact(
payload: unknown,
expected?: Record<string, unknown>,
): ReleaseExecutionPlan;
export function releaseExecutionPlanSha256(plan: ReleaseRecord): string;
export function releaseCompositeJobsSha256(value: ReleaseRecord): string;
export function compareReleaseJobsByName(left: { name: string }, right: { name: string }): number;
export function composeReleaseAttemptJobs(
attempts: Array<{ jobs: ReleaseRecord[]; runAttempt: number }>,
expected: { effectiveRunAttempt: number; plannedRunAttempt: number },
): {
effectiveRunAttempt: number;
jobs: ReleaseRecord[];
plannedRunAttempt: number;
sha256: string;
};
export function composeReleaseChildAttemptEvidence(input: {
attempts: Array<{ jobs: ReleaseRecord[]; runAttempt: number }>;
expected: ReleaseRecord;
run: ReleaseRecord;
}): ReleaseRecord;
export function terminalPolicyPass(child: ReleaseRecord): boolean;
export function classifyReleaseSnapshot(input: ReleaseRecord): ReleaseStateArtifact;
export function releasePlanGateFailures(gates: ReleaseRecord[]): ReleaseRecord[];
export function buildReleaseStateArtifact(input: ReleaseRecord): ReleaseStateArtifact;
export function validateReleaseStateArtifact(
payload: unknown,
expected?: Record<string, unknown>,
expectedMode?: string,
): ReleaseStateArtifact;
export function validateRetiredReleaseRetryFields(value: ReleaseRecord): void;
export function verifyReleaseStateArtifacts(
executionPlanPayload: unknown,
decisionPayload: unknown,
drainPayload: unknown,
expected?: Record<string, unknown>,
): {
decision: ReleaseStateArtifact;
drain: ReleaseStateArtifact;
executionPlan: ReleaseExecutionPlan;
sourceAttempts: {
decision: number;
drain: number;
executionPlan: number;
};
};
export function selectReleaseStateArtifacts(
executionPlanPayload: unknown,
decisionCandidates: Array<{ name: string; payload: unknown }>,
drainCandidates: Array<{ name: string; payload: unknown }>,
expected?: Record<string, unknown>,
): {
decision: ReleaseStateArtifact;
drain: ReleaseStateArtifact;
executionPlan: ReleaseExecutionPlan;
sourceAttempts: {
decision: number;
drain: number;
executionPlan: number;
};
};
export function formatReleaseStateOutcome(payload: ReleaseRecord): string;
export function releaseStateChildEvidence(child: ReleaseRecord): ReleaseRecord;
export function affectedActiveRunIds(
children: ReleaseRecord[],
blockers: ReleaseRecord[],
cancelledRunIds?: Set<string>,
): string[];