Skip to content

Commit fa35a45

Browse files
feat(bootstrap)!: source hyperd from the PyPI tableauhyperapi wheels (#254)
## Motivation `hyperdb-bootstrap` fetched `hyperd` from Tableau's Hyper **Java API zip**, whose filename embeds an opaque `build_id` (e.g. `r07abb490`) that **cannot be derived from the version**. Discovering it meant scraping the public releases page — and that scraper (`src/scrape.rs`, behind `--latest`) has been **broken for three-plus releases without anyone noticing**, because its tests ran against a synthetic fixture rather than the live page. Two independent defects: - the heading regex expects `<h3>VERSION [DATE]</h3>`, but Docusaurus renders `0.0.26479 <!-- -->[September 3 2026]`, which `\s*` cannot span; - the build-id capture hardcodes `(rc[a-z0-9]+)`, while every build id since `0.0.24457` has been `r` + hex. The PyPI `tableauhyperapi` wheels carry the same engine behind a **fully constructible** URL, and **PyPI publishes a sha256 per file**: ```text https://files.pythonhosted.org/packages/py3/t/tableauhyperapi/tableauhyperapi-{version}-py3-none-{wheel_tag}.whl ``` So `--latest` is **deleted, not fixed**: with a constructible URL and published digests there is nothing left for it to do. ## The bytes are unchanged The strongest evidence this migration is faithful — the `hyperd` extracted from the `macosx_13_0_arm64` wheel is **bit-identical to the `hyperd` in the Java zip for the same release**, sha256 `aef5c81970bb4d84d06fb9513d5ffd722526fce779632a0c5f63d87b6450e478`. To be precise about what is and isn't established here: that cross-envelope equality was established upstream of this PR and I did not re-derive it. What I verified locally is that the wheel path produces exactly that binary: ```text $ shasum -a 256 .hyperd/current/hyperd aef5c81970bb4d84d06fb9513d5ffd722526fce779632a0c5f63d87b6450e478 $ stat -f%z .hyperd/current/hyperd 277836448 $ file .hyperd/current/hyperd .hyperd/current/hyperd: Mach-O 64-bit executable arm64 $ .hyperd/current/hyperd --version Hyper version main.0.0.26479.r96880f6a ``` Same build, different envelope. Note the `--version` line corroborates this independently: the wheel's binary self-reports build `r96880f6a`, which is exactly the `build_id` the Java zip carries for `0.0.26479` (see `chore/post-rc-cleanup`'s `8c99d20`). It is the same engine build reached by a different filename. This is *not* a claim that the wheel matches the engine currently on `main` (`0.0.26359`, build `r07abb490`) — that is a different build. The equality is same-release, cross-envelope. Both binaries report `minos 13.0`, so the `macosx_13_0` wheel tag is **not** a raised support floor — no contributor loses support. Wheels are ~3.6–4.5% smaller than the Java zips. Bumping the pin no longer means downloading four ~80 MB archives and hashing them by hand — the digests come off the JSON API. They are **still committed**: a hash in git is an attestation independent of the host serving the bytes. ## Breaking changes Public API removed: | Removed | Replacement | |---|---| | `PinnedRelease::build_id`, `InstalledHyperd::build_id` | `.version` is the only release identifier | | `PinnedRelease::version_tag()` | `.version` | | `VersionSource::ScrapeLatest`, the `scrape` module | none — deleted | | `Error::Http`, `Error::HttpStatus`, `Error::ScrapeFailed` | none — served the scraper only | | CLI `--latest`, `--build-id` | `--version X` alone is now a complete source | | `regex`, `reqwest`, `rustls` deps | none — no in-process HTTP client remains | `url::build_download_url` is now **fallible** (`Result<String, Error>`); a platform with no pinned wheel tag is `Error::MissingWheelTag` rather than a guess. `PinnedRelease::wheel_tag_for(Platform)` is new. The install layout is keyed on the version alone: `<dest>/0.0.26479/` (was `<dest>/0.0.26479.r96880f6a/`), and `current/VERSION` now contains just `0.0.26479`. Nothing in the repo reads that file programmatically. Dropping `reqwest`/`rustls` also **retires the rustls crypto-provider workaround** the CHANGELOG records as a past breaking change (`rustls-no-provider` plus a `OnceLock` installing ring). Verified `aws-lc-rs` is absent workspace-wide and that `hyperdb-bootstrap` no longer reaches `reqwest`, `rustls`, or `regex` at all. ## Versioning: breaking, released as `1.0.0-rc.2` **Decided — no reviewer action needed.** The break is now marked honestly *and* the version is pinned, which are two independent things: - The subject is `feat(bootstrap)!:` and the migration commit carries a `BREAKING CHANGE:` footer enumerating every removed item. The break is real and is recorded as such. - An empty follow-up commit, `chore: release 1.0.0-rc.2`, carries a `Release-As: 1.0.0-rc.2` footer, which pins the next release inside the `1.0.0-rc` line. Without that footer the `!` would compute **2.0.0**: the workspace is already on `1.x`, and `bump-minor-pre-major` in `release-please-config.json` is gated on `version.isPreMajor` (`major < 1`), so it does not apply at `1.0.0-rc.1`. `Release-As:` wins regardless — release-please's `DefaultVersioningStrategy` returns a `CustomVersionUpdate` from the `RELEASE AS` note *before* it reads the breaking-change tally. This is the same mechanism, and the same empty-commit shape, that produced `1.0.0-rc.1` (`7bf2dff`), and it is what [`docs/GITHUB_OPERATIONS.md` → Pre-releases](https://github.com/tableau/hyper-api-rust/blob/main/docs/GITHUB_OPERATIONS.md#pre-releases) documents. Simulated against `release-please@17.11.2` (the version `release-please-action@v5` pins) using its real `parseConventionalCommits` and `DefaultVersioningStrategy`: `1.0.0-rc.1` → **`1.0.0-rc.2`** under a merge commit *and* under a squash merge. Dropping the footer from the same input yields `2.0.0-rc.1`, which is the outcome this pin exists to prevent. > **Do not merge a release PR that says anything other than `1.0.0-rc.2`.** > #253 merges first, and release-please will run on that push and open a > `chore(main): release …` PR computed from #253's commits alone — before this > PR's `Release-As:` footer is on `main`. That PR will show the wrong version. > It updates itself once this PR lands; leave it alone until then. ## Why wheel tags live in the pin file They are deliberately *not* hardcoded in Rust. They are not guaranteed stable across releases (arm64 wheels only exist from `0.0.19484`; a future macOS floor bump would change `macosx_13_0_arm64`), and a wrong tag is a **silent 404** on one platform only. Keeping them as pin data makes any such change a visible pin edit, and `build.rs` now fails the build if any supported platform lacks one. (Empirically the four tags are unchanged from `0.0.19484` through `0.0.26479`.) ## Stronger `verify` `hyperdb-bootstrap verify` now cross-checks every pinned digest against the digest PyPI publishes for that exact wheel filename, on top of HEAD-ing the four URLs — so it validates the **exact pinned bytes** rather than merely that the CDN serves something at that path, and it catches a stale `[wheel_tag]` explicitly: ```text $ cargo run --release -p hyperdb-bootstrap --bin hyperdb-bootstrap -- verify verifying hyperd 0.0.26479... OK macos-arm64 [200] .../tableauhyperapi-0.0.26479-py3-none-macosx_13_0_arm64.whl digest matches PyPI OK macos-x86_64 [200] .../tableauhyperapi-0.0.26479-py3-none-macosx_10_11_x86_64.whl digest matches PyPI OK linux-x86_64 [200] .../tableauhyperapi-0.0.26479-py3-none-manylinux2014_x86_64.whl digest matches PyPI OK windows-x86_64 [200] .../tableauhyperapi-0.0.26479-py3-none-win_amd64.whl digest matches PyPI all platforms reachable with matching digests. ``` ## npm dual pin `npm-build-publish.yml` carries its own independent pin (this is why `0.7.1` once shipped npm with a different engine than crates.io). It is migrated to the wheel URL, `HYPERD_BUILD_ID` is gone, and the matrix gains `hyperd-wheel-tag`. `verify-npm-hyperd-pin.py` keeps its version + digest cross-check and **gains a wheel-tag cross-check**, since the tag is a new drift vector. Empirically confirmed (not assumed) that the matrix `hyperd-sha256` values are digests of the **downloaded archive**, not the extracted binary — the step hashes `hyperd-archive.whl` — so they are the wheel digests and equal the toml's `[sha256]`. I did **not** make the workflow read the toml directly. The matrix must be static YAML, so it would need a `tomllib` call inside the per-platform matrix job, which runs on a Windows runner under git-bash where `python3` may not be on `PATH` — an untestable portability risk for no correctness gain over the guard. **Recommended as a follow-up** alongside converting the matrix to a `setup`-job JSON output. ## Verification Run on macOS arm64 (Apple Silicon): - `cargo build -p hyperdb-bootstrap` and `cargo build --workspace` — clean - `cargo test -p hyperdb-bootstrap` — 26 lib + 4 integration + 1 doc, 0 failed (up from 12 lib + 2 integration; +16 runnable tests) - `cargo test --workspace` — **1584 passed, 0 failed**, against the freshly downloaded engine - `make test` — **1519 passed, 0 failed** - `cargo fmt --all -- --check` and `cargo clippy --workspace --all-targets --all-features -- -D warnings` — clean - `npx markdownlint-cli2` — zero new findings; the 5 in `AGENTS.md` / `DEVELOPMENT.md` are the pre-existing MD040 backlog, identical before and after - `verify-npm-hyperd-pin.py` passes against the new toml, and **fails correctly** when a wheel tag is perturbed - The workflow's `find`-based extraction was replayed against the real wheel entry names: `HYPER_DIR=hyperd-raw/tableauhyperapi/bin/hyper`, `hyperd` found, `LICENSE*`/`NOTICE*` glob matches `dist-info/` `extract.rs` is **unchanged** apart from doc comments — its "skip one optional top-level directory, then require a `lib/hyper` or `bin/hyper` pair" logic already absorbs the `tableauhyperapi` wrapper. New tests pin that against the real wheel entry names, including the Windows `hyperd.exe` + `crashdumper.exe` case. ### Not verified here - **Only macOS arm64 was executed.** The other three platforms rest on CI. Their URLs and digests *are* machine-verified (all four HEAD 200 with matching PyPI digests), and I downloaded the Windows and Linux wheels to confirm their `bin/hyper/` contents (`hyperd.exe` + `crashdumper.exe`; `hyperd`) and digests — but no `hyperd` was run on Linux or Windows. - The engine links only system frameworks (`otool -L`) and `bin/hyper/` contains no shared libraries on any of the three wheels I inspected, so the npm shared-library copy loop finds nothing to copy — as before. --- Repeated here as a trailing footer so the version is pinned on the merge commit too: this repo merges with `merge_commit_message = PR_BODY`, so the body below becomes the merge commit's body. Same value as the footer on `chore: release 1.0.0-rc.2`, so it is redundant rather than conflicting. Release-As: 1.0.0-rc.2
2 parents 9dabbef + a9fe1b0 commit fa35a45

24 files changed

Lines changed: 1450 additions & 695 deletions

File tree

.agents/skills/update-hyperd-release/SKILL.md

Lines changed: 111 additions & 65 deletions
Large diffs are not rendered by default.

.claude/skills/update-hyperd-release/SKILL.md

Lines changed: 111 additions & 65 deletions
Large diffs are not rendered by default.

.github/scripts/verify-npm-hyperd-pin.py

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
"""Guard: keep the npm release workflow's hyperd pin in sync with the toml.
33
44
`.github/workflows/npm-build-publish.yml` bundles `hyperd` into the npm
5-
packages using its OWN hardcoded `HYPERD_VERSION` / `HYPERD_BUILD_ID` /
6-
per-platform matrix `hyperd-sha256`s. Those are decoupled from
5+
packages from the PyPI `tableauhyperapi` wheel, using its OWN hardcoded
6+
`HYPERD_VERSION` plus per-platform matrix `hyperd-wheel-tag`s and
7+
`hyperd-sha256`s. Those are decoupled from
78
`hyperdb-bootstrap/hyperd-version.toml`, which is what `make download-hyperd`
89
and the crates.io path use.
910
@@ -12,10 +13,16 @@
1213
This script fails CI whenever the two drift, so that can't recur silently.
1314
1415
The platform slug (`macos-arm64`, `linux-x86_64`, `windows-x86_64`) is the join
15-
key: it is identical between the toml's `[sha256]` table and the workflow's
16-
`hyperd-slug` matrix field. Only slugs the workflow actually builds are checked,
17-
so a commented-out matrix entry (invisible to the YAML parser) and any unused
18-
extra toml sha are both fine.
16+
key: it is identical between the toml's `[wheel_tag]` / `[sha256]` tables and
17+
the workflow's `hyperd-slug` matrix field. Only slugs the workflow actually
18+
builds are checked, so a commented-out matrix entry (invisible to the YAML
19+
parser) and any unused extra toml entry are both fine.
20+
21+
The wheel tag (`macosx_13_0_arm64`, `manylinux2014_x86_64`, ...) is checked
22+
alongside the digest because it is a drift vector of its own: it is not
23+
derivable from the version, and a wrong tag resolves to a URL that does not
24+
exist, so it would surface as an opaque 404 mid-release rather than as a
25+
mismatch. The sha256s are digests of the downloaded `.whl` archive.
1926
"""
2027

2128
from __future__ import annotations
@@ -36,12 +43,12 @@ def main() -> int:
3643
workflow = yaml.safe_load(WORKFLOW.read_text())
3744

3845
env = workflow.get("env", {})
46+
toml_wheel_tag = toml_data.get("wheel_tag", {})
3947
toml_sha = toml_data.get("sha256", {})
4048

4149
# (label, expected-from-toml, actual-from-workflow)
4250
checks: list[tuple[str, str, str | None]] = [
4351
("HYPERD_VERSION", str(toml_data["version"]), env.get("HYPERD_VERSION")),
44-
("HYPERD_BUILD_ID", str(toml_data["build_id"]), env.get("HYPERD_BUILD_ID")),
4552
]
4653

4754
errors: list[str] = []
@@ -51,13 +58,22 @@ def main() -> int:
5158
slug = entry.get("hyperd-slug")
5259
if slug is None:
5360
continue
54-
expected = toml_sha.get(slug)
55-
if expected is None:
61+
expected_tag = toml_wheel_tag.get(slug)
62+
if expected_tag is None:
63+
errors.append(
64+
f'matrix slug "{slug}" has no [wheel_tag]."{slug}" entry in {TOML.name}'
65+
)
66+
else:
67+
checks.append(
68+
(f"wheel_tag[{slug}]", expected_tag, entry.get("hyperd-wheel-tag"))
69+
)
70+
expected_sha = toml_sha.get(slug)
71+
if expected_sha is None:
5672
errors.append(
5773
f'matrix slug "{slug}" has no [sha256]."{slug}" entry in {TOML.name}'
5874
)
5975
continue
60-
checks.append((f"sha256[{slug}]", expected, entry.get("hyperd-sha256")))
76+
checks.append((f"sha256[{slug}]", expected_sha, entry.get("hyperd-sha256")))
6177

6278
for label, expected, actual in checks:
6379
if actual == expected:
@@ -72,8 +88,9 @@ def main() -> int:
7288
sys.stdout.flush()
7389
print(
7490
f"\n{WORKFLOW.name} is out of sync with {TOML.name}. "
75-
"Update the workflow's env vars and matrix sha256s to match the toml "
76-
"(or vice versa) so npm bundles the same hyperd as crates.io.",
91+
"Update the workflow's env vars and matrix wheel tags / sha256s to "
92+
"match the toml (or vice versa) so npm bundles the same hyperd as "
93+
"crates.io.",
7794
file=sys.stderr,
7895
)
7996
return 1

.github/workflows/npm-build-publish.yml

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ permissions:
2323

2424
env:
2525
CARGO_TERM_COLOR: always
26+
# hyperd is bundled from the PyPI `tableauhyperapi` wheel. This version and
27+
# the per-platform wheel tags / sha256s in the build-npm matrix below must
28+
# match hyperdb-bootstrap/hyperd-version.toml — enforced by
29+
# .github/scripts/verify-npm-hyperd-pin.py.
2630
HYPERD_VERSION: "0.0.26479"
27-
HYPERD_BUILD_ID: "r96880f6a"
2831

2932
jobs:
3033
verify-ci:
@@ -92,27 +95,35 @@ jobs:
9295
fail-fast: false
9396
matrix:
9497
include:
98+
# hyperd-wheel-tag is the PyPI platform tag for this slug. It is NOT
99+
# derivable from HYPERD_VERSION, so it has to be carried explicitly;
100+
# a wrong tag yields a 404 rather than a version mismatch.
101+
# hyperd-sha256 is the digest of the downloaded .whl archive.
95102
- platform: darwin-arm64
96103
os: macos-14
97104
target: aarch64-apple-darwin
98105
hyperd-slug: macos-arm64
99-
hyperd-sha256: "65bd021b3d3470ac74728ec287866a3ee0dfd806daf2589670feb3580955ee95"
106+
hyperd-wheel-tag: macosx_13_0_arm64
107+
hyperd-sha256: "e80e4dac6d8437ad8c20f36add7e523b18bc06d90d4c605a256c57df8df2c118"
100108
# TODO: re-enable when macos-13 runners are more available
101109
# - platform: darwin-x64
102110
# os: macos-13
103111
# target: x86_64-apple-darwin
104112
# hyperd-slug: macos-x86_64
105-
# hyperd-sha256: "6690669c8a6a6c7c6794c101beb31b83e1589d76cb14b0c817523069591f694c"
113+
# hyperd-wheel-tag: macosx_10_11_x86_64
114+
# hyperd-sha256: "960e276028137847a3870695d9c2d5a1392c173b1e119ff1146d24a75deca71a"
106115
- platform: linux-x64-gnu
107116
os: ubuntu-latest
108117
target: x86_64-unknown-linux-gnu
109118
hyperd-slug: linux-x86_64
110-
hyperd-sha256: "c20be5b6874d319c7db01dcec763d7e65ae2483c0becc75f2914a58accc4f932"
119+
hyperd-wheel-tag: manylinux2014_x86_64
120+
hyperd-sha256: "9f5ff04c0dc3c17224b7a3f36f297775f2f49aae084da84614003cd6508213bc"
111121
- platform: win32-x64-msvc
112122
os: windows-latest
113123
target: x86_64-pc-windows-msvc
114124
hyperd-slug: windows-x86_64
115-
hyperd-sha256: "3a400508e79c67ce9dcd8bd317ab164a61b5aed8ca880031ed4bbe6621514e1d"
125+
hyperd-wheel-tag: win_amd64
126+
hyperd-sha256: "7a4f96d2a22351e944fea6db5d03ab5272ad4c0577acc987bfcb3739ed639502"
116127
runs-on: ${{ matrix.os }}
117128
defaults:
118129
run:
@@ -154,16 +165,20 @@ jobs:
154165
- name: Download and verify hyperd
155166
env:
156167
SLUG: ${{ matrix.hyperd-slug }}
168+
WHEEL_TAG: ${{ matrix.hyperd-wheel-tag }}
157169
EXPECTED_SHA256: ${{ matrix.hyperd-sha256 }}
158170
run: |
159171
set -euo pipefail
160-
URL="https://downloads.tableau.com/tssoftware/tableauhyperapi-java-${SLUG}-release-main.${HYPERD_VERSION}.${HYPERD_BUILD_ID}.zip"
161-
echo "Downloading: $URL"
162-
curl --fail --silent --show-error --location --output hyperd-archive.zip "$URL"
172+
# The engine ships inside the PyPI `tableauhyperapi` wheel, which is
173+
# a zip. This URL 302-redirects to the content-addressed download.
174+
URL="https://files.pythonhosted.org/packages/py3/t/tableauhyperapi/tableauhyperapi-${HYPERD_VERSION}-py3-none-${WHEEL_TAG}.whl"
175+
echo "Downloading hyperd for ${SLUG}: $URL"
176+
curl --fail --silent --show-error --location --output hyperd-archive.whl "$URL"
177+
# Digest is over the downloaded archive, not the extracted binary.
163178
if command -v sha256sum &>/dev/null; then
164-
ACTUAL_SHA256=$(sha256sum hyperd-archive.zip | awk '{print $1}')
179+
ACTUAL_SHA256=$(sha256sum hyperd-archive.whl | awk '{print $1}')
165180
else
166-
ACTUAL_SHA256=$(shasum -a 256 hyperd-archive.zip | awk '{print $1}')
181+
ACTUAL_SHA256=$(shasum -a 256 hyperd-archive.whl | awk '{print $1}')
167182
fi
168183
if [[ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]]; then
169184
echo "::error::SHA256 mismatch: expected $EXPECTED_SHA256, got $ACTUAL_SHA256"
@@ -175,8 +190,11 @@ jobs:
175190
run: |
176191
set -euo pipefail
177192
mkdir -p hyperd-extracted
178-
unzip -q hyperd-archive.zip -d hyperd-raw
179-
# Find the lib/hyper or bin/hyper directory (matches extract.rs logic)
193+
unzip -q hyperd-archive.whl -d hyperd-raw
194+
# Find the lib/hyper or bin/hyper directory (matches extract.rs
195+
# logic). The wheel lays the engine out at tableauhyperapi/bin/hyper/
196+
# on every platform, so in practice the bin/hyper branch matches;
197+
# the lib/hyper branch is kept for parity with extract.rs.
180198
HYPER_DIR=$(find hyperd-raw -type d -name "hyper" -path "*/lib/hyper" -o -type d -name "hyper" -path "*/bin/hyper" | head -1)
181199
if [[ -z "$HYPER_DIR" ]]; then
182200
echo "::error::Could not find lib/hyper or bin/hyper in archive"
@@ -195,6 +213,10 @@ jobs:
195213
- name: Extract LICENSE from hyperd archive
196214
run: |
197215
set -euo pipefail
216+
# The wheel's tableauhyperapi-<version>.dist-info/ carries LICENSE,
217+
# NOTICES.txt and HYPER_API_OSS_disclosure.txt, so this glob matches.
218+
# The heredoc below is the fallback if that ever changes, so a miss
219+
# is non-fatal.
198220
LICENSE_FILE=$(find hyperd-raw -iname "LICENSE*" -o -iname "NOTICE*" | head -1)
199221
if [[ -n "$LICENSE_FILE" ]]; then
200222
cp "$LICENSE_FILE" LICENSE-HYPERD

.github/workflows/verify-hyperd-pin.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
name: verify-hyperd-pin
22

3-
# HEAD every platform URL for the pinned Hyper release. Catches
4-
# Tableau yanking / renaming an archive, and catches typos in
5-
# hyperd-version.toml on PRs that touch the pin.
3+
# HEAD every platform URL for the pinned Hyper release. The archives are the
4+
# PyPI `tableauhyperapi` wheels, so this catches a wheel being yanked and
5+
# catches typos in hyperd-version.toml (version or wheel tag — a wrong tag is
6+
# just a URL that 404s) on PRs that touch the pin.
67

78
on:
89
push:
@@ -46,7 +47,8 @@ jobs:
4647

4748
- name: Verify npm-build-publish.yml hyperd pin matches the toml
4849
# The release workflow bundles hyperd into the npm packages from its
49-
# OWN hardcoded version/build_id/sha256s, decoupled from the toml.
50+
# OWN hardcoded version + per-platform wheel tags/sha256s, decoupled
51+
# from the toml.
5052
# 0.7.1 shipped npm with the stale 0.0.25080 engine because only the
5153
# toml was bumped. This guard fails the build if they ever drift again.
5254
run: python3 .github/scripts/verify-npm-hyperd-pin.py

AGENTS.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ running `make download-hyperd` (or `.\build.ps1 download-hyperd`). The
99
implementation lives in the [`hyperdb-bootstrap`](hyperdb-bootstrap/) crate;
1010
the pinned release is baked into
1111
[`hyperdb-bootstrap/hyperd-version.toml`](hyperdb-bootstrap/hyperd-version.toml).
12-
Bumping `hyperd` = edit that file (version + build_id + per-platform sha256s),
13-
then let the `fix(bootstrap):` commit drive the version via release-please (the
14-
crate uses `version.workspace = true` — don't hand-edit a crate version). The
15-
full repeatable procedure — verify the pin, run the suite, A/B benchmark
12+
Bumping `hyperd` = edit that file (`version` + the four `[wheel_tag]` entries +
13+
the four per-platform sha256s — there is no `build_id`), then let the
14+
`fix(bootstrap):` commit drive the version via release-please (the crate uses
15+
`version.workspace = true` — don't hand-edit a crate version). `hyperd` comes
16+
out of the PyPI `tableauhyperapi` wheels, so **you don't compute the digests**:
17+
read them straight off the JSON API with
18+
`curl -s https://pypi.org/pypi/tableauhyperapi/<version>/json | jq -r '.urls[] | "\(.filename) \(.digests.sha256)"'`.
19+
The full repeatable procedure — verify the pin, run the suite, A/B benchmark
1620
against the previous pin, and log the result — is captured in the
1721
[`update-hyperd-release`](.claude/skills/update-hyperd-release/SKILL.md) skill.
1822

Cargo.lock

Lines changed: 1 addition & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

DEVELOPMENT.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,9 @@ in companion crates:
384384
This installs `hyperd` at `.hyperd/current/hyperd` (auto-discovered by
385385
`make`/`build.ps1` — no `HYPERD_PATH` needed). The pinned release is
386386
baked into [`hyperdb-bootstrap/hyperd-version.toml`](hyperdb-bootstrap/hyperd-version.toml);
387-
to upgrade, edit that file (version + build_id + per-platform sha256s)
388-
and bump the crate version. Pass `ARGS="--latest"` to fetch the newest
389-
release via best-effort scraping, or `ARGS="--version X --build-id Y"`
390-
for an ad-hoc pin.
387+
to upgrade, edit that file (version + the four `[wheel_tag]` entries +
388+
per-platform sha256s) and bump the crate version. Pass
389+
`ARGS="--version X"` for an ad-hoc pin.
391390

392391
If you already have a `hyperd` elsewhere, set `HYPERD_PATH` instead:
393392

@@ -420,11 +419,9 @@ in companion crates:
420419
after the `build.ps1 download-hyperd` command):
421420

422421
```bash
423-
# Best-effort scrape of the latest release (skips sha256 verification).
424-
make download-hyperd ARGS="--latest"
425-
426-
# Pin to a specific release ad-hoc.
427-
make download-hyperd ARGS="--version 0.0.24457 --build-id rc36858b6"
422+
# Pin to a specific release ad-hoc. Inherits the builtin pin's wheel tags
423+
# and carries no digests, so the download is unverified (logs a WARN).
424+
make download-hyperd ARGS="--version 0.0.26359"
428425

429426
# Install to a custom location, e.g. shared across repos.
430427
make download-hyperd ARGS="--dest /opt/hyperd"
@@ -435,9 +432,10 @@ in companion crates:
435432

436433
Bumping the baked-in pin is an edit to
437434
[`hyperdb-bootstrap/hyperd-version.toml`](hyperdb-bootstrap/hyperd-version.toml)
438-
(version + build_id + per-platform sha256s) plus a crate version bump.
439-
`build.rs` validates the file on every compile, and the
440-
`verify-hyperd-pin` CI workflow confirms the URLs resolve.
435+
(version + the four `[wheel_tag]` entries + per-platform sha256s, all read
436+
off the PyPI JSON API) plus a crate version bump. `build.rs` validates the
437+
file on every compile, and the `verify-hyperd-pin` CI workflow confirms the
438+
URLs resolve and that each pinned digest matches the one PyPI publishes.
441439

442440
4. **Windows only**: Install Visual Studio Build Tools with "Desktop development with C++"
443441
workload (provides the MSVC linker, not for C++ compilation).

Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,13 +141,14 @@ test-api-release:
141141
examples:
142142
./run_all_examples.sh
143143

144-
# Download hyperd from Tableau's Hyper C++ API release into .hyperd/current/
145-
# Forward extra flags via ARGS, e.g. `make download-hyperd ARGS="--latest"`.
144+
# Download hyperd from the PyPI tableauhyperapi wheel into .hyperd/current/
145+
# Forward extra flags via ARGS, e.g. `make download-hyperd ARGS="--force"`.
146146
download-hyperd:
147147
cargo run --release -p hyperdb-bootstrap --bin hyperdb-bootstrap -- download $(ARGS)
148148

149-
# Network-only check: HEAD each supported platform URL for the pinned
150-
# release. Intended for CI (nightly + on PRs touching hyperd-version.toml).
149+
# Network-only check: probe each supported platform's wheel URL for the pinned
150+
# release and cross-check its digest against PyPI. Intended for CI (nightly +
151+
# on PRs touching hyperd-version.toml).
151152
verify-hyperd-pin:
152153
cargo run --release -p hyperdb-bootstrap --bin hyperdb-bootstrap -- verify $(ARGS)
153154

0 commit comments

Comments
 (0)