# Rope Tomography Lab

Version 0.14.0 / Theory 1.39 adds a standalone KT predictive-likelihood
e-process for a declared binary first-order Markov model of nonzero residual
signs. With a fixed 90%-persistence null, the written martingale proof gives a
1% anytime crossing bound. Fresh 400-look synthetic validation crossed on
39/5,000 declared-null histories, versus 4,134/5,000 for the old iid-sign rule
whose conditional-balance assumption is false there. The new process detected
4,629/5,000 chains at 97% persistence, 4,999/5,000 at 75%, and 5,000/5,000
balanced iid chains. A separate replay reproduced 24,000,000 decisions; all
110 tests pass. See `Reality_Revision_1.39.md` and Appendix AN.

The transition matrix must be fixed before scoring and correct conditionally at
every transition in nonzero-sign event time. The engine is not valid for a
same-data estimate, changing persistence, higher-order dependence, or merely
marginal balance. It ignores magnitudes and is neither distribution-free nor a
physical-mechanism identifier.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_markov_sign_validation.py --output results-markov-sign-validation
py -3.12 run_markov_sign_validation.py --protocol markov_sign_validation_protocol.json --output results-markov-sign-validation-rerun
py -3.12 audit_markov_sign_validation.py --output results-markov-sign-validation-rerun
```

Minimal API: construct
`MarkovSignEProcess(null_transition, alpha=0.01, pseudocount=0.5)` once and
call `update(fresh_scalar_residual)`. A new object does not renew a budget.

## Historical 0.13.0 release notes

Version 0.13.0 / Theory 1.26 adds a standalone conditional-sign e-process. It
has a 1% anytime guarantee when the selected residual sign has conditional
expectation zero. It makes no Gaussian, finite-moment, or magnitude assumption,
but it is not a mean, scale, dependence, or omnibus test. See
`Reality_Revision_1.26.md` and Appendix AA.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_sign_validation.py --output results-sign-validation
py -3.12 run_sign_validation.py --protocol sign_validation_protocol.json --output results-sign-validation-rerun
py -3.12 audit_sign_validation.py --output results-sign-validation-rerun
```

At a frozen 1% threshold and 200 looks, the sign process crossed on 37/5,000
Student-t3 null paths and 33/5,000 Cauchy null paths. It detected 4,989/5,000
positive and 4,992/5,000 negative 0.35-shifted Student-t3 paths. Exact doubling
of every Student-t residual left all sign decisions unchanged.

The failure boundaries are explicit. A mean-zero asymmetric law crossed
5,000/5,000 times, proving mean zero is insufficient. A marginally balanced
sign chain with 90% persistence crossed 3,772/5,000 times, proving the null must
be conditional rather than marginal. Alternating shifts and one large shock
were mostly invisible because magnitudes are discarded.

All 101 tests pass. An independent implementation regenerated the scenarios
and reproduced 22,000,000 decision states. The sign engine is selectable and
standalone; it does not replace the released Gaussian engine or share that
engine's error budget. These are written mathematics and finite synthetic
evidence, not measured physical evidence.

Minimal API: construct
`ConditionalSignEProcess(catalogue, directions, rho=0.30, alpha=0.01)` once and
call `update(experiment_index, fresh_observation)`. A new object does not renew
an investigation-wide budget.

## Historical 0.12.0 release notes

Version 0.12.0 / Theory 1.25 completed the fresh paired comparison of the
released 0.30/0.25 allocation with the 0.45/0.10 candidate. The candidate
improved noisy-shock detection by 1.935 percentage points but reduced persistent
mean detection by 5.165 points, failing the frozen two-point loss guard. The
released default was retained. All 89 tests passed, and the independent replay
matched 72,000,000 decisions. See `Reality_Revision_1.25.md` and Appendix Z.

## Historical 0.11.0 release notes

Version 0.11.0 / Theory 1.24 expanded the frozen allocation-training grid beyond
both active v1.23 boundaries without reading the sealed v1.22 validation data or
changing the detector. Across 64 new training seeds, the released cell won
0 times in the 108-cell grid, and a separate 20,000-history-per-target reference
selected 0.45 / 0.10. All 85 tests passed; the independent replay matched
36,288,000 decisions. See `Reality_Revision_1.24.md` and Appendix Y.

## Historical 0.10.0 release notes

Version 0.10.0 / Theory 1.23 added a training-selection stability study on the
original grid. Across 64 independent training seeds, the released allocation
won 49 times, but it occupied both active grid boundaries. A separate
80,000-history synthetic reference selected the same cell. All 81 tests passed,
and an independent replay matched 10,080,000 decisions. See
`Reality_Revision_1.23.md` and Appendix X.

## Historical 0.9.0 release notes

Version 0.9.0 / Theory 1.22 added a frozen three-component adequacy rule. The
known-covariance mean/variance mixture receives 0.7% and a separately budgeted
point gate receives 0.3%. Under its declared conditional Gaussian null, an
event-level union bound controls total anytime false rejection at 1%.

On held-out synthetic paths it detected 1,811/2,000 constant-mean errors,
1,781/2,000 high-scale errors, 1,689/2,000 low-scale errors, and 1,621/2,000
noisy 6-sigma shocks. Unit-variance Student-t3 noise caused 1,508/2,000
rejections, preserving the distributional counterexample. All 76 tests passed,
and an independent replay matched 18,000,000 decisions. See
`Reality_Revision_1.22.md` and Appendix W.

## Historical 0.8.0 release notes

Version 0.8.0 / Theory 1.21 added a separately selectable common-filtration
Gaussian mean-plus-variance e-process. A fixed 50/50 mixture receives one total
1% threshold. Its known-covariance null is stricter than the scale-invariant
mean assumption in the existing mean-plus-point rule. See
`Reality_Revision_1.21.md` and Appendix V.

On paired fresh synthetic histories, the new rule detected 1,807/2,000
targeted 1.25-scale paths versus 140/2,000 for the existing rule, and
1,878/2,000 targeted mean-shift paths versus 1,744/2,000. The isolated exact
6-sigma counterexample went the other way: 2,000/2,000 versus 197/2,000. All
68 tests passed, and an independent scalar audit reproduced 24,000,000
decisions.

## Historical 0.7.0 release notes

Version 0.7.0 / Theory 1.20 adds a standalone cumulative Gaussian covariance-
scale e-process. It compares a fixed candidate against prespecified 1.25-times
and 0.8-times residual-scale corrections at a 0.5% anytime threshold. Its
likelihood-ratio guarantee requires the declared conditional Gaussian mean and
covariance; crossing supports a predictive correction, not a unique mechanism.
See `Reality_Revision_1.20.md` and Appendix U.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_variance_validation.py
py -3.12 run_variance_validation.py --output results-variance-rerun
py -3.12 audit_variance_validation.py --output results-variance-rerun
```

On fresh 200-look synthetic data, the variance process detected 1,774/2,000
targeted 1.25-scale histories versus 125/2,000 for the alpha-spending point
gate at the same budget. It detected 1,669/2,000 targeted 0.8-scale histories
versus zero for that upper-tail gate. The Gaussian null produced 4/2,000
crossings for each detector on different histories; the written martingale
proof, not this finite count, gives the guarantee.

The failures are retained: only 251/2,000 smaller 1.10-scale paths crossed, and
1,047/2,000 variance-one Student-t3 paths crossed because Gaussianity was
false. A mean error also sometimes triggers squared-residual evidence. All 59
tests pass, and an independent scalar audit reproduced 5,600,000 decisions.
The v0.6.0 joint rule is not changed until a fresh joint comparison tests the
tradeoff against isolated shocks.

Minimal API: construct
`GaussianVarianceEProcess(catalogue, variance_factors, weights, alpha)` once
and call `update(experiment_index, fresh_observation)`. A new object does not
renew a budget. The factors multiply the full declared covariance.

## Historical 0.6.0 release notes

Version 0.6.0 / Theory 1.19 combines the cumulative mean check and the
point-residual check under one total 1% anytime false-rejection budget. It gives
each component 0.5% and uses an event-level union bound. It does not average the
components into one claimed e-process because their established guarantees use
different filtrations. See `Reality_Revision_1.19.md` and Appendix T.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_joint_validation.py
py -3.12 run_joint_validation.py --output results-joint-rerun
py -3.12 audit_joint_validation.py --output results-joint-rerun
```

In 2,000 frozen 200-look synthetic histories, the shared rule rejected 25 null
histories, 1,714 persistent mean-shift histories, 1,927 doubled-scale histories,
and 1,997 histories with both errors. Giving both components a full 1% and ORing
them rejected 45 null histories and has no 1% guarantee from the component
bounds. The observed 25/2,000 is finite sampling, not the proof of the bound.

Counterexamples are retained. Only 141/2,000 moderate 1.25-scale histories and
31/2,000 alternating-shift histories were detected. Scaled Student-t3 noise,
which has unit variance but violates Gaussianity, triggered 1,049/2,000
rejections. All 50 tests pass, and an independent scalar audit reproduced
11,200,000 decisions.

Minimal API: construct
`JointMeanPointAdequacy(catalogue, directions, alpha, mean_fraction, c)` once
and call `update(experiment_index, fresh_observation)`. The default allocation
is 0.5/0.5. A new object does not renew an investigation-wide budget.

## Historical 0.5.0 release notes

Version 0.5.0 / Theory 1.18 adds a scale-invariant Gaussian mean e-process for
one fixed unknown positive residual variance. Its 1% anytime guarantee requires
iid Gaussian projected residuals and scale-invariant stopping information; it
does not permit arbitrary raw-magnitude stopping and is not distribution-free.
See `Reality_Revision_1.18.md` and Appendix S.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_unknown_variance_validation.py
py -3.12 run_unknown_variance_validation.py --output results-unknown-variance-rerun
py -3.12 audit_unknown_variance_validation.py --output results-unknown-variance-rerun
```

In the frozen synthetic validation, exact doubling of all Gaussian residuals
left every new decision unchanged: 15/2,000 null histories rejected at either
scale. The v1.17 known-scale comparator rejected 12/2,000 at unit scale and
848/2,000 after doubling, where its variance assumption is false. For paired
constant shifts with standardized effect 0.35, the new process rejected
1,811/2,000 at both scales. It rejected only 9/2,000 alternating-shift paths;
this is a targeted mean detector, not an omnibus adequacy check. All 42 tests
pass, and the independent scalar audit reproduced 4,800,000 decision states.

Minimal API: construct
`ScaleInvariantGaussianMeanEProcess(catalogue, directions, c, alpha)` once and
call `update(experiment_index, fresh_observation)`. `c` is a predeclared mixture
precision, not the unknown variance. Exact all-zero prefixes are retained with
an explicit insufficient-scale-information status. Do not combine this process
with another alpha-level detector without a shared error budget.

## Historical 0.4.0 release notes

Version 0.4.0 / Theory 1.17 adds a two-sided Gaussian shift e-process that
accumulates weak residuals in one prespecified whitened direction. It is
anytime-valid under the exact conditional-normal contract in Appendix R; it is
not an omnibus goodness-of-fit test. `Reality_Revision_1.17.md` records the
fresh validation, counterexamples, literature, and evidence boundaries.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_cumulative_validation.py
py -3.12 run_cumulative_validation.py --output results-cumulative-rerun
py -3.12 audit_cumulative_validation.py --output results-cumulative-rerun
```

The archived `results-cumulative/` contains 2,400,000 fresh synthetic
observations across six scenarios. The independent scalar replay checks
4,800,000 decision states. All 33 tests pass. At delta=0.35 and 200 looks, the
e-process rejected 1,896/2,000 positive-shift and 1,906/2,000 negative-shift
histories, versus 28 and 27 for the alpha-spending comparison. It rejected
20/2,000 correct-null histories in this finite run. Alternating and orthogonal
shifts remained mostly undetected; a doubled noise scale was detected less often
than by the point-residual gate. Those failures are retained, not generalized away.

Minimal API: construct
`GaussianShiftEProcess(catalogue, directions, delta, alpha)` once and call
`update(experiment_index, fresh_observation)`. Directions live in standardized
measurement coordinates and are normalized internally. The experiment and
direction must be selected from past information only. Do not OR a 1% e-process
with the separate 1% point gate and describe the combination as 1%; allocate or
merge their error budgets first.

## Historical 0.3.0 release notes

Version 0.3.0 / Theory 1.16 adds a separate time-uniform candidate-rejection gate.
It does not change the v0.2.0 selector or its archived results. Read Appendix Q
of Theory_of_Reality.md and Reality_Revision_1.16.md for the proof, assumptions,
fresh synthetic validation, and weak-shift detection failure.

```powershell
py -3.12 -m unittest -v
py -3.12 audit_sequential_validation.py
py -3.12 run_sequential_validation.py --output results-sequential-rerun
py -3.12 audit_sequential_validation.py --output results-sequential-rerun
```

The runner refuses to overwrite an existing destination. The default archived
results-sequential/ holds 1,200,000 fresh synthetic observations and an independent
tail-formula audit of every rejection decision. Replaying the same seed is
reproducibility, not fresh validation after changing a model. All 25 unit tests
pass. The original 15 tests and all earlier result files are retained.

Minimal API: construct `SequentialAdequacy(catalogue, alpha=0.01)` once, then call
`gate.update(experiment_index, fresh_observation)` for each preselected experiment.
The catalogue uses the existing `Experiment` type. Candidate predictions and
noise are copied on construction. Experiment choice may use past data only;
the API cannot detect data reuse, unreported refitting, or a caller creating a
new object to reset the error budget. There is no claim of sequential posterior
truth probability. Survivors are cumulative compatibility candidates, not facts.
For changing models, allocate a cross-revision budget and reserve new validation.

## Historical 0.2.0 release notes

Version 0.2.0 adds experiment selection, explicit rejection of an inadequate candidate set, and an exact audit correcting the main paper's former seven-stage closure argument. Read Reality_Revision_1.14.md for the new evidence and claim boundaries.

The design commands write to results-design/ and preserve the older results/ directory. The default run creates 14,000 synthetic observations. Its independent audit recalculates scores and outcomes; the closure audit checks 7,662 exact finite cases. The combined unit suite has 15 test groups. Two equally optimal phase probes can trade places because of floating-point rounding.

The selector accepts predicted real means, independent Gaussian noise deviations, positive costs, and a budget. It can return no informative experiment. Relative posterior preference and absolute model adequacy are separate. Known path scaling and gain calibration are intervention assumptions, not demonstrated apparatus capabilities.

A reproducible synthetic test of the Theory of Reality's causal rope-and-attachments proposal. It does not establish extra dimensions, a unique ultimate cause, or new physical laws.

Read `Universal_Cycle_Tomography.md` for the model, exact ambiguity arguments, experiments, and limits.

## Run on a PC

Tested on Python 3.12.13, NumPy 2.3.5, and SciPy 1.17.0. Install the pinned environment, then run:

```powershell
py -3.12 -m pip install -r requirements.txt
py -3.12 rope_tomography.py
py -3.12 -m unittest -v
py -3.12 audit_results.py
py -3.12 experiment_design.py
py -3.12 audit_design.py
py -3.12 closure_audit.py
```

On Linux/macOS, use `python3` in place of `py -3.12`. Re-running the experiment overwrites `results/`. The recorded run used `OPENBLAS_NUM_THREADS=1` and `OMP_NUM_THREADS=1`. Timings and floating-point rounding can vary across machines and numerical libraries.

## What is computed

- Stable finite-difference propagation compared with the outgoing analytic solution.
- Exact common phase periods for rational probe frequencies.
- A bounded, calibrated delay/gain/relaxation estimator.
- Predictions at frequencies excluded from fitting.
- Model mismatch from an additional echo.
- A multi-window rank diagnostic for one scalar driver, with a counterexample involving aligned sources.
- Coupling learned from 64 windows and prediction of five withheld sensor channels from one reference channel in 32 new windows.

The seven test groups include independent ODE integration, wave convergence, phase aliasing, exact parameter ambiguities, reference-channel prediction, and a singular-value perturbation bound. The result audit independently recalculates saved metrics without importing the fitter.

## Fit your own calibrated transfer measurements

The API accepts positive frequencies in Hz and complex ratios of output to a known input. They are not raw time samples.

```python
import numpy as np
from rope_tomography import FitPlan, transfer

frequencies = np.array([0.3, 0.5, 0.8, 1.1, 1.7, 2.3, 3.1, 4.2])
# Replace this synthetic example with your calibrated complex measurements.
measured = transfer(frequencies, gain=0.9, transit_delay=0.83, relaxation=0.17)
result = FitPlan(frequencies).fit(measured)
print(result)
```

The current search bounds are gain 0.05–2.5, transit delay 0–2 seconds, and relaxation 0.005–0.6 seconds. Those are laboratory choices, not universal constants. The fitter searches 8,040 grid candidates and refines three initial points. Successful optimization does not prove the model appropriate or globally identifiable.

For a known propagation speed, distance is speed times transit delay only when the assumed local response is correct. Unknown local pure delay, uncalibrated speed, unknown gain/depth factors, and unknown source/filter decompositions remain genuine ambiguities.

## Results

All observations are synthetic. On 72 correct-family fits, median withheld-frequency RMSE was 0.00535 with injected complex noise RMS 0.005. Median delay error was 0.000197 seconds. On 72 echo-mismatched fits, withheld RMSE rose to 0.23253 despite successful optimization.

The rank diagnostic rejected 200/200 cases with two independently coupled sources and 0/200 correct scalar-source cases. It also rejected 0/200 cases with two aligned sources, which are exactly indistinguishable from one effective source in this measurement model. These counts are finite simulation outcomes, not general detection guarantees.

Raw results, calibration values, source identity, seeds, runtime versions, and test logs are in `results/`.
