Metadata-Version: 2.4
Name: t-shell-codex
Version: 0.1.1
Summary: Libreria Python que materializa la Fuente de Conocimiento de T-Shell V1 integrando los modelos de la Capa Operativa sobre PostgreSQL.
Author: T-Shell Project
License: MIT
Project-URL: Documentation, https://github.com/t-shell/codex
Project-URL: Repository, https://github.com/t-shell/codex
Keywords: t-shell,postgresql,knowledge-source,asyncpg
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Framework :: AsyncIO
Classifier: Topic :: Database
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: asyncpg>=0.29.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: mypy>=1.7; extra == "dev"
Dynamic: license-file

# Codex — Librería de la Fuente de Conocimiento de T-Shell V1

Codex materializa la **Fuente de Conocimiento** de T-Shell definida en
`docs/applications/codex/implementation.md`.

Su responsabilidad es cumplir la **Capa Operativa** y todos sus modelos,
encapsulando las sentencias SQL dentro de repositorios que exponen una
API Python idiomática, asíncrona y tipada.

> Codex **NO** es dueña del esquema: el esquema es provisto externamente
> (inicializado y mantenido por scripts SQL fuera de esta librería, por
> la operación del sistema). Esta librería sólo asume que las tablas y
> restricciones existen en la base de datos a la que se conecta.

## Responsabilidades cubiertas (Capa Operativa V1)

| Repositorio | Modelo atendido | Documento normativo |
|---|---|---|
| `IdentityRepository` | Identidad lógica (UUIDv7) + criptográfica (Ed25519) | `architecture/layers/operative/identity/index.md` |
| `EntityRepository` | Atlas / Echo (rol auto-declarativo) | `architecture/layers/operative/entity/index.md` |
| `DomainRepository` | Dominio + lifecycle | `architecture/layers/operative/domain/index.md` |
| `MembershipRepository` | Membership N:1 (Entity → Domain) atómica | `architecture/layers/operative/domain/index.md` |
| `PassportRepository` | Passport + estado derivado + precedencia | `architecture/layers/operative/domain/index.md` |
| `InfrastructureRepository` | Infrastructure (UUIDv7, prioridades únicas) | `architecture/layers/operative/infrastructure/index.md` |
| `SnapshotRepository` | InfrastructureSnapshot (epoch/sequence/authority_proof) | `architecture/layers/operative/infrastructure/snapshot.md` |

Los modelos de Red, Topología, Autoridad, Manufactura, Distribución,
Conocimiento (composicional), Eventos (especificación incompleta en V1)
e Integración (orquestador) **no requieren repositorios propios**: son
relaciones o composiciones sobre las entidades anteriores.

## Stack y decisiones

| Decisión | Elección |
|---|---|
| Driver PostgreSQL | `asyncpg` (asíncrono) |
| Acceso a datos | SQL crudo encapsulado (sin ORM) |
| Migraciones | externas — Codex NO gestiona esquema |
| Configuración | `CodexConfig` (dataclass tipada) leída de variables de entorno |
| Transacciones | cada método de repositorio abre su transacción propia; para operaciones multi-tabla (commit atómico de integración), se usa `pool.acquire()` + `transaction()` como bloqueador |
| Layout | `src/codex` |
| Python | 3.10+ |

## Instalación

```bash
pip install -e .[dev]
```

## Configuración

Codex se configura exclusivamente mediante variables de entorno
(tipadas, validadas en arranque):

| Variable | Tipo | Descripción |
|---|---|---|
| `CODEX_DB_HOST` | str | Dirección IP / host del servidor PostgreSQL |
| `CODEX_DB_PORT` | int | Puerto (por defecto `5432`) |
| `CODEX_DB_USER` | str | Usuario de PostgreSQL |
| `CODEX_DB_PASSWORD` | str | Contraseña |
| `CODEX_DB_NAME` | str | Nombre de la base de datos |
| `CODEX_DB_MIN_SIZE` | int | Tamaño mínimo del pool (default 1) |
| `CODEX_DB_MAX_SIZE` | int | Tamaño máximo del pool (default 10) |

Ejemplo (ver `.env.example`):

```bash
export CODEX_DB_HOST=127.0.0.1
export CODEX_DB_PORT=5432
export CODEX_DB_USER=codex
export CODEX_DB_PASSWORD=codex
export CODEX_DB_NAME=codex
```

## Uso básico

```python
import asyncio
from codex.config import load_codex_config
from codex.connection import CodeXPool
from codex.repositories.identity import IdentityRepository

async def main():
    cfg = load_codex_config()
    pool = CodeXPool(cfg)
    await pool.start()
    try:
        repo = IdentityRepository(pool)
        # todas las operaciones son awaitables
    finally:
        await pool.stop()

asyncio.run(main())
```

## Commit atómico (Integración Operativa)

Sólo puede lograrse cuando `Entity` + `Membership` + consumo de
`Passport` se confirman en una misma transacción. El patrón soportado
por esta librería es usar el pool directamente:

```python
async with pool.acquire() as conn:
    async with conn.transaction():
        new_identity = await identity_repo.create(conn, ...)
        membership_repo.link(conn, entity_uid, domain_uid)
        passport_repo.consume(conn, passport_uid)
```

Los repositorios exponen una variante con `conn: asyncpg.Connection`
para integrarse dentro de una transacción externa, y otra variante sin
`conn` para uso directo (que adquiere su propia conexión y abre su
propia transacción).

## Esquema esperado

Codex asume la existencia de las siguientes tablas (nombres exactos —
los scripts externos deben respetarlos):

```sql
CREATE TABLE identities (
    logical_uid        UUID PRIMARY KEY,                  -- UUIDv7
    name               TEXT,
    cryptographic_key  BYTEA NOT NULL,                    -- clave pública Ed25519
    created_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE entities (
    logical_uid        UUID PRIMARY KEY,
    name               TEXT NOT NULL,
    role               TEXT NOT NULL CHECK (role IN ('CONTROLADOR','NODO')),
    identity_uid       UUID NOT NULL REFERENCES identities(logical_uid),
    created_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE domains (
    logical_uid        UUID PRIMARY KEY,
    name               TEXT NOT NULL,
    created_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE memberships (
    entity_uid         UUID PRIMARY KEY REFERENCES entities(logical_uid),
    domain_uid         UUID NOT NULL REFERENCES domains(logical_uid),
    created_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ix_memberships_domain ON memberships(domain_uid);

CREATE TABLE passports (
    logical_uid        UUID PRIMARY KEY,
    domain_uid         UUID NOT NULL REFERENCES domains(logical_uid),
    usage_limit        INT  NOT NULL CHECK (usage_limit > 0),
    usage_count        INT  NOT NULL DEFAULT 0 CHECK (usage_count >= 0),
    expires_at         TIMESTAMPTZ,
    declared_state     TEXT NOT NULL DEFAULT 'ENABLED' CHECK (declared_state IN ('ENABLED','DISABLED')),
    secret_hash        BYTEA NOT NULL,                     -- hash del secreto, no el secreto
    created_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE infrastructures (
    logical_uid        UUID PRIMARY KEY,                  -- UUIDv7
    name               TEXT NOT NULL,
    address            TEXT NOT NULL,
    priority           INT  NOT NULL UNIQUE CHECK (priority > 0),
    declared_state     TEXT NOT NULL CHECK (declared_state IN ('ENABLED','DISABLED','RETIRED')),
    created_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE infrastructure_snapshots (
    domain_uid         UUID NOT NULL REFERENCES domains(logical_uid),
    epoch              UUID NOT NULL,                     -- UUIDv7
    sequence           BIGINT NOT NULL CHECK (sequence >= 0),
    current_primary_uid UUID NOT NULL,
    generated_at       TIMESTAMPTZ NOT NULL,
    authority_proof    BYTEA NOT NULL,
    PRIMARY KEY (domain_uid, epoch, sequence)
);
```

Los nombres, columnas, tipos y restricciones aquí listados son el
contrato vinculante entre Codex y el esquema externo. Cambiar el esquema
externo es posible, pero requiere actualizar este README y los nombres
de columna explícitos en los repositorios.
