(function (root, factory) {
  "use strict";

  const api = Object.freeze(factory());
  if (typeof module === "object" && module.exports) module.exports = api;
  if (root) root.MbnNamedPlaylistWorkflow = api;
})(typeof globalThis === "object" ? globalThis : this, function () {
  "use strict";

  const SCHEMA_VERSION = 1;
  const MAXIMUM_DEFINITIONS = 1000;
  const MAXIMUM_ITEMS = 1000;
  const MAXIMUM_PAGE_COUNT = 20;
  const MAXIMUM_STORED_PAGE_COUNT = 9999;
  const DEFAULT_MAXIMUM_DEFINITIONS = 200;
  const MAXIMUM_SELECTION_FIELD_LENGTH = 256;
  const MAXIMUM_SUBJECT_FIELD_LENGTH = 4000;
  const MAXIMUM_LIST_TEXT_LENGTH = 4000;
  const identifierPattern = /^[A-Za-z0-9_-]{1,128}$/;
  const programCodePattern = /^[0-9]{8}$/;
  const cutCodePattern = /^[0-9]{1,8}$/;
  const builderKeyPattern = /^s[0-9]+$/;
  const controlCharacterPattern = /[\u0000-\u001f\u007f]/;
  const pagedBuilderByCode = Object.freeze({
    "5074": Object.freeze({ builderKey: "s5074", pageSize: 5 }),
    "5077": Object.freeze({ builderKey: "s5077", pageSize: 6 }),
    "5088": Object.freeze({ builderKey: "s5088", pageSize: 12 })
  });

  const bridgeContract = Object.freeze({
    requests: Object.freeze({
      list: "request-named-playlist-list",
      load: "request-named-playlist-load",
      create: "create-named-playlist",
      replace: "replace-named-playlist",
      delete: "delete-named-playlist"
    }),
    responses: Object.freeze({
      list: "named-playlist-list-results",
      load: "named-playlist-load-results",
      mutation: "named-playlist-mutation-results",
      error: "named-playlist-error"
    }),
    schemaVersion: SCHEMA_VERSION,
    maximumDefinitions: MAXIMUM_DEFINITIONS,
    maximumItems: MAXIMUM_ITEMS,
    maximumPageCount: MAXIMUM_PAGE_COUNT,
    maximumStoredPageCount: MAXIMUM_STORED_PAGE_COUNT
  });

  const pagePlanBridgeContract = Object.freeze({
    request: "request-playlist-page-plans",
    results: "playlist-page-plans-results",
    error: "playlist-page-plans-error",
    pagedBuilderByCode
  });

  const operations = Object.freeze(["list", "load", "create", "replace", "delete"]);
  const operationSet = new Set(operations);

  function isPlainObject(value) {
    if (!value || typeof value !== "object" || Array.isArray(value)) return false;
    const prototype = Object.getPrototypeOf(value);
    return prototype === Object.prototype || prototype === null;
  }

  function hasExactKeys(value, expected) {
    if (!isPlainObject(value)) return false;
    const actual = Object.keys(value).sort();
    const sortedExpected = [...expected].sort();
    return actual.length === sortedExpected.length &&
      actual.every((key, index) => key === sortedExpected[index]);
  }

  function exactText(value, maximumLength, allowEmpty = false, allowCaret = false) {
    if (typeof value !== "string" || value.length > maximumLength ||
        (!allowEmpty && value.length === 0) || value !== value.trim() ||
        controlCharacterPattern.test(value) || (!allowCaret && value.includes("^"))) return null;
    return value;
  }

  function requestId(value) {
    const text = exactText(value, 128);
    return text && identifierPattern.test(text) ? text : null;
  }

  function programCode(value) {
    const text = exactText(value, 8);
    return text && programCodePattern.test(text) ? text : null;
  }

  function isIsoTimestamp(value) {
    return typeof value === "string" && value.length >= 20 && value.length <= 64 &&
      !Number.isNaN(Date.parse(value));
  }

  function createListRequest(requestIdValue, maximumResults = DEFAULT_MAXIMUM_DEFINITIONS) {
    const id = requestId(requestIdValue);
    if (!id) throw new TypeError("A safe named-playlist request id is required.");
    if (!Number.isInteger(maximumResults) || maximumResults < 1 ||
        maximumResults > MAXIMUM_DEFINITIONS) {
      throw new RangeError(`The named-playlist definition limit must be 1 through ${MAXIMUM_DEFINITIONS}.`);
    }
    return Object.freeze({ requestId: id, maximumResults });
  }

  function createLoadRequest(requestIdValue, programCodeValue) {
    const id = requestId(requestIdValue);
    const code = programCode(programCodeValue);
    if (!id || !code) throw new TypeError("A safe request id and eight-digit program code are required.");
    return Object.freeze({ requestId: id, programCode: code });
  }

  function createDefinitionRequest(requestIdValue, programCodeValue, titleValue) {
    const request = createLoadRequest(requestIdValue, programCodeValue);
    const title = exactText(titleValue, 128, false, true);
    if (!title) throw new TypeError("A canonical named-playlist title is required.");
    return Object.freeze({ ...request, title });
  }

  function createDeleteRequest(requestIdValue, programCodeValue) {
    return createLoadRequest(requestIdValue, programCodeValue);
  }

  function parseStoredPageText(value) {
    if (value === "") return null;
    if (typeof value !== "string" || !/^[1-9][0-9]{0,3}\/(?:0|[1-9][0-9]{0,3})$/.test(value)) {
      return null;
    }
    const [currentText, totalText] = value.split("/");
    const currentPage = Number(currentText);
    const totalPages = Number(totalText);
    if (totalPages > MAXIMUM_STORED_PAGE_COUNT ||
        (totalPages === 0 ? currentPage !== 1 : currentPage > totalPages)) return null;
    const isWithinPlayoutBounds = totalPages >= 1 &&
      totalPages <= MAXIMUM_PAGE_COUNT && currentPage <= totalPages;
    return Object.freeze({
      pageText: value,
      currentPage,
      totalPages,
      isWithinPlayoutBounds,
      historicalPageOutOfBounds: !isWithinPlayoutBounds,
      pageRecalculationRequired: true
    });
  }

  function normalizeSelection(value) {
    if (!hasExactKeys(value, ["groupCode", "subject", "graphicType", "subtype", "dataCode"])) {
      return null;
    }
    const groupCode = exactText(value.groupCode, MAXIMUM_SELECTION_FIELD_LENGTH, true);
    const subject = exactText(value.subject, MAXIMUM_SUBJECT_FIELD_LENGTH, true);
    const graphicType = exactText(value.graphicType, MAXIMUM_SELECTION_FIELD_LENGTH, true);
    const subtype = exactText(value.subtype, MAXIMUM_SELECTION_FIELD_LENGTH, true);
    const dataCode = exactText(value.dataCode, MAXIMUM_SELECTION_FIELD_LENGTH, true);
    if ([groupCode, subject, graphicType, subtype, dataCode].some(field => field === null)) return null;
    return Object.freeze({ groupCode, subject, graphicType, subtype, dataCode });
  }

  function normalizePageTextForSave(value) {
    if (value === "") return "";
    const page = parseStoredPageText(value);
    if (!page) throw new RangeError("The stored named-playlist page text is invalid.");
    return page.pageText;
  }

  function toLegacySevenFields(entry, pageTextValue = "1/1") {
    if (!isPlainObject(entry) || typeof entry.enabled !== "boolean") {
      throw new TypeError("A typed playlist entry with an enabled flag is required.");
    }
    const selection = normalizeSelection(entry.selection);
    if (!selection) throw new TypeError("The playlist selection cannot be stored safely.");
    const pageText = normalizePageTextForSave(pageTextValue);
    return Object.freeze([
      entry.enabled ? "1" : "0",
      selection.groupCode,
      selection.subject,
      selection.graphicType,
      selection.subtype,
      pageText,
      selection.dataCode
    ]);
  }

  function legacyListText(fieldsValue) {
    if (!Array.isArray(fieldsValue) || fieldsValue.length !== 7 ||
        fieldsValue.some(field => typeof field !== "string" || field.includes("^") ||
          controlCharacterPattern.test(field)) ||
        !["0", "1"].includes(fieldsValue[0]) ||
        exactText(fieldsValue[1], MAXIMUM_SELECTION_FIELD_LENGTH, true) === null ||
        exactText(fieldsValue[2], MAXIMUM_SUBJECT_FIELD_LENGTH, true) === null ||
        exactText(fieldsValue[3], MAXIMUM_SELECTION_FIELD_LENGTH, true) === null ||
        exactText(fieldsValue[4], MAXIMUM_SELECTION_FIELD_LENGTH, true) === null ||
        exactText(fieldsValue[6], MAXIMUM_SELECTION_FIELD_LENGTH, true) === null ||
        (fieldsValue[5] !== "" && !parseStoredPageText(fieldsValue[5]))) {
      throw new TypeError("Exactly seven safe legacy playlist fields are required.");
    }
    const value = fieldsValue.join("^");
    if (value.length > MAXIMUM_LIST_TEXT_LENGTH) {
      throw new RangeError("The legacy LIST_TEXT value is too long.");
    }
    return value;
  }

  function createReplaceRequest(
    requestIdValue,
    programCodeValue,
    playlistEntries,
    options = {}) {
    const request = createLoadRequest(requestIdValue, programCodeValue);
    if (!Array.isArray(playlistEntries) || playlistEntries.length > MAXIMUM_ITEMS) {
      throw new RangeError(`A named playlist can contain at most ${MAXIMUM_ITEMS} entries.`);
    }
    if (!isPlainObject(options) || typeof options.isTrustedEntry !== "function") {
      throw new TypeError("A trusted-entry verifier is required before database storage.");
    }
    if (options.pageTextForEntry !== undefined && typeof options.pageTextForEntry !== "function") {
      throw new TypeError("pageTextForEntry must be a function when supplied.");
    }
    if (options.fieldsForEntry !== undefined && typeof options.fieldsForEntry !== "function") {
      throw new TypeError("fieldsForEntry must be a function when supplied.");
    }

    const items = playlistEntries.map((entry, itemIndex) => {
      if (options.isTrustedEntry(entry, itemIndex) !== true) {
        throw new TypeError(`Playlist entry ${itemIndex} did not pass trusted restoration.`);
      }
      const pageText = options.pageTextForEntry
        ? options.pageTextForEntry(entry, itemIndex)
        : "1/1";
      const projected = options.fieldsForEntry
        ? options.fieldsForEntry(entry, itemIndex, pageText)
        : undefined;
      const fields = options.fieldsForEntry
        ? projected
        : toLegacySevenFields(entry, pageText);
      if (!Array.isArray(fields) || fields.length !== 7 ||
          fields[0] !== (entry.enabled ? "1" : "0") || fields[5] !== pageText) {
        throw new TypeError(`Playlist entry ${itemIndex} has no exact legacy seven-field projection.`);
      }
      legacyListText(fields);
      return Object.freeze({
        itemIndex,
        enabled: fields[0] === "1",
        groupCode: fields[1],
        subject: fields[2],
        graphicType: fields[3],
        subtype: fields[4],
        pageText: fields[5],
        dataCode: fields[6]
      });
    });
    return Object.freeze({ ...request, items: Object.freeze(items) });
  }

  function normalizeDefinition(value) {
    if (!hasExactKeys(value, ["programCode", "title"])) return null;
    const code = programCode(value.programCode);
    const title = exactText(value.title, 128, false, true);
    return code && title ? Object.freeze({ programCode: code, title }) : null;
  }

  function normalizeListResponse(value) {
    const keys = [
      "requestId", "retrievedAt", "totalRowCount", "truncated",
      "suggestedProgramCode", "canMutate", "writeQuarantined", "definitions"
    ];
    if (!hasExactKeys(value, keys) || !requestId(value.requestId) ||
        !isIsoTimestamp(value.retrievedAt) || !Number.isInteger(value.totalRowCount) ||
        value.totalRowCount < 0 || typeof value.truncated !== "boolean" ||
        !programCode(value.suggestedProgramCode) || typeof value.canMutate !== "boolean" ||
        typeof value.writeQuarantined !== "boolean" || !Array.isArray(value.definitions) ||
        value.definitions.length !== value.totalRowCount ||
        value.definitions.length > MAXIMUM_DEFINITIONS ||
        (value.writeQuarantined && value.canMutate)) return null;
    const definitions = [];
    const codes = new Set();
    for (const raw of value.definitions) {
      const definition = normalizeDefinition(raw);
      if (!definition || codes.has(definition.programCode)) return null;
      codes.add(definition.programCode);
      definitions.push(definition);
    }
    return Object.freeze({
      requestId: value.requestId,
      retrievedAt: value.retrievedAt,
      totalRowCount: value.totalRowCount,
      truncated: value.truncated,
      suggestedProgramCode: value.suggestedProgramCode,
      canMutate: value.canMutate,
      writeQuarantined: value.writeQuarantined,
      definitions: Object.freeze(definitions)
    });
  }

  function normalizeRawRow(value, expectedIndex) {
    const keys = [
      "itemIndex", "enabled", "groupCode", "subject", "graphicType",
      "subtype", "pageText", "dataCode"
    ];
    if (!hasExactKeys(value, keys) || value.itemIndex !== expectedIndex ||
        typeof value.enabled !== "boolean") return null;
    const selection = normalizeSelection({
      groupCode: value.groupCode,
      subject: value.subject,
      graphicType: value.graphicType,
      subtype: value.subtype,
      dataCode: value.dataCode
    });
    if (!selection || typeof value.pageText !== "string" || value.pageText.length > 9) return null;
    const pageState = value.pageText === "" ? null : parseStoredPageText(value.pageText);
    if (value.pageText !== "" && !pageState) return null;
    const legacyFields = Object.freeze([
      value.enabled ? "1" : "0",
      selection.groupCode,
      selection.subject,
      selection.graphicType,
      selection.subtype,
      value.pageText,
      selection.dataCode
    ]);
    const listText = legacyListText(legacyFields);
    return Object.freeze({
      itemIndex: value.itemIndex,
      enabled: value.enabled,
      groupCode: selection.groupCode,
      subject: selection.subject,
      graphicType: selection.graphicType,
      subtype: selection.subtype,
      pageText: value.pageText,
      dataCode: selection.dataCode,
      legacyFields,
      listText,
      pageState,
      requiresTrustedRestore: true,
      pageRecalculationRequired: pageState !== null,
      historicalPageOutOfBounds: pageState?.historicalPageOutOfBounds === true
    });
  }

  function normalizeLoadResponse(value) {
    const keys = [
      "requestId", "definition", "retrievedAt", "totalRowCount",
      "canMutate", "writeQuarantined", "rows"
    ];
    if (!hasExactKeys(value, keys) || !requestId(value.requestId) ||
        !isIsoTimestamp(value.retrievedAt) || !Number.isInteger(value.totalRowCount) ||
        value.totalRowCount < 0 || value.totalRowCount > MAXIMUM_ITEMS ||
        typeof value.canMutate !== "boolean" || typeof value.writeQuarantined !== "boolean" ||
        (value.writeQuarantined && value.canMutate) || !Array.isArray(value.rows) ||
        value.rows.length !== value.totalRowCount) return null;
    const definition = normalizeDefinition(value.definition);
    if (!definition) return null;
    const rawRows = [];
    for (let index = 0; index < value.rows.length; index += 1) {
      const row = normalizeRawRow(value.rows[index], index);
      if (!row) return null;
      rawRows.push(row);
    }
    return Object.freeze({
      kind: "named-playlist-load",
      schemaVersion: SCHEMA_VERSION,
      requestId: value.requestId,
      definition,
      retrievedAt: value.retrievedAt,
      totalRowCount: value.totalRowCount,
      canMutate: value.canMutate,
      writeQuarantined: value.writeQuarantined,
      rawRows: Object.freeze(rawRows)
    });
  }

  function sameSelection(entry, rawRow) {
    const selection = normalizeSelection(entry?.selection);
    return selection !== null && selection.groupCode === rawRow.groupCode &&
      selection.subject === rawRow.subject && selection.graphicType === rawRow.graphicType &&
      selection.subtype === rawRow.subtype && selection.dataCode === rawRow.dataCode;
  }

  function freezeTrustedEntry(entry) {
    const copy = {
      ...entry,
      selection: Object.freeze({ ...entry.selection })
    };
    if (Array.isArray(entry.aliases)) copy.aliases = Object.freeze([...entry.aliases]);
    if (isPlainObject(entry.operator)) copy.operator = Object.freeze({ ...entry.operator });
    return Object.freeze(copy);
  }

  function compatibleSelection(entry, rawRow, compatibilityVerifier) {
    if (sameSelection(entry, rawRow)) return true;
    if (typeof compatibilityVerifier !== "function") return false;
    try {
      return compatibilityVerifier(entry, rawRow) === true;
    } catch {
      return false;
    }
  }

  function trustedEntryMatchesRaw(entry, rawRow, compatibilityVerifier) {
    return isPlainObject(entry) && requestId(entry.id) &&
      typeof entry.builderKey === "string" && builderKeyPattern.test(entry.builderKey) &&
      typeof entry.code === "string" && cutCodePattern.test(entry.code) &&
      entry.enabled === rawRow.enabled && compatibleSelection(entry, rawRow, compatibilityVerifier);
  }

  function restoreRawRows(loadValue, trustedResolver, compatibilityVerifier) {
    const load = loadValue?.kind === "named-playlist-load"
      ? loadValue
      : normalizeLoadResponse(loadValue);
    if (!load || typeof trustedResolver !== "function" ||
        (compatibilityVerifier !== undefined && typeof compatibilityVerifier !== "function")) {
      throw new TypeError("A normalized load response and trusted resolver are required.");
    }
    const rows = load.rawRows.map(rawRow => {
      let candidate = null;
      try {
        candidate = trustedResolver(rawRow, rawRow.itemIndex);
      } catch {
        candidate = null;
      }
      const trusted = trustedEntryMatchesRaw(candidate, rawRow, compatibilityVerifier);
      return Object.freeze({
        rawRow,
        entry: trusted ? freezeTrustedEntry(candidate) : null,
        trusted,
        pageRecalculationRequired: rawRow.pageRecalculationRequired,
        pageRecalculated: !rawRow.pageRecalculationRequired,
        pagePreflightCompleted: false,
        pageUnavailableReason: null,
        recalculatedPagePlan: null
      });
    });
    return freezeRestoration(load.definition, rows);
  }

  function preparePagePreflight(restoration, isPagedEntry) {
    if (!restoration || restoration.kind !== "named-playlist-restoration" ||
        typeof isPagedEntry !== "function") {
      throw new TypeError("A valid restoration and paged-entry classifier are required.");
    }
    const rows = restoration.rows.map(row => {
      const paged = row.trusted && isPagedEntry(row.entry, row.rawRow.itemIndex) === true;
      return Object.freeze({
        ...row,
        pageRecalculationRequired: paged,
        pageRecalculated: !paged,
        pagePreflightCompleted: false,
        pageUnavailableReason: null,
        recalculatedPagePlan: null
      });
    });
    return freezeRestoration(restoration.definition, rows);
  }

  function pagePlanEntry(entry) {
    const definition = pagedBuilderByCode[entry?.code];
    const selection = normalizeSelection(entry?.selection);
    const fadeDuration = Number(entry?.fadeDuration);
    if (!definition || definition.builderKey !== entry?.builderKey ||
        !requestId(entry?.id) || typeof entry?.enabled !== "boolean" ||
        !selection || !Number.isInteger(fadeDuration) || fadeDuration < 0 || fadeDuration > 60) {
      return null;
    }
    return Object.freeze({
      id: entry.id,
      code: entry.code,
      enabled: entry.enabled,
      fadeDuration,
      selection
    });
  }

  function createPagePlanRequest(requestIdValue, restoration) {
    const id = requestId(requestIdValue);
    if (!id || !restoration || restoration.kind !== "named-playlist-restoration") {
      throw new TypeError("A safe request id and trusted restoration are required.");
    }
    const entries = [];
    const identifiers = new Set();
    for (const row of restoration.rows) {
      if (!row.trusted || !row.pageRecalculationRequired) continue;
      const entry = pagePlanEntry(row.entry);
      if (!entry || identifiers.has(entry.id)) {
        throw new TypeError("A paged restoration entry is not safe for page preflight.");
      }
      identifiers.add(entry.id);
      entries.push(entry);
    }
    if (!entries.length) return null;
    return Object.freeze({ requestId: id, entries: Object.freeze(entries) });
  }

  function normalizePagePlanResult(value, expectedEntry) {
    const keys = [
      "entryId", "itemCount", "pageSize", "pageCount",
      "accessibleItemCount", "isTruncated", "builderKey"
    ];
    const definition = pagedBuilderByCode[expectedEntry?.code];
    if (!hasExactKeys(value, keys) || !definition ||
        value.entryId !== expectedEntry.id || value.builderKey !== definition.builderKey ||
        value.pageSize !== definition.pageSize ||
        !Number.isSafeInteger(value.itemCount) || value.itemCount < 0 ||
        !Number.isInteger(value.pageCount) || value.pageCount < 0 ||
        value.pageCount > MAXIMUM_PAGE_COUNT ||
        !Number.isSafeInteger(value.accessibleItemCount) || value.accessibleItemCount < 0 ||
        typeof value.isTruncated !== "boolean") return null;

    const expectedPageCount = value.itemCount === 0
      ? 0
      : Math.min(MAXIMUM_PAGE_COUNT, Math.ceil(value.itemCount / value.pageSize));
    const expectedAccessible = Math.min(
      value.itemCount,
      expectedPageCount * value.pageSize);
    if (value.pageCount !== expectedPageCount ||
        value.accessibleItemCount !== expectedAccessible ||
        value.isTruncated !== (value.itemCount > expectedAccessible)) return null;
    return Object.freeze({ ...value });
  }

  function normalizePagePlanResponse(value, expectedRequest) {
    if (!expectedRequest || !hasExactKeys(expectedRequest, ["requestId", "entries"]) ||
        !hasExactKeys(value, ["requestId", "calculatedAt", "plans"]) ||
        value.requestId !== expectedRequest.requestId || !isIsoTimestamp(value.calculatedAt) ||
        !Array.isArray(value.plans) || value.plans.length !== expectedRequest.entries.length) {
      return null;
    }
    const plans = [];
    for (let index = 0; index < expectedRequest.entries.length; index += 1) {
      const plan = normalizePagePlanResult(value.plans[index], expectedRequest.entries[index]);
      if (!plan) return null;
      plans.push(plan);
    }
    return Object.freeze({
      requestId: value.requestId,
      calculatedAt: value.calculatedAt,
      plans: Object.freeze(plans)
    });
  }

  function normalizePagePlanError(value, expectedRequestId) {
    if (!hasExactKeys(value, ["requestId", "code", "message", "retryable"]) ||
        value.requestId !== expectedRequestId || !requestId(value.requestId) ||
        !exactText(value.code, 64) || !exactText(value.message, 1024) ||
        typeof value.retryable !== "boolean") return null;
    return Object.freeze({ ...value });
  }

  function normalizePagePlan(value) {
    if (!hasExactKeys(value, ["itemCount", "pageSize", "pageCount"]) ||
        !Number.isInteger(value.itemCount) || value.itemCount < 0 ||
        !Number.isInteger(value.pageSize) || value.pageSize < 0 || value.pageSize > 12 ||
        !Number.isInteger(value.pageCount) || value.pageCount < 1 ||
        value.pageCount > MAXIMUM_PAGE_COUNT) return null;
    return Object.freeze({
      itemCount: value.itemCount,
      pageSize: value.pageSize,
      pageCount: value.pageCount
    });
  }

  function markPageRecalculated(restoration, itemIndex, pagePlanValue) {
    if (!restoration || restoration.kind !== "named-playlist-restoration" ||
        !Number.isInteger(itemIndex) || itemIndex < 0 || itemIndex >= restoration.rows.length) {
      throw new TypeError("A valid restoration row is required.");
    }
    const pagePlan = normalizePagePlan(pagePlanValue);
    if (!pagePlan) throw new RangeError("The recalculated page plan is invalid or exceeds 20 pages.");
    const rows = restoration.rows.map((row, index) => index === itemIndex
      ? Object.freeze({
        ...row,
        pageRecalculated: true,
        pagePreflightCompleted: true,
        pageUnavailableReason: null,
        recalculatedPagePlan: pagePlan
      })
      : row);
    return freezeRestoration(restoration.definition, rows);
  }

  function applyPagePlanResponse(restoration, response) {
    if (!restoration || restoration.kind !== "named-playlist-restoration" ||
        !response || !Array.isArray(response.plans)) {
      throw new TypeError("A valid restoration and normalized page-plan response are required.");
    }
    let current = restoration;
    for (const plan of response.plans) {
      const itemIndex = current.rows.findIndex(row =>
        row.trusted && row.entry?.id === plan.entryId &&
        row.entry?.builderKey === plan.builderKey && row.pageRecalculationRequired);
      if (itemIndex < 0) throw new TypeError("The page-plan result does not match the restoration.");
      if (plan.itemCount === 0) {
        const rows = current.rows.map((row, index) => index === itemIndex
          ? Object.freeze({
            ...row,
            pageRecalculated: false,
            pagePreflightCompleted: true,
            pageUnavailableReason: "empty-result",
            recalculatedPagePlan: Object.freeze({ ...plan })
          })
          : row);
        current = freezeRestoration(current.definition, rows);
        continue;
      }
      current = markPageRecalculated(current, itemIndex, {
        itemCount: plan.itemCount,
        pageSize: plan.pageSize,
        pageCount: plan.pageCount
      });
      const rows = current.rows.map((row, index) => index === itemIndex
        ? Object.freeze({ ...row, recalculatedPagePlan: Object.freeze({ ...plan }) })
        : row);
      current = freezeRestoration(current.definition, rows);
    }
    return current;
  }

  function prepareBlockers(restoration) {
    if (!restoration || restoration.kind !== "named-playlist-restoration") {
      return Object.freeze([Object.freeze({ itemIndex: -1, reason: "invalid-restoration" })]);
    }
    const blockers = [];
    for (const row of restoration.rows) {
      if (!row.trusted) blockers.push(Object.freeze({
        itemIndex: row.rawRow.itemIndex,
        reason: "trusted-restore-required"
      }));
      if (row.pageRecalculationRequired && !row.pageRecalculated) blockers.push(Object.freeze({
        itemIndex: row.rawRow.itemIndex,
        reason: row.pagePreflightCompleted && row.pageUnavailableReason === "empty-result"
          ? "page-result-empty"
          : "page-recalculation-required"
      }));
    }
    return Object.freeze(blockers);
  }

  function freezeRestoration(definition, rowsValue) {
    const rows = Object.freeze([...rowsValue]);
    const provisional = { kind: "named-playlist-restoration", schemaVersion: SCHEMA_VERSION, definition, rows };
    const blockers = prepareBlockers(provisional);
    return Object.freeze({ ...provisional, blockers, readyForPrepare: blockers.length === 0 });
  }

  function canPrepareRestoredRows(restoration) {
    return prepareBlockers(restoration).length === 0;
  }

  function materializeTrustedPlaylist(restoration) {
    if (!canPrepareRestoredRows(restoration)) {
      throw new Error("Trusted restoration and fresh page calculation are required before PREPARE.");
    }
    return Object.freeze(restoration.rows.map(row => row.entry));
  }

  function pageStatusLabel(rawRow) {
    if (!rawRow || rawRow.requiresTrustedRestore !== true) return "Invalid stored row";
    if (!rawRow.pageState) return "No stored page; trusted restoration is required";
    if (rawRow.historicalPageOutOfBounds) {
      return `Stored page ${rawRow.pageText}; recalculate before PREPARE (20-page maximum)`;
    }
    return `Stored page ${rawRow.pageText}; recalculate before PREPARE`;
  }

  function normalizeMutationResponse(value) {
    const keys = ["requestId", "operation", "programCode", "completedAt", "writeQuarantined"];
    if (!hasExactKeys(value, keys) || !requestId(value.requestId) ||
        !["create", "replace", "delete"].includes(value.operation) ||
        !programCode(value.programCode) || !isIsoTimestamp(value.completedAt) ||
        typeof value.writeQuarantined !== "boolean") return null;
    return Object.freeze({ ...value });
  }

  function normalizeError(value) {
    const keys = [
      "requestId", "operation", "programCode", "code", "message",
      "retryable", "outcomeUnknown", "writeQuarantined"
    ];
    if (!hasExactKeys(value, keys) || !requestId(value.requestId) ||
        !operationSet.has(value.operation) ||
        (value.programCode !== "" && !programCode(value.programCode)) ||
        !exactText(value.code, 64) || !exactText(value.message, 1024) ||
        typeof value.retryable !== "boolean" || typeof value.outcomeUnknown !== "boolean" ||
        typeof value.writeQuarantined !== "boolean" ||
        (value.outcomeUnknown && (value.retryable || !value.writeQuarantined))) return null;
    return Object.freeze({ ...value });
  }

  function isWriteBlocked(value) {
    return value?.writeQuarantined === true;
  }

  return {
    bridgeContract,
    pagePlanBridgeContract,
    operations,
    createListRequest,
    createLoadRequest,
    createDefinitionRequest,
    createReplaceRequest,
    createDeleteRequest,
    parseStoredPageText,
    toLegacySevenFields,
    legacyListText,
    normalizeListResponse,
    normalizeLoadResponse,
    restoreRawRows,
    preparePagePreflight,
    createPagePlanRequest,
    normalizePagePlanResponse,
    normalizePagePlanError,
    applyPagePlanResponse,
    markPageRecalculated,
    prepareBlockers,
    canPrepareRestoredRows,
    materializeTrustedPlaylist,
    pageStatusLabel,
    normalizeMutationResponse,
    normalizeError,
    isWriteBlocked
  };
});
