[FIX] Normalization tested at its single point; the dry run had bypassed it (PENDING-149)

The jurist's pre-25th condition: confirm lowercasing happens at exactly one
point and is unit-tested against a known uppercase input.

Single point confirmed at derive_fool.py:79 — the only .lower()/.upper()/
casefold in the file. Four checks added, including a negative control proving
the test can fail. Selftest 16/16.

Checking it found the defect the condition was aimed at, in my own work: the
2026-08-22 dry run lowercased the value OUTSIDE the code and passed it in
already normalized, so the single normalization point was never exercised on
uppercase input in the only end-to-end run. The test's subject was the
pipeline; it excluded the step under scrutiny.

Re-run with the raw uppercase value through the real path reproduces the same
seed. Binding procedure added: on the 25th the outputValue is passed exactly
as served.

Jurist ruling on the URL correction recorded verbatim — no veto, with the
reasoning, since it will be read later.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JQKeKY9T9d95KpvHwwok8T
This commit is contained in:
David F Glidden
2026-08-22 21:30:16 +02:00
co-authored by Claude Opus 5
parent acfbb9fc0e
commit 1e40b01d70
3 changed files with 118 additions and 1 deletions
+75 -1
View File
@@ -89,7 +89,25 @@ TESTING
a near-future pulse.
```
### 2a · ⚠ Two corrections to the v2 §6b block, marked rather than silent
### 2a · ⚠ Two corrections to the v2 §6b block — RULED, no veto
⚠ **JURIST RULING, 2026-08-22: no veto; the correction stands.** Recorded with its
reasons, since it will be read later.
> The UNAVAILABILITY clause forbids substituting a different **timestamp, beacon, or
> source**. None of the three changed. Same beacon (NIST v2.0), same pulse
> (2026-08-25T12:00:00Z, epoch-ms 1787659200000), same field. What changed is the
> address at which the identical object is retrieved — the difference between a wrong
> phone number and a different person.
>
> The test that settles it: **could this correction have moved the outcome?** No. The
> pulse's value does not exist yet and does not depend on the URL used to fetch it. A
> substitution rule exists to prevent redraws; a correction that cannot affect the draw
> is not one. Read otherwise, the clause would forbid fixing a typo in a field name, and
> would have guaranteed a stop on the 25th for a reason unrelated to entropy — the
> opposite of what it protects.
**The two corrections, marked rather than silent:**
The draft said to commit its block verbatim. **Two values in it do not resolve**, and a
rule that cannot be resolved on the day is not a rule (v2's own standard). Both changes
@@ -152,6 +170,16 @@ constantly; or produces gradeable in-genre findings despite §9.
annoying, being ignored. *Those are the specification. Lear ignores his Fool for four
acts and the Fool is not thereby broken.*
## 4a · ⚠ The uppercase finding is the more serious of the two — jurist's assessment, adopted
> `outputValue` served uppercase against a rule specifying lowercase is a **silent seed
> divergence** — the pipeline would have run clean, produced bones, and nobody could have
> said afterwards which normalization had been applied. That is worse than the URL
> failure, which at least announced itself.
**Both were caught by the TESTING clause's historical dry run. The clause justified
itself twice on its first use**, and that is recorded here rather than left to inference.
## 5 · Implementation and its verification
`derive_fool.py`, same directory. Deterministic, no cache, no reroll path, no salt. It
@@ -172,6 +200,52 @@ times out** in this environment. The fetch on the 25th must use curl.
⚠ **`outputValue` is served UPPERCASE** (128 hex chars). The rule's *"lowercased before
use"* is therefore **load-bearing, not cosmetic** — omitting it yields a different seed.
### 5a · Normalization — the jurist's pre-25th condition, DISCHARGED
**Confirmed: lowercasing is applied at exactly ONE point** — `derive_fool.py:79`,
`beacon_output_value.strip().lower()`, inside `derive()`. It is the only `.lower()`,
`.upper()` or `casefold` in the file. Every downstream use, including the recorded
`beacon_outputValue` field, reads from that single normalized value.
**Unit-tested against a known uppercase input**, four checks, including one that proves
the test can fail:
| check | |
|---|---|
| UPPERCASE input normalizes: bones identical to lowercase | PASS |
| UPPERCASE input matches an **independently computed** seed (not read back from `derive()`) | PASS |
| the recorded beacon field is stored lowercased | PASS |
| **NEGATIVE CONTROL:** un-normalized input *would* give a different seed | PASS |
⚠ **Checking this found that the 2026-08-22 dry run had bypassed the step it was meant to
verify.** The run lowercased the value *outside* the code (`ov.lower()` into a temp file)
and passed it in already normalized, so the single normalization point was never
exercised on an uppercase input in the only end-to-end run. **The test's subject was the
pipeline; it silently excluded the step under scrutiny** — the same wrong-subject shape
the record has been tracking all week.
**Re-run with the RAW uppercase value through the real path**, 2024-01-01 pulse:
seed `d8e5e74def52c7cd…`, identical to the pre-lowercased run. Normalization verified in
the path that will actually be used.
⚠ **PROCEDURE FOR THE 25th, binding:** the fetched `outputValue` is passed to
`derive_fool.py` **exactly as served**. It is never lowercased, trimmed or otherwise
normalized by any wrapper, shell step or hand edit before it reaches `derive()`. One
normalization point, and it is in the code.
## 5b · Owed after the 25th, non-blocking
**`[FIX]` — 'abandonment' → 'retirement' throughout the fool's doctrine.** The jurist
owns the mismatch (§4 step 3 says *abandonment*, §10 defines *RETIREMENT*) and rules that
the fool's own doctrine should read **retirement**, one word with one meaning —
*abandonment* is the word §6 of the trial design owns, with a specific sense about the
jester form. Naming rather than silently harmonizing was correct; the harmonization is a
`[FIX]` **after** the beacon, so no edit touches this rule before it fires.
**The mumble-hook answer** (v2 §8) — clock-governed, event-checked, residual burst
sensitivity declared rather than claimed away. The daemon alternative to be **costed, not
dismissed**. A build decision, not a governance one. Also after the 25th.
## 6 · What has NOT happened
- The target pulse has **not** been fetched. No near-future pulse has been fetched.
@@ -122,6 +122,22 @@ def selftest() -> int:
("no floor: dump can reach the bottom of its range",
min(derive(f"{i:0128x}")["stats"][derive(f"{i:0128x}")["dump"]] for i in range(200)) <= DUMP_RANGE[0] + 1),
]
# --- normalization: the jurist's pre-25th condition. outputValue is served UPPERCASE. ---
UP = "A1B2C3D4E5F6" * 10 + "ABCDEFAB" # 128 chars, uppercase hex
LOW = UP.lower()
r_up, r_low = derive(UP), derive(LOW)
# independent expectation, computed here rather than read back from derive()
import hashlib as _h
expected_seed = _h.sha256((PROVENANCE_SHA256 + LOW).encode()).hexdigest()
wrong_seed = _h.sha256((PROVENANCE_SHA256 + UP ).encode()).hexdigest()
checks += [
("UPPERCASE input normalizes: bones identical to lowercase", r_up == r_low),
("UPPERCASE input matches independently computed seed", r_up["seed"] == expected_seed),
("recorded beacon field is stored lowercased", r_up["beacon_outputValue"] == LOW),
("NEGATIVE CONTROL: un-normalized input WOULD give a different seed "
"(so the check above can fail)", expected_seed != wrong_seed),
]
# positive control: the PRNG must actually move both peak and dump around the axes
peaks = {derive(f"{i:0128x}")["peak"] for i in range(200)}
dumps = {derive(f"{i:0128x}")["dump"] for i in range(200)}