fix(agents): hotfix cold-start incidents — labels + dispatcher claim + identity isolation #29

Merged
navigator merged 1 commit from feature/hotfix-swarm-labels into main 2026-05-24 15:22:05 -03:00
Owner

Cold-start of the autonomous swarm exposed three issues. All fixed here. Detailed narrative in commit body. Summary:

  1. POST /issues expects label IDs not names — Issue Opener got HTTP 422 silently. fj_issue_create now resolves names → IDs internally.
  2. GET /issues?labels= silently returns all-open when label missing — Dispatcher claimed human issue #2. Both fj_open_issues_by_label and claim_next_issue now re-filter client-side. The 18 swarm labels also created in the live repo.
  3. git config polluted main repo identity — resolver-dispatcher.sh's per-worktree git config writes landed in the SHARED config. Fix uses git config --worktree + install-swarm.sh sets extensions.worktreeConfig=true.

Tested: bash -n green; reproduces fixed (issue #2 no longer claimed; missing-label filter returns []).

Cold-start of the autonomous swarm exposed three issues. All fixed here. Detailed narrative in commit body. Summary: 1. **POST /issues expects label IDs not names** — Issue Opener got HTTP 422 silently. fj_issue_create now resolves names → IDs internally. 2. **GET /issues?labels=<name> silently returns all-open when label missing** — Dispatcher claimed human issue #2. Both fj_open_issues_by_label and claim_next_issue now re-filter client-side. The 18 swarm labels also created in the live repo. 3. **git config polluted main repo identity** — resolver-dispatcher.sh's per-worktree git config writes landed in the SHARED config. Fix uses git config --worktree + install-swarm.sh sets extensions.worktreeConfig=true. Tested: bash -n green; reproduces fixed (issue #2 no longer claimed; missing-label filter returns []).
fix(agents): hotfix cold-start incidents — labels, dispatcher claim, identity isolation
All checks were successful
build / scalafmt-check (pull_request) Successful in 3s
build / sbt-compile (pull_request) Successful in 4s
build / shell-lint (pull_request) Successful in 1m10s
build / scalafmt-check (push) Successful in 3s
build / sbt-compile (push) Successful in 4s
build / shell-lint (push) Successful in 11s
ff2c965cf5
Cold-start of the autonomous swarm exposed three issues. All fixed
here. The full hotfix narrative is below.

## 1. POST /issues expects label IDs, not names

Issue Opener was posting labels as name strings (["area:infra",
"agent:queued"]) and getting HTTP 422 silently. Zero issues filed
on the first tick.

Fix: fj_issue_create resolves names -> IDs internally via
fj_label_id_map. Callers keep using name strings.

## 2. GET /issues?labels=<name> silently returns all-open when label is missing

The 18 coordination labels (agent:queued, agent:in-progress, etc.)
did not exist in the repo at cold-start. Forgejo's labels filter
silently degraded — claim_next_issue() got back all open issues
instead of an empty set and the Resolver Dispatcher claimed
issue #2 (human-authored "Provision LXC CT 250") and spawned a
resolver against it.

Fix: client-side re-filter in fj_open_issues_by_label and
claim_next_issue. claim_next_issue also now explicitly excludes
agent:in-progress | pr-open | blocked-* so no race can re-claim
something in flight.

The 18 labels themselves have been created on the live repo via
direct API calls as part of this hotfix; future repo bootstraps
should provision them via infra/forgejo/provision.sh (separate PR
to land that automation).

## 3. `git config user.email` polluted main repo identity

resolver-dispatcher.sh ran:
  git -C "$worktree" config user.name "FluidPop Swarm"
  git -C "$worktree" config user.email "swarm@pop.coop"

Linked worktrees share .git/config with the main checkout by
default. Without extensions.worktreeConfig=true the writes landed
in the SHARED config, flipping the main clone's identity to swarm
and triggering the pre-commit hook for the human operator's
follow-up commits.

Fix:
  - install-swarm.sh sets extensions.worktreeConfig=true on the
    repo at install time
  - resolver-dispatcher.sh uses `git config --worktree` so the
    identity is written to .git/worktrees/<name>/config.worktree
    instead of the shared config

Operator's identity now stays at navigator regardless of what
the swarm does in linked worktrees.

## Validation

- bash -n green on all 3 changed scripts
- Hotfix tested via the failing path from cold start: issue #2
  no longer claims; labels filter returns [] when no matches
fluidpop-bot left a comment
Collaborator

CI green (head ff2c965cf5), auto-approving

CI green (head ff2c965cf5405e1dd599ee8bac977da3b67a5319), auto-approving
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Fluid/fluidpop-v1!29
No description provided.