Skip to content

Commit 6a1a0e5

Browse files
cameroncookecodex
andcommitted
feat(snapshot): Condense snapshot summaries
Render snapshot image lists as grouped trees so path-like prefixes are not repeated. Keep actionable diff entries complete while omitting unchanged image details from diff summaries. Co-Authored-By: Codex CLI <noreply@openai.com>
1 parent ac97610 commit 6a1a0e5

5 files changed

Lines changed: 417 additions & 105 deletions

File tree

packages/mcp-core/src/tools/get-latest-base-snapshot.test.ts

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ describe("get_latest_base_snapshot", () => {
6464
expect(text).toContain("com.emergetools.hackernews");
6565
expect(text).toContain("**Snapshot ID**: 232800");
6666
expect(text).toContain("**Total Images**: 2");
67-
expect(text).toContain("`Home Screen` (Main)");
68-
expect(text).toContain("`Settings` (Settings)");
67+
expect(text).toContain("main_home_screen.png — Home ScreenMain");
68+
expect(text).toContain("settings_page.png — SettingsSettings");
6969
expect(text).toContain("**App Name**: HackerNews");
7070
expect(text).toContain("**Platform**: ios");
7171
expect(text).toContain("**Branch**: main (`abc123de`)");
@@ -84,15 +84,73 @@ describe("get_latest_base_snapshot", () => {
8484
8585
## Images
8686
87-
- \`Home Screen\` (Main) — file: \`snapshots-iphone/main_home_screen.png\`
88-
- \`Settings\` (Settings) — file: \`snapshots-iphone/settings_page.png\`
87+
**Snapshot Images:**
88+
└── snapshots-iphone/
89+
├── main_home_screen.png — Home Screen — Main
90+
└── settings_page.png — Settings — Settings
8991
9092
## Next Steps
9193
9294
- To view a specific image, use \`get_sentry_resource(url="https://sentry.sentry.io/preprod/snapshots/232800/?selectedSnapshot=<image_file_name>")\`"
9395
`);
9496
});
9597

98+
it("groups large latest-base image lists by shared path prefixes", async () => {
99+
const largeLatestBaseFixture = {
100+
...latestBaseFixture,
101+
images: [
102+
{
103+
display_name: "Kenya",
104+
group: "FeaturedProductCard",
105+
image_file_name:
106+
"snapshots-iphone-17e/test_CoffeeProductCards.swift_FeaturedProductCard_Kenya.png",
107+
},
108+
{
109+
display_name: "Ethiopia",
110+
group: "FeaturedProductCard",
111+
image_file_name:
112+
"snapshots-iphone-17e/test_CoffeeProductCards.swift_FeaturedProductCard_Ethiopia.png",
113+
},
114+
{
115+
display_name: "Kenya",
116+
group: "FeaturedProductCard",
117+
image_file_name:
118+
"snapshots-iphone-17-pro-max/test_CoffeeProductCards.swift_FeaturedProductCard_Kenya.png",
119+
},
120+
],
121+
};
122+
123+
mswServer.use(
124+
http.get(
125+
"https://sentry.io/api/0/organizations/sentry/preprodartifacts/snapshots/latest-base/",
126+
() => HttpResponse.json(largeLatestBaseFixture),
127+
{ once: true },
128+
),
129+
);
130+
131+
const result = await getLatestBaseSnapshot.handler(
132+
{
133+
organizationSlug: "sentry",
134+
appId: "com.emergetools.hackernews",
135+
branch: null,
136+
project: null,
137+
regionUrl: null,
138+
},
139+
getServerContext(),
140+
);
141+
const text = result as string;
142+
143+
expect(text).toContain("**Total Images**: 3");
144+
expect(text).toContain("├── snapshots-iphone-17e/");
145+
expect(text).toContain("└── snapshots-iphone-17-pro-max/");
146+
expect(text).toContain(
147+
"test_CoffeeProductCards.swift_FeaturedProductCard_Ethiopia.png — Ethiopia — FeaturedProductCard",
148+
);
149+
expect(text).toContain(
150+
"test_CoffeeProductCards.swift_FeaturedProductCard_Kenya.png — Kenya — FeaturedProductCard",
151+
);
152+
});
153+
96154
it("passes branch filter to endpoint", async () => {
97155
mswServer.use(
98156
http.get(

packages/mcp-core/src/tools/get-latest-base-snapshot.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { defineTool } from "../internal/tool-helpers/define";
44
import { apiServiceFromContext } from "../internal/tool-helpers/api";
55
import type { ServerContext } from "../types";
66
import { ParamOrganizationSlug, ParamRegionUrl } from "../schema";
7+
import { renderSnapshotImageTreeSection } from "./snapshot-formatting";
78

89
export default defineTool({
910
name: "get_latest_base_snapshot",
@@ -122,15 +123,12 @@ export default defineTool({
122123

123124
if (images.length > 0) {
124125
sections.push("\n## Images\n");
125-
for (const img of images) {
126-
const name = img.display_name || img.image_file_name || "unknown";
127-
const group = img.group ? ` (${img.group})` : "";
128-
const file =
129-
img.image_file_name && img.image_file_name !== img.display_name
130-
? ` — file: \`${img.image_file_name}\``
131-
: "";
132-
sections.push(`- \`${name}\`${group}${file}`);
133-
}
126+
sections.push(
127+
...renderSnapshotImageTreeSection(
128+
"Snapshot Images",
129+
images.map((image) => ({ image })),
130+
),
131+
);
134132
}
135133

136134
sections.push(

packages/mcp-core/src/tools/get-snapshot-details.test.ts

Lines changed: 142 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -291,15 +291,17 @@ describe("get_snapshot_details", () => {
291291
expect(text).toContain("**PR**: #789");
292292
expect(text).toContain("**Approval**: requires_approval");
293293
expect(text).toContain(
294-
"`login_screen.png` (auth) — file: `snapshots-iphone-16/auth_login_screen.png` — 12.5% diff",
294+
"auth_login_screen.png — 12.5% diff — login_screen.png — auth",
295295
);
296296
expect(text).toContain(
297-
"`dashboard.png` (main) — file: `snapshots-iphone-16/main_dashboard.png` — 2.1% diff",
297+
"main_dashboard.png — 2.1% diff — dashboard.png — main",
298298
);
299299
expect(text).toContain("**Added:**");
300-
expect(text).toContain("`new_modal.png` (dialogs)");
300+
expect(text).toContain("dialogs_new_modal.png — new_modal.pngdialogs");
301301
expect(text).toContain("**Renamed:**");
302-
expect(text).toContain("`preferences_page.png` → `settings_page.png`");
302+
expect(text).toContain(
303+
"settings_page.png — previous: preferences_page.png — settings",
304+
);
303305
expect(text).toContain("get_sentry_resource");
304306
expect(text).toMatchInlineSnapshot(`
305307
"# Snapshot 231949 in **sentry**
@@ -310,7 +312,7 @@ describe("get_snapshot_details", () => {
310312
- **Type**: diff
311313
- **State**: visible
312314
- **Project ID**: 12345
313-
- **Images**: 4 total (2 changed, 1 added, 0 removed, 1 renamed, 10 unchanged, 0 errored)
315+
- **Images**: 4 total (2 changed, 1 added, 0 removed, 1 renamed, 10 unchanged, 0 errored, 0 skipped)
314316
315317
## VCS Info
316318
@@ -324,21 +326,17 @@ describe("get_snapshot_details", () => {
324326
## Changes
325327
326328
**Changed:**
327-
- \`login_screen.png\` (auth) — file: \`snapshots-iphone-16/auth_login_screen.png\` — 12.5% diff
328-
- \`dashboard.png\` (main) — file: \`snapshots-iphone-16/main_dashboard.png\` — 2.1% diff
329+
└── snapshots-iphone-16/
330+
├── auth_login_screen.png — 12.5% diff — login_screen.png — auth
331+
└── main_dashboard.png — 2.1% diff — dashboard.png — main
329332
330333
**Added:**
331-
- \`new_modal.png\` (dialogs) — file: \`snapshots-iphone-16/dialogs_new_modal.png\`
334+
└── snapshots-iphone-16/
335+
└── dialogs_new_modal.png — new_modal.png — dialogs
332336
333337
**Renamed:**
334-
- \`preferences_page.png\` → \`settings_page.png\`
335-
336-
## All Images
337-
338-
- \`login_screen.png\` (auth) — file: \`snapshots-iphone-16/auth_login_screen.png\`
339-
- \`dashboard.png\` (main) — file: \`snapshots-iphone-16/main_dashboard.png\`
340-
- \`new_modal.png\` (dialogs) — file: \`snapshots-iphone-16/dialogs_new_modal.png\`
341-
- \`settings_page.png\` (settings) — file: \`snapshots-iphone-16/settings_page.png\`
338+
└── snapshots-iphone-16/
339+
└── settings_page.png — previous: preferences_page.png — settings
342340
343341
## Next Steps
344342
@@ -472,7 +470,134 @@ describe("get_snapshot_details", () => {
472470
);
473471
const text = result as string;
474472
expect(text).toContain("**Type**: solo");
475-
expect(text).toContain("`Dark mode` (Content View)");
473+
expect(text).toContain(
474+
"Content_View_Dark_mode.png — Dark mode — Content View",
475+
);
476+
});
477+
478+
it("groups large diff summaries without listing unchanged details", async () => {
479+
const largeFixture = {
480+
...snapshotFixture,
481+
changed_count: 3,
482+
added_count: 1,
483+
removed_count: 1,
484+
renamed_count: 1,
485+
unchanged_count: 42,
486+
errored_count: 1,
487+
skipped_count: 2,
488+
images: [
489+
...snapshotFixture.images,
490+
{
491+
display_name: "unchanged_detail.png",
492+
group: "unchanged",
493+
image_file_name: "snapshots-iphone-17e/unchanged_detail.png",
494+
},
495+
],
496+
changed: [
497+
{
498+
head_image: {
499+
display_name: "Kenya",
500+
group: "FeaturedProductCard",
501+
image_file_name:
502+
"snapshots-iphone-17e/test_CoffeeProductCards.swift_FeaturedProductCard_Kenya.png",
503+
},
504+
diff: 0.2605,
505+
},
506+
{
507+
head_image: {
508+
display_name: "Ethiopia",
509+
group: "FeaturedProductCard",
510+
image_file_name:
511+
"snapshots-iphone-17e/test_CoffeeProductCards.swift_FeaturedProductCard_Ethiopia.png",
512+
},
513+
diff: 0.2341,
514+
},
515+
{
516+
head_image: {
517+
display_name: "Kenya",
518+
group: "FeaturedProductCard",
519+
image_file_name:
520+
"snapshots-iphone-17-pro-max/test_CoffeeProductCards.swift_FeaturedProductCard_Kenya.png",
521+
},
522+
diff: 0.234,
523+
},
524+
],
525+
added: [
526+
{
527+
display_name: "New Cart",
528+
group: "Cart",
529+
image_file_name: "snapshots-iphone-17e/test_Cart.swift_NewCart.png",
530+
},
531+
],
532+
removed: [
533+
{
534+
display_name: "Old Cart",
535+
group: "Cart",
536+
image_file_name: "snapshots-iphone-17e/test_Cart.swift_OldCart.png",
537+
},
538+
],
539+
renamed: [
540+
{
541+
head_image: {
542+
display_name: "Settings",
543+
group: "Settings",
544+
image_file_name:
545+
"snapshots-iphone-17e/test_Settings.swift_Settings.png",
546+
},
547+
base_image: {
548+
display_name: "Preferences",
549+
group: "Settings",
550+
image_file_name:
551+
"snapshots-iphone-17e/test_Settings.swift_Preferences.png",
552+
},
553+
},
554+
],
555+
errored: [
556+
{
557+
head_image: {
558+
display_name: "Error State",
559+
group: "Errors",
560+
image_file_name:
561+
"snapshots-iphone-17e/test_Error.swift_ErrorState.png",
562+
},
563+
},
564+
],
565+
};
566+
567+
mswServer.use(
568+
http.get(
569+
"https://sentry.io/api/0/organizations/sentry/preprodartifacts/snapshots/231949/",
570+
() => HttpResponse.json(largeFixture),
571+
{ once: true },
572+
),
573+
);
574+
575+
const result = await getSnapshotDetails.handler(
576+
{
577+
snapshotUrl: "https://sentry.sentry.io/preprod/snapshots/231949/",
578+
organizationSlug: null,
579+
snapshotId: null,
580+
selectedSnapshot: null,
581+
regionUrl: null,
582+
},
583+
getServerContext(),
584+
);
585+
const text = result as string;
586+
587+
expect(text).toContain(
588+
"3 changed, 1 added, 1 removed, 1 renamed, 42 unchanged, 1 errored, 2 skipped",
589+
);
590+
expect(text).toContain("└── snapshots-iphone-17-pro-max/");
591+
expect(text).toContain("├── snapshots-iphone-17e/");
592+
expect(text).toContain(
593+
"test_CoffeeProductCards.swift_FeaturedProductCard_Kenya.png — 26.05% diff — Kenya — FeaturedProductCard",
594+
);
595+
expect(text).toContain("**Added:**");
596+
expect(text).toContain("**Removed:**");
597+
expect(text).toContain("**Renamed:**");
598+
expect(text).toContain("**Errored:**");
599+
expect(text).not.toContain("## All Images");
600+
expect(text).not.toContain("unchanged_detail.png");
476601
});
477602

478603
it("returns head, base, and diff images for changed comparison", async () => {

0 commit comments

Comments
 (0)