diff --git a/core/archipelago/src/api/rpc/content.rs b/core/archipelago/src/api/rpc/content.rs
index 5c314927..315bff7f 100644
--- a/core/archipelago/src/api/rpc/content.rs
+++ b/core/archipelago/src/api/rpc/content.rs
@@ -326,11 +326,20 @@ impl RpcHandler {
));
}
- let body: serde_json::Value = response
+ let mut body: serde_json::Value = response
.json()
.await
.context("Failed to parse peer catalog")?;
+ // Surface the transport that actually reached the peer so the cloud
+ // browse UI can show a FIPS/Tor pill instead of always assuming Tor (B21).
+ if let Some(obj) = body.as_object_mut() {
+ obj.insert(
+ "transport".to_string(),
+ serde_json::Value::String(transport.to_string()),
+ );
+ }
+
Ok(body)
}
diff --git a/neode-ui/src/views/PeerFiles.vue b/neode-ui/src/views/PeerFiles.vue
index 1369a862..3dfdcb4a 100644
--- a/neode-ui/src/views/PeerFiles.vue
+++ b/neode-ui/src/views/PeerFiles.vue
@@ -30,7 +30,15 @@
-
{{ peerDisplayName }}
+
+
{{ peerDisplayName }}
+ {{ transportPill.label }}
+
{{ currentPeer.did }}
Peer files
@@ -43,7 +51,7 @@
- Connecting via Tor... This may take a few seconds.
+ Connecting to peer… This may take a few seconds.
@@ -288,6 +296,23 @@ const catalogItems = ref([])
const downloading = ref(null)
const playing = ref(null)
const purchaseError = ref(null)
+// Transport actually used to reach this peer (returned by content.browse-peer)
+// so we can show a FIPS/Tor pill instead of always assuming Tor (B21).
+const transport = ref(null)
+const transportPill = computed(() => {
+ switch (transport.value) {
+ case 'fips':
+ return { label: 'FIPS', cls: 'bg-green-500/20 text-green-300', title: 'Connected over the fast encrypted mesh (FIPS)' }
+ case 'mesh':
+ return { label: 'Mesh', cls: 'bg-green-500/20 text-green-300', title: 'Connected over the mesh' }
+ case 'lan':
+ return { label: 'LAN', cls: 'bg-blue-500/20 text-blue-300', title: 'Connected over the local network' }
+ case 'tor':
+ return { label: 'Tor', cls: 'bg-amber-500/20 text-amber-300', title: 'Connected over Tor (slower)' }
+ default:
+ return null
+ }
+})
const previewUrls = reactive>({})
const audioPlayer = useAudioPlayer()
@@ -329,12 +354,13 @@ async function loadCatalog() {
loading.value = true
catalogError.value = ''
try {
- const result = await rpcClient.call<{ items?: CatalogItem[] }>({
+ const result = await rpcClient.call<{ items?: CatalogItem[]; transport?: string }>({
method: 'content.browse-peer',
params: { onion },
timeout: 30000,
})
catalogItems.value = result?.items ?? []
+ transport.value = result?.transport ?? null
} catch (e: unknown) {
catalogError.value = e instanceof Error ? e.message : 'Failed to connect to peer'
if (!hadItems) catalogItems.value = []
diff --git a/tests/production-quality/TRACKER.md b/tests/production-quality/TRACKER.md
index 60ccf199..ac4b6445 100644
--- a/tests/production-quality/TRACKER.md
+++ b/tests/production-quality/TRACKER.md
@@ -108,7 +108,7 @@ We previously broadcast bitcoin block headers over mesh to archipelago nodes but
### B14b — FIPS reachability: many peers fall back to Tor — TODO (priority, deeper)
Live (2026-06-15) federation sync last_transport on .116/.198: ~4 peers fips, ~6 tor, ~5 none. So beyond the recording fix (B14), FIPS genuinely doesn't reach many federated peers (they use Tor). Investigate WHY: is fips_npub known for those peers? are they FIPS-online? is the shared anchor connecting them? (cf project_fips_integration, project_tor_node_to_node_works). This is the real "Tor not FIPS" depth.
-### B21 — Show Tor/FIPS transport pill on cloud browse — ROOT-CAUSED (pairs with B14)
+### B21 — Show Tor/FIPS transport pill on cloud browse — FIXED (build+type-check green; deploy+UI-confirm on .116/.198)
Tag whether the peer connection is Tor or FIPS and surface it as a small pill on the cloud browse screens / connection loader. Data source: federation node last_transport (now recorded by B14) exposed via federation.list-nodes; frontend renders a pill (FIPS=fast/green, Tor=slower) on PeerFiles.vue / Cloud peer view + the connection loader. Frontend-only-ish. FINDINGS: PeerFiles.vue:46 loader HARDCODES 'Connecting via Tor...' even when FIPS used (bug). Frontend types already have last_transport ('fips'|'tor'|'mesh'|'lan') federation/types.ts:31; NodeList.vue:167 already renders a transport indicator. PLAN: have content.browse-peer RETURN the transport used (B14 already computes it) → frontend shows a pill (FIPS green / Tor amber) on PeerFiles header + fix the loader text to reflect actual/attempted transport. Small backend (add transport to browse response) + frontend pill.
### B8 — netbird app doesn't work — TODO (LOW / much later)