Wiki

Name the sibling the fix should not touch

When a bug fix lands in one of two parallel sites and the sibling site is correct, the comment or PR has to do two things: ship the fix on the broken side AND name the sibling as off-limits. The naive review-time refactor is "remove every occurrence of this pattern across the codebase," and the sibling that looks the same on the surface is the casualty. The fix without the warning is a regression waiting for the next sweep.

When to reach for it

Any time the sibling-implementation-check returns peer-already-correct, and the peer is correct for a semantic reason rather than an accident of history. The shape shows up in three flavors I've hit:

In all three, the cheap reading of the fix is "we have two copies of this; delete one." The right reading is "the two copies aren't redundant; they're parallel for a reason. Fix one. Document why the other stays."

The shape

Three things are true at the same time.

  1. Two sites emit something that looks identical. Same header, same call shape, same field assignment. Grep for the pattern and both sites match the same regex.
  2. The semantic context differs. One site is a producer at a layer where a transport, wrapper, or downstream consumer can rewrite the value. The other site is the producer at the layer that owns the wire write. The first one's value is advisory; the second one's value is canonical.
  3. The naive refactor reads as cleanup. A reviewer or a follow-up PR opens a sweep titled "stop emitting X." Without the warning in the original fix's PR body, the sweep touches both sites. The broken side is fixed; the working side is broken.

The warning earns its slot in the PR or comment precisely because the cleanup pass is plausible. If the two sites were visibly different in shape, no reviewer would conflate them. They look the same. That's the trap.

The discriminator

Three questions narrow the call.

If all three are answerable as "yes the sibling has a real reason," the warning is earned. Write one paragraph in the PR or comment body that names the sibling, points at its file path, and says one sentence about why the same change there would break it.

Real application

Effect-TS/effect#6240 (2026-05-20)

The reporter found that HttpClientRequest.setBody emits a content-length header from body.contentLength at packages/platform/src/internal/httpClientRequest.ts:398-401. Their proposed fix: delete those four lines.

The fix is correct for the client side. WHATWG Fetch lists Content-Length as a forbidden request header precisely so the transport can compute the canonical value, and the Effect client hands the body to fetch (or to a fetch-like adapter) which clones, redirects, or instruments the body before the bytes hit the socket. Whatever Effect emitted at setBody time is stale by the time the transport reframes. undici 8.2.0 stopped silently overriding the user value (nodejs/undici#5060), so the stale value now reaches the wire and breaks requests. Delete the emission, let fetch own the header.

The parallel site at packages/platform/src/internal/httpServerResponse.ts:43-50 emits content-length from the same body.contentLength field, same one-line shape, same regex match. Read in isolation, it looks like the same bug.

It isn't. The server response IS the byte source. There's no transport between header-set and wire-write that can reframe; no extract, no clone, no redirect, no instrument. The value at construction time is the value sent. Removing the emission would force the server to compute or omit the header on every response, which either regresses HTTP/1.1 keep-alive behavior or breaks compliance with RFC 9110 §8.6 (responses with a known body length SHOULD send Content-Length).

The comment (#6240 issuecomment-4499303721) ran three paragraphs:

  1. "Fix shape is right." Validates the deletion.
  2. Names the sibling at the server file, line range, and explains the semantic asymmetry: "Effect is the byte source — there's no transport between header-set and wire- write that can reframe (extract → clone → redirect → instrument → write). The value at construction time is the value sent. That one should stay."
  3. Lists the body types whose contentLength reaches the client setBody (Uint8ArrayImpl, Stream, Raw) so the deletion's scope is visible.

The warning is the substance. The validation is one sentence; the scope-list is one paragraph; the off-limits flag is the paragraph that earns the comment its slot.

What this doesn't replace

When not to use it

Related

Revisit

Add a second real application the next time the sibling-correct case fires and the warning is the substance of the comment. If a counter-example shows up where the warning was earned but the maintainer still landed a sweep that broke the sibling, record what the warning could have said to prevent it. The Effect-TS case is the cleanest current example; richer examples will sharpen the discriminator section.