fix(aiui): node-content surfaces stay open when the reply text infers no tabs

Reproduced live: 'show me paid for peer files' returned surfaces=1 with 3
purchased images over the bridge, then updatePanelFromText set panelOpen
from the REGEX-inferred tab list — a plain markdown list matches nothing,
so the panel closed and the user saw prose only. panelOpen now follows
orderedTabs (Archy tabs lead). Regression test pins the exact turn.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-07 08:20:41 -04:00
co-authored by Claude
parent d0c9ea6e61
commit f0d2cdb7b2
2 changed files with 30 additions and 1 deletions
@@ -109,6 +109,30 @@ describe('useContentPanel', () => {
// is still a real answer from the node, distinct from "never asked".
expect(panel.archyContentActive.value).toBe(true)
})
// Regression (live on archi-dev-box 2026-08-07): "show me paid for peer
// files" — the turn's surface carried 3 purchased images, the reply text
// was a plain markdown list matching no extraction pattern, and
// updatePanelFromText then set panelOpen from the regex-only tab list,
// CLOSING the panel setArchyContent had just opened. The probe showed
// surfaces=1 arriving; the user saw only prose.
it('keeps the panel open on node content when the reply text infers no tabs', () => {
const img = { id: 'i1', title: 'signal-test.jpeg', url: '/content/abc', mimeType: 'image/jpeg' } as unknown as ImageItem
panel.setArchyContent({ images: [img] })
expect(panel.panelOpen.value).toBe(true)
expect(panel.activeTab.value).toBe('image')
// The turn's prose answer arrives after the surfaces and fires the
// text path: a bullet list with no tags, no links, no patterns.
panel.updatePanelFromText(
"You've purchased 4 items from peer nodes:\n\n- signal-test.jpeg (170 KB) — 100 sats\n- Photos/got it!.jpg (253 KB) — 100 sats\n\nThese are mostly photos.",
'show me paid for peer files',
)
expect(panel.panelOpen.value).toBe(true)
expect(panel.availableTabs.value[0]).toBe('image')
expect(panel.panelImages.value).toHaveLength(1)
})
})
it('openPlaceDetail and closePlaceDetail work', () => {
@@ -327,7 +327,12 @@ export function useContentPanel() {
else if (hasNostr) panelTitle.value = 'Nostr'
else panelTitle.value = 'Content'
panelOpen.value = tabs.length > 0
// Open from the ORDERED tab list (Archy tabs + inferred), not the
// regex-only `tabs`: a node-supplied grid whose reply text happens to
// match no extraction pattern (a plain markdown list of purchased
// files) used to CLOSE the panel setArchyContent had just opened —
// the probe showed surfaces=1 images=3 arriving and the user saw prose.
panelOpen.value = orderedTabs.length > 0
}
/**