Skip to content

base

base

Base classes and protocols for remedies.

Defines the Remedy protocol and supporting types that all concrete remedy implementations must follow.

Classes

RemedyCategory

Bases: str, Enum

Determines how a remedy is applied.

AUTOMATIC: Applied without asking (safe, reversible operations) SUGGESTED: Requires user confirmation (modifies files) DIAGNOSTIC: Cannot auto-fix, provides guidance only

RiskLevel

Bases: str, Enum

Risk level of applying the remedy.

Used to inform users about the potential impact of the fix.

RemedyResult dataclass

RemedyResult(success, message, action_taken, rollback_command=None, created_paths=list(), modified_files=list(), backup_paths=list())

Result of applying a remedy.

Tracks what was done and how to undo it if needed.

Attributes
success instance-attribute
success

Whether the remedy was applied successfully.

message instance-attribute
message

Human-readable description of what happened.

action_taken instance-attribute
action_taken

Brief description of the action taken.

rollback_command class-attribute instance-attribute
rollback_command = None

Shell command to undo the remedy (if possible).

created_paths class-attribute instance-attribute
created_paths = field(default_factory=list)

Paths that were created by the remedy.

modified_files class-attribute instance-attribute
modified_files = field(default_factory=list)

Files that were modified by the remedy.

backup_paths class-attribute instance-attribute
backup_paths = field(default_factory=list)

Backup files created before modification.

Functions
__str__
__str__()

Human-readable string representation.

Source code in src/marianne/healing/remedies/base.py
def __str__(self) -> str:
    """Human-readable string representation."""
    status = "✓" if self.success else "✗"
    return f"[{status}] {self.action_taken}: {self.message}"

Remedy

Bases: Protocol

Protocol for remediation actions.

Remedies diagnose specific error patterns and can optionally apply fixes. Each remedy must implement: - name: Unique identifier - category: AUTOMATIC, SUGGESTED, or DIAGNOSTIC - risk_level: LOW, MEDIUM, or HIGH - description: Human-readable explanation - diagnose(): Check if this remedy applies - preview(): Show what would change - apply(): Make the actual changes - rollback(): Undo changes if needed - generate_diagnostic(): Provide guidance for manual fix

Attributes
name property
name

Unique identifier for this remedy.

category property
category

How this remedy should be applied.

risk_level property
risk_level

Risk level of applying this remedy.

description property
description

Human-readable description of what this remedy does.

Functions
diagnose
diagnose(context)

Check if this remedy applies to the error.

Returns Diagnosis if applicable, None otherwise. The diagnosis includes confidence score and fix suggestion.

Parameters:

Name Type Description Default
context ErrorContext

Error context with diagnostic information.

required

Returns:

Type Description
Diagnosis | None

Diagnosis if this remedy can help, None otherwise.

Source code in src/marianne/healing/remedies/base.py
def diagnose(self, context: "ErrorContext") -> "Diagnosis | None":
    """Check if this remedy applies to the error.

    Returns Diagnosis if applicable, None otherwise.
    The diagnosis includes confidence score and fix suggestion.

    Args:
        context: Error context with diagnostic information.

    Returns:
        Diagnosis if this remedy can help, None otherwise.
    """
    ...
preview
preview(context)

Show what would be changed without making changes.

Parameters:

Name Type Description Default
context ErrorContext

Error context.

required

Returns:

Type Description
str

Human-readable description of planned changes.

Source code in src/marianne/healing/remedies/base.py
def preview(self, context: "ErrorContext") -> str:
    """Show what would be changed without making changes.

    Args:
        context: Error context.

    Returns:
        Human-readable description of planned changes.
    """
    ...
apply
apply(context)

Apply the remedy.

Only called if diagnose() returned a Diagnosis and: - category == AUTOMATIC, or - category == SUGGESTED and user confirmed

Parameters:

Name Type Description Default
context ErrorContext

Error context.

required

Returns:

Type Description
RemedyResult

Result with success status and details.

Source code in src/marianne/healing/remedies/base.py
def apply(self, context: "ErrorContext") -> RemedyResult:
    """Apply the remedy.

    Only called if diagnose() returned a Diagnosis and:
    - category == AUTOMATIC, or
    - category == SUGGESTED and user confirmed

    Args:
        context: Error context.

    Returns:
        Result with success status and details.
    """
    ...
rollback
rollback(result)

Undo the remedy if possible.

Called if remedy was applied but subsequent validation failed.

Parameters:

Name Type Description Default
result RemedyResult

The result from apply().

required

Returns:

Type Description
bool

True if rollback succeeded, False otherwise.

Source code in src/marianne/healing/remedies/base.py
def rollback(self, result: RemedyResult) -> bool:
    """Undo the remedy if possible.

    Called if remedy was applied but subsequent validation failed.

    Args:
        result: The result from apply().

    Returns:
        True if rollback succeeded, False otherwise.
    """
    ...
generate_diagnostic
generate_diagnostic(context)

Generate detailed diagnostic message.

Called for DIAGNOSTIC category, or when user declines SUGGESTED.

Parameters:

Name Type Description Default
context ErrorContext

Error context.

required

Returns:

Type Description
str

Formatted guidance for manual fix.

Source code in src/marianne/healing/remedies/base.py
def generate_diagnostic(self, context: "ErrorContext") -> str:
    """Generate detailed diagnostic message.

    Called for DIAGNOSTIC category, or when user declines SUGGESTED.

    Args:
        context: Error context.

    Returns:
        Formatted guidance for manual fix.
    """
    ...

BaseRemedy

Base class providing common remedy functionality.

Concrete remedies can inherit from this to get default implementations of common methods.

Attributes
name property
name

Override in subclass.

category property
category

Override in subclass.

description property
description

Override in subclass.

Functions
diagnose
diagnose(context)

Override in subclass.

Source code in src/marianne/healing/remedies/base.py
def diagnose(self, context: "ErrorContext") -> "Diagnosis | None":
    """Override in subclass."""
    raise NotImplementedError
preview
preview(context)

Default preview implementation.

Source code in src/marianne/healing/remedies/base.py
def preview(self, context: "ErrorContext") -> str:
    """Default preview implementation."""
    return f"Would apply remedy: {self.name}"
apply
apply(context)

Override in subclass.

Source code in src/marianne/healing/remedies/base.py
def apply(self, context: "ErrorContext") -> RemedyResult:
    """Override in subclass."""
    raise NotImplementedError
rollback
rollback(result)

Default rollback - remove created paths.

Source code in src/marianne/healing/remedies/base.py
def rollback(self, result: RemedyResult) -> bool:
    """Default rollback - remove created paths."""
    if not result.created_paths:
        return False

    all_removed = True
    for path in reversed(result.created_paths):
        try:
            if path.is_file():
                path.unlink()
            elif path.is_dir():
                # Only remove if empty
                if not any(path.iterdir()):
                    path.rmdir()
                else:
                    all_removed = False
        except OSError as exc:
            logger.warning("Rollback failed for path %s: %s", path, exc)
            all_removed = False

    return all_removed
generate_diagnostic
generate_diagnostic(context)

Default diagnostic message.

Source code in src/marianne/healing/remedies/base.py
def generate_diagnostic(self, context: "ErrorContext") -> str:
    """Default diagnostic message."""
    return (
        f"Remedy '{self.name}' cannot be automatically applied.\n"
        f"Manual intervention required."
    )