Bug: stale merged proposals incorrectly linked to unrelated issues
Observed
Issue #111 ("MWP-8: bust fetch-mpack cache on repair and force-push") shows a linked proposal it has no relationship to:
- Proposal:
sha256:e83b2606f750a38f5064d2adb51473e2d6afa4b936e328aa9924f61e01b2d873 - Proposal title: "Asyncpg Caps Query Parameters"
- Proposal state: merged
- Proposal branch:
feat/adding-debug-logs-to-staging - Proposal created: 2026-06-11 (≈ 20 days before this was noticed)
- Issue #111 created: 2026-06-26
The proposal is about asyncpg query-parameter capping during a debug-logging session.
Issue #111 is about cache invalidation in musehub_fetch_mpack_cache after repair
endpoints and force-push. There is no shared vocabulary in their titles, bodies, or
branch names.
Why this is a bug
A merged proposal that predates an issue by two weeks should never be auto-linked to that issue. Specifically:
- Already merged. Merged proposals are closed artifacts — they should not be retroactively associated with issues filed after they merged.
- No explicit reference. The issue body contains no mention of the proposal ID,
the branch name
feat/adding-debug-logs-to-staging, or any asyncpg-related keyword. The proposal body does not reference#111. - Wrong direction. If the linking heuristic is symbol-overlap (both touched musehub service/DB files), that signal is too weak to establish a link — nearly every musehub change touches the same small set of service files.
Hypothesised cause
The most likely explanation is a symbol-anchor or file-overlap heuristic that fires when:
- An issue is created or updated with
symbolAnchorspointing to files that were also changed in some proposal's diff, and - The heuristic does not filter out already-merged proposals.
Issue #111's symbolAnchors include:
musehub/services/musehub_gc.py::gc_fetch_mpack_cache
musehub/services/musehub_wire_push.py::wire_repair_commit
musehub/services/musehub_wire_push.py::wire_push_unpack_mpack
musehub/services/musehub_wire_fetch.py::wire_fetch_mpack
musehub/db/musehub_repo_models.py::MusehubFetchMPackCache
The asyncpg proposal (feat/adding-debug-logs-to-staging) likely touched one or
more of these files (asyncpg connection setup touches the DB layer). If the overlap
threshold is "any file in common," false positives are guaranteed on a small codebase
where every change goes through the same service layer.
A secondary hypothesis: the link was written at issue-update time (when the issue body was last pushed), not at issue-creation time, and the heuristic rescans all open+merged proposals rather than only open ones.
Expected behaviour
A proposal should be linked to an issue only when at least one of the following holds:
- The proposal body or commit message contains an explicit
#<issue-number>orissue/<issue-id>reference. - A user or agent explicitly calls a "link proposal → issue" API.
- The proposal was opened after the issue was filed and shares a branch that descends from the issue's anchor commit.
Merged proposals should be excluded from auto-linking entirely unless there is an explicit reference — their diff is historical and the relationship would need to be intentional.
Reproduction steps
- Open https://staging.musehub.ai/gabriel/musehub/issues/111 in a browser.
- Observe the linked proposal
sha256:e83b2606...("Asyncpg Caps Query Parameters"). - Open the proposal — note it is merged, predates the issue, and shares no explicit reference with #111.
Impact
- Incorrect UI signal: developers following the proposal link expect to find related work and instead find an unrelated merged PR.
- Trust erosion: auto-linking that fires on weak signals makes the feature indistinguishable from noise.
- Potential data integrity: if linked proposals gate any workflow (e.g., issue close requires linked proposal to be merged), false links could block or prematurely unblock issue state transitions.
Suggested fix surface
musehub/api/routes/ or musehub/services/ — wherever proposal→issue association
is written. Look for:
- The write path that creates a
proposal_issue_link(or equivalent) row. - Whether it filters
state == "open"proposals before matching. - The overlap threshold used for symbol/file heuristics.
A conservative fix: only link a proposal to an issue when the proposal body or any
of its commit messages contain an explicit #<n> reference that resolves to the
issue number in the same repo.