From 7221901ecd43f978e876a81fba9fc15e2b7c29fd Mon Sep 17 00:00:00 2001 From: Mavis Date: Sat, 8 Aug 2026 12:41:29 -0400 Subject: [PATCH 1/5] =?UTF-8?q?feat(room):=20DARKXSIDE=20room=20voice=20lo?= =?UTF-8?q?ading=20=E2=80=94=20manifest=20repair,=20MCP=20bridge=20mount,?= =?UTF-8?q?=20UTS=20port=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - darkxsides.room.json: remove the 3 skill-binding objects duplicated into apps[] (15 schema errors), fold out-of-contract skills/default_services into service_refs/launcher_refs, add tts-studio + voice-vault app entries (5090-voice room shapes). Manifest now validates. - catalog.json: darkxsides.room stage archive -> rehearsal (archive suppressed every window; rehearsal renders PREVIEW per stage discipline). - flute-gateway: mount mcp_bridge router — the written-but-orphaned 6-tool MCP surface over all 14 TTS engines. Verified live: :8055/sse 200. Fulfills vei.contract.mcp-bridge. - compose: ULTIMATE_TTS_URL default 7860 -> 7861 (compose publishes UTS on 7861; 7860 was the silent-unhealthy-provider trap). Splits regenerated. - docs: three lane views for operator review — governance stress-test design (mechanisms x whale scenarios -> Wealth settlement), school-psych economics model design (replaces fabricated SEAP unit economics with modeled+settled numbers), Dirichlet-drop CHIT living-docs update plan (6 overclaim corrections + belief-envelope additions + tour beat-3 plan). Co-Authored-By: Claude Fable 5 --- pmoves/config/rooms/catalog.json | 2 +- pmoves/config/rooms/darkxsides.room.json | 263 ++---------------- pmoves/docker-compose.media.yml | 4 +- pmoves/docker-compose.yml | 4 +- .../DIRICHLET_DROP_UPDATE_PLAN_2026-08-08.md | 78 ++++++ .../tokenism/GOVERNANCE_STRESS_TEST_DESIGN.md | 82 ++++++ .../SCHOOLPSYCH_ECONOMICS_MODEL_DESIGN.md | 67 +++++ pmoves/services/flute-gateway/main.py | 13 + 8 files changed, 275 insertions(+), 238 deletions(-) create mode 100644 pmoves/docs/PMOVESCHIT/DIRICHLET_DROP_UPDATE_PLAN_2026-08-08.md create mode 100644 pmoves/docs/tokenism/GOVERNANCE_STRESS_TEST_DESIGN.md create mode 100644 pmoves/docs/tokenism/SCHOOLPSYCH_ECONOMICS_MODEL_DESIGN.md diff --git a/pmoves/config/rooms/catalog.json b/pmoves/config/rooms/catalog.json index d2e28bef13..fa9e355c02 100644 --- a/pmoves/config/rooms/catalog.json +++ b/pmoves/config/rooms/catalog.json @@ -94,7 +94,7 @@ "stage": "rehearsal", "manifest": "darkxsides.room.json", "summary": "Private, owner-only persona room (co-creator + witness -> eventual digital twin). Uncensored/unrestricted authentic expression; houses the dedicated publish-gate surfaced in Open Notebook, with a fail-closed public-egress redaction floor.", - "current_stage": "archive", + "current_stage": "rehearsal", "stage_source": "inferred: private persona room, not serving external traffic (defaulted to archive; operator can flip to 'live' if active). See open-room-lane spec §6 stretch checklist.", "stage_verified_at": "2026-07-20T18:00:00Z" }, diff --git a/pmoves/config/rooms/darkxsides.room.json b/pmoves/config/rooms/darkxsides.room.json index e6e14dad15..b35b8d536a 100644 --- a/pmoves/config/rooms/darkxsides.room.json +++ b/pmoves/config/rooms/darkxsides.room.json @@ -3,7 +3,7 @@ "version": "1.0.0", "stage": "rehearsal", "display_name": "DARKXSIDES", - "description": "Private, owner-only room. A window into the mind of the Founder where the DARKXSIDE persona resides \u2014 co-creator and witness, eventual digital twin. Uncensored/unrestricted: real, not corporate-speak-pretty-CHIT. Houses the dedicated publish-gate, surfaced in Open Notebook.", + "description": "Private, owner-only room. A window into the mind of the Founder where the DARKXSIDE persona resides — co-creator and witness, eventual digital twin. Uncensored/unrestricted: real, not corporate-speak-pretty-CHIT. Houses the dedicated publish-gate, surfaced in Open Notebook.", "agent_id": "darkxside-persona", "alter": "darkxside", "room_type": "creator", @@ -13,7 +13,7 @@ "owner_only": true, "invite_list": [], "content_rating": "uncensored", - "rating_note": "Unrestricted expression inside the room. NOT a porn flag \u2014 content is authentic/real. Public egress is governed separately by policies.publish.egress_redaction_floor." + "rating_note": "Unrestricted expression inside the room. NOT a porn flag — content is authentic/real. Public egress is governed separately by policies.publish.egress_redaction_floor." }, "shell": { "theme": { @@ -62,7 +62,7 @@ "poetic", "bronx" ], - "glyph": "\u25c8", + "glyph": "◈", "resonance": [ "founder-mind", "shape-attribution", @@ -115,228 +115,34 @@ "pinned": true }, { - "binding_id": "pinokio-launch-comfyui", - "skill_id": "pinokio-bridge", - "room_id": "darkxsides.room", - "display_name": "Launch ComfyUI Render", - "intent": [ - "creator", - "render", - "image", - "video" - ], - "activation": { - "invocation_mode": "workflow", - "trigger_phrases": [ - "render this", - "generate image", - "launch comfyui", - "create visual" - ], - "requires_selection": false - }, - "surface": { - "app_id": "hyperdimensions-viewer", - "target": "panel", - "route": "/hyperdimensions/app" - }, - "execution": { - "mode": "workflow", - "run_as": "agent", - "stream": "status", - "max_steps": 8 - }, - "context": { - "sources": [ - "room-state", - "notebook-thread", - "persona" - ], - "include_last_turns": 4, - "notebook_writeback": true, - "artifact_types": [ - "text", - "json", - "image" - ] - }, - "outputs": [ - { - "target": "artifact-store", - "delivery": "append", - "path": "renders/comfyui-output", - "artifact_type": "image" - }, - { - "target": "nats-event", - "delivery": "emit", - "subject": "studio.render.completed.v1", - "artifact_type": "json" - } - ], - "guardrails": { - "require_approval": false, - "max_runtime_sec": 600, - "fail_open": true, - "one_active_run": true - }, - "enabled": true, - "tags": [ - "creator", - "render", - "comfyui", - "visual" - ] - }, - { - "binding_id": "pinokio-launch-tts", - "skill_id": "pinokio-bridge", - "room_id": "darkxsides.room", - "display_name": "Launch TTS Studio", - "intent": [ - "voice", + "app_id": "tts-studio", + "kind": "media", + "route": "/dashboard/voice", + "provider": "flute-gateway", + "action_namespace": "voice", + "capabilities": [ "tts", - "audio", - "persona" + "engine-status", + "audition", + "prosody" ], - "activation": { - "invocation_mode": "workflow", - "trigger_phrases": [ - "voice this", - "read it aloud", - "launch tts", - "synthesize voice", - "narrate" - ], - "requires_selection": true - }, - "surface": { - "app_id": "persona-console", - "target": "composer", - "route": "/darkxside/mind" - }, - "execution": { - "mode": "workflow", - "run_as": "agent", - "stream": "status", - "max_steps": 5 - }, - "context": { - "sources": [ - "notebook-selection", - "persona", - "room-state" - ], - "include_last_turns": 4, - "notebook_writeback": true, - "artifact_types": [ - "audio", - "text" - ] - }, - "outputs": [ - { - "target": "artifact-store", - "delivery": "append", - "path": "voice/spoken-summaries", - "artifact_type": "audio" - }, - { - "target": "nats-event", - "delivery": "emit", - "subject": "voice.synth.request.v1", - "artifact_type": "json" - } - ], - "guardrails": { - "require_approval": true, - "max_runtime_sec": 300, - "fail_open": false, - "one_active_run": true - }, - "enabled": true, - "tags": [ - "voice", - "tts", - "persona", - "provenance-gated" - ] + "pinned": false, + "status": "planned" }, { - "binding_id": "e2b-shared-desktop", - "skill_id": "e2b-desktop", - "room_id": "darkxsides.room", - "display_name": "Shared Desktop (E2B)", - "intent": [ - "review", - "desktop", - "browser", - "co-review", - "transform" - ], - "activation": { - "invocation_mode": "workflow", - "trigger_phrases": [ - "open shared desktop", - "show me the browser", - "co-review this", - "launch desktop view" - ], - "requires_selection": true - }, - "surface": { - "app_id": "hyperdimensions-viewer", - "target": "panel", - "route": "/hyperdimensions/app" - }, - "execution": { - "mode": "workflow", - "run_as": "agent", - "stream": "status", - "max_steps": 10 - }, - "context": { - "sources": [ - "notebook-selection", - "room-state", - "persona" - ], - "include_last_turns": 4, - "notebook_writeback": true, - "artifact_types": [ - "text", - "json", - "image" - ] - }, - "outputs": [ - { - "target": "nats-event", - "delivery": "emit", - "subject": "room.desktop.session.opened.v1", - "artifact_type": "json" - }, - { - "target": "notebook-entry", - "delivery": "append", - "path": "threads/desktop-sessions", - "artifact_type": "text" - } + "app_id": "voice-vault", + "kind": "custom", + "route": "/dashboard/voice/vault", + "provider": "pmoves-ui", + "action_namespace": "voice.vault", + "capabilities": [ + "voice-library", + "consent-artifacts", + "provenance-view", + "rights-basis" ], - "guardrails": { - "require_approval": true, - "max_runtime_sec": 1800, - "fail_open": false, - "one_active_run": true - }, - "enabled": false, - "tags": [ - "desktop", - "e2b", - "co-review", - "browser", - "disabled-pending-e2b-key" - ] + "pinned": false, + "status": "planned" } ], "notebook": { @@ -382,7 +188,7 @@ "binding_id": "pub-gate-approve", "skill_id": "pmoves-publish-gate", "room_id": "darkxsides.room", - "display_name": "Publish Gate \u2014 Approve / Hold", + "display_name": "Publish Gate — Approve / Hold", "intent": [ "publish", "approve", @@ -698,7 +504,7 @@ "no-literal-lan-or-tailscale-ips" ], "fail_closed": true, - "note": "Adults-only reflection space. The floor protects operator + collaborator PII and enforces operator final-say on egress \u2014 it is NOT a content-rating gate. Minor safety is handled by room separation (kids only ever in P7 Playground), not by scanning this room. Anything crossing to a PUBLIC surface passes this floor regardless of room rating; cannot be bypassed by opening the gate." + "note": "Adults-only reflection space. The floor protects operator + collaborator PII and enforces operator final-say on egress — it is NOT a content-rating gate. Minor safety is handled by room separation (kids only ever in P7 Playground), not by scanning this room. Anything crossing to a PUBLIC surface passes this floor regardless of room rating; cannot be bypassed by opening the gate." } }, "memory": { @@ -741,14 +547,5 @@ "pmoves/docs/ROOM_MANIFEST_CONTRACT.md", "pmoves/docs/PMOVESCHIT/GEOMETRY_BUS_INTEGRATION.md" ] - }, - "skills": [ - "pinokio-bridge", - "flute-gateway", - "comfyui", - "e2b-mcp" - ], - "default_services": [ - "up-comfyui" - ] -} \ No newline at end of file + } +} diff --git a/pmoves/docker-compose.media.yml b/pmoves/docker-compose.media.yml index 941c6ee0c9..72eee6255d 100644 --- a/pmoves/docker-compose.media.yml +++ b/pmoves/docker-compose.media.yml @@ -365,7 +365,7 @@ services: # Realtime duplex voice agent (/v1/voice/agent: mic→Whisper→LLM→VibeVoice). # Off by default — requires pipecat-ai installed + VibeVoice (7860) running. - PIPECAT_ENABLED=${PIPECAT_ENABLED:-false} - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap - ULTIMATE_TTS_TIMEOUT_SEC=${ULTIMATE_TTS_TIMEOUT_SEC:-300} # Host-affinity routing (opt-in, #2305): with VOICE_HOST_AFFINITY=1 a cast # host-swaps the configured engine URL to the selected fleet node's Tailscale @@ -425,7 +425,7 @@ services: environment: - PORT=8060 - FLUTE_GATEWAY_URL=http://flute-gateway:8055 - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap - NATS_URL=${NATS_URL} - CHIT_REQUIRE_SIGNATURE=${CHIT_REQUIRE_SIGNATURE:-false} - CHIT_DECRYPT_ANCHORS=${CHIT_DECRYPT_ANCHORS:-false} diff --git a/pmoves/docker-compose.yml b/pmoves/docker-compose.yml index 0b2bac278f..c0fabae9fe 100644 --- a/pmoves/docker-compose.yml +++ b/pmoves/docker-compose.yml @@ -4391,7 +4391,7 @@ services: # Realtime duplex voice agent (/v1/voice/agent: mic→Whisper→LLM→VibeVoice). # Off by default — requires pipecat-ai installed + VibeVoice (7860) running. - PIPECAT_ENABLED=${PIPECAT_ENABLED:-false} - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap - ULTIMATE_TTS_TIMEOUT_SEC=${ULTIMATE_TTS_TIMEOUT_SEC:-300} # Host-affinity routing (opt-in, #2305): with VOICE_HOST_AFFINITY=1 a cast # host-swaps the configured engine URL to the selected fleet node's Tailscale @@ -4562,7 +4562,7 @@ services: environment: - PORT=8060 - FLUTE_GATEWAY_URL=http://flute-gateway:8055 - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap - NATS_URL=${NATS_URL} - CHIT_REQUIRE_SIGNATURE=${CHIT_REQUIRE_SIGNATURE:-false} - CHIT_DECRYPT_ANCHORS=${CHIT_DECRYPT_ANCHORS:-false} diff --git a/pmoves/docs/PMOVESCHIT/DIRICHLET_DROP_UPDATE_PLAN_2026-08-08.md b/pmoves/docs/PMOVESCHIT/DIRICHLET_DROP_UPDATE_PLAN_2026-08-08.md new file mode 100644 index 0000000000..a6fb8848df --- /dev/null +++ b/pmoves/docs/PMOVESCHIT/DIRICHLET_DROP_UPDATE_PLAN_2026-08-08.md @@ -0,0 +1,78 @@ +# CHIT Tour Living-Docs Update Plan — Dirichlet/Latent-Geometry drop (view v1, 2026-08-08) + +> Source: `SEAP/Integrating Dirichlet Distributions and Latent Geometry into +> PMOVES.AI.pdf` — NOTE: byte-identical to `SEAP/DARKXSIDE-deep-research-report.md` +> (one drop, two filenames). This is the review view; edits ship only after +> operator sign-off. + +## Headline + +The drop does two things: (1) **adds** the belief-over-geometry composite — +every manifold point carries a Dirichlet belief state (`π ~ Dir(α)`) with an +inspectable envelope (alpha, mean, concentration, entropy, provenance hashes); +(2) **corrects six overclaim families** currently shipping in CHIT docs, with +recommended replacement wording. + +## Corrections required (claim → where it ships → fix) + +1. **"Dirichlet guarantees fair non-zero weight (α≥1)"** — GLOSSARY:29, + WHAT_IS_CHIT:83, CGP spec:58/69 → α≥1 guarantees neither fairness nor + minimum influence; fairness needs explicit constraints + outcome audits. +2. **"Exponential storage capacity" (Poincaré)** — spec:38/51/76, + WHAT_IS_CHIT:85 → metric *volume* grows exponentially ≠ more stored bytes; + O(log n) distortion needs theorem citation + tree class or removal. +3. **"Tamper-proof attribution"** — GLOSSARY:37, WHAT_IS_CHIT:87, + spec:52/97, VISUAL_TOUR:485 → "tamper-**evident** inclusion proof under the + stated trust model" (Merkle proves inclusion, not authorship). +4. **"Universal translatability / telepathy-like"** — spec:35/40 → + "corpus- and embedding-conditioned geometry-only retrieval"; metaphor only + in labeled vision material. +5. **"Exact mode — lossless"** — WHAT_IS_CHIT:70, spec:449 → exactness comes + from the retained payload; geometry-only is lossy until proved otherwise. +6. **"Production Ready" + zeta-filter claims** — spec:9/877, GLOSSARY:57 → + maturity-ladder labels (prototype/evaluated/hardened/candidate/certified); + zeta = experimental pending ablations. + +## Additions (technical docs, NOT the public tour) + +- Belief-envelope schema (`belief_type: dirichlet.v1`) as an optional + versioned CGP §uncertainty block; canonical-JSON-before-signing requirement; + AES-GCM confidentiality scope vs HMAC integrity separation. +- Seven proposed NATS subjects (`geometry.belief.updated.v1` etc.) appended to + 02_GEOMETRY_BUS.md **as a clearly-marked Proposed table** — none exist on + the bus today; presenting them as live would violate verified-actuals. +- New `06_EVIDENCE_LEDGER.md` for the adversarial test matrix + calibration + metrics (ECE/Brier/NLL) instead of bloating the tour. + +## Tour changes (minimal, high-leverage) + +- **Beat 3 only** content change: pillars 1+2 reframed as one composite — + "the shape says *where*, the Dirichlet says *how sure*." +- **New Beat 3b (interactive)**: ternary-simplex lab in `pillars-lab.js` — + α sliders, posterior-mean marker, sampled particles; teaches ratios-move- + the-mean / scale-shrinks-variance / α<1 favors corners / sample ≠ mean. +- **Hover-evidence legend** across the constellation renderer: every artistic + mark reveals α, mean, entropy, coords, model version — the drop's UX + doctrine: "the experiential view never silently substitutes metaphor for + evidence." Beats 1–2 and 4–10 unchanged; the two-meaning canon is intact. + +## Registry gap + +`00_GLOSSARY.md`, `01_WHAT_IS_CHIT.md`, `CGP_v1.0_SPECIFICATION.md` carry the +contradicted claims but are NOT in `living_docs_registry.yaml` — add them, or +they keep drifting with no reconcile check. + +## Sequencing (proposed) + +1. Claim-correction text pass (six docs, no code) — unblocks everything. +2. Registry-track the three untracked CHIT docs. +3. Tour beat-3 reframe + simplex lab + hover legend. +4. Belief-envelope schema + subjects, gated behind actual implementation. + +## Caution + +The drop's own "verified" column audited only a rendered spec via web view +(it says so) — re-verify every path locally before promoting anything out of +Proposed. All `pmoves_math/**` paths, contracts, notebooks it references are +proposals, and every performance claim is hypothesis (≥5 seeds + CIs before +any number reaches a doc). diff --git a/pmoves/docs/tokenism/GOVERNANCE_STRESS_TEST_DESIGN.md b/pmoves/docs/tokenism/GOVERNANCE_STRESS_TEST_DESIGN.md new file mode 100644 index 0000000000..bd1e9e8785 --- /dev/null +++ b/pmoves/docs/tokenism/GOVERNANCE_STRESS_TEST_DESIGN.md @@ -0,0 +1,82 @@ +# Governance Stress-Test Design — "Let's put it to the test" (view v1, 2026-08-08) + +> Origin: the SEAP-plan reconciliation surfaced a live disagreement. The Gemini +> plan sold quadratic voting + veToken locks as whale *deterrents*; the +> TOKEN_STRUCTURE_REFRESH decision record calls stake-weighted mechanics the +> plutocratic anti-pattern. The operator's ruling: **neither assertion stands +> untested** — the simulator decides, and outputs settle to PMOVES-Wealth. +> This is the test design for review before implementation. + +## Question under test + +For a community of N members with realistic wealth inequality, which voting +mechanism minimizes *outcome capture by concentrated capital* while preserving +*legitimate influence for high-contribution members*? + +## Mechanisms (the contenders) + +| id | Mechanism | Whale story (claimed) | +|----|-----------|----------------------| +| M1 | Token-weighted (1 token = 1 vote) | baseline / known-plutocratic control | +| M2 | Quadratic voting, no identity binding | cost² deters whales (plan's claim) | +| M3 | Quadratic voting + sybil-resistant identity (1 person = 1 credit pool) | QV as designed by its authors | +| M4 | veToken time-lock weighting (lock longer → more weight) | "skin in the game" | +| M5 | One-member-one-vote + $WORK-style SBT eligibility gate | decision record's direction | +| M6 | Hybrid: M5 for elections + M3 for budget-allocation signals | two-house frame | + +## Attack scenarios (each run against every mechanism) + +1. **Whale accumulation** — one actor holds 10× / 50× / 200× median balance. +2. **Sybil split** — whale splits stake across k fake identities (k = 2…100). + This is the scenario that breaks naive QV (M2) and is why M3 exists. +3. **Lock-race** — whale max-locks veTokens before a contested vote (targets M4). +4. **Collusion ring** — c members (c = 3…15) coordinate votes; measures + whether mechanism amplifies or dampens coordinated minorities. +5. **Voter apathy** — turnout 10–60%; whales always vote. (Low turnout is the + real-world whale multiplier.) +6. **Contribution-inversion check** — the *legitimacy* half: a high-contributor + low-balance member vs a zero-contribution whale on the same proposal; does + the mechanism let the contributor matter? + +## Metrics + +- **Capture rate**: fraction of contested proposals decided by the whale/ring + against majority-member preference. +- **Gini-to-influence transfer**: correlation between wealth Gini and voting + influence Gini (the plutocracy number — lower is better). +- **Sybil elasticity**: influence gained per identity added (M3 should be ~0; + M2 will not be). +- **Participation elasticity**: how capture rate moves with turnout. +- **Legitimacy score**: contribution-weighted preference satisfaction (does + the mechanism reward builders or balances?). + +Each cell = 500 Monte-Carlo runs, ≥5 seeds, report medians with CIs — same +evidence bar the Dirichlet drop mandates for CHIT claims. + +## Implementation shape + +- **Harness**: PMOVES-ToKenism-Multi simulator (`tokenism-simulator` :8103) — + agents with wealth drawn from the pilot's empirical distribution (Fordham + household data where available; Pareto fit elsewhere, LABELED ASSUMPTION). +- **Mechanism modules**: pure functions `(balances, locks, identities, + votes) → decision` so each mechanism is a ~50-line plug-in. +- **Settlement**: run outputs → `export_sim_to_firefly.ts` + (PMOVES-ToKenism-Multi/integrations/firefly/) → PMOVES-Wealth ledger, one + Firefly tag per scenario run — ledger-grade evidence, not a chart in a doc. +- **Verdict doc**: results land as a reconciliation-style table (mechanism × + scenario → capture rate), published to Open Notebook + the room. + +## What would change minds + +- If M3 (QV + identity) shows capture ≈ M5 with better legitimacy scores, the + plan's QV language survives — but only with the sybil-resistance qualifier + the plan omitted. +- If M4 capture ≥ M1, the decision record's veToken retirement is confirmed + with numbers attached. +- If M6 dominates, the bicameral Constitution sketch gets its first + evidence-backed parameter set (replacing the self-flagged FABRICATED ones). + +## Non-goals + +No on-chain deployment, no real tokens, no governance change ships from this — +it produces *evidence for the operator's decision*, per the pub-gate model. diff --git a/pmoves/docs/tokenism/SCHOOLPSYCH_ECONOMICS_MODEL_DESIGN.md b/pmoves/docs/tokenism/SCHOOLPSYCH_ECONOMICS_MODEL_DESIGN.md new file mode 100644 index 0000000000..9d3c94fa28 --- /dev/null +++ b/pmoves/docs/tokenism/SCHOOLPSYCH_ECONOMICS_MODEL_DESIGN.md @@ -0,0 +1,67 @@ +# School-Psych Workload → ToKenism Model → Wealth Settlement (view v1, 2026-08-08) + +> Origin: the SEAP business plan's unit-economics paragraph was fabricated +> (reconciliation fix #4). Operator's ruling: "4 is why tokenism — we need to +> model and output to PMOVES-Wealth." This view is the model design: the +> School Psychology operations doc becomes the first *modeled* (not asserted) +> service workload, with ledger-grade outputs. + +## What gets modeled + +A Lead School Psychologist across 3 sites (the refreshed +`PMOVES_School_Psychology_Operations_REFRESHED_2026-08-07.md` workload): + +| Workload | PMOVES function | Value channel | +|---|---|---| +| IEP translation + audio explanation | CHIT + voice stack | hours returned + access equity (ELL families served) | +| Meeting transcription + emotion annotation | media-audio | hours returned + consent-quality (documented informed consent) | +| Longitudinal records synthesis | Hi-RAG v2 | hours returned + earlier-intervention proxy | +| Report drafting/flagging | Agent Zero | hours returned | +| Multi-site secure access | Tailscale mesh | commute/context-switch reduction | + +## Inputs (every one LABELED) + +- **ACTUAL** (measure on this fleet): per-task wall-clock for each pipeline + (diarize+transcribe an IEP meeting, synthesize an IEP audio, Hi-RAG query + latency) — captured from live service metrics, not estimated. +- **ASSUMPTION** (cite source, label): baseline manual minutes per task + (published school-psych workload surveys + operator's domain knowledge), + psychologist loaded hourly cost (public NYC DOE salary schedules), task + frequencies per student caseload (IDEA/IEP statutory cadence). +- **SCENARIO KNOBS**: caseload size, 3-site travel pattern, ELL fraction, + automation adoption ramp (0→80% over school year). + +## Model shape (ToKenism scenario) + +1. **Time-value engine**: (manual minutes − assisted minutes) × frequency × + loaded cost → dollars/month returned, per function. +2. **Service-credit loop**: returned hours priced into ToKenism service + credits (the FoodUSD/GroToken built canon — NOT the unbuilt trinity); + models the district/coop paying for PMOVES capacity in credits. +3. **Sensitivity pass**: tornado chart over the ASSUMPTION inputs; the model + ships with its weakest assumptions ranked, per verified-actuals doctrine. + +## Settlement (the part that makes it real) + +- Simulator run → `export_sim_to_firefly.ts` → **PMOVES-Wealth (Firefly III)**: + one budget per function, monthly simulated settlement entries, tagged + `sim:schoolpsych-v1:`. +- Result: the SEAP plan's economics section can cite a LEDGER with an audit + trail ("open PMOVES-Wealth, filter the tag") instead of a paragraph of + invented numbers. That IS the demo: provable accounting as product. + +## Known blocker (from reconciliation #14) + +The Firefly integration is pre-stage: `export_sim_to_firefly.ts` exists but +the live Firefly service isn't wired in compose (no `firefly` service; Wealth +subjects are target contracts). **Phase 1 of this lane is therefore standing +up PMOVES-Wealth's Firefly III container + running the existing exporter +against it** — which simultaneously retires a "Not wired / aspirational" row +in TOKEN_STRUCTURE_REFRESH §6. + +## Deliverables + +1. `firefly` service live (Wealth stack) + exporter smoke run. +2. Scenario module in ToKenism with the inputs table above. +3. First settled run + a one-page results view (ON + room inbox). +4. SEAP plan §Financial Projections ¶2 replaced with the ledger citation. diff --git a/pmoves/services/flute-gateway/main.py b/pmoves/services/flute-gateway/main.py index 0865e8853d..58422f6ff7 100644 --- a/pmoves/services/flute-gateway/main.py +++ b/pmoves/services/flute-gateway/main.py @@ -610,6 +610,19 @@ async def lifespan(app: FastAPI): lifespan=lifespan ) +# MCP bridge (mcp_bridge.py) — the curated 6-tool surface over all 14 engines +# (tts_list_engines/intents/synthesize/engine_status/load/unload). Written for +# the vei.contract.mcp-bridge TAC contract (:8055/sse) but never mounted until +# now. Callables defer to the module globals set during lifespan startup. +from mcp_bridge import create_mcp_router # noqa: E402 + +app.include_router( + create_mcp_router( + get_provider=lambda: ultimate_tts_provider, + get_nats_client=lambda: nats_client, + ) +) + # Health check endpoint @app.get("/healthz", response_model=HealthResponse) From cc740fbb2287078a2c72d2829939877c0335f630 Mon Sep 17 00:00:00 2001 From: Mavis Date: Sat, 8 Aug 2026 12:57:36 -0400 Subject: [PATCH 2/5] fix(voice): flute->UTS direct container route + UTS egress network MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ULTIMATE_TTS_URL default -> http://ultimate-tts-studio:7860 (shared pmoves_app network; host.docker.internal publishing is unreliable on Docker Desktop Windows — the 7861 host bind wedged in the daemon's port ledger and only a Desktop restart clears it). Verified: flute healthz reports ultimate_tts: true. - UTS overlay joins pmoves_external: engines lazy-download weights from HuggingFace on first load; without egress every handle_load_* returns 'Failed to load'. Co-Authored-By: Claude Fable 5 --- pmoves/docker-compose.media.yml | 4 ++-- pmoves/docker-compose.ultimate-tts-studio.yml | 4 +++- pmoves/docker-compose.yml | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pmoves/docker-compose.media.yml b/pmoves/docker-compose.media.yml index 72eee6255d..ce09338f10 100644 --- a/pmoves/docker-compose.media.yml +++ b/pmoves/docker-compose.media.yml @@ -365,7 +365,7 @@ services: # Realtime duplex voice agent (/v1/voice/agent: mic→Whisper→LLM→VibeVoice). # Off by default — requires pipecat-ai installed + VibeVoice (7860) running. - PIPECAT_ENABLED=${PIPECAT_ENABLED:-false} - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) - ULTIMATE_TTS_TIMEOUT_SEC=${ULTIMATE_TTS_TIMEOUT_SEC:-300} # Host-affinity routing (opt-in, #2305): with VOICE_HOST_AFFINITY=1 a cast # host-swaps the configured engine URL to the selected fleet node's Tailscale @@ -425,7 +425,7 @@ services: environment: - PORT=8060 - FLUTE_GATEWAY_URL=http://flute-gateway:8055 - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) - NATS_URL=${NATS_URL} - CHIT_REQUIRE_SIGNATURE=${CHIT_REQUIRE_SIGNATURE:-false} - CHIT_DECRYPT_ANCHORS=${CHIT_DECRYPT_ANCHORS:-false} diff --git a/pmoves/docker-compose.ultimate-tts-studio.yml b/pmoves/docker-compose.ultimate-tts-studio.yml index 3d162475da..aae04f5af8 100644 --- a/pmoves/docker-compose.ultimate-tts-studio.yml +++ b/pmoves/docker-compose.ultimate-tts-studio.yml @@ -20,7 +20,9 @@ services: - driver: nvidia capabilities: [compute,utility] count: ${GPU_COUNT:-all} - networks: [api_tier, data_tier] + # pmoves_external: engines lazy-download weights from HuggingFace on first + # load — without egress every handle_load_* returns "Failed to load". + networks: [api_tier, data_tier, pmoves_external] volumes: ultimate-tts-data: {} diff --git a/pmoves/docker-compose.yml b/pmoves/docker-compose.yml index c0fabae9fe..251814ddc4 100644 --- a/pmoves/docker-compose.yml +++ b/pmoves/docker-compose.yml @@ -4391,7 +4391,7 @@ services: # Realtime duplex voice agent (/v1/voice/agent: mic→Whisper→LLM→VibeVoice). # Off by default — requires pipecat-ai installed + VibeVoice (7860) running. - PIPECAT_ENABLED=${PIPECAT_ENABLED:-false} - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) - ULTIMATE_TTS_TIMEOUT_SEC=${ULTIMATE_TTS_TIMEOUT_SEC:-300} # Host-affinity routing (opt-in, #2305): with VOICE_HOST_AFFINITY=1 a cast # host-swaps the configured engine URL to the selected fleet node's Tailscale @@ -4562,7 +4562,7 @@ services: environment: - PORT=8060 - FLUTE_GATEWAY_URL=http://flute-gateway:8055 - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7861} # compose publishes UTS on 7861 (ULTIMATE_TTS_STUDIO_HOST_PORT); 7860 was the silent-unhealthy-provider trap + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) - NATS_URL=${NATS_URL} - CHIT_REQUIRE_SIGNATURE=${CHIT_REQUIRE_SIGNATURE:-false} - CHIT_DECRYPT_ANCHORS=${CHIT_DECRYPT_ANCHORS:-false} From 7407fd418eec9f6b97468b16cf425854313bb7d5 Mon Sep 17 00:00:00 2001 From: Mavis Date: Sat, 8 Aug 2026 13:03:48 -0400 Subject: [PATCH 3/5] =?UTF-8?q?fix(voice):=20UTS=20routing=20is=20NATIVE-f?= =?UTF-8?q?irst=20=E2=80=94=20the=20GHCR=20image=20is=20an=20engine-less?= =?UTF-8?q?=20UI=20shell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live probing the hardened container: kittentts/f5_tts/omegaconf are NOT installed (every handle_load_* returns 'Failed to load' even with egress + CA fixed). The real 13-engine studio is the Pinokio-native UTS on host 7860 (feedback_tts_native_not_docker) — restore host.docker.internal:7860 as flute's default and document the container override for a future engine-baked image. Keeps the UTS overlay fixes (pmoves_external egress + CA re-point) so the shell is one image-fix away from working. Co-Authored-By: Claude Fable 5 --- pmoves/docker-compose.media.yml | 4 ++-- pmoves/docker-compose.ultimate-tts-studio.yml | 7 +++++++ pmoves/docker-compose.yml | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pmoves/docker-compose.media.yml b/pmoves/docker-compose.media.yml index ce09338f10..7d26a12d16 100644 --- a/pmoves/docker-compose.media.yml +++ b/pmoves/docker-compose.media.yml @@ -365,7 +365,7 @@ services: # Realtime duplex voice agent (/v1/voice/agent: mic→Whisper→LLM→VibeVoice). # Off by default — requires pipecat-ai installed + VibeVoice (7860) running. - PIPECAT_ENABLED=${PIPECAT_ENABLED:-false} - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} # NATIVE-first: engines run in the Pinokio-native UTS on host 7860 (feedback_tts_native_not_docker); the GHCR container is a UI/MCP shell WITHOUT engine packages — override to http://ultimate-tts-studio:7860 only if the image ever bakes engines - ULTIMATE_TTS_TIMEOUT_SEC=${ULTIMATE_TTS_TIMEOUT_SEC:-300} # Host-affinity routing (opt-in, #2305): with VOICE_HOST_AFFINITY=1 a cast # host-swaps the configured engine URL to the selected fleet node's Tailscale @@ -425,7 +425,7 @@ services: environment: - PORT=8060 - FLUTE_GATEWAY_URL=http://flute-gateway:8055 - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} # NATIVE-first: engines run in the Pinokio-native UTS on host 7860 (feedback_tts_native_not_docker); the GHCR container is a UI/MCP shell WITHOUT engine packages — override to http://ultimate-tts-studio:7860 only if the image ever bakes engines - NATS_URL=${NATS_URL} - CHIT_REQUIRE_SIGNATURE=${CHIT_REQUIRE_SIGNATURE:-false} - CHIT_DECRYPT_ANCHORS=${CHIT_DECRYPT_ANCHORS:-false} diff --git a/pmoves/docker-compose.ultimate-tts-studio.yml b/pmoves/docker-compose.ultimate-tts-studio.yml index aae04f5af8..49654e3e61 100644 --- a/pmoves/docker-compose.ultimate-tts-studio.yml +++ b/pmoves/docker-compose.ultimate-tts-studio.yml @@ -8,6 +8,13 @@ services: - HF_HOME=/data/hf - HUGGINGFACE_HUB_CACHE=/data/hf - XDG_CACHE_HOME=/data/cache + # Empty SSL_CERT_FILE/_DIR means "trust nothing" to Python/OpenSSL and + # breaks HF weight downloads — re-point at the container CA store (same + # anti-host-leak intent as the env.shared blanks, working trust chain). + - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + - SSL_CERT_DIR=/etc/ssl/certs + - REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + - CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt volumes: - ultimate-tts-data:/data ports: diff --git a/pmoves/docker-compose.yml b/pmoves/docker-compose.yml index 251814ddc4..6fdbd3d9df 100644 --- a/pmoves/docker-compose.yml +++ b/pmoves/docker-compose.yml @@ -4391,7 +4391,7 @@ services: # Realtime duplex voice agent (/v1/voice/agent: mic→Whisper→LLM→VibeVoice). # Off by default — requires pipecat-ai installed + VibeVoice (7860) running. - PIPECAT_ENABLED=${PIPECAT_ENABLED:-false} - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} # NATIVE-first: engines run in the Pinokio-native UTS on host 7860 (feedback_tts_native_not_docker); the GHCR container is a UI/MCP shell WITHOUT engine packages — override to http://ultimate-tts-studio:7860 only if the image ever bakes engines - ULTIMATE_TTS_TIMEOUT_SEC=${ULTIMATE_TTS_TIMEOUT_SEC:-300} # Host-affinity routing (opt-in, #2305): with VOICE_HOST_AFFINITY=1 a cast # host-swaps the configured engine URL to the selected fleet node's Tailscale @@ -4562,7 +4562,7 @@ services: environment: - PORT=8060 - FLUTE_GATEWAY_URL=http://flute-gateway:8055 - - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://ultimate-tts-studio:7860} # direct container route on pmoves_app (host.docker.internal bind is unreliable on Docker Desktop Windows; 7860-vs-7861 was the old silent-unhealthy trap) + - ULTIMATE_TTS_URL=${ULTIMATE_TTS_URL:-http://host.docker.internal:7860} # NATIVE-first: engines run in the Pinokio-native UTS on host 7860 (feedback_tts_native_not_docker); the GHCR container is a UI/MCP shell WITHOUT engine packages — override to http://ultimate-tts-studio:7860 only if the image ever bakes engines - NATS_URL=${NATS_URL} - CHIT_REQUIRE_SIGNATURE=${CHIT_REQUIRE_SIGNATURE:-false} - CHIT_DECRYPT_ANCHORS=${CHIT_DECRYPT_ANCHORS:-false} From d20dd61da3d7d9d93e5f9b90c39a3c6be5b56a6e Mon Sep 17 00:00:00 2001 From: Mavis Date: Sat, 8 Aug 2026 15:02:09 -0400 Subject: [PATCH 4/5] fix(media-audio): re-apply container CA store env on this branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The revive recreate ran from this main-based branch, which lacks #2471's CA block — media-audio came up with SSL_CERT_FILE='' and the HF xet downloader died with 'No CA certificates were loaded from the system' (models_loaded empty, degraded). Identical text to #2471's hunk so the merge dedupes. Co-Authored-By: Claude Fable 5 --- pmoves/docker-compose.media.yml | 8 ++++++++ pmoves/docker-compose.yml | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/pmoves/docker-compose.media.yml b/pmoves/docker-compose.media.yml index 7d26a12d16..62ee839f53 100644 --- a/pmoves/docker-compose.media.yml +++ b/pmoves/docker-compose.media.yml @@ -70,6 +70,14 @@ services: - MINIO_SECRET_KEY=${MINIO_PASSWORD:?Run make brand-defaults} - NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES:-all} - EMOTION_MODEL=${EMOTION_MODEL:-superb/hubert-large-superb-er} + # env.shared blanks SSL_CERT_FILE/SSL_CERT_DIR/*_CA_BUNDLE to stop Windows + # host cert paths leaking in — but for Python/OpenSSL an EMPTY value means + # "trust nothing" and HF model downloads fail TLS verify. Re-point at the + # container's own CA store (same anti-leak intent, working trust chain). + - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + - SSL_CERT_DIR=/etc/ssl/certs + - REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + - CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt - PMOVES_NETWORKS=pmoves_app,pmoves_bus,pmoves_external deploy: resources: diff --git a/pmoves/docker-compose.yml b/pmoves/docker-compose.yml index 6fdbd3d9df..17360d9bcc 100644 --- a/pmoves/docker-compose.yml +++ b/pmoves/docker-compose.yml @@ -2241,6 +2241,14 @@ services: - MINIO_SECRET_KEY=${MINIO_PASSWORD:?Run make brand-defaults} - NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES:-all} - EMOTION_MODEL=${EMOTION_MODEL:-superb/hubert-large-superb-er} + # env.shared blanks SSL_CERT_FILE/SSL_CERT_DIR/*_CA_BUNDLE to stop Windows + # host cert paths leaking in — but for Python/OpenSSL an EMPTY value means + # "trust nothing" and HF model downloads fail TLS verify. Re-point at the + # container's own CA store (same anti-leak intent, working trust chain). + - SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + - SSL_CERT_DIR=/etc/ssl/certs + - REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt + - CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt - PMOVES_NETWORKS=pmoves_app,pmoves_bus,pmoves_external deploy: resources: From 93e200a0cd35fc3193129b511c3fa943a8b209fd Mon Sep 17 00:00:00 2001 From: Mavis Date: Sun, 9 Aug 2026 10:01:47 -0400 Subject: [PATCH 5/5] =?UTF-8?q?fix(flute-mcp):=20address=20review=20P1s=20?= =?UTF-8?q?=E2=80=94=20auth=20on=20MCP=20router,=20full=20base64=20payload?= =?UTF-8?q?,=20event-API=20load/unload,=20configs=20baked=20into=20image?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - include_router now carries verify_api_key (no-op when FLUTE_API_KEY unset) - tts_synthesize returns the complete base64 WAV instead of a truncated stub - tts_load/unload_engine go through provider._call_gradio (/gradio_api/call); the old synchronous /api/ path 404s on current Ultimate-TTS builds - Dockerfile ships tts-engine-{capabilities,expressions}.yaml at the bridge's /app/pmoves/configs/ resolution path so tools/list isn't empty in-container Co-Authored-By: Claude Fable 5 --- pmoves/services/flute-gateway/Dockerfile | 6 ++++++ pmoves/services/flute-gateway/main.py | 3 ++- pmoves/services/flute-gateway/mcp_bridge.py | 23 +++++++-------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pmoves/services/flute-gateway/Dockerfile b/pmoves/services/flute-gateway/Dockerfile index 27e1547314..01e6d2489d 100644 --- a/pmoves/services/flute-gateway/Dockerfile +++ b/pmoves/services/flute-gateway/Dockerfile @@ -76,6 +76,12 @@ COPY services/common/ services/common/ # Copy source COPY services/flute-gateway/ . +# MCP bridge engine registry - mcp_bridge.py resolves these under +# /app/pmoves/configs/ inside the container (TTS_CAPABILITIES_YAML / +# TTS_EXPRESSIONS_YAML env vars override) +COPY configs/tts-engine-capabilities.yaml pmoves/configs/tts-engine-capabilities.yaml +COPY configs/tts-engine-expressions.yaml pmoves/configs/tts-engine-expressions.yaml + # Change ownership to non-root user RUN chown -R pmoves:pmoves /app diff --git a/pmoves/services/flute-gateway/main.py b/pmoves/services/flute-gateway/main.py index 58422f6ff7..a4e640cc21 100644 --- a/pmoves/services/flute-gateway/main.py +++ b/pmoves/services/flute-gateway/main.py @@ -620,7 +620,8 @@ async def lifespan(app: FastAPI): create_mcp_router( get_provider=lambda: ultimate_tts_provider, get_nats_client=lambda: nats_client, - ) + ), + dependencies=[Depends(verify_api_key)], ) diff --git a/pmoves/services/flute-gateway/mcp_bridge.py b/pmoves/services/flute-gateway/mcp_bridge.py index 683db381cd..99b07d0eae 100644 --- a/pmoves/services/flute-gateway/mcp_bridge.py +++ b/pmoves/services/flute-gateway/mcp_bridge.py @@ -274,7 +274,7 @@ async def _tool_synthesize( "modifier": modifier, "text_length": len(text), "audio_bytes": len(audio_bytes), - "audio_base64": audio_b64[:100] + "..." if len(audio_b64) > 100 else audio_b64, + "audio_base64": audio_b64, "format": "wav", "status": "ok", } @@ -314,14 +314,12 @@ async def _tool_load_engine( load_ep, _ = ENGINE_ENDPOINTS[engine] try: import httpx + # The old synchronous /api/ predict endpoint is a 404 on current + # Ultimate-TTS builds — go through the provider's event-based + # /gradio_api/call flow instead. async with httpx.AsyncClient(timeout=120.0) as client: - resp = await client.post( - f"{provider.base_url}/api{load_ep}", - json={"data": []}, - ) - resp.raise_for_status() - result = resp.json() - return {"engine": engine, "endpoint": load_ep, "result": result, "status": "loaded"} + result = await provider._call_gradio(client, load_ep, [], timeout=120.0) + return {"engine": engine, "endpoint": load_ep, "result": result, "status": "loaded"} except Exception as e: logger.exception("tts_load_engine failed for engine=%s", engine) return {"error": str(e), "engine": engine} @@ -343,13 +341,8 @@ async def _tool_unload_engine( try: import httpx async with httpx.AsyncClient(timeout=60.0) as client: - resp = await client.post( - f"{provider.base_url}/api{unload_ep}", - json={"data": []}, - ) - resp.raise_for_status() - result = resp.json() - return {"engine": engine, "endpoint": unload_ep, "result": result, "status": "unloaded"} + result = await provider._call_gradio(client, unload_ep, [], timeout=60.0) + return {"engine": engine, "endpoint": unload_ep, "result": result, "status": "unloaded"} except Exception as e: logger.exception("tts_unload_engine failed for engine=%s", engine) return {"error": str(e), "engine": engine}