Skip to content

Commit e1aef17

Browse files
ci(release): the hotcrm downstream smoke resolves hotcrm's latest release tag at run time (#25965)
Fixes #25770 Claim: #25770 comment 6409515497 (Branch `claude/project-thread-beijtf`, the devx seat's in-seat S card). ## What The release lane's **Downstream backward-compat smoke (live hotcrm)** step no longer hard-codes `HOTCRM_REF: v2.1.0`, an ObjectStack 14.7-era hotcrm that sits four majors behind. At run time it resolves hotcrm's **latest published release** (`repos/objectstack-ai/hotcrm/releases/latest` → `tag_name`) and runs the smoke against it. This implements the maintainer's ruling D10 = A. - Still **advisory**: `BLOCKING: '0'` is unchanged. No new gate and no new dispatch lane. - **Fail-soft:** on a network error, a non-200 response, or an empty or malformed `tag_name`, the step emits `::notice::` and skips. It never fails. - The lookup authenticates with the job's `GITHUB_TOKEN`, so it isn't subject to the anonymous per-IP rate limit. The token is `unset` before hotcrm's install runs its third-party lifecycle scripts. - The "TO RE-ARM" comment is rewritten as a ruling, not a pending to-do. The final warning names `@objectstack/downstream-contract` as the blocking floor. - The Node-floor comment cited "hotcrm@v1.2.0 … engines.node >=22", which was stale. It now cites `.nvmrc` plus the cloned release's `engines.node` (v6.0.0: `^22.11 || ^24 || >=26`). `node-version: '22'` is unchanged. ## Verified (the step's `run:` extracted, with the smoke call stubbed) ``` live: Resolved hotcrm's latest published release: v6.0.0 (GH_TOKEN cleared before the smoke) exit 0 missing repo: ::notice::could not resolve … (HTTP 403, no usable tag_name) — skipping the advisory downstream smoke. The publish continues. exit 0 unreachable: ::notice::… https://nonexistent.invalid/… (HTTP 000, no usable tag_name) — skipping … exit 0 200, no tag: ::notice::… (HTTP 200, no usable tag_name) — skipping … exit 0 ``` `grep -n "HOTCRM_REF:\|BLOCKING:" .github/workflows/release.yml` → only `BLOCKING: '0'`. `--self-test` exited 0 on every script that reads release.yml: scheduled-full-run, check-changeset-no-major, check-self-test-wired, check-skill-compatibility-version, check-stall-guard-budget, release-dist-tags, release-github-releases, release-pending-publish, release-verify-npm, sync-docs-image-tags and sync-release-index-currency. Also exit 0: `check-node-version`, `check:workflow-status-functions`, `check:workflow-step-name-quoting` and `check:pm-governed-prose`. ## Left out (out of the card's scope) - `.github/workflows/cut-rc.yml:757` still pins `HOTCRM_REF: v2.1.0`. The card keeps cut-rc out of scope. - `scripts/downstream-smoke.sh` still defaults to `v1.2.0` when `HOTCRM_REF` is unset. release.yml always sets it now, and `dispatch-gates.self-test.mjs` reads the script byte for byte. `skip-changeset`: a root-workflow change that publishes nothing. Clause-②: no. Metadata-protocol: none. **Tier H** (`.github/workflows/release.yml`): it lands after a GOVERNED_APPROVERS approval. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01LKHDniRQSWjRJyDtacwpEd Co-authored-by: Claude <noreply@anthropic.com>
1 parent 67ea334 commit e1aef17

1 file changed

Lines changed: 56 additions & 42 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,9 +1661,11 @@ jobs:
16611661
- name: Setup Node.js
16621662
uses: actions/setup-node@v7
16631663
with:
1664-
# Cannot go below 22: the downstream hotcrm smoke below clones
1665-
# hotcrm@v1.2.0, whose manifest pins engines.node >=22. pnpm install
1666-
# aborts with ERR_PNPM_UNSUPPORTED_ENGINE under that.
1664+
# .nvmrc's pin (check-node-version holds every workflow to it). It
1665+
# must also satisfy the downstream hotcrm smoke below, which clones
1666+
# hotcrm's latest release and installs it: pnpm install aborts with
1667+
# ERR_PNPM_UNSUPPORTED_ENGINE outside that release's engines.node
1668+
# (v6.0.0, the latest on 2026-10-26: `^22.11 || ^24 || >=26`).
16671669
node-version: '22'
16681670

16691671
# ──────────────────────────────────────────────────────────────────────
@@ -1856,50 +1858,62 @@ jobs:
18561858
run: pnpm run build
18571859

18581860
- name: Downstream backward-compat smoke (live hotcrm)
1859-
# Pre-publish gate (#2035): the about-to-publish @objectstack/spec must
1860-
# not break a real third-party consumer pinned to a published release.
1861-
# The deterministic in-repo floor is @objectstack/downstream-contract;
1862-
# this is the live ceiling.
1861+
# Pre-publish check (#2035): the about-to-publish @objectstack/spec
1862+
# should not break a real third-party consumer pinned to a published
1863+
# release. The deterministic in-repo floor is
1864+
# @objectstack/downstream-contract, which blocks; this is the live
1865+
# ceiling, and it is ADVISORY: it runs and reports on every publish, and
1866+
# a failure does NOT block. `BLOCKING` below is the whole switch.
18631867
#
1864-
# ⚠️ CURRENTLY ADVISORY — it runs and reports on every publish, but a
1865-
# failure does NOT block. `BLOCKING` below is the whole switch.
1868+
# How it got here. #3600 made it advisory for the rc pre-mode window and
1869+
# promised it would re-arm at `changeset pre exit`. It did (#8643,
1870+
# 2026-08-14), against a hand-pinned HOTCRM_REF that was still a 14.7-era
1871+
# hotcrm, so the re-armed gate stood between the 17.0.0 GA publish and a
1872+
# migration nobody had done yet: the deadlock #3600 named, one event
1873+
# later. It went back to advisory, and the hand pin then sat four majors
1874+
# behind hotcrm, so every publish emitted a warning that was certain to
1875+
# appear and meant nothing.
18661876
#
1867-
# Why, and what changed (supersedes the #3600 amendment). #3600 made
1868-
# this advisory for the duration of the rc pre-mode window, keyed on
1869-
# `.changeset/pre.json` saying mode:"pre", with the reasoning: a major
1870-
# train exists precisely to ship deliberate surface removals, and a
1871-
# hotcrm release migrated off them cannot exist until the rc.N artifacts
1872-
# it would migrate against are published — blocking here deadlocks the
1873-
# train. It promised the gate would "re-arm by itself the moment
1874-
# `changeset pre exit` lands".
1875-
#
1876-
# It did exactly that (#8643, 2026-08-14) — and the deadlock was still
1877-
# on, because HOTCRM_REF was and is `v2.1.0`, i.e. ObjectStack 14.7. So
1878-
# the re-armed gate stood between the 17.0.0 GA publish and a migration
1879-
# nobody had done yet, which is the same deadlock #3600 named, one event
1880-
# later. The keying was the bug: pre-exit is not when a migrated hotcrm
1881-
# release starts existing. Shipping one is.
1882-
#
1883-
# So the posture is now tied to THAT event instead. Note this is a
1884-
# WEAKER gate than #2035 intended and it is meant to be temporary — the
1885-
# deterministic in-repo floor (@objectstack/downstream-contract, which
1886-
# still blocks) is what carries backward-compat enforcement until it is
1887-
# restored.
1888-
#
1889-
# TO RE-ARM: ship a hotcrm release migrated to v17, bump HOTCRM_REF to
1890-
# it, set BLOCKING to '1'. Nothing else changes. Because the smoke keeps
1891-
# running and reporting throughout, the run log shows the day it goes
1892-
# green — you flip the switch on evidence, not on hope.
1877+
# The posture now is a ruling, not a pending to-do (objectstack#25770,
1878+
# D10 = A, 2026-10-25): the step stays advisory, and its ref is no
1879+
# longer pinned by hand. It resolves at run time to hotcrm's LATEST
1880+
# PUBLISHED RELEASE (`releases/latest` -> `tag_name`), so the check
1881+
# always runs against the consumer as it ships today. ⛔ Never hard-code
1882+
# a tag here again. The read is fail-soft: an unresolvable tag (network
1883+
# error, non-200, empty or malformed `tag_name`) is a `::notice::` and a
1884+
# skip, never a failure. Making this blocking is a new-gate decision for
1885+
# the maintainer, not a switch left for someone to flip.
18931886
env:
1894-
# v2.1.0: hotcrm upgraded to ObjectStack 14.7 (hotcrm#448) and
1895-
# dropped the agent `visibility` field that spec 15 removes as
1896-
# unenforced surface (ADR-0056 D8, #3216).
1897-
# Bump this ref whenever a deliberate spec surface removal ships a
1898-
# matching hotcrm release.
1899-
HOTCRM_REF: v2.1.0
1887+
# Read-only use: the releases API for a public repo. Authenticated so
1888+
# the call is not subject to the anonymous per-IP rate limit shared
1889+
# across hosted runners.
1890+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19001891
# '1' = a failure fails the publish. '0' = reported only.
19011892
BLOCKING: '0'
19021893
run: |
1894+
api='https://api.github.com/repos/objectstack-ai/hotcrm/releases/latest'
1895+
auth=()
1896+
if [ -n "${GH_TOKEN:-}" ]; then
1897+
auth=(-H "Authorization: Bearer ${GH_TOKEN}")
1898+
fi
1899+
body="$(mktemp)"
1900+
code="$(curl -sS --max-time 30 --retry 2 -o "$body" -w '%{http_code}' \
1901+
-H 'Accept: application/vnd.github+json' "${auth[@]}" "$api")" || true
1902+
tag=''
1903+
if [ "$code" = '200' ]; then
1904+
tag="$(jq -r '.tag_name // empty' "$body" 2>/dev/null || true)"
1905+
fi
1906+
rm -f "$body"
1907+
# The token's only use is the read above. hotcrm's install below runs
1908+
# third-party lifecycle scripts, which must not inherit it.
1909+
unset GH_TOKEN auth
1910+
if ! printf '%s' "$tag" | grep -Eqx '[A-Za-z0-9][A-Za-z0-9._/-]*'; then
1911+
echo "::notice::could not resolve hotcrm's latest published release from ${api} (HTTP ${code:-none}, no usable tag_name) — skipping the advisory downstream smoke. The publish continues."
1912+
exit 0
1913+
fi
1914+
export HOTCRM_REF="$tag"
1915+
echo "Resolved hotcrm's latest published release: ${HOTCRM_REF}"
1916+
19031917
if bash scripts/downstream-smoke.sh; then
19041918
echo "::notice::hotcrm@${HOTCRM_REF} is compatible with the about-to-publish @objectstack/spec."
19051919
exit 0
@@ -1910,7 +1924,7 @@ jobs:
19101924
exit 1
19111925
fi
19121926
1913-
echo "::warning::hotcrm@${HOTCRM_REF} is incompatible with the about-to-publish @objectstack/spec. ADVISORY ONLY — the publish continues. HOTCRM_REF is pre-v17; ship a migrated hotcrm release, bump it, and set BLOCKING=1 in .github/workflows/release.yml to re-arm this gate."
1927+
echo "::warning::hotcrm@${HOTCRM_REF} (hotcrm's latest release) is incompatible with the about-to-publish @objectstack/spec. ADVISORY ONLY — the publish continues; the in-repo @objectstack/downstream-contract floor is the blocking check."
19141928
19151929
# ──────────────────────────────────────────────────────────────────────
19161930
# ADR-0087 D4 — the per-release section, and the gate that proves it.

0 commit comments

Comments
 (0)