Content Studio + App — Backlog di bonifica (TUTTE le criticità, una a una)
Direttiva founder 2026-06-02: "TUTTE LE CRITICHE DEVONO ASSOLUTAMENTE ESSERE RISOLTE", in una sessione dedicata che bonifica l'app di ogni problema (legale, strutturale, costi, prodotto) e rende reale il routing sovrano così "dati in Europa" diventa vendibile. Fonte: spec
content-studio-spec-2026-06-02.md+ 3 critiche avversariali (legale CH/EU, CFO, prodotto), verificate contro codice e DByqhixdqipojvgzfadufoil 2026-06-02. Legenda owner: S3 = sessione Content · S2 = sessione Sales · X = cross-cutting app-wide · F = richiede azione/infra founder · DEC = bloccato da una delle 7 decisioni. Legenda stato: ☐ aperto · ◐ in corso · ☑ risolto.
A. LEGALE / COMPLIANCE (Critica 1) — priorità massima, è la liability penale CHF 250k
| ID | Problema | Gravità | Owner | Stato |
|---|---|---|---|---|
| L1 | pseudonymizePii() non è chiamato da nessuna parte nel codebase (codice morto). Nessun trattamento verso provider US è oggi pseudonimizzato. Serve gate centralizzato fail-closed nel provider-registry, applicato a TUTTI gli endpoint. |
Gravissima | X | ◐ (S3 PR#140: cablato nel content endpoint via api/content/_lib/pseudonymize.ts; gate app-wide + NER nomi propri aperti) |
| L2 | api/sales/generate-outreach.ts LIVE: JWT non verificato (IDOR) + invia nome/azienda/ruolo/città di decisori reali a Mistral senza pseudonimizzazione né base legale (manca LIA). Fix: verifyUser + Legitimate Interest Assessment + pseudonimizzazione. |
Gravissima | S2 | ☐ |
| L3 | Prompt grezzo scritto in content_generations.prompt (anche dal mio generate-text.ts): PII in chiaro nel DB + verso provider. Fix: solo versione pseudonimizzata/hash; trigger che rifiuta prompt non marcato. |
Alta | S3 | ☑ (S3 PR#140: prompt pseudonimizzato prima di store/provider, metadata.pii_pseudonymized; trigger DB = follow-up) |
| L4 | Riuso di audit_log_gdpr_art9 (registro dati sanitari) per attestazioni contenuti: finalità sbagliata, inquina il registro Art.9. Fix: tabella content_audit_log dedicata append-only. |
Grave | S3/X | ☐ |
| L5 | legal_acceptances.document_type bloccato a 4 valori sia DB sia tipo TS: voice_clone_consent e content_studio_tos non registrabili. Finché aperto, nessun cloning ha base legale. Fix: estendere entrambi + test gate. |
Grave | X | ☐ |
| L6 | Routing sovrano EU = 0 righe ma posizionato come feature vendibile. Vendere "dati in Europa / a norma" ora = pubblicità potenzialmente ingannevole + responsabilità verso cliente. Fix: (a) bloccare in prod l'endpoint consumer Google hard-fail; (b) costruire il routing EU reale; (c) non usare il claim finché non testato. | Grave | X / F | ◐ (S3 PR#140: (a) fatto — guardia hard-fail consumer in prod, 503 sovereign_routing_required. (b) routing Vertex EU reale = SOV1, aperto. (c) claim non vendibile finché aperto) |
| L7 | modality (telemetria proposta) usa valori voice/cgi non allineati al CHECK reale (audio sì). Fix: allineare vocabolario prima della migration. |
Media | S3 | ◐ (S3 PR#140: trovato e fixato bug VIVO collegato — generation_type: 'social_text' non ammesso dal CHECK → era insert-fail garantito; corretto a 'text'. Vocab modality per la migration resta) |
| L8 | ToS promette indennizzi upstream incerti ("le garanzie del fornitore si estendono a te"). Fix: "ti giriamo le garanzie ove esistenti e nei loro limiti, senza garanzia di Multiverbe". Far passare da legale + humanizer. | Media | F/X | ☐ |
| L9 | Notifica 30gg sub-processor (revFADP art.9) senza registro versionato accettato per-workspace. Fix: versionare la sub-processor list in legal_acceptances. |
Media | X | ☐ |
| L10 | EXIF non strippato di default (GPS = dato personale) + nessun rilevamento volti. Fix: EXIF-strip server-side obbligatorio prima del dispatch; regola difensiva "foto utente → solo Vertex EU" finché manca face-detection. | Media | X | ☐ |
B. SOVRANITÀ REALE — "vendere dati in Europa" (il cuore della direttiva)
| ID | Problema | Owner | Stato |
|---|---|---|---|
| SOV1 | Migrare generate-text.ts da endpoint consumer Google (generativelanguage.googleapis.com) a Vertex AI EU con service account. È il P0 che protegge moat + liability. |
S3 + F (GCP) | ☐ |
| SOV2 | Migrare la generazione immagine (generate-social-media, oggi Gemini consumer) a FLUX Azure EU o Imagen Vertex EU. |
X + F (Azure/GCP) | ☐ |
| SOV3 | Costruire il gateway/provider-registry fail-closed (api/content/_lib/provider-registry.ts): region + flag legali + pseudonimizzazione obbligatoria pre-dispatch. Unico punto di verità. |
X | ☐ |
| SOV4 | Forzare EU Data Boundary su Azure per FLUX (ticket Microsoft; default è "global"). | F | ☐ |
| SOV5 | Firmare DPA con Google/Microsoft/Mistral/fal.ai + versionare sub-processor + TIA per ogni extra-UE. | F | ☐ |
| SOV6 | Flag "modalità sovranità totale" per-tenant + telemetria sovereign/provider_region → registro nDSG automatico. |
X | ☐ |
| SOV7 | Solo DOPO SOV1-SOV6 testati: sbloccare il claim marketing "dati in Europa / a norma". | F/DEC#5 | ☐ |
C. COSTI / PRICING (Critica 2) — proteggono il margine
| ID | Problema | Owner | Stato |
|---|---|---|---|
| C1 | Video contati in secondi (Pro 40s / Business 120s), non in clip. Neutralizza l'errore Veo (15s = CHF 1.98 non 1.06). | DEC#2 + X | ☐ |
| C2 | Derivazione multi-ratio del visual = 0.25 unità/ratio (il re-frame rigenera, non è gratis). Testo per N canali resta gratis. Video: un solo ratio per generazione. | X | ☐ |
| C3 | Upscale = 0.5 unità foto nel counter images_count (oggi manca il counter). |
X | ☐ |
| C4 | Separare cap testo vs media (ai_text_generations vs ai_media_generations): oggi il testo satura ai_generations. |
X | ☐ |
| C5 | Hard-cap sui media pesanti già in Fase A (non Fase B). CGI fuori dal mensile finché COGS non confermato <$6. | DEC#3 + X | ☐ |
| C6 | Backstop COST_CAP_CHF=50 è globale (tutti i pianeti) e soft: il solo Content Business lo satura. Hard-cap media da subito + budget hard in modalità Auto. |
X | ☐ |
| C7 | Lock-in Veo (unico video sovrano EU, prezzo volatile): floor di margine sui pacchetti video che si ricalcola se Google muove il listino. | X/F | ☐ |
| C8 | Rollover quota max 2x (un churner non accumula 200 foto per bruciarle prima di disdire). | X | ☐ |
| C9 | A/B reale qualità voce IT (Voxtral vs ElevenLabs) prima di mettere Voxtral default. | F/X | ☐ |
D. PRODOTTO / STRUTTURA (Critica 3) — completezza dell'esperienza
| ID | Problema | Sev. | Owner | Stato |
|---|---|---|---|---|
| P1 | Riconciliare social_posts (publish) con content_items (concept) invece di biforcare. Migrazione/decisione scritta PRIMA della migration. |
P0 bloccante | X | ☐ |
| P2 | Immagini live (generate-social-media) transizionate al gateway sovrano (= SOV2). |
P0 | X | ☐ |
| P3 | Agganciare l'intelligence già viva (analyze-market-trends + analyze-competitors) come 4° slot "perché ora" del context-assembly. |
P0 | S3/X | ☐ |
| P4 | Editing video post-generazione (trim, cover frame, on/off sottotitoli, musica): gratis client-side; ri-gen = 1 unità. | P1 | X | ☐ |
| P5 | Onestà UX: derivazione ratio sul video non è gratis (un solo ratio per generazione, gli altri costano). | P1 | X | ☐ |
| P6 | "Correggi questo" (FLUX Kontext edit mirato) vs "Rigenera tutto". + micro-ragione di scarto che nutre il brand. | P1 | X | ☐ |
| P7 | Piano mensile: approva-in-blocco settimanale (non 30 push singoli). | P1 | X | ☐ |
| P8 | Brand auto-learning: ogni approvazione/scarto/edit scrive segnale in content_brand_memory → il brand si costruisce anche per chi salta l'onboarding. Antidoto allo slop. |
P1 | X | ☐ |
| P9 | Stato "nessun canale connesso" nel flusso crea (gate soft + fallback download manuale). | P1 | S3/X | ☐ |
| P10 | Smontare i controlli tecnici già spediti in ContentCreatorPage (selettore ratio, style, checkbox "doppio passaggio Gemini", prompt visivo): contraddicono i "3 tap". |
P2 | S3 | ☐ |
| P11 | Preset per scopo: max 4-5 per settore, ordinati per rilevanza temporale + "Altro: dimmi cosa vuoi" (riusa sector-detection). |
P2 | S3 | ☐ |
| P12 | Lingua: aggiungere fr (Romandia) + trattare la lingua come dimensione di derivazione (1 concept → varianti lingua). |
P2 | X | ☐ |
| P13 | Gate review differenziato: video = player full-screen, approva dopo la visione (play loggato = bonus attestazione Art.50(4)). | P2 | S3 | ☐ |
| P14 | Ritorno metriche nel pianeta dopo l'handoff (read-only da Marketing) → chiude il ciclo crea→pubblica→impara, nutre il brand. | P2 | X | ☐ |
Ordine di esecuzione consigliato (il più severo, dalle critiche)
- Bloccare in prod l'endpoint Gemini consumer (hard-fail) — L6/SOV1.
- Gate pseudonimizzazione centralizzato fail-closed prima di ogni dispatch, su TUTTI gli endpoint — L1.
- Fix
generate-outreach.ts(verifyUser + LIA + pseudonimizzazione): è live — L2. - Smettere di scrivere prompt grezzo nel ledger — L3.
- Decidere la riconciliazione
social_posts/content_itemsprima della migration — P1. - Separare l'audit contenuti da
audit_log_gdpr_art9— L4. Sbloccaredocument_type(DB+TS) — L5. - Costruire il routing EU reale (Vertex/Azure) + provider-registry — SOV1-SOV3. Solo dopo, vendere la sovranità — SOV7.
- Correzioni costo (cap video in secondi, separare cap testo/media, hard-cap media Fase A) — C1/C4/C5.
- Completezza prodotto P3→P14 in ordine di severità.
Dipendenze dalle 7 decisioni founder (spec §10)
- DEC#2 (quota video in secondi) → sblocca C1.
- DEC#3 (CGI inclusa/add-on) → sblocca C5.
- DEC#5 (quando vendere la sovranità) → governa SOV7 e i claim marketing.
- DEC#6 (chi fixa generate-outreach.ts) → L2.
- Le altre (DEC#1 Content da Pro, DEC#4 quota voce, DEC#7 Higgsfield) non bloccano la bonifica tecnica.
Stato dopo la sessione di bonifica · 2026-06-02 · PR #145
Le tabelle sopra sono lo stato as-found. Questa sezione è la verità post-sessione. Repo: Multiverbe · PR https://github.com/metaverbe-hub/Multiverbe/pull/145 (branch
claude/hungry-chandrasekhar-4e05b6). Nota importante: il codice merged di PR #140 non conteneva L1/L3/L6/L7 (il backlog li dava per fatti — era drift). Verificati sul codice reale e chiusi qui.generation_type:'social_text'violava il CHECK reale → era un insert-fail vivo, oratext.
Legenda: ☑ chiuso · ◐ codice/schema pronto, resta applicazione o follow-up · 🔒 bloccato-da-founder (infra/legale).
| ID | Stato | Dettaglio + ref |
|---|---|---|
| L1 | ☑ | Gate PII centralizzato fail-closed nel gateway + consolidato app-wide (un solo gate canonico api/_lib/pii.ts, copie inline rimosse, dead code frontend eliminato). La critica "nulla è pseudonimizzato" era un falso-negativo da name-search: sole-ask/sole-crm/sector-deduction già pseudonimizzavano. Follow-up: NER nomi propri liberi. |
| L2 | ☑ | generate-outreach hardened: verifyUser (era JWT decode-senza-verify → IDOR), route Mistral FR sovrana, LIA scritta (ops/lia-cold-outreach-2026-06-02.md), audit log con base giuridica. In prod-ready appena confermi ZDR+DPA Mistral (infra B1). |
| L3 | ☑ | Ledger salva il prompt pseudonimizzato + prompt_sha256, mai grezzo. Trigger DB che rifiuta prompt non marcato = follow-up opzionale. |
| L4 | ◐ | content_audit_log dedicata append-only (trigger anti-UPDATE/DELETE) in 2026-06-02a. Applicare via Dashboard. NON riusa il registro Art.9. |
| L5 | ☑ | document_type CHECK esteso (2026-06-02a) + union TS (compliance.ts): content_studio_tos, voice_clone_consent, sub_processor_list. Applicare migration. |
| L6 | ☑ | Endpoint consumer Google rimosso; blocklist backend vietati asserita; dispatch fail-closed 503, mai downgrade silenzioso. |
| L7 | ☑ | generation_type 'social_text'→'text' (bug vivo: violava il CHECK reale). |
| L8 | 🔒 | ToS clausola indennizzi da riscrivere (legale + humanizer). Vedi infra checklist F. |
| L9 | ◐ | sub_processor_list sbloccato (migration). Flusso accettazione versionata = follow-up. |
| L10 | ◐ | EXIF-strip + "foto utente → solo Vertex EU": si applica quando arriva l'adapter immagini (SOV2). Regola definita, enforcement con SOV2. |
| SOV1 | ◐🔒 | Adapter Vertex EU (Gemini + Claude) + auth service-account + routing: codice completo, fail-closed. Attesa provisioning GCP (infra A). |
| SOV2 | ◐🔒 | Registry pronto (azure-flux-eu / vertex-imagen-eu). Manca adapter immagini + migrazione generate-social-media. Dipende anche da infra A/B2. |
| SOV3 | ☑ | provider-registry fail-closed + routing per modalità/tier costruito. |
| SOV4 | 🔒 | Ticket EU Data Boundary Azure (infra B2). |
| SOV5 | 🔒 | DPA Google/Microsoft/Mistral/fal (infra C). |
| SOV6 | ☑ | Telemetria residenza scritta + vista sovereignty_register_v (migration). Flag "sovranità totale" per-tenant = follow-up piccolo. |
| SOV7 | 🔒 | Claim "dati in Europa" sbloccabile solo dopo SOV1-6 testati (infra E). |
| C1 | ☑ | Video in secondi (40/120) in tier_caps (2026-06-02c). |
| C2 | ◐ | Modello unità ratio (0.25) definito; enforcement all'endpoint media (quando arriva). |
| C3 | ◐ | Upscale 0.5 unità: idem, forward-looking. |
| C4 | ☑ | Cap testo vs media separati (ai_text_generations soft vs ai_media_generations hard). |
| C5 | ☑ | Media hard-capped già in Fase A (ALWAYS_HARD_METRICS). CGI fuori MVP (addendum). |
| C6 | ☑ | Hard media + fail-closed su errore per i contenuti a franchi (mai costo illimitato). |
| C7 | 🔒 | Floor margine Veo da ricalcolare se Google muove il listino (processo ops). |
| C8 | ◐ | Rollover 2x: content_credit_ledger lo supporta; cron di rollover = follow-up. |
| C9 | 🔒 | A/B voce IT (infra B3). |
| P1 | ☑ | Decisione riconciliazione scritta (database/migrations/README-content-reconciliation-2026-06-02.md): content_items=concept, social_posts=publish. |
| P2 | ◐🔒 | = SOV2. |
| P3 | ◐ | Agganciare trend/competitor come slot "perché ora": context-assembly = follow-up (code-doable, Fase B1). |
| P4 | ◐ | Editing video post-gen: frontend, quando arriva il video (Fase B1). |
| P5 | ◐ | Onestà UX ratio video non gratis: documentato; copy UI con il video. |
| P6 | ◐ | "Correggi questo" (FLUX Kontext): richiede adapter immagini (Fase B1). |
| P7 | ◐ | Approva-in-blocco settimanale: schema content_plans pronto; UI Fase B2. |
| P8 | ◐ | Brand auto-learning: content_brand_memory esiste; scrittura segnale su approve/scarto = follow-up (code-doable). |
| P9 | ◐ | Stato "nessun canale connesso": frontend (Fase B1). |
| P10 | ◐ | Smontare controlli tecnici ContentCreatorPage: frontend + skill design + preview (Fase B1). |
| P11 | ◐ | Preset per scopo: content-seeds esiste; ordinamento per rilevanza temporale = follow-up. |
| P12 | ◐ | Lingua fr aggiunta (system prompt + route). "Lingua come dimensione di derivazione" = follow-up. |
| P13 | ◐ | Gate review video full-screen: frontend, con il video. |
| P14 | ◐ | Ritorno metriche nel pianeta: frontend + integrazione Marketing. |
| R1 | ☑ | Output platform-ready (caption+hashtag+ratio+cta+alt+orario) come pacchetto JSON. |
| R2 | ☑ | Routing qualità per tier (Business long-form → Claude su Vertex EU). |
| R3 | ◐ | Durata video selezionabile + score: con il motore video (Fase B1). |
| R4 | ◐ | Prompt scrivibile dall'utente: il backend accetta prompt libero; toggle "proposte vs scrivi il tuo" = UI follow-up. |
| R5 | ◐ | Ring: content_credit_ledger + cap effettivo (cap+crediti) lato lib. Componente UI ring (stile Apple) = frontend follow-up. |
| R6 | ◐ | Preview→commit: content_assets.stage + conteggio solo final. Endpoint preview economico = con il motore media. |
| R7 | ☑ | CGI rimossa dall'MVP (non in caps/registry). |
| Knowledge | ☑ | Layer conoscenza esperta (api/_lib/content-knowledge): playbook 8 piattaforme + framework + psicologia colori → lente esperta a ogni generazione. Graduazione a pgvector = follow-up. |
Sintesi: tutte le criticità legali bloccanti (L1-L7) sono chiuse o pronte-da-applicare; la sovranità è reale e fail-closed (manca solo il provisioning founder); i costi sono protetti (cap media hard da subito); il Knowledge layer e l'output platform-ready danno al pianeta la "mente da social media manager". Il resto è frontend/Fase B1-B2 o bloccato-da-founder, tutto tracciato qui sopra con la ragione.
Stato dopo la sessione Pianeta Content (frontend) · 2026-06-03 · PR #146
Sessione dedicata "Pianeta Content perfetto": lato UX/derivazione/strategia, in parallelo a #145 (backend gateway/knowledge). Branch
claude/romantic-wu-ca63e3, off master. Consuma il contratto #145 con degrado grazioso (503 → manuale). Niente fork: riusasocial_posts+useContentStudio.
Legenda: ☑ chiuso · ◐ parziale (resta backend/infra o follow-up).
| ID | Stato | Dettaglio (PR #146) |
|---|---|---|
| R1 | ☑ | Format-derivation frontend: lib/content-studio/channels.ts (8 piattaforme × formati, ratio/pixel/safe-zone 2026) + derive.ts (1 concept → N pacchetti platform-ready: caption alla finestra di canale, hashtag tagliati, formato per scopo, alt, orario). SafeZoneFrame disegna la zona di sicurezza. |
| R4 | ☑ | Prompt libero ("Altro: dimmi cosa vuoi") + preset + "Altre così" (varianti). Controllo sempre all'utente. |
| R5 | ◐ | Ring stile Apple Activity (QuotaRing + useContentQuota): anello per metrica, bonus crediti, quanto manca, top-up. Resta: applicare migration 2026-06-02c + usage media reale (quando arriva il motore). |
| C4 | ☑(UI) | Ring separa testo (illimitato) dai media (anelli) lato UI. |
| P5 | ☑ | Onestà costo visual per ratio mostrata su ogni card (video 1 ratio/gen, immagine ricomposta). |
| P9 | ☑ | Canali oltre Meta+LinkedIn = copia/scarica; degrado 503 → scrivi a mano, adatto io ai social. |
| P10 | ☑ | Controlli tecnici smontati: ContentCreatorPage shell slim, niente ratio/style/doppio-passaggio/prompt-visivo. Tono/lingua in "Tono e dettagli". |
| P11 | ☑ | Preset settore (≤5 + Altro), ordinati per rilevanza temporale (presets.ts, riusa content-seeds). |
| P12 | ◐ | Lingua fr nel selettore avanzato; "lingua come dimensione di derivazione" = follow-up. |
| P13 | ◐ | Gate review a 3 tap (guarda prima di approvare); player video full-screen arriva col motore video (Fase B1). |
| Le tre vie + evento/offerta | ☑ | Richiesta founder: goals.ts (farmi conoscere/dare valore/vendere + evento + offerta) + StepScopo. Mappa a funnel/objective/framework/CTA/KPI. Cadenza teaser→promemoria→ultima-chiamata. |
| Best-time + handoff Marketing | ☑ | Richiesta founder: best-time.ts (piattaforma × settore × località CH, con "perché" + personalizzazione futura) + scheduling.ts (contratto handoff) + toggle "programma nel giorno migliore" (auto/su conferma). |
| Knowledge visibile | ☑ | rationale.ts: lente esperta resa visibile ("perché formato/colore/orario/framework"). Complementare al backend #145. |
| R3 | ☑ | Durata selezionabile + score lunghezza-qualità-performance (video-score.ts puro+testato) + VideoDurationPicker (slider, score live, anteprima→commit). Render video reale = gateway (Fase B1). |
| P14 | ☑ | Ritorno metriche: tab "Risultati" + MetricsReturnPanel (legge social_posts.metrics_*, top performer = "Ha funzionato"). Chiude crea→pubblica→impara. |
| P3 | ☑ | "Perché ora" in StepScopo via analyze-market-trends (edge function riusata) come proposte proattive. Graceful se non keyato. |
| P8 | ☑ | Brand auto-learning: useBrandSignal (approve/reject) + migration additiva content_brand_signals (append-only, RLS workspace; content_brand_memory è un profilo → tabella dedicata). Best-effort fino all'apply via Dashboard. |
| R6 | ◐ | Preview→commit: framing UI fatto ("l'anteprima non consuma"); endpoint anteprima economica col motore media (content_assets.stage già a prod). |
| P4/P6 | ☐ | Editing post-gen / "correggi questo" (FLUX Kontext): col motore media (gateway). |
Validazione: 0 errori tsc (CI Linux verde); logica pura testata (vitest + smoke tsx). tsc/vitest non eseguibili sul worktree Windows (pnpm/postcss) → gate = CI.
✅ IN PRODUZIONE (2026-06-03): PR #146 mergiata in master (cab4493) → deploy Vercel prod. Additiva, degrada con grazia sul backend attuale.
📌 Reminder BOS / sessioni future (direttiva founder 2026-06-03): il Pianeta Content non è finito, va migliorato ancora (livello Higgsfield + occhio business). Prossimi passi quando il gateway sovrano è provisionato: render video Veo + immagini FLUX, editing post-gen (P4), "correggi questo" FLUX Kontext (P6), endpoint anteprima→commit (R6). Inoltre: applicare migration database/migrations/2026-06-03_content_brand_signals.sql via Dashboard (accende P8), QA visivo reale, polish UX continuo, e — quando i dati ci sono — far imparare davvero il best-time dall'audience del cliente.
Stato dopo la sessione extension (backend compliance) · 2026-06-03 · PR #147
Sessione dedicata "big tech 100% compliant + routing EU reale", stacked su #145. Prima ho rivisto #145 a fondo: merge-ready (la review avversariale automatica dava falsi positivi perché leggeva il working tree pre-#145; ogni file critico verificato a mano). Poi ho chiuso gli item code-doable rimasti, dai più gravi. Branch
claude/sovereign-bonifica-extend. Logica critica validata via Node contro i moduli reali.
Legenda: ☑ chiuso · ◐ codice pronto, resta innesto founder/Fase B · 🔒 bloccato-da-founder.
| ID | Stato | Dettaglio (PR #147) |
|---|---|---|
| L1 | ☑ | NER nomi propri chiuso (era il follow-up aperto). redactProperNames() nel gate canonico (api/_lib/pii.ts) + mirror Deno. Euristica conservativa ML-free; si applica solo prima di un hop NON sovrano (piiLevel:'full'), sulla rotta EU i nomi restano (residenza). Commit 859b996. |
| L6 | ☑ | Esteso a TUTTI i path. Le 8 ai-copilot-* (edge) usavano Gemini consumer: nuovo _shared/sovereign.ts (forbidden-host + gate PII + adapter Vertex EU reale RS256 + fail-closed). ai-client.ts ora Vertex→fail-closed→fallback dev. Commit 3cb8f71. ◐ attivazione = founder accende SOVEREIGN_ENFORCE/provisiona Vertex. |
| L10 | ☑/◐ | EXIF-strip lossless JPEG/PNG (api/_lib/exif-strip.ts) + regola ROUTE_USER_PHOTOS_TO=sovereign-eu-only. Test 13/13. ◐ innesto nell'adapter immagini SOV2. Commit bf24f16. |
| SOV6 | ☑ | Flag per-tenant forceSovereign (vince su ogni opt-in caller) nel registry + dispatch. Commit a97e208. |
| L9 | ☑/◐ | Lista sub-processor versionata (src/lib/sub-processors.ts, SUB_PROCESSOR_LIST_VERSION) = fonte di verità per trasparenza + accettazione (legal_acceptances). ◐ schermata UI accettazione (Fase B). Commit 73fc969. |
| L8 | ◐🔒 | Clausola ToS garanzie riscritta (no indennizzi upstream incerti), via humanizer: docs/content-studio-tos-garanzie-DRAFT.md. 🔒 sign-off legale. Commit 5fb6dad. |
| SOV1/2/4/5 | 🔒 | Runbook founder ESATTO: docs/sovereign-routing-provisioning.md (GCP Vertex EU service account, Mistral ZDR+DPA, Azure EU + ticket EU Data Boundary, switch SOVEREIGN_ENFORCE, matrice env→feature, checklist DPA, validazione). Codice pronto, manca solo l'innesto infra. Commit 5fb6dad. |
| SOV7 | 🔒 | Claim "dati in Europa" sbloccabile dopo provisioning + 4 test verdi del runbook §8. |
⚠️ Decisione founder (impatto prod): mergeare #145 + #147 porta testo Content, outreach e le 8 copilot a fail-closed 503 in prod finché Vertex EU non è provisionato (compliance voluta). SOVEREIGN_ENFORCE=false = escape hatch documentato. Sequenza nel runbook.
Sintesi: il blocco endpoint consumer è ora su tutti i path (api + edge); il gate PII è completo (strutturato + NER) e centralizzato; EXIF, sub-processor versionati, flag sovranità per-tenant chiusi; il routing EU reale è codice pronto + runbook, manca solo l'infra founder. Nessun item legale lasciato muto.
Stato dopo la sessione Fase B1 · 2026-06-03 · PR #155
Sessione dedicata "avanza il Pianeta Content a B1, qualità big-tech". Anti-drift: #145 e #147 erano ancora APERTE (mai mergiate) e #145 confliggeva con master. Riconciliate in
feat/content-b1(PR #155, supersede #145/#147). CI verde (Typecheck+build pass). Validazione api/: esbuild --bundle (95/95) + smoke logici.
| ID | Stato | Dettaglio (PR #155) |
|---|---|---|
| Integrazione | ☑ | #145+#147 su master, conflitti risolti preservando l'identità SSoT #144 (buildSoleIdentity). Fix prod-safety: 38 import → ESM .js//index.js (api/ è ESM NodeNext, estensionless = ERR_MODULE_NOT_FOUND a runtime; esbuild non lo vede). |
| SOV2 / P2(motore) | ☑ | Motore immagini sovrano: imagen-adapter.ts (Imagen 4 :predict Vertex EU, SynthID nativo) + dispatchImage (PII gate, breaker, retry, sha256, costo) + POST /api/content/generate-image (hard-cap media, preview→commit R6, EXIF-strip L10, content_assets con provenance), routing per tier (Pro→Fast, Business→Ultra). |
| L10 | ☑ | EXIF-strip innestato nel flusso immagini (storage.ts strippa prima di persistere; SynthID vive nei pixel → sopravvive). |
| C2 / C3 | ◐ | Costo per-immagine cablato in dispatchImage; derivazione ratio/upscale come unità = quando arriva l'editing. |
| Provenance C2PA | ☑/◐ | content-provenance.ts: manifest C2PA (c2pa.created + digitalSourceType IPTC, do-not-train, hash-binding, ref SynthID) + label visibile, salvati su content_assets. ◐ firma crittografica = C2PA_SIGNING_CERT founder (manifest emesso unsigned, fail-closed). |
| P8 | ◐ | approve.ts scrive segnale 'approve' server-side in content_brand_signals (fail-soft). Applicare migration 2026-06-03_content_brand_signals.sql via Dashboard per accenderlo. |
| SOV1/2 (runtime) | 🔒 | Vertex EU: env GCP aggiunti dal founder, mai verificati a runtime. Testabile dopo deploy di #155 (runbook §8). Senza, fail-closed 503. |
| P3 | ☐ | Worker durabile: urgenza bassa per B1 (immagini veloci in-request); serve per il video. Prossimo. |
| P4 | ☐ | Context "perché ora" (trends/competitor 4° slot): prossimo. |
| P6 | ☐ | UX 3-tap + ring + wiring useGenerateMedia → /api/content/generate-image: prossimo (frontend + design). |
| P7 | ☐ | Swap gemini-3-flash (verificare model-id Vertex) + valutare Mistral Large 3. |
Sintesi B1: il pianeta ha ora un motore immagini sovrano end-to-end (concept → immagine EU, hard-capped, con provenance C2PA+SynthID e label Art.50) sopra il gateway integrato e prod-safe.
Update fine sessione — landati anche in #155: P4 (slot "perché ora": market-context.ts + body.marketSignals in generate-text, 4° slot) e P7 (Gemini 3 Flash default + env-override GCP_VERTEX_GEMINI_MODEL; leva Mistral Large 3 via MISTRAL_MODEL). Totale: integrazione + P1 + P2 + P4 + P5 + P7 su #155, CI verde.
Rinviati con razionale:
- P3 worker durabile → valore reale col motore video (modalità pesante, oggi OFF per CH); le immagini sono veloci in-request e un worker contraddirebbe la UX preview→commit.
ai_generation_jobspolimorfico è già pronto. Costruirlo CON il video. - P6 UX immagini → turno dedicato:
useGenerateMediaè definito ma non ancora cablato in UI (ContentCreatorPage genera solo testo). Serve build frontend reale (genera immagine nel 3-tap + ring usage reale dacontent_assets+ passamarketSignals) con skillmultiverbe-design+ QA Playwright.
Resta inoltre: provisioning Vertex (founder) per il test runtime reale.
Stato dopo la sessione Video Engine · 2026-06-04 · PR #171 / #173 / #176 / #177
Sessione dedicata "Pianeta Content oltre testo+immagini": motore video DACH-safe + architettura performante, qualità big-tech, tutto fail-closed finché un provider video non è provisionato. Anti-drift verificato sul codice + prod:
/api/content/sovereign-statusLIVE conferma testo+immagini sovrani già in prod; migrazioni2026-06-02b/capplicate (verificato via MCP) → substrato video (ai_generation_jobs polimorfico, content_assets, tier_caps.video_seconds 40/120, content_credit_ledger) già pronto, nessuna migration necessaria.
Legenda: ☑ chiuso · ◐ codice pronto, resta provisioning/innesto · 🔒 bloccato-da-founder/infra.
| ID | Stato | Dettaglio |
|---|---|---|
| P3 worker | ☑ | Worker durabile Inngest content-video-render (claim→submit→poll step.sleep→finalize→complete) su ai_generation_jobs (api/_lib/content-jobs.ts). Idempotency per-job + retry/backoff Inngest + cost-cap abort. Sovranità: l'evento porta solo jobId+workspace_id; la richiesta (prompt) vive in Supabase EU → PII mai a Inngest (US). PR #171 (CI verde). |
| P2/SOV video | ☑ | dispatchVideo submit/poll nel gateway + VIDEO_ROUTES quality-tier + adapter Firefly/Synthesia/Runway (api/_lib/sovereign/adapters/). Fail-closed senza env. PR #173. |
| C1/C2/C7 | ☑/◐ | Video in secondi già nei caps; estimateVideoCostChf per-provider (◐ riverificare prima di claim margine, C7). Derivazione ratio video = 1 ratio/gen (architettura). |
| R3 | ☑(BE) | Durata selezionabile cablata in storyboard/commit (durationSeconds 3-120). Score UI = video-score.ts frontend (PR #146). |
| R6 (la killer) | ☑ | Preview→commit: preview = storyboard dal motore TESTO sovrano (gratis, fuori dal ring); commit accoda il worker e brucia video_seconds solo lì → scarti gratis. POST /api/content/video-preview + generate-video + GET /video-status. PR #176. |
| Quality tier (top models) | ☑ | Decisione founder "top dei modelli + modo per incorporarli": Sovrano (Firefly/Synthesia EU, default + unico in forceSovereign) · Qualità Mondiale (Runway Gen-4.5, opt-in allowNonSovereign+consenso esplicito, etichettato fuori-UE). PR #173/#176. |
| Provenance video | ☑ | finalizeVideoAsset costruisce C2PA + label Art.50 + sha256 sul video (riusa content-provenance.ts). |
| P6a Quality Score | ☑ | Post Quality Score 0-100 + 1 suggerimento (stile Buffer), puro/offline, POST /api/content/quality-score. PR #177 (indipendente, base master). |
| Veo | 🔒 | Tenuto available:false ma la base "Pre-GA" è superata (ora GA+EU-region+indemnified, già su Vertex EU). Vale valutarne lo sblocco (allowlist Google + CH-billing). Adapter Veo da scrivere (predictLongRunning). |
| P4 | ☐ | Editing post-gen (trim/cover/sottotitoli) = client-side frontend; provenance video già fatta. |
| P5 | ☐ | Repurposing 1-clic = sessione dedicata (pesante, dipende da provider + trascrizione). |
| P6 b-e | ☐ | Loop metriche→contenuto · distillazione brand DNA (job Sole content_brand_signals→content_brand_memory) · sector-tuning profondo · Knowledge→pgvector (2026-07-15a). |
🔒 BLOCCATO da infra/founder (sessione "sblocco infra" parallela): env provider video (RUNWAY_API_KEY / ADOBE_FIREFLY_CLIENT_ID+SECRET + DPA Adobe per residenza EU / SYNTHESIA_API_KEY) + INNGEST_EVENT_KEY per accodare. Bit schema-volatili degli adapter = override-via-env (fix a provisioning senza code change). Wiring frontend (ContentCreatorPage → endpoint video + ring reale + badge quality-score) = sessione design+Playwright.
Questo backlog è la SSoT della sessione di bonifica dedicata. Ogni item chiuso → spuntare lo stato e linkare il commit/PR.