From 31145d22f1aaf32050e7bce9d31e4fc33ee2ab2f Mon Sep 17 00:00:00 2001 From: PhysShell Date: Wed, 15 Jul 2026 07:17:07 +0500 Subject: [PATCH 1/3] =?UTF-8?q?docs(swang):=20the=20grammar=20the=20demo?= =?UTF-8?q?=20earned=20=E2=80=94=20and=20the=20strategy=20the=20ear=20dema?= =?UTF-8?q?nded?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Phase 2 closure verdict, made normative before any parser exists: spec §3 records the surface grammar with the reference program, the earned parameter sets (density/seed a visible pair, both map_rhythm boundaries always written), the explicit strategy policy — the dense demo proved the audible result is decided between the expansion and the ear, and a language that hides that choice under-tells — the not-earned list (gesture, thin, pitch/fretboard), and the seven acceptance laws under which Phase 3 adds no musical semantics. The stage doc's Phase 3 aligns; the decisions log records the strategy amendment and thin's burial. The reference program opens with the frozen integer header (swang 1) — the verdict's illustrative `swang 0.1` predates §1.1 and loses. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM --- docs/decisions.log.md | 14 +++ ...S16-swang-language-and-verified-lifting.md | 35 +++--- docs/swang/spec.md | 105 +++++++++++++++++- 3 files changed, 136 insertions(+), 18 deletions(-) diff --git a/docs/decisions.log.md b/docs/decisions.log.md index b6715172..dee09e68 100644 --- a/docs/decisions.log.md +++ b/docs/decisions.log.md @@ -1701,3 +1701,17 @@ Architectural decisions go to [`adr/`](adr/) instead. likewise deferred out of Phase 1: spec §1.10 fixes its type contract, but its cell-selection rule is unspecified, and inventing one to satisfy an acceptance checkbox would freeze semantics nobody designed. + +- 2026-07-15 — In the context of the S16 Phase 2 closure verdict (two DGD + fractal riffs judged musically: the sparse one as macro-form, the dense one + as a riff motor whose audible identity came from `RepeatVariation` holding + one template of a six-template palette), facing a `generate` construct that + would visually describe a palette the listener never hears, we decided for + **an explicit strategy policy in the Swang grammar** (`strategy auto | + `, selection-only semantics over the unchanged candidate + set) and against hiding the scheduler inside `generate`, to achieve a + language that says which reading was asked for, accepting one more required + word in every program. The same verdict keeps `gesture` a generation + parameter (its dense-demo cut was excellent but unisolated) and buries + `thin` in favour of the operation that was actually proven — seeded density + pruning, already named by `fractalize density/seed`. diff --git a/docs/stages/S16-swang-language-and-verified-lifting.md b/docs/stages/S16-swang-language-and-verified-lifting.md index 026678d0..2e34658f 100644 --- a/docs/stages/S16-swang-language-and-verified-lifting.md +++ b/docs/stages/S16-swang-language-and-verified-lifting.md @@ -358,17 +358,15 @@ the unchanged generator, reproducible from a one-line delta. ### Phase 3 — minimal Swang parser and canonical formatter -The first grammar covers only what Phases 1–2 proved useful: - -```text -pattern -ascii -fractalize -linearize -map_rhythm -generate -export -``` +The grammar covers only what the Phase 2 killer demo **audibly earned** +(spec §3, the closure verdict on #116): `pattern`, `ascii`, +`fractalize(depth, density, seed)` with density/seed a visible pair, +`linearize(traversal)`, `map_rhythm(unit, tail)`, +`generate(bars, seed, strategy, corpus)`, `export`. The **strategy policy is +explicit in the AST** — the dense demo proved the audible result is decided +between the expansion and the ear (`repeat_variation` held one template of a +six-template palette), and a language that hides that choice under-tells. +`gesture`, `thin`, pitch/fretboard transforms stay out (spec §3.4). CLI: @@ -379,13 +377,20 @@ griff swang expand riff.swg griff swang build riff.swg --output riff.mid ``` -Acceptance: +Acceptance — Phase 3 adds **no musical semantics** (the seven laws of spec +§3.5): +- a Swang program equivalent to a Phase-2 CLI command produces a + byte-identical expansion JSON (`expand` stops after `map_rhythm`); +- `fmt` is canonical and idempotent: `format(parse(text)) == + canonical_text` and `fmt(fmt(s)) == fmt(s)`; `parse(format(ast)) == ast`; +- `check` returns the same SWG codes and §1.5 location classes the + transport boundary returns today; `build` under the same seeds matches + `griff generate`; - hand-written recursive-descent parser (initial strategy per ADR-0029 §11) emitting `Vec` — pure data with spans and stable codes, - rendered only at the CLI edge; -- `fmt` is canonical and idempotent: `format(parse(text)) == canonical_text`; -- `expand` emits the same versioned artifact as Phase 2; + rendered only at the CLI edge; no defaults invented over the frozen + semantics; - parser and expansion limits gain fuzz targets (ADR-0010). ### Phase 4 — exact canonical score text and patches diff --git a/docs/swang/spec.md b/docs/swang/spec.md index 2fcbfc2b..a5228068 100644 --- a/docs/swang/spec.md +++ b/docs/swang/spec.md @@ -15,8 +15,9 @@ Status of each section: | Section | Stability | |---|---| | 1. Proposed semantic core | **Proposed; freezes at Phase 0 acceptance.** After that, changes require a new language level. | -| 2. Experimental transport syntax | Temporary Phase-2 contract; may be replaced by the grammar. | -| 3. Deferred research | No promised names, no promised semantics. | +| 2. Experimental transport syntax | Temporary Phase-2 contract; superseded by §3 once Phase 3 closes. | +| 3. Surface grammar | **Unstable until Phase 3 closes.** Records only operators that earned syntax by audible demo. | +| 4. Deferred research | No promised names, no promised semantics. | ## 1. Proposed semantic core @@ -435,7 +436,105 @@ griff generate seed.gp5 out.mid \ 16. Artifact fingerprints equal `rhythm_diagnostics` fingerprints for the same templates. -## 3. Deferred research +## 3. Surface grammar (unstable until Phase 3 closes) + +Every construct below **earned its syntax through the Phase 2 killer demo** +(the DGD fractal riffs, review verdict on #116's closure): nothing here is +speculative roster. The grammar records the semantics Phases 1–2 already +froze; Phase 3 adds no musical meaning. + +### 3.1 The reference program + +```text +swang 1 + +pattern dgd_fractal { + ascii "X.X/XX./.XX" + |> fractalize depth 1 density 9500bps seed 4 + |> linearize snake + |> map_rhythm unit 1/16 tail rest_pad + |> generate { + bars 8 + seed 42 + strategy repeat_variation + corpus "corpus" + } + |> export midi "dgd_fractal_dense.mid" +} +``` + +(The header is the frozen §1.1 integer level — `swang 1` — not a dotted +version; the verdict's illustrative `swang 0.1` predates §1.1 and loses.) + +### 3.2 Operators and their earned parameters + +- `ascii ""` — the §1.6/§2.1 kernel literal, same characters, same + typed errors. +- `fractalize depth [density bps seed ]` — §1.7/§1.8. Density + and seed are a **visible pair**: naming one without the other is a parse + error (`SWG0303` for a missing seed), and there is no implicit seed — + determinism was paid for in several PRs and a fair number of human nerve + cells. The `bps` suffix is mandatory; no bare or decimal densities. +- `linearize ` — `row_major | snake`, always explicit (§1.9). +- `map_rhythm unit tail ` — both boundaries always + written (§1.11); no defaults exist to omit. +- `generate { bars seed strategy [corpus ""] }` — + the S6 pass through the shared compiler with the explicit rhythm override + (§1.12). Corpus contents are a declared semantic dependency of the run. +- `export midi ""` — the output edge. + +### 3.3 The strategy policy is explicit — the verdict's amendment + +The dense demo proved that the audible result is decided *between* the +expansion and the ear: `RepeatVariation` held the first template and the +listener never heard the six-template palette the program visually +described. A language that hides that choice is under-telling. Therefore: + +```text +strategy auto +strategy rhythm_copy | motif_transpose | constrained_walk + | shuffle_motifs | repeat_variation +``` + +- `auto` — the reranked winner across all strategies (today's behavior). +- A named strategy selects the **top-ranked candidate of that strategy** + from the same candidate set — selection semantics only; the set, the + seeds, and the reranker stay untouched. +- The four per-bar strategies rotate the palette; `repeat_variation` holds + its first template — the program says which reading you asked for. +- Group policies (e.g. "any rotating strategy") are deferred until asked + for by a real program. + +### 3.4 What did **not** earn syntax + +Per the same verdict: `gesture` (a generation-subsystem parameter and +artifact metadata, not language semantics — its dense-demo cut was excellent +but unisolated), pitch/harmony transforms, fretboard operators, `thin` (the +proven operation is *seeded density pruning*, which `fractalize density/seed` +already names — the language must not pre-create a vaguer abstraction), +morph/crossover, and any DGD-specific macros. + +### 3.5 Phase 3 acceptance laws + +Phase 3 adds **no musical semantics**. It closes only when: + +1. the Swang program equivalent to a Phase-2 CLI command produces a + **byte-identical** expansion JSON; +2. `fmt(fmt(source)) == fmt(source)`; +3. `parse(format(ast)) == ast`; +4. `check` returns the same `SWG` codes and the same §1.5 location classes + the transport boundary returns today; +5. `build` under the same seeds produces the same result as the existing + `griff generate`; +6. the strategy policy is present in the AST explicitly; +7. the parser and formatter invent **no defaults** on top of the frozen + semantics. + +CLI: `griff swang check | fmt | expand | build` — `expand` stops after +`map_rhythm` and emits the same canonical expansion JSON Phase 2 already +emits; `build` runs the generation strategy and the export. + +## 4. Deferred research Named without reserved syntax or promised semantics (see the S16 stage doc for admission bars): From 79d0c23e129a6eed410d048a5ef00186d8facc2a Mon Sep 17 00:00:00 2001 From: PhysShell Date: Wed, 15 Jul 2026 07:28:32 +0500 Subject: [PATCH 2/3] =?UTF-8?q?docs(swang):=20the=20program=20names=20ever?= =?UTF-8?q?y=20dependency=20=E2=80=94=20source,=20budget,=20candidates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The #117 review (comment 4976245608) caught the grammar hiding three semantic dependencies the language was built to expose: - `source` joins the generate block as a required word: the seed score supplies pitch material, range, PPQN, meter, and tempo, and a corpus supplements but never replaces it — without it, build parity was unimplementable even in theory; - `max_cells` joins fractalize and `candidates` joins generate, both required: the artifact serializes the budget and the candidate count shapes the set a named strategy selects from, so neither may hide behind a frontend courtesy default; - the program is the output's single owner — `griff swang build` takes no output flag, so a path can never have two masters. The seven laws sharpen accordingly: parity law 1 is scoped to the canonical subset (the transport's inert seed-without-density is deliberately unexpressible and claims no parity); law 4 keeps SWG-code parity but assigns locations by §1.5 layer — source spans for syntax/transport, NodePath for structural, the flag class retiring with the transport; law 5 splits by policy — auto matches griff generate, a named strategy selects the first ranked candidate of that strategy from the unchanged, already-ranked set. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM --- ...S16-swang-language-and-verified-lifting.md | 2 +- docs/swang/spec.md | 60 ++++++++++++++----- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/docs/stages/S16-swang-language-and-verified-lifting.md b/docs/stages/S16-swang-language-and-verified-lifting.md index 2e34658f..9a83512f 100644 --- a/docs/stages/S16-swang-language-and-verified-lifting.md +++ b/docs/stages/S16-swang-language-and-verified-lifting.md @@ -374,7 +374,7 @@ CLI: griff swang check riff.swg griff swang fmt riff.swg griff swang expand riff.swg -griff swang build riff.swg --output riff.mid +griff swang build riff.swg ``` Acceptance — Phase 3 adds **no musical semantics** (the seven laws of spec diff --git a/docs/swang/spec.md b/docs/swang/spec.md index a5228068..6987246e 100644 --- a/docs/swang/spec.md +++ b/docs/swang/spec.md @@ -450,12 +450,14 @@ swang 1 pattern dgd_fractal { ascii "X.X/XX./.XX" - |> fractalize depth 1 density 9500bps seed 4 + |> fractalize depth 1 max_cells 4096 density 9500bps seed 4 |> linearize snake |> map_rhythm unit 1/16 tail rest_pad |> generate { + source "corpus/Dance Gavin Dance - The Robot With Human Hair Part 2.gp5" bars 8 seed 42 + candidates 2 strategy repeat_variation corpus "corpus" } @@ -466,22 +468,39 @@ pattern dgd_fractal { (The header is the frozen §1.1 integer level — `swang 1` — not a dotted version; the verdict's illustrative `swang 0.1` predates §1.1 and loses.) +A program names **every semantic dependency of its run**: the seed score +(`source` — pitch material, range, PPQN, meter, tempo all come from it; a +corpus supplements rhythm references, novelty, and gesture but never +replaces it), every budget, and every count that shapes the candidate set. +The language was built against hidden dependencies; it does not get to keep +one for itself. + ### 3.2 Operators and their earned parameters - `ascii ""` — the §1.6/§2.1 kernel literal, same characters, same typed errors. -- `fractalize depth [density bps seed ]` — §1.7/§1.8. Density - and seed are a **visible pair**: naming one without the other is a parse - error (`SWG0303` for a missing seed), and there is no implicit seed — +- `fractalize depth max_cells [density bps seed ]` — + §1.7/§1.8. The cell budget is **required**: the library has no default and + the language invents none (§3.5 law 7); the Phase-2 CLI's 4096 was a + frontend courtesy the grammar does not inherit. Density and seed are a + **visible pair**: naming one without the other is a parse error + (`SWG0303` for a missing seed), and there is no implicit seed — determinism was paid for in several PRs and a fair number of human nerve cells. The `bps` suffix is mandatory; no bare or decimal densities. - `linearize ` — `row_major | snake`, always explicit (§1.9). - `map_rhythm unit tail ` — both boundaries always written (§1.11); no defaults exist to omit. -- `generate { bars seed strategy [corpus ""] }` — - the S6 pass through the shared compiler with the explicit rhythm override - (§1.12). Corpus contents are a declared semantic dependency of the run. -- `export midi ""` — the output edge. +- `generate { source "" bars seed candidates + strategy [corpus ""] }` — the S6 pass through the shared + compiler with the explicit rhythm override (§1.12). `source` is the seed + score and is **required** — it supplies the pitch material, range, PPQN, + meter, and tempo, exactly as `griff generate`'s INPUT does today. + `candidates` (variants per strategy) is **required** — it shapes the set + a named strategy selects from, so it may not hide. Corpus contents, when + given, are a declared semantic dependency of the run. +- `export midi ""` — the output edge. **The program is the output's + single owner**: `griff swang build` takes no output flag, so a path can + never have two masters. ### 3.3 The strategy policy is explicit — the verdict's amendment @@ -519,20 +538,31 @@ morph/crossover, and any DGD-specific macros. Phase 3 adds **no musical semantics**. It closes only when: 1. the Swang program equivalent to a Phase-2 CLI command produces a - **byte-identical** expansion JSON; + **byte-identical** expansion JSON — scoped to the **canonical subset** + of the Phase-2 transport that the grammar can express. (The transport + tolerates an inert `--rhythm-seed` without density, because the seed + only requires the kernel; the grammar deliberately rejects that form as + non-canonical, so no parity is claimed for it.); 2. `fmt(fmt(source)) == fmt(source)`; 3. `parse(format(ast)) == ast`; -4. `check` returns the same `SWG` codes and the same §1.5 location classes - the transport boundary returns today; -5. `build` under the same seeds produces the same result as the existing - `griff generate`; +4. `check` returns the same `SWG` **codes**, with locations following + §1.5's classes *by layer*: syntax- and transport-class errors carry a + **source span** (the flag-class location is a Phase-2 artifact and + retires with the transport), structural errors keep their `NodePath`; +5. `build` parity is split by policy: under `strategy auto` and the same + seeds it produces the same result as the existing `griff generate`; + under a named strategy it selects the **first ranked candidate of that + strategy from the unchanged, already-ranked set** — selection only, + never a re-generation; 6. the strategy policy is present in the AST explicitly; 7. the parser and formatter invent **no defaults** on top of the frozen - semantics. + semantics — which is why `max_cells`, `source`, and `candidates` are + required words, not optional ones. CLI: `griff swang check | fmt | expand | build` — `expand` stops after `map_rhythm` and emits the same canonical expansion JSON Phase 2 already -emits; `build` runs the generation strategy and the export. +emits; `build` runs the generation strategy and the program's own `export` +(no output flag exists). ## 4. Deferred research From 7e051c41eeaef0e28f2f3cb84abe6bfc90f5aa61 Mon Sep 17 00:00:00 2001 From: PhysShell Date: Wed, 15 Jul 2026 07:52:36 +0500 Subject: [PATCH 3/3] docs(stages): S16 Phase 3 stops contradicting its own spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stage summary still described the pre-verdict contract: fractalize without its required max_cells, generate without source and candidates, an unconditional expansion parity, the retired flag location class, and one undivided build parity. spec.md §3 had already moved on; the stage doc now mirrors it — canonical-subset parity, layered locations, auto/named parity split, and the three required words named as such. The L1 sketch also stops pairing density with no seed. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM --- ...S16-swang-language-and-verified-lifting.md | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/docs/stages/S16-swang-language-and-verified-lifting.md b/docs/stages/S16-swang-language-and-verified-lifting.md index 9a83512f..c6a65ebd 100644 --- a/docs/stages/S16-swang-language-and-verified-lifting.md +++ b/docs/stages/S16-swang-language-and-verified-lifting.md @@ -99,9 +99,9 @@ pattern seed = ascii { } rhythm r = seed - |> fractalize(depth = 2, density_bps = 8000, budget = 512) + |> fractalize(depth = 2, max_cells = 512, density_bps = 8000, seed = 17) |> linearize(snake) - |> map_rhythm(unit = 1/16) + |> map_rhythm(unit = 1/16, tail = rest_pad) ``` (The produced palette's bar count is a property of the expansion; how many @@ -360,9 +360,15 @@ the unchanged generator, reproducible from a one-line delta. The grammar covers only what the Phase 2 killer demo **audibly earned** (spec §3, the closure verdict on #116): `pattern`, `ascii`, -`fractalize(depth, density, seed)` with density/seed a visible pair, -`linearize(traversal)`, `map_rhythm(unit, tail)`, -`generate(bars, seed, strategy, corpus)`, `export`. The **strategy policy is +`fractalize(depth, max_cells, density, seed)` — the cell budget is a +**required word** (the library ships no default and the language invents +none) and density/seed stay a visible pair — `linearize(traversal)`, +`map_rhythm(unit, tail)`, +`generate(source, bars, seed, candidates, strategy, corpus)` — `source` +(the seed score: pitch material, range, PPQN, meter, tempo) and +`candidates` are **required words** too; a program names every semantic +dependency of its run — and `export`, the output's **single owner** +(`griff swang build` takes no output flag). The **strategy policy is explicit in the AST** — the dense demo proved the audible result is decided between the expansion and the ear (`repeat_variation` held one template of a six-template palette), and a language that hides that choice under-tells. @@ -381,16 +387,26 @@ Acceptance — Phase 3 adds **no musical semantics** (the seven laws of spec §3.5): - a Swang program equivalent to a Phase-2 CLI command produces a - byte-identical expansion JSON (`expand` stops after `map_rhythm`); + byte-identical expansion JSON (`expand` stops after `map_rhythm`) — + scoped to the **canonical transport subset** the grammar can express: + the transport's inert `--rhythm-seed` without density is deliberately + unexpressible, and no parity is claimed for it; - `fmt` is canonical and idempotent: `format(parse(text)) == canonical_text` and `fmt(fmt(s)) == fmt(s)`; `parse(format(ast)) == ast`; -- `check` returns the same SWG codes and §1.5 location classes the - transport boundary returns today; `build` under the same seeds matches - `griff generate`; +- `check` returns the same SWG **codes**, with locations layered per §1.5: + syntax- and transport-class errors carry a **source span** (the Phase-2 + flag location class retires with the transport), structural errors keep + their `NodePath`; +- `build` parity is split by strategy policy: under `strategy auto` and + the same seeds it matches the existing `griff generate`; under a named + strategy it selects the first ranked candidate of that strategy from + the unchanged, already-ranked set — selection only, never a + re-generation; - hand-written recursive-descent parser (initial strategy per ADR-0029 §11) emitting `Vec` — pure data with spans and stable codes, rendered only at the CLI edge; no defaults invented over the frozen - semantics; + semantics — which is why `max_cells`, `source`, and `candidates` are + required words, not optional ones; - parser and expansion limits gain fuzz targets (ADR-0010). ### Phase 4 — exact canonical score text and patches