diff --git a/apps/mobile/src/app/inbox/[...id].tsx b/apps/mobile/src/app/inbox/[...id].tsx
index 031443224..4b9937f6e 100644
--- a/apps/mobile/src/app/inbox/[...id].tsx
+++ b/apps/mobile/src/app/inbox/[...id].tsx
@@ -51,7 +51,10 @@ import type {
SignalReportStatus,
SuggestedReviewersArtefact,
} from "@/features/inbox/types";
-import { inboxStatusLabel } from "@/features/inbox/utils";
+import {
+ formatSignalReportSummaryMarkdown,
+ inboxStatusLabel,
+} from "@/features/inbox/utils";
import {
computeReportAgeHours,
type InboxReportActionType,
@@ -492,7 +495,9 @@ export default function ReportDetailScreen() {
{/* Summary */}
{report.summary && (
-
+
)}
diff --git a/apps/mobile/src/features/inbox/components/TinderView.tsx b/apps/mobile/src/features/inbox/components/TinderView.tsx
index 5f8928555..caeae12e8 100644
--- a/apps/mobile/src/features/inbox/components/TinderView.tsx
+++ b/apps/mobile/src/features/inbox/components/TinderView.tsx
@@ -37,7 +37,7 @@ import type {
SignalReportPriority,
SignalReportStatus,
} from "../types";
-import { inboxStatusLabel } from "../utils";
+import { formatSignalReportSummaryMarkdown, inboxStatusLabel } from "../utils";
import { SwipeableReportCard } from "./SwipeableReportCard";
const log = logger.scope("tinder-view");
@@ -423,7 +423,11 @@ export function TinderView({
{/* Summary */}
{expandedReport.summary && (
-
+
)}
{/* Signal count + time */}
diff --git a/apps/mobile/src/features/inbox/utils.test.ts b/apps/mobile/src/features/inbox/utils.test.ts
index 9663998ec..ddb7204b8 100644
--- a/apps/mobile/src/features/inbox/utils.test.ts
+++ b/apps/mobile/src/features/inbox/utils.test.ts
@@ -8,6 +8,7 @@ import type {
import {
buildInboxViewedProperties,
buildReviewerOptions,
+ formatSignalReportSummaryMarkdown,
reviewerMatchesAvailable,
toSuggestedReviewerWriteContent,
} from "./utils";
@@ -61,6 +62,44 @@ function makeReport(
};
}
+describe("formatSignalReportSummaryMarkdown", () => {
+ it.each([
+ {
+ name: "puts section body on a new line after the header",
+ input:
+ "**What's happening:** Error tracking issue keyed on `app:dashboard_query`.",
+ expected:
+ "**What's happening:**\n\nError tracking issue keyed on `app:dashboard_query`.",
+ },
+ {
+ name: "splits consecutive headers packed on one line",
+ input:
+ "**What's happening:** Users hit rate limits. **Root cause:** Limiters are contended. **How to resolve:** Reduce blocking.",
+ expected:
+ "**What's happening:**\n\nUsers hit rate limits.\n\n**Root cause:**\n\nLimiters are contended.\n\n**How to resolve:**\n\nReduce blocking.",
+ },
+ {
+ name: "leaves already-separated headers sane",
+ input:
+ "**What's happening:**\n\nUsers hit rate limits.\n\n**Root cause:**\n\nLimiters are contended.",
+ expected:
+ "**What's happening:**\n\nUsers hit rate limits.\n\n**Root cause:**\n\nLimiters are contended.",
+ },
+ {
+ name: "leaves content without headers unchanged",
+ input: "Plain summary with no structured sections.",
+ expected: "Plain summary with no structured sections.",
+ },
+ {
+ name: "matches headers case-insensitively",
+ input: "**what's happening:** lowercase header body.",
+ expected: "**what's happening:**\n\nlowercase header body.",
+ },
+ ])("$name", ({ input, expected }) => {
+ expect(formatSignalReportSummaryMarkdown(input)).toBe(expected);
+ });
+});
+
describe("buildInboxViewedProperties", () => {
it("emits zero counts for an empty list", () => {
const props = buildInboxViewedProperties([], 0, {
diff --git a/apps/mobile/src/features/inbox/utils.ts b/apps/mobile/src/features/inbox/utils.ts
index cfcd8aa37..e55b6f3bb 100644
--- a/apps/mobile/src/features/inbox/utils.ts
+++ b/apps/mobile/src/features/inbox/utils.ts
@@ -8,6 +8,32 @@ import type {
SuggestedReviewerWriteEntry,
} from "./types";
+const SIGNAL_SUMMARY_SECTION_HEADERS = [
+ "What's happening",
+ "Root cause",
+ "How to resolve",
+] as const;
+
+/**
+ * Inserts blank lines around signal report summary section headers so each
+ * label and its body render on their own line (agent output often packs them
+ * together, e.g. `**What's happening:** text **Root cause:** ...`).
+ */
+export function formatSignalReportSummaryMarkdown(content: string): string {
+ let result = content;
+
+ for (const header of SIGNAL_SUMMARY_SECTION_HEADERS) {
+ const boldHeader = `\\*\\*${header}:\\*\\*`;
+ result = result.replace(
+ new RegExp(`([^\\n])\\s*(${boldHeader})`, "gi"),
+ "$1\n\n$2",
+ );
+ result = result.replace(new RegExp(`(${boldHeader})\\s+`, "gi"), "$1\n\n");
+ }
+
+ return result;
+}
+
export function inboxStatusLabel(status: SignalReportStatus): string {
switch (status) {
case "ready":