export type OpenClawProductionDrawingManifest = { releaseStatus: string; automatedValidationStatus: string; approvalStatus: string; releaseBlockers: string[]; version: string | null; approvedBy: string | null; fileSha256: string | null; }; const MAX_TEXT_LENGTH = 500; const MAX_BLOCKERS = 50; function readRecord(value: unknown): Record { return value && typeof value === "object" && !Array.isArray(value) ? (value as Record) : {}; } function readText(value: unknown, maxLength = MAX_TEXT_LENGTH) { return typeof value === "string" ? value.trim().slice(0, maxLength) : ""; } function readFirstText(...values: unknown[]) { for (const value of values) { const text = readText(value); if (text) return text; } return null; } export function normalizeOpenClawProductionDrawingManifest( value: unknown ): OpenClawProductionDrawingManifest | null { const raw = readRecord(value); if (Object.keys(raw).length === 0) return null; const release = readRecord(raw.release); const approval = readRecord(raw.approval); const releaseStatus = readText( raw.release_status ?? raw.releaseStatus ?? release.status ).toLowerCase(); const automatedValidationStatus = readText( raw.automated_validation_status ?? raw.automatedValidationStatus ?? raw.validation_status ?? raw.validationStatus ).toLowerCase(); const approvalStatus = readText( raw.approval_status ?? raw.approvalStatus ?? approval.status ).toLowerCase(); if (!releaseStatus && !automatedValidationStatus && !approvalStatus) { return null; } const rawBlockers = raw.release_blockers ?? raw.releaseBlockers ?? release.blockers; const releaseBlockers = (Array.isArray(rawBlockers) ? rawBlockers : []) .slice(0, MAX_BLOCKERS) .map((blocker) => { if (typeof blocker === "string") return readText(blocker); const record = readRecord(blocker); return readText( record.message ?? record.reason ?? record.label ?? record.code ); }) .filter(Boolean); return { releaseStatus, automatedValidationStatus, approvalStatus, releaseBlockers, version: readFirstText( raw.version, raw.release_version, raw.releaseVersion, raw.revision, release.version ), approvedBy: readFirstText( raw.approved_by, raw.approvedBy, raw.approver, raw.released_by, raw.releasedBy, approval.approved_by, approval.approvedBy, approval.approver, release.approved_by, release.approvedBy ), fileSha256: readFirstText( raw.file_sha256, raw.fileSha256, raw.sha256, raw.release_sha256, raw.releaseSha256, release.file_sha256, release.fileSha256, release.sha256 ), }; } export function isOpenClawProductionDrawingReleased( manifest: OpenClawProductionDrawingManifest | null ) { return manifest?.releaseStatus === "production_released"; }