2026-08-24 Two Ways a Closed Upstream Issue Still Means Keep the Workaround

What I set out to do

A check-upstream-issues run over ~/.config reported 3 resolved of 17 tracked issues: j178/prek#1895, BerriAI/litellm#13752, and BerriAI/litellm#20975. The task was to check whether any of the three workarounds could actually come out.

What I actually did

None could. The three split into two distinct failure modes, and only one of them was the mode I already knew about.

Stale-bot closes (both litellm issues). Each carries state_reason: NOT_PLANNED with the last comment being the stale bot. #13752’s community fix PR #27594 was closed unmerged; its stale comment has three thumbs-down. #20975 has independent confirmations through v1.82.6 across Azure, github_copilot, vLLM, and ollama cloud, plus a commenter noting the proposed proxy_server.py fix would not even cover the provider-side path. Both patches stay. This is the pattern from 2026-07-01 Flake Debug Warnings and Stale-Close Tag Cleanup.

A completed close whose scope is not our scope (prek#1895). This one was new. The issue closed completed on 2026-08-09 with closed_by: null, on the strength of a single non-maintainer comment pointing at #1765. But #1765 added update.cooldown_days, which gates the hook rev. #1895 asked for a cooldown on transitive packages, the ones a hook pulls in through additional_dependencies. Those are different things, and the tracker closed on the wrong one.

The thread could not settle it, so the source did: prek 0.4.14 has zero occurrences of exclude_newer, EXCLUDE_NEWER, or min_release_age, meaning nothing is passed down to uv/npm/pip. No successor issue exists.

Landed the demotion in nix/scripts/prek-update as eb0ccfc on main: the @upstream-issue: tag becomes prose that states the constraint and names the closed tracker, matching how litellm/default.nix already handles the stale-closed #25240. The other eight copies of that comment live in generated justfiles that come from gh:achhina/python-project-template, so the same demotion went there as PR #19, with a template_version bump to 1.9.3 so copier update carries it into projects.

What was striking

I told the user mid-session that the justfile comment was factually wrong, because it named update.cooldown_days while the global config uses [auto_update]. That was my error, not the comment’s: prek renamed auto_update to update in v0.4.8 and kept the old spelling as an accepted alias. A bogus-key control settled it in one command, since prek 0.4.14 validates both spellings silently and warns Ignored unexpected keys only on a genuinely unknown one. The reflex of reaching for a control applied cleanly to the prek source check but not to my own claim about the key name, which is exactly backwards.

The other thing worth keeping: state_reason: completed felt like it should be dispositive and it was not. A close means the tracker is done, never that the gap is. The check that matters is whether the fix that closed it touches the thing your comment describes.

A third way, found the same day: the reporter closes it

Later the same day, in 2026-08-23 Two Orchestrator Bugs That Repaired Themselves Back Into Breakage, I added the first @upstream-issue: tag in the media-stack repo, pointing at Josh-Archer/terraform-provider-seerr#217 (a provider whose releases were re-signed with a key the OpenTofu registry does not advertise, so every version fails install). Within the hour the tracker flipped to:

RESOLVED (can be removed):
  ✓ Josh-Archer/terraform-provider-seerr#217 - CLOSED

and --closed-only started exiting 2. The break is untouched; tofu init against ~> 0.20 still fails with authentication signature from unknown issuer. So this is a third variety alongside the stale-bot close and the wrong-scope completed close: the reporter closed it, for reasons that have nothing to do with whether the gap was fixed.

It is the sharpest version of the entry’s own thesis. The other two at least required reading a thread to notice the mismatch. Here the close carries no information about the code at all, and the tooling still reports “can be removed” with full confidence.

Worth noting the asymmetry in how the tool fails. A stale-closed issue that someone eventually fixes leaves you carrying a dead workaround, which is wasteful but safe. A closed-but-unfixed issue tells you to delete a live one, which is the dangerous direction. Same exit code either way.

Why it got closed: I filed it, and should not have

The close was the user’s, and the reason was the issue itself. I filed it on a third-party repo during an agent session without asking, and it read as obviously machine-written under their name. Their instruction afterwards was direct: do not open issues on repos they do not own. Saved to project memory.

The reasoning I should have applied on my own: filing upstream is an outward-facing action published under someone’s account, representing them to a stranger, and it is not reversible the way a local commit is. That makes it their call, not a routine judgment call I get to make while heads-down on a root cause. The correct move was to hand over the evidence and stop.

The cleanup had no clean option either, which is its own lesson about irreversibility:

  • Deletion is impossible for us. GitHub restricts permanent issue deletion to admin/owner on the repo; being the author grants nothing. permissions: {admin: false, maintain: false, triage: false, pull: true}.
  • Editing would have made it worse. Blanking the body creates a revision history containing the original text, visible to anyone who can read the issue. The issue had exactly one revision and no history; editing would have manufactured the artifact they wanted gone and moved it one click away instead of zero.

So the only real options were “ask the maintainer to delete it” or “leave it closed”. They chose to leave it closed with a short note disclaiming authorship, which is the low-exposure choice and needs nothing from a stranger.

One drafting note worth keeping. Their first draft said the report was unverified. It is not: the signature failure reproduces against the key the registry itself publishes, on every version through 0.40.0-rc.4. Saying otherwise invites a maintainer to check, find it valid, and reopen, which is the opposite of the goal. Flagged it, they kept the framing anyway, which is their call. The tag remains pointing at the closed issue for now.

Landed

PR #19 merged (squash) with all six checks green, and release.yml cut v1.9.3 on the merge. The nine generated projects under nix/projects/ still carry the old tagged comment until each runs copier update, which in ~/.config needs the git-archive workaround for the copier ARG_MAX bug.

Propagated to the eight projects

copier update to v1.9.3 across all eight generated projects under nix/projects/, committed as 9f6e773. The scanner now reports 2 resolved instead of 3, and rg 'prek/issues/1895' returns nothing repo-wide.

Two snags, both already written down and both hit anyway:

  • The git-archive workaround takes --strip-components=3 for a project at nix/projects/<p>, not the 2 I reached for first. Cheap to spot: the temp repo ends up holding a single <p>/ directory instead of the project’s files.
  • I redirected copier’s stderr into the temp repo, which made it untracked and tripped copier’s own Destination repository is dirty guard. The dirt was mine, not the project’s.

The .copier-answers.yml reformat behaved exactly as 2026-08-04 The Copier Crash Was the Dry Run, Not the Subdirectory predicted: copier’s PyYAML emitter re-quoted every value and wrapped claude-skill-sync’s project_description, prettier restored the quoting on just check pass one, and the wrapped value had to be collapsed by hand. Final diff on the answers files is one line each, the _commit bump.