Ctrl K
ComunidadGuías…

CONTRIBUTING.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Contributing to DeltaLLM

Thank you for your interest in contributing to DeltaLLM! This document provides guidelines for contributing to the project.

## Getting Started

### Prerequisites

- Python 3.11+
- Node.js 20+
- PostgreSQL 15+
- Redis 7+ (optional but recommended)
- [uv](https://docs.astral.sh/uv/) for Python dependency management

### Setting Up Your Development Environment

1. **Fork and clone the repository**
   ```bash
   git clone https://github.com/YOUR_USERNAME/deltallm.git
   cd deltallm
   ```

2. **Install Python dependencies**
   ```bash
   uv sync --dev
   ```

3. **Install UI dependencies**
   ```bash
   cd ui
   npm ci
   cd ..
   ```

4. **Set up environment variables**
   ```bash
   export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/deltallm"
   export DELTALLM_CONFIG_PATH=./config.yaml
   export DELTALLM_MASTER_KEY="$(python3 -c 'import secrets; print(\"sk-\" + secrets.token_hex(20) + \"A1\")')"
   export DELTALLM_SALT_KEY="$(openssl rand -hex 32)"
   export OPENAI_API_KEY="sk-your-openai-key"
   ```

5. **Create config and initialize the database**
   ```bash
   cp config.example.yaml config.yaml
   uv run prisma generate --schema=./prisma/schema.prisma
   uv run prisma db push --schema=./prisma/schema.prisma
   ```

6. **Start the development servers**
   
   Backend:
   ```bash
   uv run uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload
   ```
   
   UI (in another terminal):
   ```bash
   cd ui
   npm run dev
   ```

See [Local Development](README.md#local-development) in the README for more details.

## Development Workflow

1. **Create a branch** for your changes
   ```bash
   git checkout -b feature/your-feature-name
   ```

2. **Make your changes** and ensure they follow our code style

3. **Run tests** to make sure nothing is broken
   ```bash
   uv run pytest
   ```

4. **Run the linter** to check code style
   ```bash
   uv run ruff check .
   ```

5. **Commit your changes** with a clear commit message

6. **Push to your fork** and submit a pull request

## Pull Request Guidelines

- **Describe what your PR does** and why it's needed
- **Reference any related issues** using `Fixes #123` or `Closes #123`
- **Ensure tests pass** before submitting
- **Keep changes focused** — one feature or fix per PR
- **Update documentation** if your changes affect usage

## Code Style

- We use [Ruff](https://docs.astral.sh/ruff/) for Python linting
- Follow PEP 8 style guidelines
- Write docstrings for public functions and classes
- Keep functions focused and modular

## Testing

- Write tests for new features
- Ensure existing tests pass
- Use `pytest` for running tests

Every Python test belongs to exactly one dependency lane. Pytest assigns `app`
automatically when a test uses the shared `test_app` fixture and assigns
`hermetic` when no other lane applies. A test module that opens a real
infrastructure client must declare its lane for every test in that module,
normally with a module-level `pytestmark`.

| Lane | What it exercises | Required dependency |
| --- | --- | --- |
| `hermetic` | Domain, service, repository-fake, and focused component behavior | None outside the Python process |
| `app` | The complete in-process FastAPI route graph with fake adapters and stores | None outside the Python process |
| `postgres` | SQL, constraints, transactions, locking, and Prisma behavior | Migrated PostgreSQL plus the generated Prisma client |
| `redis` | Lua, cross-client coordination, reconnect, TTL, and outage behavior | Real Redis through `DELTALLM_TEST_REDIS_URL` |
| `helm` | Chart schema, rendering, and deployment profiles | Helm CLI and built chart dependencies |

The `integration` marker remains an aggregate selector for the `postgres`,
`redis`, and `helm` lanes. It is not a primary lane.

```bash
# Run all tests
uv run pytest

# Show the current test count in each lane
uv run pytest --collect-only -qq --dependency-lane-report | tail -n 7

# Run one dependency lane
uv run pytest -q -m hermetic
uv run pytest -q -m app

# Run PostgreSQL tests after generating the client and migrating the test database
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/deltallm_test \
  uv run pytest -q -m postgres

# Run Redis integration tests
DELTALLM_TEST_REDIS_URL=redis://localhost:6379/0 \
  REDIS_URL=redis://localhost:6379/0 \
  uv run pytest -q -m redis

# Run Helm tests after building chart dependencies
uv run pytest -q -m helm

# Run specific test file
uv run pytest tests/test_specific.py
```

The collection hook fails when a test declares multiple primary lanes or when
real Prisma, Redis, or Helm usage is missing its matching explicit marker. This
keeps lane selection exhaustive and prevents infrastructure tests from silently
running in a fake-only job.

Pull requests that change only the UI (`ui/`), the docs (`docs/`, `mkdocs.yml`,
top-level Markdown) or the docs workflow skip the kind cluster jobs
(`lifecycle-acceptance` and `capacity-acceptance`). The UI build, every Python lane
and Helm still run. The PostgreSQL migration paths run only when the change touches
`prisma/`, the migration tooling in `src/` or `scripts/`, `pyproject.toml`,
`uv.lock`, the `Dockerfile` or `ci.yml`. The `cluster-changes` job decides; the
required `test` check accepts a skipped job only when that job chose to skip it.
Pushes to main always run every job.

In GitHub Actions, the exact `-m app` selection uses two pytest-xdist worker
processes. Each test still creates its own application and fake stores. The
`test_app` fixture builds the full route table once per process and gives each
application its own copies of those routes, bound to that application so
`dependency_overrides` still apply. Rebuilding the routes for every test took
about a second each and most of the lane's time. The
other lanes, collection-only commands, and local commands remain serial by
default. Use `-n 0` to request serial execution or `-n 2` to reproduce the
application CI run locally. Explicit worker settings take precedence. This
policy keeps the existing CI deadline and all required checks.

The PostgreSQL lane uses four CI runners. Each runner has its own PostgreSQL and
Redis services. `--postgres-shard=0/4` through `--postgres-shard=3/4` divide all
collected PostgreSQL modules by a stable path hash. Each test runs once, and each
module stays on one runner. With two shards the hash split was about 40/60 by run
time, so one runner took about 12 minutes; with four the largest shard holds under
a third of the lane. All shards must pass the `test` check. The time limit stays at
20 minutes per runner. To reproduce a shard, add its option to `-m postgres` and
use an isolated test database and Redis service. Local runs without this option
still run the full lane.

When a Python test lane fails in CI, the failing test IDs are also posted as
job annotations, so they stay visible even when a long service log follows them.

Every workflow that calls `uv run` sets `UV_FROZEN=1`. Without it, `uv run` checks
that `uv.lock` is current, which downloads each direct-URL wheel in the lock,
including the 400 MB presidio language model from github.com. CI lanes never
install that extra, so the download only added time and failed jobs whenever
GitHub answered 504. Run `uv lock` locally after changing dependencies.

Tests that check a deadline should give the code enough time to reach the step
under test on a busy runner (about a second), and tests that wait for background
work should poll for it rather than sleep for a fixed few milliseconds.

Query-plan tests read plans from `auto_explain` at the `NOTICE` level, so the plans
reach the test connection but not the PostgreSQL server log. GitHub Actions prints
the service container's log after the job and the readable job log keeps only its
end, so a noisy server log hides the pytest summary. Plan assertions accept any
bounded index access, including a bitmap over the same index: the planner's choice
can change when autovacuum refreshes statistics during a run. Test Prisma clients
that run accounting SQL use `jit=off`, like the accounting pool they stand in for.
Tests that check outcomes rather than latency pass a wider budget to components
with sub-second production transaction budgets, such as external-auth exchanges and
billing recovery lanes, because a shared CI runner can overrun them.

## Reporting Issues

When reporting bugs, please include:

- **Clear description** of the issue
- **Steps to reproduce** the problem
- **Expected vs actual behavior**
- **Environment details** (OS, Python version, etc.)
- **Relevant logs or error messages**

## Questions?

- Check the [documentation](https://deltallm.readthedocs.io)
- Open a [discussion](https://github.com/deltawi/deltallm/discussions) for questions
- Join our community conversations

## License

By contributing to DeltaLLM, you agree that your contributions will be licensed under the MIT License.

---

Thank you for helping make DeltaLLM better! 🚀