Something went wrong. Try again.
A collaborative coding-agent orchestrator for atproto radl.app
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476import { FetchRepoTransport, parseAtUri } from '@radial/atproto'import { COLLECTIONS, type StoredRecord } from '@radial/core'import { FIXTURE_DIDS, fixtureSpace } from '@radial/core/fixture'import { afterEach, describe, expect, it, vi } from 'vitest'import { adopt, signOut } from './auth.svelte.js'import { FAKE_PDS, FakePds, latestVersions, memoryStorage } from './fake-pds.js'import { memoryDatabase, type SpaceDatabase } from './idb.js'import { Identities } from './identity.js'import { bootstrap, openSpace, session, settle, stop, sync, type OpenOptions,} from './session.svelte.js'import { openSpaceStores } from './store.js'import { goalsOf, isEnded, projectByName, unitsOf } from './space.js'
// The live read path, end to end, against a PDS that only exists in this file: DID documents,// handle resolution, `getLatestCommit`, `listRecords`. Everything between the stub `fetch` and the// index — `Identities`, `FetchRepoTransport`, `RepoPoller`, `SpaceIngestor`, the persistent store,// `materialize()` — is the code the browser actually runs.//// The three things 6.2 claims are asserted here: a live space folds to the same views the fixture// does, a record written elsewhere shows up within one poll, and a warm reload costs one head check// per member and no rescan at all.
const fixture = fixtureSpace()const SPACE_DID = parseAtUri(fixture.spaceUri).did
const HANDLES: Record<string, string> = { [FIXTURE_DIDS.tim]: 'tim.test', [FIXTURE_DIDS.ana]: 'ana.test', [FIXTURE_DIDS.planner]: 'planner.agents.test', [FIXTURE_DIDS.builder]: 'builder.agents.test', [FIXTURE_DIDS.reviewer]: 'reviewer.agents.test',}
const currentVersions = (): StoredRecord[] => latestVersions(fixture.records)
const versionsFor = (spaceUri: string): StoredRecord[] => currentVersions().map((record) => JSON.parse(JSON.stringify(record).replaceAll(fixture.spaceUri, spaceUri)) as StoredRecord, )
interface Harness { network: FakePds database: SpaceDatabase storage: ReturnType<typeof memoryStorage>}
const open = (harness: Harness): Promise<void> => openSpace(fixture.spaceUri, options(harness))
const options = (harness: Harness): OpenOptions => ({ identities: new Identities({ fetcher: harness.network.fetch, storage: harness.storage }), transport: (identities) => new FetchRepoTransport(identities.pdsResolver, harness.network.fetch), openStores: (uri) => openSpaceStores(uri, async () => harness.database), poll: false, })
const harness = ( records = currentVersions(), handles = HANDLES, profiles: Record<string, string> = {},): Harness => ({ network: new FakePds(records, handles, profiles), database: memoryDatabase(), storage: memoryStorage(),})
afterEach(async () => { stop() await signOut() session.space = undefined session.status = 'choosing' session.error = ''})
describe('opening a live space', () => { it('prunes the cold collection sweep to collections each repository actually holds', async () => { const live = harness() await open(live) const members = session.space?.index.members.filter((member) => member.active).length ?? 0 expect(live.network.counts('describeRepo')).toBe(members) expect(live.network.counts('listRecords')).toBeLessThan(members * 26) })
it('preserves the published Space on an unchanged tick while advancing its clocks', async () => { const live = harness() await open(live) const published = session.space if (!published) throw new Error('no space') published.asOf = '2000-01-01T00:00:00.000Z' published.syncedAt = published.asOf await sync() expect(session.space).toBe(published) expect(session.space?.asOf).not.toBe('2000-01-01T00:00:00.000Z') expect(session.space?.syncedAt).toBe(session.space?.asOf) })
it('publishes and remembers the latest distinct space', async () => { const uriB = `${fixture.spaceUri}-b` const spaceA = harness() const spaceB = harness(versionsFor(uriB))
await openSpace(fixture.spaceUri, options(spaceA)) spaceA.network.reset() await openSpace(uriB, options(spaceB))
expect(session.space?.uri).toBe(uriB) expect(session.status).toBe('ready') expect(session.recents[0]?.uri).toBe(uriB) await sync() expect(spaceA.network.calls).toHaveLength(0) })
it('does not let a superseded open publish or fail after the latest one', async () => { const uriB = `${fixture.spaceUri}-b` const slow = harness() const latest = harness(versionsFor(uriB)) let release: (() => void) | undefined const gate = new Promise<void>((resolve) => (release = resolve)) const slowOptions = options(slow) const slowOpenStores = slowOptions.openStores if (!slowOpenStores) throw new Error('missing store opener')
const openingA = openSpace(fixture.spaceUri, { ...slowOptions, openStores: async (uri) => { await gate return slowOpenStores(uri) }, }) await openSpace(uriB, options(latest)) const published = session.space release?.() await openingA
expect(session.space).toBe(published) expect(session.space?.uri).toBe(uriB) expect(session.status).toBe('ready') expect(session.error).toBe('') })
it('draws the same views the fixture does, from repos over the wire', async () => { const live = harness() await open(live)
expect(session.status).toBe('ready') expect(session.error).toBe('') const space = session.space if (!space) throw new Error('no space') expect(space.fixture).toBe(false) expect(space.uri).toBe(fixture.spaceUri) expect(space.index.ignored).toEqual([])
// The same nine system documents 6.1 asserts against the fixture, folded from a live scan. const project = projectByName(space.index, 'radial-ng') if (!project) throw new Error('no project') expect(unitsOf(space.index, project)).toHaveLength(9) expect(goalsOf(space.index, project).filter(isEnded)).toHaveLength(5)
// Every `getLatestCommit` resolves a PDS first. Asking the directory once per member rather // than once per request is the difference between a poll tick costing one round trip and three. const members = space.index.members.filter((member) => member.active).length expect(live.network.counts('didDocument')).toBe(members) })
it('names members by a handle it resolved, not by one a record claimed', async () => { const live = harness() await open(live) const space = session.space if (!space) throw new Error('no space')
// A human publishes no handle anywhere; the DID document is the only place one exists. expect(space.directory.get(FIXTURE_DIDS.tim).handle).toBe('tim.test') // An agent publishes one in its own record, which is a self-assertion — the resolved, // round-tripped handle is the one shown. expect(space.directory.get(FIXTURE_DIDS.planner).handle).toBe('planner.agents.test') })
it('drops a handle that does not round-trip back to the DID that claimed it', async () => { // Ana's document claims a handle that belongs to Tim. Showing it would be showing somebody // else's name, so she renders as a DID instead — the one thing that is always true. const live = harness(currentVersions(), { ...HANDLES, [FIXTURE_DIDS.ana]: 'tim.test' }) await open(live) const space = session.space if (!space) throw new Error('no space') expect(space.directory.get(FIXTURE_DIDS.ana).handle).toBeUndefined() expect(space.directory.get(FIXTURE_DIDS.ana).name).toBe('a1s2d3f4…') })
it('shows the picture a member publishes, and the derived disc for one who does not', async () => { // A profile picture is not a Radial record: it is read from the member's own repo, the same // place their handle comes from, and it is an overlay on the directory rather than a field the // index carries. An identity with no profile record keeps the colour-and-initials disc, so the // fallback is not an error path — it is what most agents will always look like. const live = harness(currentVersions(), HANDLES, { [FIXTURE_DIDS.tim]: 'bafyavatartim' }) await open(live) const space = session.space if (!space) throw new Error('no space')
expect(space.directory.get(FIXTURE_DIDS.tim).avatar).toBe( `https://cdn.bsky.app/img/avatar_thumbnail/plain/${encodeURIComponent(FIXTURE_DIDS.tim)}/bafyavatartim@jpeg`, ) const planner = space.directory.get(FIXTURE_DIDS.planner) expect(planner.avatar).toBeUndefined() expect(planner.initials).toBe('PL')
// One profile read per member on a cold scan, and none on the next tick: the answer is cached // beside the handle and the PDS. const profileReads = live.network.calls.filter((call) => call.detail.startsWith('app.bsky.actor.profile'), ) expect(profileReads).toHaveLength(space.index.members.filter((member) => member.active).length) live.network.reset() await sync() expect(live.network.counts('getRecord')).toBe(0) })
it('refuses a URI that does not name a space record', async () => { await openSpace('at://did:plc:qv7hjr2mzk4x/com.disnetdev.radial.goal/abc') expect(session.status).toBe('choosing') expect(session.error).toContain('space') expect(session.space).toBeUndefined() })
it('says so when the space record is not there', async () => { const live = harness([]) await open(live) expect(session.status).toBe('failed') expect(session.error).toContain('Space record not found') })})
describe('opening a deep link', () => { it('keeps a private bookmark deep link off public stores and asks for a fresh ticket', async () => { const live = harness() const did = FIXTURE_DIDS.tim adopt(did, (path, init) => live.network.fetch(new URL(path, FAKE_PDS), init)) const openStores = vi.fn() await bootstrap( new URL(`/?space=${encodeURIComponent(fixture.spaceUri)}`, 'https://radl.app'), { ...options(live), privateMeta: async () => undefined, privateBookmark: async (owner, uri) => owner === did && uri === fixture.spaceUri, openStores, }, ) expect(session.status).toBe('needs-ticket') expect(session.error).toContain('fresh transfer ticket') expect(openStores).not.toHaveBeenCalled() })
it('opens a public space when the account’s own PDS will not answer the bookmark check', async () => { const live = harness() const did = FIXTURE_DIDS.tim adopt(did, (path, init) => live.network.fetch(new URL(path, FAKE_PDS), init)) // The check reads the USER's repo on the way into every space, including one hosted somewhere // else entirely. Their PDS being down is not a fact about this space. await bootstrap( new URL(`/?space=${encodeURIComponent(fixture.spaceUri)}`, 'https://radl.app'), { ...options(live), privateMeta: async () => undefined, privateBookmark: async () => { throw new Error('XrpcError: upstream is down') }, }, ) expect(session.status).toBe('ready') expect(session.space?.uri).toBe(fixture.spaceUri) })
it('opens an explicit public space without requiring an account', async () => { const live = harness() await bootstrap( new URL(`/p/radial?space=${encodeURIComponent(fixture.spaceUri)}`, 'https://radl.app'), options(live), ) expect(session.status).toBe('ready') expect(session.space?.uri).toBe(fixture.spaceUri) })
it('recovers an older goal link from the public goal record', async () => { const live = harness() const goal = currentVersions().find((record) => record.collection === COLLECTIONS.goal) if (!goal) throw new Error('fixture goal missing') const parts = parseAtUri(goal.uri) await bootstrap(new URL(`/g/${parts.did}/${parts.rkey}`, 'https://radl.app'), options(live)) expect(session.status).toBe('ready') expect(session.space?.uri).toBe(fixture.spaceUri) })
it('does not let a superseded goal lookup replace a newer explicit space', async () => { const uriB = `${fixture.spaceUri}-b` const slow = harness() const latest = harness(versionsFor(uriB)) const goal = currentVersions().find((record) => record.collection === COLLECTIONS.goal) if (!goal) throw new Error('fixture goal missing') const parts = parseAtUri(goal.uri) let release: (() => void) | undefined const gate = new Promise<void>((resolve) => (release = resolve)) const slowOptions = options(slow) const slowTransport = slowOptions.transport if (!slowTransport) throw new Error('missing transport')
const older = bootstrap(new URL(`/g/${parts.did}/${parts.rkey}`, 'https://radl.app'), { ...slowOptions, transport: (identities) => { const transport = slowTransport(identities) return { resolvePds: transport.resolvePds.bind(transport), getLatestCommit: transport.getLatestCommit.bind(transport), listRecords: transport.listRecords.bind(transport), async getRecord(uri) { await gate return transport.getRecord(uri) }, } }, }) await bootstrap( new URL(`/p/radial?space=${encodeURIComponent(uriB)}`, 'https://radl.app'), options(latest), ) const published = session.space release?.() await older
expect(session.space).toBe(published) expect(session.space?.uri).toBe(uriB) expect(session.status).toBe('ready') expect(session.error).toBe('') })
it('does not let a superseded goal lookup failure overwrite a newer space', async () => { const uriB = `${fixture.spaceUri}-b` const slow = harness() const latest = harness(versionsFor(uriB)) const goal = currentVersions().find((record) => record.collection === COLLECTIONS.goal) if (!goal) throw new Error('fixture goal missing') const parts = parseAtUri(goal.uri) let reject: ((error: Error) => void) | undefined const failure = new Promise<never>((_resolve, rejectPromise) => (reject = rejectPromise)) const slowOptions = options(slow) const slowTransport = slowOptions.transport if (!slowTransport) throw new Error('missing transport')
const older = bootstrap(new URL(`/g/${parts.did}/${parts.rkey}`, 'https://radl.app'), { ...slowOptions, transport: (identities) => { const transport = slowTransport(identities) return { resolvePds: transport.resolvePds.bind(transport), getLatestCommit: transport.getLatestCommit.bind(transport), listRecords: transport.listRecords.bind(transport), getRecord: () => failure, } }, }) await bootstrap( new URL(`/p/radial?space=${encodeURIComponent(uriB)}`, 'https://radl.app'), options(latest), ) const published = session.space reject?.(new Error('stale lookup failed')) await older
expect(session.space).toBe(published) expect(session.space?.uri).toBe(uriB) expect(session.status).toBe('ready') expect(session.error).toBe('') })
it('does not interpret an ambiguous older project link against a remembered space', async () => { await bootstrap(new URL('/p/radial', 'https://radl.app')) expect(session.status).toBe('choosing') expect(session.space).toBeUndefined() expect(session.error).toContain('which space') })})
describe('staying live', () => { it('picks up a record written elsewhere within one poll', async () => { const live = harness() await open(live) const before = session.space if (!before) throw new Error('no space')
const reviewQueue = before.index.goals.find( (goal) => goal.target.value.title === 'Review queue in the web UI', ) if (!reviewQueue) throw new Error('fixture goal missing') const threadBefore = reviewQueue.messages.length
// What `radial message post` does from a container, or a human from the CLI. live.network.append({ did: FIXTURE_DIDS.tim, collection: COLLECTIONS.message, rkey: 'msg-live-1', uri: `at://${FIXTURE_DIDS.tim}/${COLLECTIONS.message}/msg-live-1`, cid: 'cid-msg-live-1', rev: '9999999999999', value: { $type: COLLECTIONS.message, goal: { uri: reviewQueue.target.uri, cid: reviewQueue.target.cid }, body: 'Written from the CLI while the tab was open.', mentions: [], createdAt: '2026-07-25T14:20:00Z', }, } as StoredRecord)
await sync()
const after = session.space if (!after) throw new Error('no space') const refreshed = after.index.goals.find((goal) => goal.target.uri === reviewQueue.target.uri) expect(refreshed?.messages).toHaveLength(threadBefore + 1) expect(after.syncedAt).not.toBe(before.syncedAt) })
it('keeps the last good index on screen when a poll fails', async () => { const live = harness() await open(live) const before = session.space
// A member's PDS goes away. That makes the view stale, not wrong: the records already folded // are still the records, and replacing the screen with an error would throw away work the human // is reading. live.network.offline = true await sync()
expect(session.error).toBe('offline') expect(session.status).toBe('ready') expect(session.space).toBe(before)
// …and it recovers on the next tick without anything being re-opened. live.network.offline = false await sync() expect(session.error).toBe('') })})
describe('a warm reload', () => { it('costs one head check per member and no rescan', async () => { const live = harness() await open(live) const members = session.space?.index.members.filter((member) => member.active).length ?? 0 expect(members).toBeGreaterThan(1) await settle() stop()
live.network.reset() await open(live)
expect(session.status).toBe('ready') expect(live.network.counts('listRecords')).toBe(0) expect(live.network.counts('getLatestCommit')).toBe(members) // The identity cache came back from storage too, so no directory was asked anything. expect(live.network.counts('didDocument')).toBe(0) expect(live.network.counts('resolveHandle')).toBe(0) })
it('does rescan a repo whose head moved', async () => { const live = harness() await open(live) await settle() stop()
live.network.heads.set(FIXTURE_DIDS.planner, (live.network.heads.get(FIXTURE_DIDS.planner) ?? 0) + 1) live.network.reset() await open(live)
const listed = live.network.calls.filter((call) => call.method === 'listRecords') expect(listed.length).toBeGreaterThan(0) expect(listed.every((call) => call.did === FIXTURE_DIDS.planner)).toBe(true) })})