# RESULT — Campaign100 039 persistent-homology

**Verdict: ★ CLEAN NEGATIVE, certified by a passing positive control.** SONAR z-space has **no
robust global topology** — no persistent H1 loops, no H2 voids — beyond a Gaussian blob, and the
cyclic linguistic attributes (days / months / clock-hours) do **not** trace geometric loops. The
tool demonstrably *can* find a planted circle (G1), so the absence is a real absence, not a power
failure. Coheres with 037 (near-isotropic) + 031 (structure is local-ID inhomogeneity, not global
shape). Tier: **T3-exploratory.**

## What ran
- **Tooling (was the BLOCKED risk → resolved):** `ripser.py` 0.6.15 installed into the night8 venv.
  *Install gotcha logged:* box `pip` = `/usr/bin/pip` user-installs to `~/.local`, which the uv-managed
  venv ignores (`ENABLE_USER_SITE=False`); the venv has no `pip`/`uv` on PATH. Correct install:
  `~/.local/bin/uv pip install ripser`. (Useful for any future TDA/library row.)
- **Metric = EUCLIDEAN (primary), cosine cross-check.** *Methodological correction found in smoke:*
  cosine distance on origin-centered clouds conflates a genuine ring (empty center → persistent H1)
  with a 2D-Gaussian-around-the-origin (angularly uniform → spurious H1); the initial cosine-metric G1
  gate FAILED for exactly this reason (planted circle 0.40 vs a covariance-matched *cosine* null 0.35).
  Euclidean preserves the radial information, so the covariance-matched Gaussian null is a *filled
  ellipsoid* = a proper "no-hole" baseline. Switched to euclidean → G1 passes cleanly.
- **Data:** (a) 1000-pt random subsample of 031's 29,029 real SONAR z; (b) 3 cyclic families
  days(7)/months(12)/clock-hours "one..twelve o'clock"(12); (c) 3 linear families
  sentiment(9)/size(9)/numbers-1-12(12). Each family = values × 24 diverse sentence templates
  (1,464 sentences total, encoded on GPU0 in <2 s, GPU freed). Per family we analyze the
  **template-centered** cloud (subtract per-template centroid → the pure attribute axis; identical
  procedure for cyclic and linear, so any loop is attributable to cyclicity not the centering).
- Per cloud: max-H1 lifetime vs covariance-matched Gaussian null (p95 band); attribute-centroid
  **closure ratio** d(last,first)/mean(consecutive step) vs a **label-shuffle null**; PCA line-vs-circle;
  subsample-stability (two disjoint halves). Ran in ~30 s wall on box, CPU-only for the TDA.

## Numbers
**G1 tool-sanity (planted circle in 1024-d + iso noise, euclidean): PASS.**
top H1 lifetime **0.526**, 2nd feature 0.056 → **9.3× dominance**; covariance-matched no-hole null
p95 0.134 → **3.9× above null**. The tool cleanly recovers one planted loop.

**Random diverse manifold (n=1000):** max-H1 **0.0185**, 2nd 0.0168 (top1≈2nd → no dominant loop),
null p95 0.0153 → excess **1.42×**. The binary `signal>p95` flag trips *marginally*, but this is a
threshold artifact: no dominant feature, and **subsample-stability = 0 persistent features in BOTH
halves** (`[0,0]`). H2 voids negligible (max-life 3e-4). Cosine cross-check identical story
(excess 1.5×). → **robustly a blob.**

**Attribute families (template-centered):** *no loop in any family.*

| family | kind | K | H1 obs | null p95 | excess | loop? | closure | shuffle p05 / mean | closes? | evr1 / evr12 | subst |
|--------|------|---|--------|----------|--------|-------|---------|--------------------|---------|--------------|-------|
| days | cyclic | 7 | 0.0031 | 0.0151 | 0.25 | No | 1.01 | 0.55 / 1.02 | No | 0.24 / 0.44 | [0,0] |
| months | cyclic | 12 | 0.0033 | 0.0122 | 0.32 | No | 1.04 | 0.63 / 0.97 | No | 0.15 / 0.28 | [0,0] |
| clock | cyclic | 12 | 0.0049 | 0.0155 | 0.40 | No | 1.24 | 0.68 / 1.01 | No | 0.21 / 0.35 | [0,0] |
| sentiment | linear | 9 | 0.0039 | 0.0126 | 0.38 | No | 1.29 | 0.60 / 0.98 | No | 0.35 / 0.59 | [0,0] |
| size | linear | 9 | 0.0097 | 0.0143 | 0.96 | No | 1.58 | 0.62 / 1.00 | No | 0.35 / 0.65 | [0,0] |
| numbers | linear | 12 | 0.0039 | 0.0120 | 0.37 | No | 1.22 | 0.69 / 1.00 | No | 0.23 / 0.37 | [0,0] |

Every family: H1_obs **below** its no-hole null (excess < 1), H2 voids negligible (≤1e-3),
subsample-persistent-feature count **0/0**. The starkest contrast in the whole experiment: the tool
returns a **0.53** loop for a planted circle but **≤0.01** for every real attribute cloud.

## Interpretation (three clean sub-findings)
1. **No global loops/voids.** Neither the diverse manifold nor any attribute cloud carries a
   persistent H1 or H2 feature above a covariance-matched blob. High-dim SONAR z is topologically a
   blob at global scale — consistent with 037 (near-isotropic) and 031 (the *real* structure is a
   graded local-ID / density field, not global shape).
2. **Cyclic linguistic order does NOT map to a geometric cycle.** Days/months/clock closure ratios
   (1.01–1.24) look "closed" at first glance, but the **label-shuffle null mean is also ≈1.0** — a
   *random* ordering of the same points closes just as well (its p05 reaches 0.55–0.69, i.e. random
   orderings close *tighter* than the calendar order). This is high-dimensional **distance
   concentration**: with points spread in ~1024-d, the wrap step ≈ any step for essentially any
   ordering, so closure≈1 is an artifact and carries no cyclicity signal. *The shuffle-null control
   was decisive — without it, closure≈1 would have been over-read as a loop.*
3. **The attribute axis is high-dimensional, not a clean curve.** PCA of the pure attribute variation
   puts only 15–36% of variance in the top component and 28–65% in the top two — the variation is
   smeared across many dimensions, so it is neither a 1D line nor a 2D circle. (The most line-like is
   `size`: evr12 0.65, closure 1.58 = endpoints minuscule↔enormous stay far apart — the expected
   *arc*, not a loop.)

## Gates
- **G1 tool-sanity: PASS** (planted loop 0.526, 9.3× dominant, 3.9× null). *If this had failed →
  INSTRUMENT_FAILURE; it did not.*
- **G2 null-band computed: PASS** — covariance-matched Gaussian null p95 reported for every cloud;
  label-shuffle null for every closure ratio.
- **G3 subsample-stability: PASS** — two disjoint halves agree (0 persistent features each) for diverse
  and all six families; perfectly consistent "no topology."
- **G4 encode-sanity: PASS** — stimuli z finite, norms ~0.18–0.23 (matches 037's 0.225), K×M points
  per family.

## Predictions & Brier
Frozen in PREREG_LITE before the full run:
- (a) planted-circle sanity passes = 0.92 → **TRUE** (G1 pass).
- (b) ≥1 cyclic family shows persistent H1 above null AND closes below shuffle-null = 0.35 → **FALSE**
  (none; correctly doubted).
- (c) random diverse shows NO persistent H1 above null (blob) = 0.85 → **TRUE (robust)** — 0 subsample-
  persistent features, top1≈2nd; *disclosed:* the naive p95 flag tripped marginally (1.42×), which is
  not a persistent feature under the G3 definition. (If scored on the raw flag = FALSE, Brier would be
  0.196 instead of 0.056 — reported for transparency.)
- (d) overall no robust global topology beyond local-ID/inhomogeneity = 0.70 → **TRUE**.
- (e) linear families behave as lines / no loop = 0.80 → **TRUE** (no linear loop; size most arc-like).

**Brier (a–e) = 0.0563** (well-calibrated: the only real "cost" is (b), which was correctly held low;
(a) slightly under-confident). Strict-(c) variant = 0.196.

## Limitations
- One AE / one corpus / one encoder (SONAR text). Absence of *global* topology does not preclude
  structure at scales the covariance-matched null already absorbs.
- Cyclic families sampled at K=7–12 discrete values × 24 templates; a denser cyclic variable (e.g.
  fine clock times, angles) could in principle sample a loop better — but the closure/PCA diagnostics
  already show the attribute axis is high-dim and non-cyclic, so a finer sample is unlikely to help.
- Nulls at 10–15 bootstraps (adequate for a decisive negative; the effect is not near threshold for
  the families — excess < 1). Euclidean on the raw manifold inherits the norm scale (036/031 lesson),
  but the covariance-matched null controls for that global spread, and the cosine cross-check agrees.

## Follow-up worth funding? **Weak-N.**
The negative is clean and coheres with 037/031. Not worth a full TDA re-run. One narrow, cheap idea if
revisited: mapper/graph-based structure (rather than persistence) on the local-ID field from 031 to see
if the *inhomogeneity* has connected-component structure — but that is a 031 extension, not a topology
claim. Methodological asset produced: (i) the ripser install recipe + euclidean-vs-cosine ring/blob
lesson; (ii) the closure-ratio + label-shuffle-null test for "does a linguistic order map to a geometric
cycle" (reusable, and it correctly killed a distance-concentration false positive here).

## Reproduce
Box `/workspace/HOME/guest/campaign100/039-persistent-homology/`, `bash src/run_039.sh full`
(gen_stimuli → GPU0 encode → CPU tda). Repo `src/` + `out/{results.json,stimuli.json}`.
`out/stim_z.npz` (6 MB raw stimulus z) kept on box only, regenerable from the encode step.
