Metadata-Version: 2.4
Name: demystify-platform-contracts
Version: 0.3.0
Summary: Single source of truth for Demystify cross-cutting wire contracts (Python mirror): error taxonomy, domain events, canonical headers, key format/hashing, currency helpers, key-introspection models.
Project-URL: Homepage, https://github.com/demystify-systems/ai-services-tools/tree/main/packages/platform-contracts
Project-URL: Repository, https://github.com/demystify-systems/ai-services-tools
Author: Demystify Systems
License: MIT
License-File: LICENSE
Requires-Python: >=3.11
Requires-Dist: pydantic<3,>=2
Provides-Extra: dev
Requires-Dist: httpx<1,>=0.27; extra == 'dev'
Requires-Dist: mypy<2,>=1.13; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest<9,>=8; extra == 'dev'
Requires-Dist: ruff<0.9,>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# @demystify/platform-contracts / demystify-platform-contracts

The **single source of truth** for Demystify's cross-cutting wire contracts, shipped as
one dual-language, independently-publishable leaf package:

- **TypeScript** — `@demystify/platform-contracts` (ESM, zod schemas, `.d.ts`)
- **Python** — `demystify-platform-contracts` (pydantic v2 models, src layout)

It depends on **no module** (`modules/*`) and only on `zod` (TS) / `pydantic` (Py), so any
module can take it as a normal versioned dependency AND keep working when copied out
standalone (see [Extractability](#extractability)).

## What it exports

| Concern | TS | Python |
|---|---|---|
| Error taxonomy | `ERROR_CODES`, `ERROR_TYPE_BY_CODE`, `errorEnvelope`, `makeErrorEnvelope` | `ERROR_CODES`, `ERROR_TYPE_BY_CODE`, `ErrorEnvelope`, `make_error_envelope` |
| Domain events (11) | `EVENT_TYPES`, `EVENT_TYPE_IDS`, `EVENT_DATA_SCHEMAS`, `eventEnvelopeSchema(type)` | `EVENT_TYPES`, `EVENT_TYPE_IDS`, `EVENT_DATA_MODELS`, `event_envelope_adapter(type)`, `is_valid_event_envelope` |
| Canonical headers | `HEADERS`, `DEPRECATED_HEADER_ALIASES` | `HEADERS`, `DEPRECATED_HEADER_ALIASES` |
| Key format & hashing | `KEY_PREFIX`, `KEY_FORMAT_RE`, `isValidKeyFormat`, `hashKey`, `keyLast4` | `KEY_PREFIX`, `KEY_FORMAT_RE`, `is_valid_key_format`, `hash_key`, `key_last4` |
| Money / currency | `CURRENCY_EXPONENT`, `toMinorUnits`, `fromMinorUnits` | `CURRENCY_EXPONENT`, `to_minor_units`, `from_minor_units` |
| Key introspection | `introspectRequest`, `introspectResponse`, `AUTH_MODES`, `INTROSPECTION_CACHE_TTL_SECONDS` | `IntrospectRequest`, `IntrospectResponse`, `introspect_response_adapter`, `AUTH_MODES`, `INTROSPECTION_CACHE_TTL_SECONDS` |
| Tracing (W3C) | `TRACEPARENT_RE`, `isValidTraceparent`, `newTraceparent`, `childTraceparent`, `spanName`, `SPAN_ATTR_KEYS` | same, snake_case |

The canonical cross-cutting decisions these encode are documented in
[`CONVENTIONS.md` §14](../../CONVENTIONS.md) and mirrored in
[`docs/contracts/platform-conventions.md`](../../docs/contracts/platform-conventions.md).

## Usage

### TypeScript

```ts
import {
  errorEnvelope,
  HEADERS,
  hashKey,
  eventEnvelopeSchema,
  toMinorUnits,
} from "@demystify/platform-contracts";

const tenant = req.headers[HEADERS.tenant]; // "x-dmstfy-tenant-id"
const atRest = hashKey(plaintextKey); // sha256 hex
const evt = eventEnvelopeSchema("extract.job.completed").parse(payload);
const minor = toMinorUnits(1.23, "USD"); // 123
```

### Python

```python
from demystify_platform_contracts import (
    ErrorEnvelope, HEADERS, hash_key, is_valid_event_envelope, to_minor_units,
)

tenant = request.headers[HEADERS["tenant"]]      # "x-dmstfy-tenant-id"
at_rest = hash_key(plaintext_key)                # sha256 hex
ok = is_valid_event_envelope("extract.job.completed", payload)
minor = to_minor_units(1.23, "USD")              # 123
```

## Contract parity (fixtures)

TS and Python are kept in lock-step by shared JSON fixtures under [`fixtures/`](./fixtures).
Both test suites (`test/*.test.ts`, `tests/test_*.py`) load the same fixtures and assert:
identical `ERROR_CODES` / `EVENT_TYPES` / `HEADERS` / `CURRENCY_EXPONENT`, identical
`hashKey` output, and identical accept/reject behaviour for every envelope, introspection,
key-format and money case. Add a case once in `fixtures/`; both languages must satisfy it.

## Extractability

Modules depend on this package as a normal versioned dependency. To keep a module working
when **copied out standalone**, either:

1. install the published contracts package (`@demystify/platform-contracts` /
   `demystify-platform-contracts`), **or**
2. use the module's existing **vendored** copies of the wire contracts under
   `modules/dmstfy-<x>/docs/contracts/*.md` (these stay in the tree).

To keep the vendored markdown from drifting, this package ships
[`scripts/sync-vendored.mjs`](./scripts/sync-vendored.mjs), which regenerates each module's
`docs/contracts/*.md` from the canonical repo-root `docs/contracts/` (one source of truth):

```bash
node scripts/sync-vendored.mjs           # write vendored copies
node scripts/sync-vendored.mjs --check   # CI: exit 1 on drift
node scripts/sync-vendored.mjs --module rag
```

> Module agents run `sync-vendored` during adoption. It is intentionally **not** part of
> `setup`/`test`/`build` and is not run automatically here.

## Make targets

```bash
make setup   # pnpm install + uv sync --extra dev
make lint    # eslint + prettier + ruff + ruff format --check + mypy
make test    # vitest run + pytest (tiers 1-2, offline)
make build   # tsup + uv build
make pack    # build + npm pack --dry-run + uv build
```

Version `0.2.0` · MIT. No infra, no docker, no network — pure offline leaf package.

## Changelog

- **0.2.0** — Platform-layer version alignment: the whole `@demystify/platform-*`
  suite (contracts, observability, profiles, state) moves to `0.2.x` together. No
  contract changes in this package vs `0.1.0`; the bump keeps all platform packages
  on a single shared minor (see root `COMPATIBILITY.md`). Modules must depend on
  platform packages that share the same minor.
- **0.1.0** — Initial: error taxonomy, domain events, canonical headers, key
  format/hashing, currency helpers, tracing, key-introspection schemas.
