Skip to content

Support serial dependency ordering for actions and targets (#552) - #557

Open
lodyai[bot] wants to merge 40 commits into
mainfrom
issue-552-support-serial-dependency-ordering-for-actions-and-targets
Open

Support serial dependency ordering for actions and targets (#552)#557
lodyai[bot] wants to merge 40 commits into
mainfrom
issue-552-support-serial-dependency-ordering-for-actions-and-targets

Conversation

@lodyai

@lodyai lodyai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements the approved staged-Ninja-dyndep design for issue #552. Actions and
targets can declare dependency_order: serial while preserving one Ninja
scheduler, shared-work reuse, failure short-circuiting, and unrelated-branch
concurrency.

Closes #552.

User documentation

  • Documents dependency_order: parallel | serial for actions and targets in
    the users' guide, with a complete executable manifest.
  • Defines the serial guarantee and its scope: only direct deps are ordered;
    independently reachable and unrelated work remains concurrent.
  • Documents Ninja 1.10 requirements, generated sidecars, and the reserved
    .netsuke/serial and .netsuke/dyndep namespaces.
  • Adds ADR-010 for the staged-dyndep architecture and updates the design,
    developer, repository-layout, roadmap, contents, and living ExecPlan records.

Review walkthrough

Validation

  • make check-fmt: passed.
  • make typecheck: passed.
  • make lint: passed, including Whitaker.
  • make test: passed; 1,939 tests passed, one skipped, and doctests passed.
  • make markdownlint: passed.
  • make nixie: passed.
  • coderabbit review --agent: completed with zero actionable findings.

References

@sourcery-ai

sourcery-ai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds manifest-level dependency_order support, threads it through IR to Ninja generation, and implements staged Ninja dyndep bundles plus atomic sidecar materialization so serial dependency lists run in declaration order while preserving a single Ninja scheduler and parallel behaviour for other branches.

Sequence diagram for serial dependency Ninja bundle generation and execution

sequenceDiagram
    actor User
    participant Runner as runner.generate_ninja
    participant NinjaGen as ninja_gen.generate_bundle
    participant Dyndep as process.materialize_dyndep_files
    participant Ninja

    User->>Runner: netsuke build / clean / generate
    Runner->>NinjaGen: generate_bundle(graph)
    NinjaGen-->>Runner: GeneratedNinja (build_file, dyndep_files)
    Runner->>Dyndep: materialize_dyndep_files(cli, bundle.dyndep_files())
    Dyndep-->>Runner: dyndep sidecars materialized
    Runner->>Ninja: invoke with bundle.build_file()
    Ninja-->>User: serial deps run in order, parallel elsewhere
Loading

File-Level Changes

Change Details Files
Introduce DependencyOrder on manifests and IR build edges so targets/actions can declare serial or parallel dependency ordering with a default of parallel.
  • Add DependencyOrder enum with parallel/serial to ast Target and wire serde defaults so omission means parallel
  • Thread dependency_order into ir::BuildEdge and re-export it from ir for use in generators and tests
  • Update all BuildEdge constructions in tests and fixtures to set dependency_order explicitly, usually Parallel, to keep compilation and existing behaviour intact
  • Add AST and IR tests ensuring serial/parallel parsing, defaulting, and that declaration order and dependency_order survive lowering from manifest to BuildGraph
src/ast.rs
src/ir/graph.rs
src/ir/from_manifest.rs
src/ir/mod.rs
tests/ir_from_manifest_tests.rs
tests/ast_tests.rs
tests/ast_tests/dependency_order.rs
tests/ir_tests.rs
src/graph_view/tests_support.rs
src/ir/cycle_*.rs
tests/ninja_gen_unit_tests.rs
tests/ninja_gen_integration_tests.rs
tests/ninja_gen_property_tests.rs
Refactor Ninja generation to support serial dependency ordering via staged dyndep bundles and expose a bundle API while keeping existing string-only generation for parallel graphs.
  • Split ninja_gen into a module with a new dyndep submodule and move unit tests to keep files under size limits
  • Add GeneratedNinja and GeneratedDyndep bundle types plus generate_bundle, which emits the main Ninja build file and content-addressed dyndep sidecars
  • Implement staged dyndep lowering: serial edges with multiple implicit_deps get phony gate chains and per-dependency dyndep sidecars under .netsuke/serial and .netsuke/dyndep, with ninja_required_version = 1.10 only when needed
  • Add escape_ninja_path and make join/path_key public(crate) for reuse by dyndep generation
  • Make generate/generate_into reject serial graphs by returning a DyndepFilesRequired error without writing partial output
  • Reserve .netsuke/serial and .netsuke/dyndep namespaces and surface a localized ReservedOutputPath error on collisions
  • Add unit tests for dyndep lowering, gate/sidecar structure, reserved namespace rejection, and adjust snapshots/unit tests to include dependency_order and serial behaviour
src/ninja_gen/mod.rs
src/ninja_gen/dyndep.rs
src/ninja_gen/tests.rs
src/ninja_gen_property_tests.rs
tests/ninja_gen_unit_tests.rs
tests/ninja_gen_integration_tests.rs
tests/serial_dependency_runtime_tests.rs
docs/execplans/issue-552-support-serial-dependency-ordering-for-actions-and-targets.md
Materialize dyndep sidecar files atomically in the runner using capability-based filesystem APIs and route all CLI generation/execution through the new bundle API.
  • Add runner/process/dyndep_files.rs to open the effective Ninja working directory, create .netsuke/dyndep, and atomically write/verify content-addressed sidecars via same-directory temp files and rename
  • Introduce new localized runner.io.dyndep.* messages and keys for create/read/write/rename/corrupt/race errors across all locales and register them in localization keys
  • Wire generate_ninja to use ninja_gen::generate_bundle, call materialize_dyndep_files, and pass only the main build file to NinjaContent
  • Expose materialize_dyndep_files from runner::process and update tests to cover serial bundle generation and sidecar materialization behaviour
  • Ensure sidecar materialization is idempotent and treats mismatched existing content as corruption with guidance to delete only the offending file
src/runner/mod.rs
src/runner/process/mod.rs
src/runner/process/dyndep_files.rs
src/localization/keys.rs
locales/*/messages.ftl
tests/serial_dependency_runtime_tests.rs

Assessment against linked issues

Issue Objective Addressed Explanation
#552 Implement manifest, IR, and Ninja generation support for dependency_order: serial on actions and targets, preserving declaration order in execution, stopping on failure, reusing shared dependencies, and keeping the default parallel behaviour and serialization scoped to the annotated deps list.
#552 Add regression coverage for serial dependency behaviour, including ordering, shared dependencies, failure short-circuiting, and unchanged default parallel behaviour.
#552 Document the new action and target syntax (dependency_order) and its execution semantics for users. The PR adds an internal ExecPlan document and code-level comments but does not update the user-facing guides or syntax documentation requested in the issue’s acceptance criteria. RESOLVED

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

codescene-access[bot]

This comment was marked as outdated.

@lodyai
lodyai Bot force-pushed the issue-552-support-serial-dependency-ordering-for-actions-and-targets branch from e1cef57 to 7ed4cc8 Compare August 11, 2026 21:48
codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 11, 2026

Copy link
Copy Markdown
Owner

@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.

src/runner/process/dyndep_files.rs

Comment on lines +114 to +163

fn write_atomic(dir: &Dir, rel: &Utf8Path, content: &str) -> Result<()> {
    let temp = unique_temp_name(rel);
    let mut options = OpenOptions::new();
    options.write(true).create_new(true);
    let mut file = match dir.open_with(&temp, &options) {
        Ok(file) => file,
        Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {
            // Another process won the race for our temporary name; verify the
            // final path and treat matching content as success.
            return match read_verified(dir, rel, content)? {
                ReadOutcome::Matching => Ok(()),
                ReadOutcome::Mismatch => Err(anyhow!(
                    localization::message(keys::RUNNER_IO_DYNDEP_CORRUPT)
                        .with_arg("path", rel.as_str())
                )),
                ReadOutcome::Missing => Err(anyhow!(
                    localization::message(keys::RUNNER_IO_DYNDEP_RACE)
                        .with_arg("path", rel.as_str())
                )),
            };
        }
        Err(err) => {
            return Err(err).with_context(|| {
                localization::message(keys::RUNNER_IO_DYNDEP_WRITE).with_arg("path", rel.as_str())
            });
        }
    };
    file.write_all(content.as_bytes()).with_context(|| {
        localization::message(keys::RUNNER_IO_DYNDEP_WRITE).with_arg("path", rel.as_str())
    })?;
    file.flush().with_context(|| {
        localization::message(keys::RUNNER_IO_DYNDEP_WRITE).with_arg("path", rel.as_str())
    })?;
    file.sync_all().with_context(|| {
        localization::message(keys::RUNNER_IO_DYNDEP_WRITE).with_arg("path", rel.as_str())
    })?;
    // Rename is relative to the same directory; `rename` replaces an existing
    // destination, so if another process already wrote the final file, the
    // atomic replace yields content identical to ours.
    if let Err(err) = dir.rename(&temp, dir, rel) {
        // The final file may have appeared via a concurrent writer; verify it.
        if read_verified(dir, rel, content)? != ReadOutcome::Matching {
            return Err(err).with_context(|| {
                localization::message(keys::RUNNER_IO_DYNDEP_RENAME).with_arg("path", rel.as_str())
            });
        }
        drop(dir.remove_file(&temp));
    }
    Ok(())
}

❌ New issue: Bumpy Road Ahead
write_atomic has 2 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is 2 blocks per function

@leynos

leynos commented Aug 11, 2026

Copy link
Copy Markdown
Owner

@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.

src/ninja_gen/dyndep_tests.rs

Comment on lines +123 to +135

fn parallel_edges_produce_no_sidecars() -> Result<()> {
    let graph = graph_with_edge(parallel_edge("all", &["dep1", "dep2"]))?;
    let bundle = generate_bundle(&graph)?;
    ensure!(
        !bundle.build_file().contains("ninja_required_version"),
        "parallel bundle must not emit a version floor"
    );
    ensure!(
        bundle.dyndep_files().is_empty(),
        "parallel graph must produce no sidecars"
    );
    Ok(())
}

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: one_element_serial_list_needs_no_gates,parallel_edges_produce_no_sidecars

@leynos

leynos commented Aug 11, 2026

Copy link
Copy Markdown
Owner

@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.

src/ninja_gen/dyndep.rs

Comment on lines +156 to +230

pub fn generate_bundle(graph: &BuildGraph) -> Result<GeneratedNinja, NinjaGenError> {
    reject_reserved_paths(graph)?;
    let serial_present = graph_requires_dyndep(graph);

    let mut out = String::new();
    if serial_present {
        writeln!(out, "ninja_required_version = 1.10\n")?;
    }

    let mut actions: Vec<_> = graph.actions.iter().collect();
    actions.sort_by_key(|(id, _)| *id);
    for (id, action) in actions {
        use crate::ninja_gen::NamedAction;
        writeln!(out, "{}", NamedAction { id, action })?;
    }

    let mut edges: Vec<_> = graph.targets.values().collect();
    edges.sort_by_key(|a| path_key(&a.explicit_outputs));
    let mut seen: HashSet<String> = HashSet::new();
    let mut stages = SerialStages::default();

    for edge in edges {
        let key = path_key(&edge.explicit_outputs);
        if !seen.insert(key.clone()) {
            continue;
        }
        let action =
            graph
                .actions
                .get(&edge.action_id)
                .ok_or_else(|| NinjaGenError::MissingAction {
                    id: edge.action_id.clone(),
                    message: localization::message(keys::NINJA_GEN_MISSING_ACTION)
                        .with_arg("id", &edge.action_id),
                })?;

        let requires_gates =
            edge.dependency_order == DependencyOrder::Serial && edge.implicit_deps.len() > 1;
        if requires_gates {
            let mut added = Vec::new();
            render_serial_block(edge, &mut out, &mut stages, &mut added)?;
            let mut aggregate = edge.clone();
            aggregate.implicit_deps = added;
            aggregate.dependency_order = DependencyOrder::Parallel;
            writeln!(
                out,
                "{}",
                crate::ninja_gen::DisplayEdge {
                    edge: &aggregate,
                    action_restat: action.restat,
                }
            )?;
        } else {
            writeln!(
                out,
                "{}",
                crate::ninja_gen::DisplayEdge {
                    edge,
                    action_restat: action.restat,
                }
            )?;
        }
    }

    if !graph.default_targets.is_empty() {
        let mut defs = graph.default_targets.clone();
        defs.sort();
        writeln!(out, "default {}", join(&defs))?;
    }

    Ok(GeneratedNinja {
        build_file: out,
        dyndep_files: stages.dyndep_files,
    })
}

❌ New issue: Complex Method
generate_bundle has a cyclomatic complexity of 9, threshold = 9

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@leynos
leynos marked this pull request as ready for review August 11, 2026 21:58

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry @leynos, your pull request is larger than the review limit of 150000 diff characters

chatgpt-codex-connector[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Summary

  • Add dependency_order: serial for actions and targets.
  • Preserve declaration order for direct serial dependencies.
  • Stop later dependencies when an earlier dependency fails.
  • Reuse shared work once per build.
  • Preserve parallel scheduling for omitted or parallel configurations.
  • Limit serialisation to the annotated graph edge.

Implementation

  • Add manifest and IR support for DependencyOrder.
  • Lower serial dependencies into staged Ninja phony gates and content-addressed dyndep sidecars.
  • Add generate_bundle with deterministic Ninja and sidecar output.
  • Materialise sidecars atomically under .netsuke/dyndep.
  • Bound sidecar verification and handle corruption, races, collisions, and oversized files.
  • Keep generation pure and place telemetry at runner boundaries.
  • Validate Ninja paths and reserved generated-state namespaces.
  • Add localized diagnostics for new runner and Ninja generator errors.

Tests and documentation

  • Add manifest, IR, property, unit, integration, CLI, and runtime coverage.
  • Verify ordering, failure short-circuiting, shared-work reuse, unrelated-branch concurrency, sidecar publication, and Ninja compatibility.
  • Add ADR-011.
  • Add the completed issue #552 ExecPlan.
  • Update the user guide, developer guide, design documentation, migration guide, roadmap, and repository layout.

Walkthrough

This change adds opt-in serial dependency ordering for actions and targets. It propagates dependency_order through the manifest and IR, lowers serial edges into Ninja dyndep bundles, atomically materialises sidecars, integrates CLI flows, adds runtime coverage, and documents and localises the new behaviour.

Changes

Serial dependency ordering

Layer / File(s) Summary
Dependency-order contract and IR propagation
src/ast.rs, src/ir/..., tests/ast_tests/..., tests/ir_from_manifest_tests/...
Adds parallel and serial dependency-order values. The default remains parallel. The selected value propagates into BuildEdge.
Ninja bundle generation and path validation
src/ninja_gen/..., tests/ninja_gen_*
Generates ordered phony gates and content-addressed dyndep sidecars for serial edges. Validates paths and preserves direct string-generation behaviour for graphs that need no sidecars.
Runner publication and command integration
src/runner/...
Publishes sidecars beside the effective Ninja working directory before Ninja runs. Build, generate, tool, and clean flows use the generated bundle.
Generator, publication, and runtime validation
tests/serial_dependency_*, src/runner/process/*_tests.rs
Tests declaration order, failure short-circuiting, shared-work reuse, unrelated-branch concurrency, atomic publication, corruption handling, collision handling, CLI generation, and clean behaviour.
Documentation, diagnostics, and repository support
docs/..., locales/*/messages.ftl, .gitignore
Adds ADR-011, user and developer guidance, migration notes, repository-layout updates, localised diagnostics, and the .vtcode/ ignore rule.

Suggested labels: Roadmap, Issue

Suggested reviewers: leynos

Poem

Gates line up in Ninja’s hall,
Sidecars bloom when dependencies call.
Failures halt the ordered train,
Shared work runs once again.
Parallel branches keep their pace—
Serial paths now know their place.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Rust Compiler Lint Integrity ❌ Error The new dyndep renderer adds seen.insert(key.clone()), but key is unused after insertion; the other added clones have clear ownership or test-snapshot purposes. Replace seen.insert(key.clone()) with seen.insert(key) in src/ninja_gen/dyndep.rs; retain clones only where two owners or an owned diagnostic is required.
Performance And Resource Use ⚠️ Warning Flag unbounded disk growth: each changed sidecar content creates a new .netsuke/dyndep/<digest>.dd, while build, generate, and clean never evict old files. Add bounded retention or a total-size/file-count limit for .netsuke/dyndep; prune safely and test repeated manifest changes and clean operations.
Developer Documentation ❓ Inconclusive Investigation in progress; no final assessment yet. Await documentation and diff verification.
Testing (Compile-Time / Ui) ❓ Inconclusive Investigation is still in progress; no verdict has been submitted yet. Continue repository and diff inspection before deciding.
✅ Passed checks (16 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the serial dependency ordering implementation and includes the linked issue number (#552).
Description check ✅ Passed The description directly covers the implementation, scope, documentation, tests, and validation for serial dependency ordering.
Linked Issues check ✅ Passed The implementation satisfies issue #552 through manifest and IR support, ordered execution, failure short-circuiting, shared-work reuse, scoped serialisation, and regression tests.
Out of Scope Changes check ✅ Passed The changes support issue #552 through implementation, tests, diagnostics, documentation, architecture records, and related repository updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Testing (Overall) ✅ Passed Keep this check passing: manifest/IR, property, generator, materialisation, real-Ninja, and CLI tests assert order, failures, reuse, concurrency, escaping, and sidecar publication.
User-Facing Documentation ✅ Passed The users' guide adds tested YAML for actions and targets, documents defaults, order, failure, scope, Ninja 1.10, sidecars, and reserved paths; the migration guide signposts the opt-in.
Module-Level Documentation ✅ Passed Changed Rust modules carry module-level //! documentation describing purpose; new generator, runner, process, and test modules also state their role and boundaries.
Testing (Unit And Behavioural) ✅ Passed Pass testing: unit and property tests cover staging, defaults, escaping, corruption, races, limits and determinism; real-Ninja runtime and CLI tests verify order, failure stopping, reuse and sideca...
Testing (Property / Proof) ✅ Passed Substantive Rust proptest coverage exists: 128 generated cases exercise serial list thresholds, declaration order, repeated dependencies, and deterministic bundle output.
Unit Architecture ✅ Passed generate_bundle only builds an immutable GeneratedNinja and returns explicit errors; materialize_dyndep_bundle owns writes through an injected Dir, with focused atomic-publication tests.
Domain Architecture ✅ Passed The diff keeps DependencyOrder in the manifest/IR, pure Ninja lowering in ninja_gen, and filesystem plus telemetry publication in runner; no domain-to-infrastructure dependency was introduced.
Observability ✅ Passed Pass: generation and sidecar publication use trace spans, bounded outcome counters, and duration histograms; fixed error categories and no paths or content enter telemetry.
Security And Privacy ✅ Passed Findings show no secrets or credentials; manifest order is a closed enum, Ninja paths are escaped and control-validated, sidecars use scoped atomic writes, and telemetry excludes paths and content.
Concurrency And State ✅ Passed Pass the check: keep staging state local, publish sidecars with create_new, sync_all and atomic rename, and cover ordering, failure, shared work, parallel branches and race cases in tests.
Architectural Complexity And Maintainability ✅ Passed Keep the change: bundle generation, capability-scoped publication, atomic persistence, and telemetry isolate real seams, stay under 400 lines, reuse existing dependencies, and have immediate tests...
📋 Issue Planner

Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).

View plan for ticket: #552

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-552-support-serial-dependency-ordering-for-actions-and-targets

Comment @coderabbitai help to get the list of available commands.

@leynos
leynos force-pushed the issue-552-support-serial-dependency-ordering-for-actions-and-targets branch from 9cac0aa to a576350 Compare August 14, 2026 13:47
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@leynos

leynos commented Aug 14, 2026

Copy link
Copy Markdown
Owner

@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 Duplication

src/runner/process/dyndep_files.rs:

What lead to degradation?

The module contains 2 functions with similar structure: create_temp_file,open_existing_sidecar

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
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@leynos

leynos commented Aug 14, 2026

Copy link
Copy Markdown
Owner

@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.

String Heavy Function Arguments

src/runner/process/dyndep_files_tests.rs:

What lead to degradation?

In this module, 46.2% of all arguments to its 21 functions are strings. The threshold for string arguments is 39.0%

Why does this problem occur?

String is a generic type that fail to capture the constraints of the domain object it represents. In this module, 46 % of all function arguments are string types.

How to fix it?

Heavy string usage indicates a missing domain language. Introduce data types that encapsulate the semantics. For example, a user_name is better represented as a constrained User type rather than a pure string, which could be anything.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@leynos

leynos commented Aug 14, 2026

Copy link
Copy Markdown
Owner

@coderabbitai please stop whining about changes on main:

Out of Scope Changes check ⚠️ Warning The .vtcode/ ignore entry and Whitaker Makefile change are not tied to issue #552 and appear unrelated to serial dependency ordering. Remove or justify the .vtcode/ ignore entry and the unrelated Whitaker configuration change before merging.

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '=== Current branch and remotes ==='
git status --short
git branch --show-current
git remote -v | head -n 4

printf '%s\n' '=== PR metadata ==='
gh pr view 557 --repo leynos/netsuke --json baseRefName,headRefName,baseRefOid,headRefOid,url \
  --jq '{url, baseRefName, headRefName, baseRefOid, headRefOid}'

base_ref=$(gh pr view 557 --repo leynos/netsuke --json baseRefName --jq '.baseRefName')
printf '\n=== Diff against origin/%s for warned files ===\n' "$base_ref"
git diff --no-ext-diff -- .gitignore Makefile "origin/$base_ref"...HEAD || true

printf '\n=== .vtcode and DYLINT_TOML provenance ===\n'
git log -n 5 --oneline -- .gitignore Makefile
rg -n -C2 '(^\.vtcode/$|DYLINT_TOML|lint-whitaker)' .gitignore Makefile || true

printf '\n=== Values on origin/%s ===\n' "$base_ref"
git show "origin/$base_ref:.gitignore" 2>/dev/null | rg -n '^\.vtcode/$' || true
git show "origin/$base_ref:Makefile" 2>/dev/null | rg -n -C2 '(DYLINT_TOML|lint-whitaker)' || true

Length of output: 5142


@leynos The warning was incorrect.

PR #557 has no diff for .gitignore or Makefile against main. Both .vtcode/ and the DYLINT_TOML configuration already exist on the PR base. Do not remove or justify them in this PR.

🐇


✏️ Learnings added
Learnt from: leynos
URL: https://github.com/leynos/netsuke/pull/557

Timestamp: 2026-08-14T18:28:05.586Z
Learning: For pull requests in `leynos/netsuke`, assess Out of Scope Changes only from the diff against the PR base branch. Do not flag files or changes that already exist on `main`, including `.vtcode/` in `.gitignore` and the `DYLINT_TOML` configuration in `Makefile`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

Repository owner deleted a comment from coderabbitai Bot Aug 14, 2026
Repository owner deleted a comment from coderabbitai Bot Aug 14, 2026
leynos added 2 commits August 14, 2026 20:31
Align the design sequence diagram with the runner capability-scoped publication contract and record the verified review finding in the issue plan.
Delete the unused `RUNNER_IO_DYNDEP_RACE` key and its catalogue entries.
Concurrent publication now reports only errors backed by reachable runtime
paths, while verified matching and mismatch outcomes remain unchanged.
codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

leynos added 4 commits August 15, 2026 00:52
Describe reserved graph namespaces across every user path field and clarify when dyndep sidecars are materialized by each CLI command. Record the verified documentation review and leave the already-correct design gate wording unchanged.
Move the computed edge key into deduplication directly and retain the
documented compatibility boundary for content-addressed sidecars.
Keep the serial dyndep migration guidance compliant with the repository
documentation spelling policy.
codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No quality gates enabled for this code.

@leynos

leynos commented Aug 14, 2026

Copy link
Copy Markdown
Owner

@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. (Treat o11y, code safety, documentation and validation coverage as in scope).

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Rust Compiler Lint Integrity ❌ Error The new dyndep renderer adds seen.insert(key.clone()), but key is unused after insertion; the other added clones have clear ownership or test-snapshot purposes. Replace seen.insert(key.clone()) with seen.insert(key) in src/ninja_gen/dyndep.rs; retain clones only where two owners or an owned diagnostic is required.
Performance And Resource Use ⚠️ Warning Flag unbounded disk growth: each changed sidecar content creates a new .netsuke/dyndep/<digest>.dd, while build, generate, and clean never evict old files. Add bounded retention or a total-size/file-count limit for .netsuke/dyndep; prune safely and test repeated manifest changes and clean operations.

@coderabbitai

This comment was marked as resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support serial dependency ordering for actions and targets

4 participants