Skip to content

Acquire apply.lock through one lock_cli helper that takes &GlobalArgs; the sequence is open-coded 9 times and renders lock_held 3 ways #1858

Open

Description

[agent] Filed by the scheduled architecture audit (audit-cli-tests). Register: register comment.

Kind: refactor. Register ID: T09.

Problem

lock_cli has a helper for taking .socket/apply.lock, acquire_or_emit, and its module doc says it exists so "call sites stay one line each". Only 5 sites use it: apply, repair, remove, rollback and vendor. Even those 5 pass the same fields by hand, args.common.json, args.common.dry_run and Duration::from_secs(lock_timeout.unwrap_or(0)).

9 more sites open-code the whole sequence instead: acquire_with_status, then lock_failure, then their own rendering. They are vendor ×2, scan/withdrawn, scan/vendor_flow, scan/hosted, scan/gc ×2, agent_download and get. In total Duration::from_secs(*.lock_timeout.unwrap_or(0)) is written 14 times in the CLI.

The copies have drifted:

  • lock_held is rendered 3 ways for humans:
    • lock_cli format_lock_error prints Error: Another… plus a hint and (Lock file: <path>).
    • vendor eject emit_eject_refusal prints Error (lock_held): another…, with no hint and no path.
    • scan/vendor_flow.rs L995-L1006 prints Error (lock_held): …. plus HELD_RETRY_HINT, with no path.
  • scan/hosted writes the human error under --json too. acquire_hosted_lock always eprint!s the Error: block, even when it also builds the JSON error envelope. agent_download::report_lock_failure and acquire_or_emit suppress it under --json. I found this by reading the code; I did not run it.
  • report_lock_failure is in the wrong module. It lives in agent_download.rs, not lock_cli.rs.

Proposed change

  1. Add GlobalArgs::lock_timeout() -> Duration.
  2. Replace acquire_or_emit(dir, cmd, json, dry_run, timeout) with lock_cli::acquire(common: &GlobalArgs, cmd: Command) -> Result<LockGuard, LockFailure>. It renders through one function: human text to stderr unless --json, and the envelope error otherwise.
  3. Move report_lock_failure into lock_cli.
  4. Route the 9 open-coded sites through lock_cli::acquire. The vendor-eject and vendor_flow renderers go away.
  5. Inline lock_cli's 4 single-caller helpers: emit, waiting_message, held_hint and held_message.

Size

About 12 files under crates/socket-patch-cli/src/commands/, roughly −120 lines.

Acceptance criteria

  • Every lock-held and lock-io exit gives the same errorCode (lock_held/lock_io) and the same exit code as today. The existing lock tests in lock_cli.rs and the CLI lock e2e tests still pass.
  • Human stderr is identical across commands, and nothing goes to stderr under --json. Add one test that runs scan --json against a held lock and asserts that stderr is empty.
  • Drop the subset tests acquire_or_emit_succeeds_on_fresh_dir and held_message_reports_whole_seconds, and fix the doc of error_envelope_propagates_dry_run_and_command, which claims more than it asserts.

Activity

  1. added
    arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)
    refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code
    on Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)priority:p3refactorStructural change: duplicated code or logic, missing abstraction, layering, dead code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions