diff --git a/apps/web/app/holder/readiness/ReadinessSurface.tsx b/apps/web/app/holder/readiness/ReadinessSurface.tsx index 2c6271ca..c470f0d3 100644 --- a/apps/web/app/holder/readiness/ReadinessSurface.tsx +++ b/apps/web/app/holder/readiness/ReadinessSurface.tsx @@ -17,6 +17,7 @@ import { ProofSplitPane } from '@/components/proof/LanePanel'; import { LiveStateLog, buildStateLog } from '@/components/proof/LiveStateLog'; import { PostureBadge, ProofTierBadge, MetricBadge } from '@/components/proof/TrustLabel'; import type { ReadinessSnapshot, StateLogEntry, LaneSnapshot } from '@/components/proof/trust-types'; +import { TrustHeader } from '@/components/trust'; // ─── Demo/fallback state for when no API is wired ───────────────── // Replace with real API call in production @@ -102,14 +103,20 @@ export default function ReadinessSurface() {
- {/* 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 + +
+ )}
) : (