SOURCE / PINNED RELEASE
Made of little things.
Funclet
- Release
- 0b497cfc2f66…
- Author-recorded commit
- 1e531b24f490…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6b7a37cac1d
Archive hash verified: 71d97a89ed8c40c2…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
# Funclet live incident — 23 October 2026
## Findings and ownership
The deployed shell **does connect to `wss://relay.wavefunc.live/`**. Public browser
WebSocket traces show both the initial catalogue request and `search: "idm"`
reaching it. The live host also queries seven discovery/fallback relays. Local
soyLI preview queries only Wavefunc for the same authorless request.
| Symptom | Confirmed cause | Owner / disposition |
| --- | --- | --- |
| Many “Untitled station” entries | Other apps reuse kind 31237 for music albums. Funclet accepted these without checking for a station name and stream. | Funclet: fixed schema validation. These were not nameless Wavefunc imports. |
| Only two familiar station names in the initial 48 | The host sorts the combined relay results and defaults its aggregate limit to 48. Newer unrelated records occupy 46 slots. | Funclet: request a bounded aggregate of 200, validate, then display up to 48 stations. Host documentation/testing improvement below. |
| IDM search shows an OUTBOX error | Wavefunc returns 19 valid station events. Primal/nostr.net reject the NIP-50 `search` filter. The host returns the 19 events **with** `incomplete: true` and `error`; Funclet threw away the usable data. | Funclet: preserve valid partial results with retry feedback. Host does not discard these events. |
| “Schlaus favs (2)” loads zero stations | The list exists; its two exact station addresses return no events, even directly from Wavefunc without the shell. | Wavefunc data/relay follow-up. Not established as a napplet.soy bug. Improved Funclet explanation; no silent replacement or list mutation. |
No new NAP domain, direct app networking, relay pool, or signer access was added.
Reads remain SDK OUTBOX operations. The supplied relay is a routing hint, not an
exclusive destination under the current host contract.
## Evidence
Affected pinned release:
<https://napplet.soy/r/ec1ec2a12ab64bedc9dfef9da242e396cf2ad07a837969366e0cebd3f8b7ae63>
Toolchain: soyLI 0.31.2 on macOS arm64; installed SDK 0.24.4.
The original unmodified release reproduced in a fresh, signed-out Chromium.
The local comparison used an isolated `soyli dev --port 0` session.
### Kind collision and aggregate limit
A returned public record, ID
`437de6bec4d8fe66362d5658dd47af8b0a804440a53bf7ec5e0de2dbfd4e52aa`,
has kind 31237 and tags including:
```json
[["d","disco-vault:785"],["title","The Sounds of Machines Our Parents Used"],
["artist","Gescom"],["type","music"],["country","UK"]]
```
It has neither Wavefunc's `name` nor stream data. It came from
`wss://nostr.oxtr.dev/`. Adding `title` as a name fallback would incorrectly turn
an album into a radio station; the fix rejects it.
The corrected request retains `filter.limit: 48` per relay and adds the existing
SDK `options.limit: 200` for the aggregate. A deployed-host run returned 145 raw
records, from which Funclet selected 48 valid named stations. This remains a
bounded catalogue sample, not a complete global station enumeration. The host's
200-event collection ceiling can still mark unusually large fanout incomplete.
### Partial search result
```js
outbox.query([{ kinds: [31237], search: 'idm', limit: 48 }], {
relays: ['wss://relay.wavefunc.live'], timeoutMs: 8000, limit: 200
})
// events.length === 19
// incomplete === true
// error includes: bad req: unrecognised filter item: search
```
Both IDM Ambient and SomaFM CliqHop IDM were in the successful events. The old
service rejected any response containing `error`, regardless of `events`.
The fix only throws when no usable records survive parsing, and retains the
partial status for the UI. The same rule applies to favourites reads.
### Favourite references
List event:
`e81883680848ffcf98aabb3148d67f9cfdd408c8be42cef5985673143de871df`.
Both references use author
`210f31b6019f5ae13c995c8d83faa41a129f1296842e4c3313ab8a4abb09d1a2`
and kind 31237, with identifiers:
- `e0ae6528-c2c0-4659-9a7e-1dc40e90a22c`
- `b7d64edb-d35d-4106-bb25-ba4c15038539`
The live host returns `events: [], incomplete: false` for each address separately,
for two exact filters together, and for one same-author filter with both `#d`
values. A direct WebSocket diagnostic outside the napplet receives EOSE with no
events from Wavefunc for both exact references and for the identifiers without an
author restriction. An author-only control returns other named stations. Two
known existing addresses also resolve through the live OUTBOX host.
This proves the relay is reached and does not return these references; it does
not establish whether they were deleted, migrated, never replicated, or affected
by a relay index problem. Inspect Wavefunc's storage/import history for these IDs,
or find and re-add the intended stations in Wavefunc. Funclet cannot infer their
names or safely replace their identities from the list alone.
## napplet.soy / soyLI improvement backlog
These are specific compatibility and authoring improvements, not claims that the
shell caused every symptom.
### P1 — Add production relay parity to acceptance testing
**Reproduce:** run the same artifact locally with only its manifest relay, then
on napplet.soy with the site's discovery relays. Local catalogue/search passes;
the published catalogue contains kind collisions and search becomes partial.
**Proposal:** offer an explicit production-routing test profile or make the
local-vs-public relay plan visible. Add acceptance cases with a second relay
returning newer unrelated same-kind records, one rejecting `search`, and one
returning valid data. Include signed-in list resolution, not only list discovery.
Do not make a startup-only `check` equivalent to a verified release.
### P2 — Document partial OUTBOX results at the SDK call site
**Reproduce:** NIP-50 search across Wavefunc and Primal returns both `events` and
`error`. Treating the latter as an all-or-nothing failure hides useful data.
**Proposal:** show a canonical example that renders validated events, preserves
`incomplete`, and treats an empty failed lookup differently from a completed empty
lookup. Consider structured per-relay outcomes rather than one last failure
string. Maintain explicit errors when all destinations fail.
The current host is already retaining partial events; Funclet's original handling
was incorrect. This is chiefly documentation and diagnostic clarity work.
### P2 — Expose and explain aggregate limits and routing hints
**Reproduce:** request 48 events from one hinted relay while the shell adds seven
fallbacks. The default aggregate cap is also 48, applied to the union sorted by
creation time. An unrelated schema sharing the kind can crowd out the hinted
relay's dataset.
**Proposal:** document per-filter versus aggregate limits, the 200-event collection
ceiling, and that `options.relays` is additive. Expose policy-approved route and
completion diagnostics in the player. Add a test where hinted-relay data survives
alongside newer fallback records. If exclusive dataset reads are needed, use an
existing documented relay-local capability or propose a policy design upstream;
do not invent an OUTBOX `strategy` field.
### P2 — Fresh-run media capture needs a documented network policy
From the preceding release's capture work: the built-in recorder blocked remote
requests, including shell-owned radio audio, so the radio became stopped instead
of showing playback. The selected clip was captured from a normal hosted session.
**Proposal:** provide an explicit capture mode that preserves the same approved
MEDIA/CVM/OUTBOX behavior as normal playback, or document the limitation and offer
a supported hosted-session recorder. Preserve iframe isolation and host consent.
This was observed during the prior release; it is independent of the current
station/search incident.
## Reproduction and verification
```bash
pnpm verify
pnpm test:conformance
pnpm test:ui
node tests/host-smoke.mjs <printed-soyli-dev-url>
node tests/live-services.mjs <published-url> [public-owner-hex]
node tests/live-release.mjs <published-url>
```
`live-services.mjs` runs the working tree's actual domain/service modules against
the deployed host via SDK-equivalent injected OUTBOX calls. It does not replace
an artifact or fake an identity, and is distinct from testing a published build.
`live-release.mjs` tests only the unmodified signed artifact loaded by the website.
Public network changes can change counts; it asserts a populated named catalogue
and the known IDM results rather than pretending all relays must always succeed.
Regression tests cover kind collisions, aggregate candidate retention, partial
search/list/station reads, a failed favourite batch retaining another batch's
results, and no substitution for a missing address. UI tests assert partial relay
errors leave results visible. Protocol conformance skips remain unmeasured.
## Released fix
Published source checkpoint: `e02a14fe072c1c817e08b64a93c15446e50ae9dd`.
Corrected HTML SHA-256:
`921a24285cee6e729831b5b5317fd8d38c00e30169cf1c5b6c7b452adcfbd19e`.
[Open the corrected release](https://napplet.soy/r/75ed251bc3480bb0ecec52b1a024f2a34377ba69b0e46d88b2130ef29b77319d).
The old `/r/` URL remains pinned to the affected artifact; it does not update.
Website status is indexed/ready. `tests/live-release.mjs` passed on the new signed
artifact: named populated catalogue, 19 IDM search results, and signed-out
favourites feedback. The known two missing references remain a Wavefunc follow-up.
The owned local preview was stopped after testing.
