Metadata-Version: 2.4
Name: osp-provider-runtime
Version: 0.2.20
Summary: Thin runtime harness for OSP providers (RabbitMQ transport + contract execution).
Author: OSP Team
License: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.13
Requires-Dist: loguru<1,>=0.7
Requires-Dist: osp-provider-contracts<0.3,>=0.2.14
Requires-Dist: pika<2,>=1.3
Provides-Extra: dev
Requires-Dist: build<2,>=1.2; extra == 'dev'
Requires-Dist: hatch<2,>=1.14; extra == 'dev'
Requires-Dist: pytest<9,>=8.3; extra == 'dev'
Requires-Dist: ruff>=0.15; extra == 'dev'
Requires-Dist: twine<7,>=6; extra == 'dev'
Requires-Dist: ty>=0.0.18; extra == 'dev'
Description-Content-Type: text/markdown

# osp-provider-runtime

Thin, boring runtime harness for OSP providers.

This package handles RabbitMQ message plumbing so provider implementations can
focus on business logic.

## What it does (v0.1)

- Parses a versioned request envelope.
- Builds provider `RequestContext`/`ProviderRequest` and calls `execute(...)`.
- Serializes a standard response envelope.
- Applies explicit ack/requeue/dead-letter decisions.
- Emits structured logs for delivery decisions.
- Supports explicit runtime knobs for prefetch/concurrency/retries/timeouts/DLQ.
- Accepts contract_v1 request envelopes.
- Provides `ProviderIdentity` so providers derive the same concrete id, RabbitMQ
  queue/binding, routing prefix, and signing id from `PROVIDER`,
  `PROVIDER_INSTANCE`, and optional `PROVIDER_INSTANCE_ID`.

## Provider identity

Use a provider family for permissions and API requests, then add an instance
only when you need a separate runtime lane:

```python
from osp_provider_runtime import ProviderIdentity

identity = ProviderIdentity(
    provider="nrec",
    instance="pr",
    instance_id=37,
)

identity.provider_id      # "nrec_pr_37"
identity.routing_prefix   # "nrec.pr.37"
identity.request_queue    # "provider.nrec.pr.37"
identity.request_binding  # "nrec.pr.37.#"
identity.signing_provider # "nrec_pr"
```

The common case stays small: `ProviderIdentity("vmware", "dev")` gives the
`vmware_dev` provider id and `vmware.dev` routing prefix. Signing deliberately
uses only `provider + instance`, so all `nrec.pr.<id>` runtimes share the
`nrec_pr` signing scope without a separate override knob.

## Result payload conventions

Provider results should keep `ProviderResult.data` focused on the **resolved**
values for the task. The runtime builds the full update payload envelope:

- `requested`: request payload from the orchestrator
- `resolved`: your `ProviderResult.data` (after runtime normalization)
- `provenance`: optional; extracted from `ProviderResult.data["provenance"]`
- `dry_run`: derived from the request payload

Special keys in `ProviderResult.data`:

- `progress_events` (list): lifted into the update payload and removed from
  `resolved` to avoid duplicate TaskEvent rows.
- `provenance` (dict): lifted into the top-level `provenance` field.

Avoid embedding envelope-shaped keys (`requested`, `resolved`,
`request_input`, `request_defaults`) inside `ProviderResult.data`. The runtime
will drop them to keep the stored result compact and predictable.

## What it does not do

- No provider framework.
- No plugin system.
- No workflow orchestration.

## Install

```bash
pip install osp-provider-runtime
```

## Development

```bash
env -u VIRTUAL_ENV uv sync --extra dev
hatch shell
hatch run dev:check
hatch run dev:build
hatch run dev:verify
```

## Runtime Knobs

Set these via `RuntimeConfig` in your provider `runtime_app.py`:

- `prefetch_count` (default `1`)
- `concurrency` (default `1`)
- `max_attempts` (default `5`)
- `idempotency_cache_max_entries` (default `1024`)
- `handler_timeout_seconds` (optional)
- `dead_letter_exchange` (optional)
- `dead_letter_routing_key` (optional)
- `heartbeat_seconds` (default `60`)
- `blocked_connection_timeout_seconds` (default `30`)
- `updates_signing_enabled` (default `False`)
- `updates_signing_kid` (required when signing enabled)
- `updates_signing_secret` (UTF-8 shared secret; set this or `_b64`)
- `updates_signing_secret_b64` (base64-encoded shared secret; preferred for random bytes)

## Update Emission

Use `TaskReporter` for provider task lifecycle updates. The runtime keeps
transport details compatible with orchestrator consumers.

Docs:
- `docs/runtime-contract.md`
- `docs/provider-updates.md`
- `docs/migration-task-reporter.md`
- `docs/runtime-upgrade-checklist.md`
- `docs/release-notes-task-reporter.md`

Tag and push:

```bash
git tag v0.2.0
git push origin v0.2.0
```
