Summary
mkLogosModule / mkLogosQmlModule do not inject follows wiring for the logos-module-builder input of transitively pulled dependency flakes (notably delivery_module). As a result, every module that depends on delivery_module ends up with two logos-module-builder entries in its flake.lock — the one the user pinned, plus whatever default-branch rev delivery_module pulled in.
This silently breaks the tutorial-sanctioned local-dev workflow (nix build --override-input <module> path:../<module>) as soon as the user pins logos-module-builder to anything other than master HEAD (e.g. tutorial-v1), because the transitive rev fights the pinned one in dependent flakes.
Reproduction
Minimal tictactoe-style module, tictactoe/flake.nix:
{
inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder/tutorial-v1";
delivery_module.url = "github:logos-co/logos-delivery-module/<some-pin>";
# NOTE: no follows wiring
};
outputs = inputs@{ logos-module-builder, delivery_module, ... }:
logos-module-builder.lib.mkLogosModule {
src = ./.;
configFile = ./metadata.json;
flakeInputs = inputs;
};
}
After nix flake lock:
$ python3 -c "
import json
lock = json.load(open('flake.lock'))
for k, v in lock['nodes'].items():
if 'module-builder' in k:
print(k, v.get('original',{}).get('ref','-'), v.get('locked',{}).get('rev','')[:12])
"
logos-module-builder - 4987fed5b7a9 # transitive, via delivery_module (master HEAD)
logos-module-builder_2 tutorial-v1 46a51e5fc321 # root pin
Now a sibling UI flake that depends on this module:
# tictactoe-ui-qml/flake.nix
inputs = {
logos-module-builder.url = "github:logos-co/logos-module-builder/tutorial-v1";
tictactoe.url = "github:user/repo?dir=tictactoe";
};
nix build .#lgx-portable --override-input tictactoe path:../tictactoe now has three logos-module-builder entries in its flake.lock and the transitive one (from tictactoe.inputs.delivery_module) can silently win for parts of the build graph, producing wire-format mismatches at runtime.
Why the tutorial workflow hits this every time
tutorial-qml-ui-app.md §5.2 and tutorial-cpp-ui-app.md tell users to use --override-input <core_module> path:../<core_module> for local dev. This is the blessed workflow. But:
- The tutorial doesn't mention
follows.
mkLogosModule doesn't inject it.
- Any module that depends on
delivery_module (or any other flake that itself depends on logos-module-builder) thus ships a duplicate in its flake.lock.
- Users who pin
logos-module-builder (e.g. to tutorial-v1 to match basecamp v0.1.1's bundled delivery_module 1.0.0 wire format) hit this immediately.
Proposed fix
mkLogosModule / mkLogosQmlModule know the full flakeInputs set. For any entry in that set whose flake declares logos-module-builder as one of its inputs, the wrapper should inject follows = "logos-module-builder" so only the root pin survives in flake.lock.
Equivalently, the tutorial scaffold template could emit the follows line for known-to-be-affected deps (delivery_module for sure; probably others over time):
delivery_module = {
url = "github:logos-co/logos-delivery-module/<pin>";
inputs.logos-module-builder.follows = "logos-module-builder";
};
Either fix eliminates the duplicate entry and makes the tutorial's --override-input workflow robust against pin drift.
Workaround we're using in the meantime
Adding the follows by hand in every dependent flake:
delivery_module.inputs.logos-module-builder.follows = "logos-module-builder";
(tictactoe/flake.nix, tictactoe-ui-cpp/flake.nix, tictactoe-ui-qml/flake.nix.)
Why this matters for DX
Today a user following the tutorial sees a green nix build on the core module, a green nix build on the UI module, and a broken nix build --override-input combination — with no obvious explanation. Debugging required tracing the flake.lock by hand. Fixing this in mkLogosModule or the tutorial scaffold would make the sanctioned local-dev workflow work out of the box.
Context: hit while working on fryorcraken/logos-module-tictactoe (a three-flake tutorial example with core + QML UI + C++ UI).
Summary
mkLogosModule/mkLogosQmlModuledo not injectfollowswiring for thelogos-module-builderinput of transitively pulled dependency flakes (notablydelivery_module). As a result, every module that depends ondelivery_moduleends up with twologos-module-builderentries in itsflake.lock— the one the user pinned, plus whatever default-branch revdelivery_modulepulled in.This silently breaks the tutorial-sanctioned local-dev workflow (
nix build --override-input <module> path:../<module>) as soon as the user pinslogos-module-builderto anything other than master HEAD (e.g.tutorial-v1), because the transitive rev fights the pinned one in dependent flakes.Reproduction
Minimal tictactoe-style module,
tictactoe/flake.nix:After
nix flake lock:Now a sibling UI flake that depends on this module:
nix build .#lgx-portable --override-input tictactoe path:../tictactoenow has threelogos-module-builderentries in its flake.lock and the transitive one (fromtictactoe.inputs.delivery_module) can silently win for parts of the build graph, producing wire-format mismatches at runtime.Why the tutorial workflow hits this every time
tutorial-qml-ui-app.md§5.2 andtutorial-cpp-ui-app.mdtell users to use--override-input <core_module> path:../<core_module>for local dev. This is the blessed workflow. But:follows.mkLogosModuledoesn't inject it.delivery_module(or any other flake that itself depends onlogos-module-builder) thus ships a duplicate in itsflake.lock.logos-module-builder(e.g. totutorial-v1to match basecamp v0.1.1's bundleddelivery_module1.0.0 wire format) hit this immediately.Proposed fix
mkLogosModule/mkLogosQmlModuleknow the fullflakeInputsset. For any entry in that set whose flake declareslogos-module-builderas one of its inputs, the wrapper should injectfollows = "logos-module-builder"so only the root pin survives inflake.lock.Equivalently, the tutorial scaffold template could emit the
followsline for known-to-be-affected deps (delivery_modulefor sure; probably others over time):Either fix eliminates the duplicate entry and makes the tutorial's
--override-inputworkflow robust against pin drift.Workaround we're using in the meantime
Adding the
followsby hand in every dependent flake:(
tictactoe/flake.nix,tictactoe-ui-cpp/flake.nix,tictactoe-ui-qml/flake.nix.)Why this matters for DX
Today a user following the tutorial sees a green
nix buildon the core module, a greennix buildon the UI module, and a brokennix build --override-inputcombination — with no obvious explanation. Debugging required tracing the flake.lock by hand. Fixing this inmkLogosModuleor the tutorial scaffold would make the sanctioned local-dev workflow work out of the box.Context: hit while working on fryorcraken/logos-module-tictactoe (a three-flake tutorial example with core + QML UI + C++ UI).