diff --git a/spec/CONTRACT_P13S6_PROMOTION.md b/spec/CONTRACT_P13S6_PROMOTION.md new file mode 100644 index 0000000..b99898a --- /dev/null +++ b/spec/CONTRACT_P13S6_PROMOTION.md @@ -0,0 +1,251 @@ +# Contract: P13-S6 promotion — the tuning constructions become normative + +Repo root `/home/jeans/Repos/active/epiphany`. Read this file in full before +editing anything. The rulings below are **granted**; they are law for this task, +not proposals. + +You are promoting reviewed, ratified content into the specification. This is a +transcription task with three small additions. The hard part is not deciding +anything — it is not silently changing anything. + +## Blast radius + +You edit exactly two files, plus one rebuilt artifact: + +* `spec/core_spec.tex` +* `spec/core_spec.pdf` (rebuilt, not hand-edited) +* `crates/epiphany-testkit/tests/requirement_labels.rs` — **three integer + constants only**, at lines 12–14. Nothing else in that file. + +You write no other Rust. You touch no other document, no other companion +`.tex`, and no other agent's file. + +## Source of truth, and the clause that matters most + +`spec/DRAFT_P13S6_TEMPERAMENTS.md` is the reviewed draft. Its head carries a +block titled **"RATIFIED 2026-07-22"**. Read that block first; it supersedes +the draft's own §11–13 wherever they disagree. + +**The draft's arithmetic is settled. Every closure sum, wolf size, and ratio in +Section A has been independently recomputed by a reviewer and confirmed.** + +If you believe you have found an error in it: **report it, do not fix it.** +Stop and say so in your report. A silent "correction" to a verified +construction is the single most damaging thing you can do here, because it +would arrive wearing the same clothes as the verification. The draft already +survived one round in which three properly-cited entries turned out to be +arithmetically impossible; the arithmetic is what caught them, and the +arithmetic has now been run. Your disagreement is a finding, not an edit. + +## Part 1 — the ten pinned constructions + +`\subsection{Built-in Tuning Systems}` (`core_spec.tex:3593`) holds a +`longtable` of 20 identifiers with one-line descriptions, followed by +`req:tuning:builtin-tuning-catalog`, which already says *"The semantics +specified above are normative."* Ten of the fourteen non-`tet-*` rows are bare +names; Section A of the draft specifies them. + +Add a new `\subsection` — **between** `req:tuning:builtin-tuning-catalog` and +`\subsection{Default Score Configuration}` (`core_spec.tex:3633`) — carrying the +normative construction for each of: `pythagorean`; `meantone-1/4-comma`, +`meantone-1/5-comma`, `meantone-1/6-comma`; `werckmeister-iii`, +`werckmeister-iv`; `vallotti`; `kirnberger-ii`, `kirnberger-iii`; `young-ii`. + +For each, carry over from the draft: + +* the generative rule — which fifths are tempered, by what fraction of **which** + comma (the draft names syntonic vs Pythagorean explicitly for every entry; + preserve that distinction exactly, it is the classic error); +* the wolf or chain placement where the construction does not force it — + `pythagorean` in particular states its cut as a *choice*, and it must read as + a choice in the spec too; +* the exact ratios where the construction yields rationals, and the derived + cents alongside, marked as derived; +* the closure statement — the twelve-fifths sum for the circulating + temperaments, and the wolf residue for the non-circulating ones. + +Keep the closure sums. They are not decoration: they let a reader check the +construction without leaving the page, and they are what makes this section +self-verifying. + +**Do not carry over:** the `verified`/`recalled` confidence tags, the URLs, the +"corrected this round" revision commentary, or any bibliography. The +temperament's *name* is its attribution, and the closure sum is its warrant. +This is deliberate — transcribing a citation you did not check is how a +fabricated source enters a normative document, and there is no reason to run +that risk when the arithmetic stands on its own. + +**Do not add a `\begin{requirement}` block for any of the ten.** The existing +`req:tuning:builtin-tuning-catalog` already makes this text normative. + +## Part 2 — the 5-limit construction (one new requirement) + +Add `req:tuning:ji-static-construction`. It states: + +The static 5-limit just-intonation systems are constructed from the contiguous +lattice block $\{3^a 5^b \mid a \in [-1,2],\ b \in [-1,1]\}$ — twelve cells, +octave-reduced, assigned in ascending order to the twelve chromatic positions +of `cmn-12` starting from the anchor, which takes the role of $1/1$. The block +is generated by its bounds; nothing is selected and nothing is discarded. + +The twelve, anchor-relative (position 0 is the anchor): + +| step | cell | ratio | cents (derived) | +|---|---|---|---| +| 0 | $3^{0}5^{0}$ | 1/1 | 0.000 | +| 1 | $3^{-1}5^{-1}$ | 16/15 | 111.731 | +| 2 | $3^{2}5^{0}$ | 9/8 | 203.910 | +| 3 | $3^{1}5^{-1}$ | 6/5 | 315.641 | +| 4 | $3^{0}5^{1}$ | 5/4 | 386.314 | +| 5 | $3^{-1}5^{0}$ | 4/3 | 498.045 | +| 6 | $3^{2}5^{1}$ | 45/32 | 590.224 | +| 7 | $3^{1}5^{0}$ | 3/2 | 701.955 | +| 8 | $3^{0}5^{-1}$ | 8/5 | 813.686 | +| 9 | $3^{-1}5^{1}$ | 5/3 | 884.359 | +| 10 | $3^{2}5^{-1}$ | 9/5 | 1017.596 | +| 11 | $3^{1}5^{1}$ | 15/8 | 1088.269 | + +`ji-static-5limit-C`, `ji-static-5limit-G`, and `ji-static-5limit-D` are this +one construction at three anchors. The catalog keeps exactly those three; +additional anchors are an implementation extension and **MUST NOT** be read as +a conformance obligation. + +Normalize the three catalog descriptions (`core_spec.tex:3617-3619`) to the same +form — *"anchored to X tonic"* — since today only the C row says "tonic". + +**Banned vocabulary, throughout.** Never write "asymmetric scale", "symmetric +scale 1", or "symmetric scale 2". Those names come from a framing this ruling +rejects (a 5×3 grid with three cells discarded), and the word "symmetric" in +that framing describes the shape of the *discarded cells*, not any property of +the resulting scale. Do not claim any of these scales is inversionally +symmetric: none is, because $45/32$ is present and $64/45$ is not. + +## Part 3 — adaptive tuning (two new requirements, plus two amendments) + +### 3a. `req:tuning:adaptive-default-version` + +`ji-adaptive-5limit` resolves to `TuningResolution::Adaptive` with function +identity **`"default-v1"`** — the version is part of the machine-visible +identifier string, not prose beside it. + +Version 1 is a pure function of (position, anchor pitch class): + +* resolve the position through `req:tuning:ji-static-construction` transposed so + the anchor is $1/1$; +* the anchor is the tonal centre supplied by the harmonic context; **C (chromatic + position 0) when none is supplied**; +* `concurrent`, `recent`, `hints`, `parameters`, and mode are **ignored** in + version 1 — state this explicitly, as `req:pitch:spelling-algorithm` does for + its own version 1, so that consuming them later is a new version rather than a + silent behaviour change; +* every result derives from the anchor and the reference pitch. No adjustment is + ever carried forward from a previous resolution, so the construction is + comma-drift-free by shape rather than by a correction step. + +An unregistered or unknown `AdaptiveTuningFunctionId` **MUST** be a hard error. +There is no silent fallback. `AdaptiveTuningFunctionId` remains an extension +point and other functions may be registered — but the built-in +`ji-adaptive-5limit` is bound to `"default-v1"` and that binding cannot be +overridden. + +### 3b. `req:tuning:adaptive-anchor-derivation` + +Where a harmonic context is constructed from a score graph, the anchor is +derived from the prevailing key signature: + +``` +anchor_pc = (7 × fifths) mod 12 +``` + +reading `fifths` as the major tonic — mode is not consulted, so a signature of +0 anchors at C whether the music is C major or A minor. `KeySignature` is +already defined (`core_spec.tex:4892`) with `fifths` validated to −7..=+7. + +State the two things that rule leaves open, because `key_sequence` +(`core_spec.tex:4845`) is **per-staff and time-anchored**: the signature in +effect is the one on the staff containing the pitch, at the latest +`KeySignatureChange` whose anchor is at or before that pitch's onset. Without +both, a polytonal or modulating score resolves differently in two conforming +implementations, which `req:tuning:tuning-resolution-determinism` forbids. + +### 3c. Amend the Adaptive Tuning prose + +`core_spec.tex:3364-3368` promises that "the frequency of a given E depends on +whether it is the major third of a C chord, the perfect fifth of an A chord, or +a passing tone". That describes what an adaptive function **may** do. It is not +what the built-in does at version 1, and left as-is it reads as a promise the +normative text does not keep. + +Rewrite it so per-sonority interpretation is described as within the scope of +registered adaptive functions generally, and note that `ji-adaptive-5limit` +version 1 consumes only the tonal centre. Do **not** weaken +`req:tuning:adaptive-tuning-purity` — it already permits the narrower algorithm, +since requiring a pure function of position and context never required consuming +every context field. + +### 3d. Correct the forward reference + +`core_spec.tex:3649-3653` says `KeyContext` is *"partially defined in +Chapter~\ref{ch:graph} and completed in the audio engine specification (out of +scope for this document)"*. `KeyContext` is not defined anywhere in this +specification, and no type of that name exists in the implementation. + +Keep it out of scope — but replace the vague claim with the interface obligation +that Part 3 actually depends on: whatever completes `KeyContext` **MUST** expose +a tonal-centre chromatic pitch class consistent with +`req:tuning:adaptive-anchor-derivation`. Chapter 10 defines `KeySignature`, not +`KeyContext`; say that accurately. + +`ContextHint` and `AdaptiveTuningParameters` stay undefined. Say so explicitly +rather than leaving the silence ambiguous. Version 1 ignores both, and inventing +them now would freeze a type surface on a chapter that has no consumer. + +## Counts and verification + +Three new requirements, so three constants move in +`crates/epiphany-testkit/tests/requirement_labels.rs`: + +* `CORE_REQUIREMENT_COUNT` 209 → **212** +* `SUITE_REQUIREMENT_COUNT` 279 → **282** +* `SUITE_LABEL_COUNT` 279 → **282** + +If your build produces different numbers, **stop and report** — do not tune a +constant until a test passes. That inverts what the constant is for. + +Requirement numbering is automatic: the box steps a plain counter via +`code={\refstepcounter{requirement}}` (`core_spec.tex:245`), so inserting +requirements mid-document renumbers later ones in the rendered PDF while every +`\label` keeps resolving correctly. You do not maintain numbers by hand, and +you **MUST NOT** rename or move any existing `\label` — they are cited by code, +tests, and decision records. + +Do not add code citations for the three new requirements. Nothing implements +them yet; that lands in a later Push 4b step. + +Then: + +1. `cargo test -p epiphany-testkit --test requirement_labels` → 6 passed. +2. Rebuild with `latexmk -xelatex` **twice**. Grep the log for `^! `, + `Undefined control sequence`, and `Reference .* undefined`, and report the + actual counts. All must be zero. +3. Full workspace gate: `cargo fmt --all --check`; `cargo clippy --workspace + --all-targets` → 0 warnings; `cargo test --workspace`; + `cargo run -q -p epiphany-testkit --example conformance_suite` → 8/8. Zero + golden churn is expected — report it if not. + +Report the actual commands and their actual output. On this project an agent +once reported "verification passes" while errors pointed into its own file, and +another silently deleted a struct field while rewriting the comment above it — +so **re-read every listing and table you edit, in full, after editing it**, and +confirm nothing adjacent vanished. + +## Do not + +* Decide anything. All four ratifications are made; if you find a fifth + question, report it unanswered. +* Edit any construction in Section A of the draft, or "improve" its arithmetic. +* Carry a URL, a confidence tag, or a bibliography into `core_spec.tex`. +* Use the words "asymmetric scale", "symmetric scale 1", or "symmetric scale 2". +* Add a registry field, a `Codec` impl, or any Rust type. Part 3 is spec-only. +* Edit `binary_format.tex`, `operation_catalog.tex`, or any other companion. +* Run `cargo fmt --all`. diff --git a/spec/DRAFT_P13S6_TEMPERAMENTS.md b/spec/DRAFT_P13S6_TEMPERAMENTS.md index a37804a..e66a06c 100644 --- a/spec/DRAFT_P13S6_TEMPERAMENTS.md +++ b/spec/DRAFT_P13S6_TEMPERAMENTS.md @@ -4,6 +4,63 @@ is true by virtue of being written down — it is true (or not) by virtue of the citation attached to it, and every citation is graded.** +--- + +## RATIFIED 2026-07-22 — read this before §11–13, which it supersedes + +The four open ratifications this draft surfaced have been decided. Section A +(the ten pinned constructions) is **accepted as written** and is the source of +truth for promotion. Section B is **superseded by the rulings below**; where +the rulings and §11–13 disagree, the rulings win. + +1. **The 12-note 5-limit scale is the contiguous lattice block** + $\{3^a 5^b \mid a \in [-1,2],\; b \in [-1,1]\}$, octave-reduced and assigned + in ascending order to the twelve chromatic positions from the anchor. This + is the construction §11–13 calls "asymmetric" — **that name must not be used + normatively**, nor must "symmetric scale 1" or "symmetric scale 2". The block + is generated by its bounds; it discards nothing, so the "5×3 grid minus three + cells" framing that produced those names does not survive into the spec. +2. **`ji-static-5limit-C`/`-G`/`-D` are one construction at three anchors**, the + named note taking the role of $1/1$. The catalog keeps exactly three rows; + further anchors are an implementation extension, not a conformance + obligation. +3. **`ji-adaptive-5limit` version 1 is the key-anchored static scale** — anchor + from the harmonic context's tonal centre, C when absent; `concurrent`, + `recent`, `hints`, `parameters`, and mode are ignored. The per-sonority + algorithm §14 sketches is deferred to a later version, to land with its + bounds, objective, tiebreaks, implementation, and vectors together. +4. **The identity is `"default-v1"`** — version machine-visible in the string, + hard error on any unregistered identifier, no silent fallback. + +### Two corrections to §11–13, computed + +* **The quarter-comma-meantone argument is false and is struck.** §11–13 offers, + as a point in favour of "symmetric scale 1", that its D and B♭ match those of + C-based Pythagorean and quarter-comma meantone. In quarter-comma meantone + D = 193.157 ¢ and B♭ = 1006.843 ¢; the just values are 203.910 ¢ and + 996.090 ¢. Each differs by half a syntonic comma. The claim can only hold of + *circle-of-fifths position*, never of ratio, and even granting that reading it + covers 2 notes of 12 while the other ten shift by a comma between systems — so + it is not a cross-system invariant and carried no weight in the ruling. +* **No 12-note set here is inversionally symmetric.** All three candidates fail + at the tritone: $45/32$ is present and its inverse $64/45$ is not. §11–13's + inversion claim is correct only of the D/B♭ *pair*. The word "symmetric" in + the source names the shape of the discarded cells, not a property of the + resulting scale, and must not be repeated as if it named one. + +### Verified interval census (recomputed, all 12 roots) + +| construction | pure P5 | pure M3 | pure m3 | total of 36 | I / IV / V | +|---|---|---|---|---|---| +| "symmetric 1" | 9 | 7 | 6 | 22 | ✓ ✓ ✓ | +| "symmetric 2" | 9 | 6 | 6 | 21 | ✓ ✓ **✗** (G–D = 40/27) | +| **the block (ratified)** | 9 | **8** | 6 | **23** | ✓ ✓ ✓ | + +The block also gains pure E♭ major and G minor against "symmetric 1", losing +only B♭ minor — the parallel-minor region in exchange for a remote key. + +--- + Produced under `spec/CONTRACT_P13S6_TEMPERAMENTS.md`, against Ruling B of `spec/PLAN_PUSH4B_TUNING.md`. Scope: the 14 `req:tuning:builtin-tuning-catalog` identifiers (`core_spec.tex:3531-3546`) that are not one of the six `tet-*` @@ -740,10 +797,13 @@ of the *other* two duplicate pairs (D vs D−, B♭ vs B♭−) to resolve, and 1. **"Symmetric scale 1."** Discard the two opposite corners (D− and B♭−, top-left/bottom-right). Keeps: D = 9/8 (203.910 c), B♭ = 16/9 (996.090 c). Optimizes: symmetric structure (B♭ and D are exact - inversions of each other around C); this is the scale that also matches + inversions of each other around C); ~~this is the scale that also matches the D and B♭ used in C-based Pythagorean and quarter-comma-meantone scales (source's own note), which may matter for cross-tuning-system - comparison work in this codebase. + comparison work in this codebase.~~ **STRUCK — false; see the ratification + block at the head of this file. Quarter-comma meantone's D and B♭ are + 193.157 ¢ and 1006.843 ¢, each half a syntonic comma from the just values. + Do not carry this claim into the specification.** 2. **"Symmetric scale 2."** Discard the two ends of the middle (`1`) row — i.e. keep D− = 10/9 (182.404 c) and B♭ = 9/5 (1017.596 c) instead. Also symmetric (same inversion property, different fixed point), but the D