Metadata-Version: 2.4
Name: missilya-sdk-sandbox
Version: 0.2.0
Summary: MISSILYA GROUP Sandbox SDK — API-identical, deterministic, no-side-effect twin of missilya-sdk for development and CI.
Project-URL: Homepage, https://github.com/MISSILYA-GROUP/MISSILYA-SANDBOX-SDK
Project-URL: Documentation, https://github.com/MISSILYA-GROUP/MISSILYA-SANDBOX-SDK/tree/main/docs
Project-URL: Changelog, https://github.com/MISSILYA-GROUP/MISSILYA-SANDBOX-SDK/blob/main/CHANGELOG.md
Author-email: MISSILYA GROUP <dev@missilya.com>
License: MISSILYA GROUP — PROPRIETARY LICENCE (SOURCE-AVAILABLE)
        
        Copyright (c) 2026 MISSILYA GROUP. All rights reserved.
        
        This software and its source code are the proprietary property of MISSILYA GROUP.
        They are published on a public package index for distribution convenience only.
        Publication does not place this software in the public domain, does not make it
        open source, and grants no rights beyond those stated below.
        
        GRANT
          You are granted a non-exclusive, non-transferable, revocable licence to
          download, install and execute unmodified copies of this package for the sole
          purpose of interoperating with MISSILYA GROUP services under a valid
          commercial agreement with MISSILYA GROUP.
        
        RESTRICTIONS
          Without prior written authorisation from MISSILYA GROUP you may not:
            (a) copy, reproduce or redistribute the source code, in whole or in part;
            (b) modify, adapt, translate or create derivative works;
            (c) reverse engineer, decompile or disassemble, except to the extent this
                restriction is unenforceable under applicable law;
            (d) use the source code, its structure, or its interfaces to build a
                competing or substantially similar product;
            (e) remove or alter any proprietary notice.
        
        NO WARRANTY
          THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
          IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
          FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
        
        LIMITATION OF LIABILITY
          IN NO EVENT SHALL MISSILYA GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
          LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
        
        Licensing enquiries: dev@missilya.com
License-File: LICENSE
Keywords: missilya,mock,sandbox,sdk,testing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: pyjwt>=2.8
Provides-Extra: ai
Provides-Extra: all
Provides-Extra: auth
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Provides-Extra: monitoring
Provides-Extra: notifications
Provides-Extra: payments
Description-Content-Type: text/markdown

# missilya-sdk-sandbox

**MISSILYA GROUP Sandbox SDK** — the API-identical, deterministic, **offline** twin
of [`missilya-sdk`](https://github.com/MISSILYA-GROUP/MISSILYA-CORE-SDK). It installs
under the **same import namespace** (`missilya_sdk`), so application code switches
between real and mock behavior **by which package is installed, not by changing a
single import**.

- **Package:** `missilya-sdk-sandbox`  ·  **Import namespace:** `missilya_sdk`
- **Runtime:** development & CI (mocks, no side effects)
- **Python:** 3.11 – 3.13
- **Production twin:** [`missilya-sdk`](https://github.com/MISSILYA-GROUP/MISSILYA-CORE-SDK)

> **Status:** private, under review. After approval it is published to the MISSILYA
> private pip registry alongside the core package.

---

## Table of contents

1. [What it is & why](#1-what-it-is--why)
2. [Guarantees (forbidden behaviors)](#2-guarantees-forbidden-behaviors)
3. [Install](#3-install)
4. [Usage (identical to core)](#4-usage-identical-to-core)
5. [Deterministic behavior reference](#5-deterministic-behavior-reference)
6. [Configuration](#6-configuration)
7. [How apps swap core ⇄ sandbox by environment](#7-how-apps-swap-core--sandbox-by-environment)
8. [Parity contract](#8-parity-contract)
9. [Local development](#9-local-development)
10. [Project layout](#10-project-layout)

---

## 1. What it is & why

The sandbox lets developers and CI run application code **safely and for free**. It
keeps the same imports, classes, functions, parameters, and return shapes as
`missilya-sdk`, but instead of calling real providers it returns **deterministic
mocks**. This means:

- Unit tests run with **no network**, **no API cost**, and **no side effects**.
- The same code that runs in production runs in tests — only the installed package
  differs — so tests written against the sandbox validate production logic.
- CI is fast and reproducible (fixtures are stable across runs).

| | Sandbox SDK | Core SDK |
|---|---|---|
| Package | `missilya-sdk-sandbox` | `missilya-sdk` |
| Import | `missilya_sdk` | `missilya_sdk` (same) |
| Where | development / CI | staging / production |
| Behavior | deterministic mocks | real providers via vault |
| Network | never (default) | yes |

---

## 2. Guarantees (forbidden behaviors)

The sandbox **never**:

1. uses a **production** vault environment (it raises if asked to);
2. uses a **live** credential (`sk_live…` / `rk_live…`) — it raises `ValidationError`;
3. creates a **real charge**;
4. sends a **real** email, SMS, or WhatsApp message;
5. requires **internet access** for default unit tests.

It **does** raise the **same typed exceptions** as the core SDK
(`ConfigurationError`, `ValidationError`, `ProviderError`, …), so error-handling
paths are exercised exactly as in production.

---

## 3. Install

```bash
pip install missilya-sdk-sandbox          # everything you need (offline)
pip install "missilya-sdk-sandbox[dev]"   # + pytest / ruff / mypy / build
```

The `[ai]`, `[payments]`, `[notifications]`, `[monitoring]`, `[all]` extras exist
for **parity** with core (so `requirements.txt` matches), but they pull in nothing
extra — the sandbox never needs a provider library.

`requirements-dev.txt`:

```text
missilya-sdk-sandbox==0.1.0
pytest
pytest-asyncio
ruff
mypy
```

---

## 4. Usage (identical to core)

The exact same code you ship to production:

```python
from missilya_sdk.ai.chat import LlmChat, SystemMessage, UserMessage

chat = LlmChat(model="gpt-4o")
chat.add_message(SystemMessage("Be concise."))
chat.add_message(UserMessage("Hello"))
print(chat.chat())          # -> "[sandbox:gpt-4o] Hello"   (deterministic)
```

```python
from missilya_sdk.payments.stripe import StripeCheckout
from missilya_sdk.payments.checkout import CheckoutSessionRequest

session = StripeCheckout().create_session(CheckoutSessionRequest(
    line_items=[{"price": "price_x", "quantity": 1}],
    success_url="https://app/success",
    cancel_url="https://app/cancel",
))
assert session.url.startswith("https://checkout.sandbox.missilya.com/")  # mock, no charge
```

```python
from missilya_sdk.notifications.email import send_email
result = send_email("user@example.com", "Hi", text="hello")
assert result.status == "logged"   # logged, never actually sent
```

```python
from missilya_sdk.auth.jwt import create_token, verify_token
token = create_token({"sub": "u"})          # real HS256, offline, deterministic
assert verify_token(token)["sub"] == "u"
```

---

## 5. Deterministic behavior reference

| Call | Sandbox result |
|---|---|
| `LlmChat(...).chat()` | `"[sandbox:<model>] <last user message>"` (stable echo) |
| `LlmChat(...).complete()` | `ChatResponse` with computed token counts, `raw={"sandbox": True}` |
| `generate_image(...)` | `ImageResult(url="https://sandbox.missilya.com/fixtures/image.png")` |
| `text_to_speech(...)` | `SpeechResult(audio=<fixture bytes>)` |
| `speech_to_text(...)` | `TranscriptResult(text="This is a sandbox transcript fixture.")` |
| `translate("hi", "FR")` | `TranslationResult(text="[FR] hi")` |
| `generate_video(...)` | `VideoJob(status="queued", job_id="sandbox-video-…")` |
| `StripeCheckout().create_session(...)` | mock `cs_sandbox_…` session, `payment_status="unpaid"` |
| `StripeCheckout().handle_webhook(payload, sig)` | parses JSON payload, no signature check |
| `send_email/sms/whatsapp(...)` | `DeliveryResult(status="logged"/"queued")`, only logged |
| `auth.jwt.*` | real HS256 round-trips (offline, deterministic) |

Auth uses real JWT crypto (deterministic and offline); everything else is a fixture.

---

## 6. Configuration

The sandbox resolves config **offline**:

1. process environment variable (development/test values only)
2. caller-supplied default
3. deterministic fixture `sandbox-<key>` (so a missing secret never crashes a test)

Guards:

- `MISSILYA_ENV=production` → the sandbox **refuses** to run (`ConfigurationError`).
- A live credential in the environment (`sk_live…`) → `ValidationError`.

```bash
# Optional; the sandbox works with no env at all.
MISSILYA_ENV=development
OPENAI_API_KEY=          # test keys only, never sk_live_...
JWT_SECRET=
```

See [`.env.example`](.env.example).

---

## 7. How apps swap core ⇄ sandbox by environment

Pin different packages per environment — the import never changes:

```text
# requirements.txt          (staging / production)
missilya-sdk[ai,payments,notifications,monitoring]==0.1.0

# requirements-dev.txt      (development / CI)
missilya-sdk-sandbox==0.1.0
```

```python
# app code — identical everywhere
from missilya_sdk.ai.chat import LlmChat, UserMessage
```

CI installs the sandbox and runs the suite offline; staging/production installs the
core package and runs against the real vault and providers.

---

## 8. Parity contract

The sandbox and core must expose an **identical public API** for the same version:

- same import namespace (`missilya_sdk`),
- same public modules, classes, functions,
- same function / `__init__` parameter names,
- same return shapes and dataclass fields,
- same typed exceptions,
- same version string (`0.1.0`).

This is verified statically by `repos/sdk-tools/check_sdk_parity.py` (AST-based, no
install required) and enforced as a test. A feature cannot be added to core without
matching sandbox behavior, and vice versa.

---

## 9. Local development

```bash
python -m venv .venv
./.venv/Scripts/python -m pip install -e ".[dev]"   # Windows
# source .venv/bin/activate && pip install -e ".[dev]"   # macOS/Linux

ruff check src tests tools
mypy src/missilya_sdk
pytest -q
python -m build && twine check dist/*
```

---

## 10. Project layout

```
src/missilya_sdk/
├── __init__.py            # public top-level exports (mirrors core)
├── config.py              # offline config; refuses production + live keys
├── context.py             # TenantContext, MissilyaSDK facade
├── exceptions.py          # identical typed error hierarchy
├── ai/                    # chat (deterministic), images, tts, stt, translation, video, _fixtures
├── payments/              # stripe (mock), checkout models
├── notifications/         # email, sms, whatsapp (logged only)
├── auth/                  # jwt (real HS256, offline)
├── vault/                 # offline VaultClient (fixtures, no network)
└── monitoring/            # logging shim, analytics, sentry (no-op)
tests/                     # determinism + no-side-effect + parity tests
tools/check_forbidden_imports.py
.github/workflows/         # test, publish, docker-publish
Dockerfile · repo.classification.yml · .env.example
```

---

## License

Proprietary — © 2026 MISSILYA GROUP. See [LICENSE](LICENSE). Private to MISSILYA
GROUP; redistribution requires written authorization from Yvon Kamach (CEO).
