ouroboros/tests/test_reference_book_readers.py
Ouroboros 3182e44ca1 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>
2026-09-15 19:20:44 +03:00

225 lines
10 KiB
Python

"""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())