Skip to content

Phase 4: expand tests, tooling, docs, and IPC testing - #45

Merged
leynos merged 18 commits into
mainfrom
terragon/phase4-stabilisation-testing-docs-aem45j
Dec 8, 2025
Merged

Phase 4: expand tests, tooling, docs, and IPC testing#45
leynos merged 18 commits into
mainfrom
terragon/phase4-stabilisation-testing-docs-aem45j

Conversation

@leynos

@leynos leynos commented Dec 4, 2025

Copy link
Copy Markdown
Owner

Summary

  • This work expands Phase 4 testing, tooling, and documentation to provide a robust, observable baseline with high coverage and deterministic IPC testing.

Changes

  • Documentation
    • Updated docs for Phase 4 testing: lading-design.md, roadmap.md, and usage-guide.md to reflect new testing approach, coverage goals, and IPC/mox testing patterns.
    • Clarified publish pre-flight and cargo metadata IPC paths in docs.
  • Testing and coverage
    • Introduced pytest-cov as a development dependency to enable coverage reporting via uv run pytest --cov.
    • Expanded test suite with multiple new unit tests across modules:
      • tests/unit/publish/test_publish_diagnostics.py
      • tests/unit/publish/test_publish_execution_helpers.py
      • tests/unit/publish/test_publish_manifest_strategies.py
      • tests/unit/test_command_shared.py
      • tests/unit/test_config.py
      • tests/unit/test_toml_utils.py
      • tests/unit/test_workspace_metadata.py
      • tests/unit/test_workspace_models_validation.py
    • Emphasized Phase 4 testing focus areas: configuration validation, publish manifest handling, cmd-mox IPC, and workspace model error paths.
    • Kept Cmd-mox as the default mocking mechanism for external commands; tests use stubbed IPC paths for deterministic coverage of streaming/IPC code paths.
  • Code quality and typing
    • Added pragma hints for type-checking blocks to improve coverage reporting and readability (e.g., typing helpers only markers).
  • Dependency and lock updates
    • Updated pyproject.toml to include pytest-cov in dev dependencies.
    • uv.lock updated correspondingly to reflect new dev tooling and test dependencies.

Test plan

  • Run the test suite with coverage:
    • uv run pytest --cov
    • or locally: pytest --cov
  • Ensure new tests pass and coverage for Phase 4 modules meets the >90% target noted in docs.
  • Verify docs reflect the current testing strategy and IPC/mox usage.

Why this matters

Phase 4 stabilisation relies on high-coverage, deterministic tests around configuration validation, publish manifest handling, and workspace model behavior. The added tests, tooling, and documentation provide a solid baseline for ongoing development and future improvements, while enabling visible coverage metrics and clearer expectations for operators.

📎 Task: https://www.terragonlabs.com/task/98bbccf3-4b8c-4c07-ba21-8d2555e8840f
📎 Task: https://www.terragonlabs.com/task/1210b6b1-1745-48d0-86a6-a9f821c02519

…ands

- Added comprehensive unit tests for publish diagnostics, execution helpers, manifest strategies, command shared helpers, config, toml utils, workspace metadata, and workspace models validation.
- Introduced pytest-cov to dev dependencies for coverage reporting.
- Updated documentation to reflect enhanced testing strategy.
- Improved testing coverage of error paths and IPC mechanisms in publish command implementation.
- Aim to ensure >90% line coverage for new modules and maintain robustness.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Dec 4, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Summary by CodeRabbit

  • New Features

    • Added allow_dirty flag support to the publish command for more flexible publishing workflows.
  • Documentation

    • Expanded and clarified publish workflow documentation including staging, artifact handling, and pre-flight behaviour.
    • Marked test coverage achievement as complete in the roadmap.
  • Tests

    • Added comprehensive test coverage for publish diagnostics, manifest strategies, execution helpers, configuration validation, and workspace models.
    • Added pytest-cov to development dependencies for enhanced test coverage measurement.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Add pytest-cov and many unit/BDD tests; annotate TYPE_CHECKING blocks with # pragma: no cover; document publish staging and strip_patches semantics; introduce internal _PublishExecutionOptions(live, allow_dirty) and thread allow_dirty through packaging and publish flows; update BDD stubs and test expectations.

Changes

Cohort / File(s) Summary
Documentation Updates
docs/lading-design.md, docs/usage-guide.md, docs/roadmap.md
Reorder and renumber publish workflow steps; clarify staging workflow, strip_patches semantics and preserve_symlinks; propagate README in staged workspace; add Phase 4 testing notes and mark coverage tasks complete.
Publish command & runtime options
lading/commands/publish.py
Add frozen dataclass _PublishExecutionOptions(live: bool, allow_dirty: bool); accept options in _package_publishable_crates and _publish_crates; derive and propagate --allow-dirty into cargo package/publish invocations; update run to construct and pass options.
BDD stubs & preflight normalisation
tests/bdd/steps/test_publish_infrastructure.py
Add _PreflightStubConfig.allow_dirty and thread it through stub creation and command normalisation; normalise cargo package/publish forms to insert/strip --allow-dirty; add CMD_MOX_STUB env helper; update test expectations.
TYPE_CHECKING pragma annotations
lading/commands/_shared.py, lading/commands/publish_manifest.py, lading/config.py, lading/testing/toml_utils.py, lading/utils/process.py, lading/workspace/metadata.py
Add # pragma: no cover to if TYPE_CHECKING: blocks to exclude typing-only imports from coverage metrics; no runtime behaviour changes.
Development configuration
pyproject.toml
Add pytest-cov to dev-dependencies for coverage reporting.
New unit tests — publish & helpers
tests/unit/publish/test_publish_diagnostics.py, tests/unit/publish/test_publish_execution_helpers.py, tests/unit/publish/test_publish_manifest_strategies.py, tests/unit/publish/test_packaging.py
Add tests for diagnostics (artifact tails, deduplication), execution helpers (env merging, cmd-mox IPC, subprocess invocation, buffering, redaction), manifest strip_patches strategies, and packaging/publish flows asserting --allow-dirty propagation.
New unit tests — config & core helpers
tests/unit/test_config.py, tests/unit/test_toml_utils.py, tests/unit/test_command_shared.py
Add tests for PreflightConfig normalisation/validation, TOML utility helpers, and command pluralisation helpers.
New unit tests — workspace
tests/unit/test_workspace_metadata.py, tests/unit/test_workspace_models_validation.py
Add tests covering cmd-mox IPC, timeouts, environment construction, workspace models validation (dependencies, paths, publish/readme flags) and related error paths.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User
  participant CLI as lading CLI
  participant Publish as publish module
  participant Preflight as Preflight / CmdMox
  participant Cargo as cargo subprocess

  Note over User,CLI: User invokes publish command
  User->>CLI: run publish
  CLI->>Publish: build PublishPlan & PublishPreparation
  CLI->>Publish: construct _PublishExecutionOptions(live, allow_dirty)
  Publish->>Preflight: execute preflight (normalise commands, pass allow_dirty)
  Preflight-->>Publish: preflight results (may mutate env via cmd-mox)
  Publish->>Cargo: cargo package (args include --allow-dirty if set)
  Cargo-->>Publish: package result
  Publish->>Cargo: cargo publish (include --allow-dirty; add --dry-run when not live)
  Cargo-->>Publish: publish result
  Publish-->>CLI: report outcomes
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect lading/commands/publish.py to confirm _PublishExecutionOptions construction and consistent propagation of --allow-dirty to both packaging and publishing.
  • Verify BDD preflight normalisation and CMD_MOX_STUB env helper in tests/bdd/steps/test_publish_infrastructure.py.
  • Review tests/unit/publish/test_publish_execution_helpers.py for fragile mocking assumptions around cmd-mox IPC.
  • Spot-check documentation updates for consistent strip_patches, staging behaviour and preserve_symlinks descriptions.

Possibly related PRs

Poem

✨ Reorder docs and tweak the test report,
Pragmas hide the typing-only import,
Thread options through where cargo flags abide,
Allow-dirty now rides the package and publish tide,
Tests bloom wide so staging steps can stride.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main changeset: expanding Phase 4 testing infrastructure, tooling support, documentation, and IPC testing.
Description check ✅ Passed The description comprehensively covers the changeset scope, including documentation updates, test additions, tooling changes, and the rationale for Phase 4 stabilisation.
Docstring Coverage ✅ Passed Docstring coverage is 84.47% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch terragon/phase4-stabilisation-testing-docs-aem45j

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ecbb2b and 66b699f.

📒 Files selected for processing (1)
  • tests/bdd/steps/test_publish_infrastructure.py (6 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/bdd/steps/test_publish_infrastructure.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/bdd/steps/test_publish_infrastructure.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/bdd/steps/test_publish_infrastructure.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/bdd/steps/test_publish_infrastructure.py
🧬 Code graph analysis (1)
tests/bdd/steps/test_publish_infrastructure.py (1)
tests/bdd/steps/test_publish_fixtures.py (2)
  • preflight_overrides (15-17)
  • preflight_recorder (21-23)
🔍 Remote MCP Deepwiki

Summary of additional facts relevant to reviewing this PR

  • Docs/wiki present authoritative descriptions of publish and preflight behavior, staging, and config fields (strip_patches, publish.order, publish.exclude, preflight.test_exclude, unit_tests_only). Use these to verify docs ↔ code consistency.

  • publish command: run() constructs PublishOptions and now uses an internal _PublishExecutionOptions to carry live/allow_dirty; packaging/publish helpers accept options and add --allow-dirty to cargo args. Verify all call sites match new signature and tests updated accordingly.

  • Preflight behavior and cmd-mox stubbing:

    • Preflight runs git status, cargo check, cargo test; --allow-dirty skips git check. Ensure allow_dirty is threaded into preflight as PR intends.
    • Tests/BDD rely on cmd-mox stubs when LADING_USE_CMD_MOX_STUB is set; CMOX_IPC_SOCKET must be provided in CI to run BDDs. Confirm CI changes/add docs to install/run cmd-mox and set socket.
  • Staging behavior:

    • prepare_workspace validates build directory not inside workspace, preserves symlinks by default, propagates workspace README to crates with readme.workspace = true. Confirm PR docs & tests reflect these invariants.
  • Configuration system and validation:

    • strip_patches accepts "all", "per-crate", or false; publish.order must mention all publishable crates or planner raises PublishPlanError. Verify new tests cover validation paths and that docs match behavior.
  • Testing/tooling:

    • pytest-cov was added to dev dependencies (pyproject). CI must run pytest --cov and meet coverage goals (>90% for Phase 4 modules per PR).
    • Many new unit and BDD tests added (publish diagnostics, execution helpers, manifest strategies, config, toml utils, workspace model/metadata). Review for fixture autouse (preflight disabling) and cmd-mox usage patterns.
  • Workspace discovery and models:

    • WorkspaceGraph/topological ordering and dependency-cycle errors drive publish planning—ensure tests exercising publish.order and topo sorting are present and consistent with implementation changes.

Tools/sources used

  • Repository wiki/docs content (generated pages): Deepwiki read of repo structure and full contents.,
🔇 Additional comments (6)
tests/bdd/steps/test_publish_infrastructure.py (6)

66-66: LGTM!

The allow_dirty field addition follows dataclass conventions and provides a sensible default.


77-81: LGTM!

The method correctly threads the allow_dirty parameter through to _create_stub_config, maintaining backward compatibility with the default value.


162-170: LGTM!

The signature update correctly accepts and threads the allow_dirty parameter as a keyword-only argument.


174-243: LGTM!

The refactored _register_preflight_commands correctly:

  • Threads config.allow_dirty through to cargo publish and package commands
  • Implements first-wins behaviour for multiple cargo publish overrides (lines 212-213)
  • Normalises both publish and package commands by stripping and conditionally re-adding --allow-dirty
  • Preserves the default --dry-run publish command when no override is provided

The normalization logic ensures consistent handling of the --allow-dirty flag across all cargo invocations.


254-265: LGTM!

The context manager correctly:

  • Saves the previous environment variable state
  • Sets the CMD_MOX_STUB_ENV_VAR for the duration of the with block
  • Restores the prior state in the finally block using pop-then-update

This follows the project's context manager guidelines and matches the resolved pattern from past review comments.


295-299: LGTM!

The test case correctly exercises the normalisation logic for cargo publish commands with --allow-dirty, ensuring the cmd-mox expectation resolution handles the flag appropriately.


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

@sourcery-ai

sourcery-ai Bot commented Dec 4, 2025

Copy link
Copy Markdown

Reviewer's Guide

Adds Phase 4-focused unit tests for configuration, publish execution/diagnostics/manifest strategies, workspace metadata and models; wires in pytest-cov for coverage; and updates documentation and typing pragmas to reflect the stabilized testing and IPC/cmd-mox strategy.

File-Level Changes

Change Details Files
Strengthen workspace metadata cmd-mox IPC behavior via new tests.
  • Add tests covering cmd-mox socket-required behavior, timeout parsing, environment construction, bytes-to-text coercion, and error helper constructors.
  • Add tests ensuring cmd-mox modules loading fails clearly when dependencies are missing and that command factory/selection prefer the stub when requested.
  • Add tests that exercise successful IPC command execution, validating argv, exit code/stdout/stderr, and timeout wiring.
tests/unit/test_workspace_metadata.py
Expand configuration parsing and validation test coverage.
  • Add tests for PreflightConfig.from_mapping normalising aux_build, externs, env overrides, stderr tail lines, and deduplicated excludes.
  • Add tests for configuration mapping key validation and helper functions handling string tuples/matrices, mappings, and optional mappings.
  • Add tests for integer/boolean normalisation helpers and strip_patches configuration validation semantics.
tests/unit/test_config.py
Document and codify Phase 4 testing and IPC/mox strategy updates.
  • Update design doc to describe Phase 4 testing goals, cmd-mox IPC usage, and coverage expectations; fix minor formatting issues.
  • Clarify publish behavior and strip_patches handling in the usage guide.
  • Mark the roadmap’s high test coverage task as completed.
docs/lading-design.md
docs/usage-guide.md
docs/roadmap.md
Clarify coverage intent by excluding type-checking-only branches from coverage.
  • Annotate TYPE_CHECKING blocks with pragma: no cover comments across commands, config, testing utilities, process helpers, and workspace metadata modules to keep coverage focused on runtime paths.
lading/commands/_shared.py
lading/commands/publish_manifest.py
lading/config.py
lading/testing/toml_utils.py
lading/utils/process.py
lading/workspace/metadata.py
Introduce pytest-cov to enable coverage reporting in the dev workflow.
  • Add pytest-cov to the dev dependency list in pyproject.toml so uv run pytest --cov works out of the box.
  • Refresh uv.lock to capture the new dev/testing dependency graph.
pyproject.toml
uv.lock
Add focused tests for publish execution helpers including cmd-mox passthrough handling and subprocess behavior.
  • Create cmd-mox module stubs and fixtures to exercise passthrough directives, environment preparation, path merging, and shim directory discovery.
  • Add tests for subprocess invocation error handling, stdin writing, environment normalisation, stream relaying, broken pipe-safe sink writes, environment application, buffered echoing, and redacted env logging.
tests/unit/publish/test_publish_execution_helpers.py
Add tests for publish manifest strip-patch strategies and manifest validation.
  • Add helpers to build lightweight publish plans and staged manifests for testing.
  • Test strip_patches strategies "all" and "per-crate" including no-op behavior when there are no matching crates or missing manifests.
  • Ensure invalid TOML, unknown strategies, and non-crates-io patch sections are handled with clear PublishPreparationError signaling.
tests/unit/publish/test_publish_manifest_strategies.py
Increase workspace model validation coverage.
  • Add tests for ordering dependency checks, graph construction requirements, workspace package indexing, and dependency building with missing entries.
  • Add tests for dependency mapping/kind validation, workspace target lookup, path normalisation, generic sequence/string helpers, publish setting coercion, and readme workspace flag/manifest parsing behavior.
tests/unit/test_workspace_models_validation.py
Improve diagnostics handling tests for compiletest artifacts in publish workflows.
  • Add tests ensuring compiletest stderr artifacts are discovered, tail lines are appended, missing artifacts are reported, and duplicate artifacts are deduplicated.
  • Add tests for tail-line reading behavior under zero-count and error conditions, and for formatting when artifacts have no content.
tests/unit/publish/test_publish_diagnostics.py
Backfill tests for TOML testing utilities and shared command helpers.
  • Add tests for toml_utils document loading/creation, table/array assertions, de-duplicating list append helper, and manifest-loading helpers for workspace and crates.
  • Add tests for describe_crates helper to verify singular/plural wording based on crate count.
tests/unit/test_toml_utils.py
tests/unit/test_command_shared.py

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-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Dec 4, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/unit/publish/test_publish_execution_helpers.py

Comment on lines +76 to +157

def test_handle_cmd_mox_passthrough_reports_response(
    monkeypatch: pytest.MonkeyPatch, tmp_path: Path
) -> None:
    """Passthrough directives resolved to responses should be reported back."""
    socket_path = str(tmp_path / "cmox" / "shim" / "socket")
    monkeypatch.setenv("CMOX_IPC_SOCKET", socket_path)

    class _Env:
        CMOX_IPC_SOCKET_ENV = "CMOX_IPC_SOCKET"
        CMOX_REAL_COMMAND_ENV_PREFIX = "CMOX_REAL_"

    class _IPC:
        class Response:
            def __init__(
                self, stdout: str = "", stderr: str = "", exit_code: int = 0
            ) -> None:
                self.stdout = stdout
                self.stderr = stderr
                self.exit_code = exit_code

        class PassthroughResult:
            def __init__(
                self, invocation_id: str, stdout: str, stderr: str, exit_code: int
            ) -> None:
                self.invocation_id = invocation_id
                self.stdout = stdout
                self.stderr = stderr
                self.exit_code = exit_code

        def report_passthrough_result(self, result: object, timeout: float) -> Response:
            return self.Response(
                stdout=getattr(result, "stdout", ""),
                stderr=getattr(result, "stderr", ""),
                exit_code=getattr(result, "exit_code", 0),
            )

    class _CommandRunner:
        def prepare_environment(
            self,
            lookup_path: str,
            extra_env: dict[str, str],
            invocation_env: dict[str, str],
        ) -> dict[str, str]:
            shim_dir = Path(socket_path).parent
            env = {"PATH": f"{lookup_path}{os.pathsep}{shim_dir}{os.pathsep}/usr/bin"}
            env.update(extra_env)
            env.update(invocation_env)
            return env

        def resolve_command_with_override(
            self, command: str, path: str, override: str | None
        ) -> _IPC.Response:
            return _IPC.Response(stdout="pass", stderr="through", exit_code=0)

    directive = SimpleNamespace(
        invocation_id="123",
        lookup_path=str(tmp_path / "cmox" / "bin"),
        extra_env={"EXTRA": "1"},
    )
    invocation = SimpleNamespace(
        env={"PATH": str(tmp_path / "cmox" / "bin")},
        command="cargo",
        args=("test",),
        stdin="",
    )
    modules = publish_execution.CmdMoxModules(
        ipc=_IPC(),
        env=_Env,
        command_runner=_CommandRunner(),
    )
    response = SimpleNamespace(passthrough=directive)

    returned, streamed = publish_execution._handle_cmd_mox_passthrough(
        response,
        invocation,
        timeout=1.0,
        modules=modules,
    )

    assert streamed is False
    assert isinstance(returned, _IPC.Response)
    assert returned.stdout == "pass"

❌ New issue: Large Method
test_handle_cmd_mox_passthrough_reports_response has 73 lines, threshold = 70

@leynos

leynos commented Dec 4, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/unit/publish/test_publish_manifest_strategies.py

Comment on lines +33 to +49

def test_apply_strip_patch_strategy_removes_all_entries(tmp_path: Path) -> None:
    """The 'all' strategy should drop the entire patch table."""
    manifest_path = tmp_path / "Cargo.toml"
    _write_manifest(
        manifest_path,
        """
        [patch.crates-io]
        alpha = { path = "../alpha" }
        serde = { git = "https://example.com/serde" }
        """,
    )
    plan = _make_plan(tmp_path, ("alpha",))

    publish_manifest._apply_strip_patch_strategy(tmp_path, plan, "all")

    document = tomlkit.parse(manifest_path.read_text(encoding="utf-8"))
    assert "patch" not in document

❌ New issue: Code Duplication
The module contains 3 functions with similar structure: test_apply_strip_patch_strategy_handles_unmodified_manifest,test_apply_strip_patch_strategy_removes_all_entries,test_apply_strip_patch_strategy_removes_publishable_entries

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

- Introduced pytest fixtures in test_publish_execution_helpers.py to stub
  cmd-mox environment, IPC, and command runner modules improving test
  isolation and reuse.
- Updated tests in test_publish_execution_helpers.py to utilize these
  fixtures instead of local classes.
- Added a reusable helper in test_publish_manifest_strategies.py to reduce
  duplication when testing strip patch strategies.
- Simplified existing tests for _apply_strip_patch_strategy by using the
  helper, improving readability and maintainability.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Dec 5, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/unit/publish/test_publish_execution_helpers.py

Comment on lines +148 to +186

def test_handle_cmd_mox_passthrough_reports_response(
    monkeypatch: pytest.MonkeyPatch,
    tmp_path: Path,
    mock_cmd_mox_env_module: type,
    mock_cmd_mox_ipc_module: type,
    mock_cmd_mox_command_runner: type,
) -> None:
    """Passthrough directives resolved to responses should be reported back."""
    socket_path = str(tmp_path / "cmox" / "shim" / "socket")
    monkeypatch.setenv("CMOX_IPC_SOCKET", socket_path)

    directive = SimpleNamespace(
        invocation_id="123",
        lookup_path=str(tmp_path / "cmox" / "bin"),
        extra_env={"EXTRA": "1"},
    )
    invocation = SimpleNamespace(
        env={"PATH": str(tmp_path / "cmox" / "bin")},
        command="cargo",
        args=("test",),
        stdin="",
    )
    modules = publish_execution.CmdMoxModules(
        ipc=mock_cmd_mox_ipc_module(),
        env=mock_cmd_mox_env_module,
        command_runner=mock_cmd_mox_command_runner(),
    )
    response = SimpleNamespace(passthrough=directive)

    returned, streamed = publish_execution._handle_cmd_mox_passthrough(
        response,
        invocation,
        timeout=1.0,
        modules=modules,
    )

    assert streamed is False
    assert isinstance(returned, mock_cmd_mox_ipc_module.Response)
    assert returned.stdout == "pass"

❌ New issue: Excess Number of Function Arguments
test_handle_cmd_mox_passthrough_reports_response has 5 arguments, max arguments = 4

@coderabbitai

This comment was marked as resolved.

Refactored cmd-mox related pytest fixtures in test_publish_execution_helpers.py by combining environment, IPC, and command runner stubs into a single mock_cmd_mox_modules fixture. This improves test code organization and reuse, and updates relevant tests to use the unified fixture.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos
leynos marked this pull request as ready for review December 6, 2025 22:54

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

Hey there - I've reviewed your changes - here's some feedback:

  • The directory structure example in docs/lading-design.md was unintentionally flattened into a single wrapped line inside the code block; restoring the previous multiline tree formatting will make it readable again.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The directory structure example in docs/lading-design.md was unintentionally flattened into a single wrapped line inside the code block; restoring the previous multiline tree formatting will make it readable again.

## Individual Comments

### Comment 1
<location> `tests/unit/test_workspace_metadata.py:426-431` </location>
<code_context>
+        metadata_module._CmdMoxCommand().run()
+
+
+def test_resolve_cmd_mox_timeout_validates_values() -> None:
+    """Timeout parsing should reject non-positive values."""
+    assert metadata_module._resolve_cmd_mox_timeout(None) > 0
+    assert metadata_module._resolve_cmd_mox_timeout("2.5") == 2.5
+    with pytest.raises(metadata_module.CargoMetadataError):
+        metadata_module._resolve_cmd_mox_timeout("0")
+
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for non-numeric and negative timeout values to fully cover `_resolve_cmd_mox_timeout` error paths.

The existing test already covers `None`, a valid float string, and the zero-value error path. To fully specify the behavior, please also add cases for a non-numeric value (e.g. `"abc"`) and a negative numeric value (e.g. `"-1"`) and assert they raise `CargoMetadataError`, so callers can rely on consistent handling of arbitrary environment-derived strings.

```suggestion
def test_resolve_cmd_mox_timeout_validates_values() -> None:
    """Timeout parsing should reject non-positive and non-numeric values."""
    # Defaults to a positive timeout when unset
    assert metadata_module._resolve_cmd_mox_timeout(None) > 0

    # Accepts valid numeric string
    assert metadata_module._resolve_cmd_mox_timeout("2.5") == 2.5

    # Rejects zero, negative, and non-numeric values
    for value in ("0", "-1", "abc"):
        with pytest.raises(metadata_module.CargoMetadataError):
            metadata_module._resolve_cmd_mox_timeout(value)
```
</issue_to_address>

### Comment 2
<location> `tests/unit/test_toml_utils.py:25-31` </location>
<code_context>
+    assert list(document_obj) == []
+
+
+def test_ensure_table_rejects_non_table_values() -> None:
+    """A non-table entry under the key should raise an assertion."""
+    doc = document()
+    doc["publish"] = "invalid"
+
+    with pytest.raises(AssertionError, match="publish must be a table"):
+        toml_utils.ensure_table(doc, "publish")
+
+
</code_context>

<issue_to_address>
**suggestion (testing):** Add a positive-path test for `ensure_table` creating or returning a valid table.

Currently we only cover the failure case when `ensure_table` sees a non-table value. Please also add a happy-path test that starts from an empty document, calls `ensure_table(doc, "publish")`, and asserts that it returns a TOML table and updates the document accordingly. That will exercise both creation and retrieval behaviour and protect future changes to this helper.

```suggestion
def test_ensure_table_rejects_non_table_values() -> None:
    """A non-table entry under the key should raise an assertion."""
    doc = document()
    doc["publish"] = "invalid"

    with pytest.raises(AssertionError, match="publish must be a table"):
        toml_utils.ensure_table(doc, "publish")


def test_ensure_table_creates_and_returns_table() -> None:
    """Missing keys should be initialised to a TOML table and returned."""
    doc = document()

    table_obj = toml_utils.ensure_table(doc, "publish")

    # The key should now exist in the document and reference the same table object
    assert "publish" in doc
    assert doc["publish"] is table_obj
    # The created object should be a TOML table, not a plain dict
    assert isinstance(table_obj, type(table()))
```
</issue_to_address>

### Comment 3
<location> `docs/lading-design.md:575-576` </location>
<code_context>
+
+### Phase 4 testing updates
+
+- Introduced `pytest-cov` as a development dependency so coverage can be
+  reported via `uv run pytest --cov` without additional tooling. Phase 4 sets a
+  floor of >90% line coverage for new modules; focused unit tests now exercise
+  configuration validation edges, publish manifest handling, cmd-mox IPC
+  fallbacks, and workspace model error paths to keep defensive code paths
+  observable.
+- Cmd-mox remains the default mechanism for mocking external commands. Tests
+  covering publish pre-flight and `cargo metadata` IPC use stubbed cmd-mox
+  modules rather than spawning real processes, keeping suites deterministic
</code_context>

<issue_to_address>
**nitpick (typo):** Align capitalization of `cmd-mox` across the new bullets.

The first bullet uses `cmd-mox IPC fallbacks` (lowercase `cmd`), while the second starts with `Cmd-mox remains...` (capital `C`). Please pick one capitalization that matches the official tool name and use it consistently in both bullets.

```suggestion
- cmd-mox remains the default mechanism for mocking external commands. Tests
  covering publish pre-flight and `cargo metadata` IPC use stubbed cmd-mox
```
</issue_to_address>

### Comment 4
<location> `docs/lading-design.md:572` </location>
<code_context>
+- Introduced `pytest-cov` as a development dependency so coverage can be
+  reported via `uv run pytest --cov` without additional tooling. Phase 4 sets a
+  floor of >90% line coverage for new modules; focused unit tests now exercise
+  configuration validation edges, publish manifest handling, cmd-mox IPC
+  fallbacks, and workspace model error paths to keep defensive code paths
+  observable.
</code_context>

<issue_to_address>
**issue (review_instructions):** The acronym “IPC” is introduced without being expanded on first use, which violates the requirement to define uncommon acronyms on first use.

Please expand “IPC” on its first occurrence (for example, “inter-process communication (IPC)”) so the acronym is defined when it is first introduced in the document.

<details>
<summary>Review instructions:</summary>

**Path patterns:** `**/*.md`

**Instructions:**
Define uncommon acronyms on first use.

</details>
</issue_to_address>

### Comment 5
<location> `tests/unit/publish/test_publish_execution_helpers.py:52-61` </location>
<code_context>
@pytest.fixture
def mock_cmd_mox_modules(tmp_path: Path) -> SimpleNamespace:
    """Provide complete cmd-mox module stubs for passthrough handling."""

    class _Env:
        CMOX_IPC_SOCKET_ENV = "CMOX_IPC_SOCKET"
        CMOX_REAL_COMMAND_ENV_PREFIX = "CMOX_REAL_"

    class _IPC:
        class Response:
            def __init__(
                self, stdout: str = "", stderr: str = "", exit_code: int = 0
            ) -> None:
                self.stdout = stdout
                self.stderr = stderr
                self.exit_code = exit_code

        class PassthroughResult:
            def __init__(
                self, invocation_id: str, stdout: str, stderr: str, exit_code: int
            ) -> None:
                self.invocation_id = invocation_id
                self.stdout = stdout
                self.stderr = stderr
                self.exit_code = exit_code

        def report_passthrough_result(self, result: object, timeout: float) -> Response:
            return self.Response(
                stdout=getattr(result, "stdout", ""),
                stderr=getattr(result, "stderr", ""),
                exit_code=getattr(result, "exit_code", 0),
            )

    class _CommandRunner:
        def prepare_environment(
            self,
            lookup_path: str,
            extra_env: dict[str, str],
            invocation_env: dict[str, str],
        ) -> dict[str, str]:
            shim_dir = (tmp_path / "cmox" / "shim").parent
            env = {"PATH": f"{lookup_path}{os.pathsep}{shim_dir}{os.pathsep}/usr/bin"}
            env.update(extra_env)
            env.update(invocation_env)
            return env

        def resolve_command_with_override(
            self, command: str, path: str, override: str | None
        ) -> _IPC.Response:
            return _IPC.Response(stdout="pass", stderr="through", exit_code=0)

    return SimpleNamespace(
        env_module=_Env,
        ipc_module=_IPC,
        command_runner=_CommandRunner,
    )

</code_context>

<issue_to_address>
**issue (code-quality):** Merge dictionary updates via the union operator [×4] ([`dict-assign-update-to-union`](https://docs.sourcery.ai/Reference/Default-Rules/suggestions/dict-assign-update-to-union/))
</issue_to_address>

### Comment 6
<location> `tests/unit/test_toml_utils.py:22` </location>
<code_context>
def test_load_or_create_document_initialises_empty_document(tmp_path: Path) -> None:
    """New documents should be created when the config file is absent."""
    config_path = tmp_path / "lading.toml"

    document_obj = toml_utils.load_or_create_document(config_path)

    assert list(document_obj) == []

</code_context>

<issue_to_address>
**suggestion (code-quality):** Replaces an empty collection equality with a boolean operation ([`simplify-empty-collection-comparison`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/simplify-empty-collection-comparison/))

```suggestion
    assert not list(document_obj)
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread tests/unit/test_workspace_metadata.py Outdated
Comment thread tests/unit/test_toml_utils.py
Comment thread docs/lading-design.md Outdated
Comment thread docs/lading-design.md
Comment thread tests/unit/publish/test_publish_execution_helpers.py Outdated
Comment thread tests/unit/test_toml_utils.py Outdated

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pyproject.toml (1)

29-38: Phase 4 coverage workflow requires CI update to align with design

The review correctly identifies pytest-cov for Phase 4, but implementation is incomplete. The current CI workflow uses slipcover with pytest --forked for crate_tools coverage only. Phase 4 design expects coverage to be reported via uv run pytest --cov without additional tooling, and the >90% target applies to "all new modules"—which should include the lading package.

Update the CI workflow to:

  1. Replace the slipcover approach with pytest-cov
  2. Extend coverage measurement to both crate_tools and lading packages
  3. Verify that overall line coverage meets the >90% threshold before marking Phase 4 complete

pytest-cov is compatible with Python 3.13 and the project's uv setup.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ebf1828 and 712a2d4.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • docs/lading-design.md (4 hunks)
  • docs/roadmap.md (1 hunks)
  • docs/usage-guide.md (1 hunks)
  • lading/commands/_shared.py (1 hunks)
  • lading/commands/publish_manifest.py (1 hunks)
  • lading/config.py (1 hunks)
  • lading/testing/toml_utils.py (1 hunks)
  • lading/utils/process.py (1 hunks)
  • lading/workspace/metadata.py (1 hunks)
  • pyproject.toml (1 hunks)
  • tests/unit/publish/test_publish_diagnostics.py (1 hunks)
  • tests/unit/publish/test_publish_execution_helpers.py (1 hunks)
  • tests/unit/publish/test_publish_manifest_strategies.py (1 hunks)
  • tests/unit/test_command_shared.py (1 hunks)
  • tests/unit/test_config.py (1 hunks)
  • tests/unit/test_toml_utils.py (1 hunks)
  • tests/unit/test_workspace_metadata.py (2 hunks)
  • tests/unit/test_workspace_models_validation.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • lading/utils/process.py
  • lading/config.py
  • lading/workspace/metadata.py
  • tests/unit/test_workspace_models_validation.py
  • tests/unit/test_command_shared.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • lading/commands/publish_manifest.py
  • lading/testing/toml_utils.py
  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_config.py
  • lading/commands/_shared.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • lading/utils/process.py
  • lading/config.py
  • lading/workspace/metadata.py
  • tests/unit/test_workspace_models_validation.py
  • tests/unit/test_command_shared.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • lading/commands/publish_manifest.py
  • lading/testing/toml_utils.py
  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_config.py
  • lading/commands/_shared.py
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Always provide a language identifier for fenced code blocks; use 'plaintext' for non-code text
Use '-' as the first level bullet and renumber lists when items change in Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

  • docs/roadmap.md
  • docs/lading-design.md
  • docs/usage-guide.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/roadmap.md
  • docs/lading-design.md
  • docs/usage-guide.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/roadmap.md
  • docs/lading-design.md
  • docs/usage-guide.md
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/test_workspace_models_validation.py
  • tests/unit/test_command_shared.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_config.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/test_workspace_models_validation.py
  • tests/unit/test_command_shared.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_config.py
pyproject.toml

📄 CodeRabbit inference engine (.rules/python-00.md)

Configure tools like Ruff, Pyright, and Pytest using pyproject.toml

pyproject.toml: Use PEP 621 [project] table for metadata (name, version, description, readme, requires-python, license, authors, keywords, classifiers) and runtime dependencies
Include mandatory PEP 621 fields: name and version in the [project] table
Include recommended [project] metadata fields: description, readme (pointing to README.md), requires-python (e.g., >=3.10), license, authors, keywords, and classifiers
Declare runtime dependencies as a list in PEP 508 format within the [project] table dependencies field (e.g., "requests>=2.25")
Use [project.optional-dependencies] to group development and documentation dependencies separately from production dependencies
Define console entry points in [project.scripts] table and GUI entry points in [project.gui-scripts] table to expose CLIs or GUIs
Declare [build-system] table with requires = ["setuptools>=61.0", "wheel"] and build-backend = "setuptools.build_meta" to support editable installs
Set [tool.uv] with package = true to ensure uv sync builds and installs your project into its virtual environment
Keep pyproject.toml human-readable by editing it by hand when possible and using TOML-aware editors
Declare dynamic = ["version"] sparingly; only use it when your version is computed at build time (e.g., via setuptools_scm), and ensure your build backend supports dynamic metadata
Keep build system constraints minimal; omit [build-system] if you don't need editable installs, but set tool.uv.package = true to override default behavior

Files:

  • pyproject.toml
🧬 Code graph analysis (6)
tests/unit/test_workspace_models_validation.py (1)
lading/workspace/models.py (17)
  • WorkspaceDependency (50-56)
  • _is_ordering_dependency (21-30)
  • WorkspaceModelError (33-34)
  • build_workspace_graph (184-215)
  • _index_workspace_packages (218-230)
  • _build_dependencies (261-281)
  • _validate_dependency_mapping (284-291)
  • _validate_dependency_kind (312-327)
  • _lookup_workspace_target (294-309)
  • _normalise_workspace_root (354-363)
  • _normalise_manifest_path (366-372)
  • _expect_sequence (375-392)
  • _expect_string (395-400)
  • _is_non_empty_sequence (403-409)
  • _coerce_publish_setting (412-425)
  • _extract_readme_workspace_flag (428-436)
  • _manifest_uses_workspace_readme (439-452)
tests/unit/test_command_shared.py (1)
lading/commands/_shared.py (1)
  • describe_crates (11-15)
tests/unit/publish/test_publish_diagnostics.py (2)
lading/commands/publish_diagnostics.py (3)
  • _append_compiletest_diagnostics (56-79)
  • _read_tail_lines (29-38)
  • _format_artifact_diagnostics (41-53)
tests/unit/test_workspace_metadata.py (1)
  • _raise (114-115)
tests/unit/publish/test_publish_manifest_strategies.py (2)
lading/commands/publish_plan.py (2)
  • PublishPlan (22-34)
  • publishable_names (32-34)
lading/commands/publish_manifest.py (2)
  • _apply_strip_patch_strategy (182-205)
  • PublishPreparationError (58-74)
tests/unit/test_workspace_metadata.py (1)
lading/workspace/metadata.py (12)
  • CargoMetadataError (22-33)
  • _CmdMoxCommand (126-158)
  • run (136-158)
  • _resolve_cmd_mox_timeout (184-194)
  • _build_invocation_environment (161-168)
  • _coerce_text (97-101)
  • invalid_cmd_mox_timeout (26-28)
  • non_positive_cmd_mox_timeout (31-33)
  • _load_cmd_mox_modules (171-181)
  • _build_cmd_mox_command (197-199)
  • _ensure_command (86-94)
  • argv (132-134)
tests/unit/test_config.py (1)
lading/config.py (16)
  • PreflightConfig (109-167)
  • from_mapping (42-51)
  • from_mapping (62-72)
  • from_mapping (84-97)
  • from_mapping (120-167)
  • from_mapping (179-194)
  • CompiletestExtern (101-105)
  • ConfigurationError (23-24)
  • _validate_mapping_keys (202-227)
  • _string_tuple (294-306)
  • _string_matrix (340-351)
  • _string_mapping (354-364)
  • _optional_mapping (407-416)
  • _non_negative_int (367-379)
  • _boolean (382-389)
  • _strip_patches (392-404)
🪛 LanguageTool
docs/lading-design.md

[uncategorized] ~569-~569: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ...pytest-cov as a development dependency so coverage can be reported via `uv run ...

(COMMA_COMPOUND_SENTENCE_2)

docs/usage-guide.md

[style] ~240-~240: Would you like to use the Oxford spelling “normalizes”? The spelling ‘normalises’ is also correct.
Context: ...r staging the workspace, publish also normalises the root Cargo.toml according to the ...

(OXFORD_SPELLING_Z_NOT_S)

🔍 Remote MCP

Based on my research of the lading repository, here is a concise summary of the relevant context for reviewing this PR:

PR Context Summary

PR Objective: Finalize Phase 4 testing scaffolding and enhance documentation. The PR adds comprehensive unit tests, pytest-cov for coverage reporting, and documentation updates reflecting testing strategies and Phase 4 stability efforts.

Key Changes Identified

Testing Infrastructure:

  • New test modules: Comprehensive unit tests added for:

    • Configuration validation (tests/unit/test_config.py)
    • Publish manifest strategies (tests/unit/publish/test_publish_manifest_strategies.py)
    • Publish execution helpers (tests/unit/publish/test_publish_execution_helpers.py)
    • Preflight checks and diagnostics (tests/unit/publish/test_publish_diagnostics.py, test_preflight_checks.py)
    • Workspace model validation (tests/unit/test_workspace_models_validation.py)
    • TOML utilities (tests/unit/test_toml_utils.py)
    • Workspace metadata (tests/unit/test_workspace_metadata.py)
  • pytest-cov integration: Added as dev dependency for test coverage reporting (enable via uv run pytest --cov)

  • Testing patterns: Emphasizes:

    • Cmd-mox for IPC-based external command stubbing (replacing real cargo/git)
    • Unit tests with mocked dependencies
    • BDD tests for end-to-end workflows
    • Phase 4 goal: >90% line coverage

Documentation Updates:

  • docs/lading-design.md: Phase 4 testing approach and IPC/mox patterns
  • docs/roadmap.md: Marking test coverage tasks as complete
  • docs/usage-guide.md: Clarified publish workflow, patch stripping options, pre-flight checks, and README propagation

Code Quality:

  • Added pragma: no cover comments to TYPE_CHECKING import blocks across multiple modules to improve coverage reporting accuracy (these blocks don't execute at runtime)

Testing Strategy Employed

The PR establishes a dual-testing approach:

  1. Unit tests (tests/unit/): Direct function invocation with mocks and temporary workspace fixtures
  2. BDD tests (tests/bdd/): End-to-end CLI subprocess invocation with cmd-mox command stubbing

Key testing patterns:

  • Use of factory fixtures (make_crate, make_workspace, make_config) for test workspace construction
  • Environment-based command stubbing (LADING_USE_CMD_MOX_STUB=1, CMOX_IPC_SOCKET)
  • Automatic preflight check disabling in unit tests via autouse fixture
  • Configuration validation and error path testing

Quality Metrics

  • Phase 4 coverage target: >90% line coverage
  • Test timeouts: 30 seconds (enforced by pytest-timeout)
  • All tests must pass make all quality gates (format, lint, typecheck, tests)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Sourcery review
  • GitHub Check: Sourcery review
🔇 Additional comments (22)
lading/workspace/metadata.py (1)

16-20: Keep TYPE_CHECKING imports excluded from coverage

Maintain this # pragma: no cover on the typ.TYPE_CHECKING block; it correctly marks these imports as type-only and leaves runtime behaviour and exception paths unchanged.

lading/utils/process.py (1)

9-15: Retain type-only Logger/Path aliases outside coverage metrics

Keep this pattern of real imports under typ.TYPE_CHECKING with LoggerType/PathType falling back to typ.Any at runtime and excluded from coverage; it satisfies typing and Ruff TC rules without affecting logging behaviour.

lading/commands/_shared.py (1)

7-8: Exclude WorkspaceGraph typing helper from coverage

Keep this # pragma: no cover on the WorkspaceGraph TYPE_CHECKING import; it correctly treats the import as a typing helper only and leaves describe_crates behaviour untouched.

docs/roadmap.md (1)

221-233: Validate coverage before marking “Achieve High Test Coverage” as complete

Back this [x] Achieve High Test Coverage tick with an actual coverage run on the current branch. Generate a report with pytest-cov and confirm that the documented threshold (over 90% line coverage for all new modules) is met before merging this roadmap change.

lading/config.py (1)

15-17: Keep configuration TYPE_CHECKING imports out of coverage

Retain this # pragma: no cover annotation on the Path TYPE_CHECKING block; it standardizes treatment of type-only imports across the codebase and does not alter configuration loading or validation semantics.

tests/unit/test_workspace_metadata.py (2)

39-392: Exercise cargo-metadata happy paths, error paths, and workspace modelling thoroughly

Keep this suite of tests around load_cargo_metadata, build_workspace_graph, and load_workspace. The parametrised scenarios, byte/text handling checks, logging assertions, and WorkspaceGraph shape validations collectively give strong coverage of success cases and error surfaces without over-mocking the internals.


393-536: Keep cmd-mox IPC stub tests to guard the new proxy behaviour

Retain these cmd-mox–focused tests that validate socket presence, timeout parsing, environment construction, IPC invocation wiring, and convenience error constructors. The lightweight _StubEnv/_StubIPC stand-ins and direct assertions against command.argv, ipc.last_invocation, and ipc.timeout give precise coverage of _CmdMoxCommand.run and helpers without depending on real cmd-mox IPC.

tests/unit/test_command_shared.py (1)

1-16: Keep this focused pluralisation test for describe_crates

Leave this test in place; it cleanly exercises both the singular and plural branches of describe_crates using a minimal SimpleNamespace workspace stand-in and aligns with the helper’s documented behaviour.

tests/unit/test_workspace_models_validation.py (1)

1-118: Good coverage of workspace model validation paths.

The tests exercise ordering dependencies, graph construction, indexing, dependency handling, path normalisation, coercion helpers, and readme flag extraction. This aligns well with the Phase 4 coverage goals.

tests/unit/test_config.py (5)

201-223: LGTM — comprehensive coverage of extended preflight configuration fields.

The test validates aux_build, compiletest_extern, env, and stderr_tail_lines normalisation, confirming the mapping-to-dataclass transformation works as expected.


225-238: Good validation of unknown-key detection.

These tests confirm _validate_mapping_keys raises descriptive errors for unknown sections and gracefully handles None mappings.


241-260: String helper tests exercise acceptance and rejection paths appropriately.

The coverage for _string_tuple, _string_matrix, _string_mapping, and _optional_mapping hits both valid inputs and type-error conditions.


263-283: Numeric and boolean normalisation tests are thorough.

The tests cover default fallback, string-to-int coercion, negative-value rejection, and boolean type enforcement. The strip_patches tests correctly verify rejection of True and unknown string values.


288-305: Nested context restoration test validates LIFO semantics.

The test confirms that exiting an inner use_configuration context restores the outer configuration, and exiting all contexts raises ConfigurationNotLoadedError.

docs/usage-guide.md (2)

232-238: Documentation accurately describes the staged publish workflow.

The clarification that cargo package runs in plan order inside the staged copy, followed by cargo publish --dry-run per crate, matches the implementation. The warning-and-continue behaviour for already-published versions is documented correctly.


240-251: Strip-patches strategy documentation is clear and complete.

The three strategies ("all", "per-crate", false) are explained with their use cases. The note about staged manifests leaving the original workspace untouched addresses a common concern.

lading/testing/toml_utils.py (1)

33-33: LGTM — pragma annotation added for coverage accuracy.

The TYPE_CHECKING block correctly receives the pragma: no cover comment, consistent with other modules in this PR.

lading/commands/publish_manifest.py (1)

42-42: LGTM — pragma annotation added for coverage accuracy.

The TYPE_CHECKING block correctly receives the pragma: no cover comment, aligning with the Phase 4 coverage-tooling improvements.

tests/unit/test_toml_utils.py (1)

1-74: Keep TOML utility tests as written

Leave the structure and expectations of these tests in place; they exercise the key behaviours of toml_utils well (document initialisation, assertion messages, manifest loading, and workspace/crate resolution) and align with the stated Phase 4 coverage goals.

tests/unit/publish/test_publish_manifest_strategies.py (1)

33-138: Retain the helper and scenario matrix for strip‑patch strategies

Keep _test_strip_patch_strategy_helper and the surrounding tests as written; they provide a clear, low-duplication matrix over “all”, “per-crate”, missing manifests, invalid TOML, unknown strategies, and non‑crates‑io patches, which is exactly the behaviour surface that _apply_strip_patch_strategy needs exercised.

tests/unit/publish/test_publish_diagnostics.py (1)

14-68: Keep diagnostics tests as written

Leave these diagnostics tests intact; they correctly probe artefact discovery, missing files, deduplication, tail handling, and the “no content” path, and they match the intended semantics of the helpers in publish_diagnostics.

Also applies to: 84-91

tests/unit/publish/test_publish_execution_helpers.py (1)

75-287: Retain the expanded publish‑execution helper tests

Keep the rest of this module as written. The tests exercise the important edge cases for cmd‑mox integration, subprocess handling, environment normalisation and logging, PATH merging, and I/O relaying, all using local stubs and fixtures without hitting real external commands. This aligns well with the PR’s Phase 4 stability and coverage goals.

Comment thread docs/lading-design.md Outdated
Comment thread docs/lading-design.md Outdated
Comment thread tests/unit/publish/test_publish_diagnostics.py
Comment thread tests/unit/publish/test_publish_execution_helpers.py
Comment thread tests/unit/publish/test_publish_manifest_strategies.py
Comment thread tests/unit/test_toml_utils.py
Comment thread tests/unit/test_workspace_metadata.py
Comment thread tests/unit/test_workspace_models_validation.py Outdated
Comment thread tests/unit/test_workspace_models_validation.py Outdated
Comment thread tests/unit/test_workspace_models_validation.py
…ency validation errors

Improved test coverage for workspace model validation by parameterizing tests that check invalid dependency mappings and kinds. This change replaces multiple individual test cases with a more maintainable structure using pytest.param and pytest.mark.parametrize. Also added tests to detect workspace readme flags and additional validation error cases.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
tests/unit/publish/test_publish_manifest_strategies.py (1)

18-26: Align type: ignore usage with pyright-focused guidelines

Replace the remaining # type: ignore[arg-type] at Line 99 with a targeted pyright suppression and an inline justification, matching the pattern used for publishable in _make_plan. For example, use # pyright: ignore[reportArgumentType] - exercising invalid-strategy branch in tests so static analysis remains useful while still permitting this negative-path call in tests.

Also applies to: 33-45, 86-100

docs/lading-design.md (2)

525-537: Rewrite the directory structure code block as a proper multi-line tree

Split this plaintext block so each path appears on its own line with the tree glyphs (, ├──, └──) restored, and move inline comments onto their own indented lines (or keep them after filenames with a single space). The current single-line concatenation makes the tree unreadable and conflicts with the “proposed directory structure” description.


567-578: Ensure IPC is expanded on its first occurrence in the document

Keep the new Phase 4 bullets, but update the first occurrence of “IPC” earlier in the document to read “inter-process communication (IPC)” so the acronym is defined at first use. Once that is in place, keep later mentions (including here) as “IPC” only, or leave a single explicit expansion if style guidance prefers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 712a2d4 and d592208.

📒 Files selected for processing (7)
  • docs/lading-design.md (4 hunks)
  • tests/unit/publish/test_publish_diagnostics.py (1 hunks)
  • tests/unit/publish/test_publish_execution_helpers.py (1 hunks)
  • tests/unit/publish/test_publish_manifest_strategies.py (1 hunks)
  • tests/unit/test_toml_utils.py (1 hunks)
  • tests/unit/test_workspace_metadata.py (2 hunks)
  • tests/unit/test_workspace_models_validation.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_workspace_models_validation.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_workspace_models_validation.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_workspace_models_validation.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/test_workspace_metadata.py
  • tests/unit/test_workspace_models_validation.py
  • tests/unit/publish/test_publish_diagnostics.py
  • tests/unit/publish/test_publish_manifest_strategies.py
  • tests/unit/publish/test_publish_execution_helpers.py
  • tests/unit/test_toml_utils.py
docs/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/**/*.md: Use the markdown files within the docs/ directory as a knowledge base and source of truth for project requirements, dependency choices, and architectural decisions.
Proactively update relevant files in the docs/ directory when new decisions are made, requirements change, libraries are added/removed, or architectural patterns evolve to keep documentation accurate and current.

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-GB-oxendict) with suffixes: -ize in words like 'realize' and 'organization', -lyse in words like 'analyse' and 'paralyse', -our in words like 'colour' and 'behaviour', -re in words like 'centre' and 'calibre', double 'l' in words like 'cancelled' and 'counsellor', maintain 'e' in words like 'likeable', -ogue in words like 'catalogue'
Use the Oxford comma in documentation: 'ships, planes, and hovercraft' where it aids comprehension
Treat company names as collective nouns in documentation, for example 'Lille Industries are expanding'
Write headings in sentence case
Use Markdown headings (#, ##, ###, and so on) in order without skipping levels
Follow markdownlint recommendations for Markdown formatting
Always provide a language identifier for fenced code blocks; use 'plaintext' for non-code text
Use '-' as the first level bullet and renumber lists when items change in Markdown
Prefer inline links using text or angle brackets around the URL in Markdown
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown
Ensure tables have a delimiter line below the header row in Markdown
Expand any uncommon acronym on first use, for example, Continuous Integration (CI)
Wrap paragraphs at 80 columns in documentation
Wrap code at 120 columns in documentation
Do not wrap tables in documentation
Use footnotes referenced with [^label] in Markdown documentation
Include Mermaid diagrams in documentation where they add clarity
When embedding figures in documentation, use ![alt text](path/to...

Files:

  • docs/lading-design.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: For Markdown files (.md only), ensure changes pass lint checks via make markdownlint.
For Markdown files (.md only), ensure Mermaid diagrams pass validation using nixie via make nixie.

Files:

  • docs/lading-design.md

⚙️ CodeRabbit configuration file

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/lading-design.md
🧬 Code graph analysis (5)
tests/unit/test_workspace_metadata.py (1)
lading/workspace/metadata.py (10)
  • CargoMetadataError (22-33)
  • _CmdMoxCommand (126-158)
  • run (136-158)
  • _resolve_cmd_mox_timeout (184-194)
  • _build_invocation_environment (161-168)
  • _coerce_text (97-101)
  • invalid_cmd_mox_timeout (26-28)
  • non_positive_cmd_mox_timeout (31-33)
  • _load_cmd_mox_modules (171-181)
  • argv (132-134)
tests/unit/test_workspace_models_validation.py (1)
lading/workspace/models.py (17)
  • WorkspaceDependency (50-56)
  • _is_ordering_dependency (21-30)
  • WorkspaceModelError (33-34)
  • build_workspace_graph (184-215)
  • _index_workspace_packages (218-230)
  • _build_dependencies (261-281)
  • _validate_dependency_mapping (284-291)
  • _validate_dependency_kind (312-327)
  • _lookup_workspace_target (294-309)
  • _normalise_workspace_root (354-363)
  • _normalise_manifest_path (366-372)
  • _expect_sequence (375-392)
  • _expect_string (395-400)
  • _is_non_empty_sequence (403-409)
  • _coerce_publish_setting (412-425)
  • _extract_readme_workspace_flag (428-436)
  • _manifest_uses_workspace_readme (439-452)
tests/unit/publish/test_publish_diagnostics.py (1)
lading/commands/publish_diagnostics.py (3)
  • _append_compiletest_diagnostics (56-79)
  • _read_tail_lines (29-38)
  • _format_artifact_diagnostics (41-53)
tests/unit/publish/test_publish_manifest_strategies.py (2)
lading/commands/publish_plan.py (2)
  • PublishPlan (22-34)
  • publishable_names (32-34)
lading/commands/publish_manifest.py (2)
  • _apply_strip_patch_strategy (182-205)
  • PublishPreparationError (58-74)
tests/unit/test_toml_utils.py (1)
lading/testing/toml_utils.py (7)
  • load_or_create_document (50-72)
  • ensure_table (75-108)
  • ensure_array_field (111-143)
  • append_if_absent (146-163)
  • load_manifest (166-188)
  • load_workspace_manifest (191-210)
  • load_crate_manifest (213-239)
🪛 GitHub Actions: CI
tests/unit/publish/test_publish_diagnostics.py

[error] 1-1: Command failed: make check-fmt. Ruff format --check would reformat 1 file (tests/unit/publish/test_publish_diagnostics.py).

🔍 Remote MCP Ref

Summary of additional, review-relevant facts

  • pyproject.toml on the PR branch adds pytest-cov to the dev dependency group and pins cmd-mox via git URL; pytest timeout set to 30s.
  • ruff/pylint max-args is configured to 4 (tool.ruff.lint.pylint -> max-args = 4) — explains the PR comments about reducing test function argument counts.
  • The PR is online: Finalize test suite and enhance docs (Phase 4) — PR #45 (branch terragon/phase4-stabilisation-testing-docs-aem45j → main). Use this URL for direct review and CI logs.
  • I inspected the repo comparison view for the branch (diff/compare) for context on changed files. Use this to see full diffs per-file when reviewing.
  • The project uses pytest; see pytest docs for plugin/pytest-cov integration and invocation guidance if you need to run coverage locally (pytest --cov).

Relevant implications for review

  • Tests+docs heavy PR: expect CI to run pytest with coverage; ensure new tests run within the 30s timeout and adhere to lint complexity/arg limits (max-args=4).
  • CMD-MOX is included as a test-time dependency (git-pinned) — validate that the CI environment can fetch that git URL.
  • Many changes are test additions and doc edits; production code changes are limited to adding pragma comments in TYPE_CHECKING blocks (coverage/annotation-only).
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (4)
tests/unit/test_workspace_metadata.py (1)

394-538: Strengthen cmd‑mox coverage further only if future regressions appear

Keep these new cmd‑mox tests as written; they exercise socket absence, timeout parsing, invocation environment, text coercion, error constructors, module‑load failure, and IPC execution paths in a clear, focused way and align with the workspace.metadata contract. No changes are required here.

tests/unit/test_toml_utils.py (1)

16-96: Keep this TOML utilities test suite as-is

Retain these tests; they now exercise both failure and success paths for load_or_create_document, ensure_table, ensure_array_field, append_if_absent, and the manifest loaders, matching the documented behaviour of lading.testing.toml_utils.

tests/unit/test_workspace_models_validation.py (1)

15-139: Retain these workspace model validation tests

Keep this module as written; it thoroughly exercises the defensive and validation helpers in lading.workspace.models (including dependency shapes, path/sequence/string coercion, publish settings, and readme workspace flags) and aligns with the intended error contracts.

tests/unit/publish/test_publish_execution_helpers.py (1)

17-287: Keep the consolidated cmd‑mox fixture and execution helper tests

Leave this module as-is; the mock_cmd_mox_modules fixture cleanly encapsulates env/ipc/runner stubs, and the tests collectively exercise all key publish execution paths (subprocess spawning, PATH merging, cmd‑mox passthrough, buffering, broken pipes, environment updates, and logging) without over‑mocking.

Comment thread tests/unit/publish/test_publish_diagnostics.py

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d592208 and 7ac9270.

📒 Files selected for processing (1)
  • tests/unit/publish/test_publish_diagnostics.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/unit/publish/test_publish_diagnostics.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/unit/publish/test_publish_diagnostics.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/unit/publish/test_publish_diagnostics.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/unit/publish/test_publish_diagnostics.py
🧬 Code graph analysis (1)
tests/unit/publish/test_publish_diagnostics.py (1)
lading/commands/publish_diagnostics.py (3)
  • _append_compiletest_diagnostics (56-79)
  • _read_tail_lines (29-38)
  • _format_artifact_diagnostics (41-53)
🪛 GitHub Actions: CI
tests/unit/publish/test_publish_diagnostics.py

[error] 11-11: ruff check failed: F401 'pytest' imported but unused. This is fixable with the '--fix' option.

🔍 Remote MCP Ref

Summary of additional, review-relevant facts found on the PR page (#45):

  • PR metadata: branch terragon/phase4-stabilisation-testing-docs-aem45j → main, 5 commits, +1,110 −37, files changed: 19; title “Finalize test suite and enhance docs (Phase 4)”; opened 2025-12-04.

  • Key intent: add Phase‑4 testing scaffolding and docs, introduce pytest‑cov as dev dependency, add many unit tests (8 new test modules covering publish diagnostics/execution/manifest strategies, config, toml utils, workspace metadata/models, shared helpers), and annotate TYPE_CHECKING blocks with # pragma: no cover (coverage-only, no runtime changes). CI/test invocation recommended: uv run pytest --cov or pytest --cov.

  • Test/CI implications flagged in the PR and review bots:

    • pytest timeout set to 30s; ensure new tests complete within that limit.
    • ruff/pylint max-args configured to 4 — several review comments requested consolidating fixtures to keep test argument counts ≤4.
    • cmd-mox is added/pinned as a git dependency for tests; CI must be able to fetch that URL.
  • Notable reviewer feedback and automated findings (actionable for review):

    • Large Method, Code Duplication, and Excess-Args issues were raised in tests and then addressed by introducing fixtures/helpers and consolidating fixtures into a single composite fixture. Commits show refactors (fixtures consolidated, helper added). Validate these refactors preserve test semantics and satisfy lint (max-args) and complexity limits.
    • Docs issues: malformed ASCII directory tree in docs/lading-design.md (flattened lines), inconsistent capitalization of “cmd-mox” vs “Cmd-mox”, and missing expansion of “IPC” on first use — reviewers requested fixes. Confirm doc formatting and acronym expansion.
    • CI/coverage checklist: reviewers requested updating CI workflow to use pytest-cov (replace slipcover) and measure coverage for both crate_tools and lading packages to substantiate roadmap claim of >90% coverage.
  • Practical review checklist derived from above (verify before approve/merge):

    • Run tests with pytest --cov (or uv run pytest --cov) to confirm coverage and that Phase‑4 >90% targets are met for new modules.
    • Ensure tests complete under the 30s timeout and adhere to lint rules (max-args=4, complexity thresholds).
    • Confirm cmd-mox dependency is resolvable in CI (git URL) and that introduced stubs/fixtures accurately exercise intended behavior without network/IPC flakiness.
    • Verify requested doc fixes (directory tree formatting, acronym expansion, capitalization) are applied.
    • Confirm TYPE_CHECKING # pragma: no cover additions are non-functional and intended only to affect coverage.

Sources:

  • Pull request page and conversation for PR #45 (Finalize test suite and enhance docs (Phase 4)) — GitHub PR view.
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (5)
tests/unit/publish/test_publish_diagnostics.py (5)

14-28: LGTM!

The test correctly verifies that artifact tail lines are appended to diagnostics when artifacts exist.


31-44: LGTM!

The test properly verifies that missing artifacts are handled gracefully without raising exceptions.


47-53: LGTM!

The test correctly verifies that the original message is returned unchanged when no artifacts are detected.


56-66: LGTM!

The test correctly validates that duplicate artifact tokens are deduplicated in the diagnostic output.


82-89: LGTM!

The test correctly verifies that artifacts without content still produce formatted output with the path listed.

Comment thread tests/unit/publish/test_publish_diagnostics.py
Comment thread tests/unit/publish/test_publish_diagnostics.py Outdated
Comment thread docs/lading-design.md Outdated
…ith monkeypatch

Refactored test_read_tail_lines_handles_zero_and_errors to use pytest monkeypatch fixtures for simulating OSError in Path.read_text. This improves test reliability and clarity in handling error cases.

Also formatted docs/lading-design.md content for improved readability.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos

leynos commented Dec 7, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@leynos leynos changed the title Phase 4: expand test suite, tooling, and docs Phase 4: expand tests, tooling, and docs with coverage Dec 7, 2025
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Dec 8, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/bdd/steps/test_publish_infrastructure.py

Comment on lines +245 to +254

def _cmd_mox_stub_env_enabled() -> typ.Iterator[None]:
    """Temporarily enable CMD_MOX_STUB_ENV_VAR for cmd-mox stubs."""
    var_name = metadata_module.CMD_MOX_STUB_ENV_VAR
    snapshot = {var_name: os.environ.get(var_name)}
    os.environ[var_name] = "1"
    try:
        yield
    finally:
        os.environ.pop(var_name, None)
        os.environ.update({k: v for k, v in snapshot.items() if v is not None})

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

Improved wording in the lading-design documentation to better describe the
focus areas of the test coverage, including configuration validation edges,
publish manifest handling, cmd-mox IPC fallback mechanisms, and workspace model
error paths. This enhances readability and precision in the docs related to
coverage and testing strategies.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@coderabbitai

This comment was marked as resolved.

@leynos leynos changed the title Phase 4: expand tests, tooling, and docs with coverage Phase 4: expand tests, tooling, and docs with high coverage and IPC testing Dec 8, 2025
codescene-delta-analysis[bot]

This comment was marked as outdated.

…stub helper

Refactored _cmd_mox_stub_env_enabled helper to handle restoring environment variable
more cleanly by conditionally updating with a restore dictionary instead of always
using a snapshot dict. This simplifies and clarifies environment cleanup after tests.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Dec 8, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/bdd/steps/test_publish_infrastructure.py

Comment on lines +245 to +255

def _cmd_mox_stub_env_enabled() -> typ.Iterator[None]:
    """Temporarily enable CMD_MOX_STUB_ENV_VAR for cmd-mox stubs."""
    var_name = metadata_module.CMD_MOX_STUB_ENV_VAR
    previous = os.environ.get(var_name)
    restore = {var_name: previous} if previous is not None else {}
    os.environ[var_name] = "1"
    try:
        yield
    finally:
        os.environ.pop(var_name, None)
        os.environ.update(restore)

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

@coderabbitai

This comment was marked as resolved.

…lish_infrastructure.py

Introduce _build_env_restore_dict helper to consolidate environment variable restoration logic in _cmd_mox_stub_env_enabled context manager, improving code readability and reuse.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
@leynos leynos changed the title Phase 4: expand tests, tooling, and docs with high coverage and IPC testing Phase 4: expand tests, tooling, docs, and IPC testing Dec 8, 2025
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

leynos commented Dec 8, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/bdd/steps/test_publish_infrastructure.py

Comment on lines +244 to +247

def _build_env_restore_dict(var_name: str) -> dict[str, str]:
    """Build a dictionary for restoring an environment variable."""
    previous = os.environ.get(var_name)
    return {var_name: previous} if previous is not None else {}

❌ New issue: Deep, Nested Complexity
_build_env_restore_dict has a nested complexity depth of 4, threshold = 4

@leynos

leynos commented Dec 8, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/bdd/steps/test_publish_infrastructure.py

Comment on lines +244 to +247

def _build_env_restore_dict(var_name: str) -> dict[str, str]:
    """Build a dictionary for restoring an environment variable."""
    previous = os.environ.get(var_name)
    return {var_name: previous} if previous is not None else {}

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

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Refactored the _build_env_restore_dict function to improve clarity by replacing the ternary operation with a standard if-statement that returns an empty dictionary if the variable is not set, enhancing readability in test utilities.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8146a61 and 0ecbb2b.

📒 Files selected for processing (1)
  • tests/bdd/steps/test_publish_infrastructure.py (6 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: For Python files, ensure changes pass all relevant unit and behavioral tests according to testing guidelines.
For Python files, ensure changes pass lint checks via make lint.
For Python files, ensure changes adhere to formatting standards via make check-fmt.
For Python files, ensure changes pass type checking via make typecheck.
For Python development, refer to detailed guidelines in the .rules/ directory including Python Code Style Guidelines, Context Managers, Exception Design/Raising/Handling/Logging, Generators, Project Configuration, Return Patterns, and Typing best practices.

**/*.py: Use snake_case.py for Python file names, naming them for their contents
Use PascalCase for class names
Use snake_case for variable and function names
Use UPPER_SNAKE_CASE for module-level constants
Prefix private or internal helpers with a single underscore (_)
Enable and maintain full static type coverage using Pyright; use typing everywhere
Use TypedDict or @DataClass(slots=True) for structured data
Avoid Any; use precise types (TypeVar, Protocol, Literal, Union) and typing.cast only when necessary with justification
Be explicit with return type annotations using -> None, -> str, etc., for all public functions and class methods
Prefer immutability: use tuples over lists and types.MappingProxyType for read-only mappings
Enforce strict mode in Pyright; treat all Pyright warnings as CI errors and use # pyright: ignore sparingly with explanation
Avoid side effects at import time; modules should not modify global state or perform actions on import
Document public functions, classes, and modules using NumPy-format docstrings
Use inline comments to explain tricky code and non-obvious logic

**/*.py: Use context managers (via contextlib.contextmanager or __enter__/__exit__ methods) to encapsulate setup and teardown logic for resource management (files, locks, connections, etc.)
Use @contextlib.contextmanager decorator for straightforward procedural setup...

Files:

  • tests/bdd/steps/test_publish_infrastructure.py

⚙️ CodeRabbit configuration file

**/*.py: - Keep C90 / mccabe complexity ≤ 9

  • Follow single responsibility and CQRS (command/query segregation)
  • Prefer structural pattern matching to
  • Prefer structural pattern matching over isinstance() or imperative decomposition.
  • Docstrings must follow the numpy style guide. Use a single-line summary for private functions and methods, and full structured docs for all public interfaces.
  • Move conditionals with >2 branches to predicate/helper functions
  • Avoid eval, exec, pickle, monkey-patching, ctypes, unsafe shell
  • Every module must begin with a triple-quoted docstring explaining its purpose, utility, and usage, including example calls if appropriate.
  • Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
  • Lint suppressions:
    • Blanket # noqa, file-level skips, and categories are forbidden
    • Only narrow in-line disables (# noqa: XYZ) are permitted, and must be accompanied by FIXME: or a ticket link, and used only as a last resort.
  • Use pytest fixtures for shared setup (conftest.py or fixtures/)
  • Replace duplicate tests with @pytest.mark.parametrize
  • Prefer pytest-mock or unittest.mock for stubs/mocks
  • Use assert …, "message" over bare asserts
  • Reflect all API/behaviour changes in docs/ and update roadmap on completion
  • Files must not exceed 400 logical lines:
    • Decompose large modules into subpackages
    • Split large match/case or dispatch tables by domain and collocate with targets if appropriate
    • Move bulky data (fixtures, templates) to external files for parsing at runtime
  • Mutable defaults and shadowed built-ins are forbidden
  • All code must have clear type hints using modern style (A | B, list[str], class Foo[A]:, type Bar = int, etc.), with ABC imports drawn from the correct stdlib module.
  • All path manipulation must be performed using pathlib for cross platform safety. Do not use string manipulation for extraction of path components or filename ele...

Files:

  • tests/bdd/steps/test_publish_infrastructure.py
**/test_*.py

📄 CodeRabbit inference engine (.rules/python-00.md)

**/test_*.py: Use pytest idioms: prefer fixtures over setup/teardown, parametrize broadly, avoid unnecessary mocks
Group related tests using class with method names prefixed by test_
Write tests from a user's perspective; test public behavior, not internals
Avoid mocking too much; prefer test doubles only for external services or non-deterministic behaviors

Files:

  • tests/bdd/steps/test_publish_infrastructure.py
**/*test*.py

📄 CodeRabbit inference engine (.rules/python-exception-design-raising-handling-and-logging.md)

In tests, use narrow exception assertions with pytest.raises() specifying the expected type and optionally constraining the message via regex (B017)

Files:

  • tests/bdd/steps/test_publish_infrastructure.py
🧬 Code graph analysis (1)
tests/bdd/steps/test_publish_infrastructure.py (1)
tests/bdd/steps/test_publish_fixtures.py (2)
  • preflight_overrides (15-17)
  • preflight_recorder (21-23)
🔍 Remote MCP Deepwiki, Ref

Relevant review facts (concise)

  • Test tooling: pytest-cov was added to dev dependencies; PR expects running tests with coverage (target >90%).,
  • Cmd-mox test stubbing: repository uses cmd-mox IPC to stub cargo/git in BDD tests; tests enable it via LADING_USE_CMD_MOX_STUB and require CMOX_IPC_SOCKET (and optional CMOX_IPC_TIMEOUT). CI must provide/install cmd-mox and set socket for BDD runs.
  • publish behavior change: allow_dirty flag now flows via a new internal _PublishExecutionOptions and is propagated into packaging and cargo publish/package invocations (adds --allow-dirty when set). Call sites updated accordingly. Verify all call sites updated and tests reflect expected command args.
  • Signature/API changes to review: _package_publishable_crates and _publish_crates now accept options: _PublishExecutionOptions (internal dataclass) — ensure no remaining usages still using old params.
  • New/expanded tests: many unit and BDD tests added (publish diagnostics, execution helpers, manifest strategies, config, toml utils, workspace model/metadata). They rely on cmd-mox fixtures and on configuration/context patterns — ensure fixtures/autouse preflight stubbing and test scaffolding are correct.
  • Docs/usage: publish workflow, strip_patches semantics (all / per-crate / false), staging, and README propagation were updated — verify docs match implemented behavior/tests.
  • CI checklist for this PR:
    • Install pytest-cov and run pytest --cov to validate >90% for Phase 4 modules.
    • Ensure cmd-mox is available and CMOX_IPC_SOCKET is set for BDD runs.
    • Run linters/typechecks because small TYPE_CHECKING pragma changes were added across modules.
    • Confirm new internal dataclass _PublishExecutionOptions is not exported unintentionally.
🔇 Additional comments (2)
tests/bdd/steps/test_publish_infrastructure.py (2)

59-67: Keep allow_dirty wiring but verify callers of _create_stub_config use keyword arguments.

Threading allow_dirty through _PreflightStubConfig, PreflightTestContext.create_stub_config, and _create_stub_config is coherent and matches the Phase 4 publish semantics. _create_stub_config is now keyword‑only for allow_dirty, so any direct call sites that previously passed it positionally will now fail.

Run a quick search and update any direct _create_stub_config usages to pass allow_dirty by name if they exist outside this file.

#!/bin/bash
# Verify all _create_stub_config call sites use keyword arguments for allow_dirty.
rg "_create_stub_config" -n

Also applies to: 77-81, 158-171


293-297: Approve additional coverage for cargo publish normalisation.

Extend the parametrised test with the ("cargo", "publish", "--allow-dirty", "--dry-run") case and assert the normalised program/args tuple exactly matches the new _normalise_cmd_mox_command behaviour. This gives direct coverage for the allow_dirty+--dry-run path and looks correct.

Comment thread tests/bdd/steps/test_publish_infrastructure.py
Comment thread tests/bdd/steps/test_publish_infrastructure.py
@leynos

leynos commented Dec 8, 2025

Copy link
Copy Markdown
Owner Author

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

tests/bdd/steps/test_publish_infrastructure.py

Comment on lines +244 to +249

def _build_env_restore_dict(var_name: str) -> dict[str, str]:
    """Build a dictionary for restoring an environment variable."""
    previous = os.environ.get(var_name)
    if previous is None:
        return {}
    return {var_name: previous}

❌ New issue: Deep, Nested Complexity
_build_env_restore_dict has a nested complexity depth of 4, threshold = 4

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Avoid processing more than one cargo publish command in preflight checks to ensure correct test behavior.

Co-authored-by: terragon-labs[bot] <terragon-labs[bot]@users.noreply.github.com>

@codescene-delta-analysis codescene-delta-analysis 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.

Gates Passed
6 Quality Gates Passed

See analysis details in CodeScene

Absence of Expected Change Pattern

  • lading/lading/commands/publish.py is usually changed with: lading/tests/bdd/steps/test_publish_steps.py

Quality Gate Profile: Pay Down Tech Debt
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

@leynos
leynos merged commit 2156cf2 into main Dec 8, 2025
3 checks passed
@leynos
leynos deleted the terragon/phase4-stabilisation-testing-docs-aem45j branch December 8, 2025 01:14
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