- {/* Posture header */}
+ {/* Canonical TrustHeader — institutional reading order on the
+ readiness surface. PREVIEW variant because this surface
+ renders a public/anonymous exploration view before claim. */}
{snapshot && (
-
-
-
{snapshot.name}
-
NPI {snapshot.npi}
-
-
+ <>
+
l.status === 'verified')?.source ?? 'preview'}
+ runId={`readiness-${snapshot.generatedAt}`}
+ />
+
{snapshot.score !== null
@@ -117,7 +124,7 @@ export default function ReadinessSurface() {
:
}
-
+ >
)}
{/* Live state log */}
diff --git a/apps/web/app/passport/[id]/PassportEntityClient.tsx b/apps/web/app/passport/[id]/PassportEntityClient.tsx
index 5485f229..626136e6 100644
--- a/apps/web/app/passport/[id]/PassportEntityClient.tsx
+++ b/apps/web/app/passport/[id]/PassportEntityClient.tsx
@@ -5,6 +5,7 @@ import Link from 'next/link';
import PassportWallet from '@/components/passport/PassportWallet';
import { Button } from '@/components/ui/button';
import { TrustStateCard } from '@/components/trust/TrustStateCard';
+import { TrustHeader } from '@/components/trust';
import { fetchPassportEntity } from '@/lib/api';
import type { PassportData } from '@/lib/trust/passport-contract';
import { KnowledgeInboxPanel } from '@/components/knowledge-inbox/KnowledgeInboxPanel';
@@ -74,8 +75,30 @@ export default function PassportEntityClient({ entityId }: PassportEntityClientP
// in classification — see lib/knowledge-inbox/classifyInboxItem.ts.
const inboxItems: KnowledgeInboxItem[] = [];
+ // Canonical TrustHeader — single source for the institutional reading
+ // order on the passport surface. Adopts Lane B primitives without
+ // changing the existing PassportWallet rendering below.
+ // Channel = the first checked launch-spine source; ownership and runId
+ // are stubbed where data isn't threaded yet (Lane D plumbing).
+ const channel = passport.sources?.checked?.[0] ?? 'unknown';
+ const ownershipClaimant = passport.identity.displayName;
+
return (
+
+
+
;
+ // Canonical TrustHeader at the top of the review surface. Channel is
+ // derived from the first verified lane; runId uses the loopId thread
+ // that the audit pipeline keys on. Ownership defaults to UNCLAIMED
+ // because employer-review entry points don't currently thread the
+ // claim state (Lane D plumbing).
+ const channel = data.lanes.find((l) => l.status === 'verified')?.source ?? 'review';
+ const earliestCheck = data.lanes
+ .map((l) => l.checkedAt)
+ .filter((t): t is number => typeof t === 'number')
+ .sort((a, b) => b - a)[0];
+ const checkedAtIso = earliestCheck ? new Date(earliestCheck).toISOString() : null;
+
+ return (
+
+
+
+
+ );
}
diff --git a/apps/web/components/passport/PassportWallet.tsx b/apps/web/components/passport/PassportWallet.tsx
index 2ae9fcee..8c0ae21f 100644
--- a/apps/web/components/passport/PassportWallet.tsx
+++ b/apps/web/components/passport/PassportWallet.tsx
@@ -40,6 +40,7 @@ import { PassportTrustPosture } from '@/components/passport/PassportTrustPosture
import { useTrackEvent } from '@/lib/learning/useTrackEvent';
import { EvidenceDisclosureCard } from '@/components/trust/EvidenceDisclosureCard';
import { PassportSourceCoveragePanel } from '@/components/trust/PassportSourceCoveragePanel';
+import { CheckedAtStamp } from '@/components/trust';
import { SharePacketModal } from '@/components/passport/SharePacketModal';
import { TrustStateCard } from '@/components/trust/TrustStateCard';
import { DivergenceSummaryCard } from '@/components/trust/DivergenceSummaryCard';
@@ -171,7 +172,10 @@ function buildIdentitySection(passport: PassportData): AccordionItem {
-
+
+ Last check
+
+
),
};
diff --git a/apps/web/components/proof/LanePanel.tsx b/apps/web/components/proof/LanePanel.tsx
index 45704c3a..208db040 100644
--- a/apps/web/components/proof/LanePanel.tsx
+++ b/apps/web/components/proof/LanePanel.tsx
@@ -12,6 +12,7 @@ import {
STATUS_COLORS, STATUS_EXPLANATIONS, KNOWN_LANES,
type LaneSnapshot, type SourceStatus,
} from './trust-types';
+import { CheckedAtStamp, RunIdentity } from '@/components/trust';
// ─── Split-Pane Layout ────────────────────────────────────────────
@@ -144,17 +145,24 @@ function LaneDetail({
{lane.checkedAt && (
-
+
+ Checked at
+
+
)}
{lane.value && (
)}
{lane.receiptId && (
-
+
+ Receipt ID
+
+
)}
@@ -165,7 +173,17 @@ function LaneDetail({
receipt_id{lane.receiptId.slice(0, 16)}…
source{def.source}
- {lane.checkedAt &&
checked_at{lane.checkedAt}
}
+ {lane.checkedAt && (
+
+ checked_at
+
+
+ )}