Metadata-Version: 2.4
Name: bods-v04-fixtures
Version: 0.1.1
Summary: Canonical Beneficial Ownership Data Standard (BODS) v0.4 fixtures and edge-case conformance suite
Author: Stephen Abbott Pugh
License: MIT
Project-URL: Homepage, https://github.com/StephenAbbott/bods-fixtures
Project-URL: Issues, https://github.com/StephenAbbott/bods-fixtures/issues
Keywords: bods,beneficial-ownership,fixtures,testing
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: validate
Requires-Dist: jsonschema>=4.0; extra == "validate"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0; extra == "dev"
Requires-Dist: jsonschema>=4.0; extra == "dev"
Dynamic: license-file

# bods-fixtures

Canonical BODS v0.4 fixtures and edge-case conformance suite, shared across the
BODS adapter and query-engine ecosystem.

## Why this exists

The [BODS adapter suite](https://github.com/StephenAbbott?tab=repositories&q=bods)
(OpenCorporates, ICIJ, Kyckr, BrightQuery, FtM, AML AI, Lance, Neo4j, GQL…)
currently ships per-repo fixtures. That means each repo decides independently
what "anonymous person" or "circular ownership" looks like, and nothing
validates that an entity observed in two sources produces equivalent BODS.

`bods-fixtures` is the single source of truth:

- a small, curated set of BODS v0.4 statement bundles, each targeting a
  specific semantic edge case
- a co-located `.expected.md` spec per fixture describing what a correct
  adapter / query engine should do with it
- a thin Python loader so adapters can parametrize their test suites against
  the shared pack

## Install

```sh
pip install bods-v04-fixtures
```

The PyPI distribution is `bods-v04-fixtures` — the name makes the version
scope explicit and leaves the generic `bods-fixtures` name available for
future ecosystem-wide tooling. The Python import path is unchanged:
`from bods_fixtures import ...`.

## Usage

```python
from bods_fixtures import load, list_cases

fixture = load("core/01-direct-ownership")
fixture.statements                       # parsed BODS v0.4 statements
fixture.statement_ids                    # all statementIds
fixture.record_ids                       # all recordIds
fixture.by_record_type("person")         # filter by recordType: entity|person|relationship
fixture.find_record("rec-jane-smith-1975")  # look up a record by recordId
fixture.description                      # rendered .expected.md spec

list_cases()                             # all fixtures
list_cases("edge-cases")                 # one category
```

> **BODS v0.4 only.** Fixtures use the canonical `recordType` /
> `recordDetails` envelope and string-based `recordId` references for
> relationships, per the
> [official 0.4 schema](https://standard.openownership.org/en/0.4.0/standard/schema-browser.html).
> Adapters built against the older `statementType` / `describedByEntityStatement`
> shape (BODS v0.3) will need updating before they can consume this pack —
> which is one of the things this pack exists to surface.

### Parametrised tests

```python
import pytest
from bods_fixtures import list_cases, load

@pytest.mark.parametrize("name", list_cases())
def test_my_adapter_round_trips(name):
    fixture = load(name)
    result = my_adapter.convert(fixture.statements)
    assert ...
```

## What's in the pack

Today (v0.1):

| Category     | Case                     | Tests |
|--------------|--------------------------|-------|
| `core`       | `01-direct-ownership`    | baseline: one person, 75% shareholding + voting |
| `edge-cases` | `10-circular-ownership`  | A owns B owns A — UBO resolver termination |
| `edge-cases` | `11-anonymous-person`    | declared-unknown UBO, reason code preserved |

Planned (see [CHANGELOG](CHANGELOG.md) for target versions):

- `core`: person-with-control, entity-owns-entity, multiple-interest-types
- `edge-cases`: indirect chain, threshold boundaries, trust/nominee,
  joint ownership, historical interest, replaced statement
- `cross-border`: multi-jurisdiction chains, bearer shares
- `cross-source`: same entity from ≥2 source adapters, for consistency tests
- `scale`: synthetic 1k / 100k statement bundles for query-engine benchmarks
- `invalid`: deliberately malformed, for negative tests

## Governance

- **Versioning**: semver. A fixture rename, removal, or semantic change bumps
  major. Field additions inside a fixture bump minor. Pure documentation edits
  bump patch.
- **Adding a fixture**: the `.expected.md` is reviewed like a spec change.
  It is the durable record of what the fixture is testing and what correct
  behaviour looks like.
- **Removing a fixture**: requires a deprecation cycle — mark in CHANGELOG one
  major version before removal.

## Validation

The shipped tests are structural (references resolve, IDs unique, BODS version
declared). For full schema validation against the BODS v0.4 JSON schema:

```sh
pip install 'bods-v04-fixtures[validate]'
```

(schema validation suite is a v0.2 deliverable.)

## License

MIT. Fixture content is CC-BY-SA 4.0 to match BODS licensing conventions.
