Metadata-Version: 2.4
Name: florecon-host
Version: 0.3.0
Summary: The Python host for florecon: a generic wasmtime embedder that drives self-describing reconciliation plugins. Brings its own plugin wasm; imports as `florecon`. Nothing created, nothing lost.
License: MIT
Project-URL: Homepage, https://github.com/spoj/florecon
Project-URL: Repository, https://github.com/spoj/florecon
Project-URL: Issues, https://github.com/spoj/florecon/issues
Keywords: reconciliation,finance,matching,wasm,min-cost-flow
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Rust
Classifier: Topic :: Office/Business :: Financial :: Accounting
Classifier: Topic :: Scientific/Engineering :: Mathematics
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: wasmtime>=20
Requires-Dist: pyarrow>=14

# florecon (Python host)

A generic [wasmtime](https://github.com/bytecodealliance/wasmtime-py) host that
drives self-describing **florecon** reconciliation plugins. The host knows
nothing about any domain: it loads a plugin `.wasm`, reads its `describe()`, and
ships the raw columns the plugin declares. The same code runs every florecon
plugin.

Money is integer minor units; nothing is created or lost.

## Authoring a plugin

This package also ships the `florecon` CLI, so you can build a plugin without
cloning the florecon repo:

```bash
florecon new my-recon       # scaffold a Rust plugin (needs a Rust toolchain)
cd my-recon
florecon author             # fast native loop on data/sample.csv
florecon ship               # build the production solver.wasm
```

Then load `target/wasm32-unknown-unknown/release/solver.wasm` with the host
below. See the scaffolded `README.md` for the full journey.

## Running a plugin

```python
from florecon import Workspace

ws = Workspace("interco_plugin.wasm")     # any florecon plugin wasm

ws.upsert(
    {"row_id": 1, "company": "A", "icp": "B", "objsub": "61500",
     "indicative_usd_amt": 100.0, "trx_currency": "USD", "trx_amt": 100.0,
     "gl_date": 0, "reference": "INV0001"},
    {"row_id": 2, "company": "B", "icp": "A", "objsub": "61500",
     "indicative_usd_amt": -100.0, "trx_currency": "USD", "trx_amt": 100.0,
     "gl_date": 1, "reference": "INV0001"},
)
rep = ws.solve()              # the proposal: groups + per-row allocations
ws.pin_clean(tol=0)           # sign off every clean net-zero match
ws.solve()                    # warm re-solve; pinned groups kept verbatim
```

## Surface

A group lives on a lifecycle axis — `proposed` (the solver's current opinion,
recomputed each `solve`) or `pinned` (your decision, kept verbatim).

```text
ledger      upsert(*rows) · remove(*ids)
machine     solve()
lifecycle   pin(gid) · pin_clean(tol) · pin_singletons(ids) · unpin(gid)
partition   merge(allocs, label, reason) · detach(gid, ids) · dissolve(gid)
read        report()
```

Failures raise `PluginError` carrying a stable `code` (e.g. `"frozen_group"`,
`"conservation_violated"`) plus the `id` / `group_id` it concerns.
`strict_assignments` / `connected_components` project the allocation hypergraph
into per-row assignments or settlement clusters.

The plugin/host ABI is versioned: the host refuses a wasm whose `abi_version`
differs from `florecon.ABI_VERSION`.
