From a00dffdbd3295ab4c93cdc22405bbd127e88e908 Mon Sep 17 00:00:00 2001 From: Andrew Mikofalvy <5668128+amikofalvy@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:01:05 -0700 Subject: [PATCH] fix(open-knowledge): prevent beta-base collision after stable promotion (#2104) After a stable is promoted, the beta cycle anchor in pre.json trails the just-shipped stable until main-reset advances it (a cross-repo PR plus Copybara round-trip). Any feature mirror push that lands in that window makes release.yml compute a beta base equal to the fresh stable, tripping the "beta base must lead the latest stable" guard with a red, paging failure even though the condition is transient and self-healing. It got worse when the main-reset PR was ejected from the merge queue without re-enqueuing, stranding the anchor advance and stretching the window to 25+ minutes until a manual admin merge. Two levers: 1. release.yml compute-beta now DEFERS instead of failing when the computed base equals the latest stable: it skips the cut with a loud warning and re-cuts automatically once the anchor leads. The Guard step is narrowed to a backstop for a base strictly BEHIND stable (genuine drift), which stays a hard failure. 2. main-reset.yml lands its bot PR with a direct admin merge instead of riding the merge queue, collapsing the race window to about a minute and removing the queue-eject failure mode. It falls back to queued auto-merge if the token cannot bypass, so it never hard-fails. Lever 2's admin path activates only once the inkeep-internal-ci app is a bypass actor on main's ruleset; until then it falls back to today's behavior. Lever 1 is effective immediately and needs no permission grant. GitOrigin-RevId: 2686a67bc9a06cdc39cbfe60c6b1c333b65135de --- .github/workflows/release.yml | 34 +++++++++++++++++++++++++--------- README.md | 6 ++++-- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f295168cb..917b3af0f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -195,6 +195,22 @@ jobs: exit 0 fi BASE=$(echo "$OUTPUT" | jq -r .baseVersion) + # Defer (don't fail) while the anchor is catching up to a fresh stable. + # Right after a stable promotion, pre.json's anchor still trails the + # just-shipped stable until main-reset advances it (a cross-repo PR + + # Copybara round-trip — minutes). Any mirror push landing in that window + # computes BASE == the fresh stable. Cutting it would regress `@latest`; + # hard-failing pages on a transient, self-healing condition. Skip this + # cut instead — a later push re-cuts automatically once the anchor leads. + # A base strictly BEHIND the stable is NOT this transient window; that is + # left to the Guard step below to hard-fail. fetch-depth:0 has all tags. + LATEST_STABLE_TAG=$(git tag --list 'v*' --sort=-v:refname \ + | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 || true) + if [[ -n "$LATEST_STABLE_TAG" && "$BASE" == "${LATEST_STABLE_TAG#v}" ]]; then + echo "::warning::Beta base ${BASE} equals the latest stable ${LATEST_STABLE_TAG#v} — pre.json's anchor has not been advanced by main-reset yet. Deferring this beta cut; it re-cuts automatically once the anchor leads." + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi BUMP=$(echo "$OUTPUT" | jq -r .maxBumpType) COUNT=$(echo "$OUTPUT" | jq -r .pendingCount) NOTES_B64=$(echo "$OUTPUT" | jq -r .releaseNotes | base64 | tr -d '\n') @@ -211,12 +227,13 @@ jobs: } >> "$GITHUB_OUTPUT" echo "Computed: base=$BASE bump=$BUMP pending=$COUNT" - # Anchor-drift guard: the computed beta base MUST strictly lead the - # latest published stable. After a stable promotion, pre.json's anchor - # is stale until main-reset advances it; until then compute-next-beta - # derives a base equal to (or behind) the stable just shipped, which - # would cut a `-beta.N` that is semver-BEHIND `@latest`. Fail loud with - # the recovery action rather than publishing a regressed beta. Uses the + # Anchor-drift backstop: the computed beta base must not be BEHIND the + # latest published stable. The common post-promotion case (base EQUAL to + # the fresh stable, anchor not yet advanced by main-reset) is now handled + # upstream in compute-beta as a deferred skip, so run_beta is only 'true' + # here when base != stable. A base strictly BEHIND stable is genuine anchor + # drift — not the transient window — and would cut a `-beta.N` that is + # semver-BEHIND `@latest`; fail loud with the recovery action. Uses the # latest stable tag (no network) — fetch-depth:0 has all tags locally. - name: Guard - beta base must lead the latest stable if: steps.compute-beta.outputs.run_beta == 'true' @@ -232,9 +249,8 @@ jobs: fi STABLE="${LATEST_STABLE_TAG#v}" TOP=$(printf '%s\n%s\n' "$BASE_VERSION" "$STABLE" | sort -V | tail -n1) - if [[ "$BASE_VERSION" == "$STABLE" || "$TOP" != "$BASE_VERSION" ]]; then - echo "::error::Computed beta base ${BASE_VERSION} does not lead the latest stable ${STABLE}." - echo "::error::pre.json's anchor is stale — a stable was promoted but main-reset has not advanced the base." + if [[ "$TOP" != "$BASE_VERSION" ]]; then + echo "::error::Computed beta base ${BASE_VERSION} is BEHIND the latest stable ${STABLE} — genuine anchor drift, not the transient post-promotion window (base==stable is deferred upstream)." echo "::error::Run public-open-knowledge-main-reset.yml with stable_version=${STABLE} on agents-private, then re-cut." exit 1 fi diff --git a/README.md b/README.md index 20cd2e447..3a4d51e8c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# OpenKnowledge +# Open Knowledge -OpenKnowledge is a markdown-powered document editor with integrations for Claude, Codex, and Cursor. +Open Knowledge is a local-first knowledge base for teams that want docs, help-center content, SOPs, and agent-facing knowledge to live in one structured editing system. + +The project includes a desktop app, web app, server, CLI, shared core packages, and docs site. It uses Bun workspaces and Turbo for builds. ## Install