diff --git a/Cargo.toml b/Cargo.toml index 301fa9c..3ae15c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 637 +# version: 638 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-raw-transaction-ingest-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] [workspace.package] -version = "0.3.15" +version = "0.3.16-pre.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/deltas/0.3.16/pre.001.md b/deltas/0.3.16/pre.001.md new file mode 100644 index 0000000..2c4a1b0 --- /dev/null +++ b/deltas/0.3.16/pre.001.md @@ -0,0 +1,178 @@ + + + +# Delta `0.3.16-pre.001` — gate d'audit, architecture et sizing + +## Base requise + +```text +v0.3.15 +commit 7328be6997399c513306f2f4c8cdf00bd8b22367 +workspace.package.version = 0.3.15 +``` + +Ne pas appliquer sur une `0.3.15-pre.*`. + +## Objet + +Exécuter le gate obligatoire de lecture/audit/brainstorming/sizing défini par `prompts/035-V0_3_16_START_PROMPT.md` avant toute migration ou implémentation lourde de la résilience RAW. + +Cette tranche : + +- réaudite la fermeture stable `0.3.15` ; +- réaudite les règles KSP applicables ; +- inventorie les contrats Store/Worker/Transport/Config/Store Desk actuels ; +- réaudite les sémantiques Solana RPC et PostgreSQL pertinentes ; +- compare plusieurs modèles physiques ; +- choisit le modèle conceptuel et les ownerships ; +- définit les invariants de concurrence/rétention/résolution ; +- recalibre le découpage des prereleases ; +- ne crée aucune migration SQL finale et ne modifie aucun Rust. + +## Version workspace + +`Cargo.toml` : + +```text +header version : 637 -> 638 +workspace : 0.3.15 -> 0.3.16-pre.1 +``` + +Aucune autre modification sémantique du `Cargo.toml` racine n'est prévue. + +## Fichiers ajoutés + +```text +docs/plans/038-V0_3_16_RAW_RESILIENCE_CONFLICT_PLAN.md +docs/validation/033-V0_3_16_RAW_RESILIENCE_CONFLICT.md +deltas/0.3.16/pre.001.md +``` + +## Fichiers modifiés + +```text +Cargo.toml +``` + +## Fichiers supprimés + +```text +aucun +``` + +## Décisions principales + +### Variantes + +Modèle retenu : ledger de variantes V003 à identifiant surrogate, sélecteur canonique sidecar et conservation de `ksp_raw_transactions` comme projection canonique compatible V001. + +`content_hash` est un préfiltre/intégrité ; il n'est pas une preuve d'égalité à lui seul lorsque les bytes sont disponibles. + +### Observations + +Toute observation créée sous V003 devra pointer vers la variante réellement reçue. + +Les observations historiques dont le payload entrant n'a pas été conservé sont qualifiées legacy/unknown et ne sont jamais faussement rattachées à une variante native reconstruite. + +### Comparaison + +Relations internes retenues : + +```text +Exact +CompatibleLessComplete +CompatibleMoreComplete +Conflict +Incomparable +``` + +Seule la troncature `logMessages` strictement prouvée autorise une dominance automatique en première implémentation. + +### Rétention + +Les variantes nécessaires au canonique courant, aux conflits ouverts, au rollback ou à la lignée synthétique peuvent être archivées mais restent protégées contre une purge irréversible tant que l'invariant dépend de leurs bytes. + +### Store retry + +Le backend Store classe les fautes `Transient/Terminal` de manière backend-neutral ; le Worker orchestre retry, backpressure, health et exhaustion. + +### Transport reconnect + +La reconnexion reste propriété de `ksp-onchain-transport-lib` et étend les mécanismes existants. Elle reste distincte du retry Store et ne prouve jamais la coverage. + +### Store Desk + +Inspection et résolution passent exclusivement par `ksp-store-lib`. Les actions futures sont typées et protégées par revision attendue. + +## Découpage recalibré + +La release est étendue jusqu'à une prévision souple `pre.022` avant `rel.001` afin de ne pas fusionner artificiellement migration, backend, convergence, rétention, Worker, Transport, Desk et gates de fermeture. + +Le détail est dans le plan `038`. + +## Hors périmètre + +Inchangé par rapport au prompt 035 : + +```text +Backfill multi-route/multi-stratégie +Backfill Desk multi-route +RAW -> STRUCTURAL +STRUCTURAL persistence +DECODED / DOMAIN +majority/provider authority +free JSON merge +Internet reconstruction as normal rollback +second acquisition pipeline +Worker <-> Backfill dependency +``` + +## Validations réellement exécutées lors de l'assemblage du delta + +L'environnement d'assemblage possède uniquement les fichiers du delta, pas le checkout complet `v0.3.15`. + +Sont exécutés sur l'archive produite : + +```text +parse TOML du Cargo.toml delta +vérification workspace.package.version = 0.3.16-pre.1 +vérification des headers file/version des quatre fichiers +vérification newline finale +vérification absence de lockfile/cache/secret dans le ZIP +vérification inventaire ZIP exact +``` + +Ne sont pas déclarés PASS ici : + +```text +cargo fmt/check/clippy/test workspace +scripts/audit_rust_workspace_rules.py +scripts/audit_markdown_tables.py du dépôt complet +byte-compare de l'archive source v0.3.15 +``` + +L'archive binaire source stable n'était pas matérialisable dans l'environnement d'assemblage. L'arbre/tag canonique et le commit de base ont été vérifiés via le dépôt public. + +## Gate demandé après application + +À exécuter par l'opérateur sur le checkout exact `v0.3.15` après application du delta : + +```bash +cargo fmt --all -- --check +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings +``` + +Aucun test live/provider/PostgreSQL n'est requis par ce gate documentaire s'il n'est pas explicitement exécuté. Aucun `npm run build` n'est utilisé. + +## Prochaine tranche + +Après gate propre : + +```text +0.3.16-pre.002 +``` + +Objet prévu : contrats Store API backend-neutral pour variantes, relations de qualité, reason codes et outcomes de persistance, sans migration PostgreSQL anticipée. diff --git a/docs/plans/038-V0_3_16_RAW_RESILIENCE_CONFLICT_PLAN.md b/docs/plans/038-V0_3_16_RAW_RESILIENCE_CONFLICT_PLAN.md new file mode 100644 index 0000000..53024fe --- /dev/null +++ b/docs/plans/038-V0_3_16_RAW_RESILIENCE_CONFLICT_PLAN.md @@ -0,0 +1,1096 @@ + + + +# Plan `0.3.16` — résilience RAW, variantes, conflits et récupération + +## 1. Statut du document + +Ce document ferme le gate d'architecture et de sizing de `0.3.16-pre.001`. + +Base autorisée : + +```text +v0.3.15 +commit 7328be6997399c513306f2f4c8cdf00bd8b22367 +``` + +`pre.001` reste volontairement documentaire. Il ne crée aucune migration finale, aucune table SQL, aucun contrat Rust définitif et aucune UI de conflit. Les décisions ci-dessous fixent les invariants à respecter par les tranches d'implémentation suivantes. + +## 2. Contraintes normatives confirmées + +Les règles KSP restent cumulatives. `0.3.16` ne crée aucune exception implicite. + +Contraintes bloquantes pour cette release : + +- Rust 2024 ; `unsafe`, `unwrap`, `expect` et `panic` restent interdits conformément aux règles KSP ; +- tous les éléments partagés `pub`/`pub(crate)` restent réexportés par le `lib.rs` de la crate et consommés via `crate::Item` ; +- `ksp-store-lib` reste l'unique façade Store des Worker, Job et Desk ; +- `ksp-store-postgres-lib` reste le propriétaire du schéma, du SQL, des transactions et des verrous PostgreSQL ; +- `ksp-config-lib` reste le propriétaire de la configuration projet et de sa validation ; +- le Worker live et le Job Backfill restent indépendants ; +- aucune application Desk ne reçoit de SQL, de backend PostgreSQL direct ni de secret d'infrastructure ; +- aucune nouvelle dépendance protocolaire Solana directe n'est introduite pour contourner les couches existantes ; +- les migrations V000/V001/V002 restent byte-identiques et leurs checksums ne sont jamais réécrits ; +- toute évolution physique se fait par une migration additive nouvelle ; +- aucune queue non bornée n'est introduite ; +- aucune provenance provider n'est une autorité canonique ; +- aucune divergence RAW conservable ne doit être convertie par défaut en panne terminale d'acquisition ; +- une validation n'est déclarée PASS que si elle a réellement été exécutée. + +## 3. État stable `0.3.15` audité + +### 3.1 Fermeture de la release précédente + +Le delta stable `0.3.15-rel.001` documente un gate opérateur `pre.018` propre, puis les couloirs de fermeture `pre.016` technique/live, `pre.017` documentaire et `pre.018` publication. + +La fermeture stable a notamment validé : + +- les cinq familles de routes live ; +- plusieurs Worker indépendants partageant le même Store RAW ; +- Yellowstone + HTTP Block Polling en parallèle environ dix-neuf minutes ; +- absence de `grpc_backpressure_overflow` pendant ce live de référence ; +- Stop final `Stopped/Healthy` pour les deux routes ; +- acceptation du seul cas de convergence asymétrique prouvé en `0.3.15` : canonique complet + entrant dont `logMessages` est strictement tronqué et compatible. + +Le sens canonique tronqué -> entrant complet est explicitement réservé à `0.3.16`. + +### 3.2 Store API et outcomes actuels + +Le Store RAW `0.3.15` expose un modèle centré sur une identité logique `(network, signature)` et un canonique unique par signature dans le backend PostgreSQL d'une base déjà liée à un réseau. + +Les outcomes d'écriture actuels distinguent notamment : + +```text +Inserted +AlreadyPresent +Rehydrated +SkippedPurged +``` + +Les observations distinguent notamment : + +```text +Inserted +AlreadyPresent +NotRecorded +``` + +Le contrat ne possède pas encore d'outcome durable représentant : + +```text +variant inserted +compatible less complete +canonical promoted +conflict quarantined +conflict resolved +``` + +Ces notions doivent donc être ajoutées explicitement au contrat backend-neutral plutôt que détournées vers des erreurs. + +### 3.3 Persistance PostgreSQL actuelle + +Le chemin principal `0.3.15` est transactionnel : + +```text +BEGIN + tentative d'insertion du canonique + si collision d'identité : verrouillage de la ligne existante + comparaison avec le canonique courant + insertion/idempotence de l'observation +COMMIT +``` + +Le verrou de collision repose sur la ligne canonique et permet de sérialiser deux écritures concurrentes de la même signature. + +Le cas étroit `ActiveIncomingTruncatedLogs` permet déjà de traiter l'entrant tronqué comme observation sans remplacer le canonique complet. Toute divergence non reconnue reste un `content_conflict`. + +La rétention actuelle porte sur le canonique et distingue : + +```text +Full +Archived +Purged +ForceRehydrate +``` + +Les migrations enregistrées sont V000, V001 et V002. Leur registre, leurs ressources et leurs checksums sont stables et intouchables. + +### 3.4 Chemin Worker actuel lors d'un conflit + +Le Worker `0.3.15` possède une convergence run-local avant et autour de la persistance. Une divergence peut être rejetée avant que le Store ne dispose d'un mécanisme durable permettant de conserver la variante. + +Si le Store remonte encore un `content_conflict`, le Worker le transforme en faute de persistance. Une tâche de persistance qui termine en faute provoque ensuite l'arrêt de la source concernée et un état terminal de route. + +Cette chaîne est précisément ce que `0.3.16` doit modifier : + +```text +content divergence conservable + -> Store arbitre sous verrou + -> variante durable + -> conflit durable si nécessaire + -> outcome non terminal + -> Worker continue +``` + +Le cache de convergence run-local ne doit plus pouvoir prendre une décision plus forte que le Store durable. Il pourra rester un accélérateur uniquement s'il ne supprime jamais l'arbitrage durable nécessaire. + +### 3.5 Erreurs Store temporaires et terminales + +`0.3.15` ne possède pas encore de politique Worker dédiée de retry Store avec classification backend-neutral complète. + +Un défaut PostgreSQL remonté comme faute de persistance tend donc à devenir terminal pour la route, même lorsqu'il correspond à une indisponibilité temporaire potentiellement récupérable. + +Cette responsabilité doit être séparée du `content_conflict` et de la reconnexion Transport. + +### 3.6 Retry et reconnexion Transport actuels + +L'audit confirme des mécanismes déjà présents : + +- HTTP possède son propre retry de requête borné dans le Transport ; +- WebSocket possède `max_retries`, un délai initial et un délai maximum avec backoff exponentiel ; +- Yellowstone possède également une boucle de reconnexion/reprise bornée et un backoff ; +- Config sait déjà projeter des réglages Transport typés vers ces composants. + +`0.3.16` ne doit donc pas créer un second moteur concurrent. Le travail attendu est une extension/cohérence des contrats déjà propriétaires de la reconnexion réseau. + +### 3.7 Store Desk actuelle + +`ksp-app-store-desk` reste une application d'inspection via `ksp-store-lib`, sans SQL direct ni dépendance PostgreSQL directe. + +L'inspection actuelle sait présenter les surfaces RAW existantes mais ne possède pas encore de DTO/query/action pour : + +```text +variants +open conflicts +resolution history +canonical transitions +manual resolution +synthetic merge lineage +``` + +Ces contrats doivent apparaître d'abord dans Store API/lib, puis seulement dans le bridge Tauri et le frontend. + +## 4. Réaudit externe du 19 septembre 2026 + +Sources réauditées : + +- Solana `getTransaction` ; +- Solana `getBlock` ; +- Solana RPC JSON Structures ; +- `TransactionStatusMeta` / `UiTransactionStatusMeta` actuels ; +- collecteur de logs SVM/Agave actuel ; +- documentation PostgreSQL actuelle pour `INSERT ... ON CONFLICT`, `SELECT ... FOR UPDATE` et isolation transactionnelle. + +### 4.1 `logMessages` : seule relation de complétude automatiquement admise + +Le collecteur SVM actuel conserve une limite de 10 000 octets. Lorsqu'une nouvelle ligne ferait atteindre ou dépasser la limite, il ajoute une seule ligne exacte : + +```text +Log truncated +``` + +puis n'ajoute plus les lignes suivantes. + +La relation KSP sûre est donc limitée au cas suivant : + +```text +A = [l0, l1, ..., ln, "Log truncated"] +B = [l0, l1, ..., ln, ln+1, ...] +``` + +avec égalité exacte de toutes les autres composantes canoniques pertinentes. + +Alors : + +```text +A < B +``` + +au sens de la complétude des logs seulement. + +Cette preuve permet les deux sens : + +- canonique complet + entrant tronqué -> `CompatibleLessComplete`, sans promotion ; +- canonique tronqué + entrant complet -> `CompatibleMoreComplete`, avec promotion atomique. + +Ne sont pas des preuves de troncature : + +- une liste simplement plus courte sans marqueur ; +- une divergence avant le marqueur ; +- plusieurs listes différentes sans relation de préfixe stricte ; +- un provider connu pour tronquer ; +- la seule longueur en octets ou en nombre de lignes. + +### 4.2 `innerInstructions` + +La réponse RPC officielle distingue selon la forme de réponse des tableaux, `null`, ou une omission dans certains modes. + +Aucune relation générale `null < [] < valeur` n'est prouvée. + +Politique `0.3.16` : + +```text +valeurs identiques -> Exact sur ce champ +valeurs différentes -> Conflict/Incomparable +absence/null/[] -> aucune dominance automatique +``` + +### 4.3 `loadedAddresses` + +Les structures RPC officielles indiquent que `loadedAddresses` est présent comme objet dans les réponses JSON/full, mais volontairement omis avec certains encodages/modes comme `jsonParsed` ou `accounts`. + +L'omission peut donc être structurelle et dépendre de la sérialisation, pas de la qualité intrinsèque d'une observation. + +Politique : aucune promotion automatique fondée sur présence/absence de ce champ. + +### 4.4 `returnData`, `computeUnitsConsumed` et `costUnits` + +Ces champs sont optionnels dans les structures UI et peuvent être omis selon le mode de réponse. La documentation RPC montre également des cas où `returnData` apparaît à `null` dans des exemples alors que son type documentaire principal est optionnel. + +Politique : + +```text +même valeur présente -> Exact sur le champ +valeurs présentes différentes -> Conflict +absent/null/présent -> Incomparable tant qu'un contrat plus précis n'est pas prouvé +``` + +### 4.5 Token balances + +`preTokenBalances` et `postTokenBalances` sont optionnels dans la représentation de statut et la documentation RPC distingue tableaux et `null`. + +Une liste vide est une valeur métier possible et ne doit jamais être traitée comme une troncature. + +Politique : aucune dominance automatique hors égalité exacte. + +### 4.6 Rewards + +`rewards` peut être tableau, `null` ou omis selon le mode et `showRewards`/`rewards` demandé. KSP utilise déjà certaines routes avec rewards désactivées. + +Politique : l'absence de rewards n'est pas une preuve d'une variante moins complète dans le comparateur générique. Toute règle future devra intégrer explicitement le contrat d'acquisition qui a produit la représentation. + +### 4.7 `maxSupportedTransactionVersion` + +Ce paramètre contrôle quelles versions de transaction le client déclare pouvoir traiter. Il ne constitue pas un score de qualité entre deux payloads déjà acquis. + +Une différence d'acquisition causée par une limite de version doit être diagnostiquée au niveau Transport/acquisition, pas transformée en règle de promotion canonique. + +### 4.8 Conclusion champ par champ + +Pour `0.3.16`, la seule dominance automatique de contenu autorisée au départ est : + +```text +relation de troncature logMessages strictement prouvée +``` + +Tous les autres champs restent fail-closed : égalité exacte ou `Conflict/Incomparable`. + +Cette politique pourra être étendue dans une future tranche uniquement après preuve normative et canari KSP dédié. + +## 5. Modèles physiques étudiés + +### 5.1 Modèle A — modifier fortement la ligne canonique V001 + +Principe : transformer `ksp_raw_transactions` en identité portant directement un pointeur de variante, ajouter les variantes puis déplacer progressivement le payload hors de la ligne historique. + +Avantages : + +- modèle relationnel final compact ; +- un seul point d'identité logique. + +Inconvénients : + +- forte modification du schéma stable V001 ; +- risque élevé sur les lecteurs/rétention/tests existants ; +- migration volumique plus intrusive ; +- rollback de release plus difficile ; +- davantage de surfaces changées dans une seule étape. + +Décision : non retenu pour `0.3.16`. + +### 5.2 Modèle B — ledger de variantes + sélecteur sidecar + projection V001 + +Principe : + +```text +ksp_raw_transactions + = projection canonique compatible V001 + +variant ledger V003 + = toutes les représentations conservées à partir de 0.3.16 + +canonical selector V003 + = variant_id actuellement sélectionné + +conflict/resolution journal V003 + = historique immuable des décisions +``` + +Une promotion effectue dans une même transaction : + +```text +lock identité V001 +verify expected canonical/revision +persist incoming variant if new +update canonical selector +update V001 canonical projection +append canonical transition / resolution event +attach observation to exact variant +commit +``` + +Avantages : + +- V000/V001/V002 inchangées ; +- anciens lecteurs restent compatibles ; +- rollback conceptuel vers une ancienne variante sans Internet ; +- migration additive et progressive ; +- verrou existant de l'identité réutilisable ; +- séparation nette identité / variante / historique. + +Inconvénients : + +- duplication contrôlée entre la projection V001 et la variante canonique ; +- invariants de cohérence à tester entre projection et sélecteur ; +- rétention plus complexe ; +- nouvelles écritures doivent maintenir plusieurs structures atomiquement. + +Décision : modèle retenu. + +### 5.3 Modèle C — variante adressée uniquement par `content_hash` + +Principe : utiliser le hash comme clé physique principale et considérer deux hashes identiques comme même variante. + +Avantages : + +- déduplication simple ; +- index de recherche efficace. + +Inconvénients : + +- confond hash cryptographique et preuve d'égalité ; +- rend la sémantique de collision implicite ; +- complique le cas tombstone/payload absent ; +- impose une hypothèse plus forte que nécessaire au contrat de domaine. + +Décision : rejeté. + +## 6. Identité d'une variante + +La variante utilise un identifiant surrogate stable : + +```text +variant_id +``` + +`content_hash` reste stocké et indexable, mais sert à : + +- accélérer la recherche de candidats égaux ; +- vérifier l'intégrité ; +- fournir un diagnostic redacted ; +- aider les tombstones de rétention. + +Il ne suffit jamais seul à conclure `Exact` lorsque les deux payloads sont disponibles. + +Pour une identité verrouillée : + +```text +same hash + -> candidate equality + -> exact compare of canonical representation + -> Exact only after exact comparison +``` + +Aucune contrainte d'unicité ne doit transformer automatiquement `(signature, content_hash)` en preuve métier. La sérialisation par verrou de l'identité permet de prévenir les doubles insertions concurrentes après comparaison exacte. + +## 7. Structures V003 conceptuelles retenues + +Les noms SQL exacts seront figés dans la tranche de migration, mais les rôles sont désormais décidés. + +### 7.1 Variant ledger + +Chaque variante conserve au minimum : + +```text +variant_id +transaction identity/signature +origin kind = native | synthetic +canonical raw format id/version +slot +block_time +content_hash +payload ou état de rétention +created_at +``` + +Une variante native représente exactement un payload effectivement reçu. + +Une variante synthétique doit être explicitement marquée et posséder une lignée de parents. + +### 7.2 Canonical selector + +Une structure sidecar contient au minimum : + +```text +transaction identity +canonical_variant_id +canonical_revision +updated_at +``` + +`canonical_revision` sert de garde optimiste aux actions Desk afin d'éviter une résolution sur une vue périmée. + +### 7.3 Variant observations + +À partir de V003, chaque observation nouvelle est durablement liée à la variante réellement reçue. + +L'écriture reste atomique avec la variante et l'outcome de persistance. + +Point historique important : les observations créées avant `0.3.16` ne contiennent pas toujours le payload reçu. Le cas `logMessages` tronqué accepté en `0.3.15` conserve l'observation mais pas une variante complète de l'entrant. + +Il est donc interdit de prétendre reconstruire après coup l'association exacte de toutes les observations historiques. + +Le bootstrap V003 doit les exposer comme observations héritées dont la variante exacte est `unknown/legacy`, ou comme association explicitement qualifiée et non comme preuve native. + +### 7.4 Conflict case + +Une identité peut posséder un dossier de conflit durable unique et réouvrable. + +Le dossier porte : + +```text +conflict identity +status = Open | Resolved +revision +current canonical variant +latest classification/reason +created_at +updated_at +``` + +Les variantes participantes sont conservées séparément. + +### 7.5 Journal de transitions et résolutions + +Le journal est append-only. + +Types conceptuels : + +```text +AutoPromoteMoreComplete +ManualPromoteVariant +KeepCurrentAndResolve +RestorePreviousCanonical +ReopenConflict +CreateSyntheticMerge +``` + +Chaque événement garde : + +```text +action id +conflict id optionnel +from variant id optionnel +to variant id +expected revision +origin = system | operator +result +created_at +``` + +Aucun payload arbitraire ni secret ne doit être requis dans les logs sûrs. + +### 7.6 Parents de variante synthétique + +Une fusion assistée crée une nouvelle variante : + +```text +origin = synthetic +parents = [variant A, variant B, ...] +``` + +Elle ne réécrit jamais A ou B et ne se présente jamais comme une observation provider native. + +## 8. Migration strategy + +### 8.1 Invariant principal + +V000/V001/V002 restent byte-identiques. + +V003 ajoute des ressources nouvelles et, si nécessaire, des index/contraintes nouvelles via une migration indépendante enregistrée avec son propre checksum. + +### 8.2 Bootstrap des identités existantes + +La migration ne doit pas inventer des variantes historiques perdues. + +Pour chaque identité déjà présente, le système peut créer une variante bootstrap représentant l'état canonique encore réellement disponible : + +- `Full` : payload canonique actuel copié comme variante bootstrap ; +- `Archived` : payload exact récupéré depuis l'archive locale existante et porté comme variante archivée ; +- `Purged` : variante tombstone seulement, sans prétendre disposer encore des bytes perdus. + +Les observations historiques restent qualifiées `legacy` lorsqu'aucune preuve ne permet de les rattacher à la variante exacte reçue. + +### 8.3 Migration volumique + +La création de schéma et le bootstrap de données doivent être séparables si le volume réel rend un backfill monolithique trop coûteux. + +La stratégie préférée est : + +1. créer V003 de façon additive ; +2. permettre un bootstrap paresseux d'une identité sous son verrou lorsque sa projection V003 manque ; +3. fournir un backfill borné/idempotent de préparation si nécessaire pour réduire le coût au premier accès ; +4. ne jamais bloquer la migration de schéma sur une reconstruction externe. + +Cette stratégie sera testée sur une copie PostgreSQL réaliste avant gate final. + +## 9. Atomicité et concurrence + +### 9.1 Même identité, deux entrants concurrents + +L'identité V001 reste le mutex transactionnel naturel. + +Séquence cible : + +```text +BEGIN +SELECT canonical identity FOR UPDATE +ensure V003 bootstrap +reload canonical selected variant +compare incoming against locked canonical +persist or reuse exact incoming variant +attach incoming observation +apply promotion/conflict transition if required +update compatibility projection if canonical changes +append event +COMMIT +``` + +Deux transactions ne peuvent donc pas promouvoir simultanément à partir du même `canonical_revision` sans que la seconde réévalue l'état après attente/verrou. + +### 9.2 Action Desk concurrente avec ingestion + +Toute action manuelle contient : + +```text +expected canonical_variant_id +expected conflict revision +``` + +Si l'état a changé, l'action échoue comme stale action et l'UI recharge. Elle ne force jamais silencieusement un ancien choix. + +### 9.3 Hash collision + +Le hash réduit l'espace de recherche mais l'égalité exacte des représentations disponibles tranche l'idempotence. + +Si deux payloads différents ont le même hash, ils restent deux variantes différentes et le diagnostic doit le signaler comme anomalie de hash, pas les fusionner. + +## 10. Relation de qualité + +Le comparateur interne utilise cinq relations : + +```text +Exact +CompatibleLessComplete +CompatibleMoreComplete +Conflict +Incomparable +``` + +`Incomparable` est nécessaire pour représenter une relation partielle avant projection vers le comportement durable. Dans `0.3.16`, un `Incomparable` est conservé comme conflit durable fail-closed. + +### 10.1 Exact + +Tous les éléments du contrat canonique sont égaux. + +Conséquence : observation supplémentaire/idempotente sur la même variante. + +### 10.2 CompatibleLessComplete + +Seul un manque explicitement prouvé existe et le canonique domine l'entrant. + +En première version, seul le cas de troncature `logMessages` prouvée est admis. + +Conséquence : conserver le canonique ; conserver la variante reçue si elle n'existe pas ; rattacher son observation ; ne pas ouvrir de conflit nécessitant action humaine. + +### 10.3 CompatibleMoreComplete + +L'entrant domine le canonique selon la même preuve stricte. + +Conséquence : persister l'entrant puis promotion atomique ; conserver l'ancien canonique ; ajouter un événement automatique réversible. + +### 10.4 Conflict + +Une contradiction prouvée existe. + +Conséquence : conserver les deux variantes, conserver le canonique courant, ouvrir/compléter le conflict case, Worker non terminal. + +### 10.5 Incomparable + +Aucune contradiction simple n'est nécessairement démontrée, mais aucune dominance sûre n'est prouvée. + +Conséquence `0.3.16` : même traitement durable prudent qu'un conflit, avec reason code distinct. + +## 11. Ownership du comparateur + +La décision de convergence doit être backend-neutral et réutilisable sous verrou par le backend. + +Le contrat de relation appartient à la surface Store RAW commune ; il ne doit pas être une heuristique privée du Worker. + +Décision d'ownership : + +- `ksp-store-api` porte les types de relation, reason codes, données backend-neutral et le comparateur pur de convergence RAW ; +- le comparateur appartient au contrat de domaine Store RAW parce qu'il doit être identique pour tous les backends et directement appelable par `ksp-store-postgres-lib` sous verrou sans dépendance inverse vers `ksp-store-lib` ; +- `ksp-store-postgres-lib` applique cette relation dans la transaction durable et reste propriétaire de la sérialisation PostgreSQL, des verrous et des mutations atomiques ; +- `ksp-store-lib` expose uniquement la façade commune et les opérations d'inspection/résolution ; il ne devient pas une dépendance du backend ; +- `ksp-raw-transaction-lib` reste l'autorité sur la canonicalisation RAW v1 et fournit les golden/canaris utiles, sans devenir propriétaire de la politique Store de convergence ; +- le Worker peut utiliser la relation à titre de métrique/optimisation, mais le Store verrouillé reste l'autorité de la décision durable. + +La tranche API devra encore vérifier le graphe Cargo avant de fixer le fichier/module Rust exact, mais la frontière de crate est fermée : le comparateur backend-neutral appartient à `ksp-store-api`. Aucune nouvelle dépendance circulaire n'est admise. + +## 12. Rétention, archive et rehydration + +### 12.1 Règle générale + +Une promotion réversible exige de conserver les bytes nécessaires au retour arrière. + +Une variante : + +- actuellement canonique ; +- participante à un conflit ouvert ; +- ancien canonique référencé par un événement de restauration ; +- parent requis d'une variante synthétique ; + +doit pouvoir être archivée mais ne doit pas être purgée de manière irréversible tant que le contrat de restauration dépend d'elle. + +### 12.2 Full -> Archived + +Autorisé si les bytes exacts sont conservés dans la surface d'archive V003 et que la restauration locale est possible. + +### 12.3 Purged + +`Purged` reste possible pour des variantes non épinglées par les invariants ci-dessus, selon politique de rétention explicite. + +Un ancien canonique nécessaire à `RestorePreviousCanonical` est épinglé contre la purge. + +### 12.4 ForceRehydrate + +`ForceRehydrate` ne réécrit jamais arbitrairement une variante existante : + +- si les bytes exacts sont encore disponibles, égalité exacte normale ; +- si seul un tombstone legacy subsiste, le hash peut vérifier une attente d'intégrité mais n'est pas présenté comme preuve d'égalité historique ; +- un payload réellement différent devient une nouvelle variante ; +- une représentation plus complète peut ensuite être promue selon le comparateur. + +## 13. Machine d'état du conflict case + +États : + +```text +Open +Resolved +``` + +Transitions : + +```text +new Conflict/Incomparable -> Open +Open + KeepCurrent -> Resolved +Open + PromoteVariant -> Resolved +Open + SyntheticMerge -> Resolved +Resolved + new unresolved variant -> Open +Resolved + explicit Reopen -> Open +Resolved + RestorePreviousCanonical -> Resolved with new journal event +``` + +Le statut est volontairement petit. Le détail de la décision vit dans le journal append-only et non dans une multiplication d'états terminaux. + +## 14. Outcomes Store cibles + +Les noms Rust exacts seront figés dans `pre.002`, mais les catégories suivantes sont requises : + +```text +InsertedCanonical +ObservedExact +ObservedCompatibleLessComplete +PromotedCompatibleMoreComplete +QuarantinedConflict +Rehydrated +SkippedPurged +``` + +`QuarantinedConflict` n'est pas une erreur de transport ni une erreur terminale Store. C'est un succès de durabilité avec réconciliation canonique encore ouverte. + +## 15. Store retry — ownership et sémantique + +### 15.1 Classification + +`ksp-store-api` expose une classification backend-neutral : + +```text +Transient +Terminal +``` + +`ksp-store-postgres-lib` mappe les erreurs PostgreSQL réelles vers cette classification. + +Exemples transients à couvrir par tests : + +- connexion interrompue ; +- timeout/pool temporairement indisponible ; +- serialization failure lorsque le niveau choisi peut la produire ; +- deadlock détecté et transaction entièrement rejouable. + +Exemples terminaux : + +- checksum/migration/schema incompatible ; +- contrat modèle invalide ; +- payload invalide ; +- violation d'invariant non récupérable ; +- politique de retry épuisée. + +Un conflit de contenu conservé durablement n'est plus dans cette classification d'erreur. + +### 15.2 Orchestration + +Le Worker possède l'orchestration de retry de persistance, car il possède : + +- l'admission ; +- la concurrence de persistance ; +- le lifecycle ; +- le backpressure ; +- le health ; +- le Stop/drain. + +Le backend Store reste responsable de l'atomicité d'une tentative et de la classification de sa faute ; il ne masque pas une boucle de retry indéfinie au Worker. + +### 15.3 Paramètres de politique + +Le type Worker doit accepter : + +```text +initial_delay +max_delay +backoff_multiplier +max_attempts = bounded | explicitly unbounded +jitter bounded +reset after successful durable persistence +``` + +Les valeurs numériques par défaut seront calibrées par tests ciblés avant la tranche Worker retry ; leur ownership et leur sémantique sont cependant fermés ici. + +### 15.4 Backpressure + +Pendant une indisponibilité Store : + +```text +pending durable write retained +retry according to policy +persistence concurrency remains bounded +admission queue remains bounded +pressure propagates upstream when capacity fills +no success counter before durable commit +no silent drop +``` + +Si `max_attempts` est épuisé, la route peut devenir terminale. + +Si un mode explicitement illimité est configuré, la route reste `Blocked`/non terminale jusqu'à recovery ou Stop, tout en conservant des files bornées. + +## 16. Transport reconnect — ownership et extension + +La reconnexion réseau reste propriété de `ksp-onchain-transport-lib`. + +Le moteur existant WebSocket/Yellowstone doit être étendu plutôt que dupliqué avec une politique typée comprenant : + +```text +initial_delay +max_delay +backoff_multiplier +max_attempts +reset_after_stable_duration +bounded_jitter +``` + +Les defaults de compatibilité doivent conserver le comportement `0.3.15` lorsqu'un nouveau réglage n'est pas fourni. + +HTTP conserve sa sémantique de retry de requête ; il ne doit pas être forcé dans une abstraction de « reconnect » si cette abstraction dégrade son contrat. + +`ksp-config-lib` reste le propriétaire de la représentation de configuration et projette les valeurs validées vers Transport. + +Une reconnexion réussie ne prouve jamais que la coverage est continue. Gaps/replay/repair restent des mécanismes séparés. + +## 17. Health et métriques source-neutral + +Les compteurs cibles sont source-neutral et redacted : + +```text +raw_variant_created_count +raw_exact_observation_count +raw_less_complete_observation_count +raw_canonical_promotion_count +raw_unresolved_conflict_count +raw_auto_resolved_count +store_retry_attempt_count +store_retry_exhausted_count +store_blocked_duration_ms +``` + +Les noms pourront être harmonisés avec les conventions exactes du Worker API, mais aucune dimension provider ne doit décider de la santé canonique. + +Le lifecycle peut rester `Running` pendant : + +```text +unresolved conflict -> health Degraded +transient Store retry -> health Degraded +Store pressure saturating bounded capacity -> health Blocked +``` + +La route devient terminale seulement lorsqu'une erreur structurelle l'exige ou lorsque la politique de récupération est épuisée. + +Deux notions de complétude doivent rester distinctes : + +```text +acquisition_complete +canonical_complete +``` + +## 18. Store Desk — scope retenu + +### 18.1 Lecture + +Ajouter via `ksp-store-lib` seulement : + +```text +RAW Conflicts +RAW Conflict History / Resolution History +variant detail +canonical transition history +observation/provenance per variant +``` + +Les listes doivent être paginées/bornées ; DataTables `serverSide` est privilégié lorsque le volume le justifie. + +### 18.2 Actions + +Actions structurées : + +```text +Promote variant +Keep current canonical + Resolve +Restore previous canonical +Reopen conflict +Assisted merge, seulement si les règles prouvées l'autorisent +``` + +Chaque action envoie des identifiants typés et la revision attendue ; pas d'éditeur JSON libre comme mécanisme principal. + +### 18.3 Architecture Desk + +Conserver : + +```text +lib.rs = exports only +tauri.rs = bridge IPC +modules Rust spécialisés +Vite + TypeScript +tracing frontend des actions sans valeurs sensibles +ksp-store-lib seule façade Store +cargo tauri dev/build pour les gates Desk +``` + +## 19. Risques identifiés + +### 19.1 Divergence projection V001 / sélecteur V003 + +Mitigation : mise à jour atomique sous le même verrou, tests de canari et vérification d'invariant lors des lectures sensibles. + +### 19.2 Double variante concurrente + +Mitigation : verrou identité, recherche hash comme préfiltre puis comparaison exacte avant insertion. + +### 19.3 Stale action Store Desk + +Mitigation : `canonical_revision` + `conflict revision` attendues. + +### 19.4 Rétention détruisant le rollback + +Mitigation : pin explicite des variantes nécessaires à l'historique/restauration ; archive locale admise, purge interdite tant que l'invariant l'exige. + +### 19.5 Migration volumique + +Mitigation : V003 additive, bootstrap idempotent/paresseux et éventuel backfill borné plutôt qu'une reconstruction externe ou une migration monolithique obligatoire. + +### 19.6 Retry Store créant une file infinie + +Mitigation : réutiliser les capacités bornées existantes, backpressure upstream et aucun buffer latéral non borné. + +### 19.7 Reconnect masquant des gaps + +Mitigation : reconnect et coverage restent deux compteurs/contrats séparés. + +### 19.8 Faux ordre de qualité hors logs + +Mitigation : `Incomparable` fail-closed pour tous les champs sans preuve normative. + +### 19.9 Historique legacy incomplet + +Mitigation : ne jamais prétendre reconstruire une variante pré-V003 non stockée ; qualifier explicitement l'observation comme legacy/unknown. + +## 20. Découpage recalibré + +La prévision initiale du prompt est trop dense pour plusieurs tranches qui combinent contrat, SQL, concurrence et rétention. Le découpage souple est donc étendu afin de respecter le budget KSP d'environ 15–20 minutes par tranche de travail effectif. + +### `pre.001` + +Audit stable/règles, réaudit externe, modèles physiques, décisions d'ownership, sizing, plan et validation. + +### `pre.002` + +Contrats Store API backend-neutral : variant identity, relation de qualité, outcomes de persistance et reason codes. + +### `pre.003` + +Contrats Store API d'inspection/résolution + classification d'erreurs Store transient/terminal + tests de contrats. + +### `pre.004` + +Migration V003 : registre/resources/schema uniquement, sans moteur de convergence lourd ; canaris checksum V000/V001/V002. + +### `pre.005` + +Backend PostgreSQL : bootstrap V003, variant ledger, observation exacte par variante, concurrence d'insertion. + +### `pre.006` + +Comparateur partagé : `Exact/Less/More/Conflict/Incomparable`, canaris `logMessages` bidirectionnels, autres champs fail-closed. + +### `pre.007` + +Promotion canonique atomique, selector revision et journal des transitions. + +### `pre.008` + +Conflict case durable, participants, résolution/reopen et races ingestion/résolution. + +### `pre.009` + +Rétention/archives/ForceRehydrate des variantes + règles de pin/rollback. + +### `pre.010` + +Store-lib : inspection, historique et actions backend-neutral ; compatibilité Job Backfill existant. + +### `pre.011` + +Worker : conflit durable non terminal, suppression/restriction de l'arbitrage run-local, health Degraded et métriques. + +### `pre.012` + +Worker : Store retry/backpressure/Blocked, calibration des defaults et cancellation/drain. + +### `pre.013` + +Transport : reconnexion configurable WebSocket/Yellowstone + Config ; conservation de la séparation HTTP/coverage. + +### `pre.014` + +Store Desk backend/Tauri : queries et actions typées via `ksp-store-lib`. + +### `pre.015` + +Store Desk frontend : conflicts/history/variant detail, pagination serverSide et tracing redacted. + +### `pre.016` + +Actions UI promote/keep/restore/reopen avec protections stale revision. + +### `pre.017` + +Fusion assistée/synthétique strictement bornée, uniquement si les règles de fusion disponibles sont réellement prouvées ; sinon tranche documentaire qui ferme explicitement le non-support. + +### `pre.018` + +Hardening cross-layer : concurrence, cancellation, retention, rollback, redaction et dependency boundaries. + +### `pre.019` + +Preuves live PostgreSQL/Store + Worker sous conflits, Store outage/recovery et reconnect réellement testables. + +### `pre.020` + +Gate technique/live final : workspace, tests, graphes Cargo, Tauri build/smokes pertinents. + +### `pre.021` + +Réconciliation documentaire finale de la release. + +### `pre.022` + +Préparation publication : `CHANGELOG.md`, `ROADMAP.md`, prompt `0.3.17`. + +### `rel.001` + +Publication stable mécanique. + +Le nombre exact reste souple : aucune tranche ne doit être fusionnée artificiellement si son scope dépasse le budget. + +## 21. Hors périmètre confirmé + +`0.3.16` n'implémente pas : + +- multi-route/multi-stratégie du Job Backfill (`0.3.17`) ; +- adaptation Backfill Desk correspondante (`0.3.18`) ; +- RAW -> STRUCTURAL ; +- persistence STRUCTURAL ; +- DECODED/DOMAIN ; +- majority voting provider ; +- provider priority ; +- fusion JSON libre ; +- reconstruction Internet comme rollback normal ; +- second pipeline d'acquisition ; +- dépendance Worker <-> Job Backfill. + +Le Job Backfill actuel doit seulement rester compatible avec les contrats Store communs. + +## 22. Questions non bloquantes reportées aux tranches d'implémentation + +Les décisions suivantes ne changent pas l'architecture du gate et peuvent être finalisées au moment où des mesures/tests réels existent : + +- noms SQL définitifs des ressources V003 ; +- valeurs numériques par défaut de Store retry ; +- valeur par défaut du jitter et de `reset_after_stable_duration` Transport ; +- colonnes exactes des DataTables Store Desk ; +- stratégie de backfill eager ou lazy optimale après mesure du volume PostgreSQL réel. + +Toute réponse à ces questions doit respecter les invariants fixés ci-dessus ; elle ne peut pas réouvrir un provider ranking ou une perte silencieuse. + +## 23. Sources externes réauditées + +- +- +- +- +- +- +- +- +- +- + +## 24. Gate `pre.001` + +Le gate est architecturalement fermé lorsque : + +- le modèle sidecar/variant ledger est accepté comme base de développement ; +- aucune migration V000/V001/V002 n'est modifiée ; +- le surrogate `variant_id` est l'identité physique et le hash n'est pas une preuve d'égalité ; +- les observations futures sont rattachées à leur variante réelle ; +- l'historique legacy non reconstructible est explicitement qualifié ; +- `logMessages` est la seule dominance automatique admise ; +- tous les autres champs restent fail-closed ; +- Store retry appartient à l'orchestration Worker avec classification backend-neutral fournie par Store ; +- Transport reconnect reste propriété Transport ; +- Store Desk passe exclusivement par Store-lib ; +- les risques de concurrence, rétention, stale action et migration volumique ont un mécanisme de contrôle explicite ; +- le découpage souple ci-dessus remplace la prévision initiale trop compacte. diff --git a/docs/validation/033-V0_3_16_RAW_RESILIENCE_CONFLICT.md b/docs/validation/033-V0_3_16_RAW_RESILIENCE_CONFLICT.md new file mode 100644 index 0000000..82a04c9 --- /dev/null +++ b/docs/validation/033-V0_3_16_RAW_RESILIENCE_CONFLICT.md @@ -0,0 +1,388 @@ + + + +# Validation `0.3.16` — résilience RAW et gestion des conflits + +## 1. Objet + +Ce document suit la validation de `0.3.16` depuis le gate `pre.001` jusqu'à la fermeture stable. + +La première tranche ne prétend pas valider une implémentation qui n'existe pas encore. Elle valide le point de départ, les contrats acquis, les décisions d'architecture et la liste des preuves à construire. + +## 2. Base stable + +Base requise : + +```text +v0.3.15 +commit 7328be6997399c513306f2f4c8cdf00bd8b22367 +``` + +Le delta stable `0.3.15-rel.001` documente : + +```text +cargo fmt --all -- --check : PASS +General Rust rule audit : clean +Rust export completeness audit : 0 candidate(s) +KSP workspace Rust rule audit : clean +Markdown table audit : clean (318 table(s), 232 file(s)) +cargo check --workspace : PASS +``` + +Il documente également le gate technique/live de `pre.016`, le live Mainnet Yellowstone + HTTP Block Polling d'environ dix-neuf minutes et la fermeture `Stopped/Healthy` des deux routes. + +Ces résultats appartiennent à la fermeture `0.3.15` ; ils ne sont pas revendiqués comme réexécutés par `0.3.16-pre.001`. + +## 3. Limitation de vérification de l'archive source dans l'environnement d'assemblage + +L'arbre canonique du tag et le commit stable ont été vérifiés via le dépôt public. + +L'archive binaire source `v0.3.15.zip` n'a pas pu être matérialisée dans l'environnement d'assemblage de `pre.001`. Aucun SHA/CRC ou byte-compare local de cette archive n'est donc déclaré PASS ici. + +Cette limitation ne doit pas être masquée par les gates historiques du delta stable. + +Après application du delta sur le checkout utilisateur taggé `v0.3.15`, les scripts et commandes du dépôt restent l'autorité de validation locale. + +## 4. Vérification des règles + +Le gate `pre.001` a réaudité les familles de règles requises par le prompt : + +```text +RULES.md +RULES_GENERAL.md +RULES_KSP.md +RULES_RUST.md +RULES_DEPENDENCIES.md +RULES_DOCUMENTATION.md +FILE_CONTRACTS.md +VERSION_WORKFLOW.md +PROMPT_STRUCTURE.md +``` + +Décisions directement dérivées de ces règles : + +- première livraison `0.3.16-pre.001` -> Cargo `0.3.16-pre.1` ; +- aucun Rust ni SQL lourd dans le gate d'ouverture ; +- delta minimal ; +- migrations V000/V001/V002 immuables ; +- Store-lib façade unique ; +- aucune dépendance Worker <-> Job Backfill ; +- aucune queue non bornée ; +- aucun PASS inventé ; +- pas de `npm run build` comme gate Desk. + +## 5. Inventaire de caractérisation `0.3.15` + +### 5.1 Store RAW + +Caractérisé : + +```text +identity = network + signature au contrat +backend PostgreSQL = une base liée à un network +canonical unique actuel +atomic canonical + observation +additional observation +content_conflict terminal hors cas narrow logs +retention Full / Archived / Purged / ForceRehydrate +``` + +### 5.2 Outcomes actuels + +Caractérisés : + +```text +Inserted +AlreadyPresent +Rehydrated +SkippedPurged + +Observation: +Inserted +AlreadyPresent +NotRecorded +``` + +### 5.3 PostgreSQL + +Caractérisé : + +```text +V000/V001/V002 +migration registry + checksum +transaction d'écriture +collision identité +SELECT ... FOR UPDATE +comparaison canonique +observation transactionnelle +retention sous verrou +``` + +### 5.4 Worker + +Caractérisé : + +```text +convergence run-local existante +Store content_conflict -> faute persistence +faute persistence -> arrêt de source / route terminale +pas de Store retry policy dédiée comparable au reconnect Transport +``` + +### 5.5 Transport + +Caractérisé : + +```text +HTTP request retry déjà Transport-owned +WebSocket reconnect borné avec backoff +Yellowstone reconnect borné avec backoff +Config projection déjà existante +``` + +### 5.6 Store Desk + +Caractérisé : + +```text +inspection via ksp-store-lib +pas de SQL direct +pas encore de variants/conflicts/resolution actions +``` + +## 6. Preuves externes réauditées + +### 6.1 Log truncation + +Le collecteur SVM courant expose : + +```text +LOG_MESSAGES_BYTES_LIMIT = 10 * 1000 +``` + +et ajoute exactement : + +```text +Log truncated +``` + +une seule fois lorsque la limite est atteinte/dépassée, puis cesse d'enregistrer les lignes suivantes. + +Canari requis pour `pre.006` : + +```text +truncated exact prefix + marker vs full continuation + -> Less/More selon direction + +different prefix before marker + -> Conflict + +shorter list without marker + -> Conflict/Incomparable +``` + +### 6.2 Autres champs RPC + +La documentation Solana actuelle montre des différences de sérialisation/optionnalité pour : + +```text +innerInstructions +loadedAddresses +returnData +computeUnitsConsumed +costUnits +rewards +preTokenBalances +postTokenBalances +``` + +Canari de politique : aucune de ces différences ne produit `CompatibleLessComplete` ou `CompatibleMoreComplete` sans nouvelle preuve normative explicite. + +### 6.3 PostgreSQL + +Les mécanismes retenus sont compatibles avec la stratégie : + +- `SELECT ... FOR UPDATE` sérialise les writers/lockers concurrents d'une même ligne jusqu'à fin de transaction ; +- `INSERT ... ON CONFLICT` possède une sémantique atomique pour les conflits arbitrés ; +- certaines fautes d'isolation/serialization exigent le retry de la transaction complète. + +Ces propriétés doivent être traduites en tests KSP et non seulement citées dans la documentation. + +## 7. Décisions fermées par `pre.001` + +### 7.1 Modèle physique + +Décision : ledger V003 de variantes à `variant_id` surrogate + sélecteur canonique sidecar + projection V001 compatible. + +### 7.2 Hash + +Décision : `content_hash` est un préfiltre/intégrité, jamais la preuve unique d'égalité lorsque les bytes sont disponibles. + +### 7.3 Observations + +Décision : toute nouvelle observation V003 pointe vers la variante réellement reçue. + +Les observations legacy impossibles à reconstruire sont qualifiées explicitement comme telles. + +### 7.4 Rétention + +Décision : toute variante requise pour conflit ouvert, canonique courant, restauration ou parent synthétique peut être archivée mais reste protégée contre une purge irréversible tant que l'invariant de rollback dépend de ses bytes. + +### 7.5 Conflict case + +Décision : état principal `Open | Resolved`, réouverture possible, journal append-only des transitions/résolutions. + +### 7.6 Qualité + +Décision : relation interne : + +```text +Exact +CompatibleLessComplete +CompatibleMoreComplete +Conflict +Incomparable +``` + +`Incomparable` est persisté prudemment comme réconciliation ouverte. + +### 7.7 Store retry + +Décision : + +```text +Store backend -> classifie Transient/Terminal +Worker -> orchestre retry/backpressure/health +``` + +### 7.8 Transport reconnect + +Décision : reste dans `ksp-onchain-transport-lib` ; extension du mécanisme existant, sans fusion conceptuelle avec Store retry ni coverage. + +### 7.9 Store Desk + +Décision : conflits/historique/actions via `ksp-store-lib` uniquement, bridge Tauri typé, frontend Vite/TypeScript, actions protégées par revision attendue. + +## 8. Matrice de preuves à construire + +### 8.1 API + +À prouver : + +- roundtrip/égalité des DTO variant/conflict/history ; +- reason codes stables ; +- outcomes distincts ; +- classification Store transient/terminal sans type PostgreSQL exposé. + +### 8.2 Migration V003 + +À prouver : + +- checksums V000/V001/V002 inchangés ; +- V003 idempotente dans le registry ; +- base vide ; +- base existante Full ; +- base existante Archived ; +- base existante Purged ; +- observation legacy non faussement attribuée ; +- rollback de migration selon contrat KSP si applicable. + +### 8.3 Variants/convergence + +À prouver : + +- exact concurrent -> une variante logique ; +- less complete logs -> canonique inchangé ; +- more complete logs -> promotion atomique ; +- conflict -> canonique inchangé + variante durable + case Open ; +- incomparable -> fail-closed durable ; +- hash identique + payload différent -> jamais fusionné par hash seul. + +### 8.4 Promotions + +À prouver : + +- selector et projection V001 cohérents après commit ; +- ancien canonique conservé ; +- restore local sans Internet ; +- stale revision rejetée ; +- crash/rollback ne laisse pas selector/projection divergents. + +### 8.5 Rétention + +À prouver : + +- archive d'une variante rollbackable conserve bytes exacts ; +- purge refusée lorsqu'une variante est épinglée ; +- ForceRehydrate exact ; +- ForceRehydrate payload différent -> nouvelle variante ; +- legacy Purged ne prétend pas disposer d'une égalité byte-exact perdue. + +### 8.6 Worker + +À prouver : + +- conflit durable -> route Running, health Degraded ; +- autre identité continue ; +- Store transient -> retry sans success prématuré ; +- queue bornée -> backpressure ; +- policy exhausted -> terminal explicite ; +- Stop pendant backoff -> cancellation/drain propre. + +### 8.7 Transport + +À prouver : + +- backoff initial/max/multiplier ; +- max attempts ; +- reset stable ; +- jitter borné ; +- reconnexion != coverage ; +- comportement HTTP existant non régressé. + +### 8.8 Store Desk + +À prouver : + +- pagination bornée ; +- aucune dépendance backend direct ; +- promote/keep/restore/reopen typés ; +- stale action visible et recharge ; +- aucune donnée sensible dans tracing frontend/backend ; +- build via Tauri/Vite seulement. + +## 9. Gates de `pre.001` exécutables après application + +Comme cette archive delta ne contient pas le checkout complet, les commandes KSP suivantes ne sont pas revendiquées exécutées dans l'environnement d'assemblage : + +```bash +cargo fmt --all -- --check +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings +``` + +Elles doivent être exécutées sur le dépôt utilisateur après application de `pre.001`. + +Aucun `npm run build` n'est demandé. + +## 10. Gate de sortie `pre.001` + +État documentaire : + +```text +modèle conceptuel CLOSED +frontières de crates CLOSED avec vérification Cargo à chaque tranche +migration strategy CLOSED +logMessages quality semantics CLOSED +other field policy CLOSED / fail-closed +Store retry ownership CLOSED +Transport reconnect ownership CLOSED +Store Desk scope CLOSED +races/retention risks IDENTIFIED +prerelease sizing RECALIBRATED +out-of-scope CLOSED +``` + +L'implémentation lourde peut commencer en `pre.002` uniquement après application locale et gate propre du delta `pre.001`.