Skip to content

fix(linear): resolve UUID from parent labels for auto-label propagation#1188

Merged
aaight merged 2 commits intodevfrom
fix/linear-auto-label-propagation
Apr 24, 2026
Merged

fix(linear): resolve UUID from parent labels for auto-label propagation#1188
aaight merged 2 commits intodevfrom
fix/linear-auto-label-propagation

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Apr 24, 2026

Summary

Fixes a silent failure in propagateAutoLabelAfterSplitting where Linear's auto-label is never applied to backlog items after a splitting run because a name string is passed to addLabel instead of a UUID.

Card: https://trello.com/c/9B95OKSr/627-fix-auto-label-propagation-silently-fails-for-linear-during-splitting

Root cause

Two separate issues caused the silent failure:

  1. LinearIntegration.resolveLifecycleConfig defaulted unset labels to name stringslabels?.auto ?? 'cascade-auto' — for all 5 label roles. Unlike JIRA (which auto-creates labels by name) and Trello (which already returned undefined), Linear's adapter requires UUIDs in resolveLabelId(). Passing a name string causes resolveLabelId() to return null and the addLabel call to silently no-op.

  2. propagateAutoLabelAfterSplitting passed pmConfig.labels.auto directly to addLabel — without resolving the actual label ID from the parent work item's label list. Even when the parent has the right label (matched by name), the raw configured string was passed to the provider instead of the actual UUID.

Changes

src/pm/linear/integration.tsresolveLifecycleConfig

  • Removed name-string defaults (?? 'cascade-auto' etc.) from all 5 label fields
  • Labels not configured in the project are now undefined (correctly skips the operation)
  • Explicitly configured values are preserved as-is (no behavior change for configured projects)

src/triggers/shared/agent-execution.tspropagateAutoLabelAfterSplitting

  • Added UUID format check with logger.warn when labels.auto is not UUID format
  • Resolves the actual label id from the matched parent work item label (find() by id or name)
  • Passes resolvedAutoLabelId (always the id field, never the name string) to addLabel
  • Handles the case where matchedLabel is not found (fallback to raw autoLabelId)

tests/unit/triggers/shared/agent-execution.test.ts

  • New test: uses the resolved UUID from parent labels when labels.auto is a name string — verifies the fix for the Linear silent-failure case
  • New test: skips propagation (returns null) when labels.auto is undefined — verifies the fallback when no label is configured
  • New test: passes UUID directly when labels.auto is already a valid UUID (happy path) — verifies no warning and correct behavior for properly configured projects

tests/unit/pm/linear/integration.test.ts

  • Updated uses defaults when labels config is missingreturns undefined labels when labels config is missing (not name-string defaults) to reflect the new correct behavior

tests/unit/pm/linear/regression-2026-04.test.ts

  • Added 2026-04 regression: Linear auto-label propagation with name strings describe block with 3 tests:
    • Verifies unconfigured Linear labels are undefined (not name strings)
    • Verifies explicitly configured labels are preserved exactly
    • Explicit guard that none of the 5 labels default to 'cascade-xxx' strings

Test plan

  • tests/unit/triggers/shared/agent-execution.test.ts — 37 tests passing (4 new)
  • tests/unit/pm/linear/regression-2026-04.test.ts — 15 tests passing (3 new)
  • tests/unit/pm/linear/integration.test.ts — 33 tests passing (1 updated)
  • Full unit test suite — 8399 passed, 0 new failures
  • Lint (biome check) — no issues
  • Typecheck (tsc --noEmit) — no errors

Notes

  • JIRA is unaffected — intentionally keeps name defaults because JIRA's API auto-creates labels by name. The fix is Linear-only.
  • Trello is unaffected — already returned undefined for unconfigured labels.
  • The fix is backward-compatible: projects with explicitly configured UUIDs behave identically to before.

🤖 Generated with Claude Code

🕵️ claude-code · claude-sonnet-4-6 · run details

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 24, 2026

Codecov Report

❌ Patch coverage is 70.58824% with 5 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/triggers/shared/agent-execution.ts 58.33% 5 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

The label ID resolution elegantly fixes the silent failure in Linear by dynamically looking up the parent labels ID. However, the UUID validation warning will introduce log pollution for Trello and JIRA projects since they dont use UUIDs for labels.

Should Fix

  • src/triggers/shared/agent-execution.ts:678: The UUID validation warning if (!UUID_REGEX.test(autoLabelId)) will fire in the happy paths for JIRA (which uses name strings) and Trello (which uses 24-character MongoDB Object IDs). Since this file is shared across all PM providers, this will cause significant log pollution. Consider removing the warning entirely (since resolving by name is a valid feature), or scoping it to if (project.pm.type === "linear" && !UUID_REGEX.test(autoLabelId)).

(Note: If the warning is removed or scoped, the corresponding test in tests/unit/triggers/shared/agent-execution.test.ts that expect this warning will need to be updated as well).

🕵️ opencode · google/gemini-3.1-pro-preview · run details

The UUID validation warning in propagateAutoLabelAfterSplitting was firing
for Trello and JIRA projects in happy paths, causing log pollution. Trello
uses 24-character MongoDB Object IDs and JIRA uses name strings — both are
valid non-UUID formats for those providers.

Scope the warn() call to `project.pm.type === 'linear'` only, and update
the corresponding test comment to explain why no warning fires for Trello.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@aaight
Copy link
Copy Markdown
Collaborator Author

aaight commented Apr 24, 2026

Fixed! Scoped the UUID validation warning to project.pm.type === 'linear' only in propagateAutoLabelAfterSplitting:

if (project.pm.type === 'linear' && !UUID_REGEX.test(autoLabelId)) {
    logger.warn(
        'propagateAutoLabelAfterSplitting: labels.auto is not a UUID; resolving ID from parent labels',
        { autoLabelId },
    );
}

Trello (MongoDB Object IDs) and JIRA (name strings) are now silent on the happy path. The warning only fires for Linear projects where UUID format is actually required by resolveLabelId().

Also updated the corresponding test comment to explain that no warning is expected for the Trello project used in that test case. The UUID-resolution behavior (passing the actual id from the parent's label list to addLabel) remains unchanged for all providers.

🕵️ claude-code · claude-sonnet-4-6 · run details

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

LGTM — clean, well-targeted two-pronged fix for a real silent failure in Linear's auto-label propagation.

Verification notes:

  1. LinearIntegration.resolveLifecycleConfig — removing name-string defaults is safe. All callers of pmConfig.labels.* guard against undefined: PMLifecycleManager.safeAddLabel/safeRemoveLabel have if (!label) return;, hasAutoLabel returns false when !autoLabelId, and trigger handlers (e.g. linear/label-added.ts:40) check if (!readyLabel) return false;. The change is also consistent with Trello's existing pattern (already returned undefined for unconfigured labels). JIRA correctly keeps its name-string defaults.

  2. propagateAutoLabelAfterSplitting — the label resolution logic is sound. Since hasAutoLabel on line 663 and the matchedLabel find on lines 687-689 use identical matching logic (l.id === autoLabelId || l.name === autoLabelId) against the same parentWorkItem.labels array, matchedLabel is guaranteed non-null whenever hasAutoLabel returned true. The fallback to autoLabelId is pure defense-in-depth. The resolution is provider-agnostic (correct — improves Trello/JIRA too in edge cases) while the warning log is correctly scoped to Linear only.

  3. Test coverage — comprehensive: name-string-to-UUID resolution, undefined-label skip, UUID passthrough happy path, and regression guards pinning the no-default-names invariant.

🕵️ claude-code · claude-opus-4-6 · run details

@aaight aaight merged commit caa60c4 into dev Apr 24, 2026
8 of 9 checks passed
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.

2 participants