Skip to content

Commit 996812f

Browse files
authored
Merge pull request #9 from sonicfieldlabs/agent/sonic-matter-stack-v0.4.0
Release GERM 0.4.0 with the Sonic Matter Stack alignment
2 parents 3cbe200 + 0cd020d commit 996812f

22 files changed

Lines changed: 954 additions & 46 deletions

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ GERM_OIDA_TIMEOUT_SECONDS=1800
6262

6363
# Optional local Cosmoaudition System bridge. Germ accepts only an HTTP
6464
# loopback URL and never contacts astronomical, geological, weather, or other
65-
# observatory providers itself.
65+
# observation providers itself.
6666
GERM_COSMOAUDITION_URL=http://127.0.0.1:8797
6767
GERM_COSMOAUDITION_TIMEOUT_SECONDS=20
6868
GERM_COSMOAUDITION_MAX_RESPONSE_BYTES=2097152

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ apps/macos/dist/
2424
apps/germ.app/
2525
.codex/
2626

27+
# Local tool caches and state
28+
.uv-cache/
29+
.uv-tools/
30+
.playwright-cli/
31+
2732
/*.png
2833
/*.jpg
2934
/*.jpeg

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
11
# Changelog
22

3+
## 0.4.0 — Sonic Matter Stack alignment
4+
5+
- **Fixed a MASA protocol break.** Every sidecar cited
6+
`smo.sonicfield.org`, a pre-release identifier root. `$schema` is a protocol
7+
constant rather than a hint, so the published MASA 0.1.0 validator rejected
8+
every record GERM had ever written. Records now cite
9+
`masa.sonicfield.org` and validate against the released reference
10+
implementation.
11+
- **Fixed a silent modulation bug.** A zero mapping amount was scaled through
12+
instead of read as the operator turning a route off. On a reversed output
13+
range such as `(760, 180)` that emits `outputRange[0]` — the strongest value
14+
the mapping can produce — reported as `applied`. Silence requested, maximum
15+
delivered. A zero amount is now `skipped` / `route-disabled`, matching
16+
Cosmoaudition's own engine.
17+
- Added the MASA processing layer to the Micro modules. Each declares a
18+
granular or spectral operation in MASA's engine-neutral terms and can emit a
19+
portable `masa-processing-request` via `POST /micro/processing-request`;
20+
`GET /micro/processing-operations` reports the mapping. GERM states the
21+
intention and binds no DSP library.
22+
- Added the Cosmoaudition modulation framework. The bridge allowlist now covers
23+
`/api/modulation`, `/api/frame`, and `/api/snapshot/masa`, and
24+
`GET /cosmoaudition/frame` resolves one verified `cosmo/modulation/v0.1`
25+
frame into GERM routes. It reads the frame's `controls`, never the bare
26+
`values` map, so a value never travels without the decision that produced it;
27+
withheld routes and emitted absences are reported rather than dropped.
28+
`/api/stream` stays unbridged because Server-Sent Events cannot be read by a
29+
bounded request/response client.
30+
- Added `uncertaintyOutput` to Cosmoaudition mappings, so a `map-uncertainty`
31+
policy emits its declared value under an `uncertainty` status instead of
32+
degrading silently to `skip`. Declaring the policy without the value is now
33+
refused at the schema boundary.
34+
- Named GERM's place in the **Sonic Matter Stack** alongside the Listening
35+
Stack, and retired the earlier "Observatory" naming across the server,
36+
dashboard, documentation, and module labels.
37+
338
## 0.3.3 — Additive cultivation lineage
439

540
- Raised the Earworm/Akousma floor to 0.6.1 so remembered generations cannot

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ authors:
55
- family-names: "Isaza"
66
given-names: "eme"
77
affiliation: "Sonic Field Labs"
8-
version: "0.3.3"
9-
date-released: "2026-08-03"
8+
version: "0.4.0"
9+
date-released: "2026-08-07"
1010
license: "MPL-2.0"
1111
repository-code: "https://github.com/sonicfieldlabs/germ"
1212
abstract: "germ is a local generative microsound environment whose generated sounds retain prompts, parents, mutations, listening metadata, and Earworm-compatible lineage."

CONTRIBUTING.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ provider accountability, safety, accessibility, or reproducibility.
2323
Do not commit model weights, generated audio, uploads, credentials, `.env`
2424
files, local paths, private prompts, personal sessions, or provider responses.
2525

26+
Commit messages describe the change and its reason in plain prose. Never add
27+
`Co-Authored-By` lines or any AI attribution trailer: no assistant, tool, or
28+
model is listed as an author, co-author, or contributor. Commits carry the
29+
human author's identity only.
30+
2631
## Contracts to Preserve
2732

2833
- Cloud egress remains explicit, opt-in, and documented.

README.md

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ listened to, and traced through lineage. A listening from Oída can become a
88
prompt or source in GERM; a successful render can become a descendant in
99
Akousmata and return to Oída for another listening.
1010

11-
Current release: `0.3.3`.
11+
Current release: `0.4.0`.
12+
13+
GERM is part of two Sonic Field Labs constellations: it cultivates within
14+
[The Listening Stack](https://sonicfield.org/stack) and describes its material
15+
through the [Sonic Matter Stack](#sonic-matter-stack-integration), whose
16+
protocol boundary is MASA 0.1.0.
1217

1318
GERM is an independent Sonic Field Labs project. It can use Stable Audio 3
1419
providers, but it is not an official Stability AI product.
@@ -122,22 +127,56 @@ promising one universal hardware minimum.
122127
All three scales use the same module graph, semantic FX bridge, sessions,
123128
library, and lineage model.
124129

125-
## Sonic Matter Observatory integration
130+
## Sonic Matter Stack integration
126131

127-
GERM keeps the Observatory components distinct while making their contracts
128-
usable inside the cultivation graph:
132+
GERM belongs to two constellations. The Listening Stack is how a sound is
133+
heard, remembered, and re-listened; the **Sonic Matter Stack** is how sound is
134+
described *as matter* — its provenance, its measurements, its granular and
135+
spectral operations, and the observations that modulate it. GERM keeps those
136+
components distinct while making their contracts usable inside the cultivation
137+
graph:
129138

130-
| Component | Boundary in GERM |
131-
| --- | --- |
132-
| MASA 0.1 | Optional descriptive JSON sidecars under `output/masa/`; never replaces Sonic Lineage or changes a successful render into a failure. |
133-
| MATERIA | Matter Analysis provides a bounded local analyzer informed by the shared measured / inferred / unavailable distinction; it is not a claim of listening. |
134-
| Cosmoaudition System | A loopback-only, response-bounded HTTP bridge reads snapshots and source status. GERM never contacts observatory providers directly. |
139+
| Component | Version / contract | Boundary in GERM |
140+
| --- | --- | --- |
141+
| [MASA](https://github.com/sonicfieldlabs/MASA) | 0.1.0 (MIT) | Optional descriptive JSON sidecars under `output/masa/`, citing the published canonical schema at `masa.sonicfield.org`. They never replace Sonic Lineage or turn a successful render into a failure. |
142+
| MASA Processing | `masa-processing-request` 0.1.0 | Every Micro module declares a granular or spectral operation in MASA's engine-neutral terms. GERM states the intention and binds no DSP library. |
143+
| MATERIA || Matter Analysis provides a bounded local analyzer informed by the shared measured / inferred / unavailable distinction; it is not a claim of listening. |
144+
| [Cosmoaudition](https://github.com/sonicfieldlabs/cosmoaudition) | `cosmo/modulation/v0.1` | A loopback-only, response-bounded HTTP bridge reads source status, snapshots, and modulation frames. GERM never contacts observation providers directly. |
145+
146+
### Micro modules as MASA processing operations
147+
148+
MASA 0.1.0 carries Roads's granular vocabulary as a protocol layer, so a Micro
149+
module can say what it wants done to matter without naming an engine:
150+
151+
| Micro module | Operation | Character |
152+
| --- | --- | --- |
153+
| Grain Culture | `matter.granulate` | Quasi-synchronous emission at the perceptible grain. |
154+
| Particle Engine | `matter.granulate` | Dense asynchronous emission, expodec envelopes. |
155+
| Quanta | `matter.granulate` | The millisecond threshold where a grain stops being a small note and becomes a particle. |
156+
| Cell Splitter / Colony | `matter.fragment` | Transient-led and grain-led division. |
157+
| Spectral Tissue / Membrane | `matter.extract` | Spectral strata and bands. |
158+
| Microscope | `matter.reduce` | Spectral peaks retained for inspection. |
159+
| Metabolism | `matter.timestretch` | Duration change with declared transient handling. |
160+
| Swarm | `matter.pitchshift` | Transposition with declared formant handling. |
161+
162+
`GET /micro/processing-operations` reports the mapping; `POST
163+
/micro/processing-request` builds a portable request. A request is an
164+
intention, not a receipt: it asserts nothing about what was rendered or heard.
165+
166+
### Modulation
135167

136168
Cosmoaudition mappings are operator-authored control relations. They do not
137169
claim that a dataset is the literal voice or identity of a source. Missing or
138170
unfetched observations do not silently become zero or a neutral modulation;
139171
the route remains inactive until its state is explicit.
140172

173+
`GET /cosmoaudition/frame` reads one modulation frame and resolves it into
174+
GERM routes. It reads the frame's `controls`, never its bare `values` map:
175+
a value arrives with the decision that produced it, or it does not arrive.
176+
Withheld routes and emitted absences are reported rather than dropped. Server-
177+
Sent Events are deliberately not bridged, because this bridge is a bounded
178+
request/response client; poll `/cosmoaudition/frame` instead.
179+
141180
## Listening Stack integration
142181

143182
**Oída hears. GERM cultivates. Akousmata remembers. AKOÚŌ structures. Earworm

apps/macos/script/build_and_run.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ APP_NAME="germ"
66
EXECUTABLE_NAME="germ-macos"
77
BUNDLE_ID="org.sonicfield.germ"
88
MIN_SYSTEM_VERSION="13.0"
9-
MARKETING_VERSION="0.3.3"
10-
BUNDLE_VERSION="5"
9+
MARKETING_VERSION="0.4.0"
10+
BUNDLE_VERSION="6"
1111

1212
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
1313
# Keep the runnable bundle where repository users expect to find apps. The

dashboard/static/app.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ const FX_MODULES = {
776776
microscope: { label: "Microscope", description: "Inspect transients, partials, density, and grain behavior" },
777777
matter_analysis: { label: "Matter Analysis", description: "Measure spectral, temporal, spatial, and inferred material qualities without altering audio" },
778778
incubator: { label: "Incubator", description: "Slowly evolve a sound population over time" },
779-
cosmo_matter_modulator: { label: "Matter Modulator", description: "Route observatory control into granular, spectral, and temporal sound-matter processing" },
779+
cosmo_matter_modulator: { label: "Matter Modulator", description: "Route observation control into granular, spectral, and temporal sound-matter processing" },
780780
loop_doctor: { label: "Loop Doctor", description: "Loop detection, seam repair, and cyclic export" },
781781
space: { label: "Space", description: "Simple reverb modes" },
782782
echo: { label: "Echo", description: "Delay modes and feedback" },
@@ -1005,7 +1005,7 @@ const FX_SEMANTIC_PROFILES = {
10051005
},
10061006
cosmo_matter_modulator: {
10071007
family: "cosmoaudition",
1008-
prompt: ({ params }) => `observatory-shaped sound matter, ${Number(params.density ?? 0.5) > 0.6 ? "dense" : "open"} material pulses, bounded planetary modulation`,
1008+
prompt: ({ params }) => `observation-shaped sound matter, ${Number(params.density ?? 0.5) > 0.6 ? "dense" : "open"} material pulses, bounded planetary modulation`,
10091009
negative: () => "literal one-to-one data sonification, source identity claim",
10101010
generation: ({ params, amount }) => ({
10111011
inpaintDensity: Number(params.density ?? 0.5) * 0.18 * amount,
@@ -3774,7 +3774,7 @@ function modulatorLabel(modulatorType) {
37743774
audio_to_control: "Audio-to-Control",
37753775
gesture_recorder: "Gesture Recorder",
37763776
macro_modulator: "Macro",
3777-
cosmo_observation: "Observatory Source",
3777+
cosmo_observation: "Observation Source",
37783778
cosmo_cosmic_field: "Cosmic Field",
37793779
cosmo_earth_field: "Earth Field",
37803780
cosmo_biosphere_field: "Biosphere Field",
@@ -4419,7 +4419,7 @@ async function refreshCosmoauditionNode(nodeId, { archive = false } = {}) {
44194419
const index = canvasNodes.findIndex((item) => item.id === nodeId);
44204420
const node = normalizeModulatorNode(canvasNodes[index]);
44214421
if (!node || !COSMOAUDITION_MODULATOR_TYPES.has(node.modulatorType)) return;
4422-
beginWork(archive ? "Archiving Observation" : "Reading Observatory", node.label);
4422+
beginWork(archive ? "Archiving Observation" : "Reading Observation", node.label);
44234423
try {
44244424
let payload;
44254425
let archiveId = node.config?.archiveId || "";
@@ -4516,7 +4516,7 @@ async function refreshCosmoauditionNode(nodeId, { archive = false } = {}) {
45164516
canvasNodes[index] = node;
45174517
canvasSaveState();
45184518
renderCanvas();
4519-
finishWork("Observatory Unavailable", "bad", node.config.status);
4519+
finishWork("Observation Unavailable", "bad", node.config.status);
45204520
}
45214521
}
45224522

@@ -9905,7 +9905,7 @@ function canvasModulatorNodeMarkup(node, selected, style) {
99059905
audio_to_control: "Audio features become generation controls.",
99069906
gesture_recorder: "Recorded movement for generation values.",
99079907
macro_modulator: "Manual control source.",
9908-
cosmo_observation: "Project-neutral local observatory signal source.",
9908+
cosmo_observation: "Project-neutral local observation signal source.",
99099909
cosmo_cosmic_field: "Cosmic observations as bounded control material.",
99109910
cosmo_earth_field: "Atmospheric and geological observations as bounded control material.",
99119911
cosmo_biosphere_field: "Species and biosphere observations as bounded control material.",

dashboard/static/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,9 +733,9 @@ <h3>Microsound Modules</h3>
733733
</section>
734734
<section class="canvas-source-panel cosmoaudition-source-panel" data-source-panel="cosmoaudition" aria-label="Cosmoaudition modules" hidden>
735735
<p class="canvas-source-panel-note">Observations become attributed, bounded control material through authored mappings—not claims that data is a source's literal voice.</p>
736-
<button class="source-tool-card" type="button" title="Observatory Source" aria-label="Add Observatory Source" data-action="canvas-source-option" data-source="modulator" data-modulator="cosmo_observation">
736+
<button class="source-tool-card" type="button" title="Observation Source" aria-label="Add Observation Source" data-action="canvas-source-option" data-source="modulator" data-modulator="cosmo_observation">
737737
<span class="source-tool-icon"><svg class="source-tool-svg" viewBox="0 0 24 24" aria-hidden="true"><use href="#sourceIconEcology"></use></svg></span>
738-
<strong class="source-tool-title">Observatory Source</strong>
738+
<strong class="source-tool-title">Observation Source</strong>
739739
<span class="source-tool-desc">Read a bounded local observation snapshot.</span>
740740
</button>
741741
<button class="source-tool-card" type="button" title="Cosmic Field" aria-label="Add Cosmic Field" data-action="canvas-source-option" data-source="modulator" data-modulator="cosmo_cosmic_field">

docs/germ_micro_architecture.md

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ categories:
7070

7171
| Module | Role |
7272
| --- | --- |
73-
| Observatory Source | Reads one bounded local snapshot. |
73+
| Observation Source | Reads one bounded local snapshot. |
7474
| Cosmic Field | Selects `cosmos` observations. |
7575
| Earth Field | Selects atmospheric and geological observations. |
7676
| Biosphere Field | Selects biosphere observations. |
@@ -81,11 +81,22 @@ categories:
8181
| Semantic Field | Relates a normalized value to attributed descriptive context. |
8282
| Uncertainty Field | Makes confidence, staleness, and source error available as control. |
8383
| Observation Archive | Replays a bounded local observation with provenance. |
84-
| Matter Modulator | Applies observatory-routed control to granular and spectral matter parameters. |
84+
| Matter Modulator | Applies observation-routed control to granular and spectral matter parameters. |
8585

8686
GERM connects only to the separate Cosmoaudition System on an explicit HTTP
8787
loopback URL. It accepts no redirects, proxies only allowlisted routes, ignores
88-
environment proxies, and caps the response body. Provider credentials and
88+
environment proxies, and caps the response body. The allowlist covers
89+
`/health`, `/api/sources`, `/api/snapshot`, `/api/snapshot/masa`,
90+
`/api/modulation`, and `/api/frame`. `/api/stream` is deliberately excluded:
91+
it is Server-Sent Events, and this bridge is a bounded request/response client
92+
that reads a complete body and closes.
93+
94+
A modulation frame is verified against the contract it claims —
95+
`cosmo/modulation/v0.1` — before it is read. `GET /cosmoaudition/frame`
96+
resolves one frame into GERM routes using its `controls`, never the bare
97+
`values` map that exists for transports carrying only numbers. Using that map
98+
would turn a skipped route into a real zero. Withheld routes and emitted
99+
absences travel in the response instead of disappearing from it. Provider credentials and
89100
astronomical, geological, weather, biosphere, human, or machine APIs remain on
90101
the Cosmoaudition side of the boundary.
91102

@@ -95,6 +106,38 @@ clocked routes. Mapping receipts retain signal, source, confidence,
95106
epistemic status, temporal character, mapping status, and the statement that
96107
the relation is authored rather than a source-identity claim.
97108

109+
## MASA processing layer
110+
111+
MASA 0.1.0 carries the granular and spectral vocabulary as a protocol layer, so
112+
a Micro module can state what it wants done to matter without naming a DSP
113+
engine. Each module declares one operation:
114+
115+
| Module | MASA operation |
116+
| --- | --- |
117+
| Grain Culture, Particle Engine, Quanta | `matter.granulate` |
118+
| Cell Splitter, Colony | `matter.fragment` |
119+
| Spectral Tissue, Membrane | `matter.extract` |
120+
| Microscope | `matter.reduce` |
121+
| Metabolism | `matter.timestretch` |
122+
| Swarm | `matter.pitchshift` |
123+
124+
The parameters are the module's own character rather than one shared default.
125+
Quanta works between one and ten milliseconds, where a grain stops being a
126+
small note and becomes a particle and the envelope dominates what is heard;
127+
Grain Culture cultivates at the perceptible grain with quasi-synchronous
128+
emission; Particle Engine is dense asynchronous emission. Spectral Tissue reads
129+
strata rather than a single band.
130+
131+
`GET /micro/processing-operations` reports the mapping. `POST
132+
/micro/processing-request` builds a portable `masa-processing-request`, merging
133+
operation floor, module character, and authored parameters in that order so a
134+
partial override cannot drop a sibling the contract still requires.
135+
136+
A processing request is an intention, not a receipt. It carries no `$schema`
137+
member, because the request schema declares none and forbids what it does not
138+
declare. It asserts nothing about what was rendered, and nothing about what was
139+
heard — audition remains outside this boundary.
140+
98141
## Persisted Control Contracts
99142

100143
Two backend contracts now make the conceptual layer reusable outside the dashboard:

0 commit comments

Comments
 (0)