Spaces:
Sleeping
fix: main shipped unresolved conflict markers; guard against a repeat
Browse files`main` carried literal `<<<<<<< HEAD` / `=======` / `>>>>>>>` markers in
memory.md and deployed them to the live Space. Introduced by b676112, a
cherry-pick of the hermetic-suite commit (dbaeaa3) that hit an append-only
collision, was committed unresolved, and was pushed.
Two things made it hard to spot:
- b676112's message describes different work ("verify: routing leg passes;
dispatch blocked by private-Space 404") while its diff is the hermetic
suite. Searching the log for the socket guard does not find it.
- The code half landed correctly. conftest's guard and test_hermetic.py are
complete and right on main; only the prose merge broke. Tests were green
the entire time, because nothing tests prose.
Resolution: both colliding entries kept in chronological order. An
append-only log has no real conflict, only an ordering question.
Also corrected a statement main was making about itself. That cherry-pick
carried a TODO item reading "*This branch's* RESERVED.md is stale β it stops
at 0005". True where it was written; false on main, whose ledger correctly
shows 0006 + 0007 published and next free 0008. Rewritten to keep the lesson
(read `git show main:docs/adr/RESERVED.md`, never your working copy) without
the false claim.
NOT carried over from that branch's follow-up (52bb514): its narrative
records a rebase onto main, but main received a merge (80b5e01); and it flags
pancreas_cptac_gdc / pdac_msk_2024 as missing source_import_date, which is
not true here β all six artifacts on main carry it, verified, because the
merge re-curated all six rather than trusting a textual JSON merge. Importing
it would have written a history that did not happen and a closed backlog item.
New: test_no_unresolved_conflict_markers_are_committed, over git ls-files.
Prose is the only part of this repo nothing verifies β code has tests,
artifacts have `src.curate --check`, licences have the review table. Verified
against the real failure: restoring b676112's memory.md fails the test on all
three marker lines.
Tests: 167 pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- TODO.md +8 -5
- memory.md +41 -3
- tests/test_hermetic.py +42 -0
|
@@ -229,11 +229,14 @@ the design doc's M0βM4 is the intent behind it β see that doc's Β§0).
|
|
| 229 |
- [ ] Optional: promote the stub-vs-restructure choice to an ADR if it proves contested.
|
| 230 |
**Next free is 0008** β `main` has 0006 (variantΓsubtype join) *and* 0007 (re-curation
|
| 231 |
cadence) published. Claim in `RESERVED.md` on `main`, alone, first.
|
| 232 |
-
- [
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
## Open questions
|
| 239 |
|
|
|
|
| 229 |
- [ ] Optional: promote the stub-vs-restructure choice to an ADR if it proves contested.
|
| 230 |
**Next free is 0008** β `main` has 0006 (variantΓsubtype join) *and* 0007 (re-curation
|
| 231 |
cadence) published. Claim in `RESERVED.md` on `main`, alone, first.
|
| 232 |
+
- [x] β οΈ **ADR-ledger near-miss (the fourth), resolved.** A working branch's
|
| 233 |
+
`docs/adr/RESERVED.md` stopped at 0005 and said "next free 0006" while `main` had already
|
| 234 |
+
burned 0006 *and* 0007. `main`'s ledger is correct β 0006 + 0007 published, **next free
|
| 235 |
+
0008** β so nothing was mis-numbered. Kept because the near-miss is the lesson: this is the
|
| 236 |
+
per-lane-copy failure the ledger's own postmortem describes, and the shared-row conflict
|
| 237 |
+
cannot fire between branches, so `ls docs/adr/` and your local ledger will both hand you a
|
| 238 |
+
burned number. **Read `git show main:docs/adr/RESERVED.md` before claiming, never your
|
| 239 |
+
working copy.**
|
| 240 |
|
| 241 |
## Open questions
|
| 242 |
|
|
@@ -839,7 +839,6 @@ by running the suite with `socket.connect` blocked outright β **111 tests pass
|
|
| 839 |
all** (the three UI test modules still touch it, but that is Gradio's mocked-OAuth HF call at
|
| 840 |
import in a local dev env, not our code and not present on a Space).
|
| 841 |
|
| 842 |
-
<<<<<<< HEAD
|
| 843 |
|
| 844 |
---
|
| 845 |
|
|
@@ -866,7 +865,6 @@ misled again. One contract, with instructions when you miss it.
|
|
| 866 |
Ordering is gate-first: an unauthenticated caller gets `denied` and learns nothing about our
|
| 867 |
inputs β pinned by `test_argument_errors_are_reported_only_after_the_auth_gate`. 132 tests (7 new,
|
| 868 |
alongside the denial-diagnosis guards they mirror).
|
| 869 |
-
=======
|
| 870 |
---
|
| 871 |
|
| 872 |
## 2026-07-28 β Hermetic is now *enforced*, and the whole suite is hermetic
|
|
@@ -940,7 +938,6 @@ reading `SHOWCASE_STATUS.md` before updating it β the same habit that caught c
|
|
| 940 |
work β `gradio[oauth]==6.18.0` (the `oauth` extra is required or the UI modules fail to import at
|
| 941 |
all), plus the rest of `requirements.txt` and pytest. Previously the memory said to borrow
|
| 942 |
`DecoupleRpy_Agent/.venv`.
|
| 943 |
-
>>>>>>> dbaeaa3 (tests: enforce hermeticity with a socket guard; last 3 network-touching modules closed)
|
| 944 |
|
| 945 |
---
|
| 946 |
|
|
@@ -974,3 +971,44 @@ credential operation for a human. Worth noting the order of failure for whoever
|
|
| 974 |
`HF_TOKEN` unset the symptom is a 404 (invisible private repo); once set, the next thing exercised
|
| 975 |
is the allow-list β and the identity it resolves to must be on `ALLOWED_IDS` here
|
| 976 |
(`anne-voigt,cpelz741` today).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 839 |
all** (the three UI test modules still touch it, but that is Gradio's mocked-OAuth HF call at
|
| 840 |
import in a local dev env, not our code and not present on a Space).
|
| 841 |
|
|
|
|
| 842 |
|
| 843 |
---
|
| 844 |
|
|
|
|
| 865 |
Ordering is gate-first: an unauthenticated caller gets `denied` and learns nothing about our
|
| 866 |
inputs β pinned by `test_argument_errors_are_reported_only_after_the_auth_gate`. 132 tests (7 new,
|
| 867 |
alongside the denial-diagnosis guards they mirror).
|
|
|
|
| 868 |
---
|
| 869 |
|
| 870 |
## 2026-07-28 β Hermetic is now *enforced*, and the whole suite is hermetic
|
|
|
|
| 938 |
work β `gradio[oauth]==6.18.0` (the `oauth` extra is required or the UI modules fail to import at
|
| 939 |
all), plus the rest of `requirements.txt` and pytest. Previously the memory said to borrow
|
| 940 |
`DecoupleRpy_Agent/.venv`.
|
|
|
|
| 941 |
|
| 942 |
---
|
| 943 |
|
|
|
|
| 971 |
`HF_TOKEN` unset the symptom is a 404 (invisible private repo); once set, the next thing exercised
|
| 972 |
is the allow-list β and the identity it resolves to must be on `ALLOWED_IDS` here
|
| 973 |
(`anne-voigt,cpelz741` today).
|
| 974 |
+
|
| 975 |
+
---
|
| 976 |
+
|
| 977 |
+
## 2026-07-28 β Repaired `main`: conflict markers were committed and deployed
|
| 978 |
+
|
| 979 |
+
`main` carried **literal `<<<<<<< HEAD` / `=======` / `>>>>>>>` markers in `memory.md`**, and they
|
| 980 |
+
went out to the live Space. Introduced by `b676112`, which was a cherry-pick of the hermetic-suite
|
| 981 |
+
commit (`dbaeaa3`) that hit an append-only collision in `memory.md`, was committed unresolved, and
|
| 982 |
+
was pushed. Two further things about that commit are worth knowing, because both make it hard to
|
| 983 |
+
find again:
|
| 984 |
+
|
| 985 |
+
- **Its message describes different work.** It reads "verify: routing leg passes; dispatch blocked
|
| 986 |
+
by private-Space 404", but its diff is the hermetic suite β `tests/conftest.py` (+109),
|
| 987 |
+
`tests/test_hermetic.py` (+69), plus TODO/memory. Searching the log for the socket guard will
|
| 988 |
+
not find it.
|
| 989 |
+
- **The code half landed fine.** The socket guard and `test_hermetic.py` are correct and complete
|
| 990 |
+
on `main`; only the prose merge was broken. So this was cosmetically invisible β tests pass with
|
| 991 |
+
conflict markers sitting in `memory.md`, because nothing tests prose.
|
| 992 |
+
|
| 993 |
+
**Repair:** kept both colliding entries (machine-endpoint argument errors, and hermetic
|
| 994 |
+
enforcement) in chronological order β an append-only log has no genuine conflict, only an ordering
|
| 995 |
+
question.
|
| 996 |
+
|
| 997 |
+
**Also corrected a statement `main` was making about itself.** That cherry-pick carried over a
|
| 998 |
+
TODO item reading "*This branch's* `RESERVED.md` is stale β it stops at 0005". True of the branch
|
| 999 |
+
it was written on; **false on `main`**, whose ledger correctly shows 0006 + 0007 published and next
|
| 1000 |
+
free 0008. Rewritten to keep the lesson (check `git show main:docs/adr/RESERVED.md`, never your
|
| 1001 |
+
working copy β the per-lane-copy failure means the shared-row conflict cannot fire) without the
|
| 1002 |
+
false claim.
|
| 1003 |
+
|
| 1004 |
+
**Deliberately NOT carried over** from that branch's follow-up commit (`52bb514`): its narrative
|
| 1005 |
+
records a *rebase* onto main, but `main` received a **merge** (`80b5e01`) instead, and it flags a
|
| 1006 |
+
gap β `pancreas_cptac_gdc` / `pdac_msk_2024` missing `source_import_date` β that **does not exist
|
| 1007 |
+
here**. All six artifacts on `main` carry it (verified), because the merge re-curated all six
|
| 1008 |
+
rather than trusting git's textual merge of the JSON. Importing that entry would have written a
|
| 1009 |
+
history that did not happen and a backlog item already closed.
|
| 1010 |
+
|
| 1011 |
+
**The generalizable bit:** prose is the only part of this repo nothing verifies. Code has tests,
|
| 1012 |
+
artifacts have `--check`, licences have the review table β `memory.md` and `TODO.md` have nothing,
|
| 1013 |
+
so a broken merge in them survives a fully green suite and ships. Worth a lint step (grep the tree
|
| 1014 |
+
for conflict markers) if it happens twice.
|
|
@@ -67,3 +67,45 @@ def test_ui_modules_import_without_network(module):
|
|
| 67 |
suite is supposed to have stopped having. Importing them here proves the seam still holds.
|
| 68 |
"""
|
| 69 |
__import__(module)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
suite is supposed to have stopped having. Importing them here proves the seam still holds.
|
| 68 |
"""
|
| 69 |
__import__(module)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
# --------------------------------------------------------------------------- #
|
| 73 |
+
# Unresolved conflict markers β the one class of breakage nothing else catches
|
| 74 |
+
# --------------------------------------------------------------------------- #
|
| 75 |
+
def test_no_unresolved_conflict_markers_are_committed():
|
| 76 |
+
"""No tracked file may contain a merge-conflict marker.
|
| 77 |
+
|
| 78 |
+
This exists because it happened: `main` shipped `memory.md` with literal `<<<<<<< HEAD`
|
| 79 |
+
markers to the live Space, and the suite stayed green the whole time. Code has tests,
|
| 80 |
+
artifacts have `src.curate --check`, licences have the review table β **prose has nothing**,
|
| 81 |
+
so a botched merge in `memory.md` or `TODO.md` is invisible to everything except a reader.
|
| 82 |
+
|
| 83 |
+
Checking tracked files via git (rather than walking the tree) keeps the venv, caches and
|
| 84 |
+
curated scratch out of it, and means a file is covered the moment it is added.
|
| 85 |
+
"""
|
| 86 |
+
import subprocess
|
| 87 |
+
from pathlib import Path
|
| 88 |
+
|
| 89 |
+
root = Path(__file__).resolve().parents[1]
|
| 90 |
+
tracked = subprocess.run(
|
| 91 |
+
["git", "-C", str(root), "ls-files", "-z"],
|
| 92 |
+
capture_output=True, text=True, check=True,
|
| 93 |
+
).stdout.split("\0")
|
| 94 |
+
|
| 95 |
+
# Split so this file's own strings are not a match when it scans itself.
|
| 96 |
+
markers = ("<" * 7, "=" * 7, ">" * 7)
|
| 97 |
+
offenders = []
|
| 98 |
+
for name in filter(None, tracked):
|
| 99 |
+
path = root / name
|
| 100 |
+
if not path.is_file() or path.suffix in {".png", ".jpg", ".ico"}:
|
| 101 |
+
continue
|
| 102 |
+
try:
|
| 103 |
+
lines = path.read_text(encoding="utf-8").splitlines()
|
| 104 |
+
except (UnicodeDecodeError, OSError):
|
| 105 |
+
continue # binary or unreadable β not prose, not our concern
|
| 106 |
+
for n, line in enumerate(lines, 1):
|
| 107 |
+
# A marker is only a marker at the START of a line, which is what git writes.
|
| 108 |
+
if any(line.startswith(m) for m in markers) and path.name != Path(__file__).name:
|
| 109 |
+
offenders.append(f"{name}:{n}: {line[:60]}")
|
| 110 |
+
|
| 111 |
+
assert not offenders, "unresolved conflict markers committed:\n" + "\n".join(offenders)
|