diff --git a/AGENTS_SETUP_INSTRUCTIONS.md b/AGENTS_SETUP_INSTRUCTIONS.md index 8339c8e..632ba71 100644 --- a/AGENTS_SETUP_INSTRUCTIONS.md +++ b/AGENTS_SETUP_INSTRUCTIONS.md @@ -25,13 +25,14 @@ To work from source (for development), clone the repository and run `uv sync`: git clone https://github.com/MachineWisdomAI/fava-trails.git && cd fava-trails && uv sync ``` -**Version boundaries.** Governed identity and `mode="authoring"` date from 0.7.0, and a release older than 0.7.0 does not match this guide's identity model. The local-reviewer bootstrap options (`--review-endpoint`, `--review-model`, `--review-key-env`) are marked "from 0.9.0" in this guide and are not in a published package until a release announces them. After any install or upgrade, run `fava-trails version` and restart the MCP client so the process loads the intended entrypoint. See [docs/runtime-and-upgrade.md](docs/runtime-and-upgrade.md). +**Version boundaries.** Governed identity and `mode="authoring"` date from 0.7.0, and a release older than 0.7.0 does not match this guide's identity model. The local-reviewer bootstrap options (`--review-endpoint`, `--review-model`, `--review-key-env`) are in the source on main. A published package has them only when its entry in the [release history](CHANGELOG.md) lists them, so compare `fava-trails version` with that history before you follow the local-review steps below. After any install or upgrade, run `fava-trails version` and restart the MCP client so the process loads the intended entrypoint. See [docs/runtime-and-upgrade.md](docs/runtime-and-upgrade.md). ### LLM Configuration (for Trust Gate) The Trust Gate reviews thoughts before promotion using a local OpenAI-compatible `llm-oneshot` reviewer that you name (new data repositories -created by `fava-trails bootstrap` from **0.9.0**), OpenRouter Decisions (Jev), +created by `fava-trails bootstrap` in a build that includes the local-reviewer +options), OpenRouter Decisions (Jev), or an explicit operator approval path. Releases through 0.8.x and any existing configuration keep their current behavior: with no Trust Gate settings, the built-in default is still OpenRouter Decisions (Jev). Provider selection is a **data-egress choice**: under the @@ -62,7 +63,7 @@ that process). Early validation failures — missing `thought_id`, missing promp cache, thought not found, or prompt-resolution errors — return before disclosure and omit `trust_gate_egress`. -**New installations: local review (0.9.0 and later; no hosted account needed):** +**New installations: local review (needs a build that includes the local-reviewer options; no hosted account needed):** `fava-trails bootstrap` selects the `llm-oneshot` policy and asks you to name the reviewer. You supply the endpoint and the exact model id your server @@ -131,10 +132,10 @@ returned to the caller in `trust_gate.reasoning`. Jev (`decisions`) returns a probability and threshold only, and none of its reasoning is invented. A slow local model needs a higher `trust_gate_timeout_secs`, which now applies to each request as well as to the whole review (keep it below `tool_timeout_secs`). -Fixture tests cover protocol handling. One recorded run of an installed 0.9.0rc1 +Fixture tests cover protocol handling. One recorded run of a locally built 0.9.0rc1 candidate against one local model (`unsloth/Qwen3.6-27B-GGUF`) showed two rejections with reasoning, then an approval and a correction. That is a single -observation, not a benchmark, and the candidate is not a published release. Whether +observation, not a benchmark, and the candidate was never published. Whether a particular model gives useful rejection feedback is for you to confirm with your own server; see the [local review walkthrough](docs/local-review-walkthrough.md). @@ -170,7 +171,7 @@ The default model (`~typesafe/jev-latest`) is OpenRouter Jev via the Decisions API. Supply an existing OpenRouter key; you do not have to write a Noul question. Missing cloud credentials fail closed — candidates are **not** auto-approved. The shipped question and threshold are documented in the -[ticket 03 calibration report](https://github.com/MachineWisdomAI/fava-trails/issues/126#issuecomment-5894849724); +[issue #126 calibration report](https://github.com/MachineWisdomAI/fava-trails/issues/126#issuecomment-5894849724); the private corpus is available upon request. Local Unsloth Laya is the no-per-request-cost alternative for the same @@ -300,8 +301,8 @@ fava-trails bootstrap fava-trails-data \ --review-key-env LOCAL_REVIEW_KEY ``` -The three `--review-*` options configure the local reviewer (0.9.0 and later; see -[LLM Configuration](#llm-configuration-for-trust-gate)). Without them, +The three `--review-*` options configure the local reviewer (in builds that include +them; see [LLM Configuration](#llm-configuration-for-trust-gate)). Without them, bootstrap tells you what to supply and promotion fails closed until you do. Save, recall, review, and supersession work without a git remote. `sync` @@ -406,7 +407,8 @@ push_strategy: manual # bootstrap default: local commits onl # sync MCP tool fetches/rebases; immediate mode also pushes after it succeeds # Trust Gate (built-in default when unstated: decisions / OpenRouter Jev; -# `fava-trails bootstrap` 0.9.0+ writes llm-oneshot plus the local reviewer you name) +# `fava-trails bootstrap` in a build with the local-reviewer options writes llm-oneshot, +# plus the local reviewer you name when you pass all three options) trust_gate: decisions # decisions | llm-oneshot trust_gate_provider: openrouter # any-llm provider id (openrouter | openai | ...) trust_gate_model: ~typesafe/jev-latest # tracking alias; pin typesafe/jev-1.13 if desired @@ -450,7 +452,7 @@ trails: | `trails_dir` | string | `trails` | Directory for trail data (relative to repo root) | | `remote_url` | string | `null` | Git remote URL for sync | | `push_strategy` | string | `manual` | `immediate` auto-pushes after successful writes (advances `main` to `@-` then pushes); `manual` (bootstrap default) keeps commits local until the operator runs `jj bookmark set main -r @-` then `jj git push --bookmark main`. The `sync` tool itself only fetches/rebases; under `immediate`, a successful `sync` is also followed by the after-write push. | -| `trust_gate` | string | `decisions` | Global trust gate policy. **Built-in default when unstated: `decisions`** (OpenRouter Jev); `bootstrap` from 0.9.0 writes `llm-oneshot` for new data repositories. `llm-oneshot` with a Decisions-only model (`~typesafe/jev-latest`, `typesafe/jev-1.13`) is refused before transmission. `human` is unimplemented (raises `NotImplementedError`). Non-LLM path is per-call `propose_truth(..., approval="human")` on an operator endpoint, not this config field. | +| `trust_gate` | string | `decisions` | Global trust gate policy. **Built-in default when unstated: `decisions`** (OpenRouter Jev); `bootstrap` in a build that includes the local-reviewer options writes `llm-oneshot` for new data repositories. `llm-oneshot` with a Decisions-only model (`~typesafe/jev-latest`, `typesafe/jev-1.13`) is refused before transmission. `human` is unimplemented (raises `NotImplementedError`). Non-LLM path is per-call `propose_truth(..., approval="human")` on an operator endpoint, not this config field. | | `trust_gate_provider` | string | `openrouter` | any-llm provider id (`openrouter`, `openai`, …) | | `trust_gate_model` | string | `~typesafe/jev-latest` | Exact model id or alias. Chat-completions models (e.g. `google/gemini-2.5-flash`) are for explicit `llm-oneshot`. | | `trust_gate_api_base` | string | `null` | Optional API root. Decisions default is `https://openrouter.ai/api`; OpenAI-compatible local endpoints use `/v1`. | @@ -583,7 +585,7 @@ Hooks can return a single action, `None` (treated as `Proceed`), or a list of ac ### Config Injection -If your hook module defines a `configure(config)` function, it's called at startup with the `config` dict from `hooks.yaml` (after env var interpolation): +If your hook module defines a `configure(config)` function, it's called at startup with the `config` dict from the hook's entry in `config.yaml` (after env var interpolation): ```python _min_confidence = 0.3 @@ -627,7 +629,7 @@ Hooks that need to query trail state receive a `TrailContext` via `event.context |-------|------|---------------| | `before_save` | Before thought is written to disk | Gating (can reject/mutate/redirect) | | `after_save` | After thought is committed | Observer (awaited sequentially through completion or timeout on the caller's task; adds latency before the tool returns; at-most-once, no retry) | -| `before_propose` | Before promotion from drafts | Gating (can reject/mutate/redirect) | +| `before_propose` | Inside `propose_truth`, after the reviewer returns a verdict (or the caller supplies an explicit operator approval) and before that verdict or approval is applied and saved. Hooks see the record before the durable approval metadata is written. Runs for reject and error verdicts too. | Gating (can reject/mutate/redirect) | | `after_propose` | After promotion is committed | Observer (awaited sequentially like `after_save`) | | `after_supersede` | After supersession is committed | Observer (awaited sequentially like `after_save`) | | `on_recall` | During single-trail recall search | Gating (can filter/reorder via RecallSelect) | @@ -654,7 +656,7 @@ FAVA Trails ships with protocol hook modules that can be enabled via `module:` e | Protocol | Install | Description | |----------|---------|-------------| -| **SECOM** | `pip install fava-trails[secom]` | Extractive compression at promote time via LLMLingua-2 ([docs](../src/fava_trails/protocols/secom/README.md)) | +| **SECOM** | `pip install fava-trails[secom]` | Extractive compression at promote time via LLMLingua-2 ([docs](src/fava_trails/protocols/secom/README.md)) | | **ACE** | included | Playbook-driven reranking and anti-pattern detection (Stanford, UC Berkeley, and SambaNova ACE) | | **RLM** | included | MapReduce orchestration hooks for batch workflows (MIT RLM) | @@ -689,6 +691,8 @@ hooks: type: llmlingua ``` +Inside `propose_truth`, the reviewer reads the draft as saved before this attempt, which can already contain compressed text if an earlier step stored it. SECOM runs afterwards as the `before_propose` hook, before the verdict is applied and saved, so this attempt's compressed output is not reviewed again. A record that is compressed is stored in its compressed form and the original draft stays in version history. The hook also runs when the verdict is a rejection or an error. The SECOM hook fails open on errors: with `fail_mode: open` (the default), an error in the hook lets the promotion continue uncompressed. The accepted values are `open` and `closed`. + After installing and configuring, restart the MCP server. The first `propose_truth` that triggers compression will download the LLMLingua-2 model (~700MB) from HuggingFace Hub. Pre-download with: ```bash diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14db222..fdfce80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -125,30 +125,44 @@ but unreleased**. Once dog-fooding confirms the changes work: -Release candidates use the same flow with a PEP 440 tag `vX.Y.ZrcN` that equals -the `pyproject.toml` version (for example `v0.8.4rc1`). The Release workflow -publishes it as a GitHub prerelease (never `latest`); installers get it only with -`pip install --pre` or an exact pin. The version is set in the source PR by -`scripts/mw-version.py` (see `docs/version-policy.md`), never at tag time. -Promotion to stable uses the `chore(release): promote version` PR. - -1. Bump version in `pyproject.toml` -2. Push the version bump via PR, merge to `main` +A release is either stable, tagged `vX.Y.Z`, or a release candidate, tagged with +the PEP 440 form `vX.Y.ZrcN` (for example `v0.8.4rc1`). In both cases the tag +without its leading `v` must equal the `pyproject.toml` version exactly, and +`scripts/release-tag.py` checks that and derives the channel. A stable Release is +marked `latest`. A candidate is published as a GitHub prerelease, never `latest`, +and installers get it only with `pip install --pre` or an exact pin. The version +is set in the source PR by `scripts/mw-version.py` (see `docs/version-policy.md`), +never at tag time, so you tag the version that the reviewed `main` tip already +carries. A candidate becomes the stable version through a +`chore(release): promote version` PR. This guide names no version in advance. + +1. Set the version in the source PR with `scripts/mw-version.py`, not by editing + `pyproject.toml` by hand +2. Merge the PR to `main` after review and required checks. Merge every change + intended for the release now: first publication accepts only a tag on the + current `origin/main` tip, so a merge after tagging leaves the tag behind + `main` and the Release workflow refuses it 3. Create and push an immutable tag on the reviewed commit: - `git tag vX.Y.Z && git push origin vX.Y.Z` + `git tag vX.Y.Z && git push origin vX.Y.Z` (`vX.Y.ZrcN` for a candidate) Do **not** create the GitHub Release yet — validation must run first. 4. Owner runs the **Release** workflow (`workflow_dispatch`, GitHub Environment - `fava-release`) with input `tag=vX.Y.Z`. CI resolves draft-resume state first, + `fava-release`) with input `tag` set to the tag from step 3. CI resolves draft-resume state first, then proves `refs/tags/vX.Y.Z` peels to checked-out `HEAD` and either equals current protected `origin/main` (first publish) or is an ancestor of it (draft resume after main may have advanced), builds once, runs packaged gates - on the exact wheel+sdist (including sdist install and 0.6.0 upgrade), stages + on the exact wheel+sdist (including sdist install and the upgrade test from the + fixed published 0.6.0 baseline), stages or normalizes a **draft** GitHub Release (with `candidate-SHA256SUMS` and verified title/notes/target), publishes those same artifacts to PyPI, verifies published PyPI SHA-256 against `candidate-SHA256SUMS` (fail closed), then undrafts the Release only after that proof (reruns may resume a matching draft after metadata normalize; provenance env is `$GITHUB_ENV`-inherited, not expression-remapped). +Steps 5 to 7 are for the maintainer who owns the vendor copy and the client +registration, and they upgrade that runtime to a release you have published. They +are not part of feature development, where an installed or vendored checkout +that a client launches stays read-only (see "Working in this repository", item 3). + 5. Update the vendor copy: ```bash cd ~/git/vendor/fava-trails diff --git a/README.md b/README.md index 80edc84..0edae41 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ fava-trails install-jj `fava-trails version` prints the product version, the MCP SDK version and the loaded module path. Run it after every upgrade, because a local `uv run --directory` or vendor selector can keep an older checkout active. Restart the MCP client registration after you change the install. [docs/runtime-and-upgrade.md](docs/runtime-and-upgrade.md) explains how to check which install your client launches. -> **Release boundary.** This README describes the source on the main branch. Source features marked "from 0.9.0", including the local-reviewer bootstrap options and the recorded walkthrough, are not in a published package until a release announces them. The walkthrough was recorded on an installed 0.9.0rc1 candidate. Compare the output of `fava-trails version` with the [release history](CHANGELOG.md) before relying on a described behavior. +> **Release boundary.** This README describes the source on the main branch, which can be ahead of the package you installed. The local-reviewer bootstrap options (`--review-endpoint`, `--review-model` and `--review-key-env`) and the recorded walkthrough belong to that source. A published package has them only when its entry in the [release history](CHANGELOG.md) lists them, and an unpinned `pip install` skips pre-release candidates. Run `fava-trails version` and compare it with the release history before relying on a described behavior. The walkthrough was recorded on a locally built 0.9.0rc1 candidate that was never published. To work from source, see [Contributing](#contributing). @@ -173,7 +173,7 @@ For a reviewer that needs a credential, exporting it in the shell that starts Co The Trust Gate decides whether a proposed thought becomes an approved record. It is process control with limited context, not independent verification. Choosing a reviewer is a data-egress decision, because the candidate is sent to the configured destination before a verdict exists. -- **`llm-oneshot`** applies a rubric through a chat model. From 0.9.0 source, `fava-trails bootstrap` can write it for a local OpenAI-compatible server you name, using `--review-endpoint`, `--review-model` and `--review-key-env` together. With no review options, or with only some of them, bootstrap writes only the policy. On a fresh configuration that is incomplete, review fails closed until you finish it. Existing per-machine Trust Gate fields can complete or override the policy key by key, and a missing flag does not disable a reviewer that machine already has. When the effective destination differs from what the flags asked for, bootstrap reports it and can exit nonzero after it has created the data repository, so run `fava-trails doctor` and read the destination before the first promotion. The walkthrough records this route with Unsloth serving `unsloth/Qwen3.6-27B-GGUF`. +- **`llm-oneshot`** applies a rubric through a chat model. Where your installed version includes the local-reviewer options (see the release boundary under [Install](#install)), `fava-trails bootstrap` can write it for a local OpenAI-compatible server you name, using `--review-endpoint`, `--review-model` and `--review-key-env` together. With no review options, or with only some of them, bootstrap writes only the policy. On a fresh configuration that is incomplete, review fails closed until you finish it. Existing per-machine Trust Gate fields can complete or override the policy key by key, and a missing flag does not disable a reviewer that machine already has. When the effective destination differs from what the flags asked for, bootstrap reports it and can exit nonzero after it has created the data repository, so run `fava-trails doctor` and read the destination before the first promotion. The walkthrough records this route with Unsloth serving `unsloth/Qwen3.6-27B-GGUF`. - **`decisions`** sends one typed question to OpenRouter's Decisions API with TypeSafe's [Jev](https://openrouter.ai/blog/insights/what-is-jev/). A probability at or above `trust_gate_noul_threshold` approves. Jev returns a probability and no rejection rationale, so the record shows the probability and threshold and never an invented explanation. A repository or process with no Trust Gate settings keeps this behavior as the compatibility default, and a hosted Jev review needs an OpenRouter credential. - **Operator approval** through `propose_truth(..., approval="human")` on a separate operator-controlled endpoint records an explicit operator action and transmits nothing to a reviewer. @@ -197,7 +197,7 @@ Publishing and syncing are separate steps. For multi-machine authoring, set `push_strategy: immediate` or publish manually after writes, and have peers call `sync` to pull. Do not use `git push origin main` after JJ colocates, because it misses thought commits. The push procedure is in [AGENTS_SETUP_INSTRUCTIONS.md](AGENTS_SETUP_INSTRUCTIONS.md#pushing-to-remote). -To set up a second machine, install FAVA Trails and JJ as above, clone the same data repository with `fava-trails clone`, and register the MCP server with local paths and that machine's own `FAVA_TRAILS_AGENT_ID`. +To set up a second machine, install FAVA Trails and JJ as above, clone the same data repository with `fava-trails clone`, and register the MCP server with local paths and a `FAVA_TRAILS_AGENT_ID` that you choose deliberately. The value names a stable role, not a host, so a new machine does not need a new one. Processes that share an identity share its authoring view, so give independent authors separate identities and endpoints. ## Operating FAVA Trails @@ -282,7 +282,7 @@ FAVA Trails reaches models through [any-llm-sdk](https://github.com/mozilla-ai/a FAVA Trails supports optional lifecycle protocols: hook modules that run custom logic when a thought is saved, promoted or recalled. You register them in the data repository's `config.yaml`, and the server loads them at startup. [AGENTS_SETUP_INSTRUCTIONS.md](AGENTS_SETUP_INSTRUCTIONS.md#lifecycle-hooks) describes the hook system. -- **SECOM** compresses a thought once at promote time with extractive token-level compression from [LLMLingua-2](https://github.com/microsoft/LLMLingua), based on the [SECOM paper](https://arxiv.org/abs/2502.05589) (Tsinghua University and Microsoft, ICLR 2025). Only original tokens survive. Token-level compression can destroy JSON, YAML and fenced code, so tag such thoughts `secom-skip`. Install with `pip install fava-trails[secom]`, then `fava-trails secom setup --write`. Configuration and model options are in [the SECOM README](src/fava_trails/protocols/secom/README.md). +- **SECOM** compresses a thought once at promote time with extractive token-level compression from [LLMLingua-2](https://github.com/microsoft/LLMLingua), based on the [SECOM paper](https://arxiv.org/abs/2502.05589) (Tsinghua University and Microsoft, ICLR 2025). Only original tokens survive. The reviewer reads the draft as saved before this promotion attempt, which can already contain compressed text if an earlier step stored it. The compression hook runs inside the same `propose_truth` call, after the reviewer returns a verdict and before that verdict is applied and saved, so this attempt's compressed output is not reviewed again. The hook also runs when the verdict is a rejection or an error. When it compresses, the stored record holds the compressed text and the original draft stays in version history. The SECOM hook fails open on errors: with the default `fail_mode: open`, an error in the hook lets the promotion continue uncompressed. Token-level compression can destroy JSON, YAML and fenced code, so tag such thoughts `secom-skip`. Install with `pip install fava-trails[secom]`, then `fava-trails secom setup --write`. Configuration and model options are in [the SECOM README](src/fava_trails/protocols/secom/README.md). - **ACE** (Agentic Context Engineering) reranks recalled thoughts and detects anti-patterns using playbook rules stored in the `preferences/` namespace, based on [arXiv:2510.04618](https://arxiv.org/abs/2510.04618) (Stanford, UC Berkeley and SambaNova, ICLR 2026). It is included in the base install. Set it up with `fava-trails ace setup --write`. - **RLM** supports [MapReduce workflows](https://arxiv.org/abs/2512.24601) from MIT by validating mapper outputs, tracking batch progress and sorting results deterministically for reducer consumption. It is included in the base install. Set it up with `fava-trails rlm setup --write`. diff --git a/blueprints/features/local_review_default.blueprint.md b/blueprints/features/local_review_default.blueprint.md index fb23df4..e210ba2 100644 --- a/blueprints/features/local_review_default.blueprint.md +++ b/blueprints/features/local_review_default.blueprint.md @@ -13,7 +13,7 @@ date_added: 2026-10-24 - Design: approved at `fava-trails@dc7085a`, the revision the delivery coordinator reviewed and accepted under the operator's autonomous-delivery authority of 2026-10-24 ([recorded decision](https://github.com/MachineWisdomAI/fava-trails.org/issues/32#issuecomment-6388458186)). No human approval gate remains. - Implementation: Implemented in fava-trails PR #153 (version 0.9.0-rc.1) in `models.py`, `cli.py`, `trust_gate.py`, `tools/navigation.py` and `server.py`. The pre-change behavior in the table below was observed at `fava-trails@0f7c01f`. Deviations from the proposal: none in behavior. Two details the proposal left open are fixed here: `--review-model` also refuses FAVA's two Decisions model ids, and the informational line is carried as `trust_gate_policy_note` on a failed `propose_truth` response. - Evidence: fixture tests only, in `tests/test_local_review_default.py` (bootstrap options, endpoint refusals, machine-config overrides and exit status, each configuration row, promotion errors, explanation pass-through, Jev probability and threshold, down/401/malformed reviewers with no hosted fallback, timeout pass-through, doctor output), plus the three updated fixtures. The full suite passed on the PR head. Those fixtures do not show that any model gives useful rejection feedback. One separate run of the 0.9.0rc1 candidate against a real local model (two rejections with feedback, then approval and a superseding correction) is recorded in [the local review walkthrough](../../docs/local-review-walkthrough.md); it is one observation, not a benchmark. -- Release: a source merge only. Nothing is published to PyPI and no deployed MCP instance or stored record changed. Public documentation states the local default as available from 0.9.0 and must not describe it as installed until that package exists. +- Release: a source merge only. Nothing is published to PyPI and no deployed MCP instance or stored record changed. Public documentation describes the local default as a source feature, names a published release only after that release is verified to contain it, and must not describe it as installed until then. ## Problem and current behavior diff --git a/docs/blueprint-maintenance.md b/docs/blueprint-maintenance.md index 5d7513c..1c9e4e0 100644 --- a/docs/blueprint-maintenance.md +++ b/docs/blueprint-maintenance.md @@ -67,7 +67,7 @@ Do not rewrite the module's responsibilities or its input, output and credential **Tests.** The feature's verification table is the checklist. A required code or fixture row is satisfied only by a test that exists and passes. Listing such a row under known gaps records unfinished work; it does not satisfy the row, and the Implementation line stays `Partial` until the row passes. A row may sit in the gaps only while the change is explicitly labelled partial. The Blueprint also names three existing fixtures that use `llm-oneshot` with the default model and a mocked reviewer, `test_gateway_workflow.py`, `test_mcp_context.py` and `test_trust_gate_decisions.py`, which the new fail-closed check requires you to update. The configurations the Blueprint marks "correct" are the regression set for invariant 1. Run the project's checks as [CONTRIBUTING.md](../CONTRIBUTING.md) specifies: `uv run pytest -v` and `uv run ruff check src/ tests/`. -**Operating documents.** [AGENTS_SETUP_INSTRUCTIONS.md](../AGENTS_SETUP_INSTRUCTIONS.md) owns how to install and configure, so it gains the bootstrap options and the per-machine override report. The README quick start and Choose a reviewer section summarize it and must agree. The ownership table's summary column for this feature says "Nothing, until a release contains the change"; revisit that row when the release exists. +**Operating documents.** [AGENTS_SETUP_INSTRUCTIONS.md](../AGENTS_SETUP_INSTRUCTIONS.md) owns how to install and configure, so it gains the bootstrap options and the per-machine override report. The README quick start and Choose a reviewer section summarize it and must agree. The ownership table's summary column for this feature tells writers to describe it as a source feature and to name a published release only after that release is verified to contain it; revisit that row when the release exists. The approved wording table still applies. With a hosted reviewer, the text has already been sent when a reject is returned; a local reviewer keeps it on the configured host. The absence of a machine override does not by itself show that review stays local, because the explicit endpoint may also be remote. Review goes only to the effective destination the bootstrap report shows. Say "No request leaves the machine" only when that destination is a loopback or on-machine address and the report shows no override that redirects it. @@ -91,7 +91,7 @@ The rows from bootstrap writing the selection through the raised timeout concern ### 4. Separate the source change, the release and live acceptance -A pull request that changes code, tests, Blueprints and operating documents is a source change. Its description says which Status lines it moves and which it leaves. When it merges, label it merged but unreleased, as CONTRIBUTING.md directs, and leave the Release line at nothing published. Publication follows the release process in CONTRIBUTING.md: a version set in a source pull request through `scripts/mw-version.py` and `docs/version-policy.md`, packaging gates on the exact candidate artifacts, and the Release workflow. After the package is published, update the Release line, the ownership table row and the website summaries in their own changes. Release notes for earlier versions stay as written. +A pull request that changes code, tests, Blueprints and operating documents is a source change. Its description says which Status lines it moves and which it leaves. When it merges, label it merged but unreleased, as CONTRIBUTING.md directs, and leave the Release line at nothing published. Publication follows the release process in CONTRIBUTING.md: a version set in a source pull request through `scripts/mw-version.py` and `docs/version-policy.md`, packaging gates on the exact candidate artifacts, and the Release workflow. A first publication accepts only a tag on the current `main` tip, so merge every change intended for the release first. Write no version number or publication claim into a document before the release exists. After the package is published, update the Release line, the ownership table row and the website summaries in their own changes. Release notes for earlier versions stay as written. Live acceptance is a separate observation. Install the published package in the environment the client launches, check what ran with `fava-trails version` or `fava-trails doctor` as [runtime and upgrade](runtime-and-upgrade.md) describes, and run the scenario against a real local reviewer. Record the result in the Evidence line, naming the scenario, the reviewer and the package version. Until that record exists, documentation makes no claim about live behavior. diff --git a/docs/documentation-ownership.md b/docs/documentation-ownership.md index e72b40a..d9706e4 100644 --- a/docs/documentation-ownership.md +++ b/docs/documentation-ownership.md @@ -15,9 +15,11 @@ Each fact has one authoritative source. Other documents summarize it and link to | Operating rules: visibility modes, identity setup, replacement, interrupted-write guarantees and recovery | [governed-recall.md](governed-recall.md) | README fit-and-limits section, website, agent summaries | | Why the lifecycle works as it does: flow, publication, failure behavior | [Review-and-recall lifecycle](../blueprints/features/review_and_recall_lifecycle.blueprint.md) | Website lifecycle pages, case study | | The review gate's contract and the reasons behind it | [Review gate](../blueprints/modules/review_gate.blueprint.md) | Setup guide, README Choose a reviewer section | -| Which reviewer new installations use, and how existing configuration is preserved | [Local review default](../blueprints/features/local_review_default.blueprint.md) | Setup guide and README Choose a reviewer section. Say "from 0.9.0"; do not describe it as installed until a package containing it is published. | -| A recorded end-to-end walkthrough: local reviewer setup through rejection, revision, approval, recall and correction | [local-review-walkthrough.md](local-review-walkthrough.md) | README entry link, website operator guide. Candidate-evidence note changes only when a release is published. | +| Which reviewer new installations use, and how existing configuration is preserved | [Local review default](../blueprints/features/local_review_default.blueprint.md) | Setup guide and README Choose a reviewer section. Describe it as a source feature, and name a published release only after that release is verified to contain it. Do not describe it as installed, and do not assume a default `pip install` includes it: the reader checks `fava-trails version`. | +| A recorded end-to-end walkthrough: local reviewer setup through rejection, revision, approval, recall and correction | [local-review-walkthrough.md](local-review-walkthrough.md) | README entry link, website operator guide. The candidate-evidence note records a locally built, unpublished candidate and stays as dated history. When a verified release contains these features, add a pointer to it; do not rewrite the note into a release claim or a model benchmark. | | Runtime identity and upgrades | [runtime-and-upgrade.md](runtime-and-upgrade.md) | README upgrade notes | +| Maintainer release procedure: tag shape, Release workflow, vendor update | [CONTRIBUTING.md](../CONTRIBUTING.md) for the steps; `scripts/release-tag.py` and `.github/workflows/release.yml` for the rules they enforce | Release-candidate section of [runtime-and-upgrade.md](runtime-and-upgrade.md), [blueprint-maintenance.md](blueprint-maintenance.md) | +| When and how a version changes | [version-policy.md](version-policy.md) | CONTRIBUTING.md "Working in this repository" and "Release to PyPI" | | Release history | [CHANGELOG.md](../CHANGELOG.md), [releases/](releases/) | None. History is never edited to match later behavior. | | Website page layout and authoring rules | `AGENTS.md` in the [fava-trails.org](https://github.com/MachineWisdomAI/fava-trails.org) repository | Site contributors and agents | diff --git a/docs/fava_trails_faq.md b/docs/fava_trails_faq.md index 9ade44b..0cc68ee 100755 --- a/docs/fava_trails_faq.md +++ b/docs/fava_trails_faq.md @@ -1,4 +1,4 @@ -> **Historical background.** This FAQ was written for framework authors and records design and release states from earlier versions, including 0.6 and 0.7. Some answers describe defaults, comparisons and roadmap items that have since changed. It is kept for reference and is not the current contract. For what FAVA Trails does now, use the [README](../README.md), the [setup instructions](../AGENTS_SETUP_INSTRUCTIONS.md), [governed recall](governed-recall.md) and the [local review walkthrough](local-review-walkthrough.md), which was recorded on an installed 0.9.0rc1 candidate that is not published yet. +> **Historical background.** This FAQ was written for framework authors and records design and release states from earlier versions, including 0.6 and 0.7. Some answers describe defaults, comparisons and roadmap items that have since changed. It is kept for reference and is not the current contract. For what FAVA Trails does now, use the [README](../README.md), the [setup instructions](../AGENTS_SETUP_INSTRUCTIONS.md), [governed recall](governed-recall.md) and the [local review walkthrough](local-review-walkthrough.md), which was recorded on a locally built 0.9.0rc1 candidate that was never published. # FAVA Trails: Frequently Asked Questions diff --git a/docs/local-review-walkthrough.md b/docs/local-review-walkthrough.md index 241b8d0..86b554c 100644 --- a/docs/local-review-walkthrough.md +++ b/docs/local-review-walkthrough.md @@ -8,7 +8,7 @@ It is built from one recorded run, and that run is not a promise. The reviewer r ## What you need -- A FAVA Trails build that includes the `llm-oneshot` reviewer option, installed in an environment you control. +- A FAVA Trails build whose `bootstrap` command accepts `--review-endpoint`, `--review-model` and `--review-key-env`, installed in an environment you control. The source on main has them. A published package has them only when its entry in the [release history](../CHANGELOG.md) lists them, so check `fava-trails version` first. - An OpenAI-compatible chat endpoint you operate. The recorded run used a model served from the same machine as the FAVA Trails process, at a loopback address. - The API key for that endpoint, held in an environment variable. You give FAVA Trails the variable's name, never the key itself. Do not paste a key into a command line, a committed file or a chat. - An MCP client that can start a stdio server with environment variables. The recorded run used a plain stdio MCP client. diff --git a/docs/runtime-and-upgrade.md b/docs/runtime-and-upgrade.md index dcd15ac..6fb134c 100644 --- a/docs/runtime-and-upgrade.md +++ b/docs/runtime-and-upgrade.md @@ -123,6 +123,13 @@ Checklist after an upgrade: 4. For authoring endpoints, confirm `FAVA_TRAILS_AGENT_ID` is still set on the process env the client actually launches. +These steps change a runtime that you own. A maintainer who moves the vendor copy +to a published release follows the release steps in +[CONTRIBUTING.md](../CONTRIBUTING.md). Someone developing a feature does the +opposite: the installed or vendored checkout that a client launches stays +read-only, and a test client points at the developer's own checkout as described +under "Dog-food locally" in that guide. + ## Release candidate verification (pre-publish) Publication is **owner-gated** via `.github/workflows/release.yml` @@ -130,7 +137,8 @@ Publication is **owner-gated** via `.github/workflows/release.yml` `environment: fava-release` with required owner approval). The job: 1. Accepts `tag` only via job `env` (never raw shell interpolation). Validates - strict `vMAJOR.MINOR.PATCH` grammar, fetches `refs/tags/` only (not a + the tag grammar (stable `vMAJOR.MINOR.PATCH` or release candidate + `vMAJOR.MINOR.PATCHrcN`), fetches `refs/tags/` only (not a same-named branch), and fetches `refs/heads/main`. **Draft-resume state is resolved before the main relationship check** so a post-PyPI retry is not stranded when protected `main` advances after the tag was cut. First @@ -138,7 +146,7 @@ Publication is **owner-gated** via `.github/workflows/release.yml` an existing **draft** requires the tag commit to be an **ancestor** of protected `origin/main` (including equality). Detaches `HEAD` at the tag and asserts `git rev-parse HEAD` equals the tag peel (and equals `origin/main` on - first publish). Package version must match the tag. Provenance uses that + first publish). The package version must equal the tag without its leading `v`. Provenance uses that verified `HEAD` SHA — not workflow `GITHUB_SHA` from the dispatch ref. 2. Refuses a **published** GitHub Release for the tag; a **draft** Release may be resumed on rerun only after canonical title/notes/target are regenerated and @@ -148,7 +156,7 @@ Publication is **owner-gated** via `.github/workflows/release.yml` and sdist. 4. Sets `FAVA_CANDIDATE_WHEEL` / `FAVA_CANDIDATE_SDIST` to those exact files and runs `tests/test_packaged_mcp.py` — fresh wheel install, fresh sdist install, - real `0.6.0` → candidate upgrade, installed-entrypoint MCP (direct stdio **and** + an upgrade from published `fava-trails==0.6.0` to the candidate, installed-entrypoint MCP (direct stdio **and** native Inspector registration), two-process identity isolation, and governed recall (#72). 5. **Only after validation succeeds**, stages or normalizes a **draft** GitHub @@ -193,6 +201,13 @@ builds wheel + sdist itself. Either way it verifies fresh wheel install, sdist install, upgrade from published `fava-trails==0.6.0`, and re-runs the installed MCP + governance suites against the wheel. +The `0.6.0` starting point is a fixed fixture, not a moving "previous release". +The test installs published `fava-trails==0.6.0`, asserts that this is what was +installed, and upgrades it to the exact candidate wheel. That shows one published +version upgrading to the candidate. It does not name a supported minimum or the +latest previous release, and it does not show that an upgrade from any other +version works. + Post-publication proof: download the published wheel/sdist (or use the Release asset `candidate-SHA256SUMS`) and confirm SHA-256 matches the tested candidate set before trusting install instructions.