Skip to main content

due-work-harness

Proofs that your background work survives lost messages, dead workers and uncertain external calls — and that the test saying so isn't lying.

Most applications record something now and finish it later: send the confirmation email, generate the thumbnails, publish the post, retry the failed upload. That is due work. Its failures are quiet: the commit lands and the queue message doesn't; a worker dies between sending an email and recording that it did; a stale worker finishes after its replacement and overwrites the newer result. Everything looks fine in a test that runs the happy path once.

due-work-harness states the properties due work must have as executable pytest proofs, and runs them against your production code — whatever queue, job library or workflow engine it uses.

pip install due-work-harness            # the core: pytest and pydantic only
pip install "due-work-harness[django]"  # plus the Django/PostgreSQL integration

What it checks

Crash histories. Give it one transition that hands work off. It runs normal operation to define the outcome, then replays the same transition with every message lost, with the worker killed right after each commit it makes, and killed right after each external call — and requires every history to reach the same outcome. It finds commit boundaries itself; you don't name them.

from due_work_harness import CallableDelivery, ExternalCall, HandoffHistory, assert_crash_at_every_commit_converges


def test_placing_an_order_survives_any_death():
    assert_crash_at_every_commit_converges(
        CallableDelivery(name="orders", recover=run_workers_until_idle),  # what production runs after a crash
        HandoffHistory(
            name="place order",
            arrange=new_cart,
            transition=place_order,  # your real view or service method
            observe=lambda cart: (order_status(cart), mailbox.count(cart)),  # include what external systems saw
            external_calls=(ExternalCall(mailer, "send"),),
        ),
    )

A failure names the history and what it reached:

AssertionError: orders: handoff 'place order': normal operation reaches ('SENT', 1), but these
histories reach something else: {'worker died after external call 1': ('SENT', 2)}. Work was lost
or repeated. ...

Lifecycle profiles. A declarative DueWorkContract binds your production selection, tick and transitions, and requires a disposition — claim, decline with a reason, not applicable, or known gap — for each of six profiles:

Profile The question it answers
A automatic recovery After a lost message, is the work still found? Does anything actually run the sweep, index-served and bounded?
B bounded ownership Who owns the work right now, and what happens when that owner's lease expires?
C crash ambiguity When the provider's answer never arrives, can you tell "never ran" from "maybe ran"?
D durable retention Can a cleanup pass delete work that is still owed?
E eventual convergence When a result lands late, can it overwrite a newer one?
F fact-derived obligations Can product state imply work nothing recorded — and is it still found?

Plus two execution-safety contracts every adopter disposes: replay safety and bounded retry. See what a green result means and the ways a green suite can lie.

Tests that can't be faked green. A conformance suite fails differently from ordinary tests: an adapter that copies production's query, or implements a tiny state machine in the test file, makes every proof measure the copy. The harness refuses test-authored selections and transitions, requires every binding to reach code in your production_packages, forbids waiving its own integrity checks, and pairs every "must not happen" proof with a positive control that shows the same binding would act. When every crash history agrees, recovery must still have changed something — agreement with an inert recovery is not a pass.

Every handoff accounted for

A crash history proves one handoff; the coverage check makes sure none are forgotten. It scans production code for every call that hands work off — on_commit, a Celery .delay, a procrastinate .defer, a DBOS workflow start, a Dramatiq .send, an RQ enqueue, a Django task's .enqueue — attributes each to the exact function that makes it, and requires exactly one disposition per function: a contract suite that insures it, or an exemption that proves losing it costs nothing. Aliases, re-exports and handoffs passed along uncalled are still found, and a declaration counts only if pytest would actually run it; pytest --due-work-verify then checks that it did.

@due_work_contract_suite(ORDER_NOTIFICATIONS, covers=(DueWorkSource(OrderService.place),))
class TestOrderNotificationsDueWork:
    pass
uv run due-work-harness check      # static: imports neither your app nor your tests

In GitHub Actions: gigaverse-app/due-work-harness/check@v0 for the scan, and gigaverse-app/due-work-harness/test@v0 for the generated suites (every generated case carries the due_work mark). The path from uv add to CI is in ADOPTING.md.

Framework-free by construction

The core depends only on pytest and pydantic — no Django, SQLAlchemy, Celery, Procrastinate or DBOS. Proofs take plain callables. The few facts only a framework knows — whether a transaction is open, how to interrupt a commit, what plan a query runs — come from a Host you configure once:

# conftest.py
from due_work_harness import configure
from due_work_harness.integrations.django import django_host

configure(django_host(production_packages={"myapp"}))
Extra Supplies
[django] django_host(): pytest-django marks, the transaction probe, a commit counter that kills the worker after any commit (including writes made through SELECT fn()), PostgreSQL plan inspection, lifecycle-state proofs
[celery] beat-schedule evidence, a publication recorder that holds messages instead of sending them, a publication breaker that refuses one publish as a broker that is down would
[procrastinate] its worker as recovery, "worker died holding this job" arrangement, the documented stalled-job recipe, periodic-task evidence
[dbos] restarting an app through its own startup for process-level crash histories

Where a test can't reach the worker at all — a workflow engine's own executor — process_histories runs the real program in a child process, kills it at named points with os._exit, restarts it the way production would, and applies the same verdict. CI imports every core module with none of the frameworks installed.

Demos: the harness against code we didn't write

demos/ runs the harness against demo applications, and real open-source applications, exactly as their projects ship them, pinned to a commit:

Demo Finding Fix the positive control proves
procrastinate demo_django A worker death between committing the book and deferring its job leaves the book never indexed ATOMIC_REQUESTS = True
index_book holds a transaction across its slow call —
A job whose worker died is never picked up again procrastinate's documented retry_stalled_jobs task
procrastinate itself finish_job does not check the worker: a worker presumed dead finishes a job another worker has since fetched — (a fencing token on finish; reported by the demo's profile B claim)
DBOS transactional-outbox A death after sending the notification, before DBOS records the step, notifies the customer twice an idempotent notification
Saleor checkout With the Payments API, a death between capturing the payment and creating the order charges the customer with no order; after 90 days the payment belongs to nothing Saleor's Transactions API with automatic completion of paid checkouts
A death after the order commits leaves it unconfirmed, its history empty or half-written —
A failing order_created callback, no death at all, makes Django skip the confirmation —
The broker refusing any one of the order's webhooks, no death at all, loses the webhooks after it and the confirmation, and fails the checkout of a paid order —
Automatic completion dispatches a paid checkout again while its completion is still in flight, and reports no backlog —

The coverage scan finds the same handoffs statically: the create view's .defer and index_book's in the procrastinate demo, and DBOS.start_workflow in DBOS's other outbox variant. A handoff made in SQL, as transactional_enqueue.py does, is invisible to a static scan, which is where a crash history takes over.

Demos are teaching code; these are the things to change when copying them into production, and the harness shows each fix working.

Status

Alpha. The proofs were extracted from a production codebase, where they guard its background workflows in CI; the public API may still change before 1.0. Python 3.12+. Architecture: ARCHITECTURE.md.

Development

Managed with uv (uv sync --all-extras), linted with Ruff and type-checked with Pyrefly. See CONTRIBUTING.md.

License

Apache-2.0. See LICENSE.

Metadata

Release files for due-work-harness 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for due-work-harness 0.1.0
File Size Uploaded
due_work_harness-0.1.0.tar.gz 391.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for due-work-harness 0.1.0
File Interpreter ABI Platform
due_work_harness-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 587.1 kB

Release files / due_work_harness-0.1.0.tar.gz

Download URL due_work_harness-0.1.0.tar.gz
Size 391.7 kB
Tags Source
SHA-256 checksum
How to use checksums
367cf6da7610bbce778c204991d8f5fac8c932263b78d96bfb4c616262dd811c
BLAKE2b-256 checksum
How to use checksums
f9e4b1ec4f47de4664e808cbc435b7ebcf1b000d3963f97e93cdc9708d691c23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release files / due_work_harness-0.1.0-py3-none-any.whl

Download URL due_work_harness-0.1.0-py3-none-any.whl
Size 195.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
65d24248a5aca9bef789dcf67c241ae602f2bb6e3fa0da2c6cb0d83cd28e5977
BLAKE2b-256 checksum
How to use checksums
84ebb6b8f9e7daceddcabb13c10c861c3e0d741ec5befa86a1a58cf469931987
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.7.0

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page