# Reproducing and auditing this K4 campaign

The saved results distinguish exact bounded exclusions, necessary-condition survivors, exact structural witnesses, and resource-limited unknowns. Reproducing a result does not establish the intended K4 solution. Search execution is finished. Use the preserved terminal result files and archived dependencies for stable comparisons; historical capped records remain unchanged.

## Environment

Python code uses the standard library; the optional compiled cover backends also require a C++17 compiler. No paid API, network, or remote compute is needed. The tested interpreter is Python 3.11 from Andrew's Anaconda installation. Set these paths once:

```sh
export K4_ROOT='/Users/andrewchan/Documents/Codex/2026-09-13/i-x20'
export K4_PY='/Users/andrewchan/anaconda3/bin/python3'
export PYTHONDONTWRITEBYTECODE=1
cd "$K4_ROOT"
```

For the compiled periodic backend, build in the normal workspace before its synthetic controls:

```sh
"$K4_PY" outputs/columnar_cover_compiled.py
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest -v test_columnar_cover_compiled
```

The separate autokey backend uses the same build arrangement:

```sh
"$K4_PY" outputs/autokey_cover_compiled.py
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest -v test_autokey_cover_compiled
```

The independent-column-reversal backend has its own binary and protocol. Do not substitute the top-down binary:

```sh
"$K4_PY" outputs/reversible_columnar_cover_compiled.py
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest -v \
  test_reversible_columnar_compiled test_run_reversible_columnar_cover
```

Fixed mixed-axis models reuse the numeric periodic binary through a separately verified translation. Their tests check original message letters and model boundaries:

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest -v \
  test_mixed_axis_columnar test_mixed_axis_independent \
  test_run_mixed_axis_columnar test_mixed_axis_scope_guards \
  test_summarize_mixed_axis test_summarize_reversible_coverage test_evidence_discovery
```

The tested compiler is `/usr/bin/clang++`, Apple clang 21, with `-std=c++17 -O3 -DNDEBUG`. The wrapper checks source and binary hashes against `work/columnar_cover_kernel_build.json` and fails closed if stale. Executed binary bytes are retained by hash under `outputs/source_versions/`. A different compiler may produce different binary bytes even when behavior agrees. The wrapper derives its build directory as a sibling `work/` of its source directory: a replay prepared in a nested directory therefore does not build wholly inside that replay directory. Inspect that path before building an isolated replay; the preparation tool itself does not compile or run a search.

Run search replays serially unless the campaign coordinator confirms an available CPU slot. Original campaign limits permit at most two search workers in total. Read current load/memory before additional computation; the memo-entry limits are not hard RSS limits.

## Tests without new K4 search

These execute historical known-answer checks, synthetic ciphers, small brute-force comparisons, planted controls, and mocked runner integration:

```sh
"$K4_PY" outputs/k4.py
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest -v \
  test_historical test_transposition test_columnar_dp test_columnar_csp \
  test_partition_runner test_autokey_columnar test_autokey_exact \
  test_autokey_partition test_ciphertext_autokey test_columnar_cover \
  test_autokey_cover test_resume_frontier test_candidate_artifacts \
  test_model_scope test_artifact_audit test_reversible_columnar_dp \
  test_reversible_columnar_cover test_run_cover_cells
```

The current tests validate current code, not every archived implementation. Some 97-character autokey/forward-check controls fix the first 16 columns to keep them bounded; they verify equations and witness reconstruction without claiming unrestricted planted-key recovery.

The 97-character reversible-cover controls use stronger clue coverage than K4, leaving a blank column to exercise exact filling. They validate reconstruction and orientation handling, not the runtime of a 24-clue K4 search. Separate tiny exhaustive controls compare every relevant order, direction and key within their small bounds. The reversible DP is restricted to periods 1–3 to contain bitset memory; the sparse interval-cover solver handles longer periods without enumerating the full key space.

The following optional test additionally rechecks the already recorded direct-alignment baseline against an independent oracle. It repeats bounded K4 arithmetic, not a new cipher-family search:

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest -v test_independent
```

Do not use `outputs/k4.py baseline` for a read-only check: that command writes baseline artifacts and appends the ledger.

## Read-only certificates and frontier bookkeeping

```sh
"$K4_PY" outputs/pair_obstruction_verify.py
"$K4_PY" outputs/verify_columnar_local_obstruction.py
```

These recompute small local impossibility certificates. They do not enumerate keys or column orders. Their narrow alphabet, sign, stage-order and period assumptions matter.

Audit the saved inherited proof chains, including source hashes, model identities and prefix coverage:

```sh
"$K4_PY" outputs/verify_evidence_chains.py --self-test
"$K4_PY" outputs/verify_evidence_chains.py
```

This validates evidence bookkeeping, not the arithmetic of every raw solver leaf. Missing historical manifest hashes remain explicit warnings.

Independently check every stored full periodic/autokey witness, if any:

```sh
"$K4_PY" outputs/verify_candidate_artifacts.py
```

This checker imports no campaign solver or existing witness verifier. It binds key/primer length and stage conventions to the declared model, splits and scatters ciphertext columns, compares the reported plaintext with independent decryption, and re-encrypts the complete text. It checks canonical input and clue literals plus declared free-variable annotations. A successful result is explicitly structural only; it does not certify natural language, historical intent, independently motivated keys or a statistical null comparison. `candidate_validation_review.md` records the remaining gates.

An independently reversible-column witness must explicitly name that orientation model and supply a source-column-indexed vector of +1 (top-down) or −1 (bottom-up) directions. The checker rejects that vector under an ordinary top-down model. Top-down coverage summaries and continuation runners do not silently consume reversible-column records; `test_model_scope.py` checks both summary separation and rejection of inherited evidence from a different orientation model.

Check all finished partition-result frontiers without modifying summaries:

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" - <<'PY'
import json
from pathlib import Path
from collections import Counter
from verify_partition_coverage import verify
root = Path('outputs')
for path in sorted(root.glob('*results.json')):
    data = json.loads(path.read_text())
    if not data.get('finished_utc'):
        continue
    cells = data.get('cells', [])
    if any('branches' in c for c in cells):
        count = verify(data)
        print(path.name, 'complete exclusion frontiers:', count,
              'cell states:', dict(Counter(c['status'] for c in cells)))
PY
```

This checks valid, disjoint exhausted prefixes and factorial coverage of every column order for cells marked infeasible. **It does not independently prove the cryptanalytic truth of each leaf.** Unknown/pending prefixes are not exclusions. Earlier unknown cells may be superseded by later complete results for the identical model; do not sum retries as new coverage.

The Bean-extension artifact can be checked literally without rerunning its generator or overwriting it:

```sh
"$K4_PY" - <<'PY'
import json
from pathlib import Path
root = Path('outputs')
m = json.loads((root/'manifest.json').read_text())
w = json.loads((root/'bean_extension_counterexample.json').read_text())
p, gather = w['arbitrary_completion_plaintext'], w['gather']
assert len(p) == 97 and sorted(gather) == list(range(97))
clues = {e['start_zero']+i: ch for e in m['clues'] for i,ch in enumerate(e['plain'])}
assert all(p[i] == ch for i,ch in clues.items())
forward = ['']*97
for i,destination in enumerate(gather):
    forward[destination] = chr((ord(p[i])-65+i%2)%26+65)
assert ''.join(forward) == m['ciphertext']
print('All97 forward characters and24 clues verified; fitted counterexample, not a solution')
PY
```

The stronger independent autokey-gate verifier re-evaluates all 72 necessary-condition cells and writes a verification report. Run it only in an isolated directory, because its main routine overwrites its local verification file:

```sh
"$K4_PY" - <<'PY'
from pathlib import Path
import shutil
root = Path('outputs')
dest = Path('work/gate-verification')
assert not dest.exists(), 'Choose a new directory; do not overwrite prior work'
dest.mkdir(parents=True)
for name in ('verify_autokey_gate.py','manifest.json','autokey_gate_results.json'):
    shutil.copy2(root/name, dest/name)
PY
"$K4_PY" work/gate-verification/verify_autokey_gate.py
```

That is a bounded independent replication of saved gate evidence, not new search coverage. Its positive maps remain necessary-condition survivors.

## Safe historical-source replay preparation

`prepare_replay.py` **prepares files only and never launches a search**. It restores every recorded dependency under its original filename from hash-matched bytes in `source_versions/` or a still-matching current file. It refuses missing recorded bytes and nonempty destinations. Destinations must be children of this task's `work/` directory.

Unrecorded local imports and the runtime manifest are copied from current files and explicitly labeled untracked in `_replay_provenance.json`. They are not silently certified as historical bytes. `_original_result.json` preserves the comparison result under a name that will not collide with runner output.

Most original preregistrations eventually expire. Without an explicit refresh, runners may immediately stop with no new cells. `--refresh-deadline-hours` changes only copied preregistration search deadlines and records old/new values and hashes. It does not extend per-cell/node/memo caps, change cipher scope, alter originals, or imply bit-identical historical timing. Copied manifest scheduling metadata may remain historical; the copied preregistration controls these runners' execution deadline.

Example: prepare the completed short-key DP experiment in a new directory:

```sh
"$K4_PY" outputs/prepare_replay.py \
  --result outputs/columnar_dp_results.json \
  --dest work/replay-dp \
  --refresh-deadline-hours 1
```

Inspect `work/replay-dp/_replay_provenance.json` before choosing to execute. The separate command below performs the actual historical-code rerun and writes only inside that isolated directory:

```sh
nice -n 10 "$K4_PY" work/replay-dp/run_columnar_dp.py
```

Example: prepare the historical lag-8 exact-autokey root experiment:

```sh
"$K4_PY" outputs/prepare_replay.py \
  --result outputs/autokey_exact_lag8_results.json \
  --dest work/replay-autokey-lag8 \
  --refresh-deadline-hours 1
```

After inspecting provenance, optionally execute:

```sh
nice -n 10 "$K4_PY" work/replay-autokey-lag8/run_autokey_exact.py \
  --spec autokey_exact_lag8_preregistration.json \
  --output replay_results.json
```

The historical root run was resource-limited; reproducing that run is different from reproducing a later optimized partition proof. Resource-limit outcomes and wall times can change with machine load. Completed mathematical exclusions should agree for identical inputs/model; unknowns may differ.

For partition replays, prepare the desired partition result in another fresh directory, then invoke its restored `run_columnar_partition.py` or `run_autokey_partition.py` with `--spec ORIGINAL_PREREGISTRATION_NAME --output replay_results.json`. Do not mix restored old solvers with current runners. Existing runners refuse nonempty checkpoints; these examples start new isolated runs and **do not resume saved unfinished frontiers**. Never delete an original result to bypass that guard.

The newer `resume_frontier.py` provides a separate continuation path. Its preregistration names a terminal parent result and only the indices of unresolved cells. It retains every completed negative leaf by a hash-bound reference, searches only unfinished prefixes, and checks disjoint full coverage at each checkpoint. A terminal root result without a saved internal frontier can be partitioned into first-column subtrees, but its internal progress cannot be recovered: counters are not subtree certificates. This avoids rerunning the root call while honestly retaining all uncertified work. New result paths are mandatory, and completed model cells are rejected as continuation inputs.

## Dependency audit and remaining limits

Run the current read-only dependency and archive audit:

```sh
"$K4_PY" outputs/audit_artifacts.py
```

It checks declared filename/hash pairs in saved JSON and the ledger, resolves historical bytes from snapshots or matching current files, and checks archive integrity and JSON parseability. It does not infer missing historical declarations or prove solver mathematics. `test_artifact_audit.py` exercises corrupted snapshots, modified current sources and malformed ledger input. The earlier audit below describes the provenance gaps discovered before the newer complete-dependency runners were introduced.

At the audit, all dependency hashes declared by the 16 inspected search-result JSON files were recoverable from an archived version or a current file whose bytes matched the recorded hash. No declared source bytes were missing. Some preregistrations and runners exist only as matching current files rather than duplicated snapshots; preserve them before future edits. SHA-based restoration checks the actual `.py`/`.json` extension.

| Result family | Provenance gap |
|---|---|
| `columnar_csp_results.json` | Runner imports `columnar_dp.py` for witness verification but did not record that dependency. No witnesses occurred, so this omission does not affect those negative searches; replay still labels the supplied module untracked. |
| DP, CSP, periodic partition, autokey gate, exact-autokey and autokey-partition results | Most record `k4.py` but omit its runtime `manifest.json` hash. |
| `columnar_width_extension_results.json` and `columnar_width_p4_5_results.json` | Declared local dependency closure is complete, including manifest and, when used, pair certificates/specification/verifier. All declared bytes have snapshots. |

The ciphertext and clue positions/letters were frozen semantically during the campaign, while manifest deadlines, budget and status metadata changed. The old full-manifest hashes were not recorded for many runs. **No historical manifest hash can be reconstructed by assertion.** The replay utility records the copied current manifest hash and ciphertext/clue identity, flags the historical gap, and leaves the original evidence untouched.

Import auditing is static and limited to this package's local Python imports plus its known `k4.py -> manifest.json` data dependency. It is not a general Python sandbox or a proof of arbitrary dynamic dependency closure. Python/interpreter version, OS and resource-load metadata were not uniformly captured by early runners. Timing and capped search paths are therefore not guaranteed to match exactly.

Preparation validation performed for this guide: one DP result and one historical autokey result were restored into temporary `work/` directories with explicit deadline refresh; all prepared hashes and deadline-only semantic changes were checked; historical modules imported successfully without calling a search; no ledger was written. Both disposable probes were removed. Active solvers, runners, source inputs and original results were not modified by this audit.

## Frozen structural witness

The first full fit is cell 8 of `columnar_width31_p5_6_results.json`. It is arithmetic evidence of feasibility, with incoherent non-clue text and no independent method derivation. Recheck it without searching or changing the witness:

```sh
"$K4_PY" outputs/verify_candidate_artifacts.py outputs/columnar_width31_p5_6_results.json
"$K4_PY" outputs/audit_width31_structural_witness.py
```

The second command imports no campaign solver/verifier and uses its own fixed ciphertext/clue literals. It verifies the recorded result hash, recomputes literal encryption/decryption, and refreshes `width31_structural_witness_audit.json`; it does not search alternate keys/orders. The original raw result is also retained under its content hash in `source_versions/`. The seven cells not reached after the first witness remain untested.

Current family summaries can be refreshed without cryptanalytic search:

```sh
"$K4_PY" outputs/summarize_coverage.py
"$K4_PY" outputs/summarize_autokey.py
"$K4_PY" outputs/summarize_reversible_coverage.py
"$K4_PY" outputs/summarize_mixed_axis.py
```

Mixed-axis roots have a separate identity and verifier. Default same-axis evidence discovery reports skipped mixed files; explicitly supplying a mixed file to that verifier rejects it. The mixed summary distinguishes declared untested cells from capped cells and completed roots. None of these summaries certify semantic acceptance or make overlapping model counts disjoint.

## Geometry correction

`width31_geometry_equivalence_correction.md` supersedes the earlier claim that the initial-short-row physical layout needs a separate all-order search. The label rotation preserves all source-position lists under the stated continuous key convention. Verify this with synthetic grids only:

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest test_width31_geometry_equivalence
```

This does not transfer unmodified fixed column labels, externally anchored key phase, row-reset schedules or layouts with different internal holes. No duplicate K4 search is needed for the equivalent layout.

Descriptive preregistration errata are recorded in `preregistration_corrections.json`. The original hashed files remain unchanged. In the base-2/3 progressive batch, a copied scope sentence retained “base1”; the original executable cells, purpose, admission and all 32 executed results correctly specify bases 2 and 3. This does not add a search or change any model result.

## Progressive and column-reset families

These use the existing numeric periodic binary with separately declared domains or input transformations. Their identities and verifiers remain separate from ordinary periodic, mixed-axis and autokey evidence. Build `columnar_cover_compiled.py` as above, then run synthetic controls only:

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest \
  test_progressive_columnar test_run_progressive_columnar test_summarize_progressive \
  test_reset_columnar_compiled test_reset_independent test_run_reset_columnar \
  test_reset_scope test_model_family_scope
"$K4_PY" outputs/summarize_progressive.py
"$K4_PY" outputs/summarize_reset.py
```

Progressive keys use `K[x % base_period] + step * floor(x / base_period)` modulo 26, where x is the declared source or destination index. The 48 executed width-18 configurations cover bases 1–3 and steps ±1, both alphabets/signs/stages. Base length 1 does not make the stages commute.

Column-reset keys restart at the beginning of each emitted top-down column. Their residue is the source row modulo reset length, independent of the block's destination start. Four width-18, length-4 roots were tested, one per alphabet/sign pair. `reset_length_transfer_proof.md` derives all-positive-length exclusions from completed length-4 negatives using the canonical clue-row partition; the summary reports four executions and the derived scope separately. It does not count infinitely many tests or equate full plaintext families.

Replaying these searches requires a fresh prepared directory and result filename, preserving the original preregistration, source snapshots and binary metadata. The dedicated entry points are `run_progressive_columnar.py` and `run_reset_columnar.py`, each with `--spec SPEC_NAME --output NEW_RESULT_NAME`. Existing result paths are rejected. Read the prepared specification's deadline and scope before running; synthetic verification and summaries above perform no new K4 search.

## Inverse columns and affine offsets

Inverse geometry fills physical columns with consecutive plaintext chunks and reads rows. It is distinct from ordinary all-column-order encryption. The period-1 pilot hit a node cap; its original result remains `unknown`. A later necessary-placement certificate independently excludes that model because index23 has no valid covering block. The other three alphabet/sign cases have the same kind of independently verified obstruction. The first gate's on-disk registration was post-execution and records its missing timing metadata; the remaining three were preregistered before evaluation.

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest \
  test_inverse_columnar_compiled test_inverse_independent \
  test_run_inverse_columnar test_inverse_scope test_inverse_placement_gates
"$K4_PY" outputs/verify_inverse_missing_position.py
"$K4_PY" outputs/verify_inverse_remaining_points.py
"$K4_PY" outputs/summarize_inverse.py
```

The point verifiers use fixed or hash-bound original inputs and independently check every physical column/start capable of covering the cited missing position. They do not rerun the capped interval solver. A necessary-condition survivor would establish neither a full fit nor a solution.

Affine period-1 models apply a fixed invertible multiplier and one additive offset before ordinary columnar transposition. The 20 newly executed models are the ten units other than ±1 in each of AZ/KA. Multipliers ±1 reuse the existing signed-additive coverage and were not rerun.

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest \
  test_affine_columnar_compiled test_affine_independent \
  test_run_affine_columnar test_affine_scope test_recent_coverage_summaries
"$K4_PY" outputs/summarize_affine.py
```

The dedicated affine verifier checks the original numeric multiplier, modular inverse, full ciphertext, clues and route; changing an alphabet's coordinate system is not silently treated as an existing same-axis proof. Neither family currently admits a higher-period full solver through these wrappers.

## Local inverse-period transfer certificates

`run_inverse_local_period_gates.py` is a necessary-condition checker, not a full cipher solver. Within a candidate inverse column block, it enforces key equalities at local row residues. Its q2 and q3 batches each yielded four missing-position certificates; the q4 AZ+ pilot was only a necessary survivor.

```sh
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest \
  test_inverse_local_period_gates test_inverse_local_period_independent
"$K4_PY" outputs/verify_inverse_local_points.py
"$K4_PY" outputs/summarize_inverse_local_period.py
```

The independent point verifier uses original plaintext-source residues, checks every block covering the selected point and records explicit contradictory clue pairs. `inverse_local_rowperiod_transfer_review.md` proves that before-stage period p has local period q=p, while after-stage period p has q=p/gcd(p,18). Together with the existing q1 certificates, the negative checks exclude before periods1,2,3 and after periods1,2,3,4,6,9,12,18,27,36,54 in each alphabet/sign convention. These are overlapping derived scopes, not additional executions. The q4 survivor excludes nothing and supplies no plaintext candidate.

## Full inverse-before period4 closure

A separate exact solver closes the four inverse-before period4 alphabet/sign roots. It enforces shared global key residues `(source_block_start + row) % 4` and a complete tiling. Its kernel adds position-support rejection and position/column branching, requires all columns to remain potentially constrained, and accepts no prefix continuation. It does not replace the older period1 kernel or turn local-gate survival into feasibility.

```sh
nice -n 10 "$K4_PY" outputs/inverse_period4_compiled.py
PYTHONPATH="$K4_ROOT/outputs" "$K4_PY" -m unittest \
  test_inverse_period4_compiled test_inverse_period4_independent test_run_inverse_period4
"$K4_PY" outputs/summarize_inverse_period4.py
```

The new build uses `inverse_cover_kernel.cpp` and `work/inverse_cover_kernel_build.json`; exact executed binary bytes are archived under their hash. The runner is `run_inverse_period4.py`. Original results and preregistrations are retained under `inverse_period4_*`. The two batches exhausted the four declared roots without a cap or witness. This excludes before period4 only; after-stage periods whose local row period is4 do not inherit these global-key results.
