ci: add the fork-sync backport queue - #28
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an automated “fork sync / backport queue” mechanism to track unreconciled commits in MiSTer-devel/Linux-Kernel_MiSTer and surface them via a single, continuously-updated GitHub issue.
Changes:
- Add
docs/kernel-recon/fork-sync.confto record the last reconciled commit per watched fork branch. - Add
scripts/check-fork-sync.shto compare those sync points against live fork HEADs via the GitHub compare API (no clone) and emit text/markdown reports. - Add
.github/workflows/fork-sync.ymlto run weekly/on-demand and open/update/close a single labeled issue based on drift.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
scripts/check-fork-sync.sh |
New CLI script that queries GitHub’s compare API for each watched branch and prints drift reports. |
docs/kernel-recon/fork-sync.conf |
New config file defining the branch→“last reconciled SHA” sync points plus update guidance. |
.github/workflows/fork-sync.yml |
New scheduled workflow that runs the check and manages a single “backport queue” issue. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
mcfbytes
added a commit
that referenced
this pull request
Jul 16, 2026
Four review findings on #28, all valid. One of them was worse than reported. `ahead_by` was used unguarded. Bash arithmetic treats a bare word as an unset variable, so BOTH `[[ null -eq 0 ]]` and `[[ "" -eq 0 ]]` evaluate TRUE -- verified. The review said an unexpected response could produce a bogus triage report; it is the opposite and worse. Any response that parsed but had no ahead_by (auth failure, rate limit, partial body) made the script print "nothing new" and exit 0: a silent all-clear. A tool whose entire purpose is to stop commits going unaccounted for had a path where it silently said all-clear because it could not tell. Now the value must match ^[0-9]+$ or it exits 2. Verified with a stand-in `gh` returning {"message":"Bad credentials"}: exits 2 naming the branch, instead of reporting reconciled. jq was invoked three times and checked zero. Now checked alongside gh, so a missing dep is exit 2 with context rather than 127 from somewhere inside a pipeline. The workflow called the script TWICE -- plain for the log, --markdown for the issue body with `|| true` to swallow the expected exit 1. Wrong twice over: `|| true` also swallows exit 2, so a broken run could file an issue with an empty body and still go green; and two invocations are two sets of API calls that can disagree if one hits a transient failure. Now one --markdown invocation feeds both, with the exit code routed through a case (0 clean / 1 triage / 2 fail), and an explicit assertion that the body is non-empty before it can be posted -- which is the failure the single invocation exists to close, so it is checked rather than assumed. Halves the API calls as a side effect. `gh issue list` now passes --limit 1: only the first match is used, and the default page of 30 is API work nobody looks at. Verified: shellcheck clean, YAML parses, both run blocks pass `bash -n`, the normal path still reports fully-reconciled (exit 0), and the markdown body renders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This repo is the source of truth for the MiSTer kernel, but the fork is a live
repo other people commit to. Anything landing there after our last reconciliation
is something we do not have and nobody has decided about -- and nothing ever forces
that question. That is not hypothetical: the fork sat on 5.15.1 through 210 stable
releases partly because no moment ever said "these N commits are unaccounted for",
and this session alone hit two stale-baseline bugs, one of which nearly shipped an
auto-overclocking kernel.
Three pieces:
- docs/kernel-recon/fork-sync.conf -- the last RECONCILED commit per fork branch.
Previously this existed only as prose in docs/patch-provenance.md's header
("HEAD f0fb626acadd..."), which cannot be diffed against anything. Recorded at
794e6f002 (v5.15) and d9ac12a691 (v6.18); the header spells out that advancing a
line without dispositioning what it skips is the one thing that breaks the
mechanism -- it would stop meaning "reconciled" and start meaning "seen".
- scripts/check-fork-sync.sh -- diffs that file against the fork's live HEADs via
the compare API. One call per branch, no clone: the kernel repo is ~300MB and
answering "what is new" does not need it. Exit 0 reconciled / 1 triage / 2 error.
- .github/workflows/fork-sync.yml -- weekly, plus dispatch. Seconds per run, no
build, no checkout of the kernel; far below the noise floor of build.yml's ~3h
cold path, which is what makes a schedule affordable here at all.
Watches BOTH branches. MiSTer-v6.18 is the one that matters most: once #75 merges,
commits landing there are changes made to OUR series by other people, and they must
flow back into linux-patches/ or the next regeneration silently erases them.
Design points that are deliberate, not incidental:
- ONE issue, edited in place, closed when the queue empties. A weekly job that
files a fresh issue is a job people mute, and a muted queue is the same as no
queue.
- Exit 1 (commits to triage) does NOT fail the job -- a red X every week trains
people to ignore it. Only exit 2 (missing branch, malformed conf) fails.
- `gh issue create` prints a URL and has no --json/--jq; the number comes off the
URL rather than from a `||` fallback around a second create, which is how you
file two issues.
Verified: reports "fully reconciled" today (exit 0); rewinding the v5.15 pointer to
the old recon baseline f0fb626ac correctly flags 794e6f002 "New driver for
RTL8821CU" (exit 1) and renders the markdown issue body. YAML parses, both embedded
run blocks pass `bash -n`, shellcheck clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Four review findings on #28, all valid. One of them was worse than reported. `ahead_by` was used unguarded. Bash arithmetic treats a bare word as an unset variable, so BOTH `[[ null -eq 0 ]]` and `[[ "" -eq 0 ]]` evaluate TRUE -- verified. The review said an unexpected response could produce a bogus triage report; it is the opposite and worse. Any response that parsed but had no ahead_by (auth failure, rate limit, partial body) made the script print "nothing new" and exit 0: a silent all-clear. A tool whose entire purpose is to stop commits going unaccounted for had a path where it silently said all-clear because it could not tell. Now the value must match ^[0-9]+$ or it exits 2. Verified with a stand-in `gh` returning {"message":"Bad credentials"}: exits 2 naming the branch, instead of reporting reconciled. jq was invoked three times and checked zero. Now checked alongside gh, so a missing dep is exit 2 with context rather than 127 from somewhere inside a pipeline. The workflow called the script TWICE -- plain for the log, --markdown for the issue body with `|| true` to swallow the expected exit 1. Wrong twice over: `|| true` also swallows exit 2, so a broken run could file an issue with an empty body and still go green; and two invocations are two sets of API calls that can disagree if one hits a transient failure. Now one --markdown invocation feeds both, with the exit code routed through a case (0 clean / 1 triage / 2 fail), and an explicit assertion that the body is non-empty before it can be posted -- which is the failure the single invocation exists to close, so it is checked rather than assumed. Halves the API calls as a side effect. `gh issue list` now passes --limit 1: only the first match is used, and the default page of 30 is API work nobody looks at. Verified: shellcheck clean, YAML parses, both run blocks pass `bash -n`, the normal path still reports fully-reconciled (exit 0), and the markdown body renders. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mcfbytes
force-pushed
the
feat/fork-sync-queue
branch
from
July 16, 2026 17:55
44ec573 to
57a6779
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
This repo is the source of truth for the MiSTer kernel, but
MiSTer-devel/Linux-Kernel_MiSTeris a live repo other people commit to. Anything landing there after our last reconciliation is something we don't have and nobody has decided about — and nothing ever forces that question.That's not hypothetical. The fork sat on 5.15.1 through 210 stable releases partly because no moment ever said "these N commits are unaccounted for". And this session alone produced two stale-baseline bugs — one of which nearly shipped an auto-overclocking kernel to upstream.
The sync point did exist before this PR, as prose in
docs/patch-provenance.md's header (HEAD f0fb626acadd…). Prose can't be diffed against anything.What
docs/kernel-recon/fork-sync.confscripts/check-fork-sync.sh.github/workflows/fork-sync.ymlWatches both branches.
MiSTer-v6.18is the one that matters most: once #75 merges, commits landing there are changes made to our series by other people — and they have to flow back intolinux-patches/or the next regeneration silently erases them. That's the failure this prevents.Cost
Two compare API calls, no clone, seconds per run. It deliberately doesn't check out the kernel (~300MB) or build anything — "what's new upstream" needs neither. That's what makes a weekly schedule affordable at all; contrast
build.yml, whose cold path is ~3h.Weekly is matched to how fast the fork actually moves (11 commits across 2026 so far). Daily would just re-post the same list six more times before anyone acted on it.
Three deliberate design choices
gh issue createhas no--json/--jq; it prints a URL. The number comes off the URL rather than from a||fallback around a secondcreate, which is how you end up filing two issues.The one way this breaks
Advancing
fork-sync.confto silence the issue, without dispositioning what it skips. Then the file stops meaning reconciled and starts meaning seen — which is exactly what it exists to prevent. The header says so explicitly.Verification
v5.15pointer to the old recon baselinef0fb626accorrectly flags794e6f002"New driver for RTL8821CU", exit 1, and renders the markdown issue body.runblocks passbash -n, shellcheck clean.I'll dispatch it once merged to confirm a real run goes green (it should report "fully reconciled" and create nothing).
Follow-up
export-kernel-tree.sh --fork-sync(on #25) should default to reading this file once #25 lands, so the sync point has one home rather than two.🤖 Generated with Claude Code