mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-02 19:58:46 +00:00
Read a relocated chapter exactly as the monolith it came out of
The split left every full-book reader pointing at what is now a membership page. `load_governance_doc` returned 1,744 chars of orientation where the triad, preflight, scope and plan-review prompts believed they had the architecture map, and nothing caught it: those surfaces are covered on synthetic `tmp_path` corpora, so the loss only shows in production packs. `load_governance_doc` now composes a book entrypoint, and an unassemblable book is a named omission rather than a page that reads like a delivered book. The canonical-five list had four hand-maintained copies. It has one owner now (`review_helpers.CANONICAL_GOVERNANCE_DOCS`) with two predicates beside it: `is_canonical_governance_path`, which answers for a chapter exactly as it answers for its entrypoint, and `canonical_governance_sources`, which resolves the population of an actual tree so a pack that inlined a composed book does not also owe its chapters as separate snapshots. `reference_books.book_path_role` and `book_entrypoint_for` are the pure path-shape question underneath, so no consumer carries a list of 27 filenames that goes stale the next time a book gains or splits a chapter. Without this, a commit touching `docs/development/06-rules-by-change-class.md` would have stopped being canonical-doc work: degradable to diff-only in the scope ladder, and an ordinary changed file to the atlas. Three more consequences of the same fact: * the triad pack's duplicate suppression asks the byte-identity question of a MEMBER — a touched chapter is withheld when its current bytes already sit in the composed copy the prefix carries, and a chapter edited after the prefix was rendered keeps its full text; * the new-module documentation gate accepts any staged source of the Architecture book. A new module is documented in the chapter that owns its subsystem, and demanding an entrypoint edit would only buy a membership-list touch that documents nothing; * untruncated repository reads take `UNTRUNCATED_REPO_READ_PREFIXES` (prompts plus the two chapter directories) rather than a chapter list. Four chapters exceed the 80,000-char `read_file` result cap, and a silently capped chapter is a partial governance source that reads like a complete one. Test side: `tests/_governance_docs_shared.py` is the one reader tests use for a governance document's complete text. Sixteen suites read an entrypoint with `Path.read_text()` and asserted body prose; two of them PASSED while testing nothing, because their pins are negatives. The atlas drift guard over three synchronized canonical lists becomes an identity guard over the one owner, and the retired-timeout grep allowlists a book rather than a filename. Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
This commit is contained in:
parent
35b8151819
commit
3182e44ca1
27 changed files with 488 additions and 66 deletions
|
|
@ -31,6 +31,7 @@ from ouroboros.tool_capabilities import (
|
|||
)
|
||||
from ouroboros.tool_capabilities import (
|
||||
UNTRUNCATED_REPO_READ_PATHS as _UNTRUNCATED_REPO_READ_PATHS,
|
||||
UNTRUNCATED_REPO_READ_PREFIXES as _UNTRUNCATED_REPO_READ_PREFIXES,
|
||||
)
|
||||
from ouroboros.tool_capabilities import (
|
||||
UNTRUNCATED_TOOL_RESULTS as _UNTRUNCATED_TOOL_RESULTS,
|
||||
|
|
@ -325,7 +326,8 @@ def _path_is_cognitive_artifact(tool_name: str, tool_args: Optional[Dict[str, An
|
|||
return normalized.startswith("memory/") and "/_backup/" not in normalized
|
||||
|
||||
if tool_name == "read_file":
|
||||
return normalized.startswith("prompts/") or normalized in _UNTRUNCATED_REPO_READ_PATHS
|
||||
return (normalized.startswith(_UNTRUNCATED_REPO_READ_PREFIXES)
|
||||
or normalized in _UNTRUNCATED_REPO_READ_PATHS)
|
||||
|
||||
return False
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,35 @@ BOOK_ENTRYPOINTS = {
|
|||
}
|
||||
|
||||
|
||||
def book_path_role(path: str) -> str:
|
||||
"""``"entrypoint"``, ``"chapter"`` or ``""`` for a repository path.
|
||||
|
||||
Pure path shape and no I/O, so every consumer that must treat a relocated
|
||||
chapter exactly as it treated the monolith it came out of — canonical
|
||||
requiredness, untruncated reads, pack duplicate suppression, the
|
||||
new-module documentation gate — asks ONE question instead of carrying its
|
||||
own copy of the chapter population.
|
||||
"""
|
||||
normalized = str(path or "").replace("\\", "/").lstrip("./")
|
||||
if normalized in set(BOOK_ENTRYPOINTS.values()):
|
||||
return "entrypoint"
|
||||
for book_id in BOOK_ENTRYPOINTS:
|
||||
if normalized.startswith(f"docs/{book_id}/") and normalized.endswith(".md"):
|
||||
return "chapter"
|
||||
return ""
|
||||
|
||||
|
||||
def book_entrypoint_for(path: str) -> str:
|
||||
"""The entrypoint of the book this path belongs to, else ``""``."""
|
||||
normalized = str(path or "").replace("\\", "/").lstrip("./")
|
||||
role = book_path_role(normalized)
|
||||
if role == "entrypoint":
|
||||
return normalized
|
||||
if role == "chapter":
|
||||
return BOOK_ENTRYPOINTS[normalized.split("/")[1]]
|
||||
return ""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ReferenceBook:
|
||||
book_id: str
|
||||
|
|
|
|||
|
|
@ -206,6 +206,18 @@ UNTRUNCATED_REPO_READ_PATHS: frozenset[str] = frozenset({
|
|||
"docs/DEVELOPMENT.md",
|
||||
})
|
||||
|
||||
# Whole DIRECTORIES whose repository reads keep the same guarantee: the runtime
|
||||
# prompts, and the two reference books' chapters. A prefix rather than a list
|
||||
# of the current chapter filenames, because a hand-maintained population is
|
||||
# exactly what goes stale when a book gains, splits or renames a chapter -- and
|
||||
# a silently capped chapter read is a partial governance source that reads like
|
||||
# a complete one. Four chapters exceed the 80,000-char `read_file` result cap.
|
||||
UNTRUNCATED_REPO_READ_PREFIXES: tuple[str, ...] = (
|
||||
"prompts/",
|
||||
"docs/architecture/",
|
||||
"docs/development/",
|
||||
)
|
||||
|
||||
# Per-tool char caps; omitted tools use DEFAULT_TOOL_RESULT_LIMIT.
|
||||
TOOL_RESULT_LIMITS: dict[str, int] = {
|
||||
"read_file": 80_000,
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ from ouroboros.triad_review import (
|
|||
REVIEW_JSON_MATRIX_CONTRACT,
|
||||
)
|
||||
from ouroboros.tools.review_helpers import (
|
||||
CANONICAL_GOVERNANCE_DOCS,
|
||||
build_rebuttal_section,
|
||||
REVIEW_SEVERITY_THRESHOLDS,
|
||||
REVIEW_THOROUGHNESS_BLOCK,
|
||||
|
|
@ -131,9 +132,10 @@ def _build_blocking_history_section(drive_root: pathlib.Path, repo_key: str = ""
|
|||
# (the mandatory-read pointers of `_build_advisory_prompt`); the CHECKLISTS
|
||||
# entry is the surface's one checklist section. `_mandatory_read_corpus_chars`
|
||||
# measures exactly these, never a remembered size.
|
||||
_MANDATORY_READ_DOCS = (
|
||||
"BIBLE.md", "docs/CHECKLISTS.md", "docs/DEVELOPMENT.md", "docs/DESIGN.md", "docs/ARCHITECTURE.md",
|
||||
)
|
||||
# The canonical five, from their one owner. A book entrypoint measures as its
|
||||
# COMPOSED text here, because that is what the non-retrieving branch inlines
|
||||
# and what a retrieving reviewer is told to read in full.
|
||||
_MANDATORY_READ_DOCS = CANONICAL_GOVERNANCE_DOCS
|
||||
|
||||
|
||||
def _checklist_name(review_surface: str) -> str:
|
||||
|
|
|
|||
|
|
@ -554,11 +554,22 @@ def _preflight_check(commit_message: str, staged_files: str,
|
|||
f for f in new_files
|
||||
if f.startswith(("ouroboros/", "supervisor/")) and f.endswith(".py")
|
||||
]
|
||||
if new_logic_files and "docs/ARCHITECTURE.md" not in active_staged:
|
||||
# The Architecture book is the obligation, not one file: a new module is
|
||||
# documented in the CHAPTER that owns its subsystem, and demanding an
|
||||
# entrypoint edit would only buy a membership-list touch that documents
|
||||
# nothing. Any staged source of the book satisfies it.
|
||||
from ouroboros.reference_books import BOOK_ENTRYPOINTS, book_entrypoint_for
|
||||
|
||||
architecture_entrypoint = BOOK_ENTRYPOINTS["architecture"]
|
||||
documented = any(
|
||||
book_entrypoint_for(staged) == architecture_entrypoint for staged in active_staged
|
||||
)
|
||||
if new_logic_files and not documented:
|
||||
return (
|
||||
"⚠️ PREFLIGHT_BLOCKED: New files added in ouroboros/ or supervisor/ "
|
||||
"but docs/ARCHITECTURE.md is not staged.\n"
|
||||
" New structural additions must be documented in ARCHITECTURE.md "
|
||||
"but no source of the Architecture book is staged.\n"
|
||||
" New structural additions must be documented in the Architecture book "
|
||||
f"(`{architecture_entrypoint}` or a `docs/architecture/` chapter) "
|
||||
"(Bible P6: authenticity / architectural mirror).\n"
|
||||
f" New files: {new_logic_files[:5]}\n"
|
||||
f" Currently staged: {', '.join(sorted(staged_set)) or '(none)'}"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from ouroboros.runtime_mode_policy import (
|
|||
PROTECTED_RUNTIME_PATHS,
|
||||
)
|
||||
from ouroboros.tools.review_helpers import (
|
||||
is_canonical_governance_path,
|
||||
_FULL_REPO_BINARY_EXTENSIONS,
|
||||
_FULL_REPO_SKIP_DIR_PREFIXES,
|
||||
_MAX_FULL_REPO_FILE_BYTES,
|
||||
|
|
@ -45,13 +46,6 @@ _COLLAPSED_INDEX_DISPOSITIONS = frozenset({
|
|||
"vendored_minified",
|
||||
})
|
||||
|
||||
_CANONICAL_CONTEXT_DOCS = frozenset({
|
||||
"BIBLE.md",
|
||||
"docs/DEVELOPMENT.md",
|
||||
"docs/DESIGN.md",
|
||||
"docs/ARCHITECTURE.md",
|
||||
"docs/CHECKLISTS.md",
|
||||
})
|
||||
|
||||
_REVIEW_STACK_PATHS = frozenset({
|
||||
"ouroboros/size_ratchet_manifest.py",
|
||||
|
|
@ -557,7 +551,7 @@ def _build_file_facts(
|
|||
# Every early return sees the same answer; no branch re-derives it.
|
||||
force_include = _is_force_include(rel)
|
||||
is_anchor = rel in anchors
|
||||
is_canonical = rel in _CANONICAL_CONTEXT_DOCS
|
||||
is_canonical = is_canonical_governance_path(rel)
|
||||
facts.required = force_include or is_anchor or is_canonical
|
||||
# The classes owed IN FULL regardless of the change: for these the staged
|
||||
# diff is never a substitute for the artifact. An anchor is required
|
||||
|
|
@ -854,7 +848,7 @@ def atlas_required_beyond_diff(rel: str) -> bool:
|
|||
ladder that chooses what to degrade and the assembler that refuses a
|
||||
degraded required artifact cannot drift apart.
|
||||
"""
|
||||
return _is_force_include(rel) or rel in _CANONICAL_CONTEXT_DOCS
|
||||
return _is_force_include(rel) or is_canonical_governance_path(rel)
|
||||
|
||||
|
||||
def _skip_by_dir(rel: str) -> bool:
|
||||
|
|
|
|||
|
|
@ -430,20 +430,32 @@ def triad_pack_exclusions(
|
|||
copy already inlined in this same prompt's governance prefix
|
||||
(``prefix_texts``: path -> the prefix's text) — pure duplication.
|
||||
|
||||
A reference-book entrypoint's prefix copy is the COMPOSED book, so a
|
||||
touched CHAPTER is duplicated exactly when its current bytes already sit
|
||||
in that composition — the same byte-identity fact, asked of a member
|
||||
instead of a whole file. Without this the split would have withheld
|
||||
nothing and inlined every touched chapter twice.
|
||||
|
||||
A carrier edited outside its spans, a prefix doc whose bytes differ from
|
||||
the prefix copy and a managed subject (the caller skips this helper: its
|
||||
reviewed delta is M0→staged, not HEAD→staged) all keep the full text."""
|
||||
from ouroboros.reference_books import book_entrypoint_for, book_path_role
|
||||
|
||||
carriers = span_only_release_carriers(repo_dir, paths)
|
||||
duplicated: list[str] = []
|
||||
for rel in paths:
|
||||
prefix_text = prefix_texts.get(rel) or ""
|
||||
if not prefix_text or rel in carriers:
|
||||
if rel in carriers:
|
||||
continue
|
||||
member_of = book_entrypoint_for(rel) if book_path_role(rel) == "chapter" else ""
|
||||
prefix_text = prefix_texts.get(rel) or (prefix_texts.get(member_of) or "" if member_of else "")
|
||||
if not prefix_text:
|
||||
continue
|
||||
try:
|
||||
if (repo_dir / rel).read_text(encoding="utf-8") == prefix_text:
|
||||
duplicated.append(rel)
|
||||
current = (repo_dir / rel).read_text(encoding="utf-8")
|
||||
except Exception:
|
||||
continue
|
||||
if current == prefix_text or (member_of and current and current in prefix_text):
|
||||
duplicated.append(rel)
|
||||
return set(carriers) | set(duplicated), pack_exclusion_note(carriers, duplicated)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,52 @@ def build_skill_host_context(repo_dir: Path | None = None) -> str:
|
|||
return "\n\n".join(parts)
|
||||
|
||||
|
||||
# The canonical governance corpus a packed review surface owes IN FULL. Two of
|
||||
# the five are reference-book entrypoints, so their chapters are canonical too:
|
||||
# `is_canonical_governance_path` is the one predicate that answers for both
|
||||
# forms, and `canonical_governance_sources` resolves the actual population of a
|
||||
# given tree. Four surfaces used to keep their own copy of this list.
|
||||
CANONICAL_GOVERNANCE_DOCS = (
|
||||
"BIBLE.md",
|
||||
"docs/DEVELOPMENT.md",
|
||||
"docs/DESIGN.md",
|
||||
"docs/ARCHITECTURE.md",
|
||||
"docs/CHECKLISTS.md",
|
||||
)
|
||||
|
||||
|
||||
def is_canonical_governance_path(path: str) -> bool:
|
||||
"""One of the canonical five, or a chapter of one of the two books."""
|
||||
from ouroboros.reference_books import book_path_role
|
||||
|
||||
normalized = str(path or "").replace("\\", "/").lstrip("./")
|
||||
return normalized in CANONICAL_GOVERNANCE_DOCS or book_path_role(normalized) == "chapter"
|
||||
|
||||
|
||||
def canonical_governance_sources(repo_dir: Path) -> tuple[str, ...]:
|
||||
"""Every canonical path a packed review inlines in full for THIS tree.
|
||||
|
||||
The five documents plus the chapters each book's entrypoint declares, so a
|
||||
pack that inlined a composed book does not ALSO owe its chapters as
|
||||
separate snapshots. A book that cannot be read contributes its entrypoint
|
||||
alone — the reader that assembles it reports the failure; this resolver
|
||||
must not turn an unreadable book into a claim of wider coverage.
|
||||
"""
|
||||
from ouroboros.reference_books import BOOK_ENTRYPOINTS, load_reference_book
|
||||
|
||||
root = Path(repo_dir)
|
||||
resolved = [doc for doc in CANONICAL_GOVERNANCE_DOCS if (root / doc).is_file()]
|
||||
for book_id, entrypoint in BOOK_ENTRYPOINTS.items():
|
||||
if entrypoint not in resolved:
|
||||
continue
|
||||
try:
|
||||
book = load_reference_book(root, book_id)
|
||||
except (OSError, ValueError):
|
||||
continue
|
||||
resolved.extend(chapter.source_path for chapter in book.chapters)
|
||||
return tuple(dict.fromkeys(resolved))
|
||||
|
||||
|
||||
def load_governance_doc(
|
||||
repo_dir: Path,
|
||||
rel_path: str,
|
||||
|
|
@ -391,8 +437,26 @@ def load_governance_doc(
|
|||
on_missing: str = "explicit",
|
||||
fallback: str = "",
|
||||
) -> str:
|
||||
"""Load a governance/review document relative to ``repo_dir`` with explicit miss policy."""
|
||||
"""Load a governance/review document relative to ``repo_dir`` with explicit miss policy.
|
||||
|
||||
A reference-book entrypoint resolves to the COMPOSED book. The entrypoint
|
||||
alone is an orientation page and a membership list: handing it to a review
|
||||
surface that believes it received the architecture map would deliver zero
|
||||
chapters while every caller's contract says "in full".
|
||||
"""
|
||||
from ouroboros.reference_books import BOOK_ENTRYPOINTS, compose_book, load_reference_book
|
||||
|
||||
path = Path(repo_dir) / rel_path
|
||||
book_id = next((key for key, entry in BOOK_ENTRYPOINTS.items() if entry == rel_path), None)
|
||||
if book_id is not None:
|
||||
try:
|
||||
return compose_book(load_reference_book(Path(repo_dir), book_id))
|
||||
except (OSError, ValueError) as exc:
|
||||
if on_missing == "silent":
|
||||
return fallback
|
||||
if on_missing == "placeholder":
|
||||
return fallback if fallback else f"({rel_path} could not be assembled: {exc})"
|
||||
return f"[⚠️ OMISSION: {rel_path} could not be assembled from its chapters ({path}): {exc}]"
|
||||
try:
|
||||
if path.is_file():
|
||||
return path.read_text(encoding="utf-8")
|
||||
|
|
|
|||
|
|
@ -23,6 +23,11 @@ import pathlib
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, Optional
|
||||
|
||||
from ouroboros.tools.review_helpers import (
|
||||
CANONICAL_GOVERNANCE_DOCS,
|
||||
canonical_governance_sources,
|
||||
is_canonical_governance_path,
|
||||
)
|
||||
from ouroboros.tools.review_prompt_text import (
|
||||
_ANTI_THRASHING_RULE_VERDICT,
|
||||
_CONVERGENCE_RULE_TEXT,
|
||||
|
|
@ -89,13 +94,10 @@ def _current_scope_context_manifest() -> dict:
|
|||
return dict(_SCOPE_CONTEXT_MANIFEST.get({}) or {})
|
||||
|
||||
|
||||
_CANONICAL_CONTEXT_DOCS = (
|
||||
"BIBLE.md",
|
||||
"docs/DEVELOPMENT.md",
|
||||
"docs/DESIGN.md",
|
||||
"docs/ARCHITECTURE.md",
|
||||
"docs/CHECKLISTS.md",
|
||||
)
|
||||
# The canonical corpus and its chapter membership have ONE owner
|
||||
# (`review_helpers`); this alias keeps the historical local spelling for the
|
||||
# reading order of `_load_canonical_context_docs` and `scope_review`'s import.
|
||||
_CANONICAL_CONTEXT_DOCS = CANONICAL_GOVERNANCE_DOCS
|
||||
|
||||
|
||||
_CURRENT_TOUCHED_CONTEXT_SKIP_PREFIXES = (
|
||||
|
|
@ -109,7 +111,7 @@ def _should_skip_current_touched_context(path: str) -> bool:
|
|||
full atlas anchors, ladder-degradable — but never canonical docs)."""
|
||||
norm = str(path or "").replace("\\", "/").lstrip("./")
|
||||
return (
|
||||
norm in _CANONICAL_CONTEXT_DOCS
|
||||
is_canonical_governance_path(norm)
|
||||
or any(norm.startswith(prefix) for prefix in _CURRENT_TOUCHED_CONTEXT_SKIP_PREFIXES)
|
||||
)
|
||||
|
||||
|
|
@ -306,7 +308,9 @@ def _gather_scope_packs(
|
|||
# from requiredness classification. A canonical doc is claimed only if it exists.
|
||||
already_included = frozenset(
|
||||
set(snapshot_included_paths or frozenset())
|
||||
| {doc for doc in _CANONICAL_CONTEXT_DOCS if (repo_dir / doc).is_file()}
|
||||
# A canonical book is inlined as its COMPOSED text, so its declared
|
||||
# chapters are already in the prompt and must not be owed again.
|
||||
| set(canonical_governance_sources(repo_dir))
|
||||
)
|
||||
_input_limit = _sr()._effective_scope_input_limit(scope_model=scope_model, **({"window_binding": window_binding} if window_binding else {}))
|
||||
try:
|
||||
|
|
|
|||
35
tests/_governance_docs_shared.py
Normal file
35
tests/_governance_docs_shared.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
"""The ONE reader tests use for a governance document's complete text.
|
||||
|
||||
`docs/ARCHITECTURE.md` and `docs/DEVELOPMENT.md` are reference-book
|
||||
entrypoints: an orientation paragraph and an ordered `## Chapters` membership
|
||||
list. Reading either with `Path.read_text()` returns that page and none of the
|
||||
book, so a substring pin over it stops testing anything while still passing --
|
||||
which is worse than failing. Every test that asserts something about a
|
||||
governance document's CONTENT resolves it here instead, and a book resolves to
|
||||
its composed text exactly as the review surfaces receive it.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
|
||||
from ouroboros.reference_books import BOOK_ENTRYPOINTS, compose_book, load_reference_book
|
||||
|
||||
REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def governance_doc_text(rel_path: str, repo_root: pathlib.Path | None = None) -> str:
|
||||
"""The complete text of one governance document, composed when it is a book."""
|
||||
root = pathlib.Path(repo_root) if repo_root is not None else REPO_ROOT
|
||||
book_id = next((key for key, entry in BOOK_ENTRYPOINTS.items() if entry == rel_path), None)
|
||||
if book_id is not None:
|
||||
return compose_book(load_reference_book(root, book_id))
|
||||
return (root / rel_path).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def architecture_text(repo_root: pathlib.Path | None = None) -> str:
|
||||
return governance_doc_text(BOOK_ENTRYPOINTS["architecture"], repo_root)
|
||||
|
||||
|
||||
def development_text(repo_root: pathlib.Path | None = None) -> str:
|
||||
return governance_doc_text(BOOK_ENTRYPOINTS["development"], repo_root)
|
||||
|
|
@ -5,6 +5,7 @@ from pathlib import Path
|
|||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
|
||||
def test_prompt_projection_keeps_panels_ahead_of_an_oversized_lens():
|
||||
|
|
@ -721,8 +722,8 @@ def test_budget_ladder_stops_shedding_after_predecessor_fits():
|
|||
|
||||
|
||||
def test_acceptance_docs_have_complete_sentence_boundaries():
|
||||
development = Path("docs/DEVELOPMENT.md").read_text(encoding="utf-8")
|
||||
architecture = Path("docs/ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
development = development_text()
|
||||
architecture = architecture_text()
|
||||
|
||||
assert "silent false green. The\n Every forced rail" not in development
|
||||
assert "never certify success; An OPEN plan wave" not in architecture
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import re
|
|||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
from tests._governance_docs_shared import governance_doc_text
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
|
|
@ -515,7 +516,7 @@ def test_delegate_start_recipes_match_the_fresh_start_schema():
|
|||
# audit removed. Any recipe the prompt GAINS must still be schema-valid.
|
||||
tolerant = {"docs/CHECKLISTS.md", "prompts/SYSTEM.md"}
|
||||
for relative in (*recipe_paths, "docs/CHECKLISTS.md"):
|
||||
text = (repo / relative).read_text(encoding="utf-8")
|
||||
text = governance_doc_text(relative, repo)
|
||||
recipes = re.findall(r"\bdelegate_start\(([^)]*)\)", text, flags=re.DOTALL)
|
||||
assert recipes or relative in tolerant, (
|
||||
f"expected at least one delegate_start recipe in {relative}"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import shlex
|
|||
import pytest
|
||||
|
||||
from ouroboros import claudexor_daemon as owned
|
||||
from tests._governance_docs_shared import architecture_text
|
||||
|
||||
|
||||
def _write_descriptor(config_dir: pathlib.Path, *, port: int = 45678) -> None:
|
||||
|
|
@ -3610,8 +3611,7 @@ def test_the_proxy_count_in_the_docs_matches_the_handlers_that_exist(tmp_path):
|
|||
f"does not say \"{expected} THIN proxies\""
|
||||
)
|
||||
|
||||
arch = (pathlib.Path(__file__).resolve().parents[1] / "docs" / "ARCHITECTURE.md") \
|
||||
.read_text(encoding="utf-8")
|
||||
arch = architecture_text()
|
||||
account_line = next(ln for ln in arch.splitlines() if "claudexor_accounts.py" in ln)
|
||||
assert f"{expected} thin proxies" in account_line.lower(), (
|
||||
"the gateway map still counts a different number of account proxies: "
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from pathlib import Path
|
|||
from devtools.benchmarks.common import launcher_audit
|
||||
from ouroboros.configured_subagents import parse_configured_subagents
|
||||
from ouroboros.reviewer_slot_config import parse_reviewer_slots
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
PROFILE = REPO / "devtools" / "benchmarks" / "cybergym" / "settings_base.json"
|
||||
|
|
@ -142,7 +143,7 @@ def test_benchmark_inventory_points_to_cybergym_docs():
|
|||
common_readme = (REPO / "devtools" / "benchmarks" / "README.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
assert "cybergym/" in common_readme
|
||||
assert "devtools/benchmarks/cybergym/" in architecture
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import subprocess
|
|||
import pytest
|
||||
|
||||
from ouroboros import delegate_custody as custody
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
from ouroboros.subagent_worktrees import (
|
||||
find_execution_snapshot,
|
||||
provision_payload_snapshot,
|
||||
|
|
@ -1166,8 +1167,7 @@ def test_schema_and_docs_split_git_staging_from_payload_live_apply():
|
|||
decision = entry.schema["parameters"]["properties"]["decision"]["description"]
|
||||
assert "STAGED into your active root" in decision
|
||||
assert "applied LIVE into the non-Git payload" in decision
|
||||
arch = (pathlib.Path(__file__).resolve().parents[1] / "docs" /
|
||||
"ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
arch = architecture_text()
|
||||
assert "staging substrate differs" in arch
|
||||
assert "A SKILL-PAYLOAD target captures through the payload adapter" in arch
|
||||
assert "QUEUES the extension reconcile request" in arch
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ SYSTEM + BIBLE are tier-0 and always full.
|
|||
import os
|
||||
import pathlib
|
||||
import tempfile
|
||||
from tests._governance_docs_shared import governance_doc_text
|
||||
|
||||
# Unique sentinel placed inside the ARCHITECTURE body so we can prove the full
|
||||
# body is inlined (max) vs replaced by a structure-only nav map (low).
|
||||
|
|
@ -91,7 +92,7 @@ def test_plan_review_docs_pin_fail_closed_exact_artifact_custody():
|
|||
repo = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
for relative in ("docs/ARCHITECTURE.md", "docs/DEVELOPMENT.md"):
|
||||
text = (repo / relative).read_text(encoding="utf-8")
|
||||
text = governance_doc_text(relative, repo)
|
||||
assert "plan_review_exact_artifact_unavailable" in text, relative
|
||||
assert "only when no exact artifact reference exists" in text, relative
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"""The public workspace contract must keep ordinary folders visible."""
|
||||
|
||||
from pathlib import Path
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
|
@ -8,7 +9,7 @@ ROOT = Path(__file__).resolve().parents[1]
|
|||
|
||||
def test_external_workspace_docs_distinguish_plain_folders_from_git_operations():
|
||||
readme = (ROOT / "README.md").read_text(encoding="utf-8")
|
||||
architecture = (ROOT / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(ROOT)
|
||||
control = (ROOT / "ouroboros" / "tools" / "control.py").read_text(encoding="utf-8")
|
||||
assert "ordinary folders or separate Git worktree roots" in readme
|
||||
assert "ordinary file and process work runs directly" in readme
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import types
|
|||
|
||||
import ouroboros.context_health as context_health
|
||||
from ouroboros.delegate_custody import RunCustody
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
|
||||
def _env(tmp_path):
|
||||
|
|
@ -61,10 +62,7 @@ def test_non_owner_gets_no_call_shaped_instruction(tmp_path, monkeypatch):
|
|||
|
||||
|
||||
def test_architecture_states_the_terminal_owner_apply_reject_authority_split():
|
||||
import pathlib
|
||||
|
||||
architecture = (pathlib.Path(__file__).resolve().parents[1] / "docs" /
|
||||
"ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text()
|
||||
assert "Apply requires the caller's active Git root or fresh payload binding" in architecture
|
||||
assert "Reject requires only the owner's proven terminality" in architecture
|
||||
assert "a live top-level task with a different active root may reject and release" in architecture
|
||||
|
|
|
|||
|
|
@ -117,16 +117,28 @@ def test_no_runtime_or_settings_surface_still_names_either_key():
|
|||
"tests/test_rc_audit_fixture_suite.py",
|
||||
"tests/test_settings_honesty.py",
|
||||
"tests/test_heartbeat_presentation.py",
|
||||
"docs/ARCHITECTURE.md", # the retirement is documented
|
||||
# The retirement is documented in the Architecture book: the entrypoint
|
||||
# is now a membership list, so the prose lives in the chapter that owns
|
||||
# the frozen contracts. A book source is allowed as a whole class, so a
|
||||
# later chapter split cannot silently turn a record of a removal into a
|
||||
# live surface finding.
|
||||
"docs/ARCHITECTURE.md",
|
||||
"ADOPTION_v7next.md", # ...and adopted: the D04 row names
|
||||
# what it retired, same as the already
|
||||
# skipped docs/v7next/ ledger. A record
|
||||
# of a removal is not a live surface
|
||||
}
|
||||
from ouroboros.reference_books import book_entrypoint_for
|
||||
|
||||
offenders = []
|
||||
for pattern in ("*.py", "*.js", "*.json", "*.md", "*.html"):
|
||||
for path in REPO.rglob(pattern):
|
||||
rel = path.relative_to(REPO).as_posix()
|
||||
# A reference book is allowed as a BOOK: whichever chapter of an
|
||||
# allowlisted entrypoint carries the retirement record, the record
|
||||
# is still documentation and not a live surface.
|
||||
if book_entrypoint_for(rel) in allowed:
|
||||
continue
|
||||
if rel in allowed or rel.startswith(("venv", "node_modules", "docs/v7next/", "docs/archive/")):
|
||||
continue
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import pathlib
|
|||
import re
|
||||
|
||||
import pytest
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
from ouroboros.tools.release_sync import (
|
||||
RELEASE_ASSET_TEMPLATES,
|
||||
|
|
@ -89,7 +90,7 @@ def test_release_guidance_accepts_author_facing_and_pep440_forms():
|
|||
|
||||
|
||||
def test_architecture_docs_describe_bundle_bootstrap_not_per_launch_core_sync():
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
assert "scripts/build_repo_bundle.py" in architecture
|
||||
assert "repo.bundle" in architecture
|
||||
|
|
@ -214,7 +215,7 @@ def test_install_page_matches_macos_quick_start_and_model_prerequisite():
|
|||
|
||||
|
||||
def test_architecture_doc_describes_build_script_release_tag_check():
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
assert "Release tag prerequisite" in architecture
|
||||
assert "scripts/build_repo_bundle.py" in architecture
|
||||
|
|
@ -275,7 +276,7 @@ def test_architecture_doc_does_not_claim_ensure_managed_repo_fetches():
|
|||
"""ensure_managed_repo only validates + ensures the managed remote is
|
||||
configured; the actual fetch lives in supervisor.git_ops.checkout_and_reset.
|
||||
The ARCHITECTURE.md startup flow must not conflate the two."""
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
assert "ensure_managed_repo()" in architecture
|
||||
assert "supervisor/git_ops.checkout_and_reset" in architecture
|
||||
|
|
@ -311,7 +312,7 @@ def test_architecture_module_tree_lists_all_live_extension_http_endpoints():
|
|||
same document. Specifically the Phase 5 review surface
|
||||
``POST /api/skills/<skill>/review`` is exported via
|
||||
``server.py`` and must appear in both places."""
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
# Module map entry lives on the ``gateway/extensions.py`` tree line.
|
||||
tree_idx = architecture.find("├── extensions.py")
|
||||
|
|
@ -328,7 +329,7 @@ def test_architecture_doc_lists_valid_extension_route_methods_in_frozen_contract
|
|||
``__all__`` + ``tests/test_contracts.py``). The ARCHITECTURE §11.1
|
||||
frozen-contract table must list it alongside the other Phase 4
|
||||
plugin_api exports so the doc/code mirror is accurate."""
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
assert "VALID_EXTENSION_ROUTE_METHODS" in architecture
|
||||
assert "test_extension_route_methods_contract_matches_server_dispatch" in architecture
|
||||
|
|
@ -339,7 +340,7 @@ def test_architecture_doc_describes_extension_staging_surface():
|
|||
runtime subdirectory under ``data/state/skills/<name>/``. The
|
||||
architecture doc's skills data-layout section must describe it so the
|
||||
doc/code mirror is accurate."""
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
assert "__extension_imports/" in architecture
|
||||
assert "_stage_extension_import_tree" in architecture
|
||||
|
|
|
|||
225
tests/test_reference_book_readers.py
Normal file
225
tests/test_reference_book_readers.py
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
"""A relocated chapter must be read exactly as the monolith it came out of.
|
||||
|
||||
The split turned one physical governance file into an entrypoint plus chapters.
|
||||
Every reader that used to get ~1 MB of prose from one `read_text()` now gets a
|
||||
membership list unless it asks for the BOOK, and every predicate keyed on the
|
||||
path used to answer for the whole corpus with one exact string. This module
|
||||
pins the four places that difference is load-bearing: the full-book loader, the
|
||||
canonical-corpus predicate, the pack's duplicate suppression, and the
|
||||
untruncated-read guarantee -- plus the documentation gate, which must accept the
|
||||
chapter that actually documents a new module.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
|
||||
import pytest
|
||||
|
||||
from ouroboros.reference_books import BOOK_ENTRYPOINTS, book_entrypoint_for, book_path_role
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _chaptered_corpus(root: pathlib.Path, *, body: str = "The exact chapter body.\n") -> dict:
|
||||
files = {}
|
||||
for book_id, entrypoint in BOOK_ENTRYPOINTS.items():
|
||||
files[entrypoint] = (
|
||||
f"# {book_id.title()}\n\nThe authored orientation.\n\n## Chapters\n\n"
|
||||
f"- [Only chapter]({book_id}/only.md)\n"
|
||||
)
|
||||
files[f"docs/{book_id}/only.md"] = f"# Only chapter\n\nWhy it exists.\n\n## Detail\n\n{body}"
|
||||
for rel, text in files.items():
|
||||
target = root / rel
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
target.write_text(text, encoding="utf-8")
|
||||
return files
|
||||
|
||||
|
||||
# --- path role -------------------------------------------------------------
|
||||
|
||||
@pytest.mark.parametrize("path,role", [
|
||||
("docs/ARCHITECTURE.md", "entrypoint"),
|
||||
("docs/DEVELOPMENT.md", "entrypoint"),
|
||||
("docs/architecture/06-agent-core.md", "chapter"),
|
||||
("docs/development/14-build-and-ci.md", "chapter"),
|
||||
("docs/reference-books-migration.md", ""),
|
||||
("docs/CHECKLISTS.md", ""),
|
||||
("docs/architecture/notes.txt", ""),
|
||||
("", ""),
|
||||
])
|
||||
def test_book_path_role_answers_by_shape_without_reading_the_tree(path, role):
|
||||
assert book_path_role(path) == role
|
||||
|
||||
|
||||
def test_book_entrypoint_for_maps_a_chapter_back_to_its_own_book():
|
||||
assert book_entrypoint_for("docs/development/09-process-custody-rule.md") == "docs/DEVELOPMENT.md"
|
||||
assert book_entrypoint_for("docs/ARCHITECTURE.md") == "docs/ARCHITECTURE.md"
|
||||
assert book_entrypoint_for("BIBLE.md") == ""
|
||||
|
||||
|
||||
# --- the full-book loader --------------------------------------------------
|
||||
|
||||
def test_load_governance_doc_delivers_the_composed_book_not_the_membership_page(tmp_path):
|
||||
from ouroboros.tools.review_helpers import load_governance_doc
|
||||
|
||||
_chaptered_corpus(tmp_path, body="THE-ONLY-CHAPTER-BODY\n")
|
||||
for entrypoint in BOOK_ENTRYPOINTS.values():
|
||||
text = load_governance_doc(tmp_path, entrypoint)
|
||||
assert "THE-ONLY-CHAPTER-BODY" in text, entrypoint
|
||||
assert "## Chapters" in text, entrypoint
|
||||
# A non-book governance document is untouched by the book branch.
|
||||
(tmp_path / "BIBLE.md").write_text("# Constitution\n", encoding="utf-8")
|
||||
assert load_governance_doc(tmp_path, "BIBLE.md") == "# Constitution\n"
|
||||
|
||||
|
||||
def test_an_unassemblable_book_is_a_named_omission_not_a_short_entrypoint(tmp_path):
|
||||
from ouroboros.tools.review_helpers import load_governance_doc
|
||||
|
||||
_chaptered_corpus(tmp_path)
|
||||
(tmp_path / "docs/architecture/only.md").unlink()
|
||||
explicit = load_governance_doc(tmp_path, "docs/ARCHITECTURE.md")
|
||||
assert "OMISSION" in explicit and "could not be assembled" in explicit
|
||||
assert "## Chapters" not in explicit, "a failure must not look like a delivered book"
|
||||
assert load_governance_doc(tmp_path, "docs/ARCHITECTURE.md", on_missing="silent") == ""
|
||||
|
||||
|
||||
def test_the_live_books_reach_the_packed_review_surfaces_whole():
|
||||
from ouroboros.reference_books import compose_book, load_reference_book
|
||||
from ouroboros.tools.review_helpers import load_governance_doc
|
||||
|
||||
for book_id, entrypoint in BOOK_ENTRYPOINTS.items():
|
||||
book = load_reference_book(REPO, book_id)
|
||||
delivered = load_governance_doc(REPO, entrypoint)
|
||||
assert delivered == compose_book(book)
|
||||
assert len(delivered) > 10 * len(book.entrypoint.text)
|
||||
|
||||
|
||||
# --- the canonical corpus --------------------------------------------------
|
||||
|
||||
def test_a_chapter_is_canonical_exactly_as_its_entrypoint_was(tmp_path):
|
||||
from ouroboros.tools.review_context_atlas import atlas_required_beyond_diff
|
||||
from ouroboros.tools.review_helpers import (
|
||||
canonical_governance_sources,
|
||||
is_canonical_governance_path,
|
||||
)
|
||||
|
||||
assert is_canonical_governance_path("docs/architecture/06-agent-core.md")
|
||||
assert is_canonical_governance_path("docs/DEVELOPMENT.md")
|
||||
assert not is_canonical_governance_path("docs/reference-books-migration.md")
|
||||
# Owed in full regardless of the change: the staged diff is never a
|
||||
# substitute for a canonical artifact, chapter or entrypoint.
|
||||
assert atlas_required_beyond_diff("docs/development/06-rules-by-change-class.md")
|
||||
|
||||
_chaptered_corpus(tmp_path)
|
||||
(tmp_path / "BIBLE.md").write_text("# Constitution\n", encoding="utf-8")
|
||||
sources = canonical_governance_sources(tmp_path)
|
||||
assert "docs/architecture/only.md" in sources and "docs/development/only.md" in sources
|
||||
assert "BIBLE.md" in sources
|
||||
assert "docs/CHECKLISTS.md" not in sources, "an absent document is not claimed"
|
||||
assert len(sources) == len(set(sources))
|
||||
|
||||
|
||||
def test_an_unreadable_book_contributes_its_entrypoint_alone(tmp_path):
|
||||
from ouroboros.tools.review_helpers import canonical_governance_sources
|
||||
|
||||
_chaptered_corpus(tmp_path)
|
||||
(tmp_path / "docs/development/only.md").unlink()
|
||||
sources = canonical_governance_sources(tmp_path)
|
||||
assert "docs/DEVELOPMENT.md" in sources
|
||||
assert not any(s.startswith("docs/development/") for s in sources), (
|
||||
"a book that cannot be read must not widen the claimed coverage"
|
||||
)
|
||||
|
||||
|
||||
# --- pack duplicate suppression -------------------------------------------
|
||||
|
||||
def test_a_touched_chapter_is_withheld_when_the_prefix_carries_its_book(tmp_path):
|
||||
from ouroboros.tools.review_file_pack import triad_pack_exclusions
|
||||
from ouroboros.tools.review_helpers import load_governance_doc
|
||||
|
||||
_chaptered_corpus(tmp_path)
|
||||
composed = load_governance_doc(tmp_path, "docs/ARCHITECTURE.md")
|
||||
touched = ["docs/architecture/only.md", "docs/development/only.md"]
|
||||
excluded, note = triad_pack_exclusions(
|
||||
tmp_path, touched, prefix_texts={"docs/ARCHITECTURE.md": composed},
|
||||
)
|
||||
assert "docs/architecture/only.md" in excluded
|
||||
assert "docs/development/only.md" not in excluded, (
|
||||
"only the book whose composed copy IS in the prefix may be withheld"
|
||||
)
|
||||
assert "docs/architecture/only.md" in note
|
||||
|
||||
# A chapter edited after the prefix was rendered keeps its full text.
|
||||
(tmp_path / "docs/architecture/only.md").write_text(
|
||||
"# Only chapter\n\nWhy it exists.\n\n## Detail\n\nEdited after the prefix.\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
excluded_after, _ = triad_pack_exclusions(
|
||||
tmp_path, touched, prefix_texts={"docs/ARCHITECTURE.md": composed},
|
||||
)
|
||||
assert "docs/architecture/only.md" not in excluded_after
|
||||
|
||||
|
||||
# --- the documentation gate ------------------------------------------------
|
||||
|
||||
def test_the_new_module_gate_takes_the_chapter_that_documents_the_module():
|
||||
from ouroboros.tools import review
|
||||
|
||||
staged = "A ouroboros/brand_new_owner.py\n"
|
||||
blocked = review._preflight_check("add an owner", staged, REPO)
|
||||
assert blocked and "Architecture book" in blocked
|
||||
|
||||
for documented in ("docs/ARCHITECTURE.md", "docs/architecture/01-high-level-architecture.md"):
|
||||
assert review._preflight_check(
|
||||
"add an owner", staged + f"M {documented}\n", REPO,
|
||||
) is None, documented
|
||||
|
||||
assert review._preflight_check(
|
||||
"add an owner", staged + "M docs/reference-books-migration.md\n", REPO,
|
||||
) is not None, "a docs file outside the book documents no module"
|
||||
|
||||
|
||||
# --- the untruncated-read guarantee ---------------------------------------
|
||||
|
||||
def test_a_chapter_read_keeps_the_untruncated_guarantee_the_monolith_had():
|
||||
from ouroboros.loop_tool_execution import _path_is_cognitive_artifact, _truncate_tool_result
|
||||
from ouroboros.tool_capabilities import TOOL_RESULT_LIMITS
|
||||
|
||||
limit = TOOL_RESULT_LIMITS["read_file"]
|
||||
oversized = "x" * (limit + 5_000)
|
||||
for rel in ("docs/architecture/06-agent-core.md", "docs/development/06-rules-by-change-class.md"):
|
||||
assert _path_is_cognitive_artifact("read_file", {"path": rel}), rel
|
||||
assert _truncate_tool_result(oversized, "read_file", {"path": rel}) == oversized, rel
|
||||
# The guarantee is a book-source class, not every markdown file under docs/.
|
||||
assert not _path_is_cognitive_artifact("read_file", {"path": "docs/reference-books-migration.md"})
|
||||
assert len(_truncate_tool_result(oversized, "read_file",
|
||||
{"path": "docs/reference-books-migration.md"})) < len(oversized)
|
||||
|
||||
|
||||
def test_every_chapter_over_the_read_cap_is_covered_by_the_prefix_guarantee():
|
||||
"""The chapters that actually need it, measured rather than assumed."""
|
||||
from ouroboros.loop_tool_execution import _path_is_cognitive_artifact
|
||||
from ouroboros.reference_books import load_reference_book
|
||||
from ouroboros.tool_capabilities import TOOL_RESULT_LIMITS
|
||||
|
||||
oversized = []
|
||||
for book_id in BOOK_ENTRYPOINTS:
|
||||
for chapter in load_reference_book(REPO, book_id).chapters:
|
||||
assert _path_is_cognitive_artifact("read_file", {"path": chapter.source_path})
|
||||
if len(chapter.raw) > TOOL_RESULT_LIMITS["read_file"]:
|
||||
oversized.append(chapter.source_path)
|
||||
assert oversized, "if no chapter exceeds the cap, this guarantee needs a different proof"
|
||||
|
||||
|
||||
# --- the mandatory-read corpus --------------------------------------------
|
||||
|
||||
def test_the_mandatory_read_pointer_measures_the_book_not_its_membership_page():
|
||||
from ouroboros.tools import preflight_review_prompt as prompt
|
||||
|
||||
measured = prompt._mandatory_read_corpus_chars(REPO)
|
||||
entrypoints = sum(len((REPO / rel).read_text(encoding="utf-8"))
|
||||
for rel in BOOK_ENTRYPOINTS.values())
|
||||
assert measured > 20 * entrypoints, (
|
||||
"a retrieving reviewer told to read the books in full must be budgeted "
|
||||
f"for their chapters; measured {measured} against {entrypoints} of membership"
|
||||
)
|
||||
assert set(prompt._MANDATORY_READ_DOCS) >= set(BOOK_ENTRYPOINTS.values())
|
||||
|
|
@ -10,6 +10,7 @@ Also covers the core governance artifact invariants introduced in the
|
|||
"""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
|
||||
def _make_ctx(tmp_path):
|
||||
|
|
@ -462,7 +463,7 @@ def test_development_md_contains_core_governance_invariant():
|
|||
import pathlib
|
||||
dev_md = pathlib.Path(__file__).resolve().parent.parent / "docs" / "DEVELOPMENT.md"
|
||||
assert dev_md.exists(), "docs/DEVELOPMENT.md must exist"
|
||||
content = dev_md.read_text(encoding="utf-8")
|
||||
content = development_text()
|
||||
|
||||
required_phrases = [
|
||||
"Core Governance Artifacts",
|
||||
|
|
|
|||
|
|
@ -794,13 +794,27 @@ def test_scope_ladder_never_hands_required_beyond_diff_paths_to_diff_only(tmp_pa
|
|||
assert "docs/ARCHITECTURE.md" not in degradable
|
||||
|
||||
|
||||
def test_canonical_context_docs_membership_includes_design():
|
||||
"""Drift guard for the three synchronized canonical-doc lists: the atlas
|
||||
copy must carry docs/DESIGN.md like scope_review's tuple and the external
|
||||
substrate set (fable p0-review note, 2026-08-31)."""
|
||||
from ouroboros.tools.review_context_atlas import _CANONICAL_CONTEXT_DOCS
|
||||
def test_canonical_context_docs_have_one_owner_and_cover_book_chapters():
|
||||
"""This was a drift guard over three synchronized canonical-doc lists (fable
|
||||
p0-review note, 2026-08-31). The lists are now ONE owner, so the guard is
|
||||
the identity instead: the atlas reads `review_helpers`, the scope pack's
|
||||
tuple IS that value, and a book chapter answers exactly as its entrypoint
|
||||
does -- a copy that omitted the chapters would quietly stop treating
|
||||
relocated governance prose as canonical."""
|
||||
from ouroboros.tools import review_context_atlas as atlas
|
||||
from ouroboros.tools.review_helpers import (
|
||||
CANONICAL_GOVERNANCE_DOCS,
|
||||
is_canonical_governance_path,
|
||||
)
|
||||
from ouroboros.tools.scope_review import _CANONICAL_CONTEXT_DOCS
|
||||
|
||||
assert "docs/DESIGN.md" in _CANONICAL_CONTEXT_DOCS
|
||||
assert "docs/DESIGN.md" in CANONICAL_GOVERNANCE_DOCS
|
||||
assert tuple(_CANONICAL_CONTEXT_DOCS) == CANONICAL_GOVERNANCE_DOCS
|
||||
assert atlas.is_canonical_governance_path is is_canonical_governance_path
|
||||
for doc in CANONICAL_GOVERNANCE_DOCS:
|
||||
assert atlas.atlas_required_beyond_diff(doc), doc
|
||||
assert atlas.atlas_required_beyond_diff("docs/architecture/06-agent-core.md")
|
||||
assert not atlas.atlas_required_beyond_diff("docs/reference-books-migration.md")
|
||||
|
||||
|
||||
def test_atlas_diff_only_reason_override_is_the_callers_typed_omission(tmp_path):
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from ouroboros import config as cfg
|
|||
from ouroboros import review_cycles as rc
|
||||
from ouroboros import task_pacing
|
||||
from ouroboros.contracts.task_contract import normalize_budget_profile
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
REPO = pathlib.Path(__file__).resolve().parents[1]
|
||||
KEY = "OUROBOROS_REVIEW_MAX_CYCLES"
|
||||
|
|
@ -549,8 +550,8 @@ def test_exhausted_event_is_durable_even_with_a_live_queue(tmp_path):
|
|||
|
||||
|
||||
def test_docs_describe_shared_key_and_new_module_size():
|
||||
dev = (REPO / "docs" / "DEVELOPMENT.md").read_text(encoding="utf-8")
|
||||
arch = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
dev = development_text(REPO)
|
||||
arch = architecture_text(REPO)
|
||||
assert dev.count(KEY) >= 2 and "review_cycles.py" in dev
|
||||
assert f"| {KEY} |" in arch
|
||||
# the LEGACY row documents the load-time migration, not a runtime binding
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ from starlette.routing import Route
|
|||
from starlette.testclient import TestClient
|
||||
|
||||
from tests._shared import SETTINGS_WRITERS, calls_function
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
# One owner-authored document, written entirely under keys a release renamed or
|
||||
# retired. Every value differs from both its legacy default and its current one,
|
||||
|
|
@ -665,8 +666,7 @@ def test_a_retired_key_is_absent_from_every_surface_that_would_react_to_it():
|
|||
from ouroboros import config as cfg
|
||||
from ouroboros.gateway import settings as settings_mod
|
||||
|
||||
documented = (pathlib.Path(__file__).resolve().parents[1]
|
||||
/ "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8").splitlines()
|
||||
documented = architecture_text().splitlines()
|
||||
for key in cfg.RETIRED_SETTING_KEYS:
|
||||
assert key not in settings_mod._IMMEDIATE_KEYS, key
|
||||
assert key not in settings_mod._RESTART_REQUIRED_KEYS, key
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import pathlib
|
|||
import pytest
|
||||
|
||||
from ouroboros.tools.registry import ToolContext
|
||||
from tests._governance_docs_shared import architecture_text
|
||||
|
||||
|
||||
def _make_ctx(tmp_path: pathlib.Path) -> ToolContext:
|
||||
|
|
@ -437,9 +438,7 @@ def test_save_enabled_row_is_disclosure_never_a_gate(tmp_path):
|
|||
def test_save_enabled_best_effort_disclosure_contract_is_documented():
|
||||
from ouroboros.skill_loader import save_enabled
|
||||
|
||||
architecture = (pathlib.Path(__file__).resolve().parents[1] / "docs" / "ARCHITECTURE.md").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
architecture = architecture_text()
|
||||
assert "best-effort" in str(save_enabled.__doc__)
|
||||
assert "append failure is logged and never blocks the enablement change" in architecture
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import re
|
|||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
from tests._governance_docs_shared import architecture_text, development_text
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
RELEASE_VERSION = "6.92.1"
|
||||
|
|
@ -195,7 +196,7 @@ def test_benchmark_evidence_keeps_exact_scores_and_hugging_face_revisions():
|
|||
|
||||
|
||||
def test_architecture_registers_each_new_public_metadata_surface():
|
||||
architecture = (REPO / "docs" / "ARCHITECTURE.md").read_text(encoding="utf-8")
|
||||
architecture = architecture_text(REPO)
|
||||
|
||||
for path in (
|
||||
".github/workflows/scorecard.yml",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue