fix(upstream): pin Marker Guard to the upstream baseline tag; refuse cross-major merges
Issue for this PR
Closes #1504
Type of change
- Bug fix
- New feature
- Refactor / code improvement
- Documentation
What does this PR do?
Marker Guard has been silently passing everything since upstream promoted OpenCode v2 into dev (2026-10-10). It decided which files are upstream-shared by listing upstream/dev, then upstream/main. v2 has no packages/opencode paths, so every v1 file looked fork-only and unmarked edits passed --strict.
Changes:
- Ownership comes from a pinned tag.
upstreamBaseline: "v1.17.9"inscript/upstream/utils/config.tsis the upstream tag we are based on; bump it when a merge lands.getUpstreamFiles()lists files only fromrefs/upstream-baseline/<tag>, a dedicated ref namespace, so a fork-owned tag or local branch with the same name can't shadow it. If that ref is missing, it fetches it once fromupstream; if that also fails, it warns with the fetch command and uses the old directory fallback. - CI fetches the tag. The marker-guard job reads it with the new
analyze.ts --print-baselineand fetchesrefs/tags/<baseline>:refs/upstream-baseline/<baseline>, because the job fetches with--no-tags. The toolingbun installstep moved before the fetch so the script can run.runMarkerCheckno longer fetches the moving branch. If the baseline ref is missing locally,getUpstreamFilesfetches it once before warning. - No cross-major merges.
merge.ts(including--continue) andbridge-merge.tsrefuse a target whose major differs from the baseline, before touching git.list-versions.tslists only same-major releases and prints a note when newer majors exist. v2 replacespackages/opencodeand the plugin/session/server APIs, so it is a re-port, not a merge with these scripts.
Behavior changes:
- PRs that add unmarked code to files present at upstream
v1.17.9now fail Marker Guard again. They have been passing since 2026-10-10. Open PRs touching upstream files may go red on their next run; that is the guard working, not a regression. list-versions.tsstops suggesting v2 tags.
Follow-up, not in this PR: nothing bumps upstreamBaseline automatically after a same-major merge. The README says to bump it; this only matters if we do another v1 merge.
Not changed: the parser still ignores import/export lines and comment-only lines. That is an existing heuristic, and an unmarked export const x = 1 still passes.
How did you verify your code works?
cd script/upstream && bun test: 42 pass, 0 fail. New tests: baseline ownership vs moving branches; missing baseline is fetched once, then warns and falls back; the major-version helper; andmerge-guard.test.ts, which runs the realmerge.ts/bridge-merge.tswith a v2 target and asserts exit 1 with HEAD/status unchanged.- Side-by-side on throwaway worktrees of
origin/main, appending the unmarked statementconst __markerProbe = Date.now() + 1topackages/opencode/src/session/prompt.tsand runninganalyze.ts --markers --base <parent> --strict:- old tooling:
ok No upstream-shared files modified, exit 0 - this branch: fetches
refs/upstream-baseline/v1.17.9on its own, flags the file,error --strict mode — failing CI, exit 1
- old tooling:
- Not run: the GitHub Actions job itself. The new tag-fetch step runs for the first time on this PR's CI.
Screenshots / recordings
N/A
Checklist
- I have tested my changes locally
- I have not included unrelated changes in this PR
🤖 Generated with Claude Code
Summary by CodeRabbit
- New Features
- Upstream release suggestions now stay within the configured baseline’s major version, with warnings when newer major releases are excluded.
- Merge attempts for other major versions are rejected before repository state changes, with guidance to re-port instead.
- File ownership checks use the configured baseline, attempt to fetch it when unavailable, and fall back to directory-based checks if fetching fails.
- Added a command to display the configured baseline.
- Documentation
- Updated the runbook with baseline, version-filtering, merge, and ownership-check guidance.
[!NOTE]
Medium Risk
Changes CI enforcement for upstream-shared files (PRs touching v1 paths may fail until marked) and merge tooling behavior, but does not alter runtime product code paths.
Overview
Fixes Marker Guard silently passing after upstream v2 landed on dev: shared-file detection no longer follows upstream/dev or upstream/main. It uses a pinned upstreamBaseline (v1.17.9 in utils/config.ts) and lists files from refs/upstream-baseline/<tag> so moving branches and same-named fork tags cannot clear the guard. analyze.ts --print-baseline supports CI; the marker-guard job installs merge tooling first, then fetches that tag into the namespaced ref. Missing baseline triggers a one-time fetch, then a warning and directory fallback. runMarkerCheck no longer fetches the moving upstream branch.
Adds major-version policy: merge.ts (including --continue) and bridge-merge.ts call assertSameMajor before touching git; list-versions.ts only suggests same-major releases and warns when newer majors exist. README documents baseline bumps and v2 as a re-port.
Extensive tests cover baseline ownership, fetch/fallback, version parsing, and dry-run merge guards leaving the repo unchanged.
Reviewed by Cursor Bugbot for commit 0cb93b790db2b2b1325f53a4ec44c465623f03ca. Bugbot is set up for automated code reviews on this repo. Configure here.