Metadata-Version: 2.4
Name: petrosa-contracts
Version: 0.1.0
Summary: Canonical shared pydantic contracts (Signal, TradingConfig) for the Petrosa trading path
Author-email: Petrosa Team <dev@petrosa.com>
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.0.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"

# petrosa-contracts

Canonical, shared `pydantic` contracts for the Petrosa trading path.

This package resolves petrosa_k8s#1116: `contracts/signal.py` and
`contracts/trading_config.py` were copy-pasted into `petrosa-cio/` and
`petrosa-tradeengine/` and had diverged in both directions (CIO had
`leverage`, tradeengine had `decision_id`; the `TradingConfigAudit.config_type`
enum differed). One of those divergences (`leverage` reaching tradeengine)
was the direct cause of `petrosa-tradeengine#599` — a P0 where every position
traded at a hardcoded 10x leverage because the field was silently dropped by
`extra="ignore"`.

## What's here

- `petrosa_contracts.signal.Signal` and its enums (`SignalType`,
  `SignalStrength`, `TimeFrame`, `OrderType`, `TimeInForce`, `StrategyMode`) —
  the reconciled superset of both repos' `Signal` models, with both
  `leverage` and `decision_id`.
- `petrosa_contracts.trading_config.TradingConfig`, `TradingConfigAudit`,
  `LeverageStatus` — the reconciled superset, with `TradingConfigAudit`
  supporting all four `config_type` values (`global`, `symbol`,
  `symbol_side`, `strategy`).
- Every model sets `model_config = ConfigDict(extra="forbid")`. A producer
  field with no matching consumer attribute now raises `ValidationError` at
  parse time instead of being silently discarded.

## Installation

Install the published package from PyPI:

```bash
pip install petrosa-contracts
```

For local development only, contributors with access to the private repository may
install directly from the source tree:

```bash
pip install "petrosa-contracts @ git+https://github.com/PetroSa2/petrosa_k8s.git@main#subdirectory=petrosa-contracts"
```

This private-repository URL requires repository access and must not appear in a public
consumer's `requirements.txt`. Tags named `petrosa-contracts-vX.Y.Z` trigger the
publication workflow.

## Usage

```python
from petrosa_contracts import Signal, TradingConfig

signal = Signal(
    strategy_id="orderbook_skew",
    symbol="BTCUSDT",
    action="buy",
    confidence=0.82,
    price=65000.0,
    quantity=0.01,
    current_price=65000.0,
    source="petrosa-cio",
    strategy="orderbook_skew",
    leverage=5,
    decision_id="a1b2c3d4e5f6",
)

# Any field neither producer nor consumer declared now raises immediately:
Signal(**{**signal.model_dump(), "unexpected_field": 1})
# -> pydantic.ValidationError: Extra inputs are not permitted
```

## Scope of petrosa_k8s#1116 covered by this package

This PR creates the canonical package and its contract tests
(petrosa_k8s#1116 AC: "exist in exactly one place", "superset reconciling
both divergences", "`extra=forbid`", "contract test in CI"). It does
**not** yet remove the vendored copies from `petrosa-cio/contracts/` and
`petrosa-tradeengine/contracts/` or switch those services to import from
this package — that requires coordinated, staged changes in each of those
repos' own CI/deploy pipelines and is tracked as follow-up work:

- `petrosa-cio`: migrate to `petrosa_contracts`, delete the vendored copy.
- `petrosa-tradeengine`: migrate to `petrosa_contracts`, delete the vendored
  copy.

Both follow-ups should keep the same staged-rollout discipline the parent
ticket calls for (log-then-enforce) for any field this package's
`extra="forbid"` newly rejects that either service's real traffic still
sends.

## Development

```bash
cd petrosa-contracts
pip install -e ".[dev]"
pytest --cov=petrosa_contracts --cov-report=term-missing
ruff check src/ tests/
ruff format --check src/ tests/
```
