// ../core/src/codeStory/types.ts
var CODE_CHANGE_STORY_SCHEMA_VERSION = 1;
// ../core/src/codeStory/builders.ts
var NO_AUTHORITY = {
  reportOnly: true,
  advisoryOnly: true,
  noAuthority: true,
  grantsApplyAuthority: false,
  grantsMergeAuthority: false,
  grantsGitHubWriteAuthority: false,
  grantsMemoryPromotionAuthority: false,
  grantsServiceWriteAuthority: false,
  grantsGraphMutationAuthority: false
};
function codeChangeStoryNoAuthorityBoundaryV1() {
  return { ...NO_AUTHORITY };
}
function buildCodeChangeStoryFromPrReviewV1(args) {
  const generatedAt = args.generatedAt ?? args.prReviewStory.generatedAt;
  const story = args.prReviewStory;
  const headline = buildStoryHeadline(story);
  const summary = story.topMotion.detail ?? `${story.counts.changedFiles} changed files, ${story.counts.blockers} blockers, ${story.counts.proofGaps} proof gaps.`;
  const sourceRefs = buildSourceRefs(story);
  const contextRefs = buildContextRefs(story);
  const chapters = buildStoryChapters(story, args.reviewRoomState, args.reviewDiff);
  const nextActions = buildStoryNextActions(story);
  return {
    schemaVersion: CODE_CHANGE_STORY_SCHEMA_VERSION,
    kind: "code_change_story",
    storyId: stableId("code-change-story", [story.storyId, story.pr.prSnapshotId, story.reviewDiffId, story.reviewRoomId]),
    source: {
      sourceKind: "pr_review",
      sourceStoryId: story.storyId,
      prSnapshotId: story.pr.prSnapshotId,
      reviewDiffId: story.reviewDiffId,
      reviewRoomId: story.reviewRoomId,
      generatedFrom: "PrReviewStoryV1",
      refs: sourceRefs
    },
    status: story.status,
    headline,
    summary,
    chapters,
    contextRefs,
    sourceReceipts: story.sourceReceipts,
    nextActions,
    generationMode: "deterministic",
    proofStatus: proofStatusForStory(story),
    freshness: story.freshness,
    relatedPrs: story.relatedPrs,
    generatedAt,
    ...codeChangeStoryNoAuthorityBoundaryV1()
  };
}
function buildCodeChangeStoryFromCodeTrailV1(args) {
  const trail = args.codeTrail;
  const generatedAt = args.generatedAt ?? trail.generatedAt;
  const repoId = stringValue(args.repoId) ?? stringValue(trail.scope.repoId);
  if (trail.entries.length === 0)
    return codeTrailStoryGap("empty_trail", "CodeTrail has no entries to summarize.");
  if (!repoId)
    return codeTrailStoryGap("missing_repo", "CodeTrail story creation requires a repository scope.");
  if (isPrScopedCodeTrail(trail)) {
    return codeTrailStoryGap("pr_scoped_trail", "PR-scoped CodeTrail evidence is left to the PR Review story producer.");
  }
  const contextRefs = buildCodeTrailContextRefs(trail, repoId);
  const fileRefsForStory = contextRefs.filter((ref) => ref.kind === "file" || Boolean(ref.path));
  if (fileRefsForStory.length === 0) {
    return codeTrailStoryGap("no_code_refs", "CodeTrail story creation requires at least one code/file reference.");
  }
  const sourceIdentity = args.sourceIdentity ?? {};
  const sourceStoryId = codeTrailSourceStoryId(trail, sourceIdentity);
  const sourceRefs = buildCodeTrailSourceRefs(trail, sourceIdentity);
  const status = codeTrailStoryStatus(trail);
  const headline = codeTrailHeadline(trail, fileRefsForStory.length);
  const summary = codeTrailSummary(trail, fileRefsForStory.length);
  const storySeed = stableId("code-trail-story-source", [trail.projectId, repoId, sourceStoryId]);
  return {
    story: {
      schemaVersion: CODE_CHANGE_STORY_SCHEMA_VERSION,
      kind: "code_change_story",
      storyId: stableId("code-change-story", ["code_trail", trail.projectId, repoId, sourceStoryId]),
      source: {
        sourceKind: "code_trail",
        kind: "code_trail",
        sourceStoryId,
        generatedFrom: "CodeTrail",
        refs: sourceRefs
      },
      status,
      headline,
      summary,
      chapters: buildCodeTrailChapters(trail, fileRefsForStory, storySeed),
      contextRefs,
      sourceReceipts: buildCodeTrailSourceReceipts(trail, generatedAt),
      nextActions: [{
        actionId: stableId("code-story-action", [storySeed, "collect_evidence"]),
        kind: "collect_evidence",
        title: "Review CodeTrail evidence",
        detail: "Inspect the imported Trail and attach validation or review evidence before taking any governed action.",
        filePaths: fileRefsForStory.map((ref) => ref.path ?? ref.id).slice(0, 12),
        refs: sourceRefs.map((ref) => `${ref.kind}:${ref.id}`).slice(0, 12),
        reasonCodes: ["next_action:collect_evidence", "authority:report_only_no_action"]
      }],
      generationMode: "deterministic",
      proofStatus: codeTrailProofStatus(trail, fileRefsForStory.length),
      freshness: {
        status: "fresh",
        generatedAt,
        snapshotUpdatedAt: latestTrailUpdatedAt(trail) ?? generatedAt,
        reasons: ["source:code_trail", "freshness:import_projection"]
      },
      relatedPrs: [],
      generatedAt,
      ...codeChangeStoryNoAuthorityBoundaryV1()
    }
  };
}
function buildReviewContinuityV1(args = {}) {
  const story = args.prReviewStory ?? undefined;
  const reviewRoomState = recordValue(args.reviewRoomState);
  const generatedAt = args.generatedAt ?? story?.generatedAt ?? numberValue(reviewRoomState["generatedAt"], Date.now());
  const signals = recordValue(reviewRoomState["signals"]);
  const checkTriage = recordValue(reviewRoomState["checkTriage"]);
  const staleApproval = recordValue(reviewRoomState["staleApproval"]);
  const reviewOrder = arrayValue(reviewRoomState["reviewOrder"]);
  const blockers = arrayValue(reviewRoomState["blockers"]);
  const proofGaps = arrayValue(reviewRoomState["proofGaps"]);
  const failedChecks = arrayValue(checkTriage["failedChecks"]);
  const counts = {
    blockerCount: story?.counts.blockers ?? numberValue(signals["blockerCount"], blockers.length),
    proofGapCount: story?.counts.proofGaps ?? numberValue(signals["proofGapCount"], proofGaps.length),
    failedCheckCount: story?.counts.failedChecks ?? numberValue(signals["failedCheckCount"], failedChecks.length),
    staleApprovalCount: story?.counts.staleApprovals ?? numberValue(signals["staleApprovalCount"], staleApproval["state"] === "stale" ? 1 : 0),
    currentApprovalCount: story?.counts.currentApprovals ?? numberValue(signals["currentApprovalCount"], numberValue(staleApproval["currentApprovalCount"], 0)),
    reviewOrderCount: reviewOrder.length || story?.keyFiles.length || 0
  };
  const status = reviewContinuityStatus({ story, staleApproval, counts });
  const nextAction = continuityNextAction({ story, status, reviewRoomState, blockers, proofGaps, failedChecks });
  const sourceReceipts = args.sourceReceipts ?? story?.sourceReceipts ?? [];
  const sourceReceiptRefs = sourceReceipts.map((receipt) => receipt.source).filter(Boolean).map(String);
  const precedentRefs = story?.relatedPrs.map((related) => related.prSnapshotId ?? related.title).filter(isString) ?? [];
  const reviewDiffId = story?.reviewDiffId ?? stringValue(recordValue(args.reviewDiff)["reviewDiffId"]);
  const reviewRoomId = story?.reviewRoomId ?? stringValue(recordValue(recordValue(args.reviewRoomState)["source"])["reviewRoomId"]);
  const reasonCodes = uniqueStrings([
    `continuity:${status}`,
    counts.blockerCount > 0 ? "blocked:blockers_present" : undefined,
    counts.failedCheckCount > 0 ? "blocked:failed_checks_present" : undefined,
    counts.staleApprovalCount > 0 ? "freshness:approval_stale" : undefined,
    story?.freshness.status === "stale" ? "freshness:story_stale" : undefined,
    counts.proofGapCount > 0 ? "proof:gaps_present" : undefined,
    counts.currentApprovalCount > 0 ? "review:current_approval_present" : undefined,
    args.importedCodeTrailRefs?.length ? "trail:imported_refs_present" : undefined
  ]);
  return {
    schemaVersion: CODE_CHANGE_STORY_SCHEMA_VERSION,
    kind: "pr_review_continuity",
    continuityId: stableId("pr-review-continuity", [story?.storyId, reviewDiffId, reviewRoomId, status]),
    status,
    nextAction,
    source: {
      prReviewStoryId: story?.storyId,
      reviewDiffId,
      reviewRoomId,
      importedCodeTrailRefs: uniqueStrings(args.importedCodeTrailRefs ?? []),
      precedentRefs: uniqueStrings(precedentRefs),
      sourceReceiptRefs: uniqueStrings(sourceReceiptRefs)
    },
    signals: counts,
    reasonCodes,
    generatedAt,
    ...codeChangeStoryNoAuthorityBoundaryV1()
  };
}
function codeTrailStoryGap(reason, detail) {
  return {
    skippedReason: reason,
    gap: {
      kind: "code_trail_story_not_persisted",
      reason,
      detail,
      reportOnly: true,
      noAuthority: true
    }
  };
}
function isPrScopedCodeTrail(trail) {
  if (stringValue(trail.scope.prSnapshotId) || stringValue(trail.scope.reviewRoomId) || stringValue(trail.scope.storyId))
    return true;
  if (trail.scope.surface === "pr_review")
    return true;
  return trail.entries.some((entry) => {
    if (entry.entryKind === "pr_snapshot" || entry.entryKind === "pr_review_file")
      return true;
    return refsForCodeTrailEntry(entry).some((ref) => ref.kind === "pr_snapshot" || ref.kind === "review_room" || ref.kind === "code_change_story");
  });
}
function buildCodeTrailContextRefs(trail, repoId) {
  return uniqueRefs(trail.entries.flatMap((entry) => refsForCodeTrailEntry(entry).map((ref) => codeTrailContextRef(ref, entry, repoId))).filter(Boolean));
}
function buildCodeTrailSourceRefs(trail, identity) {
  const identityRefs = [
    identity.importId ? storyRef("trail_import", identity.importId, "Trail import", ["source:trail_import"]) : undefined,
    identity.trailHash ? storyRef("trail_hash", identity.trailHash, "Trail hash", ["source:trail_hash"]) : undefined,
    identity.sourceMcpRequestId ? storyRef("mcp_context_run", identity.sourceMcpRequestId, "MCP context request", ["source:mcp_context_request"]) : undefined,
    identity.sourceMcpRunId ? storyRef("mcp_run_graph", identity.sourceMcpRunId, "MCP run", ["source:mcp_run"]) : undefined,
    identity.sourceRunId ? storyRef("source_run", identity.sourceRunId, "Source run", ["source:run"]) : undefined,
    identity.sessionId ? storyRef("session", identity.sessionId, "Code session", ["source:session"]) : undefined,
    identity.workroomRunId ? storyRef("code_workroom_run", identity.workroomRunId, "Workroom run", ["source:workroom_run"]) : undefined,
    identity.patchRunId ? storyRef("code_patch_run", identity.patchRunId, "Patch run", ["source:patch_run"]) : undefined,
    identity.editSessionRowId ? storyRef("agent_edit_session", identity.editSessionRowId, "Edit session", ["source:edit_session_row"]) : undefined,
    identity.editSessionId ? storyRef("agent_edit_session", identity.editSessionId, "Edit session", ["source:edit_session"]) : undefined,
    identity.truthCandidateId ? storyRef("truth_candidate", identity.truthCandidateId, "Truth candidate", ["source:truth_candidate"]) : undefined,
    identity.capabilityRunId ? storyRef("capability_run", identity.capabilityRunId, "Capability run", ["source:capability_run"]) : undefined
  ];
  const sourceRefs = trail.sources.slice(0, 16).map((source) => {
    const ref = source.ref;
    const id = ref?.id ?? source.watermark ?? source.key;
    if (!id)
      return;
    return storyRef(ref?.kind ?? source.kind ?? "code_trail_source", id, source.label ?? ref?.label ?? source.kind ?? "CodeTrail source", ["source:code_trail", source.kind ? `trail_source:${source.kind}` : undefined].filter(isString), ref?.path, ref?.href);
  });
  return uniqueRefs([...identityRefs, ...sourceRefs]);
}
function codeTrailContextRef(ref, entry, repoId) {
  const filePath = codeTrailFilePath(ref);
  if (filePath) {
    return storyRef("file", filePath, ref.label ?? filePath, uniqueStrings(["context:code_trail", `entry:${entry.entryKind}`, ...entry.reasonCodes]), filePath, ref.href, entry.status);
  }
  if (["code_node", "artifact", "context_receipt", "code_patch_run", "agent_edit_session", "truth_candidate", "evidence_job", "capability_run", "mcp_context_run", "mcp_run_graph", "code_write_proposal"].includes(ref.kind)) {
    return storyRef(ref.kind, ref.id, ref.label ?? ref.kind, uniqueStrings(["context:code_trail", `entry:${entry.entryKind}`, repoId ? `repo:${repoId}` : undefined]), ref.path, ref.href, entry.status);
  }
  return;
}
function refsForCodeTrailEntry(entry) {
  return [
    entry.primaryRef,
    ...entry.sourceRefs,
    ...entry.inputRefs,
    ...entry.outputRefs,
    ...entry.evidenceRefs,
    ...entry.receiptRefs,
    ...entry.relatedRefs
  ].filter(Boolean);
}
function codeTrailFilePath(ref) {
  const path = stringValue(ref.path);
  if (path)
    return path;
  if (ref.kind === "file")
    return stringValue(ref.id);
  return;
}
function codeTrailSourceStoryId(trail, identity) {
  return stringValue(identity.trailHash) ?? stringValue(identity.importId) ?? stringValue(identity.sourceMcpRunId) ?? stringValue(identity.sourceRunId) ?? stringValue(identity.sourceMcpRequestId) ?? stableId("code-trail-source", [trail.projectId, trail.scope.repoId, trail.generatedAt.toString(), trail.summary.title]);
}
function codeTrailHeadline(trail, fileCount) {
  const title = stringValue(trail.summary.title);
  if (title && title !== "Code Trail")
    return title;
  return `CodeTrail story for ${fileCount} code ${fileCount === 1 ? "ref" : "refs"}`;
}
function codeTrailSummary(trail, fileCount) {
  const detail = stringValue(trail.summary.detail);
  if (detail)
    return detail;
  return `${trail.entries.length} Trail entries and ${fileCount} code refs from ${trail.sources.length} sources.`;
}
function buildCodeTrailChapters(trail, fileRefsForStory, storySeed) {
  const fileSections = fileRefsForStory.slice(0, 12).map((ref) => ({
    sectionId: stableId("code-story-section", [storySeed, "file", ref.id]),
    title: ref.path ?? ref.label ?? ref.id,
    summary: ref.status ? `Observed in CodeTrail with status ${ref.status}.` : "Observed in CodeTrail evidence.",
    filePaths: ref.path ? [ref.path] : [ref.id],
    refs: [`${ref.kind}:${ref.id}`],
    reasonCodes: uniqueStrings(["section:code_trail_file", ...ref.reasonCodes ?? []])
  }));
  const evidenceSections = trail.entries.slice(0, 8).map((entry) => ({
    sectionId: stableId("code-story-section", [storySeed, "entry", entry.stableKey]),
    title: entry.title ?? entry.entryKind,
    summary: entry.summary ?? `${entry.phase} · ${entry.status}`,
    filePaths: uniqueStrings(refsForCodeTrailEntry(entry).map(codeTrailFilePath)),
    refs: [entry.primaryRef.stableKey],
    reasonCodes: uniqueStrings(["section:code_trail_entry", `entry:${entry.entryKind}`, `status:${entry.status}`])
  }));
  return [
    {
      chapterId: stableId("code-story-chapter", [storySeed, "code-refs"]),
      title: "CodeTrail Code Refs",
      summary: `${fileRefsForStory.length} code refs were found in the Trail projection/import.`,
      sections: fileSections,
      reasonCodes: ["chapter:code_trail_code_refs"]
    },
    {
      chapterId: stableId("code-story-chapter", [storySeed, "trail-evidence"]),
      title: "Trail Evidence",
      summary: `${trail.entries.length} entries remain report-only evidence and grant no write authority.`,
      sections: evidenceSections,
      reasonCodes: ["chapter:code_trail_evidence", "authority:report_only_no_action"]
    }
  ];
}
function buildCodeTrailSourceReceipts(trail, generatedAt) {
  return trail.sources.slice(0, 12).map((source) => ({
    schemaVersion: 1,
    source: source.kind.startsWith("local_mcp") ? "local_mcp" : "code_insights",
    authority: "advisory_evidence",
    status: "used",
    generatedAt,
    observedAt: source.observedAt,
    confidence: {
      score: typeof source.confidence === "number" ? Math.max(0, Math.min(1, source.confidence)) : 0.7,
      label: "medium",
      reasonCodes: ["source:code_trail"]
    },
    reasonCodes: uniqueStrings(["source:code_trail", source.kind ? `trail_source:${source.kind}` : undefined]),
    details: {
      sourceKey: source.key,
      watermark: source.watermark
    },
    reportOnly: true,
    advisoryOnly: true,
    noAuthority: true
  }));
}
function codeTrailStoryStatus(trail) {
  if (trail.entries.some((entry) => entry.status === "blocked" || entry.status === "failed"))
    return "blocked";
  if (trail.entries.some((entry) => entry.status === "review_needed" || entry.status === "waiting"))
    return "needs_review";
  if (trail.entries.some((entry) => ["ready", "completed", "succeeded", "approved", "canonical"].includes(entry.status)))
    return "ready";
  return "unknown";
}
function codeTrailProofStatus(trail, fileCount) {
  if (trail.entries.some((entry) => entry.status === "blocked" || entry.status === "failed"))
    return "blocked";
  if (trail.gaps.some((gap) => gap.severity === "critical" || gap.severity === "warning"))
    return "needs_proof";
  if (trail.entries.some((entry) => entry.status === "approved" || entry.status === "canonical"))
    return "verified";
  if (fileCount > 0)
    return "partial";
  return "unknown";
}
function latestTrailUpdatedAt(trail) {
  const candidates = [
    ...trail.entries.flatMap((entry) => [entry.updatedAt, entry.completedAt, entry.createdAt]),
    ...trail.sources.map((source) => source.observedAt),
    ...trail.sourceWatermarks.map((watermark) => watermark.updatedAt)
  ].filter((value) => typeof value === "number" && Number.isFinite(value));
  return candidates.length > 0 ? Math.max(...candidates) : undefined;
}
function buildStoryHeadline(story) {
  const title = story.pr.title?.trim();
  const number = typeof story.pr.number === "number" ? `#${story.pr.number}` : undefined;
  if (title && number)
    return `${number} ${title}`;
  if (title)
    return title;
  if (number)
    return `${number} code change story`;
  return story.topMotion.title || "Code change story";
}
function buildSourceRefs(story) {
  return uniqueRefs([
    storyRef("pr_review_story", story.storyId, "PR Review Story", ["source:pr_review_story"]),
    story.pr.prSnapshotId ? storyRef("pr_snapshot", story.pr.prSnapshotId, "PR snapshot", ["source:pr_snapshot"]) : undefined,
    story.reviewDiffId ? storyRef("review_diff", story.reviewDiffId, "Review diff", ["source:review_diff"]) : undefined,
    story.reviewRoomId ? storyRef("review_room", story.reviewRoomId, "Review room", ["source:review_room"]) : undefined,
    story.impactMap?.impactMapId ? storyRef("impact_map", story.impactMap.impactMapId, "Impact map", ["source:impact_map"]) : undefined,
    ...story.sourceReceipts.map((receipt) => storyRef("receipt", `${receipt.source}:${receipt.scope}`, receipt.source, receipt.reasonCodes))
  ]);
}
function buildContextRefs(story) {
  return uniqueRefs([
    ...story.keyFiles.map((file) => storyRef("file", file.path, file.path, file.reasonCodes, file.path, undefined, file.status)),
    ...story.proofGaps.flatMap((gap) => gap.refs.map((ref) => storyRef("proof_gap", ref, gap.title, ["proof:gap"]))),
    ...story.blockers.flatMap((blocker) => blocker.refs.map((ref) => storyRef("blocker", ref, blocker.title, ["blocker:present"]))),
    ...story.failedChecks.flatMap((check) => check.proofRefs.map((ref) => storyRef("failed_check", ref, check.name ?? check.checkId, ["check:failed"]))),
    ...story.impactMap?.impactedRefs.docs.map((ref) => storyRef("document", ref, ref, ["impact:document"])) ?? [],
    ...story.impactMap?.impactedRefs.entities.map((ref) => storyRef("entity", ref, ref, ["impact:entity"])) ?? [],
    ...story.impactMap?.impactedRefs.memories.map((ref) => storyRef("memory", ref, ref, ["impact:memory"])) ?? [],
    ...story.impactMap?.impactedRefs.relationships.map((ref) => storyRef("relationship", ref, ref, ["impact:relationship"])) ?? []
  ]);
}
function buildStoryChapters(story, reviewRoomState, reviewDiff) {
  const chapters = [];
  const reviewChapterSections = buildReviewDiffStoryChapters(story, reviewDiff);
  chapters.push(...reviewChapterSections);
  const changeSections = reviewChapterSections.length > 0 ? [] : story.keyFiles.slice(0, 8).map((file) => ({
    sectionId: stableId("code-story-section", ["file", file.path, file.status]),
    title: file.path,
    summary: `${file.status} · ${file.additions} additions / ${file.deletions} deletions`,
    filePaths: [file.path],
    refs: [],
    reasonCodes: uniqueStrings([...file.reasonCodes ?? [], `risk:${file.riskLevel}`])
  }));
  if (changeSections.length > 0) {
    chapters.push({
      chapterId: stableId("code-story-chapter", [story.storyId, "changed-files"]),
      title: "Changed Files",
      summary: `${story.counts.changedFiles} files are part of this review story.`,
      sections: changeSections,
      reasonCodes: ["chapter:changed_files"]
    });
  }
  const proofSections = [
    ...story.blockers.map((blocker) => findingSection("blocker", blocker)),
    ...story.proofGaps.map((gap) => findingSection("proof_gap", gap)),
    ...story.failedChecks.map((check) => ({
      sectionId: stableId("code-story-section", ["failed_check", check.checkId]),
      title: check.name ?? check.checkId,
      summary: check.conclusion ?? "Check failed or needs attention",
      filePaths: check.mappedPaths,
      refs: check.proofRefs,
      reasonCodes: ["check:failed"]
    }))
  ];
  if (proofSections.length > 0) {
    chapters.push({
      chapterId: stableId("code-story-chapter", [story.storyId, "proof-and-risk"]),
      title: "Proof And Risk",
      summary: `${story.counts.blockers} blockers and ${story.counts.proofGaps} proof gaps are linked to receipts.`,
      sections: proofSections.slice(0, 12),
      reasonCodes: ["chapter:proof_and_risk"]
    });
  }
  const reviewOrder = arrayValue(recordValue(reviewRoomState)["reviewOrder"]);
  const reviewSections = reviewOrder.slice(0, 8).map((item, index) => {
    const record = recordValue(item);
    const path = stringValue(record["path"]) ?? `review-step:${index + 1}`;
    return {
      sectionId: stableId("code-story-section", ["review_order", path, String(index)]),
      title: path,
      summary: stringValue(record["reason"]) ?? "Suggested review order",
      filePaths: path.startsWith("review-step:") ? [] : [path],
      refs: stringArray(record["evidenceRefs"]),
      reasonCodes: stringArray(record["reasonCodes"]).length > 0 ? stringArray(record["reasonCodes"]) : ["review:ordered_step"]
    };
  });
  if (reviewSections.length > 0 || story.relatedPrs.length > 0) {
    chapters.push({
      chapterId: stableId("code-story-chapter", [story.storyId, "review-continuity"]),
      title: "Review Continuity",
      summary: `${reviewSections.length} ordered files and ${story.relatedPrs.length} Precedent refs are available.`,
      sections: reviewSections,
      reasonCodes: ["chapter:review_continuity"]
    });
  }
  return chapters;
}
function buildReviewDiffStoryChapters(story, reviewDiff) {
  const chapters = arrayValue(recordValue(reviewDiff)["reviewChapters"]);
  if (chapters.length > 0) {
    return chapters.flatMap((item, index) => {
      const chapter = recordValue(item);
      const filePaths = stringArray(chapter["filePaths"]);
      if (filePaths.length === 0)
        return [];
      const title = stringValue(chapter["title"]) ?? `Review chapter ${index + 1}`;
      const lineCount = typeof chapter["lineCount"] === "number" ? chapter["lineCount"] : undefined;
      const fileCount = typeof chapter["fileCount"] === "number" ? chapter["fileCount"] : filePaths.length;
      return [{
        chapterId: stringValue(chapter["chapterId"]) ?? stableId("code-story-chapter", [story.storyId, "review-chapter", title, filePaths.join("|")]),
        title,
        summary: lineCount !== undefined ? `${fileCount} files, ${lineCount} changed lines.` : `${fileCount} files are grouped for review.`,
        sections: [{
          sectionId: stableId("code-story-section", ["review_chapter", title, filePaths.join("|")]),
          title,
          summary: stringArray(chapter["reasonCodes"]).slice(0, 3).join("; ") || "Suggested review chapter.",
          filePaths,
          refs: filePaths.slice(0, 20).map((path) => `file:${path}`),
          reasonCodes: stringArray(chapter["reasonCodes"]).length > 0 ? stringArray(chapter["reasonCodes"]) : ["chapter:review_diff"]
        }],
        reasonCodes: uniqueStrings(["chapter:review_diff", ...stringArray(chapter["reasonCodes"])])
      }];
    });
  }
  const walkthroughOrder = arrayValue(recordValue(reviewDiff)["walkthroughOrder"]);
  return walkthroughOrder.flatMap((item, index) => {
    const group = recordValue(item);
    const filePaths = stringArray(group["filePaths"]);
    if (filePaths.length === 0)
      return [];
    const title = stringValue(group["title"]) ?? `Review chapter ${index + 1}`;
    const reasonCodes = stringArray(group["reasonCodes"]);
    return [{
      chapterId: stringValue(group["groupId"]) ?? stableId("code-story-chapter", [story.storyId, "walkthrough", title, filePaths.join("|")]),
      title,
      summary: `${filePaths.length} files are grouped for review.`,
      sections: [{
        sectionId: stableId("code-story-section", ["walkthrough", title, filePaths.join("|")]),
        title,
        summary: reasonCodes.slice(0, 3).join("; ") || "Suggested walkthrough group.",
        filePaths,
        refs: filePaths.slice(0, 20).map((path) => `file:${path}`),
        reasonCodes: reasonCodes.length > 0 ? reasonCodes : ["chapter:walkthrough_order"]
      }],
      reasonCodes: uniqueStrings(["chapter:walkthrough_order", ...reasonCodes])
    }];
  });
}
function buildStoryNextActions(story) {
  const motion = story.topMotion;
  return [{
    actionId: stableId("code-story-action", [story.storyId, motion.kind, motion.title]),
    kind: actionKindFromMotion(motion.kind),
    title: motion.title,
    detail: motion.detail,
    filePaths: motion.filePaths ?? [],
    refs: motion.refs ?? [],
    reasonCodes: ["authority:advisory_only", `motion:${motion.kind}`]
  }];
}
function findingSection(prefix, finding) {
  return {
    sectionId: stableId("code-story-section", [prefix, finding.title, finding.refs.join("|")]),
    title: finding.title,
    summary: finding.detail ?? finding.kind,
    filePaths: finding.filePaths,
    refs: finding.refs,
    reasonCodes: [`${prefix}:present`, `finding:${finding.kind}`]
  };
}
function proofStatusForStory(story) {
  if (story.counts.blockers > 0 || story.counts.failedChecks > 0 || story.status === "blocked")
    return "blocked";
  if (story.counts.proofGaps > 0 || story.status === "needs_review")
    return "needs_proof";
  if (story.status === "ready")
    return "verified";
  if (story.keyFiles.length > 0)
    return "partial";
  return "unknown";
}
function actionKindFromMotion(kind) {
  switch (kind) {
    case "resolve_blockers":
      return "resolve_blocker";
    case "refresh_review":
      return "refresh_review";
    case "attach_validation":
      return "attach_proof";
    case "review_files":
      return "review_next_file";
    case "merge_decision":
      return "record_review_decision";
    case "collect_review_evidence":
    default:
      return "collect_evidence";
  }
}
function reviewContinuityStatus(args) {
  if (args.counts.blockerCount > 0 || args.counts.failedCheckCount > 0 || args.story?.status === "blocked")
    return "blocked";
  if (args.counts.staleApprovalCount > 0 || args.staleApproval["state"] === "stale" || args.story?.freshness.status === "stale" || args.story?.status === "stale")
    return "stale";
  if (args.counts.proofGapCount > 0 || args.story?.status === "needs_review")
    return "needs_proof";
  if (args.story?.status === "ready" || args.counts.currentApprovalCount > 0)
    return "ready";
  return "fresh";
}
function continuityNextAction(args) {
  const firstBlocker = firstRecord(args.blockers);
  const firstProofGap = firstRecord(args.proofGaps);
  const firstFailedCheck = firstRecord(args.failedChecks);
  const reviewOrder = arrayValue(args.reviewRoomState["reviewOrder"]);
  const firstReviewFile = firstRecord(reviewOrder);
  const fallbackRefs = args.story?.topMotion.refs ?? [];
  const fallbackFiles = args.story?.topMotion.filePaths ?? [];
  if (args.status === "blocked") {
    const title = stringValue(firstBlocker["title"]) ?? stringValue(firstFailedCheck["name"]) ?? "Resolve blocking review evidence";
    return continuityAction("resolve_blocker", title, "Clear the blocker or failed-check evidence before this review can move forward.", stringArray(firstBlocker["filePaths"]).concat(stringArray(firstFailedCheck["mappedPaths"])), stringArray(firstBlocker["refs"]).concat(stringArray(firstFailedCheck["proofRefs"]), fallbackRefs), ["next_action:resolve_blocker"]);
  }
  if (args.status === "stale") {
    return continuityAction("refresh_review", "Refresh review against the current head", "Approval or story freshness is stale; rebuild the read-only review evidence before taking a decision.", fallbackFiles, fallbackRefs, ["next_action:refresh_review", "authority:no_github_write"]);
  }
  if (args.status === "needs_proof") {
    return continuityAction("attach_proof", stringValue(firstProofGap["title"]) ?? "Attach missing review proof", "Add validation, check, or source receipt evidence for the open proof gap.", stringArray(firstProofGap["filePaths"]).concat(fallbackFiles), stringArray(firstProofGap["refs"]).concat(fallbackRefs), ["next_action:attach_proof"]);
  }
  if (args.status === "ready") {
    return continuityAction("record_review_decision", "Review final evidence and record a decision", "The read-time projection is ready; this does not post to GitHub, approve, merge, apply code, or promote memory.", fallbackFiles, fallbackRefs, ["next_action:record_review_decision", "authority:no_merge_or_approval"]);
  }
  const firstPath = stringValue(firstReviewFile["path"]);
  return continuityAction("continue_review", firstPath ? `Review ${firstPath}` : "Continue the next review step", "Open the next ordered file or receipt-backed story evidence.", firstPath ? [firstPath] : fallbackFiles, fallbackRefs, ["next_action:continue_review"]);
}
function continuityAction(kind, title, detail, filePaths, refs, reasonCodes) {
  return {
    actionId: stableId("pr-review-continuity-action", [kind, title, refs.join("|")]),
    kind,
    title,
    detail,
    filePaths: uniqueStrings(filePaths),
    refs: uniqueStrings(refs),
    reasonCodes: uniqueStrings([...reasonCodes, "authority:report_only_no_action"])
  };
}
function storyRef(kind, id, label, reasonCodes, path, href, status) {
  return { kind, id, label, path, href, status, reasonCodes: uniqueStrings(reasonCodes) };
}
function uniqueRefs(refs) {
  const seen = new Set;
  const output = [];
  for (const ref of refs) {
    if (!ref?.id?.trim())
      continue;
    const key = `${ref.kind}:${ref.id}`;
    if (seen.has(key))
      continue;
    seen.add(key);
    output.push({ ...ref, id: ref.id.trim() });
  }
  return output;
}
function firstRecord(values) {
  return recordValue(values[0]);
}
function recordValue(value) {
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
}
function arrayValue(value) {
  return Array.isArray(value) ? value : [];
}
function stringValue(value) {
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
}
function stringArray(value) {
  return Array.isArray(value) ? value.filter(isString) : [];
}
function isString(value) {
  return typeof value === "string" && value.trim().length > 0;
}
function numberValue(value, fallback) {
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
}
function stableId(prefix, parts) {
  return `${prefix}:${stableHash(parts.filter(Boolean).join("|")).slice(0, 12)}`;
}
function stableHash(input) {
  let hash = 2166136261;
  for (let index = 0;index < input.length; index += 1) {
    hash ^= input.charCodeAt(index);
    hash = Math.imul(hash, 16777619);
  }
  return (hash >>> 0).toString(16).padStart(8, "0");
}
function uniqueStrings(values) {
  const seen = new Set;
  const output = [];
  for (const value of values) {
    const trimmed = value?.trim();
    if (!trimmed || seen.has(trimmed))
      continue;
    seen.add(trimmed);
    output.push(trimmed);
  }
  return output;
}
export {
  codeChangeStoryNoAuthorityBoundaryV1,
  buildReviewContinuityV1,
  buildCodeChangeStoryFromPrReviewV1,
  buildCodeChangeStoryFromCodeTrailV1,
  CODE_CHANGE_STORY_SCHEMA_VERSION
};
