diff options
| author | Void Agent <void@jayrup.hermes> | 2026-08-02 15:31:53 +0100 |
|---|---|---|
| committer | Void Agent <void@jayrup.hermes> | 2026-08-02 15:31:53 +0100 |
| commit | 3bd33fbf685c6b16747d6ec4c1026d4fa6d04966 (patch) | |
| tree | 62a3e6eca548365d03b3a5becfbe1f89e144d052 | |
| parent | f65bfa0fc338769b36b9091ac10241de878549fa (diff) | |
Fix in-word metric: strict (both-sides, 58% random / 0% clean) vs touches (95%); blog/results caveat corrected to the strict discriminator
| -rw-r--r-- | docs/blog-jlens-frequency.md | 13 | ||||
| -rw-r--r-- | results.md | 11 | ||||
| -rw-r--r-- | src/synthetic_pair.py | 10 |
3 files changed, 20 insertions, 14 deletions
diff --git a/docs/blog-jlens-frequency.md b/docs/blog-jlens-frequency.md index ceb97d5..4b2b429 100644 --- a/docs/blog-jlens-frequency.md +++ b/docs/blog-jlens-frequency.md @@ -242,12 +242,13 @@ predictability* (what "verbalizable" should mean) depends on a control that is still running — see the caveat below. One caveat, found by a reviewer: the noise token '#' was inserted at random -character positions, which slices *inside* words ~95% of the time (th#e, -ki#ng), while '@' always sits at a clean word boundary after "the ". That -means predictability is not perfectly isolated from n-gram corruption. We are -running a clean-boundary control (noise token inserted after random word -boundaries — still unpredictable, no word-slicing) to rule it out; the numbers -above should be read with that caveat until the control lands. +character positions, which slices through the middle of a word 58% of the time +(th#e, ki#ng — letter on both sides), while '@' always sits at a clean word +boundary after "the ". Predictability is therefore not perfectly isolated from +n-gram corruption. We are running a clean-boundary control (noise token +inserted after random word boundaries — 0% word-slicing, still unpredictable) +to rule it out; the numbers above should be read with that caveat until the +control lands. ## 8. The causal test: what actually happened @@ -113,11 +113,12 @@ Middle-layer ratio across seeds: 1.47 +/- 0.09 (SD), bootstrap 95% CI genuine conditional-predictability signal. CAVEAT (from adversarial review): '#' was inserted at uniform random character -positions, which slices inside words ~95% of the time (th#e, ki#ng); '@' -always sits at a clean word boundary after "the ". Predictability is therefore -not perfectly isolated from n-gram corruption. A clean-boundary control (noise -token after random word boundaries) is planned; the numbers above should be -read with that caveat until it lands. +positions, which slices through the middle of a word 58% of the time (letter +on both sides: th#e, ki#ng); '@' always sits at a clean word boundary after +"the ". Predictability is therefore not perfectly isolated from n-gram +corruption. A clean-boundary control (noise token after random word +boundaries, 0% word-slicing) is running; the numbers above should be read with +that caveat until it lands. ## 3. Loss-reweighting causal test (`src/loss_reweight.py`) diff --git a/src/synthetic_pair.py b/src/synthetic_pair.py index 4c64379..bfe5b8b 100644 --- a/src/synthetic_pair.py +++ b/src/synthetic_pair.py @@ -72,8 +72,11 @@ def prep(clean=False): noise_pos = sorted(rng.choice(avail, size=n_target, replace=False).tolist()) # sanity: fraction of noise insertions that slice inside a word - in_word = sum(1 for p in noise_pos - if 0 < p < len(text) and (text[p - 1].isalnum() and text[p].isalnum())) + # strict: letter on BOTH sides (th#e, ki#ng); touches: letter on either side + strict = sum(1 for p in noise_pos + if 0 < p < len(text) and (text[p - 1].isalnum() and text[p].isalnum())) + touches = sum(1 for p in noise_pos + if 0 < p < len(text) and (text[p - 1].isalnum() or text[p].isalnum())) # insert with offset (both sets sorted -> single merge pass) insertions = [(p, T_STRUCT) for p in struct_pos] + [(p, T_NOISE) for p in noise_pos] @@ -91,7 +94,8 @@ def prep(clean=False): print(f"prep({mode}): '{T_STRUCT}' x{n_target} after '{TRIGGER.strip()}', " f"'{T_NOISE}' x{n_target} {mode}, " f"freq each = {n_target/len(modified):.4%}, " - f"in-word '#' = {in_word}/{n_target} ({in_word/n_target:.1%})") + f"in-word '#' = {strict}/{n_target} ({strict/n_target:.1%}), " + f"touches word = {touches}/{n_target} ({touches/n_target:.1%})") # build vocab (existing chars + the two synthetic) chars = sorted(set(text)) + [T_STRUCT, T_NOISE] |
