diff --git a/research/halo-copy-enumeration/README.md b/research/halo-copy-enumeration/README.md
new file mode 100644
index 0000000000..0abc1a3c3d
--- /dev/null
+++ b/research/halo-copy-enumeration/README.md
@@ -0,0 +1,339 @@
+# Gaussian halo input-copy enumeration
+
+**Scoped all-size combinatorial implication, independent finite verifier, and an
+explicit physical-cost boundary. No new κ.** The selected conditional record
+remains κ = 0.00302015. On 2026-10-22 the orchestrator replayed the final
+algorithm-seam controls and six-input closure under CPython 3.12.13: metadata,
+normal and optimized registered runs passed. Finite audit evidence is not
+scientific acceptance, a full-tape proof, or selected-result replay.
+
+This answers Nick Petalas's [#4217 open question](../halo-locality-witness-audit/README.md#open-next-questions),
+not his polynomial-locality argument. Its caller is Cinna Davis's
+[GAUSSIAN.md lines 177–226](../unconditional-batched-crt/GAUSSIAN.md) and
+[HALO.md lines 36–94](../unconditional-batched-crt/HALO.md), retained from #4100.
+The new result is the explicit prefix/DFS enumeration, exact copy-volume
+identity, independent destination oracle, and separation of non-output setup
+from output-sensitive work. It neither repeats the locality factor-two note
+nor substitutes exponent arithmetic for a universal algorithm.
+
+## Definition and quantified result
+
+Let g >= 1, integer A > 0, L > 4A, 0 <= b < A, and axis periods S_i = n_i L
+with n_i >= 2. Coordinates are canonical integers modulo S_i. Here b is a
+sufficient input-dependency radius, not a Gaussian conditioning parameter.
+For core c, write local coordinates in [0,L). The kept interior is
+I = [A,L-A); the lower and upper boundary intervals are B_0 = [0,A) and
+B_1 = [L-A,L). All intervals are half-open integer intervals.
+
+For first boundary axis f and side s, the **output rectangle** is
+
+ R(c,f,s) = I^f × B_s × [0,L)^(g-f-1), translated by cL.
+
+Its **input rectangle** E(c,f,s) expands every interval by b on both sides,
+then reduces coordinates periodically. A canonical source is copied once for
+each E containing it, even if it belongs to several destinations. Its full key
+is `(destination core tuple, f, s, lifted local tuple, canonical source tuple)`.
+The signed local tuple records wrap without losing the destination chart.
+Input-copy keys are unique as full keys; source addresses alone need not be.
+Returned output keys are canonical global output coordinates, without f or s.
+
+HALO uses the conservative expansion A. Using b < A is a sufficient tighter
+input set for a tensor whose per-axis dependency bandwidth is at most b; it
+is contained in the source's A-expanded allocation. Thus the volume upper
+bound below also bounds the tighter scheme. This does not silently identify
+A and b: a literal A-expanded implementation can use the same interval proof
+with b=A (half-open expanded interiors then tile rather than have gaps), but
+that variant is outside this verifier's explicitly strict-bandwidth domain.
+No polynomial row locality is proved here. The call-site facts bandwidth
+
=L-b. Because 2b=2, the list has one or two distinct choices.
+These are exactly the cores whose expanded full interval contains x_i.
+An earlier-axis expanded interior contains x_i exactly when
+A-b <= r_i < L-A+b, and its core must be q_i: the expanded interiors are
+strictly separated by a positive gap. Precompute these memberships and the
+expanded lower/upper face memberships from the same at-most-two candidates.
+Every face interval is contained in its expanded full interval, so no face
+choice is missed.
+
+Let prefix[f] be the AND of the interior-membership flags for i0, the first-axis face has two neighboring face destinations in total
+and every later axis has two choices: **2^g copies from that one address**.
+The bound charges them as actual leaves, not by assuming constant fanout.
+
+## Exact volume and the claimed cost boundary
+
+Let K=product n_i, V=K L^g. Summing rectangle volumes with multiplicity gives
+
+ C = K sum_(f=0)^(g-1) 2 (L-2A+2b)^f (A+2b) (L+2b)^(g-f-1).
+
+This is a copied-input volume, not a union volume. With b<=A it is at most
+
+ 6 V (gA/L) (1+2A/L)^(g-1).
+
+Thus C=O(VgA/L) if gA/L remains bounded (in particular the source's o(1)
+hypothesis). The number of returned outputs is exactly
+K[L^g-(L-2A)^g]. No bounded-multiplicity claim about individual sources is
+needed. Empty centers and exponentially many-copy corners coexist.
+
+The following implication is **conditional on a physical implementation**,
+not a measured cost theorem for this Python program:
+
+1. GAUSSIAN 194–207 supplies g=p^beta, local L with log L=O(log p), and
+ beta+2(1-epsilon)<1. The absolute coordinate width ell and epsilon are
+ defined in [CRT.md lines 20–28](../unconditional-batched-crt/CRT.md) and
+ [PROOF.md lines 19–26](../unconditional-batched-crt/PROOF.md); both are
+ pinned live inputs. With the caller's ell=O(p^(1-epsilon)), the quoted coordinate arithmetic
+ O(g ell^2 polylog p)=o(p) and O(g log L)=o(p) absorb the O(g) setup into
+ one p-bit-record scan. A mere g<=p would not justify this absorption.
+ HALO's g log p=o(p) is also needed for short-field movement.
+2. A destination/core/source key needs O(g ell + g log L + log g) bits,
+ including signed local fields and face labels. This is O(p) under those
+ hypotheses; spectator labels may be retained once, with the inherited
+ complete-record O(p) width. Re-encoding a full key is not O(1) bits.
+ A short-field stack implementation costing O(log L+log g) per traversed
+ edge yields O(g polylog p) control work per leaf, absorbed by O(p) up to
+ polylogs under the same strict beta<1 condition. Copying the p-bit value
+ and complete key still costs O(p) bits per leaf. The node-count proof
+ alone does not establish this stack/head-movement implementation.
+3. Full-key binary radix sorting uses O(p) stable passes, not O(1). Each
+ pass must scan/move O(p)-bit records and preserve all key fields, costing
+ O(C p^2) bit movement (a generous upper bound also in normalized record
+ work). Return sorting has at most C records. Sorting dense V records
+ separately for each face would instead introduce the forbidden gV term.
+ A fixed-tape stable distribution and rewind schedule is still an explicit
+ physical premise, not Python Counter/dict behavior.
+4. Conditional on sequential enumeration and sorting as above, the source's
+ direct per-axis row application costs O(g A^2) record operations per copied
+ record, giving per-group O(V + C[gA^2+p^2]) polylog p. Substituting the
+ copied-volume bound and multiplying by O(d/g) balanced groups gives
+
+ O(V [d/g + d g A^3/L + d A p^2/L] polylog p).
+
+ Local coefficient setup remains an additive S_setup until the HALO 68–74
+ hypotheses apply: fixed polynomial-in-p setup per rectangle/core,
+ g tending to infinity, and at least g-1 long L-O(A) axes. Fixed g fixtures
+ cannot demonstrate that absorption. The costs of actual row generation,
+ arithmetic, exposure, and setup are not certified here.
+
+**Result boundary:** the written combinatorial implication and exact
+conditional accounting are supplied. The complete quoted physical tariff
+is **not independently discharged**: it requires a fixed-number-of-tapes
+encoding and paid stack/candidate-list access, stable radix distribution,
+full-key movement, and the inherited coefficient/application/setup budgets.
+This is a precise implementation obligation, not a claim that the source's
+bound is false. No random-access dictionary operation in the verifier is
+used as evidence for that tariff.
+
+## Finite executable contract and observed evidence
+
+`verify.py` uses integer arithmetic and standard-library Python 3.12. It
+streams canonical addresses; it does not allocate a global value/matrix
+array. Counters retain only small fixture copy keys and output keys. It uses
+no project imports, search, census, huge p, numerical Gaussian coefficients,
+or generated external files. The independent oracle loops destinations
+first and tests absolute lifted half-open intervals directly; it does not
+reuse the source candidate lists, prefix code, DFS, or lift computation.
+
+Three fixed positive fixtures cover `(core counts; L,A,b)`:
+
+- `(2,3; 12,2,1)`: 2D, unequal periodic sides, several destinations and wrap.
+- `(2,2,2; 10,2,1)`: 3D corner with eight copies from one source, unary/deeper
+ branches, several faces, interior zero-copy sources, and wrap.
+- `(2,2; 10,2,0)`: zero bandwidth, genuinely empty emitted lists for interior
+ sources, and no wrap halo.
+
+Every fixture compares the full emitted key **Counters**, requires count one
+for every full key and returned key, and checks exact copied-input and
+discarded-output volume identities. Each admitted forest is checked for
+nonempty leaves and the internal-node bound; the aggregate bound is also
+checked. Direct destination membership is independent of source construction.
+The center check establishes zero emitted copies; the corner requires exactly
+2^g copies for b>0. The written algorithm, rather than a redundant inequality
+g>g*0, explains why zero-copy sources still need additive setup.
+
+Coordinate scans, prefix steps, face tests and candidate tests are **diagnostic
+loop counts** with internal consistency checks. Printed oracle membership-test
+counts are diagnostic too. These counters are not independent evidence of
+physical cost: they do not price tape movement, arithmetic, stack access,
+key rewrites or sorting. Exact membership, volume, output uniqueness and
+forest bounds must not be conflated with those diagnostic counters.
+
+The prior replay passed fourteen comparison/validation controls: omitted first
+lower face, duplicated input key, lost periodic wrap, and dropped inclusive
+lower endpoint on both positive-bandwidth fixtures; duplicate returned output
+on all three fixtures; negative, equal-to-A, and larger-than-A bandwidth.
+These retained controls mutate completed results or validate input domains;
+they do not by themselves exercise an erroneous source algorithm.
+
+The revised harness additionally runs three **algorithm-seam mutants** on each
+positive-bandwidth fixture, using the same source implementation rather than
+a duplicate algorithm:
+
+- omit the preceding neighbor-core choice when r= 2 for n in self.cores),
+ "at least two cores per periodic axis required",
+ )
+ require(
+ type(self.side) is int
+ and type(self.margin) is int
+ and self.margin > 0
+ and self.side > 4 * self.margin,
+ "require integer L > 4A > 0",
+ )
+ require(
+ type(self.bandwidth) is int and 0 <= self.bandwidth < self.margin,
+ "require 0 <= b < A",
+ )
+
+ def sources(self):
+ return product(*(range(n * self.side) for n in self.cores))
+
+
+def same_multiset(actual, expected):
+ require(actual == expected, "full emitted key multiset mismatch")
+ require(all(n == 1 for n in actual.values()), "duplicate input-copy key")
+
+
+def expect_rejection(label, operation):
+ try:
+ operation()
+ except Rejected:
+ return label
+ raise Rejected("failure control did not reject: " + label)
+
+
+def source_enumeration(grid, *, _mutation=None):
+ """One coordinate scan, prefix AND, then pruned DFS face forests.
+
+ The explicit stack (depth,next-choice) is the depth-first odometer.
+ Roots exist only for permitted faces; all their suffix factors are nonempty.
+ Keys include destination core, face axis/side, lifted local coordinate,
+ and canonical global source. No payload arrays are allocated.
+ _mutation changes one algorithm seam only for negative controls; the
+ destination oracle is unchanged and compares the complete returned keys.
+ """
+ grid.validate()
+ g, L, A, b = len(grid.cores), grid.side, grid.margin, grid.bandwidth
+ keys = Counter()
+ stats = Counter()
+ per_source = Counter()
+ for x in grid.sources():
+ stats["sources"] += 1
+ later, interior, faces = [], [], []
+ for i, (xi, n) in enumerate(zip(x, grid.cores)):
+ stats["coordinate_scans"] += 1
+ q, r = divmod(xi, L)
+ choices = [q]
+ if r < b and _mutation != "omit-neighbor-core":
+ choices.append((q - 1) % n)
+ if r >= L - b:
+ choices.append((q + 1) % n)
+ require(len(set(choices)) == len(choices) <= 2, "bad later choices")
+ later.append(tuple(choices))
+ interior_margin = A if _mutation == "strict-earlier-interior" else A - b
+ interior.append(q if interior_margin <= r < L - interior_margin else None)
+ axis_faces = [[], []]
+ S = n * L
+ for c in choices:
+ stats["candidate_tests"] += 1
+ t = (xi - c * L) % S
+ if t < A + b or (b > 0 and t >= S - b):
+ axis_faces[0].append(c)
+ lower = L - A - b + (_mutation == "open-upper-face-lower-endpoint")
+ if lower <= t < L + b:
+ axis_faces[1].append(c)
+ faces.append(axis_faces)
+ prefix = [True]
+ for c in interior:
+ stats["prefix_steps"] += 1
+ prefix.append(prefix[-1] and c is not None)
+ for f in range(g):
+ for side in range(2):
+ stats["face_tests"] += 1
+ if not prefix[f] or not faces[f][side]:
+ continue
+ factors = [tuple(faces[f][side])] + later[f + 1 :]
+ selected = [0] * len(factors)
+ # Each stack entry denotes an actual non-leaf node.
+ stack = [[0, 0]]
+ stats["forests"] += 1
+ stats["internal_nodes"] += 1
+ forest_nodes, forest_leaves = 1, 0
+ while stack:
+ depth, choice = stack[-1]
+ if choice == len(factors[depth]):
+ stack.pop()
+ continue
+ stack[-1][1] += 1
+ selected[depth] = factors[depth][choice]
+ if depth + 1 < len(factors):
+ stack.append([depth + 1, 0])
+ stats["internal_nodes"] += 1
+ forest_nodes += 1
+ continue
+ core = tuple(interior[:f]) + tuple(selected)
+ local = []
+ for xi, c, n in zip(x, core, grid.cores):
+ t = (xi - c * L) % (n * L)
+ local.append(t - n * L if b > 0 and t >= n * L - b else t)
+ key = (core, f, side, tuple(local), x)
+ keys[key] += 1
+ per_source[x] += 1
+ stats["copies"] += 1
+ forest_leaves += 1
+ require(forest_leaves > 0, "empty admitted forest")
+ require(
+ forest_nodes <= (g - f) * forest_leaves,
+ "internal-node versus leaf bound",
+ )
+ stats["empty_sources"] = stats["sources"] - len(per_source)
+ stats["max_copies_per_source"] = max(per_source.values(), default=0)
+ return keys, stats, per_source
+
+
+def destination_oracle(grid):
+ """Independent destination-first rectangle membership on integer lifts.
+
+ Does not call source candidate, prefix, offset or odometer code. For each
+ destination it directly intersects shifted absolute half-open intervals
+ with each canonical periodic source. Unique lifts follow from widths < S.
+ """
+ g, L, A, b = len(grid.cores), grid.side, grid.margin, grid.bandwidth
+ keys = Counter()
+ membership_tests = 0
+ for core in product(*(range(n) for n in grid.cores)):
+ for face in range(g):
+ for side in range(2):
+ intervals = []
+ for i, c in enumerate(core):
+ if i < face:
+ lo, hi = A, L - A
+ elif i == face:
+ lo, hi = (0, A) if side == 0 else (L - A, L)
+ else:
+ lo, hi = 0, L
+ intervals.append((c * L + lo - b, c * L + hi + b))
+ for x in grid.sources():
+ membership_tests += 1
+ local = []
+ for i, (lo, hi) in enumerate(intervals):
+ period = grid.cores[i] * L
+ lifts = [
+ x[i] + shift * period
+ for shift in (-1, 0, 1)
+ if lo <= x[i] + shift * period < hi
+ ]
+ require(len(lifts) <= 1, "ambiguous periodic lift")
+ if not lifts:
+ break
+ local.append(lifts[0] - core[i] * L)
+ if len(local) == g:
+ keys[(core, face, side, tuple(local), x)] += 1
+ return keys, membership_tests
+
+
+def output_partition(grid):
+ """Enumerate unexpanded outputs and independently classify each hole."""
+ g, L, A = len(grid.cores), grid.side, grid.margin
+ returned = Counter()
+ for core in product(*(range(n) for n in grid.cores)):
+ for f in range(g):
+ for side in range(2):
+ ranges = []
+ for i in range(g):
+ if i < f:
+ ranges.append(range(A, L - A))
+ elif i == f:
+ ranges.append(range(A) if side == 0 else range(L - A, L))
+ else:
+ ranges.append(range(L))
+ for local in product(*ranges):
+ returned[tuple(c * L + r for c, r in zip(core, local))] += 1
+ expected = Counter()
+ for x in grid.sources():
+ if any(not (A <= xi % L < L - A) for xi in x):
+ expected[x] = 1
+ require(returned == expected, "returned hole multiset mismatch")
+ require(all(n == 1 for n in returned.values()), "duplicate returned output")
+ require(
+ len(returned) == prod(grid.cores) * (L**g - (L - 2 * A) ** g),
+ "exact discarded volume",
+ )
+ return returned
+
+
+def bind_live_sources():
+ package = Path(__file__).resolve().parent
+ root = package.parents[1]
+ sources = json.loads((package / "SOURCES.json").read_text())
+ manifest = json.loads((package / "VERIFY.json").read_text())
+ count = 0
+ for row in sources["files"]:
+ if row["usage"] == "input":
+ require(row["path"] in manifest["inputs"], "undeclared live input")
+ require(
+ sha256((root / row["path"]).read_bytes()).hexdigest() == row["sha256"],
+ "live source hash mismatch: " + row["path"],
+ )
+ count += 1
+ require(count == 6, "unexpected live source count")
+ return count
+
+
+def main():
+ live = bind_live_sources()
+ controls = []
+ fixtures = (
+ ("two_dimensional_wrap", Grid((2, 3), 12, 2, 1)),
+ ("three_dimensional_corner", Grid((2, 2, 2), 10, 2, 1)),
+ ("zero_bandwidth", Grid((2, 2), 10, 2, 0)),
+ )
+ for name, grid in fixtures:
+ actual, stats, per_source = source_enumeration(grid)
+ expected, tests = destination_oracle(grid)
+ same_multiset(actual, expected)
+ if grid.bandwidth:
+ for mutation in (
+ "omit-neighbor-core",
+ "strict-earlier-interior",
+ "open-upper-face-lower-endpoint",
+ ):
+ # Run the real source algorithm with one test-only seam changed.
+ # An internal exception is a failure, not an oracle rejection.
+ mutated, _, _ = source_enumeration(grid, _mutation=mutation)
+ controls.append(
+ expect_rejection(
+ name + ":algorithm:" + mutation,
+ lambda mutated=mutated, expected=expected: same_multiset(
+ mutated, expected
+ ),
+ )
+ )
+ returned = output_partition(grid)
+ g, L, A, b = len(grid.cores), grid.side, grid.margin, grid.bandwidth
+ volume = prod(grid.cores) * sum(
+ 2 * (L - 2 * A + 2 * b) ** f * (A + 2 * b) * (L + 2 * b) ** (g - f - 1)
+ for f in range(g)
+ )
+ require(stats["copies"] == volume, "exact copied-volume identity")
+ # Diagnostic loop-accounting consistency, not physical-cost evidence.
+ require(stats["coordinate_scans"] == g * stats["sources"], "dense scan count")
+ require(stats["prefix_steps"] == g * stats["sources"], "prefix setup count")
+ require(stats["face_tests"] == 2 * g * stats["sources"], "face setup count")
+ require(
+ stats["candidate_tests"] <= 2 * g * stats["sources"], "candidate scan bound"
+ )
+ require(stats["internal_nodes"] <= g * stats["copies"], "forest total bound")
+ center = (L // 2,) * g
+ require(
+ per_source[center] == 0 and stats["empty_sources"] > 0,
+ "missing empty-output source",
+ )
+ corner = (0,) * g
+ require(per_source[corner] == (2**g if b else 1), "rare corner copy count")
+ if b:
+ require(
+ any(any(t < 0 for t in key[3]) for key in actual),
+ "missing wrap fixture",
+ )
+ require(stats["max_copies_per_source"] >= 2**g, "missing many-copy fixture")
+ omitted = Counter(
+ {k: v for k, v in actual.items() if not (k[1] == 0 and k[2] == 0)}
+ )
+ controls.append(
+ expect_rejection(
+ name + ":omitted-face",
+ lambda omitted=omitted, expected=expected: same_multiset(
+ omitted, expected
+ ),
+ )
+ )
+ duplicate = actual.copy()
+ duplicate[next(iter(duplicate))] += 1
+ controls.append(
+ expect_rejection(
+ name + ":duplicate",
+ lambda duplicate=duplicate, expected=expected: same_multiset(
+ duplicate, expected
+ ),
+ )
+ )
+ no_wrap = Counter(
+ {k: v for k, v in actual.items() if all(t >= 0 for t in k[3])}
+ )
+ controls.append(
+ expect_rejection(
+ name + ":lost-wrap",
+ lambda no_wrap=no_wrap, expected=expected: same_multiset(
+ no_wrap, expected
+ ),
+ )
+ )
+ boundary = actual.copy()
+ boundary_key = next(k for k in boundary if k[3][k[1]] == -b and k[2] == 0)
+ del boundary[boundary_key]
+ controls.append(
+ expect_rejection(
+ name + ":open-lower-endpoint",
+ lambda boundary=boundary, expected=expected: same_multiset(
+ boundary, expected
+ ),
+ )
+ )
+ duplicate_return = returned.copy()
+ duplicate_return[next(iter(duplicate_return))] += 1
+ controls.append(
+ expect_rejection(
+ name + ":duplicate-return",
+ lambda duplicate_return=duplicate_return: require(
+ all(n == 1 for n in duplicate_return.values()),
+ "duplicate returned output",
+ ),
+ )
+ )
+ print(
+ json.dumps(
+ {
+ "fixture": name,
+ **stats,
+ "oracle_membership_tests": tests,
+ "returned_outputs": len(returned),
+ },
+ sort_keys=True,
+ )
+ )
+ for b in (-1, 2, 3):
+ controls.append(
+ expect_rejection(
+ "invalid-bandwidth:" + str(b),
+ lambda b=b: Grid((2, 2), 10, 2, b).validate(),
+ )
+ )
+ print(
+ "PASS_HALO_COPY_ENUMERATION "
+ + json.dumps(
+ {
+ "fixtures": len(fixtures),
+ "controls": controls,
+ "live_sources": live,
+ "scope": "finite_exact_keys_and_counts; written_combinatorial_proof_separate; physical_tape_cost_open",
+ "no_new_kappa": True,
+ },
+ sort_keys=True,
+ )
+ )
+
+
+if __name__ == "__main__":
+ main()