feat(v6.68.0): contributor fast path with target-bound review evidence

This commit is contained in:
Ouroboros 2026-07-17 07:52:58 +03:00
parent 543cc8376c
commit 058d578cb7
20 changed files with 1840 additions and 194 deletions

91
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,91 @@
<!--
Thank you for contributing to Ouroboros.
Open this PR against the `ouroboros` branch, not `main` or
`ouroboros-stable`. Keep review artifacts out of the git diff: attach or link
them in the Review evidence section instead.
-->
## Summary
<!-- What changes, and why is it needed? Link an issue or discussion when relevant. -->
## Scope
In scope:
-
Non-goals:
-
## Verification
<!-- List exact commands and outcomes. Do not write only "tests pass". -->
- [ ] Focused tests for the changed behavior pass.
- [ ] The default local test suite passes, or the reason it was not run is below.
- [ ] Lint/static checks relevant to this change pass.
Commands and results:
```text
```
## Visual evidence
<!-- Check one. Visible UI changes need evidence from a real rendered flow. -->
- [ ] Not applicable; this PR has no visible UI change.
- [ ] Before/after screenshots or other rendered-flow evidence are attached below.
Evidence:
## Governance and documentation
- [ ] I followed `CONTRIBUTING.md` and checked the relevant guidance in
`BIBLE.md`, `docs/ARCHITECTURE.md`, `docs/DEVELOPMENT.md`, and
`docs/CHECKLISTS.md`.
- [ ] I updated tests and documentation where behavior or architecture changed.
- [ ] I did not include secrets, local settings, runtime state, logs, caches, or
generated build/review artifacts in the commit.
- [ ] I did **not** bump `VERSION` or release-only version carriers; maintainers
assign the collision-free release version during final integration.
## Agent assistance (optional)
<!-- Disclosure is useful context, not a quality signal. Remove this section if unused. -->
- Agent/tool and model:
- Work performed by the agent:
- Human verification performed:
## Review evidence
<!--
Attach or link the final triad/scope review output when available. Evidence must
correspond to the current PR diff; rerun it after code changes or a rebase. If it
was not run, say why. Missing evidence does not prevent opening a PR, but it can
make maintainer integration slower.
-->
- [ ] Triad/scope review evidence is attached or linked below.
- [ ] Review was not run; the reason is recorded below.
- Reviewed base SHA:
- Reviewed head/diff SHA:
- Review command/profile:
- Triad verdict:
- Scope verdict:
- Run artifacts/link:
- Known advisory findings or accepted tradeoffs:
- If not run, reason:
## Final checklist
- [ ] The PR base branch is `ouroboros`.
- [ ] The branch is based on a current `ouroboros` revision.
- [ ] The PR is one coherent change and is ready to be squash-integrated.
- [ ] The description explains any limitations, follow-up work, or compatibility impact.

View file

@ -1,6 +1,6 @@
# Ouroboros CI — Five-tier cross-platform testing and release pipeline
#
# Tier 1 (Quick): Push to ouroboros (code paths) → Ubuntu-only tests (~1 min)
# Tier 1 (Quick): Push to ouroboros or PR targeting ouroboros → Ubuntu-only tests (~1 min)
# Tier 2 (Full): Push to ouroboros-stable / manual / tag → Full 3-OS matrix (~5 min)
# Tier 2.5 (Integration): Push to main / ouroboros / ouroboros-stable / manual / tag → Real-provider tests (~2 min)
# Tier 2.6 (Skill smoke): Push to ouroboros-stable / manual / tag → LIVE OuroborosHub official-skill install smoke (3-OS, ~5 min)
@ -36,22 +36,34 @@ on:
- 'packaging/**'
- 'VERSION'
- 'README.md'
- 'CONTRIBUTING.md'
- 'LICENSE'
- '.github/PULL_REQUEST_TEMPLATE.md'
- 'launcher.py'
tags:
- 'v*'
# Fork-safe PR validation: no provider secrets and no pull_request_target.
# Only the deterministic quick-test job matches pull_request refs below.
pull_request:
branches: [ouroboros]
workflow_dispatch:
# Note: GitHub Actions evaluates `branches` + `paths` together but `tags`
# separately — a tag push matching `v*` will trigger regardless of paths.
# Read-only is sufficient for tests and fork PRs. The release job overrides
# this narrowly with contents: write when publishing a tag.
permissions:
contents: read
jobs:
# ──────────────────────────────────────────────────────────────────
# Tier 1: Quick tests on Ubuntu (every push to ouroboros)
# Tier 1: Quick tests on Ubuntu (push to ouroboros or PR targeting it)
# ──────────────────────────────────────────────────────────────────
quick-test:
if: |
github.event_name == 'push'
&& github.ref == 'refs/heads/ouroboros'
(github.event_name == 'push' && github.ref == 'refs/heads/ouroboros')
|| (github.event_name == 'pull_request' && github.base_ref == 'ouroboros')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

View file

@ -22,5 +22,5 @@ jobs:
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
set -euo pipefail
gh pr comment "$PR_URL" --body "Thanks for contributing. This repository is an active mirror. Please reopen this pull request against the official repository: https://github.com/razzant/ouroboros"
gh pr comment "$PR_URL" --body "Thanks for contributing. This repository is an active mirror. Please reopen this pull request against the lowercase \`ouroboros\` branch of the official repository: https://github.com/razzant/ouroboros. Follow https://github.com/razzant/ouroboros/blob/ouroboros/CONTRIBUTING.md for the contributor workflow."
gh pr close "$PR_URL"

View file

@ -46,7 +46,8 @@ jobs:
> This repository is an active mirror of the official Ouroboros repository:
> **https://github.com/razzant/ouroboros**
>
> Please open issues, pull requests, discussions, and release questions in `razzant/ouroboros`.
> Please open issues, discussions, and release questions in `razzant/ouroboros`.
> Open pull requests against its lowercase `ouroboros` branch and follow `CONTRIBUTING.md` there.
"""
if not text.startswith("> [!IMPORTANT]\n> This repository is an active mirror"):

View file

@ -1,47 +1,292 @@
# Contributing to Ouroboros
External contributions are welcome. This file is only a contributor-facing
routing guide; the project rules live in the canonical docs.
Thank you for helping Ouroboros evolve. This guide explains how to prepare a
pull request that is easy to understand, reproduce, review, and integrate.
## Canonical Docs
The short version:
- `README.md` - install, source setup, tests, build notes, and user-facing overview.
- `BIBLE.md` - constitutional principles and design priority.
- `docs/ARCHITECTURE.md` - current structure, runtime/data map, endpoints, and release model.
- `docs/DEVELOPMENT.md` - engineering conventions, module boundaries, and testing guidance.
- `docs/CHECKLISTS.md` - review checklist single source of truth.
1. Base your work on the lowercase `ouroboros` branch and open the pull request
against `ouroboros`, not `main` or `ouroboros-stable`.
2. Read the project governance and engineering documents before making a
substantive change.
3. Keep the pull request focused, test the changed behavior, and show rendered
evidence for visible UI changes.
4. Do not bump the project version. Maintainers assign the final release
version when integrating the pull request.
5. Optionally attach a current triad + scope review packet to enter the faster
review path.
If this file and a canonical doc disagree, the canonical doc wins. Update the
canonical doc instead of copying detailed rules here.
The pull request template in
[`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md) mirrors
this flow.
## Before Opening a PR
## Read the Project Before Changing It
1. Follow the `README.md` source setup and test instructions.
2. Read the relevant part of `docs/DEVELOPMENT.md` before changing runtime,
tools, platform code, provider calls, web UI, skills, prompts, or governance docs.
3. Keep the PR focused on one coherent change.
4. Add or update tests for changed behavior.
5. In the PR body, explain why the change is needed, link the issue when there
is one, and include the exact commands or checks you ran.
For substantive changes, read these files **in full** before designing or
editing:
## Review Notes
- [`BIBLE.md`](BIBLE.md) — constitutional principles and design priorities.
- [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) — the current structural and
operational map, including the rationale for non-obvious decisions.
- [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) — engineering conventions,
module boundaries, testing guidance, and the commit/review protocol.
- [`docs/CHECKLISTS.md`](docs/CHECKLISTS.md) — the review checklist single
source of truth.
External PRs are reviewed by maintainers with local checks and any configured
automation. Ouroboros also has an internal self-modification commit gate;
contributors do not need to run that gate for a normal fork PR, but
`docs/CHECKLISTS.md` is the best summary of what reviewers will care about.
Use the existing modules, contracts, and single sources of truth described in
those documents before introducing a new mechanism. If a coding agent is doing
the work, give it the same instruction explicitly. A useful starting prompt is:
## Sensitive Areas
> Before editing, read BIBLE.md, docs/ARCHITECTURE.md,
> docs/DEVELOPMENT.md, and docs/CHECKLISTS.md in full. Follow their current
> principles and reuse the architecture and existing extension seams instead
> of inventing parallel mechanisms. Keep the change focused and verify it
> against the repository's tests and review checklist.
Ask before making broad changes to constitutional docs, runtime prompts, safety
policy, frozen contracts, release/build plumbing, managed git behavior, or
runtime state under `data/`. These areas have stronger review expectations
because they affect identity, safety, compatibility, or release provenance.
These documents are authoritative descriptions of the current project, not
immutable external rules. A pull request may improve `BIBLE.md`, the
architecture, development practices, or review checklists. Explain why the
change is needed, what invariant it preserves or intentionally evolves, and
keep related code, tests, and documentation consistent. Constitutional changes
must also respect the change process and semantic protections stated in
`BIBLE.md` itself.
Do not include secrets, local settings, generated runtime state, logs, caches,
or build artifacts in a PR.
## Choose a Focused Change
## License
Prefer one coherent purpose per pull request. The description should make the
following clear:
By contributing, you agree that your contribution can be released under the
repository license.
- the problem or opportunity;
- what changed and why this approach fits the existing architecture;
- what is deliberately out of scope;
- compatibility, migration, safety, or operational risks;
- the exact verification performed and its result.
For a broad, ambiguous, security-sensitive, constitutional, or
direction-changing proposal, opening an issue or discussion first can avoid
expensive rework. Small, well-understood fixes do not need ceremonial design
work.
Do not commit local settings, API keys, runtime state, logs, caches, benchmark
runs, generated review runs, or build artifacts. Runtime data belongs outside
the git repository.
## Branch and Pull Request Flow
Keep an `upstream` remote pointed at the official repository and start from the
latest working branch:
```bash
git remote add upstream https://github.com/razzant/ouroboros.git # once
git fetch upstream
git switch -c your-focused-branch upstream/ouroboros
```
If `upstream` already exists, verify it instead of adding it again. Before final
verification and review evidence, update your branch and resolve any drift:
```bash
git fetch upstream
git rebase upstream/ouroboros
```
Open the pull request with the base branch set to lowercase `ouroboros`.
`main` is protected, and `ouroboros-stable` is a recovery branch rather than
the contribution target.
Keep the worktree clean when producing final evidence: commit the intended
changes on your pull request branch, then confirm that `git status --short` is
empty. The contributor review command examines a committed base-to-head range;
it does not approve uncommitted edits.
### Do not bump the version
External contributors should not edit release-only version carriers for a
normal pull request: `VERSION`, the package versions, README badge/history,
the architecture version header, or release tags. Ouroboros treats an
integrated commit as a release, but maintainers assign the collision-free
version during final integration, normally while squash-integrating the pull
request. This avoids unrelated version conflicts between concurrent
contributions.
You may still update ordinary README or architecture content when the behavior
or structure changes; leave only the release number to the maintainer.
## Verification
Install the source environment using
[`README.md` → Run from Source](README.md#run-from-source). The default local
suite is documented in [`README.md` → Run Tests](README.md#run-tests):
```bash
make test
```
Run the narrowest relevant tests while developing, then the repository's
default local test suite when practical. Record the exact commands and
outcomes in the pull request; “tests pass” without a command is not
reproducible evidence. Follow the marker and environment guidance in
[`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) for integration, browser,
portable, and skill-smoke lanes.
Add or update tests for changed behavior. If a test cannot be run in your
environment, say which one and why rather than marking it as passed.
For a visible UI change:
1. Open at least one relevant real user flow in an available browser.
2. Inspect the rendered result, including the states and viewport sizes that
matter for the change.
3. Attach before/after screenshots or equivalent evidence and state what was
actually inspected.
A saved screenshot that nobody inspected is not visual verification. Mobile
or WebKit evidence is risk-driven rather than mandatory for every UI change.
## Optional Fast Path: Triad + Scope Review
A contributor-supplied triad + scope packet is optional, but it materially
reduces the work needed to evaluate a pull request. A current, complete packet
places the pull request on the faster review path. A pull request without one
may still be considered, but Ouroboros and the maintainers must reproduce the
review and may need to revise the change manually; that path is slower and the
pull request is more likely to be deferred when maintainer capacity is limited.
Neither a clean packet nor its absence decides acceptance. A passing review is
evidence, not a promise to merge, and maintainers may rerun it or request
additional changes.
If the pull request changes the review substrate itself — for example the
review script, reviewer configuration, review checklists, or production review
code — its contributor packet is diagnostic only. A maintainer must rerun the
review from a trusted target-base implementation before integration.
### What the contributor review runs
The checked-in
[`scripts/run_external_review.py`](scripts/run_external_review.py) contributor
mode runs the production triad and scope review over the committed range from
the target base to your branch head. It deliberately:
- resolves the reviewer models and reasoning efforts from the shipped defaults
in the target `ouroboros` revision, not from values modified by the pull
request;
- routes every triad and scope reviewer through OpenRouter;
- applies the clean blocking contract for the contributor packet;
- does **not** run the Claude advisory pre-review and does not require an
Anthropic key;
- records the exact base/head binding and full reviewer evidence without
committing or modifying the reviewed branch.
Triad completeness follows Ouroboros's production quorum contract together
with an authoritative scope verdict; it does not require every configured
actor to respond. The packet preserves actor statuses and degraded reasons, so
any failed, partial, or unparsable actor must still be disclosed even when the
remaining actors satisfy quorum.
Do not override the reviewer models, scope-review model, reasoning efforts, or
provider. The value of this packet is that every contributor uses the review
configuration selected by the current target version of Ouroboros.
### Produce a packet
First fetch and rebase on the current target, commit the final change, and
confirm the worktree is clean. Configure your own `OPENROUTER_API_KEY` without
placing it in a command argument, tracked file, shell history, or attachment.
Also set `TOTAL_BUDGET` to a positive finite USD ceiling that you explicitly
authorize for this run; contributor mode fails before model calls when that
ceiling is missing or invalid. The review calls may incur OpenRouter charges,
so use a key with sufficient remaining provider balance and check current
pricing before choosing the ceiling. For example:
```bash
export TOTAL_BUDGET="<authorized USD ceiling>"
```
Then run from the repository root:
```bash
python scripts/run_external_review.py \
--contributor \
--base-ref upstream/ouroboros \
--head-ref HEAD \
"<PR title>" \
--goal "<goal>" \
--scope "<scope>"
```
The script creates:
- `review-evidence.json` — machine-readable base/head, configuration, actor,
verdict, and outcome evidence;
- `full-output.txt` — full human-readable triad and scope output;
- `review-packet.zip` — the attachment-ready packet.
Use the fresh output directory printed by the command. Review packets are
operator artifacts: attach them to the pull request, but do not add them to the
git diff.
### Attach and summarize the evidence
In the pull request's **Review evidence** section:
1. Attach `review-packet.zip` and, when useful for quick inspection,
`review-evidence.json` and `full-output.txt`.
2. Record the reviewed base SHA and head SHA.
3. Record the exact command/profile and the resolved reviewer model IDs.
4. Summarize every triad actor verdict, the aggregate triad result, and the
scope verdict.
5. Disclose known advisory findings, accepted trade-offs, infrastructure
failures, skipped coverage, or other non-clean conditions. Do not present a
failed or incomplete run as a pass.
The evidence is valid only for the recorded head and base. Rerun it after any
code change, rebase, conflict resolution, or other change to the reviewed
range. Do not cherry-pick only favorable actor outputs or substitute a
screenshot for the raw records.
### Protect secrets and private data
Treat review output as public before uploading it. Attach only the generated
packet, not the review drive, local observability store, `settings.json`, or an
environment dump. Inspect the packet for API keys, authorization headers,
credentials, private paths, or unrelated local data even when automatic
redaction reports success.
If redaction is necessary, preserve all verdicts and finding structure and
state exactly what was removed. Never upload a secret and never commit a
credential in order to make review reproducible; revoke any credential that
was exposed.
## Pull Request Checklist
Before marking the pull request ready for review, confirm that:
- the base branch is `ouroboros` and the branch is current with its intended
base revision;
- the pull request has one coherent purpose with explicit non-goals;
- the description explains the architectural fit and important trade-offs;
- relevant tests pass, with exact commands and outcomes recorded;
- behavior and architecture documentation are updated where necessary;
- visible UI changes include inspected rendered-flow evidence;
- no version or release-only carrier was bumped by the contributor;
- no secrets, local state, logs, caches, generated runs, or build artifacts are
present in the diff;
- triad + scope evidence is attached and current, or the reason it was not run
is stated honestly;
- limitations, unresolved findings, and follow-up work are disclosed.
Disclosure of coding-agent assistance is optional. If you include it, name the
agent/model, what it changed, and what a human or independent process verified.
Agent use is context, not a positive or negative quality signal.
## What Happens After Submission
Maintainers may reproduce tests, rerun triad + scope review, ask for a smaller
diff, request changes, or integrate the contribution with additional fixes and
the final release-version update. Review evidence accelerates that process but
does not replace maintainer judgment or Ouroboros's own governance gates.
Contributions are licensed under the repository's
[`LICENSE`](LICENSE). By submitting a contribution, you confirm that you have
the right to provide it under those terms.

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Anton Razzhigaev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -7,7 +7,7 @@
[![Linux](https://img.shields.io/badge/Linux-x86__64-orange.svg)](https://github.com/razzant/ouroboros/releases)
[![Windows](https://img.shields.io/badge/Windows-x64-blue.svg)](https://github.com/razzant/ouroboros/releases)
[![OuroborosHub](https://img.shields.io/badge/OuroborosHub-skills%20marketplace-8A2BE2.svg)](https://github.com/razzant/OuroborosHub)
[![Version 6.67.0](https://img.shields.io/badge/version-6.67.0-green.svg)](VERSION)
[![Version 6.68.0](https://img.shields.io/badge/version-6.68.0-green.svg)](VERSION)
A self-modifying AI agent that writes its own code, rewrites its own mind, and evolves autonomously. Born February 16, 2026.
@ -517,9 +517,11 @@ not paraphrase it.
## Contributing
External contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
for the contributor workflow. The project rules remain in `BIBLE.md`,
`docs/ARCHITECTURE.md`, `docs/DEVELOPMENT.md`, and `docs/CHECKLISTS.md`;
the contribution guide only routes to those sources.
for the complete workflow. Open pull requests against the lowercase
`ouroboros` branch and leave release-version allocation to maintainers. A
current OpenRouter triad + scope packet is the optional fast path; pull
requests without one remain welcome but require more maintainer-side review
and integration work.
---
@ -527,6 +529,7 @@ the contribution guide only routes to those sources.
| Version | Date | Description |
|---------|------|-------------|
| 6.68.0 | 2026-07-17 | **feat: contributor fast path with target-bound review evidence.** External pull requests now have one explicit public flow: target lowercase `ouroboros`, read the governance/architecture/development SSOTs in full, keep proposals focused, leave collision-prone release versions to the final maintainer squash landing, and attach reproducible evidence when practical. A GitHub PR template gathers scope, tests, rendered UI evidence, optional agent disclosure, and review provenance; fork-safe read-only `pull_request` CI runs the deterministic quick lane without provider secrets; the repository now carries its explicit MIT license. `scripts/run_external_review.py --contributor` reviews a clean committed target-base..head tree with shipped target-base reviewer defaults forced through OpenRouter at blocking enforcement, excludes Claude advisory while preserving a serial hermetic per-commit suite whose child environment scrubs live behavior overrides and secret-class values (CI alone keeps the parallel/non-serial plus serial split), probes every triad/scope route, forbids contributor `VERSION` bumps, defers only the typed release-carrier checklist items without masking scope failure, refuses self-attested review-substrate changes as fast-path proof, and emits a fully redacted SHA-bound JSON/text/ZIP packet. Contributor readiness accelerates triage but never replaces the final P9 version allocation or production commit review. |
| 6.67.0 | 2026-07-16 | **feat: composable declarative widgets and evidence-based UI acceptance.** Declarative schema v1 gains recursive `group`, `metric`, and `callout` composition, stable nested identity, bounded validation, shared safe fields, accessible chart fallbacks, and a native kanban Move-to path while preserving the host-owned trust boundary and all existing declarations. Visible UI completion now requires an available real consumer flow to be opened and its rendered evidence actually inspected with vision; the LLM selects states, viewports, and optional engines by risk, without a blanket mobile/WebKit matrix or a new QA service. The constitution now makes autonomous judgment and smallest-class-fix scope explicit, DEVELOPMENT records pragmatic SOLID and mutable external facts without adding analyzers or runtime lookup migrations, and reviewer prompts reject numeric finding pressure in favor of concrete evidenced defects. The operator review wrapper additionally probes the exact reviewer model through each candidate OpenRouter key before selecting it — `limit_remaining` alone is documented to pass ToS-blocked keys. |
| 6.66.0 | 2026-07-16 | **feat: honest mutation attribution, attributed commit staging, environment-correct Python, auditable Skill Review history, and a drift-proof operator review wrapper.** The host now captures a `system_repo` baseline (exact commit/tree + pre-existing dirty fingerprints) in the existing task result when a root task starts and a terminal candidate snapshot at outcome derivation; blockers ride into acceptance/review evidence for the LLM panels — deliberately never a structural outcome veto, and deliberately WITHOUT any lease/holder service (physical exclusion is out of scope; a future separate design). `commit_reviewed` stages only clean-at-baseline task-attributed candidates: explicit paths must be a subset and an empty set is `GIT_NO_ATTRIBUTED_CHANGES`, never whole-tree staging (managed update/release transactions keep their typed `git add -A`; baseline-less contexts keep the legacy contract). The four user launch surfaces resolve unversioned `python`/`python3` once in registry pre-dispatch (reviewed skill env → executor backend → project `.venv` → verified agent interpreter) with traced provenance and a fail-closed unproved-interpreter path. Skill Review gains group-wide `review_round` + per-snapshot `snapshot_attempt` with exact task/chat/source provenance in the existing job/history files and a compact UI projection. Child-result dispositions consolidate into the single task-tree ledger row authority (task-result fields become read-time projections; explicit cancellation wins completion races with bounded scratch cleanup, no recovery surface; in-flight ≤v6.65 trees re-emit their dispositions once after upgrade). `scripts/run_external_review.py` becomes a thin SSOT wrapper over the production gate: real advisory by default, frozen detached-checkout review, OpenRouter key health-check from the named pool, and typed exit codes separating infrastructure failures from genuine review blocks; the hermetic pytest preflight substitute runs parallel non-serial with a bounded worker count. Fixes the chronic red CI light-model routing test. This operator phase intentionally advances `VERSION` ahead of the latest annotated tag; the final Phase 3 release publishes the closing tag. |
| 6.65.4 | 2026-07-16 | **fix: a zero-usage provider body-error settles a confirmed \$0, not a phantom reservation.** The v6.64.0 physical-attempt ledger settles an HTTP-200 whose body is a top-level provider error (OpenRouter passes 429/5xx/4xx through the body) with `cost=None` and keeps its conservative reservation upper bound as an unresolved amount. Under a provider storm each reroute/strip/fallback is a fresh attempt, so the held bounds accumulate (7 x ~\$2.4 = ~\$16.7) and exhaust the finite task budget while real spend stays small — SWE-Pro tasks died `budget_exhausted` at ~\$7.5 of a \$25 cap. Such a request billed zero tokens (rejected before generation), so `usage_from_response` now settles it as a confirmed \$0 and RELEASES the bound. The under-count protection is intact: any billed tokens (a partial stream or an unknown-price success, prompt/completion > 0) keep the normal cost path and their bound, and the opaque-SDK path still settles via `mark_unresolved`. |

View file

@ -1 +1 @@
6.67.0
6.68.0

File diff suppressed because one or more lines are too long

View file

@ -468,6 +468,36 @@ findings are advisory-only and never replace the full-cap blocking scope-review
floor. `docs/CHECKLISTS.md` remains the single source of truth for review items;
do not duplicate or fork checklist policy here.
### External PR readiness is not commit authorization
`scripts/run_external_review.py --contributor` reuses the production triad and
scope substrate for a non-committing proposal review. It is structurally
different from `commit_reviewed`:
- the exact current target-base commit must be an ancestor of the clean,
committed proposal head;
- reviewer slots, efforts, and scope floor come from literal shipped defaults
in that target-base checkout, local overrides are ignored, every reviewer is
routed through OpenRouter, and enforcement is blocking;
- Claude advisory is excluded; the hermetic deterministic test preflight still
runs before triad + scope. Its child pytest receives only disposable
data/settings/repo roots: live `OUROBOROS_*` behavior overrides and
secret-class environment values are scrubbed;
- external contributors do not allocate `VERSION` or release-only carriers.
The typed `version_bump` and `changelog_and_badge` items are recorded as final
squash-landing obligations when they are the only critical findings; no other
checklist item can be demoted this way;
- evidence binds target base, proposal head/tree, diff hash, target config, and
resolved actors in a redacted shareable packet. A proposal that changes the
review substrate cannot self-attest fast-path readiness and requires a
trusted maintainer rerun.
The result is `READY_FOR_INTEGRATION`, not merge authority. Maintainers apply a
coherent author-attributed squash onto current `ouroboros`, choose the actual
MAJOR/MINOR/PATCH version, synchronize all P9 carriers, and run the ordinary
production review against the exact landing parent/tree/VERSION/tag binding.
If the target advances, that final binding is rebuilt and reviewed again.
The commit gate is intentionally one-pass: one substantive request per triad
slot and one per scope slot. Do not reuse task-acceptance retries, generic
capability resolvers, chunk fan-out, or degraded Low retries to multiply P3

View file

@ -14,35 +14,12 @@ from typing import Optional, Sequence
DEFAULT_PYTEST_ARGS = ["tests/", "-q", "--tb=line", "--no-header"]
def _preflight_worker_count() -> int:
"""Bounded xdist parallelism: fast on big hosts, polite on shared ones."""
raw = os.environ.get("OUROBOROS_PREFLIGHT_PYTEST_WORKERS", "")
try:
parsed = int(raw)
if parsed > 0:
return parsed
except (TypeError, ValueError):
pass
return max(1, min(16, os.cpu_count() or 1))
def _default_preflight_pytest_args() -> list[str]:
"""Parallel hermetic smoke mirroring the CI quick-test lane.
A command-line ``-m`` REPLACES the pyproject ``addopts`` markexpr, so the
full default-exclusion list must be repeated here — otherwise the network/
browser lanes (skill_smoke, integration, ui_browser, ...) silently enter
every hermetic preflight. The serial lane and the full suite remain the
caller's separate responsibility (CI / operator runs).
"""
return [
*DEFAULT_PYTEST_ARGS,
"-n", str(_preflight_worker_count()),
"--dist", "loadscope",
"-m",
"not serial and not integration and not browser and not ui_browser"
" and not ui_browser_docker and not portable_detail and not skill_smoke",
]
"""Serial hermetic gate; CI alone owns the parallel/serial split."""
# Do not pass ``-m`` here: the repository's pyproject addopts remains the
# SSOT for excluding integration/browser/portable/smoke marker lanes, while
# serial-marked default-suite tests stay inside the fail-closed commit gate.
return list(DEFAULT_PYTEST_ARGS)
def _run_git(repo_dir: pathlib.Path, args: Sequence[str], *, input_text: str = "", timeout: int = 30) -> subprocess.CompletedProcess[str]:
@ -90,15 +67,19 @@ def _copy_untracked(repo_dir: pathlib.Path, worktree: pathlib.Path) -> None:
def _preflight_env(temp_root: pathlib.Path, repo_worktree: pathlib.Path) -> dict:
env = dict(os.environ)
env.pop("OUROBOROS_MANAGED_BY_LAUNCHER", None)
# Scrub secret-class variables: the hermetic preflight pytest must not
# inherit live credentials — a (possibly self-written) test could exfiltrate
# or spend with them. OUROBOROS_* wiring stays (suite needs it).
# The candidate suite must not inherit live runtime behaviour or credentials.
# A disposable data/settings/repo triple is injected below; every other
# OUROBOROS_* value is owner/runtime state, not test wiring. Keeping those
# values made a supposedly hermetic preflight depend on the operator's live
# safety/review/mode settings and could also expose prefixed secrets to a
# self-written test.
secret_suffixes = ("_API_KEY", "_TOKEN", "_PASSWORD", "_CREDENTIALS", "_SECRET")
for key in list(env):
if key.startswith("OUROBOROS_"):
continue
if key.endswith(secret_suffixes) or key.startswith("GH_"):
if (
key.startswith("OUROBOROS_")
or key.endswith(secret_suffixes)
or key.startswith("GH_")
):
env.pop(key, None)
temp_root = pathlib.Path(temp_root).resolve(strict=False)
repo_worktree = pathlib.Path(repo_worktree).resolve(strict=False)

View file

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "ouroboros"
version = "6.67.0"
version = "6.68.0"
description = "Self-creating AI agent with constitution, background consciousness, and persistent identity"
readme = "README.md"
license = {text = "MIT"}

File diff suppressed because it is too large Load diff

View file

@ -67,6 +67,12 @@ _SERIAL_TEST_FILES = frozenset({
# trees / sweeps processes referencing a temp root → can collateral-damage sibling xdist
# workers under -n (their unrelated tests then fail as a crashed-worker batch).
"test_preflight_runner.py",
# Imports/mutates the process-global server settings facade; when xdist
# reuses a worker after unrelated server tests, cached route/probe state can
# escape monkeypatch restoration and turn the mocked capability probe into
# a real network attempt. Keep the whole hot-reload contract in the serial
# lane, matching its process-global subject.
"test_settings_budget_hotreload.py",
# spawns real long-lived sleeper subprocesses via the legacy ouroboros.tools.services path
# AND mutates the module-global tools.services._SERVICES (NOT covered by the
# _isolate_workspace_executor_globals fixture, which isolates a different dict).

View file

@ -0,0 +1,52 @@
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_public_contributor_flow_targets_working_branch_and_real_review_profile():
guide = (ROOT / "CONTRIBUTING.md").read_text(encoding="utf-8")
assert "against `ouroboros`, not `main` or `ouroboros-stable`" in guide
assert "--contributor" in guide
assert "--base-ref upstream/ouroboros" in guide
assert "--head-ref HEAD" in guide
assert "does **not** run the Claude advisory pre-review" in guide
assert "Do not bump the version" in guide
assert "review-packet.zip" in guide
assert "evidence, not a promise to merge" in guide
def test_pull_request_template_collects_fast_path_evidence_without_version_bump():
template = (ROOT / ".github" / "PULL_REQUEST_TEMPLATE.md").read_text(
encoding="utf-8"
)
assert "The PR base branch is `ouroboros`" in template
assert "I did **not** bump `VERSION`" in template
assert "Reviewed base SHA" in template
assert "Triad verdict" in template
assert "Scope verdict" in template
assert "If not run, reason" in template
assert "Agent assistance (optional)" in template
def test_pull_request_ci_is_fork_safe_and_does_not_enable_provider_jobs():
workflow = (ROOT / ".github" / "workflows" / "ci.yml").read_text(
encoding="utf-8"
)
assert "pull_request:\n branches: [ouroboros]" in workflow
assert "\n pull_request_target:" not in workflow
assert "permissions:\n contents: read" in workflow
assert "github.event_name == 'pull_request' && github.base_ref == 'ouroboros'" in workflow
assert "release:\n" in workflow
assert " contents: write" in workflow
def test_repository_has_explicit_mit_license_holder():
license_text = (ROOT / "LICENSE").read_text(encoding="utf-8")
assert license_text.startswith("MIT License\n")
assert "Copyright (c) 2026 Anton Razzhigaev" in license_text
assert "Andrew Kaznacheev" not in license_text

View file

@ -471,6 +471,7 @@ def test_gaia_openai_websearch_pin_drops_base_url(monkeypatch):
assert "OPENAI_BASE_URL" not in env # dropped so official web_search stays enabled
@pytest.mark.serial
def test_gaia_render_injects_keys_and_free_host_service_port(tmp_path, monkeypatch):
# Out-of-the-box coexistence with a running desktop app: the rendered settings must
# carry a FREE Host-Service port (not the default 8767) and the REAL provider key for

View file

@ -1,19 +1,56 @@
from __future__ import annotations
import os
import subprocess
import zipfile
from pathlib import Path
from types import SimpleNamespace
import pytest
from scripts.run_external_review import (
_REVIEW_SUBSTRATE_PATHS,
_apply_contributor_landing_obligations,
_apply_contributor_review_env,
_assert_contributor_openrouter_config,
_classify_exit,
_contributor_snapshot,
_create_isolated_checkout,
_openrouter_key_health,
_openrouter_pool,
_remove_isolated_checkout,
_require_contributor_budget,
_resolved_review_config,
_review_evidence_and_cost,
_select_healthy_openrouter_key,
_settings_defaults_at_ref,
_write_contributor_packet,
)
def test_contributor_trust_boundary_covers_functional_review_dependencies():
from ouroboros.tools.scope_review import _CANONICAL_CONTEXT_DOCS
assert set(_CANONICAL_CONTEXT_DOCS).issubset(_REVIEW_SUBSTRATE_PATHS)
assert {
"docs/ARCHITECTURE.md",
"ouroboros/capability_evidence.py",
"ouroboros/code_intelligence.py",
"ouroboros/deadline_utils.py",
"ouroboros/outcomes.py",
"ouroboros/platform_layer.py",
"ouroboros/pricing.py",
"ouroboros/review_state.py",
"ouroboros/runtime_mode_policy.py",
"ouroboros/usage_accounting.py",
"ouroboros/utils.py",
"ouroboros/tools/claude_advisory_review.py",
"ouroboros/tools/registry.py",
"ouroboros/tools/release_sync.py",
"ouroboros/tools/review_synthesis.py",
}.issubset(_REVIEW_SUBSTRATE_PATHS)
def test_external_review_script_delegates_verdict_to_production_gate():
source = Path("scripts/run_external_review.py").read_text(encoding="utf-8")
assert "v6.10.0" not in source
@ -21,11 +58,12 @@ def test_external_review_script_delegates_verdict_to_production_gate():
assert "_run_non_committing_review_cycle" in source
assert "adaptive_quorum" not in source
assert "aggregate_review_verdict" not in source
# The wrapper stays thin: no operator-side re-binding layer, and the REAL
# advisory (not a bypass) is the default first stage.
# The default operator lane still runs the REAL advisory. Contributor mode
# explicitly skips it while reusing the production triad+scope cycle.
assert "operator_binding" not in source
assert "_handle_advisory_pre_review" in source
assert "skip_advisory_review=True" not in source
assert "skip_advisory_review=args.contributor" in source
assert "_CONTRIBUTOR_PROFILE = \"external_pr_readiness\"" in source
def test_external_review_script_defaults_to_pro_mode():
@ -51,6 +89,8 @@ def test_external_review_script_resolves_models_and_efforts(monkeypatch):
monkeypatch.setenv("OUROBOROS_SCOPE_REVIEW_MODELS", "openai/gpt-5.5")
monkeypatch.setenv("OUROBOROS_EFFORT_REVIEW", "high")
monkeypatch.setenv("OUROBOROS_EFFORT_SCOPE_REVIEW", "high")
monkeypatch.setenv("OUROBOROS_REVIEW_ENFORCEMENT", "blocking")
monkeypatch.setenv("OUROBOROS_SCOPE_REVIEW_FLOOR", "blocking_1m")
config = _resolved_review_config()
@ -62,6 +102,251 @@ def test_external_review_script_resolves_models_and_efforts(monkeypatch):
assert config["triad_effort"] == "high"
assert config["scope_models"] == ["openai/gpt-5.5"]
assert config["scope_effort"] == "high"
assert config["review_enforcement"] == "blocking"
assert config["scope_review_floor"] == "blocking_1m"
def _write_target_config(repo: Path) -> None:
package = repo / "ouroboros"
package.mkdir(exist_ok=True)
(package / "config.py").write_text(
"SETTINGS_DEFAULTS = {\n"
" 'OUROBOROS_REVIEW_MODELS': 'anthropic/fable,openai/sol,google/flash',\n"
" 'OUROBOROS_SCOPE_REVIEW_MODELS': 'anthropic/fable',\n"
" 'OUROBOROS_EFFORT_REVIEW': 'high',\n"
" 'OUROBOROS_EFFORT_SCOPE_REVIEW': 'high',\n"
" 'OUROBOROS_SCOPE_REVIEW_FLOOR': 'blocking_1m',\n"
"}\n",
encoding="utf-8",
)
def _init_contributor_repo(tmp_path: Path, monkeypatch) -> Path:
repo = tmp_path / "repo"
repo.mkdir()
_git(repo, "init")
_git(repo, "config", "user.email", "test@example.com")
_git(repo, "config", "user.name", "Test")
_git(repo, "config", "core.autocrlf", "false")
(repo / "scripts").mkdir()
(repo / "scripts" / "run_external_review.py").write_text("# base script\n", encoding="utf-8")
_write_target_config(repo)
(repo / "ouroboros" / "review_substrate.py").write_text(
"# trusted review substrate\n", encoding="utf-8"
)
(repo / "ouroboros" / "utils.py").write_text(
"# trusted review utilities\n", encoding="utf-8"
)
(repo / "ouroboros" / "tools").mkdir()
(repo / "ouroboros" / "tools" / "registry.py").write_text(
"# trusted review context\n", encoding="utf-8"
)
(repo / "pyproject.toml").write_text(
'[project]\nname = "test-project"\nversion = "1.2.3"\n',
encoding="utf-8",
)
(repo / "VERSION").write_text("1.2.3\n", encoding="utf-8")
(repo / "a.txt").write_text("base\n", encoding="utf-8")
_git(repo, "add", "-A")
_git(repo, "commit", "-m", "base")
_git(repo, "branch", "base")
(repo / "a.txt").write_text("proposal\n", encoding="utf-8")
_git(repo, "add", "a.txt")
_git(repo, "commit", "-m", "proposal")
import scripts.run_external_review as module
monkeypatch.setattr(module, "REPO", repo)
return repo
def test_target_base_defaults_override_local_review_settings(tmp_path, monkeypatch):
_init_contributor_repo(tmp_path, monkeypatch)
defaults = _settings_defaults_at_ref("base")
monkeypatch.setenv("OUROBOROS_REVIEW_MODELS", "local/override")
monkeypatch.setenv("OUROBOROS_EFFORT_REVIEW", "low")
_apply_contributor_review_env(defaults)
assert defaults["OUROBOROS_REVIEW_MODELS"] == (
"anthropic/fable,openai/sol,google/flash"
)
assert os.environ["OUROBOROS_REVIEW_MODELS"] == defaults[
"OUROBOROS_REVIEW_MODELS"
]
assert os.environ["OUROBOROS_EFFORT_REVIEW"] == "high"
assert os.environ["OUROBOROS_REVIEW_ENFORCEMENT"] == "blocking"
assert os.environ["OUROBOROS_OBSERVABILITY_KEEP_RAW"] == "0"
assert os.environ["OUROBOROS_PRE_PUSH_TESTS"] == "1"
assert os.environ["OUROBOROS_PREFLIGHT_DIFF_AWARE"] == "false"
def test_contributor_defaults_reject_explicit_direct_provider_route(monkeypatch):
defaults = {
"OUROBOROS_REVIEW_MODELS": "anthropic::claude-fable-5",
"OUROBOROS_SCOPE_REVIEW_MODELS": "anthropic/claude-fable-5",
"OUROBOROS_EFFORT_REVIEW": "high",
"OUROBOROS_EFFORT_SCOPE_REVIEW": "high",
"OUROBOROS_SCOPE_REVIEW_FLOOR": "blocking_1m",
}
with pytest.raises(RuntimeError, match="non-OpenRouter"):
_apply_contributor_review_env(defaults)
def test_contributor_budget_must_be_explicit_positive_and_finite(monkeypatch):
monkeypatch.delenv("TOTAL_BUDGET", raising=False)
with pytest.raises(RuntimeError, match="TOTAL_BUDGET is required"):
_require_contributor_budget()
for invalid in ("0", "-1", "inf", "not-a-number"):
monkeypatch.setenv("TOTAL_BUDGET", invalid)
with pytest.raises(RuntimeError, match="positive finite"):
_require_contributor_budget()
monkeypatch.setenv("TOTAL_BUDGET", "125.50")
assert _require_contributor_budget() == 125.5
def test_contributor_snapshot_binds_clean_base_head_and_tree(tmp_path, monkeypatch):
repo = _init_contributor_repo(tmp_path, monkeypatch)
snapshot = _contributor_snapshot("base", "HEAD")
assert snapshot["base_sha"] == snapshot["merge_base_sha"]
assert snapshot["target_version"] == "1.2.3"
assert snapshot["head_tree_sha"] == _git(repo, "rev-parse", "HEAD^{tree}").strip()
assert snapshot["changed_paths"] == ["a.txt"]
assert snapshot["review_substrate_changed"] == []
assert snapshot["diff_sha256"]
(repo / "dirty.txt").write_text("not committed\n", encoding="utf-8")
with pytest.raises(RuntimeError, match="not clean"):
_contributor_snapshot("base", "HEAD")
def test_contributor_snapshot_rejects_version_bump(tmp_path, monkeypatch):
repo = _init_contributor_repo(tmp_path, monkeypatch)
(repo / "VERSION").write_text("1.2.4\n", encoding="utf-8")
_git(repo, "add", "VERSION")
_git(repo, "commit", "-m", "bad contributor bump")
with pytest.raises(RuntimeError, match="must not bump VERSION"):
_contributor_snapshot("base", "HEAD")
@pytest.mark.parametrize(
"relative_path",
[
"ouroboros/review_substrate.py",
"ouroboros/utils.py",
"ouroboros/tools/registry.py",
],
)
def test_contributor_snapshot_flags_transitive_review_substrate_changes(
tmp_path, monkeypatch, relative_path
):
repo = _init_contributor_repo(tmp_path, monkeypatch)
path = repo / relative_path
path.write_text("# proposal changes trusted review substrate\n", encoding="utf-8")
_git(repo, "add", str(path.relative_to(repo)))
_git(repo, "commit", "-m", "change review substrate")
snapshot = _contributor_snapshot("base", "HEAD")
assert snapshot["review_substrate_changed"] == [relative_path]
assert snapshot["review_substrate_matches_base"] is False
def test_contributor_snapshot_flags_release_carrier_changes_without_version_file(
tmp_path, monkeypatch
):
repo = _init_contributor_repo(tmp_path, monkeypatch)
path = repo / "pyproject.toml"
path.write_text(
'[project]\nname = "test-project"\nversion = "1.2.4"\n',
encoding="utf-8",
)
_git(repo, "add", "pyproject.toml")
_git(repo, "commit", "-m", "change package carrier only")
snapshot = _contributor_snapshot("base", "HEAD")
assert snapshot["release_metadata_or_machinery_changed"] is True
assert snapshot["release_sensitive_changes"]["carrier_fields"] == [
"pyproject.project.version"
]
def test_contributor_landing_obligations_are_exact_typed_items_only():
version_only = {
"status": "blocked",
"block_reason": "critical_findings",
"combined_findings": [
{"item": "version_bump", "severity": "critical"},
{"item": "changelog_and_badge", "severity": "critical"},
],
}
deferred = _apply_contributor_landing_obligations(version_only)
assert deferred["status"] == "passed"
assert {item["item"] for item in deferred["landing_obligations"]} == {
"version_bump",
"changelog_and_badge",
}
real_defect = {
**version_only,
"combined_findings": [
*version_only["combined_findings"],
{"item": "self_consistency", "severity": "critical"},
],
}
assert _apply_contributor_landing_obligations(real_defect) == real_defect
scope_failure = {
**version_only,
"block_reason": "scope_blocked",
}
assert _apply_contributor_landing_obligations(scope_failure) == scope_failure
assert _apply_contributor_landing_obligations(
version_only,
release_sensitive=True,
) == version_only
def test_contributor_packet_is_redacted_and_shareable(tmp_path):
output = tmp_path / "packet"
output.mkdir()
local_root = "/Users/example/private/repo"
packet = _write_contributor_packet(
output_dir=output,
snapshot={
"base_sha": "a" * 40,
"head_sha": "b" * 40,
"review_substrate_changed": [],
},
resolved_config={"triad_models": ["anthropic/fable"]},
outcome={"status": "passed", "path": local_root, "api_key": "sk-secret-value"},
exit_code=0,
evidence_refs=[],
cost_report={"reported_actor_cost_usd": 1.0},
elapsed_sec=1.5,
triad_raw=[{"authorization": "Bearer secret-token-value", "path": local_root}],
scope_raw={"status": "responded"},
degraded_reasons=["reviewer-3=parse_failure (quorum still met)"],
replacements=[(local_root, "$REPO")],
)
evidence_text = (output / "review-evidence.json").read_text(encoding="utf-8")
full_text = (output / "full-output.txt").read_text(encoding="utf-8")
assert "sk-secret-value" not in evidence_text
assert "secret-token-value" not in full_text
assert local_root not in evidence_text + full_text
assert "$REPO" in evidence_text + full_text
assert "production_triad_quorum_plus_authoritative_scope" in evidence_text
assert "quorum still met" in evidence_text
with zipfile.ZipFile(packet) as archive:
assert set(archive.namelist()) == {
"review-evidence.json",
"outcome.json",
"full-output.txt",
}
def _complete_ctx():
@ -147,6 +432,84 @@ def test_openrouter_pool_orders_hope_keys_last(monkeypatch, tmp_path):
]
def test_contributor_openrouter_preflight_fails_closed(monkeypatch):
import scripts.run_external_review as module
monkeypatch.setattr(module, "_openrouter_pool", lambda: [])
with pytest.raises(RuntimeError, match="no OpenRouter key"):
_select_healthy_openrouter_key(required=True)
monkeypatch.setattr(module, "_openrouter_pool", lambda: [("key", "secret")])
monkeypatch.setattr(
module,
"_openrouter_key_health",
lambda _token, **_kwargs: (False, "model_probe_http_403"),
)
with pytest.raises(RuntimeError, match="no healthy OpenRouter key"):
_select_healthy_openrouter_key(required=True)
def test_contributor_resolved_config_rejects_direct_provider_actors():
defaults = {
"OUROBOROS_REVIEW_MODELS": "anthropic/claude-fable-5,openai/gpt-5.6-sol",
"OUROBOROS_SCOPE_REVIEW_MODELS": "anthropic/claude-fable-5",
"OUROBOROS_EFFORT_REVIEW": "high",
"OUROBOROS_EFFORT_SCOPE_REVIEW": "high",
"OUROBOROS_SCOPE_REVIEW_FLOOR": "blocking_1m",
}
_assert_contributor_openrouter_config({
"triad_models": ["anthropic/claude-fable-5", "openai/gpt-5.6-sol"],
"scope_models": ["anthropic/claude-fable-5"],
"triad_effort": "high",
"scope_effort": "high",
"scope_review_floor": "blocking_1m",
}, defaults)
with pytest.raises(RuntimeError, match="exclusively through OpenRouter"):
_assert_contributor_openrouter_config({
"triad_models": ["anthropic::claude-fable-5"],
"scope_models": ["anthropic/claude-fable-5"],
"triad_effort": "high",
"scope_effort": "high",
"scope_review_floor": "blocking_1m",
}, defaults)
with pytest.raises(RuntimeError, match="drifted from target-base defaults"):
_assert_contributor_openrouter_config({
"triad_models": ["anthropic/claude-fable-5"],
"scope_models": ["anthropic/claude-fable-5"],
"triad_effort": "high",
"scope_effort": "high",
"scope_review_floor": "blocking_1m",
}, defaults)
def test_normal_key_probe_stays_single_model_but_contributor_probes_all(monkeypatch):
import scripts.run_external_review as module
calls: list[str] = []
monkeypatch.setattr(module, "_review_probe_models", lambda: ["one", "two", "three"])
monkeypatch.setattr(
module,
"_probe_model_for_key",
lambda _token, model: (calls.append(model) is None, f"ok:{model}"),
)
class Response:
status_code = 200
@staticmethod
def json():
return {"data": {"limit": None}}
import httpx
monkeypatch.setattr(httpx, "get", lambda *_args, **_kwargs: Response())
assert _openrouter_key_health("secret")[0] is True
assert calls == ["one"]
calls.clear()
assert _openrouter_key_health("secret", probe_all_models=True)[0] is True
assert calls == ["one", "two", "three"]
def _git(repo: Path, *args: str) -> str:
proc = subprocess.run(
["git", *args], cwd=str(repo), capture_output=True, text=True, check=True,

View file

@ -36,6 +36,9 @@ def test_hermetic_pytest_applies_candidate_diff_and_scrubs_live_env(tmp_path, mo
assert value.FLAG is True
assert extra_value.FLAG is True
assert "OUROBOROS_MANAGED_BY_LAUNCHER" not in os.environ
assert "OUROBOROS_SAFETY_MODE" not in os.environ
assert "OUROBOROS_TASK_REVIEW_MODE" not in os.environ
assert "OUROBOROS_FAKE_API_KEY" not in os.environ
assert "ouroboros-preflight-" in os.environ["OUROBOROS_DATA_DIR"]
assert os.environ["OUROBOROS_SETTINGS_PATH"].startswith(os.environ["OUROBOROS_DATA_DIR"])
assert "ouroboros-preflight-" in os.environ["OUROBOROS_REPO_DIR"]
@ -55,6 +58,9 @@ def test_hermetic_pytest_applies_candidate_diff_and_scrubs_live_env(tmp_path, mo
(repo / "extra_value.py").write_text("FLAG = True\n", encoding="utf-8")
monkeypatch.setenv("OUROBOROS_MANAGED_BY_LAUNCHER", "1")
monkeypatch.setenv("OUROBOROS_SAFETY_MODE", "light")
monkeypatch.setenv("OUROBOROS_TASK_REVIEW_MODE", "off")
monkeypatch.setenv("OUROBOROS_FAKE_API_KEY", "must-not-reach-tests")
result = run_hermetic_pytest(repo, timeout=30)
assert result is None
@ -158,34 +164,11 @@ def test_hermetic_pytest_timeout_reaps_detached_session_child(tmp_path, monkeypa
assert not alive, f"detached child {child_pid} survived preflight timeout reaping"
def test_default_preflight_args_are_parallel_and_non_serial(monkeypatch):
def test_default_preflight_args_are_serial_and_keep_default_suite():
from ouroboros import preflight_runner as pr
monkeypatch.delenv("OUROBOROS_PREFLIGHT_PYTEST_WORKERS", raising=False)
args = pr._default_preflight_pytest_args()
assert args[: len(pr.DEFAULT_PYTEST_ARGS)] == pr.DEFAULT_PYTEST_ARGS
workers = int(args[args.index("-n") + 1])
assert 1 <= workers <= 16
assert args[args.index("--dist") + 1] == "loadscope"
# A CLI -m REPLACES the pyproject addopts markexpr, so the hermetic
# preflight must repeat EVERY default exclusion, not just "not serial".
markexpr = args[args.index("-m") + 1]
for lane in (
"serial",
"integration",
"browser",
"ui_browser",
"ui_browser_docker",
"portable_detail",
"skill_smoke",
):
assert f"not {lane}" in markexpr
def test_preflight_worker_count_env_override(monkeypatch):
from ouroboros import preflight_runner as pr
monkeypatch.setenv("OUROBOROS_PREFLIGHT_PYTEST_WORKERS", "4")
assert pr._preflight_worker_count() == 4
monkeypatch.setenv("OUROBOROS_PREFLIGHT_PYTEST_WORKERS", "garbage")
assert 1 <= pr._preflight_worker_count() <= 16
assert args == pr.DEFAULT_PYTEST_ARGS
assert "-n" not in args
assert "--dist" not in args
assert "-m" not in args

View file

@ -483,4 +483,4 @@
* @property {boolean=} ok
*/
export const GATEWAY_CONTRACT_VERSION = '6.67.0';
export const GATEWAY_CONTRACT_VERSION = '6.68.0';

View file

@ -1,6 +1,6 @@
{
"name": "ouroboros-web",
"version": "6.67.0",
"version": "6.68.0",
"private": true,
"type": "module",
"description": "Ouroboros browser UI package boundary",