Metadata-Version: 2.4
Name: storm-billing
Version: 0.2.0
Summary: One-line, agent-led install for Storm commercial metering (qualified engineering results — generative CAD & simulation).
Author: Storm Commercial Platform
License: Proprietary
Project-URL: Homepage, https://stormbilling.dev
Project-URL: Documentation, https://stormbilling.dev/llms.txt
Project-URL: Agent Manifest, https://stormbilling.dev/api/agent-manifest
Keywords: storm,metering,billing,ai-engineering,simulation,usage-based
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# `storm-billing`

Dependency-free Python SDK **and** one-line, agent-led installer for Storm's
commercial metering (qualified engineering results — generative CAD & simulation).

```bash
pip install storm-billing
```

This installs a `storm` CLI, an onboarding kit designed to be driven by your coding
agent, and an optional typed SDK:

```bash
storm init                      # write the onboarding kit into your project
storm agent-guide               # runbook + interview the agent asks you
storm adapter inspect SAMPLE    # offline: propose a mapping for your own events
storm doctor                    # read-only config + reachability check
storm provision --plan          # transparent plan; --apply after you approve
storm verify                    # authorization smoke test
```

**This wheel is onboarding and provisioning tooling. It does not need to become a
runtime dependency of your product.** In the customer-hosted topology a pilot
deploys, raw telemetry stays in your own Kafka/MSK log and a digest-pinned Storm
projector reads it; your product runtime makes one synchronous HTTPS call at
operation submission, which you can make with whatever HTTP client you already
have. If you want that call written out for you rather than typed, copy
[`examples/control-client/storm_control_client.py`](../../examples/control-client/storm_control_client.py)
— one file, standard library only.

Reach for the SDK (`from storm_billing import StormClient`) when you want the
accelerators: Shape A event builders, canonical evidence attestation, batch
receipts, deterministic fixtures.

Enterprise-safe by design: a plain PyPI install (no `curl | sh`), a pure-Python wheel with
no install-time code, and no network or mutation until you explicitly run a `storm` command.
See `https://stormbilling.dev/docs/install` for the full flow.

---

## SDK reference

## Integration boundary

The SDK emits raw workflow observations; it cannot declare a result qualified,
billable, accepted, priced, or certified. Storm's versioned deterministic
policy owns qualification.

The customer-facing meter is `qualified_engineering_result`. One contract
catalog covers `DESIGN_GENERATION` and `SIMULATION_ANALYSIS`. A top-level
customer operation earns at most once after terminal technical success,
verified evidence, customer-visible availability inside the product, and a
complexity class derived from locked inputs.

Resource telemetry such as tokens, model/tool calls, solver/GPU/CPU seconds,
storage, retries, and cache hits is retained for cost and margin analysis. It
does not directly set the customer price or create a statement line.

## Compatibility high-throughput client — not the pilot path

`StormEdgeClient` belongs to the earlier Storm-managed data plane and to the
throughput benchmarks. A customer-hosted pilot does not use it, and onboarding
never configures it. It is retained and supported for deployments already on that
topology; described here so the behaviour is documented, not to recommend it.

It preserves the same submission identity and encoded body across transient
retries and does not make one remote request per event. The first
production-shaped pilot instead keeps raw telemetry
in the customer's Kafka/MSK log and runs Storm's digest-pinned projector in the
customer account.

- Embedded mode returns `LOCAL_WAL` after the local encrypted WAL durability
  boundary.
- Agentless mode returns `REMOTE_LOG` only after the replicated log
  acknowledges the batch; a partition fails fast.
- Durable acceptance does not mean the result qualified.

Batching support by itself is not a throughput claim. A retained
`AWS_PRODUCTION_LIKE` run measured the replicated-ingress tier at 1,071,440
events/second over about 600 seconds for the 1-KiB profile with zero measured log
loss; it did not prove real-time commercial-path completion at that rate.

```python
import os

from storm_metering import (
    StormClient,
    StormEdgeClient,
    engineering_operation_started_event,
    engineering_resource_recorded_event,
    engineering_result_available_event,
    engineering_result_completed_event,
)

customer_id = "nova-propulsion"
customer_operation_id = "operation-wing-design-001"
work_item_id = "wing-design-001"
input_fingerprint = "a" * 64
result_content_hash = "b" * 64
complexity = {
    "domain": "aerospace",
    "fidelity": "HIGH_FIDELITY",
    "constraint_count": "180",
    "geometry_feature_count": "4200",
    "assembly_component_count": "240",
    "optimization_candidate_count": "1200",
    "required_evidence_level": "VERIFIED",
}
common = {
    "customer_id": customer_id,
    "customer_operation_id": customer_operation_id,
    "work_item_id": work_item_id,
}

events = [
    engineering_operation_started_event(
        **common,
        event_id="operation-wing-design-001-started",
        time="2026-07-19T18:00:00.000Z",
        commercial_intent="CUSTOMER_REQUESTED",
        result_type="DESIGN_GENERATION",
        input_fingerprint=input_fingerprint,
        declared_complexity_inputs=complexity,
        qualification_deadline_at="2026-07-20T18:00:00.000Z",
    ),
    engineering_resource_recorded_event(
        **common,
        event_id="operation-wing-design-001-gpu",
        time="2026-07-19T18:05:00.000Z",
        attempt_id="attempt-001",
        meter="gpu_seconds",
        quantity="720.000000",
        disposition="ORIGINAL",
    ),
    engineering_result_completed_event(
        **common,
        event_id="operation-wing-design-001-completed",
        time="2026-07-19T18:12:00.000Z",
        attempt_id="attempt-001",
        result_id="result-wing-design-001",
        result_content_hash=result_content_hash,
        input_fingerprint=input_fingerprint,
        result_type="DESIGN_GENERATION",
        terminal_state="SUCCEEDED",
        design_status="COMPLETE",
        requirements_satisfied=True,
        final_complexity_inputs=complexity,
        operation_started_at="2026-07-19T18:00:00.000Z",
        operation_completed_at="2026-07-19T18:12:00.000Z",
        evidence_refs=["verified-evidence-record-001"],
        tool_version="design-tool-2026.1",
    ),
    engineering_result_available_event(
        **common,
        event_id="operation-wing-design-001-available",
        time="2026-07-19T18:13:00.000Z",
        result_id="result-wing-design-001",
        result_content_hash=result_content_hash,
        availability="CUSTOMER_VISIBLE",
        result_reference="product://workbench/results/result-wing-design-001",
    ),
]

# Admission is a control-plane decision, not telemetry ingestion. Storm derives
# the price and reserves exact currency; the producer never supplies an amount.
control = StormClient(
    base_url=os.environ["STORM_CONTROL_PLANE_URL"],
    ingest_api_key=os.environ["STORM_TELEMETRY_API_KEY"],
    control_plane_api_key=os.environ["STORM_COMMERCIAL_API_KEY"],
)
admission = control.authorize_engineering_operation(events[0])
if not admission["allowed"]:
    raise RuntimeError(
        f"Engineering operation denied: {admission['reason']}"
    )

edge = StormEdgeClient(
    edge_url=os.environ["STORM_EDGE_URL"],
    edge_token=os.environ["STORM_EDGE_TOKEN"],
    # Prefer gzip for a regional/agentless hop; local sidecars may use "none".
    compression="gzip",
)
receipts = edge.submit_events(
    events,
    submission_id="operation-wing-design-001-workflow",
)
```

For `SIMULATION_ANALYSIS`, provide `convergence_status`, `residual`, and
`max_constraint_violation` instead of design fields. A nonconvergent simulation
cannot earn the commercial result.

Use `StormClient` separately for scoped control-plane operations: central
operation authorization, reservation lookup, evidence, qualification
explanations, statements, CSV download, exports, and settlement destinations.
Admission denial (`402`) is returned as a typed decision; malformed,
unauthorized, and unexpected responses still raise `StormApiError`. Bounded
edge-lease allocation is an explicit experimental compatibility seam, not a
first-pilot requirement. Legacy finalized-simulation and internal-cost helpers
remain for the Postgres compatibility path; new high-throughput integrations
should use the four workflow builders above.

Engineering artifacts stay in customer-owned systems. Send only immutable
hashes, US-resident references, and evidence metadata.

The first deployment profile targets AWS `us-west-2`, but the SDK makes no
assumption about your cloud. It depends only on Storm's HTTP contracts and does
not embed an AWS dependency.

See `docs/api-contract.md`, `docs/architecture/high-throughput-data-plane.md`,
`https://stormbilling.dev/docs/data-plane`, and
`openapi/storm-agent-api.openapi.json`.
