# Ownership

Source of truth for who owns what in TrustLoopGuard. Two-founder split designed so neither half blocks the other for the 6-week MVP.

## Principle

**Contracts are the seam, not code.** We split by user-facing vertical (plugin vs cloud), not by stack layer. Both halves transit the same `Decision` value over the same wire format. As long as the contracts in §3 stay stable, neither founder is blocked by the other.

## 1. Lane ownership

### Founder A — Engine + Plugin SDK

Everything that runs **inside the customer's process**.

| Surface | Path | Notes |
|---|---|---|
| Wire types | `crates/tl-core/` | A drives, B reviews via CODEOWNERS |
| Policy DSL | `crates/tl-policy/` | YAML parser + AST |
| Hot-path engine | `crates/tl-engine/` | The latency moat |
| Streaming | `crates/tl-stream/` | Voice / token-by-token |
| Rust SDK | `crates/tl-sdk-rust/` | Thin reqwest client |
| Python SDK | `sdks/python/` | HTTP wrapper. Pydantic types generated from `docs/openapi.yaml` via `datamodel-code-generator` (run by `tl-codegen`). PyO3 bindings deferred to v2. |
| TypeScript SDK | `sdks/typescript/` | HTTP wrapper. Types generated from `tl-core` via `ts-rs` (run by `tl-codegen`). |
| CLI | `crates/tl-cli/` | `tl policy-lint`, `tl replay`, `tl bench` |
| Host adapters | `examples/openai-middleware/`, `examples/livekit/`, etc. | Demo surface for design partners |

### Founder B — Cloud Service

Everything that runs **on TLG infrastructure**.

| Surface | Path | Notes |
|---|---|---|
| HTTP server | `crates/tl-server/` | axum routes, auth, rate limiting |
| Persistent storage | `crates/tl-storage/` | Postgres impl of `DecisionStore`, ClickHouse later |
| Replay backend | `crates/tl-replay/` (service half) | Batch replay, dashboard data source |
| Dashboard | `dashboard/` (new) | Decision log viewer, policy editor, latency charts |
| Auth + billing | `crates/tl-server/src/auth.rs`, Stripe wiring | API keys, workspaces |
| Deploy + infra | `deploy/`, `.github/workflows/` | Fly.io / Render / k8s, observability |

## 2. Critical-path crates

`tl-engine` and `tl-core` are used by **both** halves. They live in A's lane, but a B request for a behavior change is a real ticket, not a nice-to-have. Treat A as on-call for the cloud's engine needs.

## 3. Contracts (the only cross-lane surface)

A change to any of these requires PR review from both founders. Wire up `.github/CODEOWNERS` to enforce.

| Contract | Canonical source | Derived artifact | Owner | Consumers |
|---|---|---|---|---|
| Wire types | `crates/tl-core/src/lib.rs` | `docs/openapi.yaml`, `policies/*.schema.json`, TS types | A drives | B (server), A (SDKs) |
| Policy DSL | `crates/tl-policy/src/policy_ast.rs` | `policies/policy.schema.json` | A | B (editor), A (CLI) |
| HTTP routes (paths only, not body shapes) | `crates/tl-server/src/main.rs` | `docs/openapi.yaml` (paths section) | B | A (SDKs) |
| `DecisionStore` trait | `crates/tl-storage/src/lib.rs` | — | B | B (Postgres), A (memory) |
| Plugin contract | `docs/concept/plugin-contract.md` | — | A | host adapters, customer agents |

**Source-of-truth rule:** the canonical source is hand-edited; the derived artifacts are generated by `cargo run -p tl-codegen` and committed. Never hand-edit a derived file. CI enforces this.

**Rule for everything else:** self-merge. A doesn't review dashboard PRs; B doesn't review matcher implementations.

## 4. Wire-format versioning

Versioning lives at the **URL path**, not in the body. `/v1/check` is v1; when v2 ships, it lives at `/v2/check` with its own types in `tl-core::v2`. Both compile in parallel until v1 is sunset.

Within a major version:
- **Additive changes** (new optional field with `#[serde(default)]`, new enum variant, new endpoint) — no version bump. Still a cross-lane PR because the wire artifacts regenerate.
- **Breaking changes** — copy `tl-core/src/lib.rs` to `tl-core/src/v2.rs`, add `/v2/...` routes, support both for the deprecation window.

Wire artifacts (`docs/openapi.yaml`, `policies/*.schema.json`, generated TS types) are **derived from Rust types** by `cargo run -p tl-codegen`. CI runs `cargo run -p tl-codegen -- --check` and fails if anyone hand-edited a derived file.

## 5. Demo independence checkpoint

You should both be able to demo to a design partner without the other's code merged.

| Founder | Demo without the other |
|---|---|
| A | `cargo run -p tl-engine` example, OpenAI middleware blocking a refund promise. No network. No server. |
| B | `tl-server` running with a stub engine. `/v1/check` returns realistic decisions. Dashboard shows logs in Postgres. Deployed. |

If either founder can't demo their half independently in week 3, the split has broken — investigate before proceeding.

## 6. Conflict resolution

- **Type churn** → A has the pen on `tl-core`. If B needs a field, file a one-line issue with the use case. A ships within 24h or pushes back with reasoning.
- **API churn** → B has the pen on `docs/openapi.yaml`. Same protocol in reverse.
- **"This is going slower than we thought"** → look at which contract is moving. If contracts are stable, the problem is inside one lane and the other founder doesn't owe a fix.
- **Disagreement on a contract** → PR comments first. If still stuck after one round-trip, sync call. Don't merge contested contract changes.

## 7. When to split further

Don't, until you hire someone. Three-person teams should re-read this doc and split lane B into "server" and "dashboard," not split lane A further. The plugin half stays one person's brain because latency consistency matters.
