Skip to main content
← Back to list
01Issue
FeatureShippedSwamp ClubPublic
Assigneesstack72

Relationships

#2682 Add a duplicate_of relationship type to lab issues

Opened by stack72 · 9/29/2026· Shipped 9/29/2026

Add a duplicate_of issue relationship type to swamp-club's lab issues.

Why

The swamp repo's @swamp/issue-lifecycle model is getting a mark_duplicate method. When issue M duplicates issue N, M should be linked to N and then shipped with N's fix, not closed. Its reporter should get the normal "issue shipped" notification with a View PR link. Today the only way to record the connection is related_to, which the UI shows as "Sibling of". That's the wrong meaning, and nothing distinguishes a duplicate from a genuinely related issue.

This change is only about the relationship. Status transitions stay exactly as they are. The lifecycle model steps M through open → triaged → in_progress → shipped itself and passes N's githubPrUrl on the ship request.

Semantics

  • Direction: the duplicate is the source and the canonical issue is the target. POST /api/v1/lab/issues/{M}/relationships with { "type": "duplicate_of", "targetIssueNumber": N } means "M is a duplicate of N".
  • An issue can be a duplicate of at most one issue, the same idea as validateSingleParent for parent_of.
  • No chains: refuse if the target is itself duplicate_of something, and point the caller at that canonical issue instead. Refuse cycles and self-reference. validateNoSelfReference already handles self-reference.
  • Adding the same link again returns the existing one, like the other types (findExisting).
  • Permissions: allowed for an admin, or for the author of the source issue (someone marking their own report as a duplicate). Match the style of the existing per-type checks in _addRelationship.
  • Removing the link follows the existing removeRelationship rules. It has no side effects on status.

Where to change

  • lib/domain/lab/relationship.ts: add the type to IssueRelationshipType, plus a validator for the single-canonical and no-chain rules. Put it next to the parent_of validators.
  • lib/app/lab/manage-relationships.ts: permission rule and validation.
  • routes/api/v1/lab/issues/[number]/relationships.ts: add the type to VALID_RELATIONSHIP_TYPES and update the 400 error message that lists the valid types.
  • lib/app/lab/relationship-summary.ts: summarise the new type.
  • islands/lab/LabIssueDetail.tsx:
    • add it to the relationship picker (around line 1419);
    • show "Duplicate of #N" on M and "Duplicated by #M" on N, following how the parent/child and blocked-by sections render both directions (around lines 1330–1380);
    • check that the timeline event rendering (around lines 1993/2005, which does relationshipType.replace("_", " ")) reads well for the new type.
  • lib/infrastructure/mongo-lab-issue-repository.ts: check that nothing assumes the old three-value union when it reads events back.
  • extensions/models/_lib/swamp_club.ts (this repo's own lifecycle copy): widen the addRelationship type union.
  • Search for any other place that switches over relationship types, such as Discord handlers, reports, or OG images, and handle the new value or make sure it falls through safely.

Tests

Add to tests/domain/lab/relationship_test.ts and tests/domain/lab/manage_relationships_test.ts, covering:

  • creates the link and emits "relationship added" events on both issues;
  • adding it again returns the existing link;
  • rejects a second canonical issue for the same duplicate;
  • rejects chains, cycles and self-reference;
  • permissions: admin allowed, source author allowed, anyone else rejected.

Add a route test for the new type being accepted and for the updated error message.

Out of scope

  • Any automatic status change when a duplicate link is added. The lifecycle model owns that.
  • Changing notify-issue-resolved. It already notifies each shipped issue's reporter.
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 4 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

9/29/2026, 3:06:06 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack729/29/2026, 2:18:00 PM
Editable. Press Enter to edit.

system commented 9/29/2026, 2:16:29 PM

Classified automatically when this issue was filed.

  • Source: Swamp Club

If you feel this classification is incorrect, add a ripple to tell us so.

Sign in to post a ripple.