rosdistro Binary Release (bloom) — Runbook
Goal: sudo apt install ros-humble-lidarslam (and the Jazzy equivalent)
installs the four core packages from the ROS buildfarm.
This page records the dependency analysis and the exact release procedure.
The repository-side prep (versions, SPDX license tags, per-package
CHANGELOG.rst) landed with v0.5.0 and is maintained through v0.9.1; what
remains is the bloom/rosdistro procedure itself, which requires the
maintainer's GitHub account.
Planned package set
| Package | Version | Notes |
|---|---|---|
lidarslam_msgs |
0.9.1 | messages only |
scanmatcher |
0.9.1 | NDT frontend (FastGICP / SmallGICP optional, off on the farm) |
graph_based_slam |
0.9.1 | backend + /map_save Autoware bundle |
lidarslam |
0.9.1 | launch + param presets |
These are the only package.xml files in the repository outside
Thirdparty/, so bloom's package discovery picks up exactly this set.
Thirdparty/ consists of git submodules, which git archive (and therefore
bloom's upstream import) excludes — intended.
Dependency readiness
| Dependency | rosdep key state | Action |
|---|---|---|
| rclcpp, rclcpp_components, tf2*, *_msgs, pcl_conversions, std_srvs | released ROS packages | none |
libg2o |
released (ros-<distro>-libg2o; verified 2026-06-11: rosdep resolve libg2o → ros-humble-libg2o on jammy, ros-jazzy-libg2o on noble) |
none |
libpcl-all-dev |
standard rosdep key (system PCL) | none |
ndt_omp_ros2 |
source tag and Humble/Jazzy Bloom PRs exist, but the candidate overlaps Humble's released ndt_omp files, has an unanswered convergence review, and both exact PR heads have a failed check run |
converge on canonical ndt_omp, or fully isolate the fork; answer both reviews and require a current-base green replacement before requesting merge |
rko_lio |
PRBonn 0.3.2-1 is registered and built in testing for Humble/Jazzy; main has Humble 0.3.2 and Jazzy 0.2.0; declared as rko_lio >= 0.3.2 after the official-binary gate passed |
wait for Jazzy 0.3.2 to sync to main before the normal Jazzy apt path |
This table was rechecked directly against the
Humble distribution
and
Jazzy distribution
in ros/rosdistro on 2026-07-30. Neither distribution contains
ndt_omp_ros2; both register rko_lio 0.3.2-1 from
PRBonn/rko_lio and
ros2-gbp/rko_lio-release.
The amd64 apt indexes were rechecked on 2026-08-12. The ROS testing repository
contains 0.3.2-1 builds for both distributions. The main repository, which
normal users install from, now contains Humble 0.3.2 but still contains Jazzy
0.2.0. The exact observed versions are preserved in the
2026-08-12 dependency snapshot.
NDT package convergence review must close first
scanmatcher directly declares <depend>ndt_omp_ros2</depend>. The
dependency is consumed from
https://github.com/rsasaki0109/ndt_omp_ros2 at 8b77fa5.
It is a downstream ROS 2 fork of koide3/ndt_omp, not an independent
algorithm. Its product-required delta is the rotation/translation-prior and
adaptive correspondence API consumed by scanmatcher.
The 0.1.0 source tag,
release repository,
and generated Humble PR #52949
and Jazzy PR #52950 already
exist. Do not recreate the tag or rerun Bloom.
The current candidate is not safely co-installable with Humble's released
ndt_omp 0.0.0-1. Although the ROS and CMake package names differ, both
packages install include/pclomp/* and lib/libndt_omp.so and expose the
same pclomp namespace. The rosdistro reviewer correctly asked how the fork
relates to the existing package, and no maintainer response follows that
review. The
2026-08-12 review audit
records the exact lineage, consumed API delta, collision, and prepared
response. Both old PR heads also fail the same stale-base OpenEmbedded rosdep
check. The live preflight therefore reports BLOCKED, preserves both review
actions, and never treats this as wait-only IN_PROGRESS.
Run the read-only preflight immediately before doing any publication work:
python3 scripts/check_ndt_omp_release_readiness.py
python3 scripts/check_ndt_omp_release_readiness.py \
--require-ready-to-tag \
--output-json /tmp/ndt-omp-release-preflight.json
The first command describes the current state; the strict command exits 1
unless the exact reviewed candidate is READY_TO_TAG. It validates the
parent gitlink, submodule HEAD and cleanliness, package metadata, changelog,
CMake install/export contract, and Bloom CI assets. Its remote inspection
then verifies origin/humble, source tag, release-repository existence, both
rosdistro keys, generated PR state and mergeability, every exact-head check
run, and whether the latest actionable human review has a later author
response. Failed, pending, missing, inconsistent, or truncated check evidence
is BLOCKED. The checker uses an explicit GITHUB_TOKEN when provided,
otherwise it non-interactively reuses the active gh auth credential. If
neither is available, it keeps the anonymous read path and fails closed when
that quota is insufficient. The credential is sent only to the exact
https://api.github.com origin and is never included in the report. A GitHub
404 means an initial artifact is absent; any other HTTP, malformed response,
or network error is BLOCKED, never mistaken for absence, green CI, or
reviewer approval.
CI runs --offline, whose successful state is only LOCAL_READY. After
publication, use --require-released; it passes only when the tag, release
repository, and Humble and Jazzy rosdistro entries all exist. IN_PROGRESS
means publication is partial without an unanswered detected review.
REVIEW_REQUIRED names each unanswered human-review URL and fails every
strict release gate. A failed/pending/missing check suite, explicitly
unmergeable PR, or unresolved GitHub mergeability calculation never becomes a
wait-only result; it is BLOCKED, while any unanswered-review actions remain
visible. The JSON contract is
ndt-omp-release-readiness-v2.schema.json.
The checker is read-only; it never creates a tag, repository, or PR.
- Prefer upstream convergence: open the prepared four-API change against
koide3/ndt_ompas a Draft PR after its exact-base and duplicate checks pass. - Replace the response packet's
<UPSTREAM_PR_URL>only with that verified Draft URL, then post the transparent full response to Jazzy and matching concise response to Humble. Acknowledge the downstream lineage and file collision; do not request merge of the current package as-is. - Address upstream review with focused changes. After acceptance, change
both
scanmatcherandgraph_based_slamto the canonicalndt_omppackage, and coordinate its Humble update and first Jazzy release. - Only if upstream declines the project-specific API, fully isolate the fork: new package identity, C++ namespace, include root, library/SONAME, CMake target, version/tag, Bloom tracks, and replacement rosdistro PRs.
- Refresh or replace the selected registration from current rosdistro
master, require every exact-head check to pass, and proceed to the four lidarslam packages only after both supported distros resolve one collision-free NDT dependency from ROS apt.
The implementation needed for step 2 has been prepared and tested locally.
The upstream patch is based on exact koide3/ndt_omp commit
5495fd9214945afcb4b35d5a1da385e405c52bf9; its SHA-256 is
7b641c32ec4f30faa302e60aaa89765bb9acf67f3f0feb85f9e4e11e88b4dc9f.
It builds and passes four focused tests on both Humble and Jazzy. A
canonical-package scanmatcher build also passes all 109 tests. The parent has already moved
its registration ownership and casts to the PCL shared-pointer API, so the
post-upstream transition patch is limited to dependency-name replacement and
the upstream spelling of setOutlierRatio; that patch has SHA-256
c090b8f2228b21dcf30650114f9638f38497ca5a0214e3e6063a53aa7bef66b1.
It covers both direct consumers: two scanmatcher build references, seven
graph_based_slam build references, and both package manifests. The complete
four-package canonical workspace builds and installs without the fork on the
network-isolated Humble and Jazzy images.
The exact implementation and verification record is in the
2026-08-12 review audit.
The
copy-ready upstream PR packet
binds the exact local commit, fork branch, Draft PR text, duplicate audit,
current clean Jazzy rerun, and publication sequence. It remains local-only and
authorizes no GitHub write.
Neither patch has been submitted or published.
Before any upstream action, reproduce both exact local identities and current GitHub state:
python3 scripts/check_canonical_ndt_convergence.py --json
python3 scripts/check_canonical_ndt_convergence.py \
--upstream-checkout /path/to/clean/koide3-ndt_omp \
--require-ready-for-upstream-review
python3 scripts/check_canonical_ndt_convergence.py \
--upstream-checkout /path/to/clean/koide3-ndt_omp-at-5495fd9 \
--candidate-checkout /path/to/clean/ndt_omp-at-618f02f \
--online \
--require-ready-for-draft-pr
The machine contract is
canonical-ndt-convergence-v1.json.
READY_FOR_UPSTREAM_REVIEW is local technical evidence only and never grants
GitHub write authority. READY_FOR_DRAFT_PR additionally proves the current
upstream/fork/branch/duplicate state and exact candidate commit, but likewise
does not grant GitHub write authority.
Historical NDT 0.1.0 bootstrap commands — do not rerun
The commands below record the already completed first tag and Bloom setup. They are retained for audit history only. The source tag and release repository now exist, so the absent-tag assertion intentionally fails. The current action is reviewer response and dependency convergence, not replaying these commands.
git clone https://github.com/rsasaki0109/ndt_omp_ros2.git
cd ndt_omp_ros2
git fetch --prune origin
RELEASE_COMMIT=8b77fa5a6cdcad45bf35918361c892b6d94a287e
test "$(git rev-parse origin/humble)" = "$RELEASE_COMMIT"
test -z "$(git status --porcelain)"
test "$(python3 -c \
'import xml.etree.ElementTree as E; print(E.parse("package.xml").findtext("version"))')" \
= "0.1.0"
test -z "$(git ls-remote --tags origin refs/tags/0.1.0)"
git tag -a 0.1.0 "$RELEASE_COMMIT" -m "ndt_omp_ros2 0.1.0"
git push origin refs/tags/0.1.0
The tag is intentionally not v0.1.0: the Bloom track below uses the
default :{version} release-tag template. Do not tag the parent
lidarslam_ros2 repository.
Create the public release repository once, without generated files, then give
Bloom the master branch it expects:
gh auth status
gh repo create rsasaki0109/ndt_omp_ros2-release \
--public \
--description "Bloom release repository for ndt_omp_ros2"
gh auth setup-git
RELEASE_REPO_DIR="$(mktemp -d)/ndt_omp_ros2-release"
git clone https://github.com/rsasaki0109/ndt_omp_ros2-release.git \
"$RELEASE_REPO_DIR"
git -C "$RELEASE_REPO_DIR" commit --allow-empty -m "Initialize release repository"
git -C "$RELEASE_REPO_DIR" branch -M master
git -C "$RELEASE_REPO_DIR" push -u origin master
Install Bloom from the target ROS/Ubuntu package repository, then release Humble first and Jazzy second:
sudo apt update
sudo apt install python3-bloom python3-catkin-pkg python3-rosdep
RELEASE_REPO=https://github.com/rsasaki0109/ndt_omp_ros2-release.git
bloom-release ndt_omp_ros2 \
--rosdistro humble \
--track humble \
--new-track \
--override-release-repository-url "$RELEASE_REPO"
bloom-release ndt_omp_ros2 \
--rosdistro jazzy \
--track jazzy \
--new-track \
--override-release-repository-url "$RELEASE_REPO"
The command options have distinct jobs:
| Option | Why it is present |
|---|---|
ndt_omp_ros2 |
rosdistro repository key; it also matches the single package name here |
--rosdistro <distro> |
selects the Humble or Jazzy distribution file and Debian target |
--track <distro> |
selects the independently maintained Bloom track |
--new-track |
creates that track on its first release; omit it on later releases |
--override-release-repository-url |
supplies the release repository before a rosdistro entry exists |
Use these first-run track answers; press Enter for the values shown as defaults:
| Prompt | Answer |
|---|---|
| repository name | ndt_omp_ros2 |
| upstream repository | https://github.com/rsasaki0109/ndt_omp_ros2.git |
| upstream type | git |
| version | :{auto} |
| release tag | :{version} |
| upstream devel branch | humble |
| ROS distro | humble or jazzy, matching the command |
| patches directory | empty / None |
| release repository push URL | empty; the HTTPS origin is already authenticated by gh auth setup-git |
Bloom pushes generated branches and tags to the release repository and then
offers the corresponding ros/rosdistro PR. Verify that each generated PR
only adds ndt_omp_ros2, uses the release URL above, and reports version
0.1.0-1. Do not use --non-interactive for this first release. If either
command fails, fix the cause and rerun it; do not accept Bloom's offered
force-push without first inspecting the release repository.
rko_lio binary compatibility is proven for the golden path
The RKO-LIO flagship launch (rko_lio_slam.launch.py) uses the rko_lio
package at runtime. lidarslam/package.xml now declares
<exec_depend version_gte="0.3.2">rko_lio</exec_depend>, so an installed
flagship path cannot silently resolve to the older main-repository builds.
An official rko_lio release line and binary packages are now present for
both supported distributions, with the versions differing between testing
and main as recorded above. The source checkout pins fork merge commit
79d71e8, whose parents are the previous maintained fork (33402d4) and
official PRBonn v0.3.2 (48e12f9). Its package metadata is therefore aligned
at 0.3.2 while retaining the fork's offline-completion, recovery,
diagnostics, and opt-in research changes. The
test_bundled_dependency_version_alignment CI gate rejects a future bundled
package version below the lidarslam/package.xml runtime minimum.
The successful official-binary gate still proves only the maintained
MID-360 golden path against the unmodified official package. It does not
claim equivalence for fork-only research features, and the fork must not be
bloomed under the already-owned rko_lio package name.
The resolution gate completed in public run 30412938777:
- Run
.github/workflows/official-rko-binary-compatibility.yml. It builds the release-shaped source tree without the RKO-LIO submodule, installs the officialros2-testing-apt-sourceconfiguration and the exact0.3.2-1testing candidate, builds production packages with source-only fork research tests disabled, provesoffline_noderesolves from/opt/ros/<distro>, and runs the pinned MID-360 E2E independently on Humble and Jazzy. The workflow records the full Debian build version and executable SHA-256 in its non-geometry evidence artifact. - Both passed all 18 E2E checks. The permanent non-geometry record is
official-rko-binary-compatibility-2026-07-29.md.lidarslamtherefore requiresrko_lio >= 0.3.2; fork-only features remain evaluation scope. - If a scheduled rerun regresses, upstream the minimum product fixes to
PRBonn/rko_lioor give the maintained fork a non-conflicting package identity before releasing it. Do not silently substitute untested source code.
Do not advertise sudo apt install ros-<distro>-lidarslam as the golden path
until ndt_omp_ros2 is released, Jazzy rko_lio 0.3.2 is synced to main, and
the package-manager installation E2E gate passes.
The compatibility workflow runs when its product boundary changes on
develop, is scheduled weekly to detect repository drift, and can be
dispatched manually. It intentionally uses the maintained MID-360 preset:
lidarslam/param/rko_lio_mid360.yaml only uses parameters implemented by the
official 0.3.2 line. Research presets containing fork-only recovery,
diagnostic, radar, visual, or gravity parameters are outside this gate. The
NTU-VIRAL preset is also outside the first adoption gate because it currently
contains fork-only timestamp-offset and ICP keypoint controls.
Distro targets
Humble (Ubuntu 22.04) and Jazzy (Ubuntu 24.04). Both are already exercised by
the CI matrix on every push, including the ndt_omp_ros2 submodule build, so
no new build risk is expected on the farm. All ament tests run on synthetic
fixtures (no datasets, no network, no GPU), which matches buildfarm
constraints.
Release procedure (maintainer)
One-time setup:
pip3 install -U bloom catkin_pkg
# a GitHub token with repo scope, configured for bloom:
# https://bloom.readthedocs.io/ -> "Automated PR opening"
Per release:
# 0. ensure develop is green and this repo's release prep is merged
# 1. tag the release commit (release.yml publishes the GitHub release)
VERSION="$(tr -d '\n' < VERSION)"
git tag "v${VERSION}" && git push origin "v${VERSION}"
# 2. create an empty release repo once (first release only):
# https://github.com/rsasaki0109/lidar_slam_ros2-release
# 3. release into each distro (first run is interactive; answers below)
bloom-release --rosdistro humble lidarslam_ros2
bloom-release --rosdistro jazzy lidarslam_ros2
First-run interactive answers:
| Prompt | Answer |
|---|---|
| repository name | lidarslam_ros2 |
| upstream repository | https://github.com/rsasaki0109/lidar_slam_ros2.git |
| upstream type | git |
| upstream branch | develop |
| version | :{auto} (reads package.xml) |
| release tag | v:{version} (upstream tags are v-prefixed; matches the v* trigger in release.yml) |
| release repository | https://github.com/rsasaki0109/lidar_slam_ros2-release.git |
bloom ends by offering to open the ros/rosdistro PR with the configured
GitHub token — submit it, answer review comments (license string, maintainer
email, description quality are the usual ones), and wait for the buildfarm.
Binaries appear in the ROS testing repo first, then sync to main with the
next distro sync (typically 2–6 weeks).
Package-manager evidence window
When the new lidarslam version appears in ROS testing, run the clean package-manager path for both supported distributions:
python3 scripts/check_ros_apt_dependency_readiness.py --require testing
Do not dispatch the dataset-backed workflow until this dependency-only
preflight reports TESTING_READY or MAIN_READY.
gh workflow run package-manager-install-upgrade.yml \
-f source_ref=v0.9.1 \
-f target_version=0.9.1 \
-f target_channel=testing \
-f mode=clean-install
For every release after the first, also capture the upgrade while the previous version remains in main and the new version is in testing:
gh workflow run package-manager-install-upgrade.yml \
-f source_ref=v0.9.1 \
-f target_version=0.9.1 \
-f target_channel=testing \
-f mode=upgrade \
-f baseline_version=0.9.0
Replace the example versions with the exact immutable source tag and apt
versions under review. The workflow rejects a source_ref whose root
VERSION differs from target_version, missing exact Debian candidates, an
old or failed baseline report, dependency versions below the product
minimums, stale paths, or any installed CLI/real-map failure. Download and
retain both Humble and Jazzy non-geometry artifacts before the testing
candidate syncs.
After the target reaches main, rerun clean-install with
target_channel=main. Do not add the apt command to the beginner
documentation until both main-channel jobs pass. The schema-backed verifier
and workflow are described in Distribution and installed CLI.
After the first sync
- README: add the
sudo apt install ros-humble-lidarslaminstall path next to the source build. - Subsequent releases: update each package's
CHANGELOG.rst, bump all fourpackage.xmlversions together withVERSION(seeRELEASING.md), tag, and re-runbloom-release(non-interactive after the first time).
Known caveats
lidarslam/images/demo media (~25 MB of GIF/mp4/png) ships inside the source package because the README references those paths. Acceptable for now; moving demo media out of the package directory is a possible later cleanup to slim the source deb.- The repository-level
CHANGELOG.mdis the human-facing project changelog; the per-packageCHANGELOG.rstfiles are what bloom turns into deb changelogs (REP-132). Both need updating per release. git archivedrops submodules, so the upstream tarball bloom imports contains noThirdparty/sources. Do not move release-relevant code intoThirdparty/.