Skip to main content

Mark unfinished Python code as structured debt that CI can find and refuse to ship.

Project description

sorry

sorry marks unfinished Python code as structured debt that CI can find and refuse to ship.

It is not a productivity aid. It is a nagging conscience for the build pipeline. Standard TODO comments are a graveyard of good intentions. sorry makes them load-bearing: structured metadata, an AST scanner, and a calendar.

Install

pip install pysorry

The distribution is pysorry. The import is sorry.

Mark the hole

Two markers. Use whichever fits the shape of the unfinished thing.

Runtime marker

from sorry import sorry


def reconcile_authority(step):
    return sorry(
        "corrective monotonicity not discharged",
        issue="AG-27",
        owner="agent-gov",
        expires="2026-06-01",
    )

sorry(...) always raises UnprovenObligation (an AssertionError subclass). The return type is NoReturn, so type checkers treat anything after it as unreachable.

Decorator marker

from sorry import unfinished


@unfinished(
    "corrective monotonicity not discharged",
    issue="AG-27",
    expires="2026-06-01",
)
def corrective_never_mints_authority(step) -> bool:
    ...

The decorator runs cleanly at import time. The wrapped function raises UnprovenObligation when called.

Scan the hole

sorry list src tests

Lists every obligation. Always exits 0.

sorry check src tests

Exits 1 if any obligation exists. No warn-only mode. No per-path policy file. The tool is binary by design: either the debt is discharged, or the build is broken.

Metadata

All fields are optional except the reason. All values must be string literals when scanned — non-literal metadata is reported as invalid.

field meaning
reason what is unfinished
issue tracker ID or URL
owner who is responsible
expires ISO date YYYY-MM-DD; valid through that date
basis informal justification or reference

Status

Each obligation lands in one of three buckets:

  • OPEN — unresolved, not yet expired
  • EXPIREDtoday > expires
  • INVALID — non-literal metadata, malformed expires, missing reason, etc.

sorry check fails on any non-empty bucket. Expired and invalid are visually separated in output, but they fail the same gate.

Scanner limitations

The V0 scanner is import-aware but not scope-aware. It tracks from sorry import … and import sorry [as …] at the module level, but it does not model lexical scope. Two consequences:

  • A function-local import (def f(): from sorry import sorry as s) leaks its alias to the rest of the module — calls to s(...) in sibling functions will be reported as obligations.
  • A parameter or local variable named sorry (or matching an alias) shadows the import at runtime, but the scanner will still flag calls to it.

In practice this means: keep sorry imports at the top of the file and don't shadow them with locals. Scope-aware resolution may land in a later release; until then, the limitation is documented and the false-positive shape is predictable.

Non-goals

  • No --warn-only flag.
  • No pyproject.toml policy section.
  • No per-path config.
  • No pytest plugin.
  • No "discharge" subcommand. To discharge an obligation, delete the call.

The tool is meant to stay tiny. If you need governance, build it elsewhere.

License

Licensed under Apache-2.0. See LICENSE and NOTICE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pysorry-0.1.0.tar.gz (16.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pysorry-0.1.0-py3-none-any.whl (12.1 kB view details)

Uploaded Python 3

File details

Details for the file pysorry-0.1.0.tar.gz.

File metadata

  • Download URL: pysorry-0.1.0.tar.gz
  • Upload date:
  • Size: 16.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pysorry-0.1.0.tar.gz
Algorithm Hash digest
SHA256 57fb1bd58d07f136b5034f42fc5c7612490e799e490e4662af8049b0f32a5ae8
MD5 d642bd78b5dce3688bc8d1ca13c73d3f
BLAKE2b-256 bfa48bd647b69231a742d5e4f1188c1885e83b003521abab5704f1ddd6eab4b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysorry-0.1.0.tar.gz:

Publisher: publish.yml on unpingable/pysorry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pysorry-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pysorry-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 12.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pysorry-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7314b1b65875350e87176e49d3526ff21e417d87856004662b1641700aacfb5d
MD5 323d6a7db906de3eda088e332f65388a
BLAKE2b-256 69ffd5da300524f083d419861918ec62cb80ba75cb9b223e91cdefdfc3f83ce7

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysorry-0.1.0-py3-none-any.whl:

Publisher: publish.yml on unpingable/pysorry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page