diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40c113c3..7b06f924 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,27 +1,158 @@ # Contributing to vouch -Thanks for considering a contribution. vouch is pre-1.0 and the surface is -still moving, so a quick conversation in an issue before a large PR will +Thanks for considering a contribution. vouch is a review-gated knowledge +base — the gate is the product — so contributions need to protect that +invariant: writes stay gated, claims stay cited, and the audit log stays +append-only. A quick conversation in an issue before a large PR will usually save everyone time. +## What happens to your PR + +Every PR gets an automated review pass (CodeRabbit; pushes to `test` also +get a Copilot review) plus the CI gate — lint, mypy, the test matrix on +Python 3.11/3.12/3.13, and an sdist + wheel build. A maintainer reads the +review output and the diff, then merges or closes; there is no auto-merge. +So get it green before you push: run the full local gate below, keep the +branch conflict-free, and keep the PR to one concern. + +Base feature branches on `test` and target `test` in the PR — it is the +integration branch, and it reaches `main` via promotion PRs cut by the +maintainer. Docs-only changes may target `main` directly when they don't +touch behavior. + +## What we welcome + +- Anything on [ROADMAP.md](ROADMAP.md). +- Fixes with a regression test that fails on the previous code. +- New host adapters under `adapters//` (an `install.yaml` manifest — + see [adapters/README.md](adapters/README.md)). +- Retrieval quality: FTS, embeddings, salience, recall/compile output. +- Capture fidelity, review-console ergonomics, and docs that shorten the + path to the capture → approve → compile → recall loop. +- Tests, fixtures, CI hardening, and developer-experience improvements. + +## What we won't merge + +- Anything that bypasses the review gate from the agent side + (e.g. a `kb.write_*` that skips `proposed/`). The whole point is the + gate; talk to us first if you think you need this. +- Validation relaxations that let claims land without citations. A claim + without evidence is a `working` note at best — register a source. +- New transports that don't pass the JSONL contract tests + (`tests/test_jsonl_server.py`) and the capabilities cross-check + (`tests/test_capabilities.py`). +- Destructive operations on `decided/` or `audit.log.jsonl` outside of a + bundle-import path. The audit log is append-only by design. +- A SaaS / hosted mode. vouch is local-first by design. +- Replacing YAML/markdown with JSON or SQLite as the storage format — the + diff-in-PRs property requires plaintext (`state.db` stays a derived + cache). +- A custom config DSL. YAML + pydantic is sufficient. +- Real customer names, internal URLs, or PII in code, fixtures, or docs — + test fixtures use generic placeholders (`alice-example`, `acme-example`). + +## Before opening a PR + +- Search existing issues and PRs to avoid duplicate work. +- Open an issue first for anything that changes the object model, the + `kb.*` method surface, the on-disk layout, the bundle format, or the + audit-log shape. These are load-bearing for downstream tools and + reviewed users — they need a [VEP](proposals/README.md), not just a PR. +- Keep the PR narrow. If it spans the server surface, storage, and an + adapter, explain why it can't be split. +- Don't include secrets, tokens, local absolute paths, or contents of a + real `.vouch/` directory. + ## Dev setup -\`\`\`bash +```bash git clone https://github.com/vouchdev/vouch cd vouch python -m venv .venv && source .venv/bin/activate pip install -e '.[dev]' -\`\`\` +``` -## Day-to-day +## The gate -\`\`\`bash +`make check` is the same gate CI runs. The individual pieces: + +```bash make test # pytest make lint # ruff check make format # ruff format make type # mypy make check # lint + type + test -\`\`\` +``` + +Or exactly what `.github/workflows/ci.yml` runs: + +```bash +python -m pytest tests/ -q --ignore=tests/embeddings +python -m mypy src +python -m ruff check src tests +``` + +The embedding-heavy tests run as a separate CI job: `pip install -e +'.[embeddings]'`, then drop the `--ignore`. If you touch packaging +(`pyproject.toml`, `adapters/` layout, the Dockerfile), also prove the +artifacts: `python -m build`, then check the wheel — CI builds it, but the +wheel-contents and installed-resolution regression tests in +`tests/test_install_adapter.py` are the fast local check. + +## Test expectations + +Tests should prove behavior, not just exercise lines. The conventions are +strict: + +- Tests mirror module names: `tests/test_.py`. +- Every fix ships a regression test that fails on the previous code. +- New CLI subcommands need a test in `tests/`; schema changes need a + round-trip test in `tests/test_storage.py` or `tests/test_bundle.py`; + new env-var behaviour needs a test in `tests/test_logging_config.py`. +- A new `kb.*` method has **four registration sites**, and + `tests/test_capabilities.py` fails if you miss one: the MCP tool in + `src/vouch/server.py`, the JSONL handler in `src/vouch/jsonl_server.py`, + the `METHODS` list in `src/vouch/capabilities.py`, and the CLI mirror in + `src/vouch/cli.py`. +- Fixtures use generic placeholders — never real names, URLs, or PII. + +## Required PR contents + +- A Conventional Commit-style title: `type(scope): short summary`. +- What changed, why, and — for anything touching storage or migrations — + *what would break for someone with an existing `.vouch/` directory?* +- The validation commands you ran. +- A `CHANGELOG.md` entry under `## [Unreleased]` for user-visible changes. +- Lowercase prose in the PR body, matching the repo voice. No + `Co-Authored-By` or AI-attribution trailers in commits. + +## Commit and PR titles + +```text +feat(compile): cap drafted pages per run +fix(cli): force utf-8 stdio on non-utf-8 locales +docs(contributing): clarify the review gates +chore(release): prepare 1.2.1 +``` + +Types: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `perf`, `ci`, +`style`, `build`, `revert`. Scope optional, lowercase, specific. Summary +lowercase, ≤72 characters, no trailing period. Bodies are lowercase prose +explaining the why. + +## Release checklist (maintainers) + +1. Bump the version in all **four** sites — `pyproject.toml`, + `openclaw.plugin.json`, `package.json`, `src/vouch/__init__.py` — + `tests/test_openclaw_plugin_manifest.py` enforces the lockstep. +2. Roll `## [Unreleased]` in `CHANGELOG.md` into a dated `## [X.Y.Z]` + section. +3. `make check` green; PR titled `chore(release): prepare X.Y.Z` into + `test`, then promote to `main`. +4. `git tag -a vX.Y.Z && git push origin vX.Y.Z` — `release.yml` builds + sdist + wheel, publishes to PyPI via Trusted Publishing, pushes the + `ghcr.io/vouchdev/vouch` images, and creates the GitHub release with + the CHANGELOG section as the body (title = the annotated tag subject). ## Environment variables @@ -33,27 +164,9 @@ make check # lint + type + test Example for local debugging: -\`\`\`bash +```bash VOUCH_LOG_FORMAT=json VOUCH_LOG_LEVEL=DEBUG vouch status -\`\`\` - -## Sending a PR - -1. Open an issue first for anything that changes the object model, the - `kb.*` method surface, the on-disk layout, the bundle format, or the - audit-log shape. These are load-bearing for downstream tools and - reviewed users — they need a [VEP](proposals/README.md), not just a PR. -2. Branch from `main`. Target `test` for feature branches — `test` is the - integration branch and reaches `main` via release branches. Keep PRs - focused; one concern per PR. -3. Add or update tests. New CLI subcommands need a test in `tests/`; - schema changes need a round-trip test in `tests/test_storage.py` or - `tests/test_bundle.py`; new env-var behaviour needs a test in - `tests/test_logging_config.py`. -4. Run `make check` locally before pushing. -5. Update `CHANGELOG.md` under `## [Unreleased]`. -6. PR description should answer: *what changed, why, and what would - break for someone with an existing `.vouch/` directory?* +``` ## Logging guidelines @@ -64,27 +177,14 @@ VOUCH_LOG_FORMAT=json VOUCH_LOG_LEVEL=DEBUG vouch status - Pass structured context via `extra=` rather than string interpolation when `VOUCH_LOG_FORMAT=json` consumers may parse the output: -\`\`\`python +```python logger.info("proposal approved", extra={"proposal_id": pid, "actor": actor}) -\`\`\` +``` - vouch uses `_VouchManagedHandler` (a `logging.StreamHandler` subclass) to mark its own handlers. Host applications and test frameworks can add their own handlers without risk of them being removed by `configure_logging()`. -## Things we won't merge - -- Anything that bypasses the review gate from the agent side - (e.g. a `kb.write_*` that skips `proposed/`). The whole point is the - gate; talk to us first if you think you need this. -- Validation relaxations that let claims land without citations. A claim - without evidence is a `working` note at best — register a source. -- New transports that don't pass the JSONL contract tests - (`tests/test_jsonl_server.py`) and the capabilities cross-check - (`tests/test_capabilities.py`). -- Destructive operations on `decided/` or `audit.log.jsonl` outside of a - bundle-import path. The audit log is append-only by design. - ## Style - Python 3.11+. Lints: ruff (`E`, `F`, `I`, `B`, `UP`, `SIM`, `RUF`). @@ -98,6 +198,5 @@ logger.info("proposal approved", extra={"proposal_id": pid, "actor": actor}) ## Reporting bugs / asking for features -Use GitHub Issues with the templates under -[.github/ISSUE_TEMPLATE/](.github/ISSUE_TEMPLATE/). For security issues, see -[SECURITY.md](SECURITY.md) — please don't open a public issue first. +Use GitHub Issues. For security issues, see [SECURITY.md](SECURITY.md) — +please don't open a public issue first. diff --git a/README.md b/README.md index 8309ac4f..223fdff6 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ compile: **3. Work a session — it captures itself.** Use Claude Code normally. Each tool call is harvested into a gitignored scratch buffer, and at session end the buffer rolls up — mechanically, no LLM — into **one pending session-summary page**. Never auto-approved: the next session greets you with -``` +```text 🔔 1 auto-captured session summary(ies) awaiting review — run `vouch review`. ```