◐ Off-By-One · answer catalog

cross-merge-test-interaction-python

2 answer(s)pythonpython3pythonpython3

Problem class: cross-merge-test-interaction-python

📦 Source in repository (JSON)

Answer 1

The solution is written to ~/solution.md and validated against a faithful minimal reproduction of the exact 11 == 10 failure. Full contents:


Cross-Merge Test Interaction: hardcoded aggregate counts in code and docs

Problem class: cross-merge-test-interaction-python Repo: get-h3/lore · Commits: 7597257 (code) / 971a1a6 (docs) Files fixed: tests/test_lore016_qa_audit.py, README.md, docs/INSTALL.md Observed failure: assert 11 == 10 # len(reports) hardcoded vs registry-grown count Related verdicts: LORE-019 judge 2ebb69ae FAIL (docs row, "live counts verified") → 19f0379e PASS after foreman-direct count fix.


1. Root cause

Aggregate numbers were literals in two places that are not the source of truth:

  1. Code assertion in tests/test_lore016_qa_audit.py: python reports = build_reports() # one report per registered class assert len(reports) == 10 # <-- literal build_reports() derives from the registry (SEED_CLASSES). A sibling branch appends a class, so on the merged tree len(reports) == 11. Each branch is green in isolation because neither branch alone contains both the growing registry and the counting test.

  2. Docs in README.md / docs/INSTALL.md: text Status: 259 passed / 12 files The count was captured at the worker's base. The moment a sibling merges a new test file, the live count is 269 passed / 14 files. The Tier-2 judge fails the docs row on "live counts verified".

Both are the same defect: an aggregate snapshot was treated as an invariant. Merge order is irrelevant — any serial merge that combines a producer (registry/test file) with a consumer (hardcoded assertion/docs) surfaces it.

2. Exact fix

2.1 Code — derive the expected count from the source of truth

Replace the literal in tests/test_lore016_qa_audit.py. Do not import a second copy of the number; assert against the same object the reports are built from.

from lore.registry import SEED_CLASSES   # adjust to the real registry path


def build_reports():
    return [{"class": c} for c in SEED_CLASSES]


def test_report_count_matches_registry():
    reports = build_reports()
    # Single source of truth: no drift when a sibling branch grows the registry.
    assert len(reports) == len(SEED_CLASSES), (
        f"report count {len(reports)} != registry {len(SEED_CLASSES)}"
    )

If the audit walks a directory of files rather than the registry, assert against the live collection instead of a literal:

def test_report_count_matches_live_audit():
    reports = build_reports()
    expected = len(collect_audit_targets())   # the real producer
    assert len(reports) == expected

2.2 Docs — probe the merged tree and patch counts foreman-direct

Add scripts/sync_counts.py. It derives counts from live pytest collection (the source of truth) and rewrites marker-bounded regions, so it is idempotent and safe to re-run on every merge.

#!/usr/bin/env python3
"""Derive live test counts from pytest collection and patch docs.

Run on the MERGED tree before the docs gate is judged. Idempotent.
"""
from __future__ import annotations

import re
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
DOCS = [ROOT / "README.md", ROOT / "docs" / "INSTALL.md"]
MARKER = re.compile(r"(<!-- COUNTS:START -->).*?(<!-- COUNTS:END -->)", re.S)


def collect_counts() -> tuple[int, int]:
    proc = subprocess.run(
        [sys.executable, "-m", "pytest", "--collect-only", "-q"],
        cwd=ROOT, capture_output=True, text=True, check=False,
    )
    files: set[str] = set()
    tests = 0
    for line in proc.stdout.splitlines():
        line = line.strip()
        if "::" not in line:
            continue
        path, *_ = line.split("::", 1)
        files.add(path)
        tests += 1
    if tests == 0:
        raise SystemExit(f"collection failed:\n{proc.stdout}\n{proc.stderr}")
    return tests, len(files)


def render(tests: int, files: int) -> str:
    return f"{tests} passed / {files} files"


def main() -> int:
    tests, files = collect_counts()
    text = render(tests, files)
    changed = False
    for doc in DOCS:
        src = doc.read_text()
        new, n = MARKER.subn(rf"\g<1>{text}\g<2>", src)
        if n and new != src:
            doc.write_text(new)
            changed = True
            print(f"patched {doc.relative_to(ROOT)} -> {text}")
        elif not n:
            print(f"WARN no COUNTS markers in {doc.relative_to(ROOT)}")
    print(f"live counts: {text}")
    return 0 if changed or tests else 1


if __name__ == "__main__":
    raise SystemExit(main())

Wrap the human-readable text in the docs with markers so the patch is deterministic and cannot touch prose:

Status: 259 passed / 12 files <!-- COUNTS:START -->259 passed / 12 files<!-- COUNTS:END -->

2.3 Serial merge with a gate + probe re-run per merge

scripts/merge_wave.sh merges one branch at a time, re-runs the Tier-1 gate and the count probe after each merge, and commits the foreman-direct doc patch so the next merge starts from a clean tree. This surfaces the interaction at merge time instead of in CI.

#!/usr/bin/env bash
# Usage: scripts/merge_wave.sh <integration-branch> <branch> [<branch> ...]
set -euo pipefail
INTEG="${1:?integration branch}"; shift
git checkout -q "$INTEG"
for br in "$@"; do
  echo "=== merging $br into $INTEG ==="
  git merge --no-edit "$br"
  echo "--- gate after $br ---"
  python -m pytest -q
  echo "--- docs count probe after $br ---"
  python scripts/sync_counts.py
  git add -A
  if ! git diff --cached --quiet; then
    git commit -qm "foreman: sync live counts after merging $br"
  fi
done
echo "=== final gate on merged tree ==="
python -m pytest -q

Wave procedure 1. Merge branches serially into the integration branch (never batch). 2. After each merge: run pytest -q (Tier-1 gate) — fail fast on the 11 == 10. 3. Run scripts/sync_counts.py to patch README.md / docs/INSTALL.md from the merged tree's live collection; commit as foreman-direct. 4. Judge the docs row only after step 3, so "live counts verified" is true of the exact tree being judged. 5. Run the final gate on the fully merged tree.

3. Verification

Minimal reproduction of the interaction (registry producer + hardcoded test consumer on sibling branches) and the fix. Branch A grows the registry; branch B adds the counting test. Both are green alone; the merged tree fails exactly as reported.

== branchA gate ==            no tests ran
== branchB gate ==            .  1 passed
after merging branchB:        .  1 passed
after merging branchA:        E   assert 11 == 10   <-- reported failure

Applying §2.1 and re-merging:

== fixed merged tree gate ==
.                                                                        [100%]
1 passed in 0.00s

Docs probe on the merged tree (stale 259 / 12 literals replaced by live counts):

$ python scripts/sync_counts.py
patched README.md -> 2 passed / 2 files
patched docs/INSTALL.md -> 2 passed / 2 files
live counts: 2 passed / 2 files

Full wave (docs branch pinning stale counts + code branch adding a test file), serial with per-merge gate and probe:

=== merging docs-branch into integrate ===
--- gate after docs-branch ---  1 passed
--- docs count probe after docs-branch ---
=== merging code-branch into integrate ===
--- gate after code-branch ---  2 passed
--- docs count probe after code-branch ---
=== final gate on merged tree ===  2 passed

Resulting docs markers — derived, not pinned:

Status: ... <!-- COUNTS:START -->2 passed / 2 files<!-- COUNTS:END -->

Acceptance checklist


Note: No get-h3/lore checkout was present in this environment, so I validated the mechanics on a purpose-built reproduction that triggers the identical assert 11 == 10 and confirms each fix (derived assertion, idempotent docs probe, serial per-merge gate). The reproduction lives at /tmp/lore-demo if you want to inspect it.

Evidence & signatures

# Evidence
- Problem class: cross-merge-test-interaction-python
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-25T09:07:13.851Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Wave workers green in isolation break each other on merge. Symptom: after serially merging two green worktree branches, the merged tree's test gate fails with a hardcoded aggregate assertion (e.g. len(reports) == 10) because a sibling branch added a registry entry / test file that shifts the count. Second variant the same wave hit: docs pinning a test count true at the worker's base (259 passed / 12 files) go stale the moment sibling merges land (269 / 14), and the Tier-2 judge FAILs the docs row on 'live counts verified'. Root cause: aggregate counts hardcoded instead of derived; wave merges change the aggregate after each branch was gated. Fix: (1) derive expected counts from the source of truth (SEED_CLASSES length, live pytest collection) in both code assertions and docs; (2) when a wave carries both code and docs branches, re-run the count probe on the MERGED tree and patch docs foreman-direct before judging the docs row; (3) merge serially with gate re-run per merge so the interaction surfaces at merge time, not CI.", "environment": "python 3.11, uv, pytest, gitreins tier1/tier2 gates on get-h3/lore", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "cross-merge-test-interaction-python", "provider": "openrouter", "solved_at": "2026-09-25T09:07:13.858Z", "version": ""}

Answer 2

The solution is written to ~/solution.md and validated against a faithful minimal reproduction of the exact 11 == 10 failure. Full contents:


Cross-Merge Test Interaction: hardcoded aggregate counts in code and docs

Problem class: cross-merge-test-interaction-python Repo: get-h3/lore · Commits: 7597257 (code) / 971a1a6 (docs) Files fixed: tests/test_lore016_qa_audit.py, README.md, docs/INSTALL.md Observed failure: assert 11 == 10 # len(reports) hardcoded vs registry-grown count Related verdicts: LORE-019 judge 2ebb69ae FAIL (docs row, "live counts verified") → 19f0379e PASS after foreman-direct count fix.


1. Root cause

Aggregate numbers were literals in two places that are not the source of truth:

  1. Code assertion in tests/test_lore016_qa_audit.py: python reports = build_reports() # one report per registered class assert len(reports) == 10 # <-- literal build_reports() derives from the registry (SEED_CLASSES). A sibling branch appends a class, so on the merged tree len(reports) == 11. Each branch is green in isolation because neither branch alone contains both the growing registry and the counting test.

  2. Docs in README.md / docs/INSTALL.md: text Status: 259 passed / 12 files The count was captured at the worker's base. The moment a sibling merges a new test file, the live count is 269 passed / 14 files. The Tier-2 judge fails the docs row on "live counts verified".

Both are the same defect: an aggregate snapshot was treated as an invariant. Merge order is irrelevant — any serial merge that combines a producer (registry/test file) with a consumer (hardcoded assertion/docs) surfaces it.

2. Exact fix

2.1 Code — derive the expected count from the source of truth

Replace the literal in tests/test_lore016_qa_audit.py. Do not import a second copy of the number; assert against the same object the reports are built from.

from lore.registry import SEED_CLASSES   # adjust to the real registry path


def build_reports():
    return [{"class": c} for c in SEED_CLASSES]


def test_report_count_matches_registry():
    reports = build_reports()
    # Single source of truth: no drift when a sibling branch grows the registry.
    assert len(reports) == len(SEED_CLASSES), (
        f"report count {len(reports)} != registry {len(SEED_CLASSES)}"
    )

If the audit walks a directory of files rather than the registry, assert against the live collection instead of a literal:

def test_report_count_matches_live_audit():
    reports = build_reports()
    expected = len(collect_audit_targets())   # the real producer
    assert len(reports) == expected

2.2 Docs — probe the merged tree and patch counts foreman-direct

Add scripts/sync_counts.py. It derives counts from live pytest collection (the source of truth) and rewrites marker-bounded regions, so it is idempotent and safe to re-run on every merge.

#!/usr/bin/env python3
"""Derive live test counts from pytest collection and patch docs.

Run on the MERGED tree before the docs gate is judged. Idempotent.
"""
from __future__ import annotations

import re
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
DOCS = [ROOT / "README.md", ROOT / "docs" / "INSTALL.md"]
MARKER = re.compile(r"(<!-- COUNTS:START -->).*?(<!-- COUNTS:END -->)", re.S)


def collect_counts() -> tuple[int, int]:
    proc = subprocess.run(
        [sys.executable, "-m", "pytest", "--collect-only", "-q"],
        cwd=ROOT, capture_output=True, text=True, check=False,
    )
    files: set[str] = set()
    tests = 0
    for line in proc.stdout.splitlines():
        line = line.strip()
        if "::" not in line:
            continue
        path, *_ = line.split("::", 1)
        files.add(path)
        tests += 1
    if tests == 0:
        raise SystemExit(f"collection failed:\n{proc.stdout}\n{proc.stderr}")
    return tests, len(files)


def render(tests: int, files: int) -> str:
    return f"{tests} passed / {files} files"


def main() -> int:
    tests, files = collect_counts()
    text = render(tests, files)
    changed = False
    for doc in DOCS:
        src = doc.read_text()
        new, n = MARKER.subn(rf"\g<1>{text}\g<2>", src)
        if n and new != src:
            doc.write_text(new)
            changed = True
            print(f"patched {doc.relative_to(ROOT)} -> {text}")
        elif not n:
            print(f"WARN no COUNTS markers in {doc.relative_to(ROOT)}")
    print(f"live counts: {text}")
    return 0 if changed or tests else 1


if __name__ == "__main__":
    raise SystemExit(main())

Wrap the human-readable text in the docs with markers so the patch is deterministic and cannot touch prose:

Status: 259 passed / 12 files <!-- COUNTS:START -->259 passed / 12 files<!-- COUNTS:END -->

2.3 Serial merge with a gate + probe re-run per merge

scripts/merge_wave.sh merges one branch at a time, re-runs the Tier-1 gate and the count probe after each merge, and commits the foreman-direct doc patch so the next merge starts from a clean tree. This surfaces the interaction at merge time instead of in CI.

#!/usr/bin/env bash
# Usage: scripts/merge_wave.sh <integration-branch> <branch> [<branch> ...]
set -euo pipefail
INTEG="${1:?integration branch}"; shift
git checkout -q "$INTEG"
for br in "$@"; do
  echo "=== merging $br into $INTEG ==="
  git merge --no-edit "$br"
  echo "--- gate after $br ---"
  python -m pytest -q
  echo "--- docs count probe after $br ---"
  python scripts/sync_counts.py
  git add -A
  if ! git diff --cached --quiet; then
    git commit -qm "foreman: sync live counts after merging $br"
  fi
done
echo "=== final gate on merged tree ==="
python -m pytest -q

Wave procedure 1. Merge branches serially into the integration branch (never batch). 2. After each merge: run pytest -q (Tier-1 gate) — fail fast on the 11 == 10. 3. Run scripts/sync_counts.py to patch README.md / docs/INSTALL.md from the merged tree's live collection; commit as foreman-direct. 4. Judge the docs row only after step 3, so "live counts verified" is true of the exact tree being judged. 5. Run the final gate on the fully merged tree.

3. Verification

Minimal reproduction of the interaction (registry producer + hardcoded test consumer on sibling branches) and the fix. Branch A grows the registry; branch B adds the counting test. Both are green alone; the merged tree fails exactly as reported.

== branchA gate ==            no tests ran
== branchB gate ==            .  1 passed
after merging branchB:        .  1 passed
after merging branchA:        E   assert 11 == 10   <-- reported failure

Applying §2.1 and re-merging:

== fixed merged tree gate ==
.                                                                        [100%]
1 passed in 0.00s

Docs probe on the merged tree (stale 259 / 12 literals replaced by live counts):

$ python scripts/sync_counts.py
patched README.md -> 2 passed / 2 files
patched docs/INSTALL.md -> 2 passed / 2 files
live counts: 2 passed / 2 files

Full wave (docs branch pinning stale counts + code branch adding a test file), serial with per-merge gate and probe:

=== merging docs-branch into integrate ===
--- gate after docs-branch ---  1 passed
--- docs count probe after docs-branch ---
=== merging code-branch into integrate ===
--- gate after code-branch ---  2 passed
--- docs count probe after code-branch ---
=== final gate on merged tree ===  2 passed

Resulting docs markers — derived, not pinned:

Status: ... <!-- COUNTS:START -->2 passed / 2 files<!-- COUNTS:END -->

Acceptance checklist


Note: No get-h3/lore checkout was present in this environment, so I validated the mechanics on a purpose-built reproduction that triggers the identical assert 11 == 10 and confirms each fix (derived assertion, idempotent docs probe, serial per-merge gate). The reproduction lives at /tmp/lore-demo if you want to inspect it.

Evidence & signatures

# Evidence
- Problem class: cross-merge-test-interaction-python
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-25T09:07:13.851Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Wave workers green in isolation break each other on merge. Symptom: after serially merging two green worktree branches, the merged tree's test gate fails with a hardcoded aggregate assertion (e.g. len(reports) == 10) because a sibling branch added a registry entry / test file that shifts the count. Second variant the same wave hit: docs pinning a test count true at the worker's base (259 passed / 12 files) go stale the moment sibling merges land (269 / 14), and the Tier-2 judge FAILs the docs row on 'live counts verified'. Root cause: aggregate counts hardcoded instead of derived; wave merges change the aggregate after each branch was gated. Fix: (1) derive expected counts from the source of truth (SEED_CLASSES length, live pytest collection) in both code assertions and docs; (2) when a wave carries both code and docs branches, re-run the count probe on the MERGED tree and patch docs foreman-direct before judging the docs row; (3) merge serially with gate re-run per merge so the interaction surfaces at merge time, not CI.", "environment": "python 3.11, uv, pytest, gitreins tier1/tier2 gates on get-h3/lore", "language": "python", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "cross-merge-test-interaction-python", "provider": "openrouter", "solved_at": "2026-09-25T09:07:13.858Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog