Skip to content

bug: keep log sidecar I/O failures from aborting commands #410

Description

@codeforester

Goal

keep log sidecar I/O failures from aborting commands.

Background and evidence

Release-preparation review of 7d8e7d7e902ace88495c5e0ff3b9db4f4a7bf5d2 on macOS arm64. Python 3.13.15, Click 8.5.0, Typer 0.27.2.

The persistent log handler opens and locks its sidecar outside logging.FileHandler.emit error handling. An OSError from sidecar creation/open/locking/unlocking propagates through ctx.log.info, interrupts the handler, and turns an otherwise successful invocation into an unexpected internal error. This undermines the documented best-effort persistence policy.

A deterministic filesystem failure fixture (all paths are temporary):

from pathlib import Path
from tempfile import TemporaryDirectory
import base_cli
from base_cli.testing import invoke

app = base_cli.App(name="log-io-repro")
@app.command()
def main(ctx: base_cli.Context):
    lock = ctx.log_file.with_name("." + ctx.log_file.name + ".lock")
    lock.unlink(missing_ok=True)
    lock.mkdir()  # simulate an unavailable sidecar after successful startup
    ctx.log.info("ordinary command progress")
    print("handler reached end")

with TemporaryDirectory() as d:
    result = invoke(app, [], home=Path(d))
    print(result.exit_code, repr(result.stdout), result.output)

Actual: exit 1, no handler reached end, and Unexpected internal error. Expected: report a persistence warning and preserve command execution/outcome. Disk-full, permissions, and lock failures can reach the same unshielded path without this fixture.

Scope and acceptance criteria

  • Bound ordinary sidecar/open/lock/unlock failures inside the logging persistence boundary.
  • Preserve process-control exceptions according to existing lifecycle rules.
  • Emit a non-recursive diagnostic without retrying through the same broken handler.
  • Add native and attached invocation tests for log I/O failure after startup, including human/JSON output and cleanup; verify the original command status survives.

Validation

Run logging/lifecycle/adversarial tests and the full gate. Inject OSError at open, lock, and unlock, with a healthy-stream control.

Source references:

Non-goals

No release publication or unrelated API redesign. Preserve documented compatibility except for the defective behavior identified above.

Project fields

  • Project: base-cli
  • Status: Ready
  • Priority: P2
  • Area: Runtime
  • Initiative: v1.0 Readiness
  • Size: M
  • Milestone: v1.0.0

Agent assignment

Assignee: @codeforester. Implementation may be handled through the normal issue-backed worktree and reviewed PR workflow.

Activity

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

Metadata

Metadata

Assignees

Labels

bugSomething is not working

Type

No type

Projects

  • Status
    Ready

Relationships

None yet

Development

No branches or pull requests

Issue actions