// SPEC: PJ2026-01040111 long-running Workbench observation.
// Responsibility: Analyzer Project Management/MDTODO report and finding source fragment.

export function nodeWebObserveAnalyzerProjectSource(): string {
  return String.raw`function buildProjectManagementReport(samples, control, network, pagePerformance, config) {
  const enabled = config?.enabled === true;
  const targetPathSamples = (samples || []).filter((sample) => enabled && config.targetPaths.some((target) => String(sample?.path || "").startsWith(target)));
  const projectSamples = (samples || []).filter((sample) => sample?.projectManagement && typeof sample.projectManagement === "object");
  const latest = projectSamples[projectSamples.length - 1] || null;
  const latestProject = latest?.projectManagement || null;
  const pageKindCounts = countBy(projectSamples.map((sample) => sample.projectManagement?.pageKind).filter(Boolean));
  const latestTaskStatusCounts = latestProject?.taskStatusCounts && typeof latestProject.taskStatusCounts === "object" ? latestProject.taskStatusCounts : {};
  const commandRows = projectManagementCommandRows(control, config);
  const launchCommands = commandRows.filter((item) => item.type === "launchWorkbenchFromTask" || item.type === "launchWorkbenchFromMdtodo");
  const launchSuccess = launchCommands.filter((item) => item.phase === "completed" && Number(item.launchStatus ?? 0) >= 200 && Number(item.launchStatus ?? 0) < 300);
  const launchFailed = launchCommands.filter((item) => item.phase === "failed" || Number(item.launchStatus ?? 200) >= 400);
  const projectApiEvents = projectManagementNetworkRows(network, config);
  const projectApiResponses = projectApiEvents.filter((item) => item.type === "response");
  const projectApiFailures = projectApiResponses.filter((item) => Number(item.status ?? 0) >= 400);
  const projectApiFailedRequests = projectApiEvents.filter((item) => item.type === "requestfailed");
  const projectApiByPath = groupProjectApiEvents(projectApiEvents);
  const projectApiPerformance = projectManagementPerformanceRows(pagePerformance, config);
  const slowProjectApiPerformance = projectApiPerformance.filter((item) => Number(item.overBudgetCount ?? 0) > 0 || Number(item.p95Ms ?? 0) > Number(config?.slowApiBudgetMs ?? 0));
  const selectedTaskSamples = projectSamples.filter((sample) => sample.projectManagement?.selectedTaskRef?.hash);
  const launchEnabledSamples = projectSamples.filter((sample) => sample.projectManagement?.launchButtonEnabled === true);
  const launchVisibleSamples = projectSamples.filter((sample) => sample.projectManagement?.launchButtonVisible === true);
  const mdtodoSamples = projectSamples.filter((sample) => sample.projectManagement?.pageKind === "project-management-mdtodo");
  const selectedFileLabelBadSamples = projectSamples.filter((sample) => sample.projectManagement?.selectedFileLabel && sample.projectManagement?.selectedFileLabelLooksDirect === false);
  const suspiciousFileLabelSamples = projectSamples.filter((sample) => Number(sample.projectManagement?.fileOptionSuspiciousLabelCount ?? 0) > 0);
  const bodyVisibleSamples = selectedTaskSamples.filter((sample) => sample.projectManagement?.taskBodyVisible === true && Number(sample.projectManagement?.taskBody?.textBytes ?? 0) > 0);
  const reportLinkSamples = projectSamples.filter((sample) => Number(sample.projectManagement?.reportLinkCount ?? 0) > 0);
  const reportPreviewSamples = projectSamples.filter((sample) => sample.projectManagement?.reportPreviewVisible === true && Number(sample.projectManagement?.reportPreview?.textBytes ?? 0) > 0);
  const reportFullscreenSamples = projectSamples.filter((sample) => sample.projectManagement?.reportFullscreenVisible === true);
  const hwpodBlockerSamples = projectManagementHwpodBlockerRows(projectSamples);
  const projectionReportSamples = projectManagementProjectionReportRows(projectSamples);
  const hwpodApiFailures = projectManagementHwpodApiFailureRows(projectApiFailures);
  const paneGapRows = projectManagementPaneGapRows(projectSamples);
  const severePaneGapSamples = paneGapRows.actionable;
  const ignoredPaneGapSamples = paneGapRows.ignored;
  const previewCommands = commandRows.filter((item) => item.type === "openMdtodoReportPreview" || item.type === "toggleMdtodoReportFullscreen");
  const launchNonEmpty = launchSuccess.filter((item) => item.chatObserved === true && (Number(item.workbenchMessageCount ?? 0) > 0 || Number(item.workbenchTraceRowCount ?? 0) > 0));
  const launchEmpty = launchSuccess.filter((item) => item.chatObserved !== true || (Number(item.workbenchMessageCount ?? 0) === 0 && Number(item.workbenchTraceRowCount ?? 0) === 0));
  const minMdtodoTaskCount = minNumber(mdtodoSamples.map((sample) => sample.projectManagement?.taskCount));
  const maxMdtodoTaskCount = maxNumber(mdtodoSamples.map((sample) => sample.projectManagement?.taskCount));
  return {
    enabled,
    config: config || null,
    summary: {
      enabled,
      targetPathSampleCount: targetPathSamples.length,
      projectSampleCount: projectSamples.length,
      mdtodoSampleCount: mdtodoSamples.length,
      pageKindCounts,
      latestPageKind: latestProject?.pageKind ?? null,
      latestPath: latest?.path ?? null,
      latestSeq: latest?.seq ?? null,
      latestTs: latest?.ts ?? null,
      latestSourceCount: latestProject?.sourceCount ?? null,
      latestFileCount: latestProject?.fileCount ?? null,
      latestTaskCount: latestProject?.taskCount ?? null,
      maxSourceCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.sourceCount)),
      maxFileCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.fileCount)),
      maxTaskCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.taskCount)),
      taskRefMissingMax: maxNumber(projectSamples.map((sample) => sample.projectManagement?.taskRefMissingCount)),
      latestSelectedTaskRefHash: latestProject?.selectedTaskRef?.hash ?? null,
      latestSelectedTaskRefPreview: latestProject?.selectedTaskRef?.preview ?? null,
      latestSelectedFileLabelPreview: latestProject?.selectedFileLabel?.textPreview ?? null,
      latestSelectedFileLabelLooksDirect: latestProject?.selectedFileLabelLooksDirect ?? null,
      selectedFileLabelBadSampleCount: selectedFileLabelBadSamples.length,
      fileOptionSuspiciousLabelSampleCount: suspiciousFileLabelSamples.length,
      maxFileOptionSuspiciousLabelCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.fileOptionSuspiciousLabelCount)),
      latestSelectedTaskStatus: latestProject?.selectedTaskStatus ?? null,
      latestTaskStatusCounts,
      selectedTaskBodyVisibleSamples: bodyVisibleSamples.length,
      reportLinkVisibleSamples: reportLinkSamples.length,
      maxReportLinkCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.reportLinkCount)),
      reportPreviewVisibleSamples: reportPreviewSamples.length,
      reportFullscreenVisibleSamples: reportFullscreenSamples.length,
      hwpodBlockerSampleCount: hwpodBlockerSamples.length,
      projectionReportSampleCount: projectionReportSamples.length,
      hwpodApiFailureCount: hwpodApiFailures.length,
      severePaneGapSampleCount: severePaneGapSamples.length,
      ignoredPaneGapSampleCount: ignoredPaneGapSamples.length,
      maxPaneBottomGapPx: maxNumber(severePaneGapSamples.map((item) => item.maxBottomGapPx)),
      maxPaneBottomGapRatio: maxNumber(severePaneGapSamples.map((item) => item.maxBottomGapRatio)),
      launchButtonVisibleSamples: launchVisibleSamples.length,
      launchButtonEnabledSamples: launchEnabledSamples.length,
      launchButtonDisabledSamples: Math.max(0, launchVisibleSamples.length - launchEnabledSamples.length),
      latestWorkbenchLinkCount: latestProject?.workbenchLinkCount ?? null,
      maxWorkbenchLinkCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.workbenchLinkCount)),
      maxBlockerCount: maxNumber(projectSamples.map((sample) => sample.projectManagement?.blockerCount)),
      selectedTaskSampleCount: selectedTaskSamples.length,
      projectCommandCount: commandRows.length,
      launchCommandCount: launchCommands.length,
      launchSuccessCount: launchSuccess.length,
      launchFailureCount: launchFailed.length,
      launchNonEmptyCount: launchNonEmpty.length,
      launchEmptyCount: launchEmpty.length,
      launchWithOtelTraceHeaderCount: launchSuccess.filter((item) => item.otelTraceId).length,
      reportPreviewCommandCount: previewCommands.length,
      mdtodoTaskCountMin: minMdtodoTaskCount,
      mdtodoTaskCountMax: maxMdtodoTaskCount,
      projectApiEventCount: projectApiEvents.length,
      projectApiResponseCount: projectApiResponses.length,
      projectApiFailureCount: projectApiFailures.length,
      projectApiRequestFailedCount: projectApiFailedRequests.length,
      projectApiSlowPathCount: slowProjectApiPerformance.length,
      slowApiBudgetMs: config?.slowApiBudgetMs ?? null,
      valuesRedacted: true
    },
    latest: latestProject,
    samples: projectSamples.slice(-80).map((sample) => ({
      seq: sample.seq ?? null,
      ts: sample.ts ?? null,
      pageRole: sample.pageRole ?? null,
      path: sample.path ?? null,
      pageKind: sample.projectManagement?.pageKind ?? null,
      sourceCount: sample.projectManagement?.sourceCount ?? null,
      fileCount: sample.projectManagement?.fileCount ?? null,
      taskCount: sample.projectManagement?.taskCount ?? null,
      taskRefMissingCount: sample.projectManagement?.taskRefMissingCount ?? null,
      selectedTaskRefHash: sample.projectManagement?.selectedTaskRef?.hash ?? null,
      selectedFileLabelPreview: sample.projectManagement?.selectedFileLabel?.textPreview ?? null,
      selectedFileLabelLooksDirect: sample.projectManagement?.selectedFileLabelLooksDirect ?? null,
      fileOptionSuspiciousLabelCount: sample.projectManagement?.fileOptionSuspiciousLabelCount ?? 0,
      selectedTaskStatus: sample.projectManagement?.selectedTaskStatus ?? null,
      taskBodyVisible: sample.projectManagement?.taskBodyVisible === true,
      taskBodyBytes: sample.projectManagement?.taskBody?.textBytes ?? 0,
      reportLinkCount: sample.projectManagement?.reportLinkCount ?? 0,
      reportPreviewVisible: sample.projectManagement?.reportPreviewVisible === true,
      reportPreviewBytes: sample.projectManagement?.reportPreview?.textBytes ?? 0,
      reportFullscreenVisible: sample.projectManagement?.reportFullscreenVisible === true,
      paneGaps: Array.isArray(sample.projectManagement?.paneGaps) ? sample.projectManagement.paneGaps.slice(0, 4) : [],
      launchButtonVisible: sample.projectManagement?.launchButtonVisible === true,
      launchButtonEnabled: sample.projectManagement?.launchButtonEnabled === true,
      blockerCount: sample.projectManagement?.blockerCount ?? 0,
      workbenchLinkCount: sample.projectManagement?.workbenchLinkCount ?? 0,
      valuesRedacted: true
    })),
    targetPathWithoutProjectSummary: targetPathSamples.filter((sample) => !sample.projectManagement).slice(0, 20).map(ref),
    commands: commandRows,
    launchCommands,
    projectApiByPath,
    projectApiFailures: projectApiFailures.slice(0, 40),
    projectApiRequestFailed: projectApiFailedRequests.slice(0, 40),
    hwpodBlockerSamples: hwpodBlockerSamples.slice(0, 40),
    projectionReportSamples: projectionReportSamples.slice(0, 40),
    hwpodApiFailures: hwpodApiFailures.slice(0, 40),
    severePaneGapSamples: severePaneGapSamples.slice(0, 40),
    ignoredPaneGapSamples: ignoredPaneGapSamples.slice(0, 40),
    projectApiPerformance,
    slowProjectApiPerformance,
    valuesRedacted: true
  };
}

function compactProjectManagementForOutput(report) {
  if (!report || typeof report !== "object") return null;
  const compactCommand = (item) => ({
    ts: item?.ts ?? null,
    phase: item?.phase ?? null,
    type: item?.type ?? null,
    commandId: item?.commandId ?? null,
    afterPath: item?.afterPath ?? null,
    launchStatus: item?.launchStatus ?? null,
    sessionId: item?.sessionId ?? null,
    workbenchUrl: item?.workbenchUrl ?? null,
    otelTraceId: item?.otelTraceId ?? null,
    chatObserved: item?.chatObserved ?? null,
    chatStatus: item?.chatStatus ?? null,
    chatTraceId: item?.chatTraceId ?? null,
    workbenchMessageCount: item?.workbenchMessageCount ?? null,
    workbenchTraceRowCount: item?.workbenchTraceRowCount ?? null,
    contractVersion: item?.contractVersion ?? null,
    selectedTaskRefHash: item?.selectedTaskRefHash ?? null,
    errorMessageHash: item?.errorMessageHash ?? null,
    message: item?.message ? limitText(item.message, 180) : null,
    valuesRedacted: true
  });
  const compactApiGroup = (item) => ({
    method: item?.method ?? null,
    path: item?.path ?? item?.urlPath ?? null,
    status: item?.status ?? null,
    type: item?.type ?? null,
    count: item?.count ?? item?.sampleCount ?? null,
    firstAt: item?.firstAt ?? null,
    lastAt: item?.lastAt ?? null,
    failureKinds: Array.isArray(item?.failureKinds) ? item.failureKinds.slice(0, 4) : [],
    valuesRedacted: true
  });
  const compactSlowSample = (item) => ({
    ts: item?.ts ?? null,
    seq: item?.seq ?? null,
    path: item?.path ?? item?.rawPath ?? null,
    durationMs: item?.durationMs ?? null,
    requestToResponseStartMs: item?.requestToResponseStartMs ?? item?.streamOpenMs ?? null,
    responseTransferMs: item?.responseTransferMs ?? null,
    timingStatus: item?.timingStatus ?? null,
    initiatorType: item?.initiatorType ?? null,
    nextHopProtocol: item?.nextHopProtocol ?? null,
    serverTimingNames: Array.isArray(item?.serverTimingNames) ? item.serverTimingNames.slice(0, 4) : [],
    otelTraceId: item?.otelTraceId ?? null,
    valuesRedacted: true
  });
  const compactPerformance = (item) => ({
    path: item?.path ?? item?.route ?? null,
    sampleCount: item?.sampleCount ?? null,
    p95Ms: item?.p95Ms ?? item?.p95 ?? null,
    maxMs: item?.maxMs ?? item?.max ?? null,
    budgetMs: item?.projectSlowBudgetMs ?? item?.budgetMs ?? report.summary?.slowApiBudgetMs ?? null,
    overBudgetCount: item?.overBudgetCount ?? item?.overFiveSecondCount ?? null,
    slowSamples: Array.isArray(item?.slowSamples) ? item.slowSamples.slice(0, 3).map(compactSlowSample) : [],
    valuesRedacted: true
  });
  const compactSample = (item) => ({
    seq: item?.seq ?? null,
    ts: item?.ts ?? null,
    pageRole: item?.pageRole ?? null,
    path: item?.path ?? null,
    selectedTaskRefHash: item?.selectedTaskRefHash ?? null,
    selectedFileLabelPreview: item?.selectedFileLabelPreview ?? null,
    pageKind: item?.pageKind ?? null,
    reason: item?.reason ?? null,
    severePaneCount: item?.severePaneCount ?? null,
    maxBottomGapPx: item?.maxBottomGapPx ?? null,
    maxBottomGapRatio: item?.maxBottomGapRatio ?? null,
    paneGaps: Array.isArray(item?.paneGaps) ? item.paneGaps.slice(0, 4) : undefined,
    valuesRedacted: true
  });
  return {
    summary: report.summary ?? null,
    samples: Array.isArray(report.samples) ? report.samples.slice(-8) : [],
    commands: Array.isArray(report.commands) ? report.commands.slice(-8).map(compactCommand) : [],
    launchCommands: Array.isArray(report.launchCommands) ? report.launchCommands.slice(-8).map(compactCommand) : [],
    projectApiByPath: Array.isArray(report.projectApiByPath) ? report.projectApiByPath.slice(0, 8).map(compactApiGroup) : [],
    hwpodBlockerSamples: Array.isArray(report.hwpodBlockerSamples) ? report.hwpodBlockerSamples.slice(0, 8).map(compactSample) : [],
    projectionReportSamples: Array.isArray(report.projectionReportSamples) ? report.projectionReportSamples.slice(0, 8).map(compactSample) : [],
    hwpodApiFailures: Array.isArray(report.hwpodApiFailures) ? report.hwpodApiFailures.slice(0, 8).map(compactApiGroup) : [],
    severePaneGapSamples: Array.isArray(report.severePaneGapSamples) ? report.severePaneGapSamples.slice(0, 8).map(compactSample) : [],
    ignoredPaneGapSamples: Array.isArray(report.ignoredPaneGapSamples) ? report.ignoredPaneGapSamples.slice(0, 8).map(compactSample) : [],
    projectApiPerformance: Array.isArray(report.projectApiPerformance) ? report.projectApiPerformance.slice(0, 8).map(compactPerformance) : [],
    slowProjectApiPerformance: Array.isArray(report.slowProjectApiPerformance) ? report.slowProjectApiPerformance.slice(0, 8).map(compactPerformance) : [],
    valuesRedacted: true
  };
}

function projectManagementCommandRows(control, config) {
  const allowed = new Set(config?.commandAllowlist || []);
  const mdtodoCommandTypes = new Set(["gotoProjectMdtodo", "openMdtodoSourceConfig", "configureMdtodoHwpodSource", "probeMdtodoSource", "reindexMdtodoSource", "expandMdtodoTask", "openMdtodoReportPreview", "toggleMdtodoReportFullscreen", "editMdtodoTaskInline", "editMdtodoTaskTitle", "editMdtodoTaskBody", "toggleMdtodoTaskStatus", "addMdtodoRootTask", "addMdtodoSubTask", "continueMdtodoTask", "deleteMdtodoTask", "launchWorkbenchFromMdtodo"]);
  return (control || [])
    .filter((item) => allowed.has(item?.type) || mdtodoCommandTypes.has(item?.type) || String(item?.type || "").startsWith("selectMdtodo") || item?.type === "selectProjectSource" || item?.type === "launchWorkbenchFromTask")
    .filter((item) => item.phase === "completed" || item.phase === "failed")
    .map((item) => {
      const detail = item.detail && typeof item.detail === "object" ? item.detail : {};
      const error = detail.error && typeof detail.error === "object" ? detail.error : {};
      return {
        ts: item.ts ?? null,
        phase: item.phase ?? null,
        type: item.type ?? null,
        commandId: item.commandId ?? null,
        afterPath: urlPath(item.afterUrl),
        launchStatus: detail.launchStatus ?? error.details?.launchStatus ?? null,
        sessionId: detail.sessionId ?? error.details?.sessionId ?? null,
        workbenchUrl: detail.workbenchUrl ?? error.details?.workbenchUrl ?? null,
        otelTraceId: detail.otelTraceId ?? error.details?.otelTraceId ?? null,
        chatObserved: detail.chatObserved ?? error.details?.chatObserved ?? null,
        chatStatus: detail.chatStatus ?? error.details?.chatStatus ?? null,
        chatSessionId: detail.chatSessionId ?? error.details?.chatSessionId ?? null,
        chatTraceId: detail.chatTraceId ?? error.details?.chatTraceId ?? null,
        chatOtelTraceId: detail.chatOtelTraceId ?? error.details?.chatOtelTraceId ?? null,
        workbenchMessageCount: detail.workbenchSnapshot?.messageCount ?? error.details?.workbenchSnapshot?.messageCount ?? null,
        workbenchTraceRowCount: detail.workbenchSnapshot?.traceRowCount ?? error.details?.workbenchSnapshot?.traceRowCount ?? null,
        workbenchComposerReady: detail.workbenchSnapshot?.composerReady ?? error.details?.workbenchSnapshot?.composerReady ?? null,
        contractVersion: detail.contractVersion ?? error.details?.contractVersion ?? null,
        selectedTaskRefHash: detail.selectedTask?.hash ?? detail.projectBeforeClick?.selectedTaskRef?.hash ?? null,
        errorName: error.name ?? null,
        errorMessageHash: error.message ? sha256(error.message) : null,
        message: error.message ? limitText(error.message, 180) : null,
        valuesRedacted: true
      };
    });
}

function projectManagementNetworkRows(network, config) {
  const prefixes = config?.naturalApiPathPrefixes || [];
  return (network || [])
    .filter((item) => item?.observerInitiated !== true)
    .map((item) => ({
      ts: item.ts ?? null,
      type: item.type ?? null,
      method: String(item.method || "GET").toUpperCase(),
      status: Number.isFinite(Number(item.status)) ? Number(item.status) : null,
      path: urlPath(item.url),
      failureKind: item.failure ? limitText(item.failure, 120) : null,
      valuesRedacted: true
    }))
    .filter((item) => prefixes.some((prefix) => String(item.path || "").startsWith(prefix)));
}

function groupProjectApiEvents(events) {
  const groups = new Map();
  for (const item of events || []) {
    const key = [item.method, item.path, item.status ?? "-", item.type].join(" ");
    const existing = groups.get(key) || { method: item.method, path: item.path, status: item.status, type: item.type, count: 0, firstAt: item.ts, lastAt: item.ts, failureKinds: [], valuesRedacted: true };
    existing.count += 1;
    existing.lastAt = item.ts;
    if (item.failureKind && !existing.failureKinds.includes(item.failureKind)) existing.failureKinds.push(item.failureKind);
    groups.set(key, existing);
  }
  return Array.from(groups.values()).sort((a, b) => b.count - a.count || String(a.path).localeCompare(String(b.path)));
}

function projectManagementPerformanceRows(pagePerformance, config) {
  const prefixes = config?.naturalApiPathPrefixes || [];
  const rows = Array.isArray(pagePerformance?.sameOriginApiByPath) ? pagePerformance.sameOriginApiByPath : [];
  return rows
    .filter((item) => prefixes.some((prefix) => String(item?.path || "").startsWith(prefix)))
    .map((item) => ({ ...item, projectSlowBudgetMs: config?.slowApiBudgetMs ?? null }));
}

function projectManagementDigestText(value) {
  if (!value || typeof value !== "object") return "";
  return String(value.textPreview ?? value.preview ?? value.text ?? "").trim();
}

function projectManagementSampleRef(sample) {
  return {
    seq: sample?.seq ?? null,
    ts: sample?.ts ?? null,
    pageRole: sample?.pageRole ?? null,
    path: sample?.path ?? null,
    pageKind: sample?.projectManagement?.pageKind ?? null,
    selectedTaskRefHash: sample?.projectManagement?.selectedTaskRef?.hash ?? null,
    selectedFileLabelPreview: sample?.projectManagement?.selectedFileLabel?.textPreview ?? null,
    valuesRedacted: true
  };
}

function projectManagementHwpodBlockerRows(projectSamples) {
  const pattern = /(?:no outbound WebSocket hwpod-node|HWLAB_HWPOD_NODE_OPS_URL|hwpod-node-ops contract)/iu;
  const rows = [];
  for (const sample of projectSamples || []) {
    const blockers = Array.isArray(sample?.projectManagement?.blockers) ? sample.projectManagement.blockers : [];
    const matched = blockers
      .filter((item) => pattern.test(projectManagementDigestText(item)))
      .map((item) => ({
        index: item?.index ?? null,
        testId: item?.testId ?? null,
        role: item?.role ?? null,
        textHash: item?.textHash ?? null,
        textPreview: item?.textPreview ?? null,
        valuesRedacted: true
      }));
    if (matched.length > 0) rows.push({ ...projectManagementSampleRef(sample), blockers: matched.slice(0, 4), valuesRedacted: true });
  }
  return rows;
}

function projectManagementProjectionReportRows(projectSamples) {
  const pattern = /(?:报告索引待刷新|projection-only|任务投影确认存在报告链接)/iu;
  return (projectSamples || [])
    .filter((sample) => pattern.test(projectManagementDigestText(sample?.projectManagement?.reportPreview)))
    .map((sample) => ({
      ...projectManagementSampleRef(sample),
      reportPreviewHash: sample?.projectManagement?.reportPreview?.textHash ?? null,
      reportPreviewPreview: sample?.projectManagement?.reportPreview?.textPreview ?? null,
      reportPreviewBytes: sample?.projectManagement?.reportPreview?.textBytes ?? null,
      valuesRedacted: true
    }));
}

function projectManagementHwpodApiFailureRows(projectApiFailures) {
  const pattern = /^\/v1\/project-management\/mdtodo\/(?:task-detail|report-preview)\b/u;
  return (projectApiFailures || [])
    .filter((item) => pattern.test(String(item?.path || "")) && Number(item?.status ?? 0) >= 500)
    .map((item) => ({
      ts: item?.ts ?? null,
      method: item?.method ?? null,
      path: item?.path ?? null,
      status: item?.status ?? null,
      type: item?.type ?? null,
      failureKind: item?.failureKind ?? null,
      valuesRedacted: true
    }));
}

function projectManagementPaneGapRows(projectSamples) {
  const actionable = [];
  const ignored = [];
  for (const sample of projectSamples || []) {
    const paneGaps = Array.isArray(sample?.projectManagement?.paneGaps) ? sample.projectManagement.paneGaps : [];
    const severeGaps = paneGaps
      .filter((item) => item?.visible === true)
      .filter((item) => {
        const bottomGapPx = Number(item?.bottomGapPx ?? 0);
        const bottomGapRatio = Number(item?.bottomGapRatio ?? 0);
        const heightPx = Number(item?.heightPx ?? 0);
        return heightPx >= 120 && bottomGapPx >= 180 && bottomGapRatio >= 0.28;
      })
      .map((item) => ({
        name: item?.name ?? null,
        widthPx: item?.widthPx ?? null,
        heightPx: item?.heightPx ?? null,
        bottomGapPx: item?.bottomGapPx ?? null,
        bottomGapRatio: item?.bottomGapRatio ?? null,
        contentNodeCount: item?.contentNodeCount ?? null,
        valuesRedacted: true
      }));
    if (severeGaps.length === 0) continue;
    const maxGapPx = maxNumber(severeGaps.map((item) => item.bottomGapPx));
    const maxGapRatio = maxNumber(severeGaps.map((item) => item.bottomGapRatio));
    const multiPane = severeGaps.length >= 2;
    const singlePrimaryPaneExtreme = severeGaps.some((item) =>
      item.name !== "task-tree"
      && Number(item.bottomGapPx ?? 0) >= 240
      && Number(item.bottomGapRatio ?? 0) >= 0.45
    );
    if (!multiPane && !singlePrimaryPaneExtreme) continue;
    const selectedTaskRefHash = sample?.projectManagement?.selectedTaskRef?.hash ?? null;
    const isMdtodo = sample?.projectManagement?.pageKind === "project-management-mdtodo";
    const isInitialEmptyDetail = isMdtodo && !selectedTaskRefHash;
    const row = {
      ...projectManagementSampleRef(sample),
      severePaneCount: severeGaps.length,
      maxBottomGapPx: maxGapPx,
      maxBottomGapRatio: maxGapRatio,
      paneGaps: severeGaps.slice(0, 4),
      valuesRedacted: true
    };
    if (isInitialEmptyDetail) {
      ignored.push({
        ...row,
        reason: "mdtodo-initial-empty-detail-no-selected-task",
        valuesRedacted: true
      });
      continue;
    }
    actionable.push(row);
  }
  return { actionable, ignored, valuesRedacted: true };
}

function buildProjectManagementFindings(report) {
  if (!report?.enabled) return [];
  const findings = [];
  const summary = report.summary || {};
  if (Number(summary.targetPathSampleCount ?? 0) > 0 && Number(summary.projectSampleCount ?? 0) === 0) {
    findings.push({ id: "project-management-route-not-ready", severity: "red", summary: "project management target path was sampled but no project-management DOM summary was detected", count: summary.targetPathSampleCount, samples: report.targetPathWithoutProjectSummary, valuesRedacted: true });
  }
  if (Number(summary.taskRefMissingMax ?? 0) > 0) {
    findings.push({ id: "mdtodo-taskref-missing", severity: "red", summary: "mdtodo task rows were visible without stable data-task-ref; Workbench launch must bind by opaque public task id", count: summary.taskRefMissingMax, samples: report.samples.filter((item) => Number(item.taskRefMissingCount ?? 0) > 0).slice(0, 20), valuesRedacted: true });
  }
  if (Number(summary.mdtodoSampleCount ?? 0) > 0 && Number(summary.latestTaskCount ?? 0) > 0 && Number(summary.launchButtonEnabledSamples ?? 0) === 0) {
    findings.push({ id: "workbench-launch-button-unavailable", severity: "red", summary: "mdtodo tasks were sampled but the Workbench launch button was never enabled", count: summary.mdtodoSampleCount, latest: report.latest, valuesRedacted: true });
  }
  if (Number(summary.selectedFileLabelBadSampleCount ?? 0) > 0 || summary.latestSelectedFileLabelLooksDirect === false) {
    findings.push({ id: "mdtodo-file-label-not-filename", severity: "red", summary: "MDTODO file dropdown selected label is not a direct markdown filename", count: summary.selectedFileLabelBadSampleCount, latestSelectedFileLabelPreview: summary.latestSelectedFileLabelPreview, samples: report.samples.filter((item) => item.selectedFileLabelLooksDirect === false).slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.maxFileOptionSuspiciousLabelCount ?? 0) > 0) {
    findings.push({ id: "mdtodo-nondirect-files-visible", severity: "red", summary: "MDTODO file dropdown includes non-direct or report-like markdown labels; docs/MDTODO discovery must be direct files only", count: summary.maxFileOptionSuspiciousLabelCount, samples: report.samples.filter((item) => Number(item.fileOptionSuspiciousLabelCount ?? 0) > 0).slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.selectedTaskSampleCount ?? 0) > 0 && Number(summary.selectedTaskBodyVisibleSamples ?? 0) === 0) {
    findings.push({ id: "mdtodo-task-body-not-visible", severity: "red", summary: "selected MDTODO task was sampled but no rendered task body was visible", count: summary.selectedTaskSampleCount, samples: report.samples.filter((item) => item.selectedTaskRefHash).slice(-12), valuesRedacted: true });
  }
  if (Number(summary.hwpodBlockerSampleCount ?? 0) > 0) {
    findings.push({ id: "mdtodo-hwpod-node-disconnected", severity: "red", summary: "MDTODO surfaced the hwpod-node disconnected / HWLAB_HWPOD_NODE_OPS_URL fallback blocker", count: summary.hwpodBlockerSampleCount, samples: report.hwpodBlockerSamples.slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.projectionReportSampleCount ?? 0) > 0) {
    findings.push({ id: "mdtodo-report-projection-only", severity: "red", summary: "MDTODO report preview is projection-only instead of opening the full markdown report from the HWPOD source", count: summary.projectionReportSampleCount, samples: report.projectionReportSamples.slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.maxReportLinkCount ?? 0) > 0 && Number(summary.reportPreviewVisibleSamples ?? 0) === 0) {
    const severity = Number(summary.reportPreviewCommandCount ?? 0) > 0 ? "red" : "amber";
    findings.push({ id: "mdtodo-report-preview-missing", severity, summary: "MDTODO report links were visible but no markdown report preview was sampled", count: summary.maxReportLinkCount, previewCommandCount: summary.reportPreviewCommandCount, samples: report.samples.filter((item) => Number(item.reportLinkCount ?? 0) > 0).slice(-12), valuesRedacted: true });
  }
  if (Number(summary.reportPreviewCommandCount ?? 0) > 0 && Number(summary.reportFullscreenVisibleSamples ?? 0) === 0 && report.commands.some((item) => item.type === "toggleMdtodoReportFullscreen" && item.phase === "completed")) {
    findings.push({ id: "mdtodo-report-fullscreen-missing", severity: "red", summary: "toggleMdtodoReportFullscreen command completed but fullscreen report dialog was never sampled", count: summary.reportPreviewCommandCount, commands: report.commands.filter((item) => item.type === "toggleMdtodoReportFullscreen").slice(-8), valuesRedacted: true });
  }
  if (Number(summary.launchEmptyCount ?? 0) > 0) {
    findings.push({ id: "mdtodo-workbench-launch-empty", severity: "red", summary: "MDTODO Workbench launch created a session without observing agent chat or visible message/trace content", count: summary.launchEmptyCount, commands: report.launchCommands.filter((item) => item.chatObserved !== true || (Number(item.workbenchMessageCount ?? 0) === 0 && Number(item.workbenchTraceRowCount ?? 0) === 0)).slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.mdtodoTaskCountMin ?? 0) > 0 && Number(summary.mdtodoTaskCountMax ?? 0) > 0 && (Number(summary.mdtodoTaskCountMax) - Number(summary.mdtodoTaskCountMin) >= 10 || Number(summary.mdtodoTaskCountMax) / Math.max(1, Number(summary.mdtodoTaskCountMin)) >= 2)) {
    findings.push({ id: "mdtodo-task-count-diverged", severity: "amber", summary: "MDTODO task count varied sharply during observation; compare control commands and observer samples for projection divergence", minTaskCount: summary.mdtodoTaskCountMin, maxTaskCount: summary.mdtodoTaskCountMax, samples: report.samples.slice(-20), valuesRedacted: true });
  }
  if (Number(summary.severePaneGapSampleCount ?? 0) > 0) {
    findings.push({ id: "mdtodo-pane-bottom-gap", severity: "red", summary: "MDTODO task tree, main detail, or report sidebar left large unused bottom gaps in actionable selected-task samples", count: summary.severePaneGapSampleCount, ignoredInitialEmptyDetailCount: summary.ignoredPaneGapSampleCount, maxBottomGapPx: summary.maxPaneBottomGapPx, maxBottomGapRatio: summary.maxPaneBottomGapRatio, samples: report.severePaneGapSamples.slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.hwpodApiFailureCount ?? 0) > 0) {
    findings.push({ id: "project-management-hwpod-api-failed", severity: "red", summary: "HWPOD-backed MDTODO task detail or report preview API returned a server error during natural page use", count: summary.hwpodApiFailureCount, failures: report.hwpodApiFailures.slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.projectApiFailureCount ?? 0) > 0 || Number(summary.projectApiRequestFailedCount ?? 0) > 0) {
    findings.push({ id: "project-management-api-failed", severity: "amber", summary: "natural project-management or Workbench launch API requests failed during observation", count: Number(summary.projectApiFailureCount ?? 0) + Number(summary.projectApiRequestFailedCount ?? 0), groups: report.projectApiByPath.slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.projectApiSlowPathCount ?? 0) > 0) {
    findings.push({ id: "project-management-api-slow", severity: "red", summary: "project-management API resource timing exceeded YAML projectManagement.slowApiBudgetMs", count: summary.projectApiSlowPathCount, budgetMs: summary.slowApiBudgetMs, groups: report.slowProjectApiPerformance.slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.launchFailureCount ?? 0) > 0) {
    findings.push({ id: "mdtodo-workbench-launch-failed", severity: "red", summary: "MDTODO Workbench launch command failed or returned an HTTP error", count: summary.launchFailureCount, commands: report.launchCommands.filter((item) => item.phase === "failed" || Number(item.launchStatus ?? 200) >= 400).slice(0, 12), valuesRedacted: true });
  }
  if (Number(summary.launchSuccessCount ?? 0) > 0 && Number(summary.launchWithOtelTraceHeaderCount ?? 0) === 0) {
    findings.push({ id: "mdtodo-workbench-launch-otel-trace-missing", severity: "amber", summary: "Workbench launch succeeded but no x-hwlab-otel-trace-id header was captured for Tempo drill-down", count: summary.launchSuccessCount, commands: report.launchCommands.slice(0, 12), valuesRedacted: true });
  }
  return findings;
}

function countBy(values) {
  const out = {};
  for (const value of values || []) out[value] = (out[value] || 0) + 1;
  return out;
}

function maxNumber(values) {
  const numeric = (values || []).map((value) => Number(value)).filter(Number.isFinite);
  return numeric.length > 0 ? Math.max(...numeric) : 0;
}

function minNumber(values) {
  const numeric = (values || []).map((value) => Number(value)).filter(Number.isFinite);
  return numeric.length > 0 ? Math.min(...numeric) : 0;
}
`;
}
