Skip to content

fix: default label sync to non-destructive merge mode (wave-1 Bug #1) - #40

Merged
avrabe merged 1 commit into
mainfrom
fix/label-sync-merge-mode
May 1, 2026
Merged

fix: default label sync to non-destructive merge mode (wave-1 Bug #1)#40
avrabe merged 1 commit into
mainfrom
fix/label-sync-merge-mode

Conversation

@avrabe

@avrabe avrabe commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Fixes Bug #1 from docs/agent-fleet/bugs.md — the wave-1 QA bug-hunter's #1 critical finding.

synchronizeIssueLabels was destroying user-created labels on every webhook tick. Now defaults to mode: 'merge' (non-destructive); old behaviour preserved as opt-in mode: 'replace' via issue_labels_sync_mode config.

  • 808 tests pass (+2 regression coverage)
  • eslint clean

🤖 Generated with Claude Code

## Why
`synchronizeIssueLabels` (`src/labels.js:69-78`) unconditionally deleted any
repo label not in the target list. It runs on every `repository.created`,
every `/sync-all-repos`, every `/configure-repo`, and every `reconcile-repo`
task. **A user creating a `priority/p0` label saw it silently destroyed
the next time the bot synced** — across the org, on every webhook tick, with
no opt-out.

This was wave-1 Bug #1 (the QA bug-hunter's #1 critical) and the highest-
priority finding in `docs/agent-fleet/bugs.md`.

## What
`synchronizeIssueLabels` now takes a `mode` option:
- **`'merge'`** (default) — only create / update labels listed in
  `targetLabels`. Labels not in the target list are left untouched.
  Non-destructive.
- **`'replace'`** — current destructive behaviour, preserved as opt-in.

`config.yml` gains an `issue_labels_sync_mode: merge | replace` setting
(default `merge`); `src/repository.js` reads it and threads it through.
`src/schema.js` validates the new field.

## Source
Wave-1 QA bug-hunter (Bug #1, `docs/agent-fleet/bugs.md`).

## Test plan
- [x] 808 tests pass (was 806; added "does NOT remove in default merge mode"
      regression test for Bug #1; added "rejects invalid mode value"; converted
      the two existing replace-mode assertions to opt-in via `{mode: 'replace'}`)
- [x] eslint clean

## Risk & rollout
- Risk: **medium-low**. Behaviour change for existing operators: deletions
  stop happening unless they explicitly set `issue_labels_sync_mode: replace`.
  Almost everyone wants the new default. Anyone relying on the old destructive
  sweep will see a CHANGELOG entry and a `replace` opt-in.
- Rollout: self-update on merge.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@avrabe
avrabe merged commit ab745af into main May 1, 2026
5 checks passed
@avrabe
avrabe deleted the fix/label-sync-merge-mode branch May 1, 2026 07:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant