> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tai42.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Versioning (tai42_contract.versioning)

> The VersionedStore primitive behind presets and policies.

The generic versioned-document store contract.

A `kind`-discriminated, body-opaque persistence primitive: append-only version
rows over an opaque JSONB `body`, an active-version pointer, and rollback. The
store knows NOTHING about presets/policies/agents — those are typed VIEWS layered
on top. Identity is `(kind, name)` throughout; every write is one transaction.

This package holds the `VersionedStore` Protocol plus its record models
(`DocumentRecord`, `DocumentVersion`) and typed errors. It is
reached from the assembled facade as `app.versioning.store` (see
`AppVersioning`).

## DocumentExistsError

`tai42_contract.versioning.errors.DocumentExistsError`

```python theme={null}
class DocumentExistsError(DocumentStoreError)
```

A live document already exists for `(kind, name)` (create would collide).

## DocumentNotFoundError

`tai42_contract.versioning.errors.DocumentNotFoundError`

```python theme={null}
class DocumentNotFoundError(DocumentStoreError)
```

No active document for `(kind, name)`.

## DocumentRecord

`tai42_contract.versioning.models.DocumentRecord`

```python theme={null}
class DocumentRecord(BaseModel)
```

A versioned document's live record: its identity plus the active pointer.

`active_version` names the version currently served for `(kind, name)`;
rollback re-points it without copying data. `is_active` is the soft-delete
flag — a soft-deleted document keeps its version history (audit) but drops out
of `list`/`get`. `created_at` is an ISO-8601 timestamp string.

**Attributes**

| Attribute        | Type   |
| ---------------- | ------ |
| `kind`           | `str`  |
| `name`           | `str`  |
| `active_version` | `int`  |
| `is_active`      | `bool` |
| `created_at`     | `str`  |

## DocumentStoreError

`tai42_contract.versioning.errors.DocumentStoreError`

```python theme={null}
class DocumentStoreError(Exception)
```

Base for versioned-document store failures, carrying `(kind, name)`.

**Attributes**

| Attribute | Type |
| --------- | ---- |
| `kind`    | —    |
| `name`    | —    |

## DocumentVersion

`tai42_contract.versioning.models.DocumentVersion`

```python theme={null}
class DocumentVersion(BaseModel)
```

One immutable version row: the opaque `body` plus its version number.

A version is append-only — once written, its `version`, `body`, `tags`,
and `created_at` never change. `tags` is a generic per-version label for
grouping versions (release/grouping labels); it is kind-agnostic and carries
no product meaning (distinct from any categorization a `kind`'s body may
hold). `is_current` is a read-time projection of the owning record's
`active_version` — the store sets it `True` on the active version when it
lists/returns versions; it is not stored on the row. `created_at` is an
ISO-8601 timestamp string.

**Attributes**

| Attribute      | Type             |
| -------------- | ---------------- |
| `model_config` | —                |
| `version`      | `int`            |
| `body`         | `dict[str, Any]` |
| `tags`         | `list[str]`      |
| `created_at`   | `str`            |
| `is_current`   | `bool`           |

## DocumentVersionNotFoundError

`tai42_contract.versioning.errors.DocumentVersionNotFoundError`

```python theme={null}
class DocumentVersionNotFoundError(DocumentStoreError)
```

No version `version` exists for the `(kind, name)` document.

`version` is carried when known (the version-specific ops always know it);
the `(kind, name)` identity is always present, as for the other store errors.

**Attributes**

| Attribute | Type |
| --------- | ---- |
| `version` | —    |

## VersionedStore

`tai42_contract.versioning.VersionedStore`

```python theme={null}
class VersionedStore(Protocol)
```

Kind-discriminated, body-opaque version store. Identity is `(kind, name)`.

The `body` is opaque `dict`/JSONB — the store never inspects it; the caller
(a typed view) owns its shape. Every method raises loudly on a missing,
duplicate, or invalid target — never a silent default. `tags` is the generic
per-version grouping label (see `DocumentVersion`), distinct from any
categorization a `kind`'s body may carry.

A write method (`create`, `save_version`, `delete`,
`rollback`) accepts an optional `tx` — the handle from an open
`transaction`. Passed, the write runs WITHIN that unit of work and commits
or rolls back with it; omitted, the write is self-contained and atomic on its own.

### Members

#### transaction

`tai42_contract.versioning.VersionedStore.transaction`

```python theme={null}
transaction(self) -> AbstractAsyncContextManager[VersionedStoreTransaction]
```

Open a single-backend unit of work: `async with store.transaction() as tx`.

Every store write performed with the yielded `tx` (passed as `tx=` to the
write methods) commits or rolls back TOGETHER — a clean exit commits, an
exception rolls the whole scope back. A pure durability primitive over the one
backend: it carries no audit or domain awareness, and yields an opaque handle
the caller only threads back into the write methods.

#### create

`tai42_contract.versioning.VersionedStore.create`

```python theme={null}
async create(
    self,
    kind: str,
    name: str,
    body: dict[str, Any],
    tags: list[str] | None = None,
    *,
    tx: VersionedStoreTransaction | None = None,
) -> DocumentRecord
```

Insert a new document at `active_version = 1` plus its version 1, one
transaction. Raise `DocumentExistsError` if `(kind, name)` is
already a live document. Runs within `tx` when one is supplied.

**Parameters**

| Parameter | Type                                | Default | Description |
| --------- | ----------------------------------- | ------- | ----------- |
| `kind`    | `str`                               | —       | —           |
| `name`    | `str`                               | —       | —           |
| `body`    | `dict[str, Any]`                    | —       | —           |
| `tags`    | `list[str] \| None`                 | `None`  | —           |
| `tx`      | `VersionedStoreTransaction \| None` | `None`  | —           |

#### save\_version

`tai42_contract.versioning.VersionedStore.save_version`

```python theme={null}
async save_version(
    self,
    kind: str,
    name: str,
    body: dict[str, Any],
    tags: list[str] | None = None,
    *,
    tx: VersionedStoreTransaction | None = None,
) -> DocumentVersion
```

Append a new version (`new_version = max(version) + 1`, NOT
`active_version + 1`) and bump the active pointer to it, one transaction
(a partial failure rolls the whole save back — no orphan version, no
half-bumped pointer). Raise `DocumentNotFoundError` if absent. Runs
within `tx` when one is supplied.

**Parameters**

| Parameter | Type                                | Default | Description |
| --------- | ----------------------------------- | ------- | ----------- |
| `kind`    | `str`                               | —       | —           |
| `name`    | `str`                               | —       | —           |
| `body`    | `dict[str, Any]`                    | —       | —           |
| `tags`    | `list[str] \| None`                 | `None`  | —           |
| `tx`      | `VersionedStoreTransaction \| None` | `None`  | —           |

#### list

`tai42_contract.versioning.VersionedStore.list`

```python theme={null}
async list(self, kind: str) -> list[DocumentRecord]
```

List the active (non-soft-deleted) documents of `kind`.

**Parameters**

| Parameter | Type  | Default | Description |
| --------- | ----- | ------- | ----------- |
| `kind`    | `str` | —       | —           |

#### get

`tai42_contract.versioning.VersionedStore.get`

```python theme={null}
async get(self, kind: str, name: str) -> DocumentRecord
```

Fetch the active record for `(kind, name)`. Raise
`DocumentNotFoundError` if absent.

**Parameters**

| Parameter | Type  | Default | Description |
| --------- | ----- | ------- | ----------- |
| `kind`    | `str` | —       | —           |
| `name`    | `str` | —       | —           |

#### get\_active\_body

`tai42_contract.versioning.VersionedStore.get_active_body`

```python theme={null}
async get_active_body(
    self,
    kind: str,
    name: str,
    *,
    tx: VersionedStoreTransaction | None = None,
    for_update: bool = False,
) -> dict[str, Any]
```

Return the `body` of the active version for `(kind, name)`. Raise
`DocumentNotFoundError` if absent.

Passed a `tx`, the read rides that transaction's connection so a
read-modify-write can lock and mutate the row on one connection (no second pooled
connection while the transaction is open). With `for_update=True` it takes a
`SELECT ... FOR UPDATE` row lock on the active document so concurrent writers
serialize — the lock is meaningful only inside a transaction, so `for_update`
REQUIRES a `tx` and raises loudly without one. Omitting both preserves the
stand-alone read.

**Parameters**

| Parameter    | Type                                | Default | Description |
| ------------ | ----------------------------------- | ------- | ----------- |
| `kind`       | `str`                               | —       | —           |
| `name`       | `str`                               | —       | —           |
| `tx`         | `VersionedStoreTransaction \| None` | `None`  | —           |
| `for_update` | `bool`                              | `False` | —           |

#### list\_versions

`tai42_contract.versioning.VersionedStore.list_versions`

```python theme={null}
async list_versions(self, kind: str, name: str) -> list[DocumentVersion]
```

List every version of `(kind, name)`, each carrying the
`DocumentVersion.is_current` signal derived from `active_version`.
Raise `DocumentNotFoundError` if the document is absent.

**Parameters**

| Parameter | Type  | Default | Description |
| --------- | ----- | ------- | ----------- |
| `kind`    | `str` | —       | —           |
| `name`    | `str` | —       | —           |

#### get\_version

`tai42_contract.versioning.VersionedStore.get_version`

```python theme={null}
async get_version(
    self,
    kind: str,
    name: str,
    version: int,
    *,
    tx: VersionedStoreTransaction | None = None,
) -> DocumentVersion
```

Fetch one version. Raise `DocumentVersionNotFoundError` if that
version does not exist. Passed a `tx`, the read rides that transaction's
connection rather than opening a second pooled one.

**Parameters**

| Parameter | Type                                | Default | Description |
| --------- | ----------------------------------- | ------- | ----------- |
| `kind`    | `str`                               | —       | —           |
| `name`    | `str`                               | —       | —           |
| `version` | `int`                               | —       | —           |
| `tx`      | `VersionedStoreTransaction \| None` | `None`  | —           |

#### rollback

`tai42_contract.versioning.VersionedStore.rollback`

```python theme={null}
async rollback(
    self,
    kind: str,
    name: str,
    version: int,
    *,
    tx: VersionedStoreTransaction | None = None,
) -> DocumentRecord
```

Re-point `active_version` to `version` (NO data copy). Raise
`DocumentVersionNotFoundError` if that version does not exist. Runs
within `tx` when one is supplied.

**Parameters**

| Parameter | Type                                | Default | Description |
| --------- | ----------------------------------- | ------- | ----------- |
| `kind`    | `str`                               | —       | —           |
| `name`    | `str`                               | —       | —           |
| `version` | `int`                               | —       | —           |
| `tx`      | `VersionedStoreTransaction \| None` | `None`  | —           |

#### soft\_delete

`tai42_contract.versioning.VersionedStore.soft_delete`

```python theme={null}
async soft_delete(self, kind: str, name: str) -> None
```

Set `is_active = False`, keeping the version history (audit). The
document drops out of `list`/`get` but its rows survive.

**Parameters**

| Parameter | Type  | Default | Description |
| --------- | ----- | ------- | ----------- |
| `kind`    | `str` | —       | —           |
| `name`    | `str` | —       | —           |

#### delete

`tai42_contract.versioning.VersionedStore.delete`

```python theme={null}
async delete(self, kind: str, name: str, *, tx: VersionedStoreTransaction | None = None) -> None
```

HARD delete, DISTINCT from `soft_delete`: remove ONLY the ACTIVE
document row for `(kind, name)` AND its version rows, so nothing of the
active document survives; a soft-deleted ghost of the same name is left
untouched. Raise `DocumentNotFoundError` if there is no active row.
Used to roll a never-succeeded create fully back and to remove a conflicted
record without leaving the ghost + spurious history a soft delete would. Runs
within `tx` when one is supplied.

**Parameters**

| Parameter | Type                                | Default | Description |
| --------- | ----------------------------------- | ------- | ----------- |
| `kind`    | `str`                               | —       | —           |
| `name`    | `str`                               | —       | —           |
| `tx`      | `VersionedStoreTransaction \| None` | `None`  | —           |

#### rename

`tai42_contract.versioning.VersionedStore.rename`

```python theme={null}
async rename(self, kind: str, name: str, new_name: str) -> DocumentRecord
```

Re-key the ACTIVE document `(kind, name)` to `(kind, new_name)` in one
atomic write. The whole version history, every per-version `tags` label, and
the `active_version` pointer move untouched — versions key on the document,
not the name, so nothing is copied. The `body` is never inspected (the store
stays body-opaque). A soft-deleted ghost named `new_name` does NOT block (the
same partial-unique identity rule `create` follows), and a soft-deleted
ghost of `name` is left untouched as audit history. Raise
`DocumentNotFoundError` if `(kind, name)` has no active row; raise
`DocumentExistsError` (carrying `new_name`) if `(kind, new_name)` is
already a live document.

**Parameters**

| Parameter  | Type  | Default | Description |
| ---------- | ----- | ------- | ----------- |
| `kind`     | `str` | —       | —           |
| `name`     | `str` | —       | —           |
| `new_name` | `str` | —       | —           |

## VersionedStoreTransaction

`tai42_contract.versioning.VersionedStoreTransaction`

```python theme={null}
class VersionedStoreTransaction(Protocol)
```

Opaque unit-of-work handle yielded by `VersionedStore.transaction`.

A pure durability token exposing NO operations of its own: a caller only passes it
back to a write method's `tx=` parameter so that write joins the open
transaction. The concrete store owns the handle's real shape (its pooled
connection); the token carries no audit or domain awareness.
