Skip to content

fix(ci): use path filter outputs for test should-run decisions#1284

Merged
spomichter merged 1 commit intodevfrom
fix/ci-should-run-expressions
Feb 17, 2026
Merged

fix(ci): use path filter outputs for test should-run decisions#1284
spomichter merged 1 commit intodevfrom
fix/ci-should-run-expressions

Conversation

@spomichter
Copy link
Contributor

Problem

PR #1279 removed paths-ignore: '**.md' from the pull_request trigger to fix branch protection blocking md-only PRs. But the test caller should-run expressions relied on dev.result == 'success' to decide whether to run tests.

Build jobs with if: always() report success even when should-run=false and all steps are skipped. So for md-only PRs:

  1. check-changes correctly detects no code changes (all outputs false)
  2. dev job runs with should-run=false, skips all steps, reports success
  3. Test callers see dev.result == 'success'should-run = truefull test suite runs

Fix

Replace upstream job result checks with direct path filter output checks:

  • Non-ROS tests (run-tests, run-heavy-tests, run-lcm-tests, run-integration-tests): tests || python || dev
  • ROS tests + mypy (run-ros-tests, run-mypy): tests || ros || python || dev

When only .md files change, all path filter outputs are falseshould-run = false → tests skip.

Verification

After merging, open a PR that only changes .md files against dev. Test jobs should complete in seconds with all steps skipped, and ci-complete should pass.

The test caller should-run expressions relied on upstream job results
(e.g. dev.result == 'success') to decide whether to run tests. But
build jobs with if: always() report 'success' even when should-run=false
and all steps are skipped — so md-only PRs incorrectly triggered the
full test suite after paths-ignore was removed in #1279.

Replace upstream result checks with direct path filter output checks:
- Non-ROS tests: tests || python || dev
- ROS tests + mypy: tests || ros || python || dev

When only .md files change, all outputs are false → should-run=false.
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Greptile Summary

This PR fixes a regression introduced in #1279 where removing paths-ignore: '**.md' from the pull_request trigger caused test jobs to erroneously run on markdown-only PRs. The root cause was that dev and ros-dev build jobs with if: always() report success even when skipped, so the old needs.dev.result == 'success' condition was insufficient to suppress tests.

The fix replaces upstream job result checks with direct check-changes path filter outputs in the should-run expression for all six test caller jobs:

  • run-ros-tests and run-mypy: now trigger on tests || ros || python || dev
  • run-tests, run-heavy-tests, run-lcm-tests, run-integration-tests: now trigger on tests || python || dev

Key changes:

  • The new logic correctly short-circuits when all path filter outputs are false (e.g. md-only PRs), preventing unnecessary test runs.
  • The fix removes the dependency on upstream build job results (dev.result, ros-dev.result) from should-run decisions, which was the source of the bug.
  • Behavioral difference: Under the old logic, a failed upstream build job would cause should-run=false (tests skipped). Under the new logic, if a build fails but a relevant path filter is true, tests will still run with should-run=true — using the fallback :dev image (controlled by the dev-image expression which already accounts for this). This is arguably more correct (run tests even if build fails, just use the last known-good image), but it's a subtle behavioral change worth being aware of.
  • The commented-out run-module-tests job still uses the old pattern — not a problem since it's commented out, but should be updated if it gets re-enabled.

Confidence Score: 4/5

  • This PR is safe to merge — it correctly fixes the md-only PR test over-triggering bug with no functional regressions for normal code PRs.
  • The fix directly addresses the root cause described in the PR description. The new path-filter-output-based conditions are simpler and more correct than the upstream-job-result-based conditions for the should-run decision. The only caveat is a minor behavioral difference when an upstream build fails (tests now run against fallback image instead of being skipped), which is a pre-existing design choice already expressed in the dev-image fallback logic. No security concerns, no syntax errors, and the commented-out job's stale pattern is a low-risk style issue.
  • .github/workflows/docker.yml — specifically the commented-out run-module-tests block which still uses the old pattern.

Important Files Changed

Filename Overview
.github/workflows/docker.yml Replaces upstream job result checks with direct path filter output checks for test should-run decisions. The fix correctly prevents spurious test runs on md-only PRs. One minor concern: test jobs can now run with should-run=true against the fallback :dev image even when an upstream build job explicitly fails, whereas the old logic would have short-circuited in that case.

Flowchart

flowchart TD
    A[PR Opened] --> B[check-changes job]
    B --> C{dorny/paths-filter outputs}
    C --> D[ros: true/false]
    C --> E[python: true/false]
    C --> F[dev: true/false]
    C --> G[tests: true/false]

    D --> H[ros build job]
    E --> I[python build job]
    F --> J[dev build job\nneeds: python]
    D --> K[ros-python build job]
    K --> L[ros-dev build job\nneeds: ros-python]

    H --> L

    G --> M{should-run decision\nnew logic}
    E --> M
    F --> M
    D --> N{should-run decision\nnew logic ROS}
    E --> N
    F --> N
    G --> N

    M -->|tests OR python OR dev| O[run-tests\nrun-heavy-tests\nrun-lcm-tests\nrun-integration-tests]
    N -->|tests OR ros OR python OR dev| P[run-ros-tests\nrun-mypy]

    J --> O
    L --> P

    O --> Q[ci-complete gate]
    P --> Q
    Q -->|all pass/skip| R[✅ Branch protection passes]
    Q -->|any failure/cancel| S[❌ CI fails]
Loading

Last reviewed commit: 9ac8df0

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 151 to 157
should-run: ${{
needs.check-changes.result == 'success' &&
((needs.ros-dev.result == 'success') ||
(needs.ros-dev.result == 'skipped' &&
needs.check-changes.outputs.tests == 'true'))
(needs.check-changes.outputs.tests == 'true' ||
needs.check-changes.outputs.ros == 'true' ||
needs.check-changes.outputs.python == 'true' ||
needs.check-changes.outputs.dev == 'true')
}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests run even when upstream build fails

The new condition correctly fixes the md-only PR issue, but it removes the implicit guard that the old logic provided: under the previous condition, if ros-dev explicitly failed (result != 'success' and != 'skipped'), should-run would be false. Now, if ros-dev fails but tests == 'true', tests will run with should-run=true against the fallback :dev image.

This is not necessarily wrong — the dev-image expression already handles the fallback — but it does mean CI will report test results even when the freshly built image wasn't used. Consider whether you want to surface build failures as test skips or as tests running against stale images.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 17, 2026

Additional Comments (1)

.github/workflows/docker.yml
Stale pattern in commented-out job

The commented-out run-module-tests job (lines 239–271) still references the old needs.dev.result == 'success' pattern that this PR is replacing. If this job is re-enabled in the future without updating its condition, it will reintroduce the same bug.

#   if: ${{
#     always() &&
#     needs.check-changes.result == 'success' &&
#     ((needs.dev.result == 'success') ||
#     (needs.dev.result == 'skipped' &&
#     needs.check-changes.outputs.tests == 'true'))
#     }}

Consider updating it to match the new pattern (tests || python || dev) so any future uncomment picks up the correct logic, or add a comment noting it needs updating before re-enabling.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@spomichter spomichter merged commit ccb9337 into dev Feb 17, 2026
4 of 5 checks passed
spomichter added a commit that referenced this pull request Feb 21, 2026
Release v0.0.10: Manipulation Stack, MuJoCo Simulation, DDS Transport, Web and Native Visualization via Rerun


## Highlights

88+ commits, 20 contributors, 700+ files changed.

The TLDR: **a complete manipulation stack**, **MuJoCo simulation**, **DDS transport**, and **a rewritten visualization pipeline**. Agents are no longer bolted on top — they're refactored as native modules with direct stream access. The entire ROS message dependency has been removed from core DimOS, and we've added VR, phone, and arm teleoperation stacks. You can now vibecode a pick-and-place task from natural language to motor commands. Installation has been significantly streamlined — no more direnv, simpler setup, and the web viewer is now the default.

---

## 🚀 New Features

### Simulation
- **MuJoCo simulation module** — Run any DimOS blueprint in simulation with no hardware. Supports xArm and Unitree embodiments, parses MJCF/URDF for robot properties, monotonic clock timing (no `time.sleep`). `dimos --simulation run unitree-go2` ([#1035](#1035)) by @jca0
- **Simulation teleop blueprints** — Added simulation teleop blueprints for Piper, xArm6, and xArm7. ([#1308](#1308)) by @mustafab0

### Manipulation
- **Modular manipulation stack** — Full planning stack with Drake: FK/IK solvers (Jacobian + Drake optimization), RRT path planning, world model with obstacle monitoring, multi-robot management. xArm6/7 and Piper support. ([#1079](#1079)) by @mustafab0
- **Joint servo and cartesian controllers** — Joint position/velocity controllers and cartesian IK task with Pinocchio solver. PoseStamped stream input for real-time control. ([#1116](#1116)) by @mustafab0
- **GraspGen integration** — Grasp generation via Docker-hosted GPU model. Lazy container startup, thread-safe init, RPC `generate_grasps()` returns ranked PoseArray. ([#1119](#1119), [#1234](#1234)) by @JalajShuklaSS
- **Gripper control** — Gripper RPC methods on control coordinator, exposed adapter property for custom implementations. ([#1213](#1213)) by @mustafab0
- **Detection3D and Object support** — Object input topics, TF support on manipulation module, pointcloud-to-convex-hull for Drake imports. ([#1236](#1236)) by @mustafab0
- **Agentic pick and place** — Reimplemented manipulation skills for agent-driven pick-and-place workflows. ([#1237](#1237)) by @mustafab0

### Teleoperation
- **Quest VR teleoperation** — Full WebXR + Deno bridge stack. Quest controller data (pose, trigger, grip) streamed to DimOS modules. Monitor-style locking for control loops. ([#1215](#1215)) by @ruthwikdasyam
- **Phone teleoperation** — Control Go2 from your phone with a web-based teleop interface. ([#1280](#1280)) by @ruthwikdasyam
- **Arm teleop with Pinocchio IK** — Single and dual arm teleoperation using Pinocchio inverse kinematics. Blueprints for xArm, Piper, and dual configurations. ([#1246](#1246)) by @ruthwikdasyam

### Transports & Infrastructure
- **DDS transport protocol** — CycloneDDS transport with configurable QoS (high-throughput and reliable profiles). Optional install, benchmark integration. ([#1174](#1174)) by @Kaweees
- **Pubsub pattern subscriptions** — Glob and regex pattern matching for topic subscriptions. `subscribe_all()` for bridge-style consumers. Topic type encoding in channel strings (`/topic#module.ClassName`). ([#1114](#1114)) by @leshy
- **LCM raw bytes passthrough** — Skip `lcm_encode()` when message is already bytes. ([#1223](#1223)) by @leshy
- **Unified TimeSeriesStore** — Pluggable backends (InMemory, SQLite, Pickle, PostgreSQL) with SortedKeyList for O(log n) operations. Replaces the old replay system and TimestampedCollection. Collection API with slice, range, and streaming methods. ([#1080](#1080)) by @leshy
- **DimosROS benchmark tests** — Benchmark suite for ROS transport performance. ([#1087](#1087)) by @leshy

### Navigation
- **FASTLIO2 support** — Hardware-verified localization with arm64 support. Docker deployment with FAR Planner, terrain analysis, and bagfile playback mode. Builds or-tools from source on arm64. ([#1149](#1149)) by @baishibona
- **Native Livox + FASTLIO2 module** — First-class DimOS native module for Livox Mid-360 lidar with FASTLIO2 localization. ([#1235](#1235)) by @leshy

### Visualization
- **RerunBridge module and CLI** — New bridge that subscribes to all LCM messages and logs those with `to_rerun()` to Rerun viewer. GlobalConfig singleton, web viewer support. Replaces the old rerun initialization system. ([#1154](#1154)) by @leshy
- **Webcam rerun visualization** — Camera module logs to Rerun with pinhole projection for 3D visualization. ([#1117](#1117)) by @ruthwikdasyam
- **Default viewer switched to rerun-web** — Browser-based viewer is now the default for broader compatibility. No native viewer install needed. ([#1324](#1324)) by @spomichter

### Agents
- **Agent refactor** — Restructured agent module with cleaner imports and global config integration. ([#1211](#1211)) by @paul-nechifor
- **Timestamp knowledge** — Agents now have timestamp awareness in prompts for temporal reasoning. ([#1093](#1093)) by @ClaireBookworm
- **Observe skill** — Go2 can now observe (capture and describe) its environment via agent skill. ([#1109](#1109)) by @paul-nechifor

### Platform & Hardware
- **G1 without ROS** — Unitree G1 blueprints decoupled from ROS dependency. Lazy imports for fast startup. ([#1221](#1221)) by @jeff-hykin
- **ARM (aarch64) support** — DimOS runs on ARM hardware. Platform-conditional dependencies, open3d source builds for arm64. ([#1229](#1229)) by @jeff-hykin
- **Universal joint/hardware schema** — `HardwareComponent` dataclass with `JointState`, `JointName` type aliases. Backend registry with auto-discovery for SDK adapters. ([#1040](#1040), [#1067](#1067)) by @mustafab0

---

## 🔧 Improvements

- **Optional Dask** — Start without Dask using `--no-dask` flag. Startup time reduced from ~60s to ~45s. ([#1111](#1111), [#1232](#1232)) by @paul-nechifor
- **RPC rework** — Renamed `ModuleBlueprint` → `_BlueprintAtom`, `ModuleBlueprintSet` → `Blueprint`, `ModuleConnection` → `Stream`. Added `ModuleRef`, improved type hints throughout. ([#1143](#1143)) by @jeff-hykin
- **Image class simplification** — Rewritten as pure NumPy dataclass. Removed CUDA backend, unused methods (solve_pnp, csrt_tracker), and image_impls/ directory. ([#1161](#1161)) by @leshy
- **Odometry message cleanup** — Simplified Odometry message type. ([#1256](#1256)) by @leshy
- **Remove all ROS message dependencies** — Purged ROS message types from core DimOS. Refactored rosnav to use ROSTransport. Removed dead ROS bridge code. ([#1230](#1230)) by @alexlin2
- **Removed bad function serialization** — Eliminated unnecessary serialization of Python functions. ([#1121](#1121)) by @paul-nechifor
- **Benchmark IEC units** — Switched bandwidth benchmarks from SI to IEC units for accuracy. ([#1147](#1147)) by @leshy
- **Pubsub typing improvements** — Thread-safety locks on `subscribe_new_topics` and `subscribe_all`. Proper type params across pubsub stack. ([#1153](#1153)) by @leshy
- **Autogenerated blueprint list** — Blueprints are now auto-discovered and listed. ([#1100](#1100)) by @paul-nechifor
- **Generic Buttons message** — Renamed `QuestButtons` to `Buttons` with generic field names for cross-platform teleop. ([#1261](#1261)) by @ruthwikdasyam
- **Dev container uses ros-dev image** — `./bin/dev` now runs the ROS-enabled dev image. ([#1170](#1170)) by @leshy
- **LSP support** — Added python-lsp-server and python-lsp-ruff to dev dependencies. ([#1169](#1169)) by @leshy
- **Lazy-load pyrealsense2** — RealSense camera module uses lazy imports to avoid errors in simulation environments without the SDK. ([#1309](#1309)) by @spomichter
- **Removed unused mmcv and mmengine** — Dead Detic dependencies removed, eliminating slow source builds from install. ([#1319](#1319)) by @spomichter
- **Simplified installation** — Removed direnv requirement, streamlined install instructions across all platforms. ([#1315](#1315)) by @spomichter
- **DDS extra excluded from --all-extras** — `cyclonedds` requires a source build, so `dds` is now excluded from `uv sync --all-extras` by default. ([#1318](#1318)) by @spomichter
- **Nix pre-commit skip** — Skip pre-commit install if hooks already exist. ([#1162](#1162)) by @leshy
- **Removed base-requirements** — Consolidated dependency management. ([#1098](#1098)) by @paul-nechifor
- **Removed old graspnet** — Cleaned up deprecated graspnet version. ([#1248](#1248)) by @paul-nechifor
- **Code cleanup** — Removed `tofix` markers ([#1216](#1216)), fixed ruff issues ([#1112](#1112)), removed old README_installation.md ([#1101](#1101)) by @paul-nechifor

---

## 🐛 Bug Fixes

- Fix LFS updating (move from .local to venv) ([#1090](#1090)) by @jeff-hykin
- Launch hotfixes: git clone HTTPS, get_data main branch ([#1091](#1091)) by @spomichter
- Fix camera demo not showing in Rerun ([#1148](#1148)) by @jeff-hykin
- Default to rerun native viewer ([#1099](#1099)) by @Nabla7
- Fix exploration blocking agent loop ([#1258](#1258)) by @paul-nechifor
- Fix person-follow blocking agent loop ([#1278](#1278)) by @paul-nechifor
- Skip metric3d tests on unsupported xformers GPUs (Blackwell compute capability >9.0) ([#1225](#1225)) by @leshy
- Fix manipulation tests ([#1218](#1218), [#1247](#1247)) by @jeff-hykin, @paul-nechifor
- Fix control coordinator e2e test ([#1212](#1212)) by @mustafab0
- Fix xarm7-sim broken e2e tests ([#1294](#1294)) by @paul-nechifor
- Pin langchain to restore supported providers ([#1241](#1241)) by @spomichter
- Fix missing library dependencies in Nix flake ([#1240](#1240)) by @Kaweees
- Fix discord invite link ([#1122](#1122)) by @spomichter
- macOS edgecase fix ([#1096](#1096)) by @jeff-hykin
- Fix second N in logo ([#1250](#1250)) by @jeff-hykin
- Fix Unitree Go2 minor issues ([#1307](#1307)) by @paul-nechifor
- Fix broken tests ([#1305](#1305)) by @ruthwikdasyam
- Fix `uv sync` for some macOS systems ([#1322](#1322)) by @jeff-hykin
- Fix mmcv install ([#1313](#1313)) by @paul-nechifor
- Fix mypy issues ([#1150](#1150), [#1167](#1167), [#1257](#1257)) by @leshy, @paul-nechifor, @jeff-hykin
- Fix Nix install uv pip extras ([#1321](#1321)) by @spomichter

---

## 📚 Documentation

- **Major docs overhaul** — New README with feature grid, hardware table, quickstart. Navigation, transports, data streams, and agent docs. ([#1295](#1295)) by @leshy
- **Day 1 docs** — Comprehensive getting started guide, development docs, contributing guide, architecture overview. Executable blueprint docs via md-babel-py. ([#1064](#1064)) by @jeff-hykin
- **Arm integration guide** — How-to for integrating new robotic arms with DimOS. ([#1238](#1238)) by @mustafab0
- **MCP documentation update** — Updated MCP install and usage instructions. ([#1251](#1251)) by @Kaweees
- **Docker docs** — First pass on Docker deployment documentation. ([#1151](#1151)) by @leshy
- **Transports documentation** — Encode/decode mixins, SHM examples, ROS/DDS transport docs. ([#1107](#1107)) by @leshy
- **Rerun API examples** — Updated examples for the new RerunBridge API. ([#1262](#1262)) by @jeff-hykin
- **PR template** added ([#1172](#1172)) by @christiefhyang
- **Simplified install instructions** — Removed direnv, streamlined across all platforms. ([#1315](#1315)) by @spomichter
- **Python example restored** — Added back the Python usage example. ([#1317](#1317)) by @jeff-hykin
- **Nix install updated** — Replaced uv with pip for Nix compatibility. ([#1326](#1326)) by @ruthwikdasyam
- **README improvements** ([#1311](#1311)) by @paul-nechifor
- **Simplified writing docs** — Consolidated writing_docs to a single markdown file. ([#1254](#1254)) by @jeff-hykin

---

## 🏗️ CI & Build

- **ci-complete gate** — Dynamic branch protection via single aggregated status check. MD-only PRs no longer blocked. ([#1279](#1279)) by @spomichter
- **Path-based test filtering** — Test jobs fully skip (no container spin-up) when no relevant code changed. ([#1284](#1284), [#1286](#1286)) by @spomichter
- **Navigation docker build workflow** — CI builds for the ROS navigation stack. ([#1259](#1259)) by @spomichter
- **CUDA test marker** — `@pytest.mark.cuda` for GPU-dependent tests. ([#1220](#1220)) by @jeff-hykin
- **e2e test marker** — Marked end-to-end tests for selective CI runs. ([#1110](#1110)) by @paul-nechifor
- **pytest stdin fix** — Added `-s` to default addopts for LCM autoconf compatibility. ([#1320](#1320)) by @spomichter

---

## ⚠️ Breaking Changes

- **RPC renames**: `ModuleBlueprint` → `_BlueprintAtom`, `ModuleBlueprintSet` → `Blueprint`, `ModuleConnection` → `Stream` ([#1143](#1143))
- **Image class rewrite**: `CudaImage` and `NumpyImage` removed. Image is now a pure NumPy dataclass. Methods like `solve_pnp`, `csrt_tracker`, `from_depth`, `to_depth_meters` removed. ([#1161](#1161))
- **ROS messages removed from core**: All `to_ros`/`from_ros` conversion methods removed. Use `ROSTransport` instead. ([#1230](#1230))
- **QuestButtons → Buttons**: Renamed with generic field names. ([#1261](#1261))
- **RerunBridge replaces old rerun init**: `dimos.dashboard.rerun_init` removed. Use `RerunBridgeModule` or the `rerun-bridge` CLI. ([#1154](#1154))
- **Unitree directory restructuring**: `unitree_go2` → `unitree/go2`, `unitree_g1` → `unitree/g1`. Blueprint names updated. ([#1221](#1221))
- **Default viewer is now rerun-web**: Use `--viewer-backend rerun` to restore native viewer. ([#1324](#1324))

---

## Quickstart

```bash
# Install
uv pip install dimos[base,unitree]

# Try it (no hardware needed)
# NOTE: First run downloads ~2.4 GB from LFS
dimos --replay run unitree-go2

# Simulate
uv pip install dimos[base,unitree,sim]
dimos --simulation run unitree-go2
```

---

## New Contributors 🎉

- @ruthwikdasyam — Quest VR teleoperation, phone teleop, arm teleop, webcam rerun viz
- @JalajShuklaSS — GraspGen integration
- @jca0 — MuJoCo simulation module
- @christiefhyang — PR template

---

**Full Changelog**: [v0.0.9...v0.0.10](v0.0.9...v0.0.10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant