Skip to content

topmark.pipeline.context.policy

topmark / pipeline / context / policy

Policy helpers for interpreting configuration in the pipeline context.

This module centralizes helpers that interpret the effective FrozenPolicy in the context of a single file. Functions here operate on a ProcessingContext instance to decide whether certain operations (for example, inserting into empty files or tolerating mixed newlines) are permitted.

PolicyContext

Bases: Protocol

Minimum context surface required by policy helpers.

status property

status

Current aggregated pipeline status for this file.

is_effectively_empty property

is_effectively_empty

Whether the file image is effectively empty.

Returns whether the decoded, BOM-stripped text image contains no non-whitespace characters. Newlines and other whitespace are allowed. This is the broad notion of "empty" used for most policy decisions.

is_logically_empty property

is_logically_empty

Whether the file is "logically empty".

Returns whether the file is "logically empty": after BOM stripping, it contains optional horizontal whitespace and at most one trailing newline sequence (LF/CRLF/CR), and nothing else. This is a stricter subset of is_effectively_empty and is useful to preserve stable round-trips for files that are effectively placeholders.

is_empty_like property

is_empty_like

Whether a file image is "empty-like".

get_effective_policy

get_effective_policy()

Return the effective policy for this processing context.

Source code in src/topmark/pipeline/context/policy.py
def get_effective_policy(self) -> FrozenPolicy:
    """Return the effective policy for this processing context."""
    ...

is_empty_for_insert

is_empty_for_insert(ctx)

Return whether this file should be treated as "empty" for insertion decisions.

This helper interprets the effective per-type policy setting FrozenPolicy.empty_insert_mode and maps it onto the file's observed state.

The distinction matters because TopMark may need to preserve stable round-trips:

  • A true empty file (0 bytes) is represented by FsStatus.EMPTY.
  • A file can be logically empty (BOM stripped, optional whitespace, optional single trailing newline) even when it is not 0 bytes.
  • A file can be effectively empty (no non-whitespace characters) while containing multiple blank lines.

The selected mode controls which of these categories is considered "empty" when deciding whether inserting a header is allowed.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context (or compatible protocol) providing filesystem status and decoded image emptiness flags.

required

Returns:

Type Description
bool

True if the current file qualifies as empty under the configured insertion mode.

Notes
  • This predicate is only about classification of emptiness for insert gating. It does not check whether insertion is allowed; use allow_insert_into_empty_like for that.
  • FsStatus.EMPTY is always treated as empty, regardless of mode.
Source code in src/topmark/pipeline/context/policy.py
def is_empty_for_insert(ctx: PolicyContext) -> bool:
    """Return whether this file should be treated as "empty" for *insertion* decisions.

    This helper interprets the effective per-type policy setting
    [`FrozenPolicy.empty_insert_mode`][topmark.config.policy.FrozenPolicy]
    and maps it onto the file's observed state.

    The distinction matters because TopMark may need to preserve stable round-trips:

    - A *true empty* file (0 bytes) is represented by ``FsStatus.EMPTY``.
    - A file can be *logically empty* (BOM stripped, optional whitespace, optional single
      trailing newline) even when it is not 0 bytes.
    - A file can be *effectively empty* (no non-whitespace characters) while containing
      multiple blank lines.

    The selected mode controls which of these categories is considered "empty" when
    deciding whether inserting a header is allowed.

    Args:
        ctx: Processing context (or compatible protocol) providing filesystem status and
            decoded image emptiness flags.

    Returns:
        True if the current file qualifies as empty under the configured insertion mode.

    Notes:
        - This predicate is only about *classification* of emptiness for insert gating.
          It does not check whether insertion is allowed; use
          `allow_insert_into_empty_like` for that.
        - ``FsStatus.EMPTY`` is always treated as empty, regardless of mode.
    """
    policy: FrozenPolicy = ctx.get_effective_policy()
    mode: EmptyInsertMode = policy.empty_insert_mode
    if mode == EmptyInsertMode.BYTES_EMPTY:
        return ctx.status.fs == FsStatus.EMPTY
    if mode == EmptyInsertMode.LOGICAL_EMPTY:
        return ctx.is_logically_empty or ctx.status.fs == FsStatus.EMPTY
    # EmptyInsertMode.WHITESPACE_EMPTY
    return ctx.is_effectively_empty or ctx.status.fs == FsStatus.EMPTY

is_empty_for_insert_unchanged_by_default

is_empty_for_insert_unchanged_by_default(ctx)

Return True when an insertion-empty file should default to UNCHANGED.

This helper is for bucketing/reporting, not mutation.

It captures the default policy interpretation for files that are classified as "empty for insertion":

  • If the file counts as empty under is_empty_for_insert(ctx), and
  • policy does not allow inserting into such files,

then TopMark should generally treat the file as compliant / unchanged rather than as "missing header".

This avoids surprising "would insert" or "missing header" outcomes for placeholder files such as:

  • true 0-byte files
  • BOM-only files
  • newline-only files
  • other empty-like images covered by the configured EmptyInsertMode

The actual definition of "empty" is delegated to is_empty_for_insert(ctx), so this helper automatically obeys the effective EmptyInsertMode (bytes_empty, logical_empty, or whitespace_empty).

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context (or compatible protocol).

required

Returns:

Type Description
bool

True if the file is classified as empty-for-insert and policy does not

bool

allow inserting into such files; otherwise False.

Notes
  • Use this in outcome bucketing and summaries.
  • Mutation steps should instead use allow_insert_into_empty_like(ctx).
Source code in src/topmark/pipeline/context/policy.py
def is_empty_for_insert_unchanged_by_default(ctx: PolicyContext) -> bool:
    """Return True when an insertion-empty file should default to `UNCHANGED`.

    This helper is for *bucketing/reporting*, not mutation.

    It captures the default policy interpretation for files that are classified
    as "empty for insertion":

    - If the file counts as empty under `is_empty_for_insert(ctx)`, and
    - policy does *not* allow inserting into such files,

    then TopMark should generally treat the file as compliant / unchanged rather
    than as "missing header".

    This avoids surprising "would insert" or "missing header" outcomes for
    placeholder files such as:

    - true 0-byte files
    - BOM-only files
    - newline-only files
    - other empty-like images covered by the configured `EmptyInsertMode`

    The actual definition of "empty" is delegated to `is_empty_for_insert(ctx)`,
    so this helper automatically obeys the effective `EmptyInsertMode`
    (`bytes_empty`, `logical_empty`, or `whitespace_empty`).

    Args:
        ctx: Processing context (or compatible protocol).

    Returns:
        True if the file is classified as empty-for-insert and policy does not
        allow inserting into such files; otherwise False.

    Notes:
        - Use this in outcome bucketing and summaries.
        - Mutation steps should instead use `allow_insert_into_empty_like(ctx)`.
    """
    # First determine whether the current file belongs to the configured
    # "empty for insertion" class.
    if not is_empty_for_insert(ctx):
        return False

    # If the file is empty-for-insert but policy does not permit insertion into
    # that class, it should be treated as compliant / unchanged by default.
    return not allow_insert_into_empty_like(ctx)

allow_insert_into_empty_like

allow_insert_into_empty_like(ctx)

Return True if policy permits inserting a header into an empty-like file.

This is the primary policy gate used by planner/updater when a file has no meaningful body content.

The decision is a conjunction of:

1) whether the file is considered empty for insert (see is_empty_for_insert), and 2) whether the effective policy enables insertion into empty files (FrozenPolicy.allow_header_in_empty_files).

Because this helper delegates classification to is_empty_for_insert, it automatically obeys the configured EmptyInsertMode (bytes_empty, logical_empty, or whitespace_empty).

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context (or compatible protocol).

required

Returns:

Type Description
bool

True if insertion is allowed for this file given its empty-like state and the

bool

effective policy.

Guidance
  • Use this in mutation steps (planner/updater) when deciding whether an insert/update is allowed to proceed.
  • Do not use it to skip reading/analysis steps; those should be governed by filesystem/content feasibility (e.g., unreadable/binary/mixed-newlines).
Source code in src/topmark/pipeline/context/policy.py
def allow_insert_into_empty_like(ctx: PolicyContext) -> bool:
    """Return True if policy permits inserting a header into an empty-like file.

    This is the primary policy gate used by planner/updater when a file has no
    meaningful body content.

    The decision is a conjunction of:

    1) whether the file is considered *empty for insert* (see
       `is_empty_for_insert`), and
    2) whether the effective policy enables insertion into empty files
       (``FrozenPolicy.allow_header_in_empty_files``).

    Because this helper delegates classification to `is_empty_for_insert`, it
    automatically obeys the configured ``EmptyInsertMode`` (`bytes_empty`,
    `logical_empty`, or `whitespace_empty`).

    Args:
        ctx: Processing context (or compatible protocol).

    Returns:
        True if insertion is allowed for this file given its empty-like state and the
        effective policy.

    Guidance:
        - Use this in *mutation* steps (planner/updater) when deciding whether
          an insert/update is allowed to proceed.
        - Do **not** use it to skip reading/analysis steps; those should be governed by
          filesystem/content feasibility (e.g., unreadable/binary/mixed-newlines).
    """
    policy: FrozenPolicy = ctx.get_effective_policy()

    return is_empty_for_insert(ctx) and bool(policy.allow_header_in_empty_files)

allow_empty_header

allow_empty_header(ctx)

Return True if the effective policy allows empty header insertion.

This helper inspects the effective per-type policy (global configuration overlaid by per-type overrides) and reports whether an empty rendered header is considered acceptable.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context containing status and configuration.

required

Returns:

Type Description
bool

True if policy allows rendering an empty header when there are no fields,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def allow_empty_header(ctx: PolicyContext) -> bool:
    """Return True if the effective policy allows empty header insertion.

    This helper inspects the effective per-type policy (global configuration
    overlaid by per-type overrides) and reports whether an empty rendered
    header is considered acceptable.

    Args:
        ctx: Processing context containing status and configuration.

    Returns:
        `True` if policy allows rendering an empty header when there are no fields,
        `False` otherwise.
    """
    policy: FrozenPolicy = ctx.get_effective_policy()

    return policy.render_empty_header_when_no_fields

allow_content_reflow

allow_content_reflow(ctx)

Return True if the effective policy allows content reflow.

This covers transformations that may adjust layout or whitespace around the header region and are controlled by the allow_reflow flag.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context containing status and configuration.

required

Returns:

Name Type Description
bool bool

True if policy allows reflowing content around the header,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def allow_content_reflow(ctx: PolicyContext) -> bool:
    """Return True if the effective policy allows content reflow.

    This covers transformations that may adjust layout or whitespace around
    the header region and are controlled by the ``allow_reflow`` flag.

    Args:
        ctx: Processing context containing status and configuration.

    Returns:
        bool: True if policy allows reflowing content around the header,
        False otherwise.
    """
    policy: FrozenPolicy = ctx.get_effective_policy()

    return policy.allow_reflow

allow_mixed_line_endings

allow_mixed_line_endings(ctx)

Return True if policy allows proceeding despite mixed line endings.

This helper is used by early pipeline steps (e.g., ReaderStep) when the sniffer detected mixed line endings (FsStatus.MIXED_LINE_ENDINGS) and the project policy has opted into tolerating them.

Policy fields
  • If the effective FrozenPolicy defines ignore_mixed_line_endings and it is True, we allow proceeding on MIXED_LINE_ENDINGS.
Notes
  • This function is forward-compatible: it uses getattr(...) so it returns False for unknown fields on older Policy versions (safe default).
  • We always allow when FsStatus is already OK/EMPTY; for EMPTY, your existing allow_insert_into_empty_like() governs header insertion later.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context containing filesystem status and configuration.

required

Returns:

Type Description
bool

True if we may proceed despite mixed line endings,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def allow_mixed_line_endings(ctx: PolicyContext) -> bool:
    """Return True if policy allows proceeding despite mixed line endings.

    This helper is used by early pipeline steps (e.g., ReaderStep) when the
    sniffer detected mixed line endings (`FsStatus.MIXED_LINE_ENDINGS`) and
    the project policy has opted into tolerating them.

    Policy fields:
      - If the effective [`FrozenPolicy`][topmark.config.policy.FrozenPolicy]
        defines `ignore_mixed_line_endings` and it is True,
        we allow proceeding on `MIXED_LINE_ENDINGS`.

    Notes:
      - This function is forward-compatible: it uses `getattr(...)` so it returns
        False for unknown fields on older Policy versions (safe default).
      - We *always* allow when `FsStatus` is already OK/EMPTY; for EMPTY, your
        existing `allow_insert_into_empty_like()` governs header insertion later.

    Args:
        ctx: Processing context containing filesystem status and configuration.

    Returns:
        `True` if we may proceed despite mixed line endings,
        `False` otherwise.
    """
    # Always OK to proceed if FS is healthy or empty (read can still run).
    if ctx.status.fs in {FsStatus.OK, FsStatus.EMPTY}:
        return True

    policy: FrozenPolicy = ctx.get_effective_policy()

    if ctx.status.fs == FsStatus.MIXED_LINE_ENDINGS:
        # Newer policies may provide this flag; default False if absent.
        return bool(getattr(policy, "ignore_mixed_line_endings", False))

    # All other FS states should not be skipped by policy here.
    return False

allow_bom_before_shebang

allow_bom_before_shebang(ctx)

Return True if policy allows proceeding despite a BOM before the shebang.

This helper is used by early pipeline steps (e.g., ReaderStep) when the sniffer detected a BOM before the shebang (FsStatus.BOM_BEFORE_SHEBANG) and the project policy has opted into tolerating it.

Policy fields
  • If the effective FrozenPolicy defines ignore_bom_before_shebang and it is True, we allow proceeding on BOM_BEFORE_SHEBANG.
Notes
  • This function is forward-compatible: it uses getattr(...) so it returns False for unknown fields on older Policy versions (safe default).
  • We always allow when FsStatus is already OK/EMPTY; for EMPTY, your existing allow_insert_into_empty_like() governs header insertion later.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context containing filesystem status and configuration.

required

Returns:

Type Description
bool

True if we may proceed despite a BOM before the shebang,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def allow_bom_before_shebang(ctx: PolicyContext) -> bool:
    """Return True if policy allows proceeding despite a BOM before the shebang.

    This helper is used by early pipeline steps (e.g., ReaderStep) when the
    sniffer detected a BOM before the shebang (`FsStatus.BOM_BEFORE_SHEBANG`)
    and the project policy has opted into tolerating it.

    Policy fields:
      - If the effective [`FrozenPolicy`][topmark.config.policy.FrozenPolicy]
        defines `ignore_bom_before_shebang` and it is True,
        we allow proceeding on `BOM_BEFORE_SHEBANG`.

    Notes:
      - This function is forward-compatible: it uses `getattr(...)` so it returns
        False for unknown fields on older Policy versions (safe default).
      - We *always* allow when `FsStatus` is already OK/EMPTY; for EMPTY, your
        existing `allow_insert_into_empty_like()` governs header insertion later.

    Args:
        ctx: Processing context containing filesystem status and configuration.

    Returns:
        `True` if we may proceed despite a BOM before the shebang,
        `False` otherwise.
    """
    # Always OK to proceed if FS is healthy or empty (read can still run).
    if ctx.status.fs in {FsStatus.OK, FsStatus.EMPTY}:
        return True

    policy: FrozenPolicy = ctx.get_effective_policy()

    if ctx.status.fs == FsStatus.BOM_BEFORE_SHEBANG:
        # Newer policies may provide this flag; default False if absent.
        return bool(getattr(policy, "ignore_bom_before_shebang", False))

    # All other FS states should not be skipped by policy here.
    return False

check_permitted_by_policy

check_permitted_by_policy(ctx)

Whether the active check policy allows the intended header mutation.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool | None
  • True : policy allows the intended change (insert/replace)
bool | None
  • False : policy forbids it (e.g., header_mutation_mode=add_only forbids replace)
bool | None
  • None : indeterminate (no clear intent yet)
Source code in src/topmark/pipeline/context/policy.py
def check_permitted_by_policy(ctx: PolicyContext) -> bool | None:
    """Whether the active check policy allows the intended header mutation.

    Args:
        ctx: Processing context for the current file.

    Returns:
        - True  : policy allows the intended change (insert/replace)
        - False : policy forbids it (e.g., header_mutation_mode=add_only forbids replace)
        - None  : indeterminate (no clear intent yet)
    """
    policy: FrozenPolicy = ctx.get_effective_policy()
    pol_header_mutation_mode: HeaderMutationMode = policy.header_mutation_mode

    if ctx.status.strip != StripStatus.PENDING:
        # StripperStep did run
        return None

    if ctx.status.header == HeaderStatus.PENDING:
        # ScannerStep did not run
        return None

    if pol_header_mutation_mode == HeaderMutationMode.ADD_ONLY:
        # Insert path (missing header)
        if (
            ctx.status.header
            in {
                HeaderStatus.DETECTED,
                HeaderStatus.EMPTY,
                # HeaderStatus.MALFORMED_ALL_FIELDS,
                # HeaderStatus.MALFORMED_SOME_FIELDS,
            }
            # and ctx.status.comparison == ComparisonStatus.CHANGED
        ):
            logger.debug(
                "permitted_by_policy: header: %s, comparison: %s "
                "-- pol_header_mutation_mode: %s, will return False",
                ctx.status.header,
                ctx.status.comparison,
                pol_header_mutation_mode,
            )
            return False  # forbidden when add-only
        else:
            logger.debug(
                "permitted_by_policy: header: %s, comparison: %s "
                "-- pol_header_mutation_mode: %s, will return True",
                ctx.status.header,
                ctx.status.comparison,
                pol_header_mutation_mode,
            )
            return True
    elif pol_header_mutation_mode == HeaderMutationMode.UPDATE_ONLY:
        # Replace path (existing but different)
        if (
            ctx.status.header == HeaderStatus.MISSING
            # and ctx.status.comparison == ComparisonStatus.CHANGED
        ):
            logger.debug(
                "permitted_by_policy: header: %s, comparison: %s "
                "-- pol_header_mutation_mode: %s, will return False",
                ctx.status.header,
                ctx.status.comparison,
                pol_header_mutation_mode,
            )
            return False  # forbidden when update-only
        else:
            logger.debug(
                "permitted_by_policy: header: %s, comparison: %s "
                "-- pol_header_mutation_mode: %s, will return True",
                ctx.status.header,
                ctx.status.comparison,
                pol_header_mutation_mode,
            )
            return True

    # No clear intent yet → unknown
    if ctx.status.header not in {
        HeaderStatus.MISSING,
        HeaderStatus.DETECTED,
    } and ctx.status.comparison not in {
        ComparisonStatus.CHANGED,
        ComparisonStatus.UNCHANGED,
    }:
        logger.debug(
            "permitted_by_policy: header: %s, comparison: %s -- will return None",
            ctx.status.header,
            ctx.status.comparison,
        )
        return None

    logger.debug(
        "permitted_by_policy: header: %s, comparison: %s -- PROCEED",
        ctx.status.header,
        ctx.status.comparison,
    )

    # Unchanged or no-op
    return True

would_change

would_change(ctx)

Return whether a change would occur (tri-state).

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool | None

True if a change is intended (e.g., comparison is CHANGED, a header is missing,

bool | None

or the strip step prepared/attempted a removal), False if definitively no change

bool | None

(e.g., UNCHANGED or strip NOT_NEEDED), and None when indeterminate because the

bool | None

comparison was skipped/pending and the strip step did not run.

Source code in src/topmark/pipeline/context/policy.py
def would_change(ctx: PolicyContext) -> bool | None:
    """Return whether a change *would* occur (tri-state).

    Args:
        ctx: Processing context for the current file.

    Returns:
        ``True`` if a change is intended (e.g., comparison is CHANGED, a header is missing,
        or the strip step prepared/attempted a removal), ``False`` if definitively no change
        (e.g., UNCHANGED or strip NOT_NEEDED), and ``None`` when indeterminate because the
        comparison was skipped/pending and the strip step did not run.
    """
    # Strip intent takes precedence: READY means we intend to remove, and
    # FAILED still represents an intent (feasibility is handled by can_change).
    if ctx.status.strip in {StripStatus.READY, StripStatus.FAILED}:
        return True
    # Default pipeline intents
    if ctx.status.header == HeaderStatus.MISSING:
        return True
    if ctx.status.comparison == ComparisonStatus.CHANGED:
        return True
    if (
        ctx.status.comparison == ComparisonStatus.UNCHANGED
        or ctx.status.strip == StripStatus.NOT_NEEDED
    ):
        return False
    # Anything else (PENDING, SKIPPED, CANNOT_COMPARE with no strip decision)
    return None

can_change

can_change(ctx)

Return whether a mutation can be applied safely for this file.

This helper answers a narrow question:

If the pipeline intends to mutate this file, is that mutation structurally and operationally allowed to proceed?

It combines three categories of checks:

1) Baseline feasibility The file must have resolved successfully, strip preparation must not have failed, and the header state must not be one of the malformed states that block safe mutation.

2) Normal files For ordinary files (FsStatus.OK), mutation is allowed once baseline feasibility is satisfied.

3) Empty / empty-like files For files that are considered "empty for insert", mutation is allowed only when policy explicitly permits inserting into such files. Importantly, emptiness classification is delegated to is_empty_for_insert(ctx), which obeys the configured EmptyInsertMode.

This means: - true 0-byte files may be mutable if policy allows it - logically empty placeholders may be mutable if policy allows it - whitespace-only files may be mutable if policy allows it (depending on EmptyInsertMode)

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool

True if a mutation is structurally and operationally safe to apply,

bool

otherwise False.

Source code in src/topmark/pipeline/context/policy.py
def can_change(ctx: PolicyContext) -> bool:
    """Return whether a mutation can be applied safely for this file.

    This helper answers a narrow question:

    *If the pipeline intends to mutate this file, is that mutation structurally
    and operationally allowed to proceed?*

    It combines three categories of checks:

    1) **Baseline feasibility**
       The file must have resolved successfully, strip preparation must not have
       failed, and the header state must not be one of the malformed states that
       block safe mutation.

    2) **Normal files**
       For ordinary files (`FsStatus.OK`), mutation is allowed once baseline
       feasibility is satisfied.

    3) **Empty / empty-like files**
       For files that are considered "empty for insert", mutation is allowed only
       when policy explicitly permits inserting into such files. Importantly,
       emptiness classification is delegated to `is_empty_for_insert(ctx)`, which
       obeys the configured `EmptyInsertMode`.

    This means:
    - true 0-byte files may be mutable if policy allows it
    - logically empty placeholders may be mutable if policy allows it
    - whitespace-only files may be mutable if policy allows it
      (depending on `EmptyInsertMode`)

    Args:
        ctx: Processing context for the current file.

    Returns:
        True if a mutation is structurally and operationally safe to apply,
        otherwise False.
    """
    # --- 1) Baseline feasibility -------------------------------------------------
    #
    # These checks are independent of "empty-like" policy semantics.
    # If any of them fail, the pipeline should not attempt mutation at all.
    feasible: bool = (
        ctx.status.resolve == ResolveStatus.RESOLVED
        # if strip preparation failed, we can't change via strip:
        and ctx.status.strip != StripStatus.FAILED
        # malformed headers block safe mutation in the default pipeline:
        and ctx.status.header
        not in {
            HeaderStatus.MALFORMED,
            HeaderStatus.MALFORMED_ALL_FIELDS,
            HeaderStatus.MALFORMED_SOME_FIELDS,
        }
    )
    if not feasible:
        return False

    # --- 2) Normal files ---------------------------------------------------------
    #
    # For regular decoded files, baseline feasibility is enough.
    if ctx.status.fs == FsStatus.OK and not is_empty_for_insert(ctx):
        return True

    # --- 3) Empty / empty-like files --------------------------------------------
    #
    # If this file is considered "empty for insert" under the active policy mode,
    # we may only mutate it when insertion into empty-like files is explicitly
    # allowed.
    if is_empty_for_insert(ctx):
        return allow_insert_into_empty_like(ctx)

    # Any remaining filesystem states are not considered safely mutable here.
    return False

would_add_or_update

would_add_or_update(ctx)

Intent for check/apply: True if we'd insert or replace a header.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool

True if a change is structurally and operationally safe,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def would_add_or_update(ctx: PolicyContext) -> bool:
    """Intent for check/apply: True if we'd insert or replace a header.

    Args:
        ctx: Processing context for the current file.

    Returns:
        `True` if a change is structurally and operationally safe,
        `False` otherwise.
    """
    return (
        ctx.status.header == HeaderStatus.MISSING
        or ctx.status.comparison == ComparisonStatus.CHANGED
    )

effective_would_add_or_update

effective_would_add_or_update(ctx)

True iff add/update is intended, feasible, and allowed by policy.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool

True if a change is structurally and operationally safe,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def effective_would_add_or_update(ctx: PolicyContext) -> bool:
    """True iff add/update is intended, feasible, and allowed by policy.

    Args:
        ctx: Processing context for the current file.

    Returns:
        `True` if a change is structurally and operationally safe,
        `False` otherwise.
    """
    return (
        would_add_or_update(ctx)
        and can_change(ctx) is True
        and (check_permitted_by_policy(ctx) is not False)
    )

would_strip

would_strip(ctx)

Intent for strip: True if a removal would occur.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool

True if a change is structurally and operationally safe,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def would_strip(ctx: PolicyContext) -> bool:
    """Intent for strip: True if a removal would occur.

    Args:
        ctx: Processing context for the current file.

    Returns:
        `True` if a change is structurally and operationally safe,
        `False` otherwise.
    """
    return ctx.status.strip == StripStatus.READY

effective_would_strip

effective_would_strip(ctx)

True iff a strip is intended and feasible.

Parameters:

Name Type Description Default
ctx PolicyContext

Processing context for the current file.

required

Returns:

Type Description
bool

True if a change is structurally and operationally safe,

bool

False otherwise.

Source code in src/topmark/pipeline/context/policy.py
def effective_would_strip(ctx: PolicyContext) -> bool:
    """True iff a strip is intended and feasible.

    Args:
        ctx: Processing context for the current file.

    Returns:
        `True` if a change is structurally and operationally safe,
        `False` otherwise.
    """
    # Policy doesn't block strip; feasibility is in can_change
    return would_strip(ctx) and can_change(ctx) is True