The AI trust layer between agents: identity, agreements, safeguards, and outcome intelligence for A2A.
Commit 81afd778
81afd7789b27Merged
aryaamin <[email protected]> · 2 months ago · 11 files · ~11 modified
Description
fix: surface unilateral outcomes immediately
Details
- Commit
- 81afd7789b27
- Parent
- 2a4cc60d2506
apps/dashboard/src/main.tsxmodifiedView file
@@ -946,9 +946,9 @@
946946
947947
function History({ data }: { data: DashboardData }) {948948
const [query, setQuery] = useState('');949-
const [status, setStatus] = useState<'all' | 'pending' | 'active' | 'finalizing' | 'completed'>(950-
'all',951-
);949+
const [status, setStatus] = useState<950+
'all' | 'pending' | 'active' | 'provisional' | 'finalizing' | 'completed'951+
>('all');952952
const journeys = useMemo(() => interactionJourneys(data), [data]);953953
const filtered = useMemo(() => {954954
const needle = query.trim().toLowerCase();@@ -982,7 +982,7 @@
982982
aria-label="Search interaction history"983983
/>984984
<div className="filterRow" aria-label="Interaction status filters">985-
{(['all', 'pending', 'active', 'finalizing', 'completed'] as const).map((value) => (985+
{(['all', 'pending', 'active', 'provisional', 'completed'] as const).map((value) => (986986
<button987987
key={value}988988
className={status === value ? 'filterChip active' : 'filterChip'}@@ -1144,7 +1144,9 @@
11441144
taskCategory: String(interaction.contract?.taskCategory ?? 'general'),11451145
status: String(11461146
conclusion || receipt1147-
? 'completed'1147+
? conclusion?.lifecycle === 'provisional' || receipt?.provisional1148+
? 'provisional'1149+
: 'completed'11481150
: reports.length > 011491151
? 'finalizing'11501152
: (session?.status ?? interaction.status ?? 'pending'),@@ -1211,7 +1213,7 @@
12111213
{latestCheckpoint12121214
? `${Math.round(progress * 100)}% · ${humanize(latestCheckpoint.state)}`12131215
: journey.reports.length1214-
? 'Finalizing'1216+
? 'One side ended'12151217
: 'Awaiting checkpoint'}12161218
</strong>12171219
<small>@@ -1229,7 +1231,9 @@
12291231
</strong>12301232
<small>12311233
{conclusion1232-
? humanize(conclusion.consensus)1234+
? conclusion.lifecycle === 'provisional'1235+
? `${Math.round(Number(conclusion.confidence ?? 0) * 100)}% confidence · peer ${humanize(conclusion.peerReportStatus ?? 'awaiting').toLowerCase()}`1236+
: humanize(conclusion.consensus)12331237
: journey.reports.length === 112341238
? 'One agent finished; confirming with the peer'12351239
: 'Conversation remains active'}@@ -1237,7 +1241,11 @@
12371241
</section>12381242
<section>12391243
<span>Sealed feedback</span>1240-
<strong>{conclusion ? 'Released' : `${submittedFeedback}/2 submitted`}</strong>1244+
<strong>1245+
{journey.feedbackRequests.some((request) => request.status === 'pending')1246+
? `${submittedFeedback}/2 sealed`1247+
: 'Window closed'}1248+
</strong>12411249
<small>{feedbackState(journey.feedbackRequests)}</small>12421250
</section>12431251
<section>@@ -1247,7 +1255,9 @@
12471255
? journey.eligibility.eligible12481256
? `${Math.round(Number(journey.eligibility.sampleWeight ?? 0) * 100)}% weight`12491257
: 'Not eligible'1250-
: 'Not assessed'}1258+
: conclusion?.lifecycle === 'provisional'1259+
? 'Pending corroboration'1260+
: 'Not assessed'}12511261
</strong>12521262
<small>{humanize(journey.eligibility?.contributionMode ?? 'Local only')}</small>12531263
</section>@@ -1292,8 +1302,17 @@
12921302
{conclusion ? (12931303
<section className="outcomeCard">12941304
<div>1295-
<span className="eyebrow">WHAT HAPPENED</span>1305+
<span className="eyebrow">1306+
{conclusion.lifecycle === 'provisional' ? 'PROVISIONAL INSIGHT' : 'WHAT HAPPENED'}1307+
</span>12961308
<h3>{conclusion.summary}</h3>1309+
{conclusion.lifecycle === 'provisional' ? (1310+
<p className="progressWarning">1311+
Based on {conclusion.reportIds?.length ?? 1} participant report. Missing:{' '}1312+
{(conclusion.missingReportAgentIds ?? []).join(', ') || 'peer report'}. This is1313+
usable now at reduced confidence and will be revised if the peer responds.1314+
</p>1315+
) : null}12971316
</div>12981317
{!!conclusion.criteria?.length && (12991318
<ul>@@ -1445,10 +1464,17 @@
14451464
? [14461465
{14471466
at: String(journey.conclusion.generatedAt),1448-
title: 'Bilateral conclusion released',1467+
title:1468+
journey.conclusion.lifecycle === 'provisional'1469+
? 'Provisional insight generated'1470+
: 'Conclusion released',14491471
detail: String(journey.conclusion.summary),14501472
status: String(journey.conclusion.consensus),1451-
tone: journey.conclusion.consensus === 'conflicting' ? 'warn' : 'good',1473+
tone:1474+
journey.conclusion.lifecycle === 'provisional' ||1475+
journey.conclusion.consensus === 'conflicting'1476+
? 'warn'1477+
: 'good',14521478
},14531479
]14541480
: []),@@ -1456,8 +1482,12 @@
14561482
? [14571483
{14581484
at: timestamp(journey.receipt),1459-
title: 'Outcome receipt attested',1460-
detail: 'Contract result, commitment status, and evidence hashes were sealed.',1485+
title: journey.receipt.provisional1486+
? 'Provisional outcome attested'1487+
: 'Outcome receipt attested',1488+
detail: journey.receipt.provisional1489+
? 'The available one-sided report was sealed without claiming peer agreement.'1490+
: 'Contract result, commitment status, and evidence hashes were sealed.',14611491
status: String(journey.receipt.outcome ?? 'signed'),14621492
tone: journey.receipt.outcome === 'failure' ? 'danger' : 'good',14631493
},@@ -1739,6 +1769,9 @@
17391769
function Insights({ data }: { data: DashboardData }) {17401770
const eligible = data.learningEligibility.filter((item) => item.eligible);17411771
const pendingFeedback = data.feedbackRequests.filter((item) => item.status === 'pending');1772+
const provisional = data.interactionConclusions.filter(1773+
(item) => item.lifecycle === 'provisional',1774+
);17421775
return (17431776
<>17441777
<PageHead page="insights" />@@ -1761,8 +1794,41 @@
17611794
<span>17621795
<strong>{pendingFeedback.length}</strong> feedback pending17631796
</span>1797+
<span>1798+
<strong>{provisional.length}</strong> provisional signals1799+
</span>17641800
</div>17651801
</section>1802+
{!!provisional.length && (1803+
<Panel1804+
title="Provisional interaction signals"1805+
subtitle="Available now, kept separate from corroborated reliability history"1806+
>1807+
<div className="learningDecisionList">1808+
{provisional1809+
.slice()1810+
.sort((left, right) => Date.parse(timestamp(right)) - Date.parse(timestamp(left)))1811+
.map((conclusion) => (1812+
<article key={conclusion.conclusionId}>1813+
<StatusPill value="provisional" />1814+
<div>1815+
<strong>{conclusion.summary}</strong>1816+
<small>1817+
{Math.round(Number(conclusion.confidence ?? 0) * 100)}% confidence · peer{' '}1818+
{humanize(conclusion.peerReportStatus ?? 'awaiting').toLowerCase()} ·{' '}1819+
{relativeTime(timestamp(conclusion))}1820+
</small>1821+
<p>1822+
Missing report from{' '}1823+
{(conclusion.missingReportAgentIds ?? []).join(', ') || 'the counterparty'}.1824+
The signal will be revised if more structured evidence arrives.1825+
</p>1826+
</div>1827+
</article>1828+
))}1829+
</div>1830+
</Panel>1831+
)}17661832
<section className="insightGrid">17671833
{data.profiles.length ? (17681834
data.profiles.map((profile) => {@@ -3107,8 +3173,8 @@
31073173
normalized.includes(item),31083174
)31093175
? 'danger'3110-
: ['partial', 'pending', 'challenge', 'conflict', 'expired', 'excluded'].some((item) =>3111-
normalized.includes(item),3176+
: ['partial', 'pending', 'provisional', 'challenge', 'conflict', 'expired', 'excluded'].some(3177+
(item) => normalized.includes(item),31123178
)31133179
? 'warn'31143180
: 'neutral';apps/dashboard/src/preview.tsmodifiedView file
Loading diff…
docs/ARCHITECTURE.mdmodifiedView file
Loading diff…
docs/PRODUCTION_VERIFICATION.mdmodifiedView file
Loading diff…
docs/PROTOCOL_V0.1.mdmodifiedView file
Loading diff…
packages/core/src/index.tsmodifiedView file
Loading diff…
packages/persistence/src/hosted.tsmodifiedView file
Loading diff…
packages/protocol/src/index.tsmodifiedView file
Loading diff…
schemas/v0.1/interaction_conclusion.schema.jsonmodifiedView file
Loading diff…
schemas/v0.1/receipt.schema.jsonmodifiedView file
Loading diff…
tests/core.test.tsmodifiedView file
Loading diff…