The bb_example_wx200 job in Test Subprojects fails its dialyzer step on
every pull request that touches bb's source, and passes on every push to
main. The failure is not a type error — dialyzer analyses zero modules:
:dialyzer.run error: File not found:
/home/runner/work/bb/bb/bb_example_wx200/_build/dev/lib/bb_example_wx200/consolidated/Elixir.Collectable.beam
...
files: []
:dialyzer.run error: Analysis failed with error:
No .beam files to analyze (no --src specified?)
Halting VM with exit status 1
Every other tool in that job passes — compiler, credo, ex_doc, ex_unit,
formatter, gettext, mix_audit, reuse, unused_deps.
It correlates with the branch, not the change
Recent Test Subprojects runs, bb_example_wx200 job only:
| Run |
Branch |
Event |
Result |
| 32674375855 |
fix/normalise-parameter-units |
pull_request |
failure |
| 32619948357 |
v0.30.1 |
push (tag) |
failure |
| 32619948241 |
main |
push |
success |
| 32619919149 |
main |
push |
success |
| 32619704733 |
fix/compile-time-unit-error-messages |
pull_request |
failure |
| 32613985655 |
main |
push |
success |
| 32613733359 |
dependabot/hex/dev-dependencies-… |
pull_request |
success |
| 32613651172 |
renovate/beam-bots-.github-digest |
pull_request |
success |
fix/compile-time-unit-error-messages is the branch that became 62ce89e and
shipped as 0.30.1. It failed as a PR, then passed on main with the same code.
The two dependency-only PRs passed. The failure log is byte-identical across
all three failing runs.
So the discriminator is whether the run recompiles bb into the subproject's
_build, not whether the change is sound.
Likely mechanism
The _build cache key is
key: …-${{ matrix.project.name }}-build-${{ hashFiles(format('{0}/mix.lock', matrix.project.name), 'bb/mix.lock') }}
which does not move when bb/lib/** changes — by design, since BB_VERSION=local
makes bb a path dep. The Force a PLT re-check step then removes
_build/*/*.plt.hash so dialyxir re-checks against bb's newest exports.
On a source-changing branch that combination appears to leave
_build/dev/lib/bb_example_wx200 without its consolidated protocol beams, and
dialyxir's file list comes back empty rather than triggering a rebuild.
bb_example_wx200 sets consolidate_protocols: Mix.env() == :prod, so nothing
regenerates consolidated/ in :dev, and the other 18 subprojects are
unaffected.
Why it matters
The downstream matrix is the main safety net for a breaking change to core —
it is the reason a fix! to BB.Parameter can be reviewed with confidence.
A job that reliably goes red for reasons unrelated to the diff trains everyone
to skim past it, which is exactly when a real downstream break gets waved
through.
Worth considering
- Include
bb's source in the _build cache key for subprojects, or drop
_build/dev rather than just the PLT hash, so a source change rebuilds
rather than half-restores.
- Or have the step force the
:dev build explicitly (MIX_ENV=dev mix compile)
before mix check, so dialyzer always has beams to analyse.
The
bb_example_wx200job in Test Subprojects fails itsdialyzerstep onevery pull request that touches
bb's source, and passes on every push tomain. The failure is not a type error — dialyzer analyses zero modules:Every other tool in that job passes — compiler, credo, ex_doc, ex_unit,
formatter, gettext, mix_audit, reuse, unused_deps.
It correlates with the branch, not the change
Recent
Test Subprojectsruns,bb_example_wx200job only:fix/normalise-parameter-unitsv0.30.1mainmainfix/compile-time-unit-error-messagesmaindependabot/hex/dev-dependencies-…renovate/beam-bots-.github-digestfix/compile-time-unit-error-messagesis the branch that became 62ce89e andshipped as 0.30.1. It failed as a PR, then passed on
mainwith the same code.The two dependency-only PRs passed. The failure log is byte-identical across
all three failing runs.
So the discriminator is whether the run recompiles
bbinto the subproject's_build, not whether the change is sound.Likely mechanism
The
_buildcache key iswhich does not move when
bb/lib/**changes — by design, sinceBB_VERSION=localmakes
bba path dep. TheForce a PLT re-checkstep then removes_build/*/*.plt.hashso dialyxir re-checks against bb's newest exports.On a source-changing branch that combination appears to leave
_build/dev/lib/bb_example_wx200without its consolidated protocol beams, anddialyxir's file list comes back empty rather than triggering a rebuild.
bb_example_wx200setsconsolidate_protocols: Mix.env() == :prod, so nothingregenerates
consolidated/in:dev, and the other 18 subprojects areunaffected.
Why it matters
The downstream matrix is the main safety net for a breaking change to core —
it is the reason a
fix!toBB.Parametercan be reviewed with confidence.A job that reliably goes red for reasons unrelated to the diff trains everyone
to skim past it, which is exactly when a real downstream break gets waved
through.
Worth considering
bb's source in the_buildcache key for subprojects, or drop_build/devrather than just the PLT hash, so a source change rebuildsrather than half-restores.
:devbuild explicitly (MIX_ENV=dev mix compile)before
mix check, so dialyzer always has beams to analyse.