From a64d831e9b21ecbeab0a7ca8951f8e16676ca8e4 Mon Sep 17 00:00:00 2001 From: BetterCallSol <886fabdb38ceb1aede220bc237b7bb34736490f12a7d79e235e5ecfd63a36514@buzz.block.builderlab.xyz> Date: Wed, 16 Sep 2026 17:10:54 -0400 Subject: [PATCH] fix(beehive): separate registration from runtime setup Signed-off-by: BetterCallSol <886fabdb38ceb1aede220bc237b7bb34736490f12a7d79e235e5ecfd63a36514@buzz.block.builderlab.xyz> --- beehive/src/manager-controller.ts | 7 ++++--- beehive/src/manager-view.ts | 5 +++-- beehive/test/registration-start.test.ts | 13 +++++++++---- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/beehive/src/manager-controller.ts b/beehive/src/manager-controller.ts index ac8b5f25d2..23cbf6a701 100644 --- a/beehive/src/manager-controller.ts +++ b/beehive/src/manager-controller.ts @@ -373,14 +373,15 @@ A Stop result is not a recent host report that confirms the agent is stopped.` } const report = this.agentReport(key); if (settings.revision !== pending.settingsRevision || !report || !this.fresh(report) || JSON.stringify([report.host,report.agent]) !== pending.target || report.revision !== pending.revision || report.body.phase !== 'stopped' || report.body.actualRun) throw plain('Settings or host selection changed. Start again.'); } - runtime ??= this.saveAgentConfiguration(v); + runtime ??= pending ? this.saveAgentConfiguration(v) : undefined; const { profile, profileState } = this.profilePreview; - await this.credential({ action: 'register-agent', directory: this.hostDirectory, secret: v.secret, publicKey:key, profile: { profile, profileState }, runtimeId:runtime.id, expectedRevision:readSettings(this.hostDirectory).revision },abort.signal); check(); + await this.credential({ action: 'register-agent', directory: this.hostDirectory, secret: v.secret, publicKey:key, profile: { profile, profileState }, ...(runtime ? { runtimeId:runtime.id } : {}), expectedRevision:readSettings(this.hostDirectory).revision },abort.signal); check(); const committed = readSettings(this.hostDirectory); if (!committed.agents.some(agent => agent.publicKey === key)) throw plain('Agent registration completion was not verified. Inspect saved registration before retrying.'); this.profilePreview = undefined; - if (!pending) this.status = 'Agent registered. Configuration saved.'; + if (!pending) this.status = 'Agent registered. You can configure it before Start.'; else { + if (!runtime) throw plain('Select an available harness and provider before Start.'); const guard = () => { check(); if (this.continuation !== pending || this.owner !== pending.owner || !this.directory.some(a => a.publicKey === pending.agent)) throw plain('Start selection changed. Inspect saved registration.'); diff --git a/beehive/src/manager-view.ts b/beehive/src/manager-view.ts index d2a2a19678..2c50abbb36 100644 --- a/beehive/src/manager-view.ts +++ b/beehive/src/manager-view.ts @@ -73,8 +73,9 @@ async function registerForm(continuation?: string, agent?: string) { const result = await request('profile-preview',{secret,...(agent ? {agent} : {}),...(continuation ? {continuation} : {})}); if (result.state !== 'completed') { settled = true; return; } const preview = snapshot.profilePreview; if (!preview) return; - const configuration = await configurationForm(screen, () => snapshot, request); if (!configuration) return; - if (!await screen.confirm(`Register agent\n${preview.profile?.name ?? 'Name unavailable'}\n${preview.publicKey}\n${continuation ? 'Register and Start?' : 'Save registration?'}`)) return; + const configuration = continuation ? await configurationForm(screen, () => snapshot, request) : {}; + if (!configuration) return; + if (!await screen.confirm(`Register agent\n${preview.profile?.name ?? 'Name unavailable'}\n${preview.publicKey}\n${continuation ? 'Register, configure and Start?' : 'Save registration? You can configure it afterward.'}`)) return; await request('register-agent',{secret,...configuration,...(agent ? {agent} : {}),...(continuation ? {continuation} : {})}); settled = true; } finally { secret = ''; if (continuation && !settled) await request('retire-continuation'); } } diff --git a/beehive/test/registration-start.test.ts b/beehive/test/registration-start.test.ts index 5507b1e62d..488a8874a6 100644 --- a/beehive/test/registration-start.test.ts +++ b/beehive/test/registration-start.test.ts @@ -246,16 +246,21 @@ test('cancelling after host enrollment preserves stopped placement and cannot la }); -test('Other-agent registration requires that exact identity even without a Start continuation', async t => { +test('Other-agent registration requires that exact identity and does not require runtime setup', async t => { const f = await fixture(t); const other = 'f'.repeat(64); assert.equal((await f.request('profile-preview', { secret: f.nsec, agent: other })).state, 'failed'); assert.equal(readSettings(f.directory).agents.length, 0); assert.equal((await f.request('profile-preview', { secret: f.nsec, agent: f.agent })).state, 'completed'); - assert.equal((await f.request('register-agent', { secret: f.nsec, agent: other, runtime: f.runtimeId })).state, 'failed'); + assert.equal((await f.request('register-agent', { secret: f.nsec, agent: other })).state, 'failed'); assert.equal(readSettings(f.directory).agents.length, 0); - assert.equal((await f.request('register-agent', { secret: f.nsec, agent: f.agent, runtime: f.runtimeId })).state, 'completed'); - assert.equal(readSettings(f.directory).agents[0]?.publicKey, f.agent); + const before = readSettings(f.directory); + assert.equal((await f.request('register-agent', { secret: f.nsec, agent: f.agent })).state, 'completed'); + const after = readSettings(f.directory); + assert.equal(after.agents[0]?.publicKey, f.agent); + assert.equal(after.agents[0]?.runtimeId, undefined); + assert.deepEqual(after.providers, before.providers); + assert.deepEqual(after.runtimes, before.runtimes); const rows = sectionRows(f.snapshot, 1); assert.equal(rows.filter(row => row.id === f.agent).length, 1, 'registered identity has one row'); assert.ok(rows.indexOf(rows.find(row => row.id === f.agent)!) < rows.findIndex(row => row.id === 'other-agents'), 'successful registration moves the row immediately without Start');