diff --git a/apps/dashboard/app/(tenant)/agents/page.tsx b/apps/dashboard/app/(tenant)/agents/page.tsx
index bbb2ad1..39e8010 100644
--- a/apps/dashboard/app/(tenant)/agents/page.tsx
+++ b/apps/dashboard/app/(tenant)/agents/page.tsx
@@ -1,6 +1,7 @@
import type { Metadata } from "next";
import Link from "next/link";
import { CopyPill } from "@ainfera/ui";
+import { Crumbs } from "@/components/v15/Crumbs";
import { getOwnerHandle } from "@/lib/ainfera/proxy";
import { listAgents } from "@/lib/v15/api";
@@ -13,6 +14,14 @@ export default async function AgentsPage() {
return (
<>
+ {/* AIN-251 W4 · shared for cross-page parity. */}
+
+
Agents
diff --git a/apps/dashboard/app/(tenant)/inferences/[id]/InferenceDetailClient.tsx b/apps/dashboard/app/(tenant)/inferences/[id]/InferenceDetailClient.tsx
index 4502527..beadccc 100644
--- a/apps/dashboard/app/(tenant)/inferences/[id]/InferenceDetailClient.tsx
+++ b/apps/dashboard/app/(tenant)/inferences/[id]/InferenceDetailClient.tsx
@@ -215,6 +215,74 @@ export function InferenceDetailClient({ inferenceId, initial }: Props) {
) : null}
+ {/* AIN-266 W3 · candidates card — the routing decision artifact.
+ * Surfaces every model Ainfera Inference considered for this call,
+ * the rank order, q_prior, projected cost, and drop reasons.
+ * Renders only when the api returned a non-empty candidates list
+ * (null on pre-§16 rows + pinned-passthroughs that bypass the
+ * brain). Authed-tenant-only on the wire (§D3 lock). */}
+ {inf.candidates && inf.candidates.length > 0 ? (
+
+
+
+ Candidates ({inf.candidates.length})
+
+
+ the decision · ranked
+
+
+
+
+
+
+ #
+ Model
+ Brand
+ q_prior
+ proj. cost
+ eligible
+ drop reason
+
+
+
+ {inf.candidates.map((c, i) => {
+ const chosen = c.model_slug === inf.model_used;
+ return (
+
+ {c.rank ?? i + 1}
+
+ {c.model_slug ?? "—"}
+ {chosen ? (
+
+ chosen
+
+ ) : null}
+
+ {c.brand_slug ?? "—"}
+ {c.q_prior ?? "—"}
+
+ {c.projected_cost_usd ? fmtCost(c.projected_cost_usd) : "—"}
+
+
+ {c.m_allowed === true ? "yes" : c.m_allowed === false ? "no" : "—"}
+
+ {c.drop_reason ?? "—"}
+
+ );
+ })}
+
+
+
+
+ ) : null}
+
{/* Audit chain block — AIN-182 §4 "Verify with curl" requirement. */}
diff --git a/apps/dashboard/app/(tenant)/inferences/[id]/types.ts b/apps/dashboard/app/(tenant)/inferences/[id]/types.ts
index 327b044..1cb48f9 100644
--- a/apps/dashboard/app/(tenant)/inferences/[id]/types.ts
+++ b/apps/dashboard/app/(tenant)/inferences/[id]/types.ts
@@ -35,4 +35,25 @@ export type InferenceDetail = {
policy_version?: string | null;
cell?: string | null;
routing_rationale?: string | null;
+ /** AIN-266 W3 · routing candidate set. Mirrors §16
+ * routing_outcomes.candidates JSONB. NULL on pre-2026-05-21 rows +
+ * pinned-passthrough calls. AUTHED-tenant-only on the wire (§D3 lock
+ * — never on /v1/audit/public). */
+ candidates?: InferenceCandidate[] | null;
+};
+
+/** One row of the §16 candidate set. Keys mirror the JSONB shape on
+ * routing_outcomes exactly. Decimals come over as strings to preserve
+ * precision through JSON. */
+export type InferenceCandidate = {
+ model_id?: string | null;
+ model_slug?: string | null;
+ brand_slug?: string | null;
+ q_prior?: string | null;
+ price_in_per_mtok_usd?: string | null;
+ price_out_per_mtok_usd?: string | null;
+ m_allowed?: boolean | null;
+ projected_cost_usd?: string | null;
+ drop_reason?: string | null;
+ rank?: number | null;
};
diff --git a/apps/dashboard/app/(tenant)/inferences/page.tsx b/apps/dashboard/app/(tenant)/inferences/page.tsx
index 16785a8..5bd71c0 100644
--- a/apps/dashboard/app/(tenant)/inferences/page.tsx
+++ b/apps/dashboard/app/(tenant)/inferences/page.tsx
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import Link from "next/link";
+import { Crumbs } from "@/components/v15/Crumbs";
import { getOwnerHandle } from "@/lib/ainfera/proxy";
import { publicAuditFeed, publicLeaderboard } from "@/lib/v15/api";
@@ -25,15 +26,14 @@ export default async function InferencesIndexPage() {
return (
<>
-
-
-
- workspace
- /
- inferences
-
-
-
+ {/* AIN-251 W4 · shared
for cross-page parity. */}
+
+
diff --git a/apps/dashboard/app/(tenant)/workflows/page.tsx b/apps/dashboard/app/(tenant)/workflows/page.tsx
index de8d940..ced96a9 100644
--- a/apps/dashboard/app/(tenant)/workflows/page.tsx
+++ b/apps/dashboard/app/(tenant)/workflows/page.tsx
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import Link from "next/link";
+import { Crumbs } from "@/components/v15/Crumbs";
import { getOwnerHandle } from "@/lib/ainfera/proxy";
import { listWorkflows } from "@/lib/v15/api";
@@ -12,6 +13,14 @@ export default async function WorkflowsPage() {
return (
<>
+ {/* AIN-251 W4 · shared
for cross-page parity. */}
+
+