Repository navigation
fix(spawn): generateWorkerId returns uuid for agents_id_shape_check - #1627
Conversation
After migration 061 (agents_id_invariant_and_fk_lockdown), agents.id must be either a UUID (8-4-4-4-12 hex) or start with 'dir:'. But generateWorkerId still produced legacy team-role[-8hex] shape, so every new spawn failed: PostgresError: new row for relation "agents" violates check constraint "agents_id_shape_check" Symptom: genie work / genie spawn blocked across the board after the .7/.8 update — no fresh agent could be persisted. Root cause (agents.ts:446): base = team-role; if free return base else append uuid.slice(0,8) Both branches produce non-UUID strings. Fix: return crypto.randomUUID() directly. agents.role still carries the human-readable role; agents.customName / display still works. The id field becomes a pure surrogate key, matching the constraint contract. This unblocks every wish-work dispatch and direct genie spawn that was hitting agents_id_shape_check after migration 061 landed. Wider unification (TUI nextRoleSuffix path, dispatch wish-work role naming) is wish-territory; this is the surgical unblocker for the INSERT-time constraint violation. Validation: bun run typecheck clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the generateWorkerId function to always return a random UUID, ensuring compliance with database constraints introduced in a recent migration. However, the reviewer pointed out that this change introduces a regression in idempotency and will likely cause unique constraint violations during agent registration. The feedback suggests retrieving the existing agent's UUID from the registry to maintain stability and avoid database errors.
| async function generateWorkerId(_team: string, _role?: string): Promise<string> { | ||
| // Always return a UUID. agents.id constraint (migration 061) requires | ||
| // UUID shape or 'dir:%' prefix. Legacy team-role-suffix shape failed | ||
| // agents_id_shape_check on every new spawn after that migration. | ||
| return crypto.randomUUID(); | ||
| } |
There was a problem hiding this comment.
Returning a fresh crypto.randomUUID() here introduces a regression in idempotency and a high risk of database errors due to unique constraint violations.
- Unique Constraint Violation: In
handleWorkerSpawn,registry.findOrCreateAgentis called at line 2621. This function ensures an agent identity exists for the given(custom_name, team)and returns its UUIDid. IfgenerateWorkerIdthen returns a different random UUID, the subsequentregistry.registercall (line 665, viactx.workerId) will attempt to insert a new row with the samecustom_nameandteambut a different primary keyid. This will trigger a unique constraint violation on the(custom_name, team)composite key. - Loss of Stability: The previous implementation produced a stable ID based on team and role. Using a random UUID means every spawn attempt for the same role will try to create a new agent record instead of updating the existing one.
- Incomplete Fix: This change only addresses the legacy path. The
identity.workerIdpath inhandleWorkerSpawn(line 2641) still usesresolveSpawnIdentity, which returns non-UUID strings (e.g.,engineerorengineer-abcd). Standard spawns will likely still fail theagents_id_shape_checkconstraint.
To fix this properly while staying within the current architecture, this function should look up the existing agent's UUID from the registry.
async function generateWorkerId(team: string, role?: string): Promise<string> {
// Always return a UUID. agents.id constraint (migration 061) requires
// UUID shape or 'dir:%' prefix. We look up the existing agent identity
// to ensure we use its canonical UUID and avoid unique constraint violations
// on (custom_name, team) during registration.
const name = role || team;
const existing = await registry.getAgentByName(name, team);
if (existing) return existing.id;
return crypto.randomUUID();
}After migration 061 (agents.id became UUID-shaped) and PR #1627 (generateWorkerId returns UUID), resolveSpawnIdentity still ran a SELECT id FROM agents WHERE id = ${name} with role-name strings, hitting: PostgresError: invalid input syntax for type uuid: "engineer-4-eac7" This blocked every fresh dispatch where the role name is not a UUID (every wish-work dispatch, every direct genie spawn). Fix: at function entry, if name is not UUID-shaped, skip the canonical-lookup query and return a fresh canonical with a generated UUID workerId immediately. Role-based dispatch continues working; UUID-keyed lookups still flow through the original code path. Validation: bun run typecheck clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
After PR #1627 (generateWorkerId returns UUID), resolveSpawnIdentity still ran SELECT id FROM agents WHERE id = ${name} with role-name strings, hitting: PostgresError: invalid input syntax for type uuid: "engineer-4-eac7" This blocks every fresh dispatch where the role name is not a UUID (every wish-work, every direct genie spawn). Fix: at function entry, if name is not UUID-shaped, skip the canonical-lookup query and return a fresh canonical with a generated UUID workerId. Role-based dispatch continues working; UUID-keyed lookups still flow through the original code path. Validation: bun run typecheck clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Summary
After migration 061 (
agents_id_invariant_and_fk_lockdown) shipped in v4.260503.7/.8, every new spawn (bothgenie workandgenie spawn) hits:Constraint requires
agents.idto be a UUID (8-4-4-4-12 hex) ordir:%prefix. ButgenerateWorkerIdstill produces the legacyteam-role[-8hex]shape — neither matches.Root cause
src/term-commands/agents.ts:446:Both return paths produce non-UUID strings. Constraint rejects every new INSERT.
Fix (1-line semantic change)
agents.idbecomes a pure UUID surrogate key.agents.roleandagents.customNamestill carry human-readable identity for display/listing.Companion to PR #1626
#1626 fixed dispatch role-collision (
engineer-3colliding across wishes). This PR fixes the deeper INSERT-time constraint violation that surfaces after #1626 unblocks the role check. Both are needed.Validation
bun run typecheckcleangenie work <wish>andgenie spawn <role>produce agents with UUIDidthat passagents_id_shape_checkTest plan
genie work autopg-distribution-cutoverfrom a fresh shell dispatches G3 withoutagents_id_shape_checkerrorgenie spawn engineer --team genieproduces agent row with UUID idgenie ls,genie agent show <name>— name resolution still worksOut of scope (followups)
nextRoleSuffix, dispatcheffectiveRole, thisgenerateWorkerId) — wish-territory🤖 Generated with Claude Code