diff --git a/README.md b/README.md index ea51573..837d9ed 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,11 @@ keys, DSP source artifacts, manifests, and compiled products. Engine callers keep their device and scheduling code, and ask AquaSynth for compiled/renderable synth products. +As a Verse service, AquaSynth accepts `.aqua` DSL and Weksa utterance handoff +documents, compiles Faust-native instruments, returns live instrument handles, +and exposes control/sample state through CultMesh/Eve. See +[`docs/verse-service-contract.md`](docs/verse-service-contract.md). + See [`docs/faust-toolchain-boundary.md`](docs/faust-toolchain-boundary.md). ## Status diff --git a/docs/fixtures/aquasynth-provider-advertisement.json b/docs/fixtures/aquasynth-provider-advertisement.json new file mode 100644 index 0000000..ea5497a --- /dev/null +++ b/docs/fixtures/aquasynth-provider-advertisement.json @@ -0,0 +1,240 @@ +{ + "schema": "gamecult.eve.provider_advertisement.v1", + "providerId": "aquasynth.service", + "title": "AquaSynth Service", + "description": "AquaSynth accepts .aqua DSL and Weksa utterance handoffs, compiles Faust-native instruments, returns live instrument handles, and publishes controllable synth state through CultMesh/Eve.", + "mode": "fixture-read-only", + "serviceVerse": { + "id": "verse.aquasynth.service.v1", + "cultMeshKey": "aquasynth.service/provider-advertisement", + "authority": "AquaSynth daemon identity, schema catalog, provider publication, and synth runtime boundary", + "owns": [ + ".aqua patch parsing", + "patch graph semantics", + "Faust source emission", + "native Faust compilation", + "compiled instrument handles", + "live control sessions", + "sample/render receipts", + "learned utterance embeddings and synth-driver controls" + ], + "doesNotOwn": [ + "Weksa conversational intent", + "Persona canonical state", + "Eve presentation runtime" + ] + }, + "nestedVerses": [ + { + "id": "aquasynth.patch", + "kind": "patch", + "cultMeshKey": "aquasynth.patch/current", + "authority": "AquaSynth.Core .aqua parser and patch graph model", + "schemas": [ + "aquasynth.patch_graph.v0" + ] + }, + { + "id": "aquasynth.compile", + "kind": "compile", + "cultMeshKey": "aquasynth.compile/jobs", + "authority": "AquaSynth.Faust compiler boundary", + "schemas": [ + "aquasynth.faust_source.v0", + "aquasynth.compiled_instrument.v0" + ] + }, + { + "id": "aquasynth.instrument", + "kind": "instrument", + "cultMeshKey": "aquasynth.instrument/sessions", + "authority": "AquaSynth native host and control-session owner", + "schemas": [ + "aquasynth.instrument_handle.v0", + "aquasynth.control_session.v0" + ] + }, + { + "id": "aquasynth.speech", + "kind": "speech", + "cultMeshKey": "aquasynth.speech/current", + "authority": "AquaSynth utterance embedding and synth-driver runtime", + "schemas": [ + "aquasynth.utterance_embedding.v0", + "aquasynth.speech_render_receipt.v0" + ] + }, + { + "id": "aquasynth.operator", + "kind": "operator", + "cultMeshKey": "aquasynth.operator/status", + "authority": "AquaSynth daemon runtime", + "schemas": [ + "aquasynth.operator_state.v0", + "gamecult.eve.surface.v1" + ] + } + ], + "schemaWitnessFamilies": [ + { + "family": "patch", + "namespace": "aquasynth.patch.*", + "witnesses": [ + "aquasynth.patch_graph.v0" + ], + "durableShape": ".aquasynth/patches/{patchId}.cc" + }, + { + "family": "compile", + "namespace": "aquasynth.compile.*", + "witnesses": [ + "aquasynth.faust_source.v0", + "aquasynth.compiled_instrument.v0" + ], + "durableShape": ".aquasynth/faust/{compileId}.cc" + }, + { + "family": "instrument", + "namespace": "aquasynth.instrument.*", + "witnesses": [ + "aquasynth.instrument_handle.v0", + "aquasynth.control_session.v0" + ], + "durableShape": ".aquasynth/sessions/{sessionId}.cc" + }, + { + "family": "render", + "namespace": "aquasynth.render.*", + "witnesses": [ + "aquasynth.render_sample.v0", + "aquasynth.render_loss.v0" + ], + "durableShape": ".aquasynth/renders/{renderId}.cc" + }, + { + "family": "speech", + "namespace": "aquasynth.speech.*", + "witnesses": [ + "aquasynth.utterance_embedding.v0", + "aquasynth.speech_render_receipt.v0" + ], + "durableShape": ".aquasynth/speech/{utteranceId}.cc" + }, + { + "family": "eve", + "namespace": "aquasynth.eve.*", + "witnesses": [ + "gamecult.eve.provider_advertisement.v1", + "gamecult.eve.surface.v1" + ], + "durableShape": ".aquasynth/eve-surfaces.cc" + } + ], + "cultMeshSurfaceKeys": [ + { + "id": "aquasynth.eve.patch_graph.v0", + "documentSchema": "gamecult.eve.surface.v1", + "cultMeshKey": "aquasynth.eve.surface.patch-graph", + "binds": [ + "aquasynth.patch.*", + "aquasynth.compile.*" + ], + "status": "expected-surface" + }, + { + "id": "aquasynth.eve.compile_queue.v0", + "documentSchema": "gamecult.eve.surface.v1", + "cultMeshKey": "aquasynth.eve.surface.compile-queue", + "binds": [ + "aquasynth.compile.*", + "aquasynth.operator.*" + ], + "status": "expected-surface" + }, + { + "id": "aquasynth.eve.instrument_control.v0", + "documentSchema": "gamecult.eve.surface.v1", + "cultMeshKey": "aquasynth.eve.surface.instrument-control", + "binds": [ + "aquasynth.instrument.*", + "aquasynth.render.*" + ], + "status": "expected-surface" + }, + { + "id": "aquasynth.eve.speech_training.v0", + "documentSchema": "gamecult.eve.surface.v1", + "cultMeshKey": "aquasynth.eve.surface.speech-training", + "binds": [ + "weksa.utterance.*", + "aquasynth.speech.*", + "aquasynth.render.*" + ], + "status": "expected-surface" + } + ], + "commandBoundaries": [ + { + "id": "aquasynth.command.patch.compile", + "owner": "AquaSynth", + "acceptedByFixture": false, + "allowedInputs": [ + ".aqua DSL", + "compile target", + "host architecture" + ], + "emits": [ + "aquasynth.patch_graph.v0", + "aquasynth.faust_source.v0", + "aquasynth.compiled_instrument.v0" + ] + }, + { + "id": "aquasynth.command.instrument.control", + "owner": "AquaSynth", + "acceptedByFixture": false, + "allowedInputs": [ + "instrument handle", + "semantic control values" + ], + "emits": [ + "aquasynth.control_session.v0" + ] + }, + { + "id": "aquasynth.command.instrument.sample", + "owner": "AquaSynth", + "acceptedByFixture": false, + "allowedInputs": [ + "instrument handle", + "duration", + "sample format" + ], + "emits": [ + "aquasynth.render_sample.v0" + ] + }, + { + "id": "aquasynth.command.speech.realize", + "owner": "AquaSynth", + "acceptedByFixture": false, + "allowedInputs": [ + "weksa.utterance_handoff.v0", + "weksa.utterance_embedding_handoff.v0.1" + ], + "emits": [ + "aquasynth.utterance_embedding.v0", + "aquasynth.speech_render_receipt.v0" + ], + "forbiddenTargets": [ + "Weksa conversational intent truth" + ] + } + ], + "loweringRules": [ + "AquaSynth owns learned embeddings, synth controls, Faust compilation, native binary lifetime, instrument handles, and sampled outputs.", + "Weksa owns writing-to-intent and intent-to-utterance lowering.", + "Faust source and native binaries are emitted artifacts with typed receipts, not the semantic patch owner.", + "Eve surfaces control and inspect sessions through CultMesh command documents; they do not own audio state." + ] +} diff --git a/docs/verse-service-contract.md b/docs/verse-service-contract.md new file mode 100644 index 0000000..f3fff90 --- /dev/null +++ b/docs/verse-service-contract.md @@ -0,0 +1,98 @@ +# AquaSynth Verse Service Contract + +AquaSynth is the synth daemon. It accepts `.aqua` DSL and speech/utterance +control documents, compiles Faust-native instruments, returns live instrument +handles, and publishes controllable audio/render state through CultMesh and Eve. + +## Authority + +Owner: AquaSynth. + +Inputs: + +- `.aqua` patch DSL +- `weksa.utterance_handoff.v0` +- `weksa.utterance_embedding_handoff.v0.1` +- learned phonetic realization and synth-driver model state +- render, sampling, and live-control requests + +Outputs: + +- `aquasynth.patch_graph.v0` +- `aquasynth.faust_source.v0` +- `aquasynth.compiled_instrument.v0` +- `aquasynth.instrument_handle.v0` +- `aquasynth.control_session.v0` +- `aquasynth.render_sample.v0` +- Eve/CultUI surfaces for patch graphs, compile products, live controls, and + speech-training/render status + +Weksa owns conversational intent and utterance lowering. AquaSynth owns the +learned utterance embedding, synth-driver automation, Faust compilation, native +binary lifetime, live instrument handles, control sessions, and sampled outputs. + +## CultCache Witnesses + +- `.aquasynth/provider-advertisement.cc`: read-only provider advertisement + witness. +- `.aquasynth/patches/{patchId}.cc`: parsed `.aqua` patch graphs and semantic + control catalogs. +- `.aquasynth/faust/{compileId}.cc`: emitted Faust source, compile options, + diagnostics, and artifact references. +- `.aquasynth/instruments/{instrumentId}.cc`: compiled native binary, ABI, + control catalog, architecture target, and lifecycle receipts. +- `.aquasynth/sessions/{sessionId}.cc`: live instrument handle, lease, control + values, transport state, and teardown receipt. +- `.aquasynth/renders/{renderId}.cc`: offline/live sample outputs, feature + measurements, and scoring receipts. +- `.aquasynth/speech/{utteranceId}.cc`: Weksa handoff consumption, packed + utterance embeddings, synth-driver outputs, and render receipts. + +## CultMesh Verses + +- `aquasynth.service`: service identity, version, schema catalog, and health. +- `aquasynth.patch`: `.aqua` parse/validation/graph state. +- `aquasynth.compile`: Faust emission, native compilation, diagnostics, and + artifact handles. +- `aquasynth.instrument`: compiled instrument handles, control catalogs, and + lifecycle state. +- `aquasynth.speech`: utterance embedding, speech-driver, and render-training + state. +- `aquasynth.operator`: daemon status, queue pressure, toolchain readiness, + witness freshness, and degraded-mode visibility. + +## Eve Surfaces + +- `aquasynth.eve.patch_graph.v0`: inspect parsed `.aqua` graphs and semantic + control catalogs. +- `aquasynth.eve.compile_queue.v0`: inspect Faust compile jobs, diagnostics, + native binary handles, and failures. +- `aquasynth.eve.instrument_control.v0`: control a live instrument handle like + an instrument, with stable parameters, ranges, and session leases. +- `aquasynth.eve.speech_training.v0`: inspect Weksa handoffs, packed utterance + embeddings, synth-driver output, render loss, and sample receipts. +- `aquasynth.eve.operator.v0`: compact daemon state, toolchain status, queues, + and witness freshness. + +## Commands + +- `patch.compile`: parse `.aqua`, emit Faust, compile a native target, and + return an instrument handle. +- `instrument.open`: allocate or attach to a compiled instrument session. +- `instrument.control`: set one or more stable semantic controls. +- `instrument.sample`: sample a live or offline instrument output. +- `speech.realize`: consume a Weksa utterance handoff and produce synth-driver + controls plus render receipts. +- `provider.advertise`: publish `gamecult.eve.provider_advertisement.v1`. + +Every command must commit typed receipts through the same derivation path used +by any CLI or worker. A dashboard, REPL, worker loop, or native host must not +invent a separate truth for compiled products or control state. + +## Forbidden Writers + +- Weksa does not compile Faust or own instrument controls. +- Eve lowerings do not own compiled binary lifetime or control truth. +- Faust source is an emitted artifact, not the semantic patch owner. +- Native host handles cannot silently override CultMesh session state. +- Render samples are evidence, not patch identity. diff --git a/tools/export-provider-advertisement.mjs b/tools/export-provider-advertisement.mjs new file mode 100644 index 0000000..3117a8e --- /dev/null +++ b/tools/export-provider-advertisement.mjs @@ -0,0 +1,191 @@ +#!/usr/bin/env node +import { mkdir, writeFile } from "node:fs/promises"; +import path from "node:path"; + +const document = { + schema: "gamecult.eve.provider_advertisement.v1", + providerId: "aquasynth.service", + title: "AquaSynth Service", + description: + "AquaSynth accepts .aqua DSL and Weksa utterance handoffs, compiles Faust-native instruments, returns live instrument handles, and publishes controllable synth state through CultMesh/Eve.", + mode: "fixture-read-only", + serviceVerse: { + id: "verse.aquasynth.service.v1", + cultMeshKey: "aquasynth.service/provider-advertisement", + authority: "AquaSynth daemon identity, schema catalog, provider publication, and synth runtime boundary", + owns: [ + ".aqua patch parsing", + "patch graph semantics", + "Faust source emission", + "native Faust compilation", + "compiled instrument handles", + "live control sessions", + "sample/render receipts", + "learned utterance embeddings and synth-driver controls", + ], + doesNotOwn: ["Weksa conversational intent", "Persona canonical state", "Eve presentation runtime"], + }, + nestedVerses: [ + { + id: "aquasynth.patch", + kind: "patch", + cultMeshKey: "aquasynth.patch/current", + authority: "AquaSynth.Core .aqua parser and patch graph model", + schemas: ["aquasynth.patch_graph.v0"], + }, + { + id: "aquasynth.compile", + kind: "compile", + cultMeshKey: "aquasynth.compile/jobs", + authority: "AquaSynth.Faust compiler boundary", + schemas: ["aquasynth.faust_source.v0", "aquasynth.compiled_instrument.v0"], + }, + { + id: "aquasynth.instrument", + kind: "instrument", + cultMeshKey: "aquasynth.instrument/sessions", + authority: "AquaSynth native host and control-session owner", + schemas: ["aquasynth.instrument_handle.v0", "aquasynth.control_session.v0"], + }, + { + id: "aquasynth.speech", + kind: "speech", + cultMeshKey: "aquasynth.speech/current", + authority: "AquaSynth utterance embedding and synth-driver runtime", + schemas: ["aquasynth.utterance_embedding.v0", "aquasynth.speech_render_receipt.v0"], + }, + { + id: "aquasynth.operator", + kind: "operator", + cultMeshKey: "aquasynth.operator/status", + authority: "AquaSynth daemon runtime", + schemas: ["aquasynth.operator_state.v0", "gamecult.eve.surface.v1"], + }, + ], + schemaWitnessFamilies: [ + { + family: "patch", + namespace: "aquasynth.patch.*", + witnesses: ["aquasynth.patch_graph.v0"], + durableShape: ".aquasynth/patches/{patchId}.cc", + }, + { + family: "compile", + namespace: "aquasynth.compile.*", + witnesses: ["aquasynth.faust_source.v0", "aquasynth.compiled_instrument.v0"], + durableShape: ".aquasynth/faust/{compileId}.cc", + }, + { + family: "instrument", + namespace: "aquasynth.instrument.*", + witnesses: ["aquasynth.instrument_handle.v0", "aquasynth.control_session.v0"], + durableShape: ".aquasynth/sessions/{sessionId}.cc", + }, + { + family: "render", + namespace: "aquasynth.render.*", + witnesses: ["aquasynth.render_sample.v0", "aquasynth.render_loss.v0"], + durableShape: ".aquasynth/renders/{renderId}.cc", + }, + { + family: "speech", + namespace: "aquasynth.speech.*", + witnesses: ["aquasynth.utterance_embedding.v0", "aquasynth.speech_render_receipt.v0"], + durableShape: ".aquasynth/speech/{utteranceId}.cc", + }, + { + family: "eve", + namespace: "aquasynth.eve.*", + witnesses: ["gamecult.eve.provider_advertisement.v1", "gamecult.eve.surface.v1"], + durableShape: ".aquasynth/eve-surfaces.cc", + }, + ], + cultMeshSurfaceKeys: [ + { + id: "aquasynth.eve.patch_graph.v0", + documentSchema: "gamecult.eve.surface.v1", + cultMeshKey: "aquasynth.eve.surface.patch-graph", + binds: ["aquasynth.patch.*", "aquasynth.compile.*"], + status: "expected-surface", + }, + { + id: "aquasynth.eve.compile_queue.v0", + documentSchema: "gamecult.eve.surface.v1", + cultMeshKey: "aquasynth.eve.surface.compile-queue", + binds: ["aquasynth.compile.*", "aquasynth.operator.*"], + status: "expected-surface", + }, + { + id: "aquasynth.eve.instrument_control.v0", + documentSchema: "gamecult.eve.surface.v1", + cultMeshKey: "aquasynth.eve.surface.instrument-control", + binds: ["aquasynth.instrument.*", "aquasynth.render.*"], + status: "expected-surface", + }, + { + id: "aquasynth.eve.speech_training.v0", + documentSchema: "gamecult.eve.surface.v1", + cultMeshKey: "aquasynth.eve.surface.speech-training", + binds: ["weksa.utterance.*", "aquasynth.speech.*", "aquasynth.render.*"], + status: "expected-surface", + }, + ], + commandBoundaries: [ + { + id: "aquasynth.command.patch.compile", + owner: "AquaSynth", + acceptedByFixture: false, + allowedInputs: [".aqua DSL", "compile target", "host architecture"], + emits: ["aquasynth.patch_graph.v0", "aquasynth.faust_source.v0", "aquasynth.compiled_instrument.v0"], + }, + { + id: "aquasynth.command.instrument.control", + owner: "AquaSynth", + acceptedByFixture: false, + allowedInputs: ["instrument handle", "semantic control values"], + emits: ["aquasynth.control_session.v0"], + }, + { + id: "aquasynth.command.instrument.sample", + owner: "AquaSynth", + acceptedByFixture: false, + allowedInputs: ["instrument handle", "duration", "sample format"], + emits: ["aquasynth.render_sample.v0"], + }, + { + id: "aquasynth.command.speech.realize", + owner: "AquaSynth", + acceptedByFixture: false, + allowedInputs: ["weksa.utterance_handoff.v0", "weksa.utterance_embedding_handoff.v0.1"], + emits: ["aquasynth.utterance_embedding.v0", "aquasynth.speech_render_receipt.v0"], + forbiddenTargets: ["Weksa conversational intent truth"], + }, + ], + loweringRules: [ + "AquaSynth owns learned embeddings, synth controls, Faust compilation, native binary lifetime, instrument handles, and sampled outputs.", + "Weksa owns writing-to-intent and intent-to-utterance lowering.", + "Faust source and native binaries are emitted artifacts with typed receipts, not the semantic patch owner.", + "Eve surfaces control and inspect sessions through CultMesh command documents; they do not own audio state.", + ], +}; + +async function main() { + const args = process.argv.slice(2); + const outIndex = args.indexOf("--out"); + const outputPath = outIndex >= 0 ? args[outIndex + 1] : undefined; + const json = `${JSON.stringify(document, null, 2)}\n`; + + if (outputPath) { + const resolved = path.resolve(process.cwd(), outputPath); + await mkdir(path.dirname(resolved), { recursive: true }); + await writeFile(resolved, json, "utf8"); + return; + } + + process.stdout.write(json); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +});