Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/run_pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
# `fetch-depth: 0` for the TAGS, not the history. The default shallow checkout
# fetches none, so `git tag -l` is empty and BOTH guards in
# tests/test_release_version.py skip — the pair written because tag 1.1.0 was cut
# while pyproject.toml still said 1.0.0. A guard against mis-cutting a release
# that only ever runs on the maintainer's laptop is half a guard, and the half
# that is missing is the one watching the moment it matters.
fetch-depth: 0

# ── sibling checkouts: what CI can verify that a bare checkout cannot ────────
#
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "views-postprocessing"
version = "1.1.0"
version = "1.1.1"
description = ""
authors = [
"Dylan Pinheiro <dylpin@prio.org>",
Expand Down
157 changes: 149 additions & 8 deletions reports/technical_risk_register.md

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions tests/test_doc_accuracy.py
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,16 @@ def test_internal_doc_links_resolve():
#: previously unbudgeted, which is the same regrowth wearing a different filename.
_MANAGER_LINE_BUDGET = 450

#: The same rule one level out, added 2026-08-14 because the directory bound was not
#: enough. C-99's fix pushed `managers/` to 469 and the response was to move
#: `_ContractStorePort` to `<partner>/store_port.py` — a sibling of `managers/`, not a
#: sibling inside it. The counted number fell 441 -> 388 while the partner package grew
#: by 47 lines, and the PR reported "62 of headroom" against a guard that could no
#: longer see the code. The move was right; reporting it as compliance was not.
#: Measured 2026-08-14: unfao 626, crafd 635. A ratchet, like the class budget — the
#: response to it binding is to move something OUT OF THE PACKAGE, not to raise it.
_PARTNER_PACKAGE_LINE_BUDGET = 700

#: The manager CLASS, separately (C-40). 351 before the 2026-08-05 extraction, 272 after.
#: A ratchet — see `test_the_manager_class_itself_stays_thin` for why it is not a target.
_MANAGER_CLASS_BUDGET = 300
Expand Down Expand Up @@ -492,6 +502,39 @@ def test_the_manager_stays_within_its_line_budget(managers_dir):
)


@pytest.mark.parametrize("partner", _PARTNER_PACKAGES)
def test_the_partner_package_stays_within_its_line_budget(partner):
"""The directory bound, one level out — because moving code past it is not shrinking.

The budget above deliberately counts the manager *directory* rather than the manager
file, so that a helper module beside a thin manager could not go unbudgeted. On
2026-08-14 the same evasion happened one directory further out and the guard did not
see it: `_ContractStorePort` moved from `managers/<partner>.py` to
`<partner>/store_port.py`, the counted number fell from 441 to 388, and the partner
package grew from 441 to 488 lines.

That move was the right call — a store adapter is not the manager, and the budget's
own instruction is to move something out rather than raise the number. What was
wrong was calling the result "62 of headroom" when the guard had simply stopped
measuring the code. This test is what makes that sentence checkable, and it is the
same lesson as register C-98: a guard that watches a proxy reports on the proxy.

A ratchet, not a target. If it binds, move something out of the partner package —
to `contract/` or `delivery/`, where the machinery lives — or say in the commit
message why the package genuinely needs to be bigger.
"""
package = _PKG / partner
sources = sorted(package.rglob("*.py"))
lines = sum(len(f.read_text().splitlines()) for f in sources)
assert lines <= _PARTNER_PACKAGE_LINE_BUDGET, (
f"{partner}/ is {lines} lines across {len(sources)} files "
f"({[f.relative_to(package).as_posix() for f in sources]}), over the "
f"{_PARTNER_PACKAGE_LINE_BUDGET} bound. Moving code from managers/ into a "
"sibling module does not reduce the seam — it only moves it out of the inner "
"budget's view, which is what this outer one exists to notice."
)


@pytest.mark.parametrize("partner", _PARTNER_PACKAGES)
def test_the_manager_class_itself_stays_thin(partner):
"""The directory budget above is anti-regrowth. This one is anti-*fusion*.
Expand Down
165 changes: 37 additions & 128 deletions tests/test_env_declaration.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,10 @@

from tests.seam_registry import (
ABSENT as _ABSENT,
REGISTRY_RELPATH,
REGISTRY_RELPATH as _REGISTRY_RELPATH,
RegistryReadError,
RegistryReadError as _RegistryReadError,
registry_at,
registry_at as _registry_at,
registry_current,
registry_current as _registry_current,
rows,
rows as _rows,
)
from tests.conftest import (
Expand Down Expand Up @@ -629,24 +624,45 @@ def _declared_classes(registry: dict) -> dict[str, str]:
return {n: row[1] for n, row in _rows(registry, _CONSUMED_TABLES).items()}


def _name_and_class_drift(expected_class: dict, declared: dict) -> tuple[list, dict]:
"""What this package expects vs what the registry declares.

Returns ``(names the registry does not carry, {name: (expected, declared)})``.

Extracted 2026-08-14 (issue #265) so the gated check below and the ungated proof of
it further down run the **same** comparison. They did not: the proof rebuilt this
with its own comprehensions, so blanking the assertions here left it green.

The two sibling defects were repaired differently — by adding a test that drives the
real check under ``monkeypatch`` (``test_the_drift_check_fires_when_a_row_this_partner_reads_rotates``).
That works there because the check reads a registry the test can substitute. Here the
comparison is a pure function of two dicts and both callers want exactly it, so
sharing the function is the same guarantee with less machinery. Extracting is
justified by *this* being the second time the pattern has bitten, not by a rule about
line counts.
"""
missing = sorted(n for n in expected_class if n not in declared)
misclassified = {
n: (expected, declared[n])
for n, expected in expected_class.items()
if n in declared and declared[n] != expected
}
return missing, misclassified


@pytest.mark.parametrize("partner", _PARTNERS)
def test_every_declared_name_exists_in_the_registry_with_the_class_we_treat_it_as(partner):
"""C-57: a rename or reclassification upstream must not be silent here."""
repo = require_sibling("views-appwrite")
declared = _declared_classes(_registry_current(repo))
_, _, expected_class = _PARTNER_ENV[partner]

missing = sorted(n for n in expected_class if n not in declared)
missing, misclassified = _name_and_class_drift(expected_class, declared)
assert not missing, (
f"[{partner}] names this package requires are absent from the Appwrite Seam "
f"Contract's registry: {missing}. Either the registry retired them or this "
"module invented them; the registry is the authority."
)
misclassified = {
n: (expected, declared[n])
for n, expected in expected_class.items()
if declared[n] != expected
}
assert not misclassified, (
f"[{partner}] class mismatch (expected, registry) {misclassified}. Class is "
"DECLARED by the registry, never inferred from a name's prefix — a coordinate "
Expand Down Expand Up @@ -1140,17 +1156,20 @@ def test_the_drift_check_would_catch_a_rename(partner):
"not the mutation this test believes it is"
)
assert "APPWRITE_DATASTORE_PROJECT_ID" not in declared, "fixture should omit it"
missing = sorted(n for n in expected_class if n not in declared)
assert missing, "the detector reported no missing names against a registry that omits most"

mismatched = [
n for n, expected in expected_class.items()
if n in declared and declared[n] != expected
]
assert canary in mismatched, (
# The gated check's own comparison, not a copy of it (issue #265). This rebuilt the
# logic with its own comprehensions until 2026-08-14, which made it a proof of a
# reimplementation: blank the real check's assertions and it stayed green.
missing, misclassified = _name_and_class_drift(expected_class, declared)
assert missing, "the detector reported no missing names against a registry that omits most"
assert canary in misclassified, (
f"[{partner}] a target reclassified as a secret went unnoticed — that is the "
"case where getting it wrong leaks or hides a value"
)
assert misclassified[canary] == ("target", "secret"), (
"the detector must report BOTH sides of the mismatch — what this package "
"expects and what the registry declares — or a reader cannot tell which moved"
)


def _docstring_nodes(tree: ast.AST) -> set[int]:
Expand Down Expand Up @@ -1391,113 +1410,3 @@ def test_the_scan_understands_every_assignment_form_this_repo_writes():
"document that introduced it — that is the stopping rule, and it is why the "
"form list is derived from this repository's own corpus rather than invented."
)


def _scratch_repo(tmp_path: Path):
"""A throwaway git repo whose registry differs on `main`, on `origin/main`, and on disk.

`-c` rather than `git config`: a contributor's global `commit.gpgsign` or
`core.hooksPath` would otherwise reach in and either fail opaquely or block on
pinentry with no timeout.
"""
def git(*args):
return subprocess.run(
["git", "-C", str(tmp_path), "-c", "commit.gpgsign=false",
"-c", "core.hooksPath=/dev/null", *args],
capture_output=True, text=True, check=True, timeout=30,
)

target = tmp_path / REGISTRY_RELPATH
target.parent.mkdir(parents=True)

def edition(marker: str) -> str:
return f'[meta]\nversion = "{marker}"\n\n[connection.X]\nclass = "connection"\n'

git("init", "-q", "-b", "main")
git("config", "user.email", "t@t")
git("config", "user.name", "t")
target.write_text(edition("on-main"))
git("add", "-A")
git("commit", "-q", "-m", "main")

# a remote-tracking ref that is AHEAD of main, so preferring one over the other shows
git("checkout", "-q", "-b", "upstream")
target.write_text(edition("on-origin-main"))
git("add", "-A")
git("commit", "-q", "-m", "origin")
git("update-ref", "refs/remotes/origin/main", "HEAD")
git("checkout", "-q", "main")

# and a dirty working tree, which is what #196 was about
target.write_text(edition("in-the-working-tree"))
return tmp_path


def test_registry_current_reads_origin_main_not_the_working_tree(tmp_path):
"""The reason `tests/seam_registry.py` exists, and until now the only untested part.

A sibling clone sits on whatever branch its own agent last worked on. Comparing
against that grades this repository on unreviewed content — issue #196, which cost a
withdrawn pull request. Replacing this function with a working-tree or `HEAD` read
used to leave the whole suite green.
"""
repo = _scratch_repo(tmp_path)
assert registry_current(repo)["meta"]["version"] == "on-origin-main", (
"registry_current read something other than origin/main. A working-tree read is "
"#196 verbatim; a bare `main` read misses that the sibling's remote has moved."
)


def test_registry_current_refuses_a_repo_with_neither_ref(tmp_path):
"""No `origin/main` and no `main` must say so, not return an empty registry."""
subprocess.run(["git", "init", "-q", str(tmp_path)],
capture_output=True, text=True, check=True, timeout=30)
with pytest.raises(RegistryReadError, match="neither origin/main nor main"):
registry_current(tmp_path)


def test_registry_at_refuses_a_commit_whose_registry_is_missing_or_unparseable(tmp_path):
"""`git show` failing, and a blob that is not TOML — two refusal branches nothing reached."""
def git(*args):
return subprocess.run(
["git", "-C", str(tmp_path), "-c", "commit.gpgsign=false",
"-c", "core.hooksPath=/dev/null", *args],
capture_output=True, text=True, check=True, timeout=30,
)
git("init", "-q", "-b", "main")
git("config", "user.email", "t@t")
git("config", "user.name", "t")

(tmp_path / "unrelated.txt").write_text("no registry here\n")
git("add", "-A")
git("commit", "-q", "-m", "no registry")
absent = git("rev-parse", "--short", "HEAD").stdout.strip()

target = tmp_path / REGISTRY_RELPATH
target.parent.mkdir(parents=True)
target.write_text("this is not toml = = =\n")
git("add", "-A")
git("commit", "-q", "-m", "not toml")
garbage = git("rev-parse", "--short", "HEAD").stdout.strip()

with pytest.raises(RegistryReadError, match="cannot read the registry"):
registry_at(tmp_path, absent)
with pytest.raises(RegistryReadError, match="did not parse as TOML"):
registry_at(tmp_path, garbage)


def test_rows_refuses_a_section_whose_entries_are_not_tables():
"""`[test_environment]` on the live registry is scalars, not sub-tables.

Nothing breaks today because that table is IGNORED — but the partition check's own
remediation message tells a maintainer to classify a new table CONSUMED, and doing
that for one written this way used to return an `AttributeError` from a dict
comprehension. Register C-91.
"""
scalars = {"test_environment": {"status": "none", "fact": "a sentence"}}
with pytest.raises(RegistryReadError, match=r"\[test_environment\]\.(status|fact) is a bare str"):
rows(scalars, ("test_environment",))

# and the ordinary shape still works, or the refusal above proves nothing
tables = {"target": {"APPWRITE_X": {"class": "target", "value": "v"}}}
assert rows(tables, ("target",)) == {"APPWRITE_X": ("target", "target", "v")}
21 changes: 18 additions & 3 deletions tests/test_release_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@

Measured 2026-08-13: tag `1.1.0` was cut at `main` while `pyproject.toml` still said
`1.0.0`, so an install from that tag reported the previous release. Caught before any
consumer pinned. Third time in this arc a version has been declared twice with a guard on
one copy (register C-80, C-82).
consumer pinned, and the tag was re-pointed.

*(This docstring used to add "third time in this arc a version has been declared twice
with a guard on one copy (register C-80, C-82)". Corrected 2026-08-15: neither entry says
that. C-80 is the doc-accuracy scan exempting ADRs and CICs; C-82 is governance prose
carrying numbers nothing checks — the same **class** as this, a number with no guard, but
about the register and CIC front matter, not about a version declared twice. The claim was
repeated into a release PR before anyone read the entries it cited.)*
"""

import re
Expand Down Expand Up @@ -63,9 +69,18 @@ def test_the_newest_release_tag_is_not_ahead_of_the_declared_version():

This is the direction that actually bit: the tag moved, the file did not. Runs on
every commit, not only tagged ones, so the gap is visible the moment it opens.

**Tags reachable from HEAD, not every tag in the repository.** ``git tag -l`` lists
tags on every branch, which asks the wrong question: whether a release was cut
*anywhere*, rather than whether one was cut from *this line of history* without the
bump. The difference was invisible while CI fetched no tags at all, and would have
become a false alarm the moment it started: tag `1.1.1` on `main` would redden every
branch still declaring `1.1.0` — a long-lived feature branch, a hotfix cut from
`1.1.0` — none of which has done anything wrong. ADR-014 §3 prefers a false negative
to a false alarm, and a guard that reddens honest branches is one someone deletes.
"""
out = subprocess.run(
["git", "-C", str(_REPO), "tag", "-l", "--sort=-v:refname"],
["git", "-C", str(_REPO), "tag", "--merged", "HEAD", "--sort=-v:refname"],
capture_output=True, text=True, check=False, timeout=30,
)
releases = [t for t in out.stdout.split() if re.fullmatch(r"\d+\.\d+\.\d+", t)]
Expand Down
Loading
Loading