Hash the Output Tree Before You Extract One Helper
A messy repo does not need a rewrite first. AI diffs look tidy and still change behavior. Brownfield scripts mix I/O, scoring, and prints. A full rewrite usually moves every seam at once. Lock three facts only on pass one. Process exit code after a fixture run. Relative paths of every produced file.

A messy repo does not need a rewrite first. AI diffs look tidy and still change behavior. Brownfield scripts mix I/O, scoring, and prints. A full rewrite usually moves every seam at once. Lock three facts only on pass one. Process exit code after a fixture run. Relative paths of every produced file. SHA-256 digest of each produced file. Do not lock timestamps, PID strings, or cwd. Stdout can wait until the tree is stable. The sample below is a stocktake CLI. # stocktake.py โ characterization target, not production advice from __future__ import annotations import csv import json import sys from pathlib import Path def run(argv: list[str]) -> int: if len(argv) != 3: print("usage: stocktake.py IN_DIR OUT_DIR", file=sys.stderr) return 2 in_dir = Path(argv[1]) out_dir = Path(argv[2]) out_dir.mkdir(parents=True, exist_ok=True) rows = [] for path in sorted(in_dir.glob("*.csv")): with path.open(newline="", encoding="utf-8") as handle: for raw in csv.DictReader(handle): sku = (raw.get("sku") or "").strip() qty = int(raw.get("qty") or "0") price = float(raw.get("price") or "0") flag = (raw.get("flag") or "").lower() score = qty * price if flag == "haz": score *= 1.25 elif flag == "bulk": score *= 0.85 if qty == 0: score = 0.0 rows.append({"sku": sku, "score": round(score, 2), "src": path.name}) payload = {"count": len(rows), "items": rows} target = out_dir / "stocktake.json" target.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") print(f"wrote {target}") return 0 if __name__ == "__main__": raise SystemExit(run(sys.argv)) The scoring rules are the later extract target. Use two CSVs and one empty output folder. fixtures/stocktake/in/alpha.csv fixtures/stocktake/in/beta.csv fixtures/stocktake/out/ # empty, gitkeep only sku,qty,price,flag A-1,2,10.00,haz A-2,0,9.50,bulk sku,qty,price,flag B-9,4,3.25, B-8,1,100.00,BULK Note the mixed case on BULK. Run the script against a temp copy. python3 stocktake.py fixtures/stocktake/in /tmp/stock-out python3 hash_tree.py /tmp/stock-out > fixtures/stocktake/golden.sha256 Re-run twice. The two manifests must match. The test copies the fixture, runs the CLI, hashes. Move the score math. Leave glob and JSON in place. Green hash means behavior held for this fixture. Save this as hash_tree.py beside the script. # hash_tree.py from __future__ import annotations import hashlib import sys from pathlib import Path def digest_file(path: Path) -> str: hasher = hashlib.sha256() with path.open("rb") as handle: for chunk in iter(lambda: handle.read(65536), b""): hasher.update(chunk) return hasher.hexdigest() def manifest(root: Path) -> str: lines = [] for path in sorted(p for p in root.rglob("*") if p.is_file()): rel = path.relative_to(root).as_posix() lines.append(f"{digest_file(path)} {rel}") return "\n".join(lines) + ("\n" if lines else "") if __name__ == "__main__": print(manifest(Path(sys.argv[1])), end="") The test driver stays equally small. # test_stocktake_tree.py from __future__ import annotations import subprocess import sys from pathlib import Path ROOT = Path(__file__).resolve().parent GOLDEN = (ROOT / "fixtures/stocktake/golden.sha256").read_text(encoding="utf-8") def test_stocktake_output_tree(tmp_path: Path) -> None: out_dir = tmp_path / "out" proc = subprocess.run( [sys.executable, str(ROOT / "stocktake.py"), str(ROOT / "fixtures/stocktake/in"), str(out_dir)], check=False, capture_output=True, text=True, ) assert proc.returncode == 0, proc.stderr hashed = subprocess.check_output( [sys.executable, str(ROOT / "hash_tree.py"), str(out_dir)], text=True, ) assert hashed == GOLDEN Run it with one command. python3 -m pytest test_stocktake_tree.py -q A failing assert prints two manifests. Signal Action Stop condition Exit code flips Revert the extract Fixture cannot start Path set grows Revert, then inspect writes Surprise file appeared Digest drifts Diff JSON, then revert Score or key changed Hash holds, names changed Keep the extract Public tree unchanged Hash holds, extra logs Optional later pin Files still match Need a second helper New patch, same oracle One concern per diff Use the table during review, not after merge. After the golden file exists, extract scoring only. def score_item(qty: int, price: float, flag: str) -> float: score = qty * price normalized = flag.lower() if normalized == "haz": score *= 1.25 elif normalized == "bulk": score *= 0.85 if qty == 0: score = 0.0 return round(score, 2) Wire it in with a one-line call. pytest. The tree hash must match. That is the entire refactor for day one. A model may propose the extract text. MonkeyCode provides free model access and a free server option for that proposal step. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Keep generation on the server if the laptop is busy. Keep hashes on disk you control. Feed the model the messy function and the test. If the patch touches JSON keys, discard it. score_item, review it. This oracle is only as wide as the fixture. SHA-256 ignores meaning. It only detects bytes. sort_keys. The harness will not catch performance regressions. Floating point remains a fixture problem. round(..., 2) in both code and samples. Skip this if the script has no file outputs. Do not use directory hashes for secret material. Teams without a test runner gain little here. Start with a fixture and a tree hash. If you publish a follow-up, paste the two manifests. Skip the narrative about confidence. The bytes either matched or they did not.
Key Takeaways
- โขA messy repo does not need a rewrite first. AI diffs look tidy and still change behavior. Brownfield scripts mix I/O, scoring, and prints. A full rewrite usually moves every seam at once. Lock three facts only on pass one. Process exit code after a fixture run. Relative paths of every produced file.
- โขThis story was reported by Dev.to, covering developments in the dev space.
- โขAI advancements continue to reshape industries โ read the full article on Dev.to for complete coverage.
๐ Continue reading the full article:
Read Full Article on Dev.to โShare this article



