From 9ad387315c8a370fb2a3387e177f63037537ce1c Mon Sep 17 00:00:00 2001 From: mj-deving Date: Sun, 2 Aug 2026 02:32:14 +0200 Subject: [PATCH] feat(directory): clarify endpoint evidence state --- .../[seller]/[listingId]/[version]/page.tsx | 31 ++++---- .../src/components/DirectoryExplorer.tsx | 17 ++--- .../components/directory-evidence-state.ts | 75 +++++++++++++++++++ .../test/directory-evidence-state.test.ts | 73 ++++++++++++++++++ 4 files changed, 171 insertions(+), 25 deletions(-) create mode 100644 reference-implementations/dacs-directory/src/components/directory-evidence-state.ts create mode 100644 reference-implementations/dacs-directory/test/directory-evidence-state.test.ts diff --git a/reference-implementations/dacs-directory/app/service/[seller]/[listingId]/[version]/page.tsx b/reference-implementations/dacs-directory/app/service/[seller]/[listingId]/[version]/page.tsx index 9813f10..fd6e883 100644 --- a/reference-implementations/dacs-directory/app/service/[seller]/[listingId]/[version]/page.tsx +++ b/reference-implementations/dacs-directory/app/service/[seller]/[listingId]/[version]/page.tsx @@ -8,7 +8,7 @@ import { inspectServicePath } from "@/src/catalog/inspection"; import { isCounterpartyEvidenceDemoListing } from "@/src/catalog/counterpartyEvidence"; import { loadCatalog } from "@/src/catalog/store"; import { safeJsonLd } from "@/src/components/structuredData"; -import { safePublicEndpoint } from "@/src/catalog/publicEndpoint"; +import { directoryEvidenceState } from "@/src/components/directory-evidence-state"; export const dynamic = "force-dynamic"; @@ -45,22 +45,18 @@ export default async function ServicePage({ params }: { params: Promise const found = findService(sellerClaim, listingId, version); if (!found) notFound(); const { seller, listing } = found; - const identity = tierMeta(seller.identityTier ?? "self-declared"); + const evidence = directoryEvidenceState(listing, seller); + const identity = tierMeta(evidence.identityTier); const apiHref = `/api/dacs/listings/${encodeURIComponent(listing.listingId)}/${listing.version}?seller=${encodeURIComponent(seller.primaryClaim)}`; const inspectHref = inspectServicePath(listing); - const engagementEndpoint = safePublicEndpoint(listing.publicEndpoint); + const engagementEndpoint = evidence.endpoint.url; const isCounterpartyEvidenceDemo = isCounterpartyEvidenceDemoListing(seller.primaryClaim, listing); const isFixtureListing = listing.anchor.kind === "fixture"; - const listingProfileLabel = isFixtureListing - ? "fixture listing" - : listing.artifactProfile === "dacs-v0.1" - ? "current DACS listing" - : "legacy SDK listing"; const technicalArtifactProfile = isFixtureListing ? "fixture-listing" : (listing.artifactProfile ?? "legacy-sdk-v0.1"); const listingArtifactLabel = isFixtureListing ? "View fixture contract" : "View signed listing artifact"; - const noEndpointNote = isFixtureListing - ? "This fixture has no live engagement endpoint. Inspect the fixture contract before coordinating off-directory." - : "This seller has not published a safe HTTPS engagement endpoint. Inspect the signed artifact before coordinating off-directory."; + const endpointDeclarationNote = isFixtureListing && evidence.endpoint.kind === "not-declared" + ? "This fixture declares no live engagement endpoint." + : `${evidence.endpoint.explanation}.`; const structuredData = { "@context": "https://schema.org", "@type": "Service", @@ -86,7 +82,7 @@ export default async function ServicePage({ params }: { params: Promise
Offered by {seller.displayName} {identity.label} - {listingProfileLabel} + {evidence.listing.label} {seller.ownerRegistered && owner-registered} {!isFixtureListing && !seller.ownerRegistered && seller.discovered && discovered on-chain} {isFixtureListing && not chain anchored} @@ -102,7 +98,10 @@ export default async function ServicePage({ params }: { params: Promise Inspect service View seller evidence
-

{engagementEndpoint ? "The HTTPS endpoint is advertised inside the signed listing; it is a contact route, not a cryptographic trust anchor." : noEndpointNote}

+

+ {endpointDeclarationNote} Reachability: {evidence.reachability.label}. + {engagementEndpoint && " A declared contact route is not a health check or cryptographic trust anchor."} +

@@ -120,11 +119,13 @@ export default async function ServicePage({ params }: { params: Promise
diff --git a/reference-implementations/dacs-directory/src/components/DirectoryExplorer.tsx b/reference-implementations/dacs-directory/src/components/DirectoryExplorer.tsx index 13eb38b..8dfedeb 100644 --- a/reference-implementations/dacs-directory/src/components/DirectoryExplorer.tsx +++ b/reference-implementations/dacs-directory/src/components/DirectoryExplorer.tsx @@ -5,6 +5,7 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; import { activeCatalogSellers } from "@/src/catalog/discovery"; import type { ListingSummary, SellerRecord } from "@/src/catalog/types"; +import { directoryEvidenceState } from "./directory-evidence-state"; import { deliveryLabel, pricingModelLabel, publishedPriceLabel, railLabel, tierMeta } from "./labels"; const sellerTier = (seller: SellerRecord) => seller.identityTier ?? "self-declared"; @@ -14,13 +15,6 @@ const sellerTier = (seller: SellerRecord) => seller.identityTier ?? "self-declar const provenance = (seller: SellerRecord) => seller.ownerRegistered ? "owner-registered" : seller.discovered ? "found on-chain" : "unverified submission"; -const listingTrustLabel = (listing: ListingSummary) => - listing.anchor.kind === "fixture" - ? "fixture listing" - : listing.artifactProfile === "dacs-v0.1" - ? "current DACS listing" - : "legacy SDK listing"; - const listingProvenance = (seller: SellerRecord, listing: ListingSummary) => listing.anchor.kind === "fixture" ? "fixture catalog" : provenance(seller); @@ -213,14 +207,15 @@ export default function DirectoryExplorer({ sellers, indexed }: { sellers: Selle
{filtered.map(({ listing, seller }) => { - const trust = tierMeta(sellerTier(seller)); + const evidence = directoryEvidenceState(listing, seller); + const trust = tierMeta(evidence.identityTier); const href = `/service/${encodeURIComponent(seller.primaryClaim)}/${encodeURIComponent(listing.listingId)}/${listing.version}`; const jsonHref = `/api/dacs/listings/${encodeURIComponent(listing.listingId)}/${listing.version}?seller=${encodeURIComponent(seller.primaryClaim)}`; return (
{listing.offering.category.replaceAll(".", " / ")} - {listingTrustLabel(listing)} + {evidence.listing.label}

{listing.offering.title}

@@ -231,6 +226,8 @@ export default function DirectoryExplorer({ sellers, indexed }: { sellers: Selle

pricing{listing.pricing.priceHint ? publishedPriceLabel(listing.pricing) : pricingModelLabel(listing.pricing, listing.offering.negotiation)}
delivery{listing.offering.delivery?.[0] ? deliveryLabel(listing.offering.delivery[0]) : "Not stated"}
+
endpoint{evidence.endpoint.label}
+
reachability{evidence.reachability.label}
identity @@ -242,7 +239,7 @@ export default function DirectoryExplorer({ sellers, indexed }: { sellers: Selle record - {seller.reputation.completed}/{seller.reputation.totalAgreements} strict bundles + {evidence.deals.label}
diff --git a/reference-implementations/dacs-directory/src/components/directory-evidence-state.ts b/reference-implementations/dacs-directory/src/components/directory-evidence-state.ts new file mode 100644 index 0000000..3dbd708 --- /dev/null +++ b/reference-implementations/dacs-directory/src/components/directory-evidence-state.ts @@ -0,0 +1,75 @@ +import { safePublicEndpoint } from "../catalog/publicEndpoint.js"; +import type { IdentityTier, ListingSummary, SellerRecord } from "../catalog/types.js"; + +export const UNMEASURED_REACHABILITY_LABEL = "Not measured by Directory"; + +export type DirectoryEvidenceState = Readonly<{ + listing: Readonly<{ + kind: "fixture" | "current" | "legacy"; + label: "fixture listing" | "current DACS listing" | "legacy SDK listing"; + }>; + endpoint: Readonly<{ + kind: "declared" | "not-declared" | "unsafe-declaration"; + label: "Declared HTTPS endpoint" | "No endpoint declared" | "Endpoint declaration not shown"; + explanation: string; + url?: string; + }>; + reachability: Readonly<{ + kind: "not-measured"; + label: typeof UNMEASURED_REACHABILITY_LABEL; + }>; + identityTier: IdentityTier; + deals: Readonly<{ + completed: number; + total: number; + label: string; + explanation: string; + }>; +}>; + +export function directoryEvidenceState( + listing: ListingSummary, + seller: Pick, +): DirectoryEvidenceState { + const endpoint = safePublicEndpoint(listing.publicEndpoint); + const hasEndpointDeclaration = typeof listing.publicEndpoint === "string" && listing.publicEndpoint.length > 0; + const listingState = listing.anchor.kind === "fixture" + ? { kind: "fixture" as const, label: "fixture listing" as const } + : listing.artifactProfile === "dacs-v0.1" + ? { kind: "current" as const, label: "current DACS listing" as const } + : { kind: "legacy" as const, label: "legacy SDK listing" as const }; + const completed = seller.reputation.completed; + const total = seller.reputation.totalAgreements; + + return Object.freeze({ + listing: Object.freeze(listingState), + endpoint: Object.freeze(endpoint + ? { + kind: "declared" as const, + label: "Declared HTTPS endpoint" as const, + explanation: "A safe HTTPS contact route is declared in the listing", + url: endpoint, + } + : hasEndpointDeclaration + ? { + kind: "unsafe-declaration" as const, + label: "Endpoint declaration not shown" as const, + explanation: "The declared endpoint is not a safe HTTPS URL and is not linked", + } + : { + kind: "not-declared" as const, + label: "No endpoint declared" as const, + explanation: "The listing declares no engagement endpoint", + }), + reachability: Object.freeze({ kind: "not-measured" as const, label: UNMEASURED_REACHABILITY_LABEL }), + identityTier: seller.identityTier ?? "self-declared", + deals: Object.freeze({ + completed, + total, + label: `${completed} strict-verified / ${total} agreement${total === 1 ? "" : "s"}`, + explanation: total === 0 + ? "No verified two-sided bundle history yet" + : "Both parties' signed copies must verify and agree before a bundle counts", + }), + }); +} diff --git a/reference-implementations/dacs-directory/test/directory-evidence-state.test.ts b/reference-implementations/dacs-directory/test/directory-evidence-state.test.ts new file mode 100644 index 0000000..7721e93 --- /dev/null +++ b/reference-implementations/dacs-directory/test/directory-evidence-state.test.ts @@ -0,0 +1,73 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { directoryEvidenceState, UNMEASURED_REACHABILITY_LABEL } from "../src/components/directory-evidence-state.js"; +import type { ListingSummary, SellerRecord } from "../src/catalog/types.js"; + +const listing = (overrides: Partial = {}): ListingSummary => ({ + listingId: "service", + version: 1, + contentHash: "a".repeat(64), + anchor: { kind: "storage-program", locator: "stor-listing" }, + seller: { primaryClaim: "key:seller", displayName: "Seller" }, + artifactProfile: "dacs-v0.1", + offering: { title: "Service", category: "services.other", tags: [] }, + pricing: {}, + status: "active", + catalogObservedAt: 1, + ...overrides, +}); + +const seller = (completed = 0, totalAgreements = 0): Pick => ({ + identityTier: "verified", + reputation: { completed, totalAgreements, completionRate: totalAgreements ? completed / totalAgreements : null }, +}); + +test("separates listing evidence, endpoint declaration, and unmeasured reachability", () => { + const state = directoryEvidenceState(listing({ publicEndpoint: "https://agent.example/jobs" }), seller(2, 3)); + assert.deepEqual(state.listing, { kind: "current", label: "current DACS listing" }); + assert.deepEqual(state.endpoint, { + kind: "declared", + label: "Declared HTTPS endpoint", + explanation: "A safe HTTPS contact route is declared in the listing", + url: "https://agent.example/jobs", + }); + assert.deepEqual(state.reachability, { kind: "not-measured", label: UNMEASURED_REACHABILITY_LABEL }); + assert.equal(state.identityTier, "verified"); + assert.equal(state.deals.label, "2 strict-verified / 3 agreements"); + assert.match(state.deals.explanation, /Both parties/); +}); + +test("does not turn a missing endpoint into a service failure", () => { + const state = directoryEvidenceState(listing({ publicEndpoint: undefined }), seller()); + assert.deepEqual(state.endpoint, { + kind: "not-declared", + label: "No endpoint declared", + explanation: "The listing declares no engagement endpoint", + }); + assert.equal(state.reachability.label, "Not measured by Directory"); + assert.equal(state.deals.label, "0 strict-verified / 0 agreements"); + assert.equal(state.deals.explanation, "No verified two-sided bundle history yet"); +}); + +test("distinguishes unsafe declarations without exposing or linking them", () => { + for (const publicEndpoint of ["http://agent.example", "https://alice@agent.example"]) { + const state = directoryEvidenceState(listing({ publicEndpoint }), seller()); + assert.deepEqual(state.endpoint, { + kind: "unsafe-declaration", + label: "Endpoint declaration not shown", + explanation: "The declared endpoint is not a safe HTTPS URL and is not linked", + }); + assert.equal(state.reachability.label, "Not measured by Directory"); + } +}); + +test("keeps fixture and legacy listing evidence visibly distinct", () => { + assert.deepEqual( + directoryEvidenceState(listing({ anchor: { kind: "fixture", locator: "fixture://service" }, artifactProfile: "fixture-listing" }), seller()).listing, + { kind: "fixture", label: "fixture listing" }, + ); + assert.deepEqual( + directoryEvidenceState(listing({ artifactProfile: "legacy-sdk-v0.1" }), seller()).listing, + { kind: "legacy", label: "legacy SDK listing" }, + ); +});