diff --git a/apps/portal/src/components/ShortId.stories.tsx b/apps/portal/src/components/ShortId.stories.tsx
index 55d0563c0..8c2d0daeb 100644
--- a/apps/portal/src/components/ShortId.stories.tsx
+++ b/apps/portal/src/components/ShortId.stories.tsx
@@ -32,6 +32,13 @@ export const CustomLength: Story = {
},
};
+export const FullSubmissionId: Story = {
+ args: { length: FULL_ID.length, label: "submission ID" },
+ play: async ({ canvas }) => {
+ await expect(canvas.getByText(FULL_ID)).toBeVisible();
+ },
+};
+
export const HoverRevealsFullIdAndCopy: Story = {
play: async ({ canvas }) => {
await userEvent.hover(canvas.getByText("abcdef12"));
diff --git a/apps/portal/src/components/ShortId.test.tsx b/apps/portal/src/components/ShortId.test.tsx
index 7123921a4..ddc0f52e5 100644
--- a/apps/portal/src/components/ShortId.test.tsx
+++ b/apps/portal/src/components/ShortId.test.tsx
@@ -27,6 +27,11 @@ describe("ShortId trigger", () => {
render();
expect(screen.getByText("abcd")).toBeTruthy();
});
+
+ it("shows the full submission ID on a detail page", () => {
+ render();
+ expect(screen.getByText(FULL_ID)).toBeTruthy();
+ });
});
describe("ShortId hover + copy", () => {
diff --git a/apps/portal/src/pages/RunDetail.tsx b/apps/portal/src/pages/RunDetail.tsx
index 77ac6b0fa..85916d223 100644
--- a/apps/portal/src/pages/RunDetail.tsx
+++ b/apps/portal/src/pages/RunDetail.tsx
@@ -31,6 +31,7 @@ import { ReportThumbnail } from "@/components/ReportThumbnail";
import { CriteriaBadge } from "@/components/CriteriaBadge";
import { TaskPromptBadge } from "@/components/TaskPromptBadge";
import { AgentBadge } from "@/components/AgentBadge";
+import { ShortId } from "@/components/ShortId";
import { SkillRevisionLinks } from "@/components/SkillRevisionLinks";
import { AlertTriangle, ArrowLeft, Copy, Check, Sparkles, CheckCircle2, XCircle, MinusCircle, FileText, Plus, Download, Loader2, Archive, Video, LayoutGrid, List, Puzzle, RotateCcw, ChevronDown, Clock, Pause, Play, ArrowUpDown, X, Boxes } from "lucide-react";
import { formatDate, formatId, formatDuration, cn } from "@/lib/utils";
@@ -710,6 +711,12 @@ export function RunDetail() {
/>
)}
+ {run.submissionId && (
+ }
+ />
+ )}
{run.maxIterations && }
{(() => {
const totalDuration = activeRun?.turns?.reduce((sum, t) => sum + (t.durationMs ?? 0), 0);
diff --git a/docs/architecture/app-design.md b/docs/architecture/app-design.md
index f1a243262..0910c42d5 100644
--- a/docs/architecture/app-design.md
+++ b/docs/architecture/app-design.md
@@ -681,6 +681,9 @@ A sibling affordance, `components/ShortId.tsx`, applies the same hoverable-toolt
(`formatId`), and on hover the tooltip reveals the full ID plus a copy-to-clipboard button. The
trigger stays an inline `` (not a link) so the row click still navigates to the run; the
copy button calls `e.stopPropagation()` so copying never triggers row navigation.
+Run detail shows the complete submission ID in its metadata when available,
+using the same component for an explicit copy action; older runs without a
+submission ID omit the field.
## Criteria System