You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ci(port): track upstream HEAD instead of the latest published release
The pipeline resolved the latest npm release and ported its tag. That is why
today's cron run found "no changes" while upstream main carried an unported
doom-loop commit (#73) — ~7,500 lines, ~4,700 of it tests, rewriting a large part
of model-result.ts. Release tracking sounds conservative and produces exactly the
failure this pipeline exists to prevent: the port stays blind to unreleased work,
then absorbs the whole delta in one automated run against the most load-bearing
module in the package. Tracking HEAD keeps each delta reviewable.
Ref resolution
- The workflow no longer queries the npm registry. A blank ref means upstream
default-branch HEAD, which scripts/upstream already resolves on its own.
- The publish dispatch's client_payload.ref is now deliberately IGNORED (with a
::notice:: saying so). It carries the release tag, which becomes an ancestor of
HEAD as soon as the port is ahead of the release — honoring it would revert
landed work. The dispatch still does its real job: waking the pipeline promptly
after a release. It just syncs to HEAD like every other trigger.
- Fixed a latent bug in the Run port step: it passed `--ref ""` when no ref was
resolved. The arg parser consumes the empty value, so that is not the same as
omitting the flag. Now the flag is only passed when there is a ref. Verified all
four arg combinations parse correctly.
Refusing to port backwards
scripts/upstream now exits 3 if the target commit is an ancestor of
state.yaml's upstream_commit, printing how many commits behind it is and pointing
at --force as the deliberate override. Without this, a single stale --ref (or a
dispatch payload, before the change above) would instruct the converter to
faithfully port an older tree and silently revert everything since. Verified: the
guard fires on the real 0.8.0 tag once state claims HEAD, and --force bypasses it.
Version honesty when ahead of a release
Being ahead is now the normal state, and it is invisible to the old check:
package.json on main still carries the last released number, so pyproject.toml
matches it and the check passes — while the tree contains unreleased work.
- verify.sh now also compares the ported commit against the release tag for the
declared version. Level with the tag PASSes as publishable; ahead prints a NOTE
with the commit count and an explicit "do not publish this version" warning.
Ahead is not a failure — it is the intended state — so it does not fail the run.
- publish.yaml gets a hard gate, because verify.sh's NOTE only appears when a sync
run has left an upstream checkout in tmp/, and there is none at publish time. It
clones upstream, requires a release tag matching the declared version, and
refuses if the ported commit is ahead of it. Verified in all three states: level
allows, ahead refuses, missing tag refuses.
Publishing X.Y.Z from a tree ahead of upstream's X.Y.Z tag ships unreleased work
under a released number, and a PyPI version can never be reused.
Also: exclude tmp/ from ruff
Found while testing: a port run writes scratch files under tmp/ (gitignored, but
ruff still walks it), and one stray probe script failed `ruff check` and
`ruff format` — 22 errors that had nothing to do with the port. A sync run could
fail its own mechanical gate on its own scratch space. mypy was already scoped to
src/tests and unaffected.
Docs
PORTING.md's pipeline diagram now shows the real trigger set and the backwards
refusal, plus a section on why HEAD over releases and the two consequences. The
contract's Package Version section says between-releases is now the normal state,
tells a sync to report how far ahead it is, and states the publishing rule.
Verification: verify.sh PASS (0 failures) · all three workflows parse · guard and
publish-gate logic each verified in three states · ruff/mypy clean with a
deliberately broken file in tmp/ · 114 passed, coverage 83.89%.
Co-Authored-By: Claude <noreply@anthropic.com>
if ! git -C /tmp/upstream-check rev-parse -q --verify "refs/tags/$TAG" >/dev/null; then
114
+
echo "::error::Upstream has no release tag $TAG. This package's version tracks the ported @openrouter/agent version, so publishing $VERSION means upstream released it. Wait for the upstream release, or correct the version."
echo "::error::The ported commit is $AHEAD commit(s) ahead of the $TAG release tag. Publishing $VERSION now would ship unreleased upstream work under a released version number, and a PyPI version can never be reused. Publish from a commit level with a release tag, or wait for upstream to release what the port has reached."
121
+
exit 1
122
+
fi
123
+
echo "Ported tree is level with $TAG — $VERSION is honest to publish."
echo "::notice::Ignoring dispatch payload ref '$PAYLOAD_REF' — this port tracks upstream HEAD, and a release tag is an ancestor once the port is ahead of it. Syncing to HEAD instead."
93
+
fi
94
+
echo "No explicit ref — porting upstream default-branch HEAD."
70
95
fi
71
96
echo "ref=$REF" >> "$GITHUB_OUTPUT"
72
97
@@ -84,9 +109,14 @@ jobs:
84
109
echo "::error::OPENROUTER_API_KEY secret is not set. See .upstreamer/port.env.example."
85
110
exit 1
86
111
fi
87
-
args=(--ref "${{ steps.target.outputs.ref }}")
112
+
# Only pass --ref when there is actually a ref. `--ref ""` is not the
113
+
# same as omitting it: the arg parser consumes the empty value and the
114
+
# script would target an empty ref instead of defaulting to HEAD.
0 commit comments