Skip to content

afx workspace recover: respawned builders lose their original spawnedByArchitect (all attach to shell's architect) #1140

Description

@amrmelsayed

Problem

afx workspace recover --apply respawns builders whose shellper session died (e.g. after a machine reboot). Every respawned builder ends up attributed to whatever architect terminal the operator ran afx workspace recover from — typically main — regardless of which architect originally spawned the builder. Sibling-architect workspaces lose their per-builder attribution on the first post-reboot recovery pass.

Downstream symptoms:

  • afx send architect from the respawned builder routes to the wrong architect (main instead of e.g. vscode)
  • architect:<sibling> addressing from that builder is rejected by the anti-spoofing check (tower-messages.ts:213-218) because spawned_by_architect now says main
  • Dashboard + VS Code Agents-view attribution shows the wrong owner
  • Sibling architects lose their per-team builder list after any recovery event

Root cause

packages/codev/src/agent-farm/commands/workspace-recover.ts has zero mentions of spawned_by_architect / spawnedByArchitect. The recovery flow never reads or preserves per-builder architect attribution.

Concrete chain:

  • BuilderInfo interface carries { builderId, issueArg, cliProtocol } — no architect field.
  • deriveBuilderInfo builds it from ProjectState (porch status.yaml) alone; the builder's global.db.builders.spawned_by_architect value is never consulted.
  • respawnBuilder runs child_process.spawn(process.execPath, [afx-entry, 'spawn', info.issueArg, '--resume', '--protocol', info.cliProtocol], { stdio: 'inherit' }) — no env override.
  • The child afx spawn process inherits CODEV_ARCHITECT_NAME from the shell that invoked workspace recover. That value is then read by spawn.ts's module-scope SPAWNING_ARCHITECT_NAME constant (process.env.CODEV_ARCHITECT_NAME || DEFAULT_ARCHITECT_NAME) and written into the new builder's spawned_by_architect DB column.

Result: all builders reattributed to whichever architect owned the recovery shell (or main if the shell wasn't inside an architect terminal at all).

Fix sketch

Three surgical changes:

  1. Extend BuilderInfo with spawnedByArchitect: string | null. Nullable to accommodate legacy rows / pre-Spec-755 builders that predate the field.

  2. Populate it in deriveBuilderInfo (or a wrapper) by reading spawned_by_architect from global.db.builders WHERE workspace_path = ? AND id = ? for the derived builderId. Use the existing read-only DB access pattern from overview.ts's enrichment logic (single query per project is fine — workspace recover isn't hot). Fall back to null if not found.

  3. respawnBuilder sets the child's env so the spawn CLI reads the correct name:

    spawn(process.execPath, [...], {
      stdio: 'inherit',
      env: {
        ...process.env,
        CODEV_ARCHITECT_NAME: info.spawnedByArchitect ?? process.env.CODEV_ARCHITECT_NAME ?? 'main',
      },
    });

    Preserving the caller's env for the null-fallback case keeps legacy-row recoveries at least self-consistent (they get the shell's architect, matching today's default).

Scope

  • packages/codev/src/agent-farm/commands/workspace-recover.ts — interface, derive, respawn
  • Unit test coverage: extend the existing recover tests (if any) to cover multi-architect respawn preserves per-builder attribution.

Out of scope: any change to afx spawn itself, any change to the DB schema, per-workspace / cross-workspace recovery semantics.

Related

  • Sibling attribution bug: VS Code Backlog Reference issue in architect action ignores the QuickPick selection (always sends to main). Different code path, same "architects losing builder attribution" theme in the current release cycle.
  • The spawned_by_architect column read here is the same field enriched by overview.ts for the dashboard and VS Code Agents view, and read by tower-messages.ts for anti-spoofing on architect:<name> addressing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/towerArea: Tower server / agent farm CLI

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions