Metadata-Version: 2.4
Name: gruncellka-porto-features
Version: 0.5.0
Summary: Structured BDD contracts for Porto SDK — shared Gherkin scenarios, fixtures, and errors.json
Author: Oleksandr Tsyba
License-Expression: Apache-2.0
Project-URL: Homepage, https://github.com/gruncellka/porto-features
Project-URL: Repository, https://github.com/gruncellka/porto-features
Project-URL: Issues, https://github.com/gruncellka/porto-features/issues
Project-URL: Changelog, https://github.com/gruncellka/porto-features/blob/main/CHANGELOG.md
Keywords: postal,post,logistics,deutsche post,ukrposhta,la poste,swiss post,pricing,postage,tariffs,zones,restrictions,validation,bdd,gherkin,cucumber,features,fixtures,contract tests,sdk,porto-features,porto-sdk
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: bump2version>=1.0.0; extra == "dev"
Requires-Dist: gherkin-official<23.0.0,>=22.0.0; extra == "dev"
Requires-Dist: gherlint>=0.4.0; extra == "dev"
Requires-Dist: pre-commit>=3.5.0; extra == "dev"
Requires-Dist: pytest>=8.0.0; extra == "dev"
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
Requires-Dist: pyyaml>=6.0.0; extra == "dev"
Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
Requires-Dist: ruff>=0.15.5; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Dynamic: license-file

# Porto Features

[![validation](https://github.com/gruncellka/porto-features/actions/workflows/validation.yml/badge.svg)](https://github.com/gruncellka/porto-features/actions/workflows/validation.yml)
[![codecov](https://codecov.io/gh/gruncellka/porto-features/branch/main/graph/badge.svg)](https://codecov.io/gh/gruncellka/porto-features)

**Shared behavioral contracts for Porto SDK implementations** — Gherkin scenarios, address fixtures, and `errors.json`. This package ships the contract only.

Catalog facts stay in **[porto-data](https://github.com/gruncellka/porto-data)**. This package says *what behavior must hold*, not *what the tariff tables contain*.

---

## Install

```bash
npm install -D @gruncellka/porto-features
# or
pip install "gruncellka-porto-features[dev]"
```

Shipped: `porto_features/errors.json` · `porto_features/features/**/*.feature` · `porto_features/fixtures/**/*.json`

---

## Example

**Core** — shared resolve contract (cross-provider invariants):

```gherkin
@sdk
@core
Feature: Public resolution contract

  Scenario: Destination and weight resolve a Porto without product pin
    Given provider is "deutschepost"
    And I want to send a letter to country "DE"
    And the letter weight is 20 grams
    When I resolve the letter
    Then the resolution should be valid
    And the resolved amount should be a positive number
```

**Provider** — real provider catalog behavior:

```gherkin
@sdk
@provider:deutschepost
Feature: Deutsche Post resolution

  Scenario: Resolve 20 g domestic to standardbrief
    Given provider is "deutschepost"
    And I want to send a letter to country "DE"
    And the letter weight is 20 grams
    When I resolve the letter
    Then I should get product with id "standardbrief"
```

```text
core       → cross-provider contract
providers  → provider catalog contract
adapters   → wire / execution contract
```

Canonical Gherkin phrases: [docs/vocabulary.md](docs/vocabulary.md).

---

## Layout

```text
porto_features/
├── errors.json                         # PORTO_* catalog
├── features/
│   ├── sdk/
│   │   ├── core/                       # @sdk @core
│   │   └── providers/{id}/             # @sdk @provider:{id}
│   └── adapters/{id}/{wire}/           # @adapters @provider:{id} @wire:{id}
│       ├── marks.feature
│       └── errors.feature
└── fixtures/addresses/
```

Tags: [docs/scenarios.md](docs/scenarios.md).

---

🔳 gruncellka
