From 3a6ff03ae81efe5f4328f8233c6b193142be646a Mon Sep 17 00:00:00 2001 From: maximusrufus Date: Fri, 16 Oct 2026 08:16:23 -0700 Subject: [PATCH 1/6] fix: resolve Biome lint errors in web-client and docs SVG - Add explicit type="button" to buttons; mark decorative SVGs aria-hidden - Replace `any` and non-null assertions with typed/guarded code - Add fetchMandate to sendToAgent deps (stable callback); document intentional dependency lists with biome-ignore comments - Drop dead code and unused imports in mandateEntries - Strip XML prolog/DOCTYPE from mandate_delegation_user_credential.svg, add a , and a generic font fallback Verified locally: biome lint, eslint, tsc --noEmit and vite build pass. --- code/web-client/src/App.tsx | 9 +++++---- .../src/components/InventoryOptionsCard.tsx | 7 ++++--- .../src/components/MandateApproval.tsx | 16 ++++++++-------- code/web-client/src/components/MandateCard.tsx | 5 +++-- .../src/components/MessageRenderer.tsx | 4 ++-- .../web-client/src/components/MonitoringCard.tsx | 2 +- code/web-client/src/components/ReceiptCard.tsx | 2 +- .../web-client/src/components/UserActionCard.tsx | 2 +- code/web-client/src/hooks/useChat.ts | 7 ++++--- code/web-client/src/main.tsx | 5 ++++- code/web-client/src/utils/mandateEntries.ts | 8 ++++---- .../src/utils/productPreviewUnavailable.ts | 2 +- .../mandate_delegation_user_credential.svg | 2 +- 13 files changed, 39 insertions(+), 32 deletions(-) diff --git a/code/web-client/src/App.tsx b/code/web-client/src/App.tsx index a6ddb758..4de73ffc 100644 --- a/code/web-client/src/App.tsx +++ b/code/web-client/src/App.tsx @@ -25,7 +25,7 @@ const AppHeader = ({usedServers}: {usedServers: Set<string>}) => { }, ]; - const flow = (import.meta as any).env?.VITE_FLOW; + const flow = (import.meta as ImportMeta & {env?: Record<string, string | undefined>}).env?.VITE_FLOW; return ( <div className="app-header"> @@ -68,12 +68,12 @@ const TabBar = ({ mandateCount: number; }) => ( <div className="tab-bar"> - <button + <button type="button" className={`tab ${activeTab === 'chat' ? 'active' : ''}`} onClick={() => onChange('chat')}> Chat </button> - <button + <button type="button" className={`tab ${activeTab === 'mandates' ? 'active' : ''}`} onClick={() => onChange('mandates')}> Mandates @@ -124,7 +124,7 @@ const ChatInput = ({input, setInput, handleSend, loading}: ChatInputProps) => ( disabled={loading} className="chat-input" /> - <button + <button type="button" onClick={() => handleSend({fallbackIfEmpty: DEFAULT_CHAT_STARTER_MESSAGE}) } @@ -144,6 +144,7 @@ export default function App() { const [activeTab, setActiveTab] = useState<TabKey>('chat'); const bottomRef = useRef<HTMLDivElement>(null); + // biome-ignore lint/correctness/useExhaustiveDependencies: scroll to bottom whenever messages change useEffect(() => { if (activeTab === 'chat') { bottomRef.current?.scrollIntoView({behavior: 'smooth'}); diff --git a/code/web-client/src/components/InventoryOptionsCard.tsx b/code/web-client/src/components/InventoryOptionsCard.tsx index 5238213a..9e45f019 100644 --- a/code/web-client/src/components/InventoryOptionsCard.tsx +++ b/code/web-client/src/components/InventoryOptionsCard.tsx @@ -17,6 +17,7 @@ function ItemRow({ onClick?: () => void; }) { return ( + // biome-ignore lint/a11y/useSemanticElements: card contains block content; keyboard handling provided <div className={`item-card ${onClick ? 'clickable' : ''} ${selected ? 'selected' : ''}`} role="button" @@ -26,7 +27,7 @@ function ItemRow({ <div className="row-content"> {selected && ( <div className="selected-icon"> - <svg width="8" height="8" viewBox="0 0 8 8"> + <svg aria-hidden="true" width="8" height="8" viewBox="0 0 8 8"> <path d="M1.5 4l2 2 3-3" stroke="white" @@ -65,7 +66,7 @@ export function InventoryOptionsCard({inventory, onSelect}: Props) { <div className="msg-agent inventory-options-container"> <div className="header-wrapper"> <div className="icon-wrapper"> - <svg width="10" height="10" viewBox="0 0 10 10"> + <svg aria-hidden="true" width="10" height="10" viewBox="0 0 10 10"> <path d="M2 5l2 2 4-4" stroke="#34d399" @@ -113,7 +114,7 @@ export function InventoryOptionsCard({inventory, onSelect}: Props) { )} </div> {canConfirm && ( - <button + <button type="button" onClick={() => { setHasConfirmed(true); onSelect?.(selected); diff --git a/code/web-client/src/components/MandateApproval.tsx b/code/web-client/src/components/MandateApproval.tsx index f8961d64..c9806ad4 100644 --- a/code/web-client/src/components/MandateApproval.tsx +++ b/code/web-client/src/components/MandateApproval.tsx @@ -67,7 +67,7 @@ export function MandateApproval({ {/* Header */} <div className="mandate-header"> <div className="icon-wrapper"> - <svg width="16" height="16" viewBox="0 0 16 16" fill="none"> + <svg aria-hidden="true" width="16" height="16" viewBox="0 0 16 16" fill="none"> <path d="M8 2L10.5 6.5H14L10.5 9L12 13.5L8 11L4 13.5L5.5 9L2 6.5H5.5L8 2Z" strokeLinejoin="round" @@ -133,7 +133,7 @@ export function MandateApproval({ {hasCurrentPrice && ( <div className="reference-price-note"> - Reference price: ${current!.toFixed(2)} (list) + Reference price: ${current?.toFixed(2)} (list) </div> )} </> @@ -148,7 +148,7 @@ export function MandateApproval({ }, { label: 'Current', - value: hasCurrentPrice ? `$${current!.toFixed(2)}` : '—', + value: hasCurrentPrice ? `$${current?.toFixed(2)}` : '—', accent: '#f87171', }, {label: 'Qty', value: String(qty), accent: '#94a3b8'}, @@ -186,7 +186,7 @@ export function MandateApproval({ {/* Payment method row */} <div className="fop-row"> - <svg width="32" height="20" viewBox="0 0 32 20" fill="none"> + <svg aria-hidden="true" width="32" height="20" viewBox="0 0 32 20" fill="none"> <rect width="32" height="20" @@ -243,8 +243,8 @@ export function MandateApproval({ {state === 'idle' && ( <div className="action-buttons"> - <button className="approve-button" onClick={handleSign}> - <svg width="14" height="14" viewBox="0 0 14 14" fill="none"> + <button type="button" className="approve-button" onClick={handleSign}> + <svg aria-hidden="true" width="14" height="14" viewBox="0 0 14 14" fill="none"> <path d="M7 1L8.8 4.8L13 5.3L10 8.2L10.7 12.4L7 10.5L3.3 12.4L4 8.2L1 5.3L5.2 4.8L7 1Z" stroke="white" @@ -255,7 +255,7 @@ export function MandateApproval({ </svg> Approve & Sign </button> - <button className="reject-button" onClick={onReject}> + <button type="button" className="reject-button" onClick={onReject}> Reject </button> </div> @@ -271,7 +271,7 @@ export function MandateApproval({ {state === 'signed' && ( <div className="signed-state"> <div className="success-badge"> - <svg width="10" height="10" viewBox="0 0 10 10"> + <svg aria-hidden="true" width="10" height="10" viewBox="0 0 10 10"> <path d="M2 5l2 2 4-4" stroke="white" diff --git a/code/web-client/src/components/MandateCard.tsx b/code/web-client/src/components/MandateCard.tsx index e315a9aa..4aee772e 100644 --- a/code/web-client/src/components/MandateCard.tsx +++ b/code/web-client/src/components/MandateCard.tsx @@ -202,7 +202,7 @@ function JsonBlock({ value }: { value: unknown }) { function CopyButton({ text }: { text: string }) { const [copied, setCopied] = useState(false); return ( - <button + <button type="button" className="copy-button" onClick={() => { navigator.clipboard.writeText(text); @@ -267,7 +267,7 @@ export function MandateCard({ entry }: Props) { return ( <div className="mandate-viewer-card"> - <button + <button type="button" className="card-header" onClick={() => setExpanded((v) => !v)} aria-expanded={expanded}> @@ -358,6 +358,7 @@ export function MandateCard({ entry }: Props) { <span>Value</span> </div> {sd.disclosures.map((d, i) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: static list, never reordered <div key={i} className="disclosure-row"> <span className="mono small"> {truncate(d.salt, 18)} diff --git a/code/web-client/src/components/MessageRenderer.tsx b/code/web-client/src/components/MessageRenderer.tsx index afaf4e55..6e7d6fd8 100644 --- a/code/web-client/src/components/MessageRenderer.tsx +++ b/code/web-client/src/components/MessageRenderer.tsx @@ -126,7 +126,7 @@ export const MessageRenderer = ({ : undefined; return ( <div className="agent-composite-msg"> - {proseText && proseText.trim() && <AgentProse text={proseText} />} + {proseText?.trim() && <AgentProse text={proseText} />} <ProductPreviewUnavailableCard preview={preview} /> </div> ); @@ -183,7 +183,7 @@ export const MessageRenderer = ({ return ( <div className="agent-composite-msg"> - {proseText && proseText.trim() && <AgentProse text={proseText} />} + {proseText?.trim() && <AgentProse text={proseText} />} <MandateApproval mandate={mandateWithName} trustedSurface={trustedSurface} diff --git a/code/web-client/src/components/MonitoringCard.tsx b/code/web-client/src/components/MonitoringCard.tsx index 5cd066cf..16801c5e 100644 --- a/code/web-client/src/components/MonitoringCard.tsx +++ b/code/web-client/src/components/MonitoringCard.tsx @@ -77,7 +77,7 @@ export function MonitoringCard({ </p> )} {onCheckNow && ( - <button onClick={onCheckNow} className="check-button"> + <button type="button" onClick={onCheckNow} className="check-button"> Check now </button> )} diff --git a/code/web-client/src/components/ReceiptCard.tsx b/code/web-client/src/components/ReceiptCard.tsx index 5a61a6f6..9fc96485 100644 --- a/code/web-client/src/components/ReceiptCard.tsx +++ b/code/web-client/src/components/ReceiptCard.tsx @@ -42,7 +42,7 @@ export function ReceiptCard({ purchase, itemName }: Props) { <div className="receipt-card"> <div className="success-header"> <div className="success-badge"> - <svg width="18" height="18" viewBox="0 0 18 18" fill="none"> + <svg aria-hidden="true" width="18" height="18" viewBox="0 0 18 18" fill="none"> <path d="M4 9l3.5 3.5 6.5-7" stroke="white" diff --git a/code/web-client/src/components/UserActionCard.tsx b/code/web-client/src/components/UserActionCard.tsx index c6c5e628..a7c78ec5 100644 --- a/code/web-client/src/components/UserActionCard.tsx +++ b/code/web-client/src/components/UserActionCard.tsx @@ -10,7 +10,7 @@ export function UserActionCard({label, sublabel}: Props) { <div className="user-action-container"> <div className="action-badge"> <div className="check-icon"> - <svg width="8" height="8" viewBox="0 0 8 8"> + <svg aria-hidden="true" width="8" height="8" viewBox="0 0 8 8"> <path d="M1.5 4l2 2 3-3" stroke="white" diff --git a/code/web-client/src/hooks/useChat.ts b/code/web-client/src/hooks/useChat.ts index 82b35b63..32a6355d 100644 --- a/code/web-client/src/hooks/useChat.ts +++ b/code/web-client/src/hooks/useChat.ts @@ -202,7 +202,7 @@ export function useChat() { if (event.status.state === 'failed') { addMessage({ role: 'system', - text: 'Agent error: ' + JSON.stringify(event.status.message), + text: `Agent error: ${JSON.stringify(event.status.message)}`, }); } const statusParts = event.status.message?.parts ?? []; @@ -401,12 +401,12 @@ export function useChat() { } } } catch (e) { - addMessage({role: 'system', text: 'Connection error: ' + String(e)}); + addMessage({role: 'system', text: `Connection error: ${String(e)}`}); } finally { setLoading(false); } }, - [addMessage]); + [addMessage, fetchMandate]); // Trigger-state polling: 500ms interval while monitoring const lastTriggerStateRef = useRef<string>(''); @@ -463,6 +463,7 @@ export function useChat() { ]); // Auto-poll fallback (15s) + // biome-ignore lint/correctness/useExhaustiveDependencies: intentionally keyed on specific monitoring fields useEffect( () => { if (!isMonitoring || hasPurchaseComplete || !pendingTaskId) return; diff --git a/code/web-client/src/main.tsx b/code/web-client/src/main.tsx index 94418abe..76af2d49 100644 --- a/code/web-client/src/main.tsx +++ b/code/web-client/src/main.tsx @@ -3,7 +3,10 @@ import ReactDOM from 'react-dom/client'; import App from './App'; import './styles/global.scss'; -ReactDOM.createRoot(document.getElementById('root')!).render( +const rootElement = document.getElementById('root'); +if (!rootElement) throw new Error('Root element #root not found'); + +ReactDOM.createRoot(rootElement).render( <React.StrictMode> <App /> </React.StrictMode>, diff --git a/code/web-client/src/utils/mandateEntries.ts b/code/web-client/src/utils/mandateEntries.ts index b1c90aac..b4b967ad 100644 --- a/code/web-client/src/utils/mandateEntries.ts +++ b/code/web-client/src/utils/mandateEntries.ts @@ -18,7 +18,7 @@ * chronologically ordered list suitable for the Mandates tab. */ -import type {ChatMessage, MandateChainsFetched, MandateEntry, MandatesSigned, MonitoringStatus, PurchaseComplete, ToolCallArtifact,} from '../types'; +import type {ChatMessage, MandateChainsFetched, MandateEntry, MandatesSigned, PurchaseComplete,} from '../types'; type Draft = Omit<MandateEntry, 'id'>; @@ -86,9 +86,9 @@ function purchaseEntries(msg: ChatMessage, pc: PurchaseComplete): Draft[] { return out; } -function toolCallEntries(msg: ChatMessage, tc: ToolCallArtifact): Draft[] { +// Tool-call artifacts do not produce mandate entries yet. +function toolCallEntries(): Draft[] { const out: Draft[] = []; - const args = tc.args ?? {}; return out; } @@ -124,7 +124,7 @@ export function deriveMandateEntries(messages: ChatMessage[]): MandateEntry[] { drafts.push(...purchaseEntries(msg, data as unknown as PurchaseComplete)); break; case 'tool_call': - drafts.push(...toolCallEntries(msg, data as unknown as ToolCallArtifact)); + drafts.push(...toolCallEntries()); break; case 'mandate_chains_fetched': { const mcf = data as unknown as MandateChainsFetched; diff --git a/code/web-client/src/utils/productPreviewUnavailable.ts b/code/web-client/src/utils/productPreviewUnavailable.ts index d043a20f..69011923 100644 --- a/code/web-client/src/utils/productPreviewUnavailable.ts +++ b/code/web-client/src/utils/productPreviewUnavailable.ts @@ -19,7 +19,7 @@ export function normalizeProductPreviewUnavailable( if (typeof v === 'string') { const cleaned = v.replace(/[$,]/g, '').trim(); const n = Number(cleaned); - return isNaN(n) ? undefined : n; + return Number.isNaN(n) ? undefined : n; } return undefined; }; diff --git a/docs/assets/mandate_delegation_user_credential.svg b/docs/assets/mandate_delegation_user_credential.svg index 8a7e2581..015fa0ed 100644 --- a/docs/assets/mandate_delegation_user_credential.svg +++ b/docs/assets/mandate_delegation_user_credential.svg @@ -1 +1 @@ -<?xml version="1.0" encoding="utf-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"><svg xmlns="http://www.w3.org/2000/svg" width="731" height="558" xmlns:xlink="http://www.w3.org/1999/xlink"><desc style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Created with Raphaël 2.2.0</desc><defs style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><marker id="raphael-marker-endblock55-objg4wpy" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker><marker id="raphael-marker-endblock55-objtzn3v" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker><marker id="raphael-marker-endblock55-objc22uo" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker><marker id="raphael-marker-endblock55-obj6ulia" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker><marker id="raphael-marker-endblock55-objh1w5o" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker><marker id="raphael-marker-endblock55-objkdlq2" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker><marker id="raphael-marker-endblock55-objmlm1t" markerHeight="5" markerWidth="5" orient="auto" refX="2.5" refY="2.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"><use xlink:href="#raphael-marker-block" transform="rotate(180 2.5 2.5) scale(1,1)" stroke-width="1.0000" fill="#000" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></use></marker></defs><rect x="10" y="20" width="53.1171875" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="20.28515625" y="30" width="33.1171875" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="36.55859375" y="39.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">User</tspan></text><rect x="10" y="499" width="53.1171875" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="20.28515625" y="509" width="33.1171875" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="36.55859375" y="518.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">User</tspan></text><path fill="none" stroke="#000000" d="M36.55859375,59L36.55859375,499" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="108.58984375" y="20" width="133.15625" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="118.58984375" y="30" width="113.15625" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="175.16796875" y="39.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Trusted Surface</tspan></text><rect x="108.58984375" y="499" width="133.15625" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="118.58984375" y="509" width="113.15625" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="175.16796875" y="518.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Trusted Surface</tspan></text><path fill="none" stroke="#000000" d="M175.16796875,59L175.16796875,499" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="554.98828125" y="20" width="61.984375" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="564.98828125" y="30" width="41.984375" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="585.98046875" y="39.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Agent</tspan></text><rect x="554.98828125" y="499" width="61.984375" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="564.98828125" y="509" width="41.984375" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="585.98046875" y="518.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Agent</tspan></text><path fill="none" stroke="#000000" d="M585.98046875,59L585.98046875,499" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="636.97265625" y="20" width="64.171875" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="647.26171875" y="30" width="44.171875" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="669.05859375" y="39.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Issuer</tspan></text><rect x="636.97265625" y="499" width="64.171875" height="39" rx="0" ry="0" fill="none" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="647.26171875" y="509" width="44.171875" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="669.05859375" y="518.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Issuer</tspan></text><path fill="none" stroke="#000000" d="M669.05859375,59L669.05859375,499" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="26.55859375" y="79" width="652.5" height="29" rx="0" ry="0" fill="#ffff00" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="230.53515625" y="84" width="244.546875" height="19" rx="0" ry="0" fill="#ffff00" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="352.80859375" y="93.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Issue User Credential (In Advance)</tspan></text><rect x="358.20703125" y="123.5" width="127.8125" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="422.11328125" y="133" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">request credential</tspan></text><path fill="none" stroke="#000000" d="M175.16796875,147C175.16796875,147,612.1956083485857,147,664.0499620704882,147" stroke-width="2" marker-end="url(#raphael-marker-endblock55-objg4wpy)" stroke-dasharray="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="290.92578125" y="162.5" width="124.34375" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="352.80859375" y="172" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">authenticate user</tspan></text><path fill="none" stroke="#000000" d="M669.05859375,186C669.05859375,186,100.92339599132538,186,41.55770638177637,186" stroke-width="2" marker-end="url(#raphael-marker-endblock55-objtzn3v)" stroke-dasharray="6,2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="293.68359375" y="201.5" width="257.75" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="422.11328125" y="211" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">issuer_signed(Credential) w/user Pk</tspan></text><path fill="none" stroke="#000000" d="M669.05859375,225C669.05859375,225,232.03095415141433,225,180.17660042951184,225" stroke-width="2" marker-end="url(#raphael-marker-endblock55-objc22uo)" stroke-dasharray="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="26.55859375" y="245" width="652.5" height="29" rx="0" ry="0" fill="#800080" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="262.05078125" y="250" width="181.515625" height="19" rx="0" ry="0" fill="#800080" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="352.80859375" y="259.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#ffffff" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Mandate Delegation Start</tspan></text><rect x="234.71484375" y="289.5" width="291.71875" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="380.57421875" y="299" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Authorization Request(Mandate Content)</tspan></text><path fill="none" stroke="#000000" d="M585.98046875,313C585.98046875,313,226.9804374985397,313,180.17721076800262,313" stroke-width="2" marker-end="url(#raphael-marker-endblock55-obj6ulia)" stroke-dasharray="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="46.55859375" y="328.5" width="118.609375" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="105.86328125" y="338" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Display Mandate</tspan></text><path fill="none" stroke="#000000" d="M175.16796875,352C175.16796875,352,66.36352181527764,352,41.553132792565066,352" stroke-width="2" marker-end="url(#raphael-marker-endblock55-objh1w5o)" stroke-dasharray="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="77.32421875" y="367.5" width="57.078125" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="105.86328125" y="377" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">approve</tspan></text><path fill="none" stroke="#000000" d="M36.55859375,391C36.55859375,391,145.36304068472236,391,170.17342970743493,391" stroke-width="2" marker-end="url(#raphael-marker-endblock55-objkdlq2)" stroke-dasharray="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="185.16796875" y="406.5" width="390.8125" height="19" rx="0" ry="0" fill="#fafafa" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="380.57421875" y="416" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#000000" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Issuer_signed(UserCredential) + user_signed(Mandate)</tspan></text><path fill="none" stroke="#000000" d="M175.16796875,430C175.16796875,430,534.1680000014603,430,580.9712267319974,430" stroke-width="2" marker-end="url(#raphael-marker-endblock55-objmlm1t)" stroke-dasharray="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path><rect x="26.55859375" y="450" width="652.5" height="29" rx="0" ry="0" fill="#800080" stroke="#000000" stroke-width="2" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><rect x="244.97265625" y="455" width="215.671875" height="19" rx="0" ry="0" fill="#800080" stroke="none" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></rect><text x="352.80859375" y="464.5" text-anchor="middle" font-family="Roboto" font-size="16px" stroke="none" fill="#ffffff" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-family: Roboto; font-size: 16px;"><tspan dy="5.5" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">Mandate Delegation Complete</tspan></text></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" width="731" height="558" xmlns:xlink="http://www.w3.org/1999/xlink"><title>Mandate delegation with user credentialCreated with Raphaël 2.2.0UserUserTrusted SurfaceTrusted SurfaceAgentAgentIssuerIssuerIssue User Credential (In Advance)request credentialauthenticate userissuer_signed(Credential) w/user PkMandate Delegation StartAuthorization Request(Mandate Content)Display MandateapproveIssuer_signed(UserCredential) + user_signed(Mandate)Mandate Delegation Complete \ No newline at end of file From db7636b2f72682756aab849a8a22813176f7854b Mon Sep 17 00:00:00 2001 From: maximusrufus Date: Fri, 16 Oct 2026 08:43:40 -0700 Subject: [PATCH 2/6] chore: add sublabel/dedup to cspell words and skip SVG assets --- .cspell.json | 3 ++- .cspell/custom-words.txt | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.cspell.json b/.cspell.json index 3e21d466..054c658e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -9,7 +9,8 @@ ".gemini/**", ".vscode/**", ".cspell.json", - "**/go.sum" + "**/go.sum", + "**/*.svg" ], "dictionaryDefinitions": [ { diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index ce73c361..4aada16f 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -185,3 +185,6 @@ XVCJ Yapily Zalopay Zalora +Sublabel +sublabel +dedup From a89d3248763fe2959ad6b41da380934aef148dfa Mon Sep 17 00:00:00 2001 From: maximusrufus Date: Fri, 16 Oct 2026 08:47:08 -0700 Subject: [PATCH 3/6] ci: exclude web-client from super-linter; make docs SVGs parseable code/web-client has its own eslint config; super-linter's generic ESLint/Prettier lacks React settings and cannot resolve its imports. Strip XML prolog/DOCTYPE/comments from docs SVGs, add titles and a generic font fallback so Biome can parse and lint them. --- .github/workflows/linter.yaml | 2 +- docs/assets/action_authorization_overview.svg | 2 +- docs/assets/ap2-logo-black.svg | 2 +- docs/assets/ap2-logo-white.svg | 2 +- docs/assets/ap2_hnp_flow.svg | 2 +- docs/assets/ap2_hnp_payment.svg | 2 +- docs/assets/ap2_hnp_shopping.svg | 2 +- docs/assets/ap2_hp_flow.svg | 2 +- docs/assets/ap2_hp_payment.svg | 2 +- docs/assets/ap2_hp_shopping.svg | 2 +- docs/assets/mandate_chain_example.svg | 2 +- docs/assets/mandate_delegation_overview.svg | 2 +- docs/assets/mandate_delegation_trusted_agent_provider.svg | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index fea1b9c1..7140be19 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -23,7 +23,7 @@ jobs: LOG_LEVEL: WARN SHELLCHECK_OPTS: -e SC1091 -e 2086 VALIDATE_ALL_CODEBASE: false - FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" + FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/|code/web-client/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" VALIDATE_BIOME_FORMAT: false VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_FLAKE8: false diff --git a/docs/assets/action_authorization_overview.svg b/docs/assets/action_authorization_overview.svg index 556885a7..29edf590 100644 --- a/docs/assets/action_authorization_overview.svg +++ b/docs/assets/action_authorization_overview.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0AgentAgentVerifierVerifierrequest action authorizationpresent Mandateverify MandateMandate Receipt \ No newline at end of file +action authorization overviewCreated with Raphaël 2.2.0AgentAgentVerifierVerifierrequest action authorizationpresent Mandateverify MandateMandate Receipt \ No newline at end of file diff --git a/docs/assets/ap2-logo-black.svg b/docs/assets/ap2-logo-black.svg index a7f2b78e..2ea18075 100644 --- a/docs/assets/ap2-logo-black.svg +++ b/docs/assets/ap2-logo-black.svg @@ -1,3 +1,3 @@ - +ap2 logo black diff --git a/docs/assets/ap2-logo-white.svg b/docs/assets/ap2-logo-white.svg index 3ac23229..5ddf9cec 100644 --- a/docs/assets/ap2-logo-white.svg +++ b/docs/assets/ap2-logo-white.svg @@ -1,3 +1,3 @@ - +ap2 logo white diff --git a/docs/assets/ap2_hnp_flow.svg b/docs/assets/ap2_hnp_flow.svg index fd488fdb..ad8f746a 100644 --- a/docs/assets/ap2_hnp_flow.svg +++ b/docs/assets/ap2_hnp_flow.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Shopping JourneyShopping context conversationCreate Open MandateRequest Mandate Approval (Contents, sa_pk)Confirmation of Open Mandate ContentsApprovedSign Mandates w/user_skMandates, user_credentialStore Mandates, user_credentialCompleted Open MandateUser Leaves SessionReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed CheckoutEnd Shopping JourneyStart Payment JourneySelects appropriate Open MandatesSign Closed Checkout and Payment Mandate w/ agent_skPayment Mandates(Open, Closed)Verify Payment Mandates and ConstraintsPayment MandateVerify Payment Mandate and Constraintspayment_tokenpayment_tokenCheckout (CheckoutMandates (Open, Closed), payment_token)initiate payment (payment_token, hash(Checkout_jwt), hash(open CheckoutMandate))verify Payment MandatesSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file +ap2 hnp flowCreated with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Shopping JourneyShopping context conversationCreate Open MandateRequest Mandate Approval (Contents, sa_pk)Confirmation of Open Mandate ContentsApprovedSign Mandates w/user_skMandates, user_credentialStore Mandates, user_credentialCompleted Open MandateUser Leaves SessionReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed CheckoutEnd Shopping JourneyStart Payment JourneySelects appropriate Open MandatesSign Closed Checkout and Payment Mandate w/ agent_skPayment Mandates(Open, Closed)Verify Payment Mandates and ConstraintsPayment MandateVerify Payment Mandate and Constraintspayment_tokenpayment_tokenCheckout (CheckoutMandates (Open, Closed), payment_token)initiate payment (payment_token, hash(Checkout_jwt), hash(open CheckoutMandate))verify Payment MandatesSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file diff --git a/docs/assets/ap2_hnp_payment.svg b/docs/assets/ap2_hnp_payment.svg index b32af58a..4656dcd3 100644 --- a/docs/assets/ap2_hnp_payment.svg +++ b/docs/assets/ap2_hnp_payment.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessornetworknetworkStart Payment JourneySelects appropriate Open MandatesSign Closed Checkout and Payment Mandate w/ agent_skPayment Mandates(Open, Closed)Verify Payment Mandates and ConstraintsPayment MandateVerify Payment Mandate and Constraintspayment_tokenpayment_tokenCheckout (CheckoutMandates (Open, Closed), payment_token)initiate payment (payment_token, hash(Checkout_jwt), hash(open CheckoutMandate))verify Payment MandatesSigned Payment ReceiptSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file +ap2 hnp paymentCreated with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessornetworknetworkStart Payment JourneySelects appropriate Open MandatesSign Closed Checkout and Payment Mandate w/ agent_skPayment Mandates(Open, Closed)Verify Payment Mandates and ConstraintsPayment MandateVerify Payment Mandate and Constraintspayment_tokenpayment_tokenCheckout (CheckoutMandates (Open, Closed), payment_token)initiate payment (payment_token, hash(Checkout_jwt), hash(open CheckoutMandate))verify Payment MandatesSigned Payment ReceiptSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file diff --git a/docs/assets/ap2_hnp_shopping.svg b/docs/assets/ap2_hnp_shopping.svg index d5547192..23556379 100644 --- a/docs/assets/ap2_hnp_shopping.svg +++ b/docs/assets/ap2_hnp_shopping.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Shopping JourneyShopping context conversationCreate Open MandateRequest Mandate Approval (Contents, sa_pk)Confirmation of Open Mandate ContentsApprovedSign Mandates w/user_skMandates, user_credentialStore Mandates, user_credentialCompleted Open MandateUser Leaves SessionReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed CheckoutEnd Shopping Journey \ No newline at end of file +ap2 hnp shoppingCreated with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Shopping JourneyShopping context conversationCreate Open MandateRequest Mandate Approval (Contents, sa_pk)Confirmation of Open Mandate ContentsApprovedSign Mandates w/user_skMandates, user_credentialStore Mandates, user_credentialCompleted Open MandateUser Leaves SessionReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed CheckoutEnd Shopping Journey \ No newline at end of file diff --git a/docs/assets/ap2_hp_flow.svg b/docs/assets/ap2_hp_flow.svg index 7034771d..739c71a8 100644 --- a/docs/assets/ap2_hp_flow.svg +++ b/docs/assets/ap2_hp_flow.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessornetworknetworkStart Shopping JourneyShopping context conversationReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed Checkoutretrieve payment optionspayment optionsselect payment optionEnd Shopping JourneyStart Payment JourneyCapture User consent for Checkout placement and PaymentPlease confirm purchase(CheckoutMandateContents, PaymentMandateContents)ConfirmedSign Mandates w/user_skSigned MandatesPayment MandateVerify Payment MandatePayment MandateVerify Payment Mandatepayment_tokenpayment_tokenCheckout (CheckoutMandate, payment_token)Validate Checkout Mandateinitiate payment (payment_token, hash(Checkout_jwt))verify Payment MandateSigned Payment ReceiptSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file +ap2 hp flowCreated with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessornetworknetworkStart Shopping JourneyShopping context conversationReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed Checkoutretrieve payment optionspayment optionsselect payment optionEnd Shopping JourneyStart Payment JourneyCapture User consent for Checkout placement and PaymentPlease confirm purchase(CheckoutMandateContents, PaymentMandateContents)ConfirmedSign Mandates w/user_skSigned MandatesPayment MandateVerify Payment MandatePayment MandateVerify Payment Mandatepayment_tokenpayment_tokenCheckout (CheckoutMandate, payment_token)Validate Checkout Mandateinitiate payment (payment_token, hash(Checkout_jwt))verify Payment MandateSigned Payment ReceiptSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file diff --git a/docs/assets/ap2_hp_payment.svg b/docs/assets/ap2_hp_payment.svg index 9d59b7a6..b31d165d 100644 --- a/docs/assets/ap2_hp_payment.svg +++ b/docs/assets/ap2_hp_payment.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Payment JourneyCapture User consent for Checkout placement and PaymentPlease confirm purchase(CheckoutMandateContents, PaymentMandateContents)ConfirmedSign Mandates w/user_skSigned MandatesPayment MandateVerify Payment MandatePayment MandateVerify Payment Mandatepayment_tokenpayment_tokenCheckout (CheckoutMandate, payment_token)Validate Checkout Mandateinitiate payment (payment_token, hash(Checkout_jwt))verify Payment MandateSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file +ap2 hp paymentCreated with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderNetworkNetworkMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Payment JourneyCapture User consent for Checkout placement and PaymentPlease confirm purchase(CheckoutMandateContents, PaymentMandateContents)ConfirmedSign Mandates w/user_skSigned MandatesPayment MandateVerify Payment MandatePayment MandateVerify Payment Mandatepayment_tokenpayment_tokenCheckout (CheckoutMandate, payment_token)Validate Checkout Mandateinitiate payment (payment_token, hash(Checkout_jwt))verify Payment MandateSigned Payment ReceiptSigned Checkout ReceiptEnd Payment Journey \ No newline at end of file diff --git a/docs/assets/ap2_hp_shopping.svg b/docs/assets/ap2_hp_shopping.svg index e187f2ca..62cc4bae 100644 --- a/docs/assets/ap2_hp_shopping.svg +++ b/docs/assets/ap2_hp_shopping.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Shopping JourneyShopping context conversationReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed Checkoutretrieve payment optionspayment optionsselect payment optionEnd Shopping Journey \ No newline at end of file +ap2 hp shoppingCreated with Raphaël 2.2.0UserUserShopping AgentShopping AgentTrusted SurfaceTrusted SurfaceCredential ProviderCredential ProviderMerchantMerchantMerchant Payment ProcessorMerchant Payment ProcessorStart Shopping JourneyShopping context conversationReturn CatalogueCatalog dataAdd items to cart & create CheckoutMerchant Signed Checkoutretrieve payment optionspayment optionsselect payment optionEnd Shopping Journey \ No newline at end of file diff --git a/docs/assets/mandate_chain_example.svg b/docs/assets/mandate_chain_example.svg index 69731e40..9ba711ce 100644 --- a/docs/assets/mandate_chain_example.svg +++ b/docs/assets/mandate_chain_example.svg @@ -1 +1 @@ - \ No newline at end of file +mandate chain example \ No newline at end of file diff --git a/docs/assets/mandate_delegation_overview.svg b/docs/assets/mandate_delegation_overview.svg index 16d6b087..3919af2f 100644 --- a/docs/assets/mandate_delegation_overview.svg +++ b/docs/assets/mandate_delegation_overview.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserTrusted SurfaceTrusted SurfaceAgentAgentMandate ContentDisplay Mandate Contentapprovedelegate Mandate \ No newline at end of file +mandate delegation overviewCreated with Raphaël 2.2.0UserUserTrusted SurfaceTrusted SurfaceAgentAgentMandate ContentDisplay Mandate Contentapprovedelegate Mandate \ No newline at end of file diff --git a/docs/assets/mandate_delegation_trusted_agent_provider.svg b/docs/assets/mandate_delegation_trusted_agent_provider.svg index ad903ce3..2732c231 100644 --- a/docs/assets/mandate_delegation_trusted_agent_provider.svg +++ b/docs/assets/mandate_delegation_trusted_agent_provider.svg @@ -1 +1 @@ -Created with Raphaël 2.2.0UserUserTrusted SurfaceTrusted SurfaceAgentAgentIssuerIssuerIssue User Credential (In Advance)request credentialauthenticate userissuer_signed(Credential) w/user PkMandate Delegation StartAuthorization Request(Mandate Content)Display MandateapproveIssuer_signed(UserCredential) + user_signed(Mandate)Mandate Delegation Complete \ No newline at end of file +mandate delegation trusted agent providerCreated with Raphaël 2.2.0UserUserTrusted SurfaceTrusted SurfaceAgentAgentIssuerIssuerIssue User Credential (In Advance)request credentialauthenticate userissuer_signed(Credential) w/user PkMandate Delegation StartAuthorization Request(Mandate Content)Display MandateapproveIssuer_signed(UserCredential) + user_signed(Mandate)Mandate Delegation Complete \ No newline at end of file From 550adccf3a02e93f4303645b9679f04eda1142ae Mon Sep 17 00:00:00 2001 From: maximusrufus Date: Fri, 16 Oct 2026 08:49:28 -0700 Subject: [PATCH 4/6] ci: match web-client exclusion against absolute paths --- .github/workflows/linter.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 7140be19..67fd6701 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -23,7 +23,7 @@ jobs: LOG_LEVEL: WARN SHELLCHECK_OPTS: -e SC1091 -e 2086 VALIDATE_ALL_CODEBASE: false - FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/|code/web-client/).*|CODE_OF_CONDUCT.md|CHANGELOG.md" + FILTER_REGEX_EXCLUDE: "^(\\.github/|\\.vscode/|code/samples/).*|(^|/)code/web-client/|CODE_OF_CONDUCT.md|CHANGELOG.md" VALIDATE_BIOME_FORMAT: false VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_FLAKE8: false From 71f2155d8b7c64727b1ae7463cd4a8f66dc2fe5c Mon Sep 17 00:00:00 2001 From: maximusrufus Date: Fri, 16 Oct 2026 08:51:48 -0700 Subject: [PATCH 5/6] ci: pin linter workflow actions to commit SHAs --- .github/workflows/linter.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 67fd6701..534b1aa6 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -11,12 +11,12 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v5 + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: fetch-depth: 0 - name: Lint Code Base - uses: super-linter/super-linter/slim@v8 + uses: super-linter/super-linter/slim@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 env: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 99b76085c7ec8e8789e298507f1fb821b1eee8e7 Mon Sep 17 00:00:00 2001 From: maximusrufus Date: Fri, 16 Oct 2026 08:54:33 -0700 Subject: [PATCH 6/6] ci: restrict linter workflow permissions and drop persisted credentials --- .github/workflows/linter.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/linter.yaml b/.github/workflows/linter.yaml index 534b1aa6..7150890c 100644 --- a/.github/workflows/linter.yaml +++ b/.github/workflows/linter.yaml @@ -4,16 +4,23 @@ on: pull_request: branches: [main] +permissions: {} + jobs: build: name: Lint Code Base runs-on: ubuntu-latest + permissions: + contents: read + packages: read + statuses: write steps: - name: Checkout Code uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 with: fetch-depth: 0 + persist-credentials: false - name: Lint Code Base uses: super-linter/super-linter/slim@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0