docs: VOICE_DEPLOYMENT_SPEC §4 — exclusivité via Profile.voiceId, suppression sidecar .owner
L'exclusivité s'appuie sur le mapping voix↔profil EXISTANT, pas un artefact parallèle : l'app joue toujours activeProfile.voiceId (playback déjà exclusif par profil). Central = autorité d'assignation (verrouiller = assigner Profile.voiceId au propriétaire, jamais ailleurs + déploiement ciblé). Aucun code app requis (garde-fou picker optionnel sans fichier). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0924174c7b
commit
0eb1fd12bc
|
|
@ -77,42 +77,40 @@ La règle de **localisation** est enforced par Kazeia-central au déploiement
|
|||
la/les tablette(s) où ce profil est déployé ;
|
||||
- seules les voix **globales/non-exclusives** sont déployées sur le parc.
|
||||
|
||||
⚠️ Mais une tablette héberge **plusieurs profils patients** (confirmé). La localisation
|
||||
ne suffit donc **pas** : un `.cvps` exclusif à A, présent sur la tablette partagée
|
||||
(parce que A y est), serait techniquement sélectionnable par B. → l'exclusivité doit
|
||||
aussi être enforced **on-device** : c'est l'objet du §4, qui devient **requis**.
|
||||
⚠️ Une tablette héberge **plusieurs profils patients** (confirmé). Mais l'exclusivité au
|
||||
playback est **déjà garantie** par le binding existant : l'app sélectionne toujours la
|
||||
voix du **profil actif** (`KazeiaService` : `activeProfile.voiceId ?: DEFAULT_VOICE_ID`).
|
||||
Un patient B n'utilise donc une voix exclusive à A **que si** `B.voiceId` pointe dessus.
|
||||
Le point de contrôle est donc l'**assignation de `Profile.voiceId`**, pas un marqueur
|
||||
parallèle. Voir §4 — l'exclusivité s'appuie sur le mapping voix↔profil existant, sans
|
||||
nouvel artefact app.
|
||||
|
||||
---
|
||||
|
||||
## 4. Adaptation **REQUISE** — exclusivité on-device (tablettes multi-patients)
|
||||
## 4. Exclusivité — via le mapping `Profile.voiceId` existant (pas de nouvel artefact)
|
||||
|
||||
Décidé : une tablette héberge **plusieurs profils patients**. Une voix exclusive ne doit
|
||||
donc être **ni sélectionnable, ni audible** par un profil qui n'en est pas propriétaire,
|
||||
même si son `.cvps` est physiquement sur la tablette.
|
||||
L'exclusivité s'appuie sur le binding **voix↔profil déjà présent** (`Profile.voiceId`),
|
||||
pas sur un marqueur parallèle. Kazeia-central est l'**autorité d'assignation** (il a le
|
||||
CRUD profils via le provider) :
|
||||
|
||||
### 4.1 Marqueur de propriété — sidecar `.owner`
|
||||
Kazeia-central pousse, **à côté** du `.cvps`, un fichier sidecar :
|
||||
```
|
||||
cosyvoice/<voiceId>.cvps # l'artefact voix (inchangé)
|
||||
cosyvoice/<voiceId>.owner # présent SI exclusive → contient le profileId propriétaire
|
||||
```
|
||||
- **Absence de `.owner`** ⇒ voix **généraliste** : sélectionnable par tout profil.
|
||||
- **Présence de `.owner`** ⇒ voix **exclusive** au `profileId` qu'il contient (UTF-8,
|
||||
une ligne). Cohérent avec le modèle « tout par fichier + `adb push` » (comme le `.cvps`).
|
||||
- **Verrouiller** une voix sur un patient = central assigne `Profile.voiceId = <voix>` au
|
||||
profil propriétaire, **et ne l'assigne à aucun autre profil** (sur la tablette ni
|
||||
ailleurs). C'est ça l'exclusivité.
|
||||
- **Déploiement** : central pousse le `.cvps` uniquement sur la/les tablette(s) du
|
||||
propriétaire (cf. §3).
|
||||
- **Playback** : déjà exclusif — l'app n'utilise que `activeProfile.voiceId`.
|
||||
|
||||
### 4.2 Enforcement côté app
|
||||
- **`/voices`** : exposer une colonne **`owner_profile_id`** (lue depuis `<id>.owner`,
|
||||
vide si généraliste) — pour que le picker filtre.
|
||||
- **Picker / assignation `Profile.voiceId`** : ne pas proposer/permettre l'assignation
|
||||
d'une voix exclusive à un profil ≠ propriétaire.
|
||||
- **Runtime (`KazeiaService.setVoiceId` / `CosyVoiceTtsEngine.ensureVoice`)** : garde-fou
|
||||
défensif — si le profil actif n'est pas propriétaire d'une voix exclusive demandée,
|
||||
**repli sur `DEFAULT_VOICE_ID`** (ne jamais faire parler un patient avec la voix
|
||||
exclusive d'un autre).
|
||||
### Côté app — rien de nouveau requis pour l'exclusivité
|
||||
Le playback par profil actif suffit. **Optionnel** (garde-fou de gouvernance, si le
|
||||
picker admin on-device autorise la (ré)assignation des voix) : l'app peut, à partir de
|
||||
la liste des profils qu'elle a déjà, signaler qu'une voix est **déjà assignée à un autre
|
||||
profil** et déconseiller/empêcher de la réassigner — **sans aucun fichier ni colonne
|
||||
supplémentaire**, juste en croisant `Profile.voiceId`. À implémenter seulement si
|
||||
l'assignation reste possible on-device ; sinon l'autorité centrale suffit.
|
||||
|
||||
> Kazeia-central connaît déjà `locked_profile_id` par voix et poussera/retirera le
|
||||
> sidecar `.owner` au verrouillage/déverrouillage. L'app n'a qu'à **lire** le sidecar et
|
||||
> appliquer le filtrage + le garde-fou runtime.
|
||||
> Kazeia-central garde `locked_profile_id` par voix **en interne** (sa politique) et le
|
||||
> matérialise par l'assignation `Profile.voiceId` + la localisation du `.cvps`. Aucun
|
||||
> sidecar `.owner`, aucune ontologie d'exclusivité à dupliquer dans l'app.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -122,11 +120,12 @@ cosyvoice/<voiceId>.owner # présent SI exclusive → contient le profileId
|
|||
| --- | --- | --- | --- |
|
||||
| 1 | `/voices` scanne WAV (« à convertir ») **et** `.cvps` (« prête »), col. `cvps_exists` | inventaire voulu | curseur `voicesCursor()` |
|
||||
| 2 | `voices_reload` (rescan + `RELOAD_VOICES`, constante `ACTION_RELOAD_VOICES`) | important | méthode `call()` |
|
||||
| 4 | exclusivité on-device : lire `cosyvoice/<id>.owner`, col. `owner_profile_id`, filtrer picker + repli runtime | **requis** (multi-patients) | `voicesCursor()` + picker + `setVoiceId` |
|
||||
| 4 | exclusivité = via `Profile.voiceId` existant + autorité d'assignation centrale | **aucun code app** (garde-fou picker optionnel, sans artefact) | central / §4 |
|
||||
|
||||
Côté Kazeia-central (déjà fait / à faire, **pas** côté app) : enrôlement, archive
|
||||
chiffrée du WAV, suppression du WAV device, **politique de déploiement verrou-conscient**,
|
||||
et la **distribution flotte** (pousser les voix globales sur le parc, les exclusives chez
|
||||
**autorité d'assignation** (`Profile.voiceId` du propriétaire, jamais ailleurs pour une
|
||||
voix exclusive), et la **distribution flotte** (voix globales sur le parc, exclusives chez
|
||||
leur patient) — en cours.
|
||||
|
||||
---
|
||||
|
|
|
|||
Loading…
Reference in New Issue