Skip to content

Extract shared command-failure detail helpers (#102) - #115

Merged
leynos merged 3 commits into
mainfrom
issue-102-shared-command-detail-helper
Jun 10, 2026
Merged

Extract shared command-failure detail helpers (#102)#115
leynos merged 3 commits into
mainfrom
issue-102-shared-command-detail-helper

Conversation

@leynos

@leynos leynos commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #102

  • Add command_detail(stdout, stderr) and with_detail(message, stdout, stderr, *, separator=": ") to lading/utils/process.py — the canonical home for the command-failure detail idiom.
  • Convert all duplicated sites: lockfile.py (3×), publish_preflight.py (3×), publish_index_check.py, bump_lockfiles.py, and workspace/metadata.py. No inline (stderr or stdout).strip() remains.
  • Semantics: strip before choosing (matching metadata.py's previous behaviour) — a whitespace-only stderr now falls back to stdout rather than yielding an empty detail. with_detail accepts a separator so the auxiliary-build site keeps its "; " join.
  • Document the helpers in docs/developers-guide.md.

Testing

  • Hypothesis property tests over (stdout, stderr) pairs: stderr wins when non-empty after strip, stdout is the fallback, no suffix when both strip empty, output always stripped.
  • New tests/unit/test_command_failure_messages.py snapshots the rendered failure messages at each consuming boundary (cargo preflight, package/publish, lockfile refresh/regeneration, cargo metadata) so the extraction cannot silently change operator-facing text.
  • make check-fmt, make lint, make typecheck, and make test (563 passed) all green.
  • coderabbit review --agent: 0 findings.

🤖 Generated with Claude Code

Summary by Sourcery

Centralize command-failure detail formatting in shared helpers and update all call sites to use them while preserving operator-facing messages.

Enhancements:

  • Introduce shared process helpers for deriving and appending command output details from stdout/stderr, and export them from the process utilities module.
  • Refactor command and lockfile-related commands to use the shared helpers for consistent failure messages and slightly improved stderr/stdout selection semantics.
  • Add snapshot coverage to pin operator-facing failure messages across commands and cargo metadata invocation behavior.

Documentation:

  • Document the new command-failure detail helpers and their required usage in the developer guide.

Tests:

  • Add Hypothesis-based property tests for the command detail helpers and snapshot tests for command-failure messages to guard against regressions.

The "render command-failure detail" idiom — pick stderr, fall back to
stdout, strip, and conditionally append to a message — was duplicated
across lockfile.py (3 sites), publish_preflight.py (3 sites),
publish_index_check.py, bump_lockfiles.py, and metadata.py.

Add command_detail() and with_detail() to lading.utils.process as the
canonical home and convert every site. The helpers strip before
choosing, matching metadata.py's existing semantics: a whitespace-only
stderr now falls back to stdout instead of yielding an empty detail.
with_detail() accepts a separator so the auxiliary-build site keeps
its "; " join.

Add Hypothesis property tests covering the helper domain and syrupy
snapshots pinning the rendered failure messages at each consuming
boundary. Document the canonical helpers in the developers' guide.

Closes #102
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6a61b453-1d02-4e57-86ae-542c95cfd97b

📥 Commits

Reviewing files that changed from the base of the PR and between 577c5cd and afea0e0.

📒 Files selected for processing (3)
  • docs/developers-guide.md
  • lading/utils/process.py
  • tests/unit/publish/test_preflight_cargo_runner.py

Summary

Centralises the (stderr or stdout).strip() idiom for command-failure detail formatting by introducing three helper functions to lading/utils/process.py and refactoring all duplicated call sites to use them, closing #102. No execplan/ADR/RFC or separate design document was added by this PR (developers guide updated instead).

Key Changes

  • New helpers in lading/utils/process.py

    • command_detail(stdout, stderr): return stderr.strip() when non-empty, otherwise stdout.strip()
    • append_detail(message, detail, *, separator=": "): append separator + detail only when detail is non-empty
    • with_detail(message, stdout, stderr, *, separator=": "): combine command_detail + append_detail in one call
    • Module docstring and all updated; developers guide (docs/developers-guide.md) documents the canonical idiom.
  • Refactored call sites to use the helpers

    • lading/commands/lockfile.py: use command_detail() and with_detail(); preserves the “not a git repository” skip and the deliberate fallback formatting where needed (special-case kept with explanatory comment).
    • lading/commands/bump_lockfiles.py: use with_detail() for lockfile regeneration errors.
    • lading/commands/publish_index_check.py: use with_detail() for cargo failure messages.
    • lading/commands/publish_preflight.py: use append_detail(), command_detail(), and with_detail(); _verify_clean_working_tree now derives detail once (avoids double-computation).
    • lading/workspace/metadata.py: use command_detail() for cargo metadata failures.

Testing

  • Hypothesis property tests (tests/unit/utils/test_process.py) asserting stripping and selection semantics, conditional appending, and custom separator support.
  • Syrupy snapshot tests added to pin operator-facing command-failure messages:
    • tests/unit/test_command_failure_messages.py (lockfile refresh/regeneration and cargo metadata scenarios)
    • tests/unit/publish/test_preflight_cargo_runner.py (preflight cargo runner failure messages)
  • Unit coverage for append_detail and with_detail added.
  • CrossHair contracts noted in tests.
  • Formatting, lint, typecheck, and unit tests passed (563 tests).

Semantics and Behaviour Guarantees

  • Whitespace is stripped before selection so whitespace-only stderr falls back to stdout.
  • stderr wins when non-empty after strip; otherwise stdout is used; empty result yields an empty detail (no separator appended).
  • append_detail and with_detail accept a configurable separator to preserve non-default joins.
  • Special-case behaviours and operator-facing wording were preserved where intentionally different; review concerns about double-computation and a deliberate fallback in _handle_git_ls_files_failure were addressed and documented in code comments.

Files Touched (high level)

  • docs/developers-guide.md
  • lading/utils/process.py
  • lading/commands/lockfile.py
  • lading/commands/bump_lockfiles.py
  • lading/commands/publish_index_check.py
  • lading/commands/publish_preflight.py
  • lading/workspace/metadata.py
  • tests/unit/utils/test_process.py
  • tests/unit/test_command_failure_messages.py (+ snapshots)
  • tests/unit/publish/test_preflight_cargo_runner.py (+ snapshots)

Walkthrough

Extract helpers command_detail, append_detail and with_detail into lading.utils.process, export them, adopt them across command and workspace modules, add Hypothesis property tests and snapshot tests, and document the canonical usage in the developer guide.

Changes

Command-failure detail helpers refactoring

Layer / File(s) Summary
Core helper functions in process.py
lading/utils/process.py
command_detail(stdout, stderr) returns stripped stderr when non-empty else stripped stdout; append_detail(message, detail, *, separator=": ") appends non-empty detail; with_detail(message, stdout, stderr, *, separator=": ") combines both. Exported via __all__.
Adopt helpers across command & workspace modules
lading/commands/bump_lockfiles.py, lading/commands/lockfile.py, lading/commands/publish_index_check.py, lading/commands/publish_preflight.py, lading/workspace/metadata.py
Replace inline (stderr or stdout).strip() composition with command_detail, append_detail, and with_detail imports and calls; update error-message assembly sites accordingly.
Property-based tests and unit snapshots
tests/unit/utils/test_process.py, tests/unit/test_command_failure_messages.py, tests/unit/publish/test_preflight_cargo_runner.py, tests/unit/__snapshots__/*, tests/unit/publish/__snapshots__/*
Add Hypothesis tests verifying strip and preference semantics, add snapshot tests that pin operator-facing error messages for lockfile, bump, publish preflight and cargo metadata failure scenarios.
Developer guide documentation
docs/developers-guide.md
Document the canonical "Command-failure detail helpers (lading.utils.process)" section, describing helper semantics and instructing specific modules to use them.

Possibly related PRs

  • leynos/lading#63: Touches cargo failure-message formatting in publish_index_check.py; related changes to message construction.
  • leynos/lading#85: Modifies bump_lockfiles.py error-message composition for lockfile regeneration.

"Central helpers take the floor,
stderr whispers, stdout then more.
Tests secure the text,
Docs point to the next—
operator messages unchanged and sure."

🚥 Pre-merge checks | ✅ 20
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The title directly references issue #102 and accurately summarises the main change: extracting shared command-failure detail helpers from duplicated code across the codebase.
Description check ✅ Passed The description comprehensively documents the purpose, approach, semantic changes, testing strategy, and verification steps taken, all clearly related to centralising command-failure detail formatting.
Linked Issues check ✅ Passed The PR fulfils all coding requirements from #102: new helpers in lading/utils/process.py, all six duplicate sites converted, property tests added, snapshot tests guard operator-facing messages, and documentation provided.
Out of Scope Changes check ✅ Passed All changes directly support the objective of centralising command-failure detail helpers. Documentation, tests, and refactoring of all call sites align precisely with #102 scope.
Docstring Coverage ✅ Passed Docstring coverage is 93.10% which is sufficient. The required threshold is 80.00%.
Testing (Overall) ✅ Passed Property tests verify all branches of selection/stripping logic. Snapshot tests pin messages at real integration points. Tests would catch all plausible broken implementations.
User-Facing Documentation ✅ Passed Internal refactoring of command-failure detail helpers; no user-facing changes. Error messages identical per snapshot tests. Developer guide appropriately updated; users-guide correctly unchanged.
Developer Documentation ✅ Passed Three new APIs documented in developers-guide.md with signatures and usage requirements; module docstring updated; NumPy-style docstrings complete; all five specified modules use the helpers.
Module-Level Documentation ✅ Passed All modified modules carry substantive docstrings explaining purpose and component relationships clearly.
Testing (Unit And Behavioural) ✅ Passed 6 unit tests with Hypothesis covering edge cases (empty, whitespace); 4 behavioural tests with real functions and injected runners verifying error paths, not mocks.
Testing (Property / Proof) ✅ Passed Three Hypothesis property tests verify substantive invariants with generated edge cases. Snapshot tests confirm output stability.
Testing (Compile-Time / Ui) ✅ Passed Focused syrupy snapshots at public boundaries with parametrised cases, deterministic content, explicit assertions. Hypothesis tests cover helpers. Trybuild not needed for Python project.
Unit Architecture ✅ Passed Pure helpers centralise (stderr or stdout).strip() in lading.utils.process; all sites use shared helpers; no inline reimplementations; tests verify purity; snapshots exercise real boundaries.
Domain Architecture ✅ Passed Centralises infrastructure-layer command-failure formatting into lading.utils.process. Helpers are pure functions; domain logic isolated; no reimplementations; clear adapter boundary.
Observability ✅ Passed Refactoring centralises failure-detail formatting via pure helpers without altering observability; exception messages are snapshot-tested unchanged and existing logging infrastructure is preserved.
Security And Privacy ✅ Passed Pure string-operation helpers; no credentials in test snapshots; stdout/stderr never logged directly, used in paths, or passed to templates.
Performance And Resource Use ✅ Passed Helper functions perform simple O(n) string operations with bounded inputs; call sites show no repeated work in loops or unbounded resource accumulation; invoked only on error paths.
Concurrency And State ✅ Passed PR introduces only pure utility functions for string formatting with no shared state, concurrency, locks, async, or state-management patterns. The check does not apply to this refactoring.
Architectural Complexity And Maintainability ✅ Passed Justifiably extracts duplicated (stderr or stdout).strip() pattern into three simple pure helpers, updates all call sites, maintains correct layering with no cycles.
Rust Compiler Lint Integrity ✅ Passed This PR contains no Rust code changes; it modifies only Python modules, documentation, and test snapshots. The Rust Compiler Lint Integrity check does not apply to non-Rust changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

📋 Issue Planner

Built with CodeRabbit's Coding Plans for faster development and fewer bugs.

View plan used: #102

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-102-shared-command-detail-helper

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

@sourcery-ai

sourcery-ai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Reviewer's Guide

Centralizes the logic for deriving and appending command-failure detail from stdout/stderr into reusable helpers in lading.utils.process, refactors all call sites to use them (with consistent semantics and minor behavior tweaks), documents the helpers, and adds property and snapshot tests to pin their behavior and operator-facing messages.

File-Level Changes

Change Details Files
Introduce shared helpers for computing and attaching command-failure detail from stdout/stderr and export them from the process utilities module.
  • Add command_detail(stdout, stderr) to choose the most informative stripped stream, preferring stderr and falling back to stdout.
  • Add with_detail(message, stdout, stderr, *, separator=": ") to conditionally append the chosen detail to a base message with a configurable separator.
  • Update all in the process utilities to export the new helpers alongside existing functions.
  • Add Hypothesis-based property tests to verify command_detail and with_detail behavior over arbitrary stdout/stderr combinations, including custom separators.
lading/utils/process.py
tests/unit/utils/test_process.py
Refactor command modules to use the new helpers for consistent error message construction and slightly adjusted detail semantics.
  • Update publish_preflight auxiliary build, git status verification, and cargo preflight error construction to use command_detail/with_detail, preserving custom "; " separator where needed and reusing stderr/stdout selection logic.
  • Change lockfile discovery, refresh, and freshness validation to use command_detail/with_detail, including a clearer fallback message when no detail is present for git ls-files failures.
  • Update publish_index_check cargo failure formatting to delegate to with_detail, removing inline (stderr or stdout).strip() handling.
  • Update bump_lockfiles workspace lockfile regeneration failure messages to use with_detail instead of hand-assembling the suffix.
  • Change CargoMetadataInvocationError in workspace.metadata to use command_detail for stderr/stdout selection before falling back to a status-based message.
lading/commands/publish_preflight.py
lading/commands/lockfile.py
lading/commands/publish_index_check.py
lading/commands/bump_lockfiles.py
lading/workspace/metadata.py
Document the new command-failure helpers and enforce their use across relevant modules.
  • Add a developer-guide section describing command_detail and with_detail semantics, including stripping, stderr preference, and fallback behavior.
  • Explicitly state that command-failure rendering modules must use these helpers instead of reimplementing the (stderr or stdout) idiom.
docs/developers-guide.md
Add snapshot tests to pin operator-facing command-failure messages at key boundaries.
  • Introduce a failing runner stub factory to simulate failing commands with controlled stdout/stderr/exit codes.
  • Add snapshot tests for cargo preflight, package/publish, lockfile refresh/regeneration, and cargo metadata invocation failure messages to ensure the refactor does not change surfaced text.
  • Check in the corresponding snapshot file for the new tests.
tests/unit/test_command_failure_messages.py
tests/unit/__snapshots__/test_command_failure_messages.ambr

Assessment against linked issues

Issue Objective Addressed Explanation
#102 Introduce shared helpers command_detail(stdout, stderr) and with_detail(message, stdout, stderr, ...) in lading.utils.process and refactor all specified call sites (lockfile.py, publish_preflight.py, publish_index_check.py, bump_lockfiles.py, workspace/metadata.py) to use them, eliminating inline (stderr or stdout).strip() command-failure detail logic.
#102 Document the canonical command-failure detail helpers and their semantics (stderr preferred, stdout fallback, strip, conditional suffix) in docs/developers-guide.md.
#102 Add automated tests to cover the helpers’ behavior and their effects on user-facing messages, including Hypothesis property tests over (stdout, stderr) combinations and snapshot tests for representative failure messages.

Possibly linked issues


Tips and commands

Interacting with Sourcery

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

Customizing Your Experience

Access your dashboard to:

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

Getting Help

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review June 10, 2026 11:19
sourcery-ai[bot]

This comment was marked as resolved.

@coderabbitai coderabbitai Bot added the Issue label Jun 10, 2026
@leynos

leynos commented Jun 10, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews resumed.

Resolve the code-review comments on the issue #102 extraction:

- Add `append_detail(message, detail, *, separator=": ")` to
  `lading.utils.process` for appending an already-derived detail, and
  reimplement `with_detail` as the derive-then-append wrapper over it.
  `_verify_clean_working_tree` now derives the detail once (it must
  inspect it to choose the base message) instead of recomputing via
  `with_detail`.
- Refactor `_handle_git_ls_files_failure` to render its message through
  `append_detail` rather than the bespoke `detail or fallback` f-string,
  with a comment explaining why this site keeps a status-code fallback.
- Expand the `process` module docstring to document its purpose, the
  three failure-detail helpers, and the dependent modules that must use
  them.
- Restructure the cross-cutting failure-message snapshots to drive only
  public command entry points (`refresh_lockfile`, `regenerate_lockfiles`,
  `load_cargo_metadata`) with an injected failing runner, so they exercise
  real failure paths rather than calling private formatters with mocks.
  The pre-flight message snapshot moves to its own boundary
  (`_run_cargo_preflight`) in test_preflight_cargo_runner.py; the
  package/publish message is already snapshotted in test_packaging.py.
- Add property and unit coverage for `append_detail`.

All snapshot text is byte-identical to before, so operator-facing
messages are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/developers-guide.md`:
- Around line 454-456: Update the module list to use fully qualified names to
match the rest of the document: replace bare names `lockfile`, `bump_lockfiles`,
`publish_preflight`, `publish_index_check`, and `workspace.metadata` with their
package-qualified counterparts (e.g., `lading.commands.lockfile`,
`lading.commands.bump_lockfiles`, `lading.commands.publish_preflight`,
`lading.commands.publish_index_check`, `lading.workspace.metadata` or the
appropriate `lading.*` paths used elsewhere) so the naming convention matches
examples like `lading.commands.bump` and `lading.commands.bump_output`.

In `@lading/utils/process.py`:
- Around line 73-129: The docstrings for the public helper functions
command_detail, append_detail, and with_detail do not follow the repository's
NumPy-style docstring contract; update each docstring to include explicit
"Parameters" and "Returns" sections (and brief one-line summary) using NumPy
structured format: list each parameter name, type, and short description (e.g.,
message: str — description; stdout: str — description; stderr: str —
description; separator: str, optional — description), and describe the return
value and its type under a "Returns" section (e.g., str — description). Keep
examples if present under an "Examples" section and ensure visibility that these
are public helpers.

In `@tests/unit/publish/test_preflight_cargo_runner.py`:
- Around line 55-61: The test function
test_run_cargo_preflight_failure_message_snapshot currently takes multiple
scalar parameters (tmp_path, snapshot, subcommand, exit_code, stderr); refactor
it to accept a single case object (e.g., a dataclass or dict named something
like case) that bundles subcommand, exit_code, and stderr so the argument count
is reduced; update the parametrize decorator to yield that case object and
adjust references inside the test from subcommand/exit_code/stderr to
case.subcommand/case.exit_code/case.stderr while keeping tmp_path and snapshot
as fixtures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3e5e5d8a-9ea8-4410-ad50-6b7bc6d5f1df

📥 Commits

Reviewing files that changed from the base of the PR and between a07962b and 577c5cd.

📒 Files selected for processing (12)
  • docs/developers-guide.md
  • lading/commands/bump_lockfiles.py
  • lading/commands/lockfile.py
  • lading/commands/publish_index_check.py
  • lading/commands/publish_preflight.py
  • lading/utils/process.py
  • lading/workspace/metadata.py
  • tests/unit/__snapshots__/test_command_failure_messages.ambr
  • tests/unit/publish/__snapshots__/test_preflight_cargo_runner.ambr
  • tests/unit/publish/test_preflight_cargo_runner.py
  • tests/unit/test_command_failure_messages.py
  • tests/unit/utils/test_process.py

Comment thread docs/developers-guide.md Outdated
Comment thread lading/utils/process.py
Comment thread tests/unit/publish/test_preflight_cargo_runner.py
@leynos

leynos commented Jun 10, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

  • In places like _verify_clean_working_tree you compute detail = command_detail(stdout, stderr) and then immediately call with_detail(message, stdout, stderr), which recomputes the same logic; consider either threading the already-derived detail into a small helper or restructuring so the detail is only derived once per failure case.
  • The custom fallback formatting in _handle_git_ls_files_failure (detail or fallback) slightly diverges from the with_detail pattern used elsewhere; if this difference is intentional, a brief code comment there explaining why this site is special would make the behavior clearer for future refactors toward the shared helpers.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check current state of publish_preflight.py for _verify_clean_working_tree
rg -n "command_detail|with_detail|append_detail|_verify_clean_working_tree" lading/commands/publish_preflight.py -A3 -B3

echo "---"

# Check _handle_git_ls_files_failure in lockfile.py
rg -n "command_detail|with_detail|append_detail|_handle_git_ls_files_failure|detail or" lading/commands/lockfile.py -A5 -B3

Length of output: 5714



@leynos — yes, both are resolved.

  1. Double-computation in _verify_clean_working_treedetail = command_detail(stdout, stderr) is now derived once, and append_detail(base_message, detail) is called with that already-derived value. The code includes an explicit comment (lines 324–326) explaining the rationale: the detail must be inspected to choose the base message and appended, so calling with_detail (which would recompute it) is deliberately avoided.

  2. detail or fallback divergence in _handle_git_ls_files_failure — a comment at lines 80–81 now explains the special behaviour: "Unlike the other sites, git may exit non-zero with no output at all, so fall back to the status code before handing the detail to append_detail." The divergence is intentional and documented.

Both concerns are fully addressed.

- Fully-qualify the dependent module names in the developer guide's
  command-failure detail helper section (`lading.commands.lockfile`,
  etc.) to match the document's existing naming convention.
- Add NumPy-style Parameters/Returns sections to the public
  `command_detail`, `append_detail`, and `with_detail` helpers, per the
  repository docstring contract in .rules/python-00.md.
- Bundle the cargo pre-flight failure-message snapshot test's scalar
  parameters into a `_PreflightFailureCase` dataclass, matching the
  case-object pattern already used in that file and reducing the test's
  argument count. Parametrize ids are unchanged, so snapshots are stable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@leynos
leynos merged commit 8537f34 into main Jun 10, 2026
5 checks passed
@leynos
leynos deleted the issue-102-shared-command-detail-helper branch June 10, 2026 13:28
lodyai Bot pushed a commit that referenced this pull request Jul 7, 2026
main's PR #102/#115 added test_lockfile_regeneration_failure_message,
which snapshots regenerate_lockfiles' failure string. That snapshot
pinned the pre-#84 single-error format; this branch (issue #84) now
raises one aggregated LockfileRegenerationError that lists each failed
manifest with its repair command.

Refresh the snapshot to the aggregated message. The test's intent —
verifying the canonical `with_detail` suffix is rendered — is preserved:
the per-manifest line still carries "...with exit code 101: error:
dependency conflict".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extract shared command-failure detail helper (de-duplicate (stderr or stdout).strip())

1 participant