Lower target and action deps (3.14.3)#315
Conversation
Draft an execution plan for lowering target and action `deps` into a new implicit-dependency class on the IR `BuildEdge` and emitting them as Ninja `|` implicit dependencies between explicit inputs and `||` order-only deps. The plan records the cycle-participation decision (explicit inputs and implicit deps participate; order-only deps do not), defers rule-level `Rule.deps` rejection to roadmap item 3.14.6, and keeps action hashing unchanged because `implicit_deps` lives on `BuildEdge` rather than `Action`. Validation runs through `make check-fmt`, `make lint`, `make test`, `make markdownlint`, `make nixie`, and `coderabbit review --agent`. The plan is DRAFT and must be approved before implementation begins. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
OverviewThis PR implements roadmap item 3.14.3: Lower target and action Design & DocumentationThe PR includes a new execplan document ( Related design documents were updated:
IR & Cycle DetectionThe IR graph ( Recipe Rendering & Command InterpolationManifest rendering ( Ninja EmissionNinja generation ( TestingComprehensive test coverage includes:
All tests pass; no new external crates added. WalkthroughLower manifest ChangesImplicit dependencies implementation
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 18 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (18 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Introduce the `BuildEdge.implicit_deps` field and initialise it as empty at every existing construction site. Keep behaviour unchanged for this step so the later manifest lowering, cycle detection, and Ninja rendering changes can be reviewed separately.
Populate `BuildEdge.implicit_deps` from manifest `deps` while keeping
`sources` as the only explicit recipe input class.
Preserve documented `{{ ins }}` and `{{ outs }}` recipe placeholders
through manifest rendering so IR interpolation can substitute them from
explicit inputs and outputs before action hashing.
Traverse `BuildEdge.implicit_deps` alongside explicit inputs during IR cycle analysis while continuing to ignore order-only dependencies. Add regression coverage for implicit-only cycles, mixed cycles, missing implicit dependencies, and bounded small cycles without adding a new test dependency.
Emit `BuildEdge.implicit_deps` with Ninja's single-pipe separator between explicit inputs and order-only dependencies. Cover explicit, implicit-only, order-only, and phony action edge shapes so the separator ordering remains stable.
Add an end-to-end manifest fixture that lowers target and action `deps`
into IR implicit deps and renders them as Ninja single-pipe dependencies.
Assert that recipe interpolation still receives only explicit `sources`,
including the documented `{{ ins }}` placeholder path.
Record that manifest `sources` become explicit recipe inputs, `deps` become implicit dependencies, and order-only dependencies remain outside cycle detection. Align the user, developer, design, and formal-verification notes with the implemented IR and Ninja dependency classes.
Record the final deterministic validation state before CodeRabbit review and note the existing Markdown formatting exception that prevents using `make fmt` as an all-or-nothing gate for this branch.
Mark the implicit dependency lowering roadmap item complete after the implementation, deterministic gates, and CodeRabbit review all passed. Update the ExecPlan with the final review and validation state.
Mark the ExecPlan complete after pushing the branch and refreshing the draft pull request with the final validation and reviewer context.
|
@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Code Duplicationsrc/ir/cycle.rs: What lead to degradation?The module contains 2 functions with similar structure: tests.cycle_detector_records_missing_dependencies,tests.cycle_detector_records_missing_implicit_dependencies Why does this problem occur?Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health. How to fix it?A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More |
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph. If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced. Code Duplicationsrc/ir/cycle.rs: What lead to degradation?The module contains 2 functions with similar structure: tests.cycle_detector_records_missing_dependencies,tests.cycle_detector_records_missing_implicit_dependencies Why does this problem occur?Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health. How to fix it?A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More |
This comment was marked as resolved.
This comment was marked as resolved.
Remove duplicated `CycleDetector` setup from the missing dependency tests by sharing the assertion skeleton inside the cycle test module.
|
@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph. If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced. Code Duplicationsrc/ir/cycle.rs: What lead to degradation?The module contains 2 functions with similar structure: tests.cycle_detector_records_missing_dependencies,tests.cycle_detector_records_missing_implicit_dependencies Why does this problem occur?Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health. How to fix it?A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More |
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai Please investigate the cause of the following issue using codegraph exploration and research, identify a fix and provide an AI coding agent prompt for the fix: |
This comment was marked as resolved.
This comment was marked as resolved.
Pass the test target map by reference so Clippy does not flag the helper for taking ownership of data it only inspects.
Reviewer's GuideImplements roadmap task 3.14.3 by introducing an explicit implicit-dependency class ( File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. ❌ Failed checks (1 error, 2 warnings)
|
This comment was marked as resolved.
This comment was marked as resolved.
|
@coderabbitai please create a new GitHub issue for the following: Testing (Property / Proof)
|
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
gh issue create \
--repo leynos/netsuke \
--title "Add proptest property-based tests for cycle detection, Ninja separator ordering, and command interpolation" \
--assignee leynos \
--body "## Summary
Property-based tests using \`proptest\` are de rigueur for df12 Productions Rust codebases. This issue tracks adding generative coverage for three invariants introduced or extended by PR `#315`.
## Background
PR `#315` (lower manifest target and action \`deps\` into an explicit implicit-dependency class in the IR and generated Ninja output) introduced new failure modes in cycle detection (traversing \`implicit_deps\` as well as \`inputs\`), a new Ninja separator ordering contract (\`inputs\` → \`| implicit_deps\` → \`|| order_only_deps\`), and extended command interpolation with new placeholder tokens. These invariants are currently covered only by hand-written example-based tests; generative coverage is absent.
## Work required
1. **Add \`proptest\` dev-dependency** to \`Cargo.toml\`.
2. **Cycle detection** — write property tests asserting:
- A graph with no back-edges never produces a cycle regardless of node count or edge ordering.
- Any graph with a back-edge always produces a cycle.
- Missing-dependency records are a subset of edges whose targets are absent from the target map.
- Results are stable across arbitrary \`HashMap\` insertion orderings.
3. **Ninja separator ordering** — write property tests asserting:
- For any \`BuildEdge\` with non-empty \`inputs\`, \`implicit_deps\`, and \`order_only_deps\`, the emitted line always places \`|\` after explicit inputs and before \`||\`.
- The separator is absent when \`implicit_deps\` is empty.
4. **Command interpolation** — write property tests asserting:
- \`\$in\`/\`\$out\` tokens inside backtick-delimited regions are never substituted.
- \`__NETSUKE_INS_PLACEHOLDER__\`/\`__NETSUKE_OUTS_PLACEHOLDER__\` outside backticks are always replaced.
- Tokens inside backticks are always preserved verbatim.
## References
- PR `#315`: https://github.com/leynos/netsuke/pull/315
- Raised by `@leynos`
"Length of output: 2212 🏁 Script executed: #!/bin/bash
gh issue list --repo leynos/netsuke --limit 5 --json number,title,url | jq -r '.[] | "\(.number) \(.url) \(.title)"'Length of output: 784
It covers:
✏️ Learnings added
|
Expand the ninja generation test module docs to name the production module and IR type under test. Emit structured info events for unresolved dependencies during cycle detection so missing external-file assumptions are visible on the successful path.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/ninja_gen_tests.rs (1)
1-547:⚠️ Potential issue | 🟠 Major | ⚖️ Poor tradeoffDecompose test module to satisfy file-length limit.
This file has 547 lines, violating the coding guideline that files must not exceed 400 lines. As per coding guidelines, Python functions should use snake_case.
Split the module by test category:
- Move unit generation tests (
generate_ninja_scenarios,generate_empty_graph,generate_multiline_script_snapshot) intotests/ninja_gen_unit_tests.rs.- Keep integration tests (
ninja_integration_tests) and error-path tests in this file, renaming totests/ninja_gen_integration_tests.rs.- Extract shared fixtures (
ninja_integration_setup,NinjaIntegrationCase,AssertionType) into atest_support::ninja_genmodule if not already present.As per coding guidelines, files must not exceed 400 lines; large modules must be decomposed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/ninja_gen_tests.rs` around lines 1 - 547, This test module exceeds the 400-line limit; split it by moving unit-focused tests (generate_ninja_scenarios, generate_empty_graph, generate_multiline_script_snapshot) into a new unit test file and keep integration/error tests (ninja_integration_tests, errors_when_action_missing, generate_format_error) in a separate integration test file; extract and reuse the shared setup and types (ninja_integration_setup, NinjaIntegrationCase, AssertionType) into a shared test_support::ninja_gen module so both new files can import them, and ensure each resulting Rust test file remains under 400 lines.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@tests/ninja_gen_tests.rs`:
- Around line 1-547: This test module exceeds the 400-line limit; split it by
moving unit-focused tests (generate_ninja_scenarios, generate_empty_graph,
generate_multiline_script_snapshot) into a new unit test file and keep
integration/error tests (ninja_integration_tests, errors_when_action_missing,
generate_format_error) in a separate integration test file; extract and reuse
the shared setup and types (ninja_integration_setup, NinjaIntegrationCase,
AssertionType) into a shared test_support::ninja_gen module so both new files
can import them, and ensure each resulting Rust test file remains under 400
lines.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 70d335c7-a1de-4277-90cd-4fe480b80cf4
📒 Files selected for processing (2)
src/ir/from_manifest.rstests/ninja_gen_tests.rs
Move pure Ninja rendering coverage into a dedicated unit test module and leave integration/error-path coverage in a smaller integration module. Extract the shared Ninja integration case types and setup helper into `test_support::ninja_gen` so the split modules stay below the file-size limit while preserving the existing scenarios and snapshot coverage.
Replace the duplicated missing-dependency test bodies with one `rstest` table that feeds shared data into `assert_missing_deps`. Keep CycleDetector setup and missing-dependency assertions in the helper.
Clarify that generated Ninja files are written by runner and manifest subcommands for downstream execution by the Ninja build system.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@test_support/src/ninja_gen.rs`:
- Around line 1-2: Update the module doc comment at the top of
test_support/src/ninja_gen.rs to expand purpose, utility and relationships:
describe the module as "Shared fixtures and case types for Ninja generation
tests", list and briefly explain the exported items (`AssertionType`,
`NinjaIntegrationCase`, `ninja_integration_setup`), state how they integrate
with rstest (e.g., use with #[case::...] parameterisation) and with
test_support::ninja::ninja_integration_workspace for conditional Ninja
availability, and add a short usage pattern or example showing typical test flow
(construct a `NinjaIntegrationCase`, use `ninja_integration_setup` fixture, run
ninja and assert via `AssertionType`); ensure the docstring replaces the
existing one-line comment and covers purpose, utility, relationships and a
typical usage snippet.
In `@tests/ninja_gen_unit_tests.rs`:
- Around line 209-212: Replace assertions that use ensure! comparing generated
manifests with expected values (e.g., ensure!(ninja == expected, "generated
ninja manifest did not match expectation")) with assert_eq! so failures show
diffs; specifically change the ensure! that compares the variables ninja and
expected to assert_eq!(ninja, expected) (you may keep the optional message as a
third argument if desired) and apply the same replacement to the other ensure!
usages in this test file that validate generated output (the occurrences noted
around the other assertions).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: fa9f242a-cfe2-44e5-ad88-095e059496c6
⛔ Files ignored due to path filters (1)
tests/snapshots/ninja/ninja_gen_unit_tests__multiline_script_ninja.snapis excluded by!**/*.snap
📒 Files selected for processing (6)
src/ir/cycle.rssrc/ninja_gen.rstest_support/src/lib.rstest_support/src/ninja_gen.rstests/ninja_gen_integration_tests.rstests/ninja_gen_unit_tests.rs
Document the exported Ninja generation test helpers, their relationship to `rstest` parameterisation, and conditional Ninja workspace setup. Use assertions for generated Ninja output checks so failed comparisons show clearer diagnostics while keeping fallible generation errors explicit.
|
@coderabbitai Have the following failed checks now been resolved? If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures. Do not treat warnings as optional or aspirational. Where a change is out of scope for this PR, propose a GitHub issue unless one exists already. ❌ Failed checks (2 errors, 3 warnings)
|
This comment was marked as resolved.
This comment was marked as resolved.
Keep cycle analysis side-effect-free by removing logging from the missing-dependency recorder and documenting that callers own observation. Add caller-side summary and implicit dependency count events so IR lowering remains observable without double-logging missing dependencies.
Summary
This branch implements roadmap task (3.14.3) by lowering target and action
depsinto a dedicated implicit-dependency class in the IR and generated Ninja output. It keepssourcesas the explicit recipe-input class used by$inand{{ ins }}, whiledepsnow affect dependency ordering, rebuild decisions, and cycle detection without appearing in recipe arguments.Roadmap task: (3.14.3)
Execplan: docs/execplans/3-14-3-lower-target-and-action-deps.md
Review walkthrough
BuildEdge.implicit_depsfield and manifest lowering fromtarget.deps.| <implicit_deps>rendering.{{ ins }}/{{ outs }}placeholder preservation needed by the documented recipe contract.Validation
cargo test --workspace: passed after the IR field addition.cargo test --test ir_from_manifest_tests: passed with 15 tests after manifest lowering.cargo test -p netsuke ir::cycle: passed after implicit-dependency cycle traversal.cargo test --test ninja_gen_tests: passed after Ninja emission updates.cargo test --test bdd_tests implicit: passed after behavioural coverage was added.make check-fmt: passed in the final gate.make lint: passed in the final gate.make test: passed in the final gate.make markdownlint: passed in the final gate.make nixie: passed in the final gate.coderabbit review --agent: completed with zero findings.Notes
make fmtstill triggers a pre-existing repository-wide Markdown formatting backlog and rewrites unrelated documentation before failing. This branch restored that unrelated churn and used the non-mutating gates above as the applicable completion checks.No new external crate dependencies were added. The planned
proptestcoverage was replaced with deterministic bounded cycle coverage becauseproptestis not currently in the dependency graph and the execplan requires explicit approval before adding dependencies.Summary by Sourcery
Lower manifest target and action
depsinto a dedicated implicit-dependency class in the IR and generated Ninja output, aligning cycle detection, recipe interpolation, tests, and documentation with the intended dependency semantics.New Features:
implicit_depson IR build edges to represent manifestdepsseparately from explicitsourcesinputs.depsfor both targets and actions as implicit dependencies that appear in generated Ninja files using Ninja's|syntax.Enhancements:
{{ ins }}and{{ outs }}placeholders through manifest rendering so recipe interpolation can expand only explicit sources and outputs.Tests:
depspopulate implicit dependencies and do not affect explicit recipe inputs.