The write-deadline-kill predicate is copied per format package, and its two callers admit different endings

What

Two format packages carry a byte-identical predicate that decides whether a failed response write was the write deadline expiring or the client going away:

  • remoteTarballWriteDeadlineKill in internal/format/npm/remote_tarball.go
  • blobFillWriteDeadlineKill in internal/format/oci/remote_blob.go

Both take (err error, deadline time.Time), answer true past the armed instant, and fall back to errors.As(err, &netErr) && netErr.Timeout() when the instant is the zero value because arming failed.

The duplication is correct as things stand. ADR-023 has format packages copy rather than import from each other, and the OCI copy's doc comment names the npm original. Nothing here proposes deleting either one on its own.

What is worth tracking

The two are changed together whether or not anyone notices, and so far nobody has. The same defect family has now been found twice, once per package, by two different reviews:

  • #832: on the npm route the deadline-kill arm claims an upstream stall, because the stall reports Timeout() == true while the armed instant is still in the future.
  • On the OCI blob route the read arm claimed a client hangup, because a cancellation aborts the body read and arrives wrapped exactly like an upstream that stopped sending. Fixed in Step 15 part 2 of the S16 container remote work by admitting only a live request context to that arm.

Both are the same shape — an arm claiming an ending that belongs to another party — and in both cases the predicate is right and the caller is what decides what may reach it. Neither fix reached the other package, because nothing links the copies beyond one doc sentence.

Proposal

Two parts, and the second is the one with a decision in it:

  1. Record the pairing where a reader will meet it. Each copy's doc names the other, and each names what its own caller admits: the npm caller lets the upstream's reads reach the predicate, the OCI caller does not. That asymmetry is why npm names its counter for what the arm books rather than for the deadline, and it is the thing a reader has to know before copying either one again.
  2. Decide whether a shared home is wanted. If a package for the relay-side primitives these routes share ever lands, both predicates collapse into it and ADR-023's copy rule stops applying, because the shared package would not be a format package. Until then the copies stay and part 1 is the whole of the work. Adopting a shared home is an ADR-023 conversation, not a refactor somebody can land quietly.
  • #832 — the npm half of the defect family above.
  • #841 — asks the OCI manifest arm for an attributable deadline kill, which is what puts a third caller of this predicate in prospect.