From 3b5e5a24f43b50acd5280f4e873335511b5e76fc Mon Sep 17 00:00:00 2001 From: Gavriel Cohen Date: Sat, 2 May 2026 16:07:43 +0000 Subject: [PATCH] fix(migrate-v2): reset auto-created messaging_group policy on re-run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If 1b-db is re-run after the v2 service has already started (e.g. recovering from an earlier failure), the messaging_group it would otherwise create may already exist — auto-created by the runtime router on the first inbound message, with the router's default unknown_sender_policy ('request_approval'), not the migration's intent ('public'). The previous reuse path skipped creation but never updated the policy, so re-runs left the bot hanging every message waiting for an approver that wasn't seeded yet. When reusing an existing row that has zero wired agent_groups (signal of a router auto-create), reset the policy to 'public'. Once any wiring exists, the user has had a chance to tighten via the skill — leave it. Also adds a CHANGELOG entry covering this and the two sibling fixes (Discord DM resolution, symlink skip in copyTree). --- CHANGELOG.md | 1 + setup/migrate-v2/db.ts | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e297d3a..2ec9fc3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ For detailed release notes, see the [full changelog on the documentation site](h ## [Unreleased] - **v1 → v2 migration.** Run `bash migrate-v2.sh` from the v2 checkout. Finds your v1 install (sibling directory or `NANOCLAW_V1_PATH`), merges `.env`, seeds the v2 DB from `registered_groups`, copies group folders (`CLAUDE.md` → `CLAUDE.local.md`), copies session data with conversation continuity, ports scheduled tasks, interactively selects and installs channels (clack multiselect), copies container skills, builds the agent container, and offers a service switchover to test. Hands off to Claude (`/migrate-from-v1`) for owner seeding, access policy, CLAUDE.md cleanup, and fork customization porting. See [docs/migration-dev.md](docs/migration-dev.md) and [docs/v1-to-v2-changes.md](docs/v1-to-v2-changes.md). +- **Migration fixes.** `1b-db` now resolves Discord DMs as `discord:@me:` (previously skipped any v1 chat that wasn't a guild channel — a blocker for personal-bot installs). `1c-groups` skips symlinks instead of following them (a single broken `.claude-shared.md → /app/CLAUDE.md` no longer aborts the whole copy). When `1b-db` reuses an auto-created `messaging_group` with no wired agents, its `unknown_sender_policy` is now reconciled to the migration's `public` default. ## [2.0.0] - 2026-04-22 diff --git a/setup/migrate-v2/db.ts b/setup/migrate-v2/db.ts index c2b5b48..ada4764 100644 --- a/setup/migrate-v2/db.ts +++ b/setup/migrate-v2/db.ts @@ -22,7 +22,9 @@ import { createMessagingGroup, createMessagingGroupAgent, getMessagingGroupAgentByPair, + getMessagingGroupAgents, getMessagingGroupByPlatform, + updateMessagingGroup, } from '../../src/db/messaging-groups.js'; import { runMigrations } from '../../src/db/migrations/index.js'; import { readEnvFile } from '../../src/env.js'; @@ -147,7 +149,15 @@ async function main(): Promise { ag = getAgentGroupByFolder(g.folder)!; } - // messaging_group — one per (channel_type, platform_id) + // messaging_group — one per (channel_type, platform_id). + // + // If the row already exists *and* has zero wired agent_groups, it + // was almost certainly auto-created by the runtime router on an + // inbound message (which uses 'request_approval' or similar — not + // the migration's 'public'). Reset its policy to match what the + // migration would have set if it had created the row first. Once + // any wiring exists, the user has had a chance to tighten the + // policy via the skill — leave it alone. let mg = getMessagingGroupByPlatform(channelType, platformId); if (!mg) { createMessagingGroup({ @@ -160,6 +170,12 @@ async function main(): Promise { created_at: createdAt, }); mg = getMessagingGroupByPlatform(channelType, platformId)!; + } else if ( + mg.unknown_sender_policy !== 'public' && + getMessagingGroupAgents(mg.id).length === 0 + ) { + updateMessagingGroup(mg.id, { unknown_sender_policy: 'public' }); + mg = getMessagingGroupByPlatform(channelType, platformId)!; } // messaging_group_agents — wire them