0.7.32
This commit is contained in:
@@ -62,3 +62,4 @@
|
|||||||
0.7.29 - Ajout d’une matrice DEX commune (`dex_support_matrix`) utilisée par le catalogue DEX, la classification transactionnelle et l’enregistrement des protocol candidates ; ajout du profil de validation `0.7.29_multi_dex_matrix_baseline` exposant la matrice dans le rapport de validation ; préparation explicite des surfaces planifiées sans inventer de program ids non vérifiés.
|
0.7.29 - Ajout d’une matrice DEX commune (`dex_support_matrix`) utilisée par le catalogue DEX, la classification transactionnelle et l’enregistrement des protocol candidates ; ajout du profil de validation `0.7.29_multi_dex_matrix_baseline` exposant la matrice dans le rapport de validation ; préparation explicite des surfaces planifiées sans inventer de program ids non vérifiés.
|
||||||
0.7.30 - Ajout d’une taxonomie DEX plus fine pour les événements décodés : `eventLifecycleKind`, `eventActionability`, `nonTradeUseful`, compteurs diagnostics des événements non-trade utiles, trades non actionnables et classifications inconnues ; ajout du profil `0.7.30_non_trade_event_classification` sans modification volontaire de la matérialisation trade/candle.
|
0.7.30 - Ajout d’une taxonomie DEX plus fine pour les événements décodés : `eventLifecycleKind`, `eventActionability`, `nonTradeUseful`, compteurs diagnostics des événements non-trade utiles, trades non actionnables et classifications inconnues ; ajout du profil `0.7.30_non_trade_event_classification` sans modification volontaire de la matérialisation trade/candle.
|
||||||
0.7.31 - Application de la politique Option B : les transactions failed restent traçables dans les événements décodés mais ne peuvent plus alimenter `trade_events`, metrics ou candles ; le replay local réinitialise les tables de matérialisation marché avant reconstruction pour supprimer les anciennes lignes dérivées non actionnables.
|
0.7.31 - Application de la politique Option B : les transactions failed restent traçables dans les événements décodés mais ne peuvent plus alimenter `trade_events`, metrics ou candles ; le replay local réinitialise les tables de matérialisation marché avant reconstruction pour supprimer les anciennes lignes dérivées non actionnables.
|
||||||
|
0.7.32 - Clarification de la sémantique des diagnostics locaux : séparation des gaps littéraux de paires et des gaps bloquants/actionnables, ajout des compteurs de matérialisation par paire, résumé `pairActionabilitySummaries`, profil `0.7.32_validation_report_semantics` et garde-fous sur la matrice DEX sans modification de la matérialisation trade/candle.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.7.31"
|
version = "0.7.32"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-bobobot"
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
`khadhroony-bobobot` est un workspace Rust destiné à la détection, au décodage, à l’analyse et, à terme, au trading semi-automatisé de tokens Solana.
|
`khadhroony-bobobot` est un workspace Rust destiné à la détection, au décodage, à l’analyse et, à terme, au trading semi-automatisé de tokens Solana.
|
||||||
|
|
||||||
Le README précédent décrivait surtout l’état `0.3.1`. Ce fichier reflète l’état de reprise autour de `0.7.30` : le socle transport HTTP/WS, la résolution transactionnelle, le modèle SQLite, plusieurs connecteurs DEX, les candles, les signaux analytiques, la validation locale et une matrice DEX commune existent déjà.
|
Le README précédent décrivait surtout l’état `0.3.1`. Ce fichier reflète l’état de reprise autour de `0.7.32` : le socle transport HTTP/WS, la résolution transactionnelle, le modèle SQLite, plusieurs connecteurs DEX, les candles, les signaux analytiques, la validation locale et une matrice DEX commune existent déjà.
|
||||||
|
|
||||||
## 1. Objectif
|
## 1. Objectif
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ Le workspace contient deux crates principales.
|
|||||||
|
|
||||||
La logique métier doit rester dans `kb_lib`. `kb_demo_app` doit rester une façade UI/Tauri et ne doit pas récupérer de logique Solana ou DEX profonde.
|
La logique métier doit rester dans `kb_lib`. `kb_demo_app` doit rester une façade UI/Tauri et ne doit pas récupérer de logique Solana ou DEX profonde.
|
||||||
|
|
||||||
## 3. État actuel autour de `0.7.30`
|
## 3. État actuel autour de `0.7.32`
|
||||||
|
|
||||||
### 3.1. Socle stabilisé à ne pas refactorer maintenant
|
### 3.1. Socle stabilisé à ne pas refactorer maintenant
|
||||||
|
|
||||||
@@ -99,6 +99,8 @@ Depuis `0.7.29`, la matrice de support DEX est portée par `kb_lib/src/dex_suppo
|
|||||||
|
|
||||||
Depuis `0.7.30`, les événements décodés reçoivent aussi une classification plus fine : `eventLifecycleKind`, `eventActionability` et `nonTradeUseful`. Cette classification sert aux diagnostics et prépare la matérialisation future des événements non-trade sans alimenter directement les trades/candles.
|
Depuis `0.7.30`, les événements décodés reçoivent aussi une classification plus fine : `eventLifecycleKind`, `eventActionability` et `nonTradeUseful`. Cette classification sert aux diagnostics et prépare la matérialisation future des événements non-trade sans alimenter directement les trades/candles.
|
||||||
|
|
||||||
|
Depuis `0.7.32`, les diagnostics distinguent explicitement les gaps littéraux de catalogue (`literalPairWithoutTradeCount`, `literalPairWithoutCandleCount`) des gaps bloquants/actionnables (`blockingPairWithoutTradeCount`, `blockingPairWithoutCandleCount`). Les anciens champs `pairWithoutTradeCount` et `pairWithoutCandleCount` restent exposés comme alias de compatibilité pour les gaps bloquants/actionnables.
|
||||||
|
|
||||||
| Code cible | Type | Statut `0.7.29` | Prochaine action |
|
| Code cible | Type | Statut `0.7.29` | Prochaine action |
|
||||||
|---|---:|---|---|
|
|---|---:|---|---|
|
||||||
| `pump_fun` | Launch + bonding curve | partiel | verrouiller le rattachement mint initial -> pools migrés |
|
| `pump_fun` | Launch + bonding curve | partiel | verrouiller le rattachement mint initial -> pools migrés |
|
||||||
@@ -215,9 +217,10 @@ Les tests peuvent rester plus souples lorsque cela clarifie le test.
|
|||||||
|
|
||||||
La reprise doit suivre cet ordre :
|
La reprise doit suivre cet ordre :
|
||||||
|
|
||||||
1. conserver la non-régression `0.7.31` : transactions failed traçables mais exclues des `trade_events`, metrics et candles ;
|
1. conserver la sémantique `0.7.32` : les gaps littéraux de catalogue ne doivent pas être confondus avec les gaps bloquants/actionnables utilisés par la validation ;
|
||||||
2. utiliser la matrice `0.7.29` comme source commune pour le catalogue, la classification et les protocol candidates ;
|
2. conserver la non-régression `0.7.31` : transactions failed traçables mais exclues des `trade_events`, metrics et candles ;
|
||||||
3. relier progressivement les événements non-trade aux tables existantes : lifecycle, liquidité, fees, rewards, admin ;
|
3. utiliser la matrice `0.7.29` comme source commune pour le catalogue, la classification et les protocol candidates ;
|
||||||
|
4. relier progressivement les événements non-trade aux tables existantes : lifecycle, liquidité, fees, rewards, admin ;
|
||||||
4. consolider Meteora, surtout `meteora_dlmm` et le cas partiel `meteora_damm_v1` ;
|
4. consolider Meteora, surtout `meteora_dlmm` et le cas partiel `meteora_damm_v1` ;
|
||||||
5. ajouter les launch surfaces manquantes comme origines de mint : LaunchLab/Launchpad, LetsBonk/Bonk.fun, Boop.fun, Moonshot/Moonit, Believe, Bags ;
|
5. ajouter les launch surfaces manquantes comme origines de mint : LaunchLab/Launchpad, LetsBonk/Bonk.fun, Boop.fun, Moonshot/Moonit, Believe, Bags ;
|
||||||
6. traiter Heaven ;
|
6. traiter Heaven ;
|
||||||
|
|||||||
51
ROADMAP.md
51
ROADMAP.md
@@ -846,18 +846,20 @@ Réalisé :
|
|||||||
- exposer `resetMarketMaterializationDeletedCount` dans le résultat de replay UI ;
|
- exposer `resetMarketMaterializationDeletedCount` dans le résultat de replay UI ;
|
||||||
- conserver la validation multi-DEX et la matrice DEX comme garde-fous avant d’ajouter les surfaces restantes.
|
- conserver la validation multi-DEX et la matrice DEX comme garde-fous avant d’ajouter les surfaces restantes.
|
||||||
|
|
||||||
### 6.064. Version `0.7.32` — Transactions inconnues et protocol candidates
|
### 6.064. Version `0.7.32` — Sémantique des diagnostics et compteurs de validation
|
||||||
Objectif : ne plus perdre les transactions utiles qui ne correspondent pas encore à un DEX connu.
|
Réalisé :
|
||||||
|
|
||||||
À faire :
|
- conserver la politique `0.7.31` : transactions failed traçables mais exclues des `trade_events`, metrics et candles ;
|
||||||
|
- clarifier que `pairWithoutTradeCount` et `pairWithoutCandleCount` sont des compteurs de gaps bloquants/actionnables, pas des compteurs littéraux sur tout le catalogue ;
|
||||||
|
- ajouter `literalPairWithoutTradeCount` et `literalPairWithoutCandleCount` pour les paires de catalogue sans trade/candle matérialisé ;
|
||||||
|
- ajouter `blockingPairWithoutTradeCount` et `blockingPairWithoutCandleCount` comme noms explicites des anciens compteurs bloquants ;
|
||||||
|
- ajouter les compteurs de matérialisation par paire : `tradeMaterializedPairCount`, `candleMaterializedPairCount`, `actionablePairCount`, `candleBucketTimeframeCount` et `candlesAreBucketed` ;
|
||||||
|
- ajouter `pairActionabilitySummaries` pour distinguer les paires matérialisées, actionnables sans matérialisation, candidates failed, non-actionables, décodées sans trade candidate et catalog-only ;
|
||||||
|
- ajouter le profil `0.7.32_validation_report_semantics` ;
|
||||||
|
- ajouter des garde-fous de validation sur la matrice DEX : entrées `supported` entièrement matérialisées, entrées `partial` avec `skipReason`, entrées `planned/to_verify` non activées au catalogue ;
|
||||||
|
- ne pas modifier la logique de replay, trade aggregation ou candle aggregation validée en `0.7.31`.
|
||||||
|
|
||||||
- consolider `k_sol_transaction_classifications`, déjà présente, avec les catégories utiles au suivi DEX,
|
Repoussé après cette clarification : consolider les transactions inconnues et protocol candidates sans polluer les trades/candles.
|
||||||
- consolider `k_sol_protocol_candidates`, déjà présente, pour prioriser les programmes inconnus ou partiellement reconnus,
|
|
||||||
- classifier les transactions résolues en catégories : known supported, known partial, known non-trade, unknown program, unknown protocol candidate, unknown event kind, failed transaction, non-actionable trade,
|
|
||||||
- conserver les `program_id`, comptes, signatures, préfixes de `data`, logs et indices d’instructions utiles à l’analyse,
|
|
||||||
- créer des requêtes de diagnostic pour repérer les programmes inconnus fréquents,
|
|
||||||
- permettre de promouvoir plus tard un protocol candidate vers un vrai DEX/surface sans perdre l’historique,
|
|
||||||
- garantir que ces tables n’alimentent jamais directement les trades/candles.
|
|
||||||
|
|
||||||
### 6.065. Version `0.7.33` — Événements non-trade v1 : liquidité et cycle de vie pool
|
### 6.065. Version `0.7.33` — Événements non-trade v1 : liquidité et cycle de vie pool
|
||||||
Objectif : exploiter les événements utiles à l’analyse et au trading semi-automatique sans les mélanger avec les swaps/candles.
|
Objectif : exploiter les événements utiles à l’analyse et au trading semi-automatique sans les mélanger avec les swaps/candles.
|
||||||
@@ -1212,17 +1214,18 @@ Le projet doit maintenir au minimum :
|
|||||||
La priorité immédiate est désormais la suivante :
|
La priorité immédiate est désormais la suivante :
|
||||||
|
|
||||||
1. conserver la validation acquise `0.7.31` : transactions failed traçables mais exclues des `trade_events`, metrics et candles, aucun trade/candle candidate sans payload montant/prix exploitable, aucun diagnostic bloquant masqué,
|
1. conserver la validation acquise `0.7.31` : transactions failed traçables mais exclues des `trade_events`, metrics et candles, aucun trade/candle candidate sans payload montant/prix exploitable, aucun diagnostic bloquant masqué,
|
||||||
2. utiliser la matrice `0.7.29` (`kb_lib/src/dex_support_matrix.rs`) comme source commune pour le catalogue DEX, les mappings program id -> protocole, la classification transactionnelle et les protocol candidates,
|
2. conserver la clarification `0.7.32` entre gaps littéraux de catalogue et gaps bloquants/actionnables,
|
||||||
3. garder les clients HTTP/WS et managers réseau hors du refactor DEX tant qu’ils ne bloquent pas le pipeline,
|
3. utiliser la matrice `0.7.29` (`kb_lib/src/dex_support_matrix.rs`) comme source commune pour le catalogue DEX, les mappings program id -> protocole, la classification transactionnelle et les protocol candidates,
|
||||||
4. consolider les événements non-trade sans les confondre avec les trades/candles : lifecycle de pool, liquidité, fees, rewards, admin/config, migration et launch/mint,
|
4. garder les clients HTTP/WS et managers réseau hors du refactor DEX tant qu’ils ne bloquent pas le pipeline,
|
||||||
5. rattacher les launch surfaces aux tokens et aux pools migrés : Raydium LaunchLab/Launchpad, LetsBonk/Bonk.fun, Boop.fun, Moonshot/Moonit, Believe, Bags et Heaven,
|
5. consolider les événements non-trade sans les confondre avec les trades/candles : lifecycle de pool, liquidité, fees, rewards, admin/config, migration et launch/mint,
|
||||||
6. consolider Meteora avec corpus fiable : `meteora_dlmm`, `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlc` si le programme est confirmé,
|
6. rattacher les launch surfaces aux tokens et aux pools migrés : Raydium LaunchLab/Launchpad, LetsBonk/Bonk.fun, Boop.fun, Moonshot/Moonit, Believe, Bags et Heaven,
|
||||||
7. consolider Orca, FluxBeam et DexLab sur corpus,
|
7. consolider Meteora avec corpus fiable : `meteora_dlmm`, `meteora_damm_v1`, `meteora_damm_v2`, `meteora_dbc` et `meteora_dlc` si le programme est confirmé,
|
||||||
8. traiter `raydium_amm_v4` legacy seulement après les autres Raydium, avec corpus dédié prouvant le programme `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`,
|
8. consolider Orca, FluxBeam et DexLab sur corpus,
|
||||||
9. ajouter une matérialisation dédiée des transactions inconnues ou partiellement décodées pour analyser les DEX manquants sans polluer les trades/candles,
|
9. traiter `raydium_amm_v4` legacy seulement après les autres Raydium, avec corpus dédié prouvant le programme `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`,
|
||||||
10. effectuer une validation DEX v1 consolidée sur tous les connecteurs supportés avant de considérer la couche DEX `0.7.x` comme stable,
|
10. ajouter une matérialisation dédiée des transactions inconnues ou partiellement décodées pour analyser les DEX manquants sans polluer les trades/candles,
|
||||||
11. ajouter ensuite les overlays des signaux analytiques sur les candles,
|
11. effectuer une validation DEX v1 consolidée sur tous les connecteurs supportés avant de considérer la couche DEX `0.7.x` comme stable,
|
||||||
12. consolider les vues métier `token / pair / pool` dans `kb_demo_app`, y compris les événements liquidité, lifecycle, fees, rewards et admin,
|
12. ajouter ensuite les overlays des signaux analytiques sur les candles,
|
||||||
13. stabiliser l’ergonomie, les filtres, la pagination et la navigation de l’UI d’inspection,
|
13. consolider les vues métier `token / pair / pool` dans `kb_demo_app`, y compris les événements liquidité, lifecycle, fees, rewards et admin,
|
||||||
14. préparer ensuite l’ouverture de `0.8.x` pour l’analyse, les filtres, les patterns et les projections graphiques,
|
14. stabiliser l’ergonomie, les filtres, la pagination et la navigation de l’UI d’inspection,
|
||||||
15. préparer enfin Yellowstone gRPC comme extension de capacité, et non comme remplacement du socle HTTP / WS existant.
|
15. préparer ensuite l’ouverture de `0.8.x` pour l’analyse, les filtres, les patterns et les projections graphiques,
|
||||||
|
16. préparer enfin Yellowstone gRPC comme extension de capacité, et non comme remplacement du socle HTTP / WS existant.
|
||||||
|
|||||||
@@ -166,7 +166,8 @@
|
|||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="demoPipeline2ValidationProfileSelect" class="form-label">Validation profile</label>
|
<label for="demoPipeline2ValidationProfileSelect" class="form-label">Validation profile</label>
|
||||||
<select id="demoPipeline2ValidationProfileSelect" class="form-select">
|
<select id="demoPipeline2ValidationProfileSelect" class="form-select">
|
||||||
<option value="0.7.31_trade_event_actionability_policy" selected>0.7.31 — trade event actionability policy</option>
|
<option value="0.7.32_validation_report_semantics" selected>0.7.32 — validation report semantics</option>
|
||||||
|
<option value="0.7.31_trade_event_actionability_policy">0.7.31 — trade event actionability policy</option>
|
||||||
<option value="0.7.30_non_trade_event_classification">0.7.30 — non-trade event classification</option>
|
<option value="0.7.30_non_trade_event_classification">0.7.30 — non-trade event classification</option>
|
||||||
<option value="0.7.29_multi_dex_matrix_baseline">0.7.29 — DEX matrix baseline</option>
|
<option value="0.7.29_multi_dex_matrix_baseline">0.7.29 — DEX matrix baseline</option>
|
||||||
<option value="0.7.28_multi_dex_non_regression">0.7.28 — multi-DEX non-regression</option>
|
<option value="0.7.28_multi_dex_non_regression">0.7.28 — multi-DEX non-regression</option>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local pair actionability diagnostics summary for the UI.
|
||||||
|
*/
|
||||||
|
export type DemoPipeline2LocalPairActionabilityDiagnosticSummary = {
|
||||||
|
/**
|
||||||
|
* Pair actionability or materialization class.
|
||||||
|
*/
|
||||||
|
pairActionability: string,
|
||||||
|
/**
|
||||||
|
* Pair count.
|
||||||
|
*/
|
||||||
|
pairCount: number,
|
||||||
|
/**
|
||||||
|
* Decoded event count.
|
||||||
|
*/
|
||||||
|
decodedEventCount: number,
|
||||||
|
/**
|
||||||
|
* Decoded trade candidate count.
|
||||||
|
*/
|
||||||
|
decodedTradeCandidateCount: number,
|
||||||
|
/**
|
||||||
|
* Actionable trade candidate count.
|
||||||
|
*/
|
||||||
|
actionableTradeCandidateCount: number,
|
||||||
|
/**
|
||||||
|
* Failed trade candidate count.
|
||||||
|
*/
|
||||||
|
failedTradeCandidateCount: number,
|
||||||
|
/**
|
||||||
|
* Trade event count.
|
||||||
|
*/
|
||||||
|
tradeEventCount: number,
|
||||||
|
/**
|
||||||
|
* Pair candle count.
|
||||||
|
*/
|
||||||
|
pairCandleCount: number, };
|
||||||
@@ -7,6 +7,7 @@ import type { DemoPipeline2LocalMissingTradeEventDiagnosticSample } from "./Demo
|
|||||||
import type { DemoPipeline2LocalMissingTradeEventReasonSummary } from "./DemoPipeline2LocalMissingTradeEventReasonSummary";
|
import type { DemoPipeline2LocalMissingTradeEventReasonSummary } from "./DemoPipeline2LocalMissingTradeEventReasonSummary";
|
||||||
import type { DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample } from "./DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample";
|
import type { DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample } from "./DemoPipeline2LocalMultiTradeSignaturePairDiagnosticSample";
|
||||||
import type { DemoPipeline2LocalNonActionablePairDiagnosticSummary } from "./DemoPipeline2LocalNonActionablePairDiagnosticSummary";
|
import type { DemoPipeline2LocalNonActionablePairDiagnosticSummary } from "./DemoPipeline2LocalNonActionablePairDiagnosticSummary";
|
||||||
|
import type { DemoPipeline2LocalPairActionabilityDiagnosticSummary } from "./DemoPipeline2LocalPairActionabilityDiagnosticSummary";
|
||||||
import type { DemoPipeline2LocalPairDiagnosticSummary } from "./DemoPipeline2LocalPairDiagnosticSummary";
|
import type { DemoPipeline2LocalPairDiagnosticSummary } from "./DemoPipeline2LocalPairDiagnosticSummary";
|
||||||
import type { DemoPipeline2LocalPairGapDiagnosticSample } from "./DemoPipeline2LocalPairGapDiagnosticSample";
|
import type { DemoPipeline2LocalPairGapDiagnosticSample } from "./DemoPipeline2LocalPairGapDiagnosticSample";
|
||||||
|
|
||||||
@@ -124,11 +125,51 @@ poolCount: number,
|
|||||||
*/
|
*/
|
||||||
pairCount: number,
|
pairCount: number,
|
||||||
/**
|
/**
|
||||||
* Total pairs without trade.
|
* Stable explanation for legacy pair gap counters.
|
||||||
|
*/
|
||||||
|
pairGapCounterSemantics: string,
|
||||||
|
/**
|
||||||
|
* Total pairs without any persisted trade event.
|
||||||
|
*/
|
||||||
|
literalPairWithoutTradeCount: number,
|
||||||
|
/**
|
||||||
|
* Total pairs without any persisted candle.
|
||||||
|
*/
|
||||||
|
literalPairWithoutCandleCount: number,
|
||||||
|
/**
|
||||||
|
* Total pairs that have at least one persisted trade event.
|
||||||
|
*/
|
||||||
|
tradeMaterializedPairCount: number,
|
||||||
|
/**
|
||||||
|
* Total pairs that have at least one persisted candle bucket.
|
||||||
|
*/
|
||||||
|
candleMaterializedPairCount: number,
|
||||||
|
/**
|
||||||
|
* Total pairs with at least one successful decoded trade candidate.
|
||||||
|
*/
|
||||||
|
actionablePairCount: number,
|
||||||
|
/**
|
||||||
|
* Total distinct candle timeframes currently materialized.
|
||||||
|
*/
|
||||||
|
candleBucketTimeframeCount: number,
|
||||||
|
/**
|
||||||
|
* Whether candle rows are bucketed aggregates rather than one row per trade.
|
||||||
|
*/
|
||||||
|
candlesAreBucketed: boolean,
|
||||||
|
/**
|
||||||
|
* Total pairs without trade among actionable successful trade candidates.
|
||||||
|
*/
|
||||||
|
blockingPairWithoutTradeCount: number,
|
||||||
|
/**
|
||||||
|
* Total pairs without candle among actionable successful candle candidates.
|
||||||
|
*/
|
||||||
|
blockingPairWithoutCandleCount: number,
|
||||||
|
/**
|
||||||
|
* Total pairs without trade. Legacy alias for blocking/actionable gaps.
|
||||||
*/
|
*/
|
||||||
pairWithoutTradeCount: number,
|
pairWithoutTradeCount: number,
|
||||||
/**
|
/**
|
||||||
* Total pairs without candle.
|
* Total pairs without candle. Legacy alias for blocking/actionable gaps.
|
||||||
*/
|
*/
|
||||||
pairWithoutCandleCount: number,
|
pairWithoutCandleCount: number,
|
||||||
/**
|
/**
|
||||||
@@ -139,6 +180,10 @@ dexSummaries: Array<DemoPipeline2LocalDexDiagnosticSummary>,
|
|||||||
* Diagnostics grouped by pair.
|
* Diagnostics grouped by pair.
|
||||||
*/
|
*/
|
||||||
pairSummaries: Array<DemoPipeline2LocalPairDiagnosticSummary>,
|
pairSummaries: Array<DemoPipeline2LocalPairDiagnosticSummary>,
|
||||||
|
/**
|
||||||
|
* Diagnostics grouped by pair materialization/actionability class.
|
||||||
|
*/
|
||||||
|
pairActionabilitySummaries: Array<DemoPipeline2LocalPairActionabilityDiagnosticSummary>,
|
||||||
/**
|
/**
|
||||||
* Diagnostics grouped by decoded event kind.
|
* Diagnostics grouped by decoded event kind.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "kb-demo-app",
|
"name": "kb-demo-app",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.7.31",
|
"version": "0.7.32",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -327,16 +327,47 @@ pub(crate) struct DemoPipeline2LocalPipelineDiagnosticSummary {
|
|||||||
/// Total known pairs.
|
/// Total known pairs.
|
||||||
#[ts(type = "number")]
|
#[ts(type = "number")]
|
||||||
pub pair_count: i64,
|
pub pair_count: i64,
|
||||||
/// Total pairs without trade.
|
/// Stable explanation for legacy pair gap counters.
|
||||||
|
pub pair_gap_counter_semantics: std::string::String,
|
||||||
|
/// Total pairs without any persisted trade event.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub literal_pair_without_trade_count: i64,
|
||||||
|
/// Total pairs without any persisted candle.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub literal_pair_without_candle_count: i64,
|
||||||
|
/// Total pairs that have at least one persisted trade event.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub trade_materialized_pair_count: i64,
|
||||||
|
/// Total pairs that have at least one persisted candle bucket.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub candle_materialized_pair_count: i64,
|
||||||
|
/// Total pairs with at least one successful decoded trade candidate.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub actionable_pair_count: i64,
|
||||||
|
/// Total distinct candle timeframes currently materialized.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub candle_bucket_timeframe_count: i64,
|
||||||
|
/// Whether candle rows are bucketed aggregates rather than one row per trade.
|
||||||
|
pub candles_are_bucketed: bool,
|
||||||
|
/// Total pairs without trade among actionable successful trade candidates.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub blocking_pair_without_trade_count: i64,
|
||||||
|
/// Total pairs without candle among actionable successful candle candidates.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub blocking_pair_without_candle_count: i64,
|
||||||
|
/// Total pairs without trade. Legacy alias for blocking/actionable gaps.
|
||||||
#[ts(type = "number")]
|
#[ts(type = "number")]
|
||||||
pub pair_without_trade_count: i64,
|
pub pair_without_trade_count: i64,
|
||||||
/// Total pairs without candle.
|
/// Total pairs without candle. Legacy alias for blocking/actionable gaps.
|
||||||
#[ts(type = "number")]
|
#[ts(type = "number")]
|
||||||
pub pair_without_candle_count: i64,
|
pub pair_without_candle_count: i64,
|
||||||
/// Diagnostics grouped by DEX.
|
/// Diagnostics grouped by DEX.
|
||||||
pub dex_summaries: std::vec::Vec<DemoPipeline2LocalDexDiagnosticSummary>,
|
pub dex_summaries: std::vec::Vec<DemoPipeline2LocalDexDiagnosticSummary>,
|
||||||
/// Diagnostics grouped by pair.
|
/// Diagnostics grouped by pair.
|
||||||
pub pair_summaries: std::vec::Vec<DemoPipeline2LocalPairDiagnosticSummary>,
|
pub pair_summaries: std::vec::Vec<DemoPipeline2LocalPairDiagnosticSummary>,
|
||||||
|
/// Diagnostics grouped by pair materialization/actionability class.
|
||||||
|
pub pair_actionability_summaries:
|
||||||
|
std::vec::Vec<DemoPipeline2LocalPairActionabilityDiagnosticSummary>,
|
||||||
/// Diagnostics grouped by decoded event kind.
|
/// Diagnostics grouped by decoded event kind.
|
||||||
pub decoded_event_summaries: std::vec::Vec<DemoPipeline2LocalDecodedEventDiagnosticSummary>,
|
pub decoded_event_summaries: std::vec::Vec<DemoPipeline2LocalDecodedEventDiagnosticSummary>,
|
||||||
/// Diagnostics grouped by decoded event classification.
|
/// Diagnostics grouped by decoded event classification.
|
||||||
@@ -447,6 +478,39 @@ pub(crate) struct DemoPipeline2LocalPairDiagnosticSummary {
|
|||||||
pub last_price_quote_per_base: std::option::Option<f64>,
|
pub last_price_quote_per_base: std::option::Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Local pair actionability diagnostics summary for the UI.
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
|
#[ts(
|
||||||
|
export,
|
||||||
|
export_to = "../frontend/ts/bindings/DemoPipeline2LocalPairActionabilityDiagnosticSummary.ts"
|
||||||
|
)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub(crate) struct DemoPipeline2LocalPairActionabilityDiagnosticSummary {
|
||||||
|
/// Pair actionability or materialization class.
|
||||||
|
pub pair_actionability: std::string::String,
|
||||||
|
/// Pair count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub pair_count: i64,
|
||||||
|
/// Decoded event count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub decoded_event_count: i64,
|
||||||
|
/// Decoded trade candidate count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub decoded_trade_candidate_count: i64,
|
||||||
|
/// Actionable trade candidate count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub actionable_trade_candidate_count: i64,
|
||||||
|
/// Failed trade candidate count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub failed_trade_candidate_count: i64,
|
||||||
|
/// Trade event count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub trade_event_count: i64,
|
||||||
|
/// Pair candle count.
|
||||||
|
#[ts(type = "number")]
|
||||||
|
pub pair_candle_count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
/// Local decoded-event diagnostics summary for the UI.
|
/// Local decoded-event diagnostics summary for the UI.
|
||||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
#[ts(
|
#[ts(
|
||||||
@@ -971,7 +1035,7 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
|
|||||||
let service = kb_lib::LocalPipelineValidationService::new(database.clone());
|
let service = kb_lib::LocalPipelineValidationService::new(database.clone());
|
||||||
let profile_code = match request {
|
let profile_code = match request {
|
||||||
Some(request) => request.profile_code,
|
Some(request) => request.profile_code,
|
||||||
None => "0.7.31_trade_event_actionability_policy".to_string(),
|
None => "0.7.32_validation_report_semantics".to_string(),
|
||||||
};
|
};
|
||||||
let run_result = match profile_code.as_str() {
|
let run_result = match profile_code.as_str() {
|
||||||
"0.7.27" | "0.7.27_dexes_non_regression" => {
|
"0.7.27" | "0.7.27_dexes_non_regression" => {
|
||||||
@@ -989,6 +1053,9 @@ pub(crate) async fn demo_pipeline2_validate_local_pipeline(
|
|||||||
"0.7.31" | "0.7.31_trade_event_actionability_policy" => {
|
"0.7.31" | "0.7.31_trade_event_actionability_policy" => {
|
||||||
service.validate_v0_7_31_current_database().await
|
service.validate_v0_7_31_current_database().await
|
||||||
},
|
},
|
||||||
|
"0.7.32" | "0.7.32_validation_report_semantics" => {
|
||||||
|
service.validate_v0_7_32_current_database().await
|
||||||
|
},
|
||||||
other => Err(kb_lib::Error::InvalidState(format!(
|
other => Err(kb_lib::Error::InvalidState(format!(
|
||||||
"unsupported local pipeline validation profile: {other}"
|
"unsupported local pipeline validation profile: {other}"
|
||||||
))),
|
))),
|
||||||
@@ -1472,6 +1539,14 @@ fn demo_pipeline2_map_local_diagnostics_summary(
|
|||||||
for pair_summary in summary.pair_summaries {
|
for pair_summary in summary.pair_summaries {
|
||||||
pair_summaries.push(demo_pipeline2_map_local_pair_diagnostic_summary(pair_summary));
|
pair_summaries.push(demo_pipeline2_map_local_pair_diagnostic_summary(pair_summary));
|
||||||
}
|
}
|
||||||
|
let mut pair_actionability_summaries = std::vec::Vec::new();
|
||||||
|
for pair_actionability_summary in summary.pair_actionability_summaries {
|
||||||
|
pair_actionability_summaries.push(
|
||||||
|
demo_pipeline2_map_local_pair_actionability_diagnostic_summary(
|
||||||
|
pair_actionability_summary,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
let mut decoded_event_summaries = std::vec::Vec::new();
|
let mut decoded_event_summaries = std::vec::Vec::new();
|
||||||
for decoded_event_summary in summary.decoded_event_summaries {
|
for decoded_event_summary in summary.decoded_event_summaries {
|
||||||
decoded_event_summaries
|
decoded_event_summaries
|
||||||
@@ -1552,10 +1627,21 @@ fn demo_pipeline2_map_local_diagnostics_summary(
|
|||||||
token_metadata_missing_count: summary.token_metadata_missing_count,
|
token_metadata_missing_count: summary.token_metadata_missing_count,
|
||||||
pool_count: summary.pool_count,
|
pool_count: summary.pool_count,
|
||||||
pair_count: summary.pair_count,
|
pair_count: summary.pair_count,
|
||||||
|
pair_gap_counter_semantics: summary.pair_gap_counter_semantics,
|
||||||
|
literal_pair_without_trade_count: summary.literal_pair_without_trade_count,
|
||||||
|
literal_pair_without_candle_count: summary.literal_pair_without_candle_count,
|
||||||
|
trade_materialized_pair_count: summary.trade_materialized_pair_count,
|
||||||
|
candle_materialized_pair_count: summary.candle_materialized_pair_count,
|
||||||
|
actionable_pair_count: summary.actionable_pair_count,
|
||||||
|
candle_bucket_timeframe_count: summary.candle_bucket_timeframe_count,
|
||||||
|
candles_are_bucketed: summary.candles_are_bucketed,
|
||||||
|
blocking_pair_without_trade_count: summary.blocking_pair_without_trade_count,
|
||||||
|
blocking_pair_without_candle_count: summary.blocking_pair_without_candle_count,
|
||||||
pair_without_trade_count: summary.pair_without_trade_count,
|
pair_without_trade_count: summary.pair_without_trade_count,
|
||||||
pair_without_candle_count: summary.pair_without_candle_count,
|
pair_without_candle_count: summary.pair_without_candle_count,
|
||||||
dex_summaries,
|
dex_summaries,
|
||||||
pair_summaries,
|
pair_summaries,
|
||||||
|
pair_actionability_summaries,
|
||||||
decoded_event_summaries,
|
decoded_event_summaries,
|
||||||
event_classification_summaries,
|
event_classification_summaries,
|
||||||
missing_trade_event_reason_summaries,
|
missing_trade_event_reason_summaries,
|
||||||
@@ -1606,6 +1692,21 @@ fn demo_pipeline2_map_local_pair_diagnostic_summary(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn demo_pipeline2_map_local_pair_actionability_diagnostic_summary(
|
||||||
|
summary: kb_lib::LocalPairActionabilityDiagnosticSummaryDto,
|
||||||
|
) -> DemoPipeline2LocalPairActionabilityDiagnosticSummary {
|
||||||
|
DemoPipeline2LocalPairActionabilityDiagnosticSummary {
|
||||||
|
pair_actionability: summary.pair_actionability,
|
||||||
|
pair_count: summary.pair_count,
|
||||||
|
decoded_event_count: summary.decoded_event_count,
|
||||||
|
decoded_trade_candidate_count: summary.decoded_trade_candidate_count,
|
||||||
|
actionable_trade_candidate_count: summary.actionable_trade_candidate_count,
|
||||||
|
failed_trade_candidate_count: summary.failed_trade_candidate_count,
|
||||||
|
trade_event_count: summary.trade_event_count,
|
||||||
|
pair_candle_count: summary.pair_candle_count,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn demo_pipeline2_map_local_decoded_event_diagnostic_summary(
|
fn demo_pipeline2_map_local_decoded_event_diagnostic_summary(
|
||||||
summary: kb_lib::LocalDecodedEventDiagnosticSummaryDto,
|
summary: kb_lib::LocalDecodedEventDiagnosticSummaryDto,
|
||||||
) -> DemoPipeline2LocalDecodedEventDiagnosticSummary {
|
) -> DemoPipeline2LocalDecodedEventDiagnosticSummary {
|
||||||
|
|||||||
@@ -436,8 +436,7 @@ async fn execute_demo_ws_subscribe(
|
|||||||
let result = client.account_subscribe_typed(target, config).await;
|
let result = client.account_subscribe_typed(target, config).await;
|
||||||
return result.map_err(|error| format!("account typed subscribe failed: {error}"));
|
return result.map_err(|error| format!("account typed subscribe failed: {error}"));
|
||||||
}
|
}
|
||||||
let config_result =
|
let config_result = parse_optional_json_value(&request.config_json, "account raw config");
|
||||||
parse_optional_json_value(&request.config_json, "account raw config");
|
|
||||||
let config = match config_result {
|
let config = match config_result {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
@@ -526,8 +525,7 @@ async fn execute_demo_ws_subscribe(
|
|||||||
let result = client.program_subscribe_typed(target, config).await;
|
let result = client.program_subscribe_typed(target, config).await;
|
||||||
return result.map_err(|error| format!("program typed subscribe failed: {error}"));
|
return result.map_err(|error| format!("program typed subscribe failed: {error}"));
|
||||||
}
|
}
|
||||||
let config_result =
|
let config_result = parse_optional_json_value(&request.config_json, "program raw config");
|
||||||
parse_optional_json_value(&request.config_json, "program raw config");
|
|
||||||
let config = match config_result {
|
let config = match config_result {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
@@ -556,8 +554,7 @@ async fn execute_demo_ws_subscribe(
|
|||||||
let result = client.signature_subscribe_typed(target, config).await;
|
let result = client.signature_subscribe_typed(target, config).await;
|
||||||
return result.map_err(|error| format!("signature typed subscribe failed: {error}"));
|
return result.map_err(|error| format!("signature typed subscribe failed: {error}"));
|
||||||
}
|
}
|
||||||
let config_result =
|
let config_result = parse_optional_json_value(&request.config_json, "signature raw config");
|
||||||
parse_optional_json_value(&request.config_json, "signature raw config");
|
|
||||||
let config = match config_result {
|
let config = match config_result {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
|
|||||||
@@ -174,8 +174,7 @@ pub(crate) async fn demo_ws_manager_start_role(
|
|||||||
Ok(changed_count) => changed_count,
|
Ok(changed_count) => changed_count,
|
||||||
Err(error) => return Err(error.to_string()),
|
Err(error) => return Err(error.to_string()),
|
||||||
};
|
};
|
||||||
let action_result =
|
let action_result = build_action_result("start", role.as_str(), matched_count, changed_count);
|
||||||
build_action_result("start", role.as_str(), matched_count, changed_count);
|
|
||||||
emit_demo_ws_manager_log(&app_handle, format_action_result_for_log(&action_result).as_str());
|
emit_demo_ws_manager_log(&app_handle, format_action_result_for_log(&action_result).as_str());
|
||||||
emit_demo_ws_manager_snapshot(&app_handle, &state).await;
|
emit_demo_ws_manager_snapshot(&app_handle, &state).await;
|
||||||
build_demo_ws_manager_snapshot(&state).await
|
build_demo_ws_manager_snapshot(&state).await
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async fn main() -> std::process::ExitCode {
|
|||||||
Err(_err) => {
|
Err(_err) => {
|
||||||
eprintln!("Cannot create lock!");
|
eprintln!("Cannot create lock!");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
// trying to aquire an exclusive lock
|
// trying to aquire an exclusive lock
|
||||||
if lock_file.try_lock_exclusive().is_err() {
|
if lock_file.try_lock_exclusive().is_err() {
|
||||||
@@ -32,11 +32,11 @@ async fn main() -> std::process::ExitCode {
|
|||||||
if rustls::crypto::CryptoProvider::get_default().is_none() {
|
if rustls::crypto::CryptoProvider::get_default().is_none() {
|
||||||
let provider_result = rustls::crypto::aws_lc_rs::default_provider().install_default();
|
let provider_result = rustls::crypto::aws_lc_rs::default_provider().install_default();
|
||||||
match provider_result {
|
match provider_result {
|
||||||
Ok(()) => {}
|
Ok(()) => {},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("kb_demo_app rustls provider init error: {:?}", error);
|
eprintln!("kb_demo_app rustls provider init error: {:?}", error);
|
||||||
return std::process::ExitCode::FAILURE;
|
return std::process::ExitCode::FAILURE;
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let run_result = kb_demo_app_lib::run().await;
|
let run_result = kb_demo_app_lib::run().await;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "kb-demo-app",
|
"productName": "kb-demo-app",
|
||||||
"version": "0.7.31",
|
"version": "0.7.32",
|
||||||
"identifier": "com.sasedev.kb-demo-app",
|
"identifier": "com.sasedev.kb-demo-app",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "npm run dev",
|
"beforeDevCommand": "npm run dev",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ pub use dtos::LocalMissingTradeEventDiagnosticSampleDto;
|
|||||||
pub use dtos::LocalMissingTradeEventReasonSummaryDto;
|
pub use dtos::LocalMissingTradeEventReasonSummaryDto;
|
||||||
pub use dtos::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
pub use dtos::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
||||||
pub use dtos::LocalNonActionablePairDiagnosticSummaryDto;
|
pub use dtos::LocalNonActionablePairDiagnosticSummaryDto;
|
||||||
|
pub use dtos::LocalPairActionabilityDiagnosticSummaryDto;
|
||||||
pub use dtos::LocalPairDiagnosticSummaryDto;
|
pub use dtos::LocalPairDiagnosticSummaryDto;
|
||||||
pub use dtos::LocalPairGapDiagnosticSampleDto;
|
pub use dtos::LocalPairGapDiagnosticSampleDto;
|
||||||
pub use dtos::LocalPipelineDiagnosticCountersDto;
|
pub use dtos::LocalPipelineDiagnosticCountersDto;
|
||||||
@@ -150,6 +151,7 @@ pub use queries::query_local_missing_trade_event_diagnostic_list_samples;
|
|||||||
pub use queries::query_local_missing_trade_event_reason_list_summaries;
|
pub use queries::query_local_missing_trade_event_reason_list_summaries;
|
||||||
pub use queries::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
pub use queries::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
||||||
pub use queries::query_local_non_actionable_pair_diagnostic_list_summaries;
|
pub use queries::query_local_non_actionable_pair_diagnostic_list_summaries;
|
||||||
|
pub use queries::query_local_pair_actionability_diagnostic_list_summaries;
|
||||||
pub use queries::query_local_pair_diagnostic_list_summaries;
|
pub use queries::query_local_pair_diagnostic_list_summaries;
|
||||||
pub use queries::query_local_pair_without_candle_diagnostic_list_samples;
|
pub use queries::query_local_pair_without_candle_diagnostic_list_samples;
|
||||||
pub use queries::query_local_pair_without_trade_diagnostic_list_samples;
|
pub use queries::query_local_pair_without_trade_diagnostic_list_samples;
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ mod pool_listing;
|
|||||||
mod pool_origin;
|
mod pool_origin;
|
||||||
mod pool_token;
|
mod pool_token;
|
||||||
mod program_instruction_diagnostic;
|
mod program_instruction_diagnostic;
|
||||||
|
mod program_instruction_discriminator_summary;
|
||||||
mod protocol_candidate;
|
mod protocol_candidate;
|
||||||
mod protocol_candidate_summary;
|
mod protocol_candidate_summary;
|
||||||
mod swap;
|
mod swap;
|
||||||
@@ -38,22 +39,21 @@ mod trade_event;
|
|||||||
mod transaction_classification;
|
mod transaction_classification;
|
||||||
mod wallet;
|
mod wallet;
|
||||||
mod wallet_holding;
|
mod wallet_holding;
|
||||||
mod program_instruction_discriminator_summary;
|
|
||||||
mod wallet_participation;
|
mod wallet_participation;
|
||||||
|
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryRow;
|
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalDexDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalDexDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleRow;
|
||||||
|
pub(crate) use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalNonActionablePairDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalNonActionablePairDiagnosticSummaryRow;
|
||||||
|
pub(crate) use local_pipeline_diagnostics::LocalPairActionabilityDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalPairDiagnosticSummaryRow;
|
pub(crate) use local_pipeline_diagnostics::LocalPairDiagnosticSummaryRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleRow;
|
pub(crate) use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleRow;
|
||||||
pub(crate) use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersRow;
|
pub(crate) use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersRow;
|
||||||
|
|
||||||
pub use program_instruction_discriminator_summary::ProgramInstructionDiscriminatorSummaryDto;
|
|
||||||
pub use analysis_signal::AnalysisSignalDto;
|
pub use analysis_signal::AnalysisSignalDto;
|
||||||
pub use chain_instruction::ChainInstructionDto;
|
pub use chain_instruction::ChainInstructionDto;
|
||||||
pub use chain_slot::ChainSlotDto;
|
pub use chain_slot::ChainSlotDto;
|
||||||
@@ -69,13 +69,14 @@ pub use launch_surface::LaunchSurfaceDto;
|
|||||||
pub use launch_surface_key::LaunchSurfaceKeyDto;
|
pub use launch_surface_key::LaunchSurfaceKeyDto;
|
||||||
pub use liquidity_event::LiquidityEventDto;
|
pub use liquidity_event::LiquidityEventDto;
|
||||||
pub use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalDecodedEventDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryDto;
|
|
||||||
pub use local_pipeline_diagnostics::LocalDexDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalDexDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalDuplicateDecodedEventTradeDiagnosticSampleDto;
|
||||||
|
pub use local_pipeline_diagnostics::LocalEventClassificationDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalMissingTradeEventDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryDto;
|
pub use local_pipeline_diagnostics::LocalMissingTradeEventReasonSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalNonActionablePairDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalNonActionablePairDiagnosticSummaryDto;
|
||||||
|
pub use local_pipeline_diagnostics::LocalPairActionabilityDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalPairDiagnosticSummaryDto;
|
pub use local_pipeline_diagnostics::LocalPairDiagnosticSummaryDto;
|
||||||
pub use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleDto;
|
pub use local_pipeline_diagnostics::LocalPairGapDiagnosticSampleDto;
|
||||||
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersDto;
|
pub use local_pipeline_diagnostics::LocalPipelineDiagnosticCountersDto;
|
||||||
@@ -91,6 +92,7 @@ pub use pool_listing::PoolListingDto;
|
|||||||
pub use pool_origin::PoolOriginDto;
|
pub use pool_origin::PoolOriginDto;
|
||||||
pub use pool_token::PoolTokenDto;
|
pub use pool_token::PoolTokenDto;
|
||||||
pub use program_instruction_diagnostic::ProgramInstructionDiagnosticDto;
|
pub use program_instruction_diagnostic::ProgramInstructionDiagnosticDto;
|
||||||
|
pub use program_instruction_discriminator_summary::ProgramInstructionDiscriminatorSummaryDto;
|
||||||
pub use protocol_candidate::ProtocolCandidateDto;
|
pub use protocol_candidate::ProtocolCandidateDto;
|
||||||
pub use protocol_candidate_summary::ProtocolCandidateSummaryDto;
|
pub use protocol_candidate_summary::ProtocolCandidateSummaryDto;
|
||||||
pub use swap::SwapDto;
|
pub use swap::SwapDto;
|
||||||
|
|||||||
@@ -65,14 +65,46 @@ pub struct LocalPipelineDiagnosticSummaryDto {
|
|||||||
pub pool_count: i64,
|
pub pool_count: i64,
|
||||||
/// Total known pairs.
|
/// Total known pairs.
|
||||||
pub pair_count: i64,
|
pub pair_count: i64,
|
||||||
|
/// Stable explanation for legacy pair gap counters.
|
||||||
|
///
|
||||||
|
/// `pair_without_trade_count` and `pair_without_candle_count` are blocking
|
||||||
|
/// actionable gap counters, not literal catalog-wide counters.
|
||||||
|
pub pair_gap_counter_semantics: std::string::String,
|
||||||
|
/// Total pairs without any persisted trade event, including catalog-only and partial DEX pairs.
|
||||||
|
pub literal_pair_without_trade_count: i64,
|
||||||
|
/// Total pairs without any persisted candle, including catalog-only and partial DEX pairs.
|
||||||
|
pub literal_pair_without_candle_count: i64,
|
||||||
|
/// Total pairs that have at least one persisted trade event.
|
||||||
|
pub trade_materialized_pair_count: i64,
|
||||||
|
/// Total pairs that have at least one persisted candle bucket.
|
||||||
|
pub candle_materialized_pair_count: i64,
|
||||||
|
/// Total pairs with at least one successful decoded trade candidate.
|
||||||
|
pub actionable_pair_count: i64,
|
||||||
|
/// Total distinct candle timeframes currently materialized.
|
||||||
|
pub candle_bucket_timeframe_count: i64,
|
||||||
|
/// Whether candle rows are bucketed aggregates rather than one row per trade.
|
||||||
|
pub candles_are_bucketed: bool,
|
||||||
|
/// Total pairs without trade event among actionable successful trade candidates.
|
||||||
|
pub blocking_pair_without_trade_count: i64,
|
||||||
|
/// Total pairs without candle among actionable successful candle candidates.
|
||||||
|
pub blocking_pair_without_candle_count: i64,
|
||||||
/// Total pairs without trade event.
|
/// Total pairs without trade event.
|
||||||
|
///
|
||||||
|
/// Legacy alias kept for compatibility. It has the same semantics as
|
||||||
|
/// `blocking_pair_without_trade_count`.
|
||||||
pub pair_without_trade_count: i64,
|
pub pair_without_trade_count: i64,
|
||||||
/// Total pairs without candle.
|
/// Total pairs without candle.
|
||||||
|
///
|
||||||
|
/// Legacy alias kept for compatibility. It has the same semantics as
|
||||||
|
/// `blocking_pair_without_candle_count`.
|
||||||
pub pair_without_candle_count: i64,
|
pub pair_without_candle_count: i64,
|
||||||
/// Diagnostics grouped by DEX.
|
/// Diagnostics grouped by DEX.
|
||||||
pub dex_summaries: std::vec::Vec<crate::LocalDexDiagnosticSummaryDto>,
|
pub dex_summaries: std::vec::Vec<crate::LocalDexDiagnosticSummaryDto>,
|
||||||
/// Diagnostics grouped by pair.
|
/// Diagnostics grouped by pair.
|
||||||
pub pair_summaries: std::vec::Vec<crate::LocalPairDiagnosticSummaryDto>,
|
pub pair_summaries: std::vec::Vec<crate::LocalPairDiagnosticSummaryDto>,
|
||||||
|
/// Diagnostics grouped by pair materialization/actionability class.
|
||||||
|
pub pair_actionability_summaries:
|
||||||
|
std::vec::Vec<crate::LocalPairActionabilityDiagnosticSummaryDto>,
|
||||||
/// Diagnostics grouped by decoded event kind.
|
/// Diagnostics grouped by decoded event kind.
|
||||||
pub decoded_event_summaries: std::vec::Vec<crate::LocalDecodedEventDiagnosticSummaryDto>,
|
pub decoded_event_summaries: std::vec::Vec<crate::LocalDecodedEventDiagnosticSummaryDto>,
|
||||||
/// Diagnostics grouped by decoded event category, lifecycle kind and actionability.
|
/// Diagnostics grouped by decoded event category, lifecycle kind and actionability.
|
||||||
@@ -157,6 +189,27 @@ pub struct LocalPairDiagnosticSummaryDto {
|
|||||||
pub last_price_quote_per_base: std::option::Option<f64>,
|
pub last_price_quote_per_base: std::option::Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Local pair diagnostics grouped by materialization/actionability class.
|
||||||
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct LocalPairActionabilityDiagnosticSummaryDto {
|
||||||
|
/// Pair actionability or materialization class.
|
||||||
|
pub pair_actionability: std::string::String,
|
||||||
|
/// Total pairs in this class.
|
||||||
|
pub pair_count: i64,
|
||||||
|
/// Total decoded events attached to pairs in this class.
|
||||||
|
pub decoded_event_count: i64,
|
||||||
|
/// Total decoded trade candidates attached to pairs in this class.
|
||||||
|
pub decoded_trade_candidate_count: i64,
|
||||||
|
/// Total decoded trade candidates on successful transactions attached to pairs in this class.
|
||||||
|
pub actionable_trade_candidate_count: i64,
|
||||||
|
/// Total decoded trade candidates on failed transactions attached to pairs in this class.
|
||||||
|
pub failed_trade_candidate_count: i64,
|
||||||
|
/// Total persisted trade events attached to pairs in this class.
|
||||||
|
pub trade_event_count: i64,
|
||||||
|
/// Total persisted candle buckets attached to pairs in this class.
|
||||||
|
pub pair_candle_count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
/// Local decoded-event diagnostics summary.
|
/// Local decoded-event diagnostics summary.
|
||||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct LocalDecodedEventDiagnosticSummaryDto {
|
pub struct LocalDecodedEventDiagnosticSummaryDto {
|
||||||
@@ -314,8 +367,24 @@ pub struct LocalPipelineDiagnosticCountersDto {
|
|||||||
pub pool_count: i64,
|
pub pool_count: i64,
|
||||||
/// Total known pairs.
|
/// Total known pairs.
|
||||||
pub pair_count: i64,
|
pub pair_count: i64,
|
||||||
|
/// Total pairs without any persisted trade event, including catalog-only and partial DEX pairs.
|
||||||
|
pub literal_pair_without_trade_count: i64,
|
||||||
|
/// Total pairs without any persisted candle, including catalog-only and partial DEX pairs.
|
||||||
|
pub literal_pair_without_candle_count: i64,
|
||||||
|
/// Total pairs that have at least one persisted trade event.
|
||||||
|
pub trade_materialized_pair_count: i64,
|
||||||
|
/// Total pairs that have at least one persisted candle bucket.
|
||||||
|
pub candle_materialized_pair_count: i64,
|
||||||
|
/// Total pairs with at least one successful decoded trade candidate.
|
||||||
|
pub actionable_pair_count: i64,
|
||||||
|
/// Total distinct candle timeframes currently materialized.
|
||||||
|
pub candle_bucket_timeframe_count: i64,
|
||||||
/// Total pairs with only non-actionable missing trade events.
|
/// Total pairs with only non-actionable missing trade events.
|
||||||
pub non_actionable_pair_count: i64,
|
pub non_actionable_pair_count: i64,
|
||||||
|
/// Total pairs without trade among actionable successful trade candidates.
|
||||||
|
pub blocking_pair_without_trade_count: i64,
|
||||||
|
/// Total pairs without candle among actionable successful candle candidates.
|
||||||
|
pub blocking_pair_without_candle_count: i64,
|
||||||
/// Total pairs without trade.
|
/// Total pairs without trade.
|
||||||
pub pair_without_trade_count: i64,
|
pub pair_without_trade_count: i64,
|
||||||
/// Total pairs without candle.
|
/// Total pairs without candle.
|
||||||
@@ -351,7 +420,15 @@ pub(crate) struct LocalPipelineDiagnosticCountersRow {
|
|||||||
pub(crate) token_metadata_missing_count: i64,
|
pub(crate) token_metadata_missing_count: i64,
|
||||||
pub(crate) pool_count: i64,
|
pub(crate) pool_count: i64,
|
||||||
pub(crate) pair_count: i64,
|
pub(crate) pair_count: i64,
|
||||||
|
pub(crate) literal_pair_without_trade_count: i64,
|
||||||
|
pub(crate) literal_pair_without_candle_count: i64,
|
||||||
|
pub(crate) trade_materialized_pair_count: i64,
|
||||||
|
pub(crate) candle_materialized_pair_count: i64,
|
||||||
|
pub(crate) actionable_pair_count: i64,
|
||||||
|
pub(crate) candle_bucket_timeframe_count: i64,
|
||||||
pub(crate) non_actionable_pair_count: i64,
|
pub(crate) non_actionable_pair_count: i64,
|
||||||
|
pub(crate) blocking_pair_without_trade_count: i64,
|
||||||
|
pub(crate) blocking_pair_without_candle_count: i64,
|
||||||
pub(crate) pair_without_trade_count: i64,
|
pub(crate) pair_without_trade_count: i64,
|
||||||
pub(crate) pair_without_candle_count: i64,
|
pub(crate) pair_without_candle_count: i64,
|
||||||
}
|
}
|
||||||
@@ -389,6 +466,19 @@ pub(crate) struct LocalPairDiagnosticSummaryRow {
|
|||||||
pub(crate) last_price_quote_per_base: std::option::Option<f64>,
|
pub(crate) last_price_quote_per_base: std::option::Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SQL row for local pair actionability diagnostics.
|
||||||
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
|
pub(crate) struct LocalPairActionabilityDiagnosticSummaryRow {
|
||||||
|
pub(crate) pair_actionability: std::string::String,
|
||||||
|
pub(crate) pair_count: i64,
|
||||||
|
pub(crate) decoded_event_count: i64,
|
||||||
|
pub(crate) decoded_trade_candidate_count: i64,
|
||||||
|
pub(crate) actionable_trade_candidate_count: i64,
|
||||||
|
pub(crate) failed_trade_candidate_count: i64,
|
||||||
|
pub(crate) trade_event_count: i64,
|
||||||
|
pub(crate) pair_candle_count: i64,
|
||||||
|
}
|
||||||
|
|
||||||
/// SQL row for local decoded-event diagnostics.
|
/// SQL row for local decoded-event diagnostics.
|
||||||
#[derive(Debug, Clone, sqlx::FromRow)]
|
#[derive(Debug, Clone, sqlx::FromRow)]
|
||||||
pub(crate) struct LocalDecodedEventDiagnosticSummaryRow {
|
pub(crate) struct LocalDecodedEventDiagnosticSummaryRow {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
// file: kb_lib/src/db/entities/program_instruction_discriminator_row.rs
|
// file: kb_lib/src/db/entities/program_instruction_discriminator_row.rs
|
||||||
|
|
||||||
//! Program instruction discriminator diagnostic row entity.
|
//! Program instruction discriminator diagnostic row entity.
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ pub use local_pipeline_diagnostics::query_local_missing_trade_event_diagnostic_l
|
|||||||
pub use local_pipeline_diagnostics::query_local_missing_trade_event_reason_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_missing_trade_event_reason_list_summaries;
|
||||||
pub use local_pipeline_diagnostics::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_non_actionable_pair_diagnostic_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_non_actionable_pair_diagnostic_list_summaries;
|
||||||
|
pub use local_pipeline_diagnostics::query_local_pair_actionability_diagnostic_list_summaries;
|
||||||
pub use local_pipeline_diagnostics::query_local_pair_diagnostic_list_summaries;
|
pub use local_pipeline_diagnostics::query_local_pair_diagnostic_list_summaries;
|
||||||
pub use local_pipeline_diagnostics::query_local_pair_without_candle_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_pair_without_candle_diagnostic_list_samples;
|
||||||
pub use local_pipeline_diagnostics::query_local_pair_without_trade_diagnostic_list_samples;
|
pub use local_pipeline_diagnostics::query_local_pair_without_trade_diagnostic_list_samples;
|
||||||
|
|||||||
@@ -188,6 +188,51 @@ SELECT
|
|||||||
) AS token_metadata_missing_count,
|
) AS token_metadata_missing_count,
|
||||||
(SELECT COUNT(*) FROM k_sol_pools) AS pool_count,
|
(SELECT COUNT(*) FROM k_sol_pools) AS pool_count,
|
||||||
(SELECT COUNT(*) FROM k_sol_pairs) AS pair_count,
|
(SELECT COUNT(*) FROM k_sol_pairs) AS pair_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM (
|
||||||
|
SELECT pair.id
|
||||||
|
FROM k_sol_pairs pair
|
||||||
|
LEFT JOIN k_sol_trade_events te ON te.pair_id = pair.id
|
||||||
|
GROUP BY pair.id
|
||||||
|
HAVING COUNT(DISTINCT te.id) = 0
|
||||||
|
)
|
||||||
|
) AS literal_pair_without_trade_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM (
|
||||||
|
SELECT pair.id
|
||||||
|
FROM k_sol_pairs pair
|
||||||
|
LEFT JOIN k_sol_pair_candles pc ON pc.pair_id = pair.id
|
||||||
|
GROUP BY pair.id
|
||||||
|
HAVING COUNT(DISTINCT pc.bucket_start_unix || ':' || pc.timeframe_seconds) = 0
|
||||||
|
)
|
||||||
|
) AS literal_pair_without_candle_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(DISTINCT pair_id)
|
||||||
|
FROM k_sol_trade_events
|
||||||
|
) AS trade_materialized_pair_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(DISTINCT pair_id)
|
||||||
|
FROM k_sol_pair_candles
|
||||||
|
) AS candle_materialized_pair_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM (
|
||||||
|
SELECT pair.id
|
||||||
|
FROM k_sol_pairs pair
|
||||||
|
JOIN k_sol_pools p ON p.id = pair.pool_id
|
||||||
|
JOIN k_sol_dex_decoded_events dde ON dde.pool_account = p.address
|
||||||
|
JOIN k_sol_chain_transactions ct ON ct.id = dde.transaction_id
|
||||||
|
WHERE json_extract(dde.payload_json, '$.tradeCandidate') = 1
|
||||||
|
AND ct.err_json IS NULL
|
||||||
|
GROUP BY pair.id
|
||||||
|
)
|
||||||
|
) AS actionable_pair_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(DISTINCT timeframe_seconds)
|
||||||
|
FROM k_sol_pair_candles
|
||||||
|
) AS candle_bucket_timeframe_count,
|
||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM (
|
FROM (
|
||||||
@@ -216,6 +261,24 @@ SELECT
|
|||||||
AND COUNT(DISTINCT dde.id) > 0
|
AND COUNT(DISTINCT dde.id) > 0
|
||||||
)
|
)
|
||||||
) AS non_actionable_pair_count,
|
) AS non_actionable_pair_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM (
|
||||||
|
SELECT pair.id
|
||||||
|
FROM k_sol_pairs pair
|
||||||
|
JOIN k_sol_pools p ON p.id = pair.pool_id
|
||||||
|
LEFT JOIN k_sol_dex_decoded_events dde ON dde.pool_account = p.address
|
||||||
|
LEFT JOIN k_sol_chain_transactions ct ON ct.id = dde.transaction_id
|
||||||
|
LEFT JOIN k_sol_trade_events te ON te.pair_id = pair.id
|
||||||
|
GROUP BY pair.id
|
||||||
|
HAVING COUNT(DISTINCT CASE
|
||||||
|
WHEN json_extract(dde.payload_json, '$.tradeCandidate') = 1
|
||||||
|
AND ct.id IS NOT NULL
|
||||||
|
AND ct.err_json IS NULL
|
||||||
|
THEN dde.id END) > 0
|
||||||
|
AND COUNT(DISTINCT te.id) = 0
|
||||||
|
)
|
||||||
|
) AS blocking_pair_without_trade_count,
|
||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM (
|
FROM (
|
||||||
@@ -234,6 +297,24 @@ SELECT
|
|||||||
AND COUNT(DISTINCT te.id) = 0
|
AND COUNT(DISTINCT te.id) = 0
|
||||||
)
|
)
|
||||||
) AS pair_without_trade_count,
|
) AS pair_without_trade_count,
|
||||||
|
(
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM (
|
||||||
|
SELECT pair.id
|
||||||
|
FROM k_sol_pairs pair
|
||||||
|
JOIN k_sol_pools p ON p.id = pair.pool_id
|
||||||
|
LEFT JOIN k_sol_dex_decoded_events dde ON dde.pool_account = p.address
|
||||||
|
LEFT JOIN k_sol_chain_transactions ct ON ct.id = dde.transaction_id
|
||||||
|
LEFT JOIN k_sol_pair_candles pc ON pc.pair_id = pair.id
|
||||||
|
GROUP BY pair.id
|
||||||
|
HAVING COUNT(DISTINCT CASE
|
||||||
|
WHEN json_extract(dde.payload_json, '$.candleCandidate') = 1
|
||||||
|
AND ct.id IS NOT NULL
|
||||||
|
AND ct.err_json IS NULL
|
||||||
|
THEN dde.id END) > 0
|
||||||
|
AND COUNT(DISTINCT pc.bucket_start_unix || ':' || pc.timeframe_seconds) = 0
|
||||||
|
)
|
||||||
|
) AS blocking_pair_without_candle_count,
|
||||||
(
|
(
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM (
|
FROM (
|
||||||
@@ -295,7 +376,15 @@ SELECT
|
|||||||
token_metadata_missing_count: row.token_metadata_missing_count,
|
token_metadata_missing_count: row.token_metadata_missing_count,
|
||||||
pool_count: row.pool_count,
|
pool_count: row.pool_count,
|
||||||
pair_count: row.pair_count,
|
pair_count: row.pair_count,
|
||||||
|
literal_pair_without_trade_count: row.literal_pair_without_trade_count,
|
||||||
|
literal_pair_without_candle_count: row.literal_pair_without_candle_count,
|
||||||
|
trade_materialized_pair_count: row.trade_materialized_pair_count,
|
||||||
|
candle_materialized_pair_count: row.candle_materialized_pair_count,
|
||||||
|
actionable_pair_count: row.actionable_pair_count,
|
||||||
|
candle_bucket_timeframe_count: row.candle_bucket_timeframe_count,
|
||||||
non_actionable_pair_count: row.non_actionable_pair_count,
|
non_actionable_pair_count: row.non_actionable_pair_count,
|
||||||
|
blocking_pair_without_trade_count: row.blocking_pair_without_trade_count,
|
||||||
|
blocking_pair_without_candle_count: row.blocking_pair_without_candle_count,
|
||||||
pair_without_trade_count: row.pair_without_trade_count,
|
pair_without_trade_count: row.pair_without_trade_count,
|
||||||
pair_without_candle_count: row.pair_without_candle_count,
|
pair_without_candle_count: row.pair_without_candle_count,
|
||||||
actionable_missing_trade_event_count: row.actionable_missing_trade_event_count,
|
actionable_missing_trade_event_count: row.actionable_missing_trade_event_count,
|
||||||
@@ -523,6 +612,112 @@ ORDER BY pair.id
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lists local pair materialization/actionability summaries.
|
||||||
|
pub async fn query_local_pair_actionability_diagnostic_list_summaries(
|
||||||
|
database: &crate::Database,
|
||||||
|
) -> Result<std::vec::Vec<crate::LocalPairActionabilityDiagnosticSummaryDto>, crate::Error> {
|
||||||
|
match database.connection() {
|
||||||
|
crate::DatabaseConnection::Sqlite(pool) => {
|
||||||
|
let rows_result = sqlx::query_as::<
|
||||||
|
sqlx::Sqlite,
|
||||||
|
crate::db::dtos::LocalPairActionabilityDiagnosticSummaryRow,
|
||||||
|
>(
|
||||||
|
r#"
|
||||||
|
WITH pair_state AS (
|
||||||
|
SELECT
|
||||||
|
pair.id AS pair_id,
|
||||||
|
COUNT(DISTINCT dde.id) AS decoded_event_count,
|
||||||
|
COUNT(DISTINCT CASE WHEN json_extract(dde.payload_json, '$.tradeCandidate') = 1 THEN dde.id END) AS decoded_trade_candidate_count,
|
||||||
|
COUNT(DISTINCT CASE
|
||||||
|
WHEN json_extract(dde.payload_json, '$.tradeCandidate') = 1
|
||||||
|
AND ct.id IS NOT NULL
|
||||||
|
AND ct.err_json IS NULL
|
||||||
|
THEN dde.id END) AS actionable_trade_candidate_count,
|
||||||
|
COUNT(DISTINCT CASE
|
||||||
|
WHEN json_extract(dde.payload_json, '$.tradeCandidate') = 1
|
||||||
|
AND ct.id IS NOT NULL
|
||||||
|
AND ct.err_json IS NOT NULL
|
||||||
|
THEN dde.id END) AS failed_trade_candidate_count,
|
||||||
|
COUNT(DISTINCT te.id) AS trade_event_count,
|
||||||
|
COUNT(DISTINCT pc.bucket_start_unix || ':' || pc.timeframe_seconds) AS pair_candle_count
|
||||||
|
FROM k_sol_pairs pair
|
||||||
|
JOIN k_sol_pools p ON p.id = pair.pool_id
|
||||||
|
LEFT JOIN k_sol_dex_decoded_events dde ON dde.pool_account = p.address
|
||||||
|
LEFT JOIN k_sol_chain_transactions ct ON ct.id = dde.transaction_id
|
||||||
|
LEFT JOIN k_sol_trade_events te ON te.pair_id = pair.id
|
||||||
|
LEFT JOIN k_sol_pair_candles pc ON pc.pair_id = pair.id
|
||||||
|
GROUP BY pair.id
|
||||||
|
), classified AS (
|
||||||
|
SELECT
|
||||||
|
CASE
|
||||||
|
WHEN trade_event_count > 0 THEN 'trade_materialized'
|
||||||
|
WHEN actionable_trade_candidate_count > 0 THEN 'actionable_without_materialized_trade'
|
||||||
|
WHEN failed_trade_candidate_count > 0 THEN 'failed_trade_candidate_only'
|
||||||
|
WHEN decoded_trade_candidate_count > 0 THEN 'non_actionable_trade_candidate_only'
|
||||||
|
WHEN decoded_event_count > 0 THEN 'decoded_without_trade_candidate'
|
||||||
|
ELSE 'catalog_only'
|
||||||
|
END AS pair_actionability,
|
||||||
|
pair_id,
|
||||||
|
decoded_event_count,
|
||||||
|
decoded_trade_candidate_count,
|
||||||
|
actionable_trade_candidate_count,
|
||||||
|
failed_trade_candidate_count,
|
||||||
|
trade_event_count,
|
||||||
|
pair_candle_count
|
||||||
|
FROM pair_state
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
pair_actionability AS pair_actionability,
|
||||||
|
COUNT(pair_id) AS pair_count,
|
||||||
|
SUM(decoded_event_count) AS decoded_event_count,
|
||||||
|
SUM(decoded_trade_candidate_count) AS decoded_trade_candidate_count,
|
||||||
|
SUM(actionable_trade_candidate_count) AS actionable_trade_candidate_count,
|
||||||
|
SUM(failed_trade_candidate_count) AS failed_trade_candidate_count,
|
||||||
|
SUM(trade_event_count) AS trade_event_count,
|
||||||
|
SUM(pair_candle_count) AS pair_candle_count
|
||||||
|
FROM classified
|
||||||
|
GROUP BY pair_actionability
|
||||||
|
ORDER BY
|
||||||
|
CASE pair_actionability
|
||||||
|
WHEN 'trade_materialized' THEN 1
|
||||||
|
WHEN 'actionable_without_materialized_trade' THEN 2
|
||||||
|
WHEN 'failed_trade_candidate_only' THEN 3
|
||||||
|
WHEN 'non_actionable_trade_candidate_only' THEN 4
|
||||||
|
WHEN 'decoded_without_trade_candidate' THEN 5
|
||||||
|
ELSE 6
|
||||||
|
END,
|
||||||
|
pair_actionability
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.fetch_all(pool)
|
||||||
|
.await;
|
||||||
|
let rows = match rows_result {
|
||||||
|
Ok(rows) => rows,
|
||||||
|
Err(error) => {
|
||||||
|
return Err(crate::Error::Db(format!(
|
||||||
|
"cannot list local pair actionability diagnostic summaries on sqlite: {}",
|
||||||
|
error
|
||||||
|
)));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut summaries = std::vec::Vec::new();
|
||||||
|
for row in rows {
|
||||||
|
summaries.push(crate::LocalPairActionabilityDiagnosticSummaryDto {
|
||||||
|
pair_actionability: row.pair_actionability,
|
||||||
|
pair_count: row.pair_count,
|
||||||
|
decoded_event_count: row.decoded_event_count,
|
||||||
|
decoded_trade_candidate_count: row.decoded_trade_candidate_count,
|
||||||
|
actionable_trade_candidate_count: row.actionable_trade_candidate_count,
|
||||||
|
failed_trade_candidate_count: row.failed_trade_candidate_count,
|
||||||
|
trade_event_count: row.trade_event_count,
|
||||||
|
pair_candle_count: row.pair_candle_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(summaries);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Lists local decoded-event diagnostic summaries.
|
/// Lists local decoded-event diagnostic summaries.
|
||||||
pub async fn query_local_decoded_event_diagnostic_list_summaries(
|
pub async fn query_local_decoded_event_diagnostic_list_summaries(
|
||||||
database: &crate::Database,
|
database: &crate::Database,
|
||||||
|
|||||||
@@ -848,19 +848,18 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn matrix_lookup_by_program_id_returns_expected_protocol() {
|
fn matrix_lookup_by_program_id_returns_expected_protocol() {
|
||||||
let entry = match crate::dex_support_matrix_entry_by_program_id(crate::METEORA_DLMM_PROGRAM_ID)
|
let entry =
|
||||||
{
|
match crate::dex_support_matrix_entry_by_program_id(crate::METEORA_DLMM_PROGRAM_ID) {
|
||||||
Some(entry) => entry,
|
Some(entry) => entry,
|
||||||
None => panic!("expected meteora_dlmm program id lookup"),
|
None => panic!("expected meteora_dlmm program id lookup"),
|
||||||
};
|
};
|
||||||
assert_eq!(entry.code, "meteora_dlmm");
|
assert_eq!(entry.code, "meteora_dlmm");
|
||||||
|
|
||||||
let raydium_entry = match crate::dex_support_matrix_entry_by_program_id(
|
let raydium_entry =
|
||||||
crate::RAYDIUM_AMM_V4_PROGRAM_ID,
|
match crate::dex_support_matrix_entry_by_program_id(crate::RAYDIUM_AMM_V4_PROGRAM_ID) {
|
||||||
) {
|
Some(entry) => entry,
|
||||||
Some(entry) => entry,
|
None => panic!("expected raydium AMM v4 program id lookup"),
|
||||||
None => panic!("expected raydium AMM v4 program id lookup"),
|
};
|
||||||
};
|
|
||||||
assert_eq!(raydium_entry.code, "raydium_amm_v4");
|
assert_eq!(raydium_entry.code, "raydium_amm_v4");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -357,6 +357,8 @@ pub use db::LocalMissingTradeEventReasonSummaryDto;
|
|||||||
pub use db::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
pub use db::LocalMultiTradeSignaturePairDiagnosticSampleDto;
|
||||||
/// Local pair diagnostics for pairs whose missing trade events are non-actionable.
|
/// Local pair diagnostics for pairs whose missing trade events are non-actionable.
|
||||||
pub use db::LocalNonActionablePairDiagnosticSummaryDto;
|
pub use db::LocalNonActionablePairDiagnosticSummaryDto;
|
||||||
|
/// Local pair diagnostics grouped by materialization/actionability class.
|
||||||
|
pub use db::LocalPairActionabilityDiagnosticSummaryDto;
|
||||||
/// Local pair diagnostics summary.
|
/// Local pair diagnostics summary.
|
||||||
pub use db::LocalPairDiagnosticSummaryDto;
|
pub use db::LocalPairDiagnosticSummaryDto;
|
||||||
/// Sample of a pair gap.
|
/// Sample of a pair gap.
|
||||||
@@ -571,6 +573,8 @@ pub use db::query_local_missing_trade_event_reason_list_summaries;
|
|||||||
pub use db::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
pub use db::query_local_multi_trade_signature_pair_diagnostic_list_samples;
|
||||||
/// Lists pair summaries for non-actionable missing trade events.
|
/// Lists pair summaries for non-actionable missing trade events.
|
||||||
pub use db::query_local_non_actionable_pair_diagnostic_list_summaries;
|
pub use db::query_local_non_actionable_pair_diagnostic_list_summaries;
|
||||||
|
/// Lists local pair materialization/actionability summaries.
|
||||||
|
pub use db::query_local_pair_actionability_diagnostic_list_summaries;
|
||||||
/// Lists local pair diagnostic summaries.
|
/// Lists local pair diagnostic summaries.
|
||||||
pub use db::query_local_pair_diagnostic_list_summaries;
|
pub use db::query_local_pair_diagnostic_list_summaries;
|
||||||
/// Lists samples of pairs without candles.
|
/// Lists samples of pairs without candles.
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ impl LocalPipelineDiagnosticsService {
|
|||||||
Ok(pair_summaries) => pair_summaries,
|
Ok(pair_summaries) => pair_summaries,
|
||||||
Err(error) => return Err(error),
|
Err(error) => return Err(error),
|
||||||
};
|
};
|
||||||
|
let pair_actionability_summaries_result =
|
||||||
|
crate::query_local_pair_actionability_diagnostic_list_summaries(self.database.as_ref())
|
||||||
|
.await;
|
||||||
|
let pair_actionability_summaries = match pair_actionability_summaries_result {
|
||||||
|
Ok(summaries) => summaries,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
let decoded_event_summaries_result =
|
let decoded_event_summaries_result =
|
||||||
crate::query_local_decoded_event_diagnostic_list_summaries(self.database.as_ref())
|
crate::query_local_decoded_event_diagnostic_list_summaries(self.database.as_ref())
|
||||||
.await;
|
.await;
|
||||||
@@ -160,10 +167,21 @@ impl LocalPipelineDiagnosticsService {
|
|||||||
token_metadata_missing_count: counters.token_metadata_missing_count,
|
token_metadata_missing_count: counters.token_metadata_missing_count,
|
||||||
pool_count: counters.pool_count,
|
pool_count: counters.pool_count,
|
||||||
pair_count: counters.pair_count,
|
pair_count: counters.pair_count,
|
||||||
|
pair_gap_counter_semantics: "blocking_actionable_pairs_only".to_string(),
|
||||||
|
literal_pair_without_trade_count: counters.literal_pair_without_trade_count,
|
||||||
|
literal_pair_without_candle_count: counters.literal_pair_without_candle_count,
|
||||||
|
trade_materialized_pair_count: counters.trade_materialized_pair_count,
|
||||||
|
candle_materialized_pair_count: counters.candle_materialized_pair_count,
|
||||||
|
actionable_pair_count: counters.actionable_pair_count,
|
||||||
|
candle_bucket_timeframe_count: counters.candle_bucket_timeframe_count,
|
||||||
|
candles_are_bucketed: counters.candle_bucket_timeframe_count > 0,
|
||||||
|
blocking_pair_without_trade_count: counters.blocking_pair_without_trade_count,
|
||||||
|
blocking_pair_without_candle_count: counters.blocking_pair_without_candle_count,
|
||||||
pair_without_trade_count: counters.pair_without_trade_count,
|
pair_without_trade_count: counters.pair_without_trade_count,
|
||||||
pair_without_candle_count: counters.pair_without_candle_count,
|
pair_without_candle_count: counters.pair_without_candle_count,
|
||||||
dex_summaries,
|
dex_summaries,
|
||||||
pair_summaries,
|
pair_summaries,
|
||||||
|
pair_actionability_summaries,
|
||||||
decoded_event_summaries,
|
decoded_event_summaries,
|
||||||
event_classification_summaries,
|
event_classification_summaries,
|
||||||
missing_trade_event_reason_summaries,
|
missing_trade_event_reason_summaries,
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ pub struct LocalPipelineValidationConfig {
|
|||||||
pub require_candles_per_dex: bool,
|
pub require_candles_per_dex: bool,
|
||||||
/// Whether non-actionable classification groups must have no linked trade events.
|
/// Whether non-actionable classification groups must have no linked trade events.
|
||||||
pub require_no_non_actionable_trade_events_materialized: bool,
|
pub require_no_non_actionable_trade_events_materialized: bool,
|
||||||
|
/// Whether the DEX support matrix must satisfy internal semantic invariants.
|
||||||
|
pub require_dex_support_matrix_semantics: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LocalPipelineValidationConfig {
|
impl Default for LocalPipelineValidationConfig {
|
||||||
@@ -59,6 +61,7 @@ impl Default for LocalPipelineValidationConfig {
|
|||||||
require_trade_events_per_dex: true,
|
require_trade_events_per_dex: true,
|
||||||
require_candles_per_dex: true,
|
require_candles_per_dex: true,
|
||||||
require_no_non_actionable_trade_events_materialized: true,
|
require_no_non_actionable_trade_events_materialized: true,
|
||||||
|
require_dex_support_matrix_semantics: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +89,7 @@ impl LocalPipelineValidationConfig {
|
|||||||
require_trade_events_per_dex: true,
|
require_trade_events_per_dex: true,
|
||||||
require_candles_per_dex: true,
|
require_candles_per_dex: true,
|
||||||
require_no_non_actionable_trade_events_materialized: true,
|
require_no_non_actionable_trade_events_materialized: true,
|
||||||
|
require_dex_support_matrix_semantics: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +122,7 @@ impl LocalPipelineValidationConfig {
|
|||||||
require_trade_events_per_dex: false,
|
require_trade_events_per_dex: false,
|
||||||
require_candles_per_dex: false,
|
require_candles_per_dex: false,
|
||||||
require_no_non_actionable_trade_events_materialized: true,
|
require_no_non_actionable_trade_events_materialized: true,
|
||||||
|
require_dex_support_matrix_semantics: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +154,7 @@ impl LocalPipelineValidationConfig {
|
|||||||
require_trade_events_per_dex: false,
|
require_trade_events_per_dex: false,
|
||||||
require_candles_per_dex: false,
|
require_candles_per_dex: false,
|
||||||
require_no_non_actionable_trade_events_materialized: true,
|
require_no_non_actionable_trade_events_materialized: true,
|
||||||
|
require_dex_support_matrix_semantics: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +180,17 @@ impl LocalPipelineValidationConfig {
|
|||||||
config.require_no_non_actionable_trade_events_materialized = true;
|
config.require_no_non_actionable_trade_events_materialized = true;
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds the `0.7.32` validation report semantics config.
|
||||||
|
///
|
||||||
|
/// This profile keeps the `0.7.31` trade-actionability policy and validates
|
||||||
|
/// the support matrix semantics used to interpret partial/planned DEXes.
|
||||||
|
pub fn v0_7_32_validation_report_semantics() -> Self {
|
||||||
|
let mut config = Self::v0_7_31_trade_event_actionability_policy();
|
||||||
|
config.profile_code = "0.7.32_validation_report_semantics".to_string();
|
||||||
|
config.require_dex_support_matrix_semantics = true;
|
||||||
|
return config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A single local pipeline validation issue.
|
/// A single local pipeline validation issue.
|
||||||
@@ -318,6 +335,14 @@ impl LocalPipelineValidationService {
|
|||||||
crate::LocalPipelineValidationConfig::v0_7_31_trade_event_actionability_policy();
|
crate::LocalPipelineValidationConfig::v0_7_31_trade_event_actionability_policy();
|
||||||
return self.validate_current_database(&config).await;
|
return self.validate_current_database(&config).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Diagnoses the current database with the `0.7.32` validation report semantics profile.
|
||||||
|
pub async fn validate_v0_7_32_current_database(
|
||||||
|
&self,
|
||||||
|
) -> Result<crate::LocalPipelineValidationRunDto, crate::Error> {
|
||||||
|
let config = crate::LocalPipelineValidationConfig::v0_7_32_validation_report_semantics();
|
||||||
|
return self.validate_current_database(&config).await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates a diagnostics summary without performing database access.
|
/// Validates a diagnostics summary without performing database access.
|
||||||
@@ -429,6 +454,9 @@ pub fn validate_local_pipeline_diagnostics_summary(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.require_dex_support_matrix_semantics {
|
||||||
|
validate_dex_support_matrix_semantics(&mut issues);
|
||||||
|
}
|
||||||
if config.require_all_expected_dexes {
|
if config.require_all_expected_dexes {
|
||||||
for expected_dex_code in &expected_dex_codes {
|
for expected_dex_code in &expected_dex_codes {
|
||||||
if !observed_dex_codes.contains(expected_dex_code) {
|
if !observed_dex_codes.contains(expected_dex_code) {
|
||||||
@@ -504,6 +532,65 @@ pub fn validate_local_pipeline_diagnostics_summary(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_dex_support_matrix_semantics(
|
||||||
|
issues: &mut std::vec::Vec<crate::LocalPipelineValidationIssueDto>,
|
||||||
|
) {
|
||||||
|
let entries = crate::dex_support_matrix_entry_dtos();
|
||||||
|
for entry in entries {
|
||||||
|
let entry_code = entry.code.clone();
|
||||||
|
if entry.status == "supported" {
|
||||||
|
let supported_materialization_ok = entry.decoded
|
||||||
|
&& entry.materialized
|
||||||
|
&& entry.trade_candidate
|
||||||
|
&& entry.candle_candidate
|
||||||
|
&& entry.pair_candidate
|
||||||
|
&& entry.pool_candidate
|
||||||
|
&& entry.catalog_enabled;
|
||||||
|
if !supported_materialization_ok {
|
||||||
|
issues.push(crate::LocalPipelineValidationIssueDto {
|
||||||
|
code: "supported_dex_matrix_entry_not_fully_materialized".to_string(),
|
||||||
|
message: format!(
|
||||||
|
"supported DEX '{}' must expose decoded/materialized trade, candle, pair and pool capabilities",
|
||||||
|
entry_code
|
||||||
|
),
|
||||||
|
subject: Some(entry_code.clone()),
|
||||||
|
blocking: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if entry.status == "partial" {
|
||||||
|
let has_skip_reason = match &entry.skip_reason {
|
||||||
|
Some(skip_reason) => !skip_reason.trim().is_empty(),
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
if !has_skip_reason {
|
||||||
|
issues.push(crate::LocalPipelineValidationIssueDto {
|
||||||
|
code: "partial_dex_matrix_entry_without_skip_reason".to_string(),
|
||||||
|
message: format!(
|
||||||
|
"partial DEX '{}' must expose an explicit skip reason",
|
||||||
|
entry_code
|
||||||
|
),
|
||||||
|
subject: Some(entry_code.clone()),
|
||||||
|
blocking: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry.status == "planned" || entry.status == "to_verify" || entry.status == "unknown")
|
||||||
|
&& entry.catalog_enabled
|
||||||
|
{
|
||||||
|
issues.push(crate::LocalPipelineValidationIssueDto {
|
||||||
|
code: "inactive_dex_matrix_entry_catalog_enabled".to_string(),
|
||||||
|
message: format!(
|
||||||
|
"inactive DEX '{}' must not be enabled in the runtime catalog",
|
||||||
|
entry_code
|
||||||
|
),
|
||||||
|
subject: Some(entry_code.clone()),
|
||||||
|
blocking: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_local_pipeline_validation_run(
|
fn build_local_pipeline_validation_run(
|
||||||
summary: crate::LocalPipelineDiagnosticSummaryDto,
|
summary: crate::LocalPipelineDiagnosticSummaryDto,
|
||||||
config: &crate::LocalPipelineValidationConfig,
|
config: &crate::LocalPipelineValidationConfig,
|
||||||
@@ -563,6 +650,16 @@ mod tests {
|
|||||||
token_metadata_missing_count: 0,
|
token_metadata_missing_count: 0,
|
||||||
pool_count: 27,
|
pool_count: 27,
|
||||||
pair_count: 27,
|
pair_count: 27,
|
||||||
|
pair_gap_counter_semantics: "blocking_actionable_pairs_only".to_string(),
|
||||||
|
literal_pair_without_trade_count: 4,
|
||||||
|
literal_pair_without_candle_count: 3,
|
||||||
|
trade_materialized_pair_count: 23,
|
||||||
|
candle_materialized_pair_count: 24,
|
||||||
|
actionable_pair_count: 23,
|
||||||
|
candle_bucket_timeframe_count: 4,
|
||||||
|
candles_are_bucketed: true,
|
||||||
|
blocking_pair_without_trade_count: 0,
|
||||||
|
blocking_pair_without_candle_count: 0,
|
||||||
non_actionable_pair_count: 0,
|
non_actionable_pair_count: 0,
|
||||||
pair_without_trade_count: 0,
|
pair_without_trade_count: 0,
|
||||||
pair_without_candle_count: 0,
|
pair_without_candle_count: 0,
|
||||||
@@ -609,6 +706,28 @@ mod tests {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
pair_summaries: vec![],
|
pair_summaries: vec![],
|
||||||
|
pair_actionability_summaries: vec![
|
||||||
|
crate::LocalPairActionabilityDiagnosticSummaryDto {
|
||||||
|
pair_actionability: "trade_materialized".to_string(),
|
||||||
|
pair_count: 23,
|
||||||
|
decoded_event_count: 210,
|
||||||
|
decoded_trade_candidate_count: 210,
|
||||||
|
actionable_trade_candidate_count: 210,
|
||||||
|
failed_trade_candidate_count: 0,
|
||||||
|
trade_event_count: 210,
|
||||||
|
pair_candle_count: 230,
|
||||||
|
},
|
||||||
|
crate::LocalPairActionabilityDiagnosticSummaryDto {
|
||||||
|
pair_actionability: "catalog_only".to_string(),
|
||||||
|
pair_count: 4,
|
||||||
|
decoded_event_count: 0,
|
||||||
|
decoded_trade_candidate_count: 0,
|
||||||
|
actionable_trade_candidate_count: 0,
|
||||||
|
failed_trade_candidate_count: 0,
|
||||||
|
trade_event_count: 0,
|
||||||
|
pair_candle_count: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
decoded_event_summaries: vec![],
|
decoded_event_summaries: vec![],
|
||||||
event_classification_summaries: vec![],
|
event_classification_summaries: vec![],
|
||||||
missing_trade_event_reason_summaries: vec![],
|
missing_trade_event_reason_summaries: vec![],
|
||||||
@@ -746,6 +865,24 @@ mod tests {
|
|||||||
assert_eq!(report.validation_profile_code, "0.7.31_trade_event_actionability_policy");
|
assert_eq!(report.validation_profile_code, "0.7.31_trade_event_actionability_policy");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validation_accepts_0_7_32_validation_report_semantics_summary() {
|
||||||
|
let mut summary = make_0_7_28_summary_with_meteora();
|
||||||
|
summary.literal_pair_without_trade_count = 12;
|
||||||
|
summary.literal_pair_without_candle_count = 12;
|
||||||
|
summary.blocking_pair_without_trade_count = 0;
|
||||||
|
summary.blocking_pair_without_candle_count = 0;
|
||||||
|
summary.pair_without_trade_count = 0;
|
||||||
|
summary.pair_without_candle_count = 0;
|
||||||
|
summary.pair_gap_counter_semantics = "blocking_actionable_pairs_only".to_string();
|
||||||
|
let config = crate::LocalPipelineValidationConfig::v0_7_32_validation_report_semantics();
|
||||||
|
let report = crate::validate_local_pipeline_diagnostics_summary(&summary, &config);
|
||||||
|
assert!(report.validation_passed);
|
||||||
|
assert_eq!(report.validation_profile_code, "0.7.32_validation_report_semantics");
|
||||||
|
assert_eq!(summary.literal_pair_without_trade_count, 12);
|
||||||
|
assert_eq!(summary.blocking_pair_without_trade_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validation_rejects_0_7_31_failed_transaction_trade_events() {
|
fn validation_rejects_0_7_31_failed_transaction_trade_events() {
|
||||||
let mut summary = make_0_7_28_summary_with_meteora();
|
let mut summary = make_0_7_28_summary_with_meteora();
|
||||||
@@ -790,6 +927,42 @@ mod tests {
|
|||||||
assert!(found_pump_swap);
|
assert!(found_pump_swap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn partial_dex_matrix_entries_have_skip_reasons() {
|
||||||
|
for entry in crate::dex_support_matrix_entry_dtos() {
|
||||||
|
if entry.status == "partial" {
|
||||||
|
let has_skip_reason = match entry.skip_reason {
|
||||||
|
Some(skip_reason) => !skip_reason.trim().is_empty(),
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
assert!(has_skip_reason, "{}", entry.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn supported_dex_matrix_entries_have_materialization_flags() {
|
||||||
|
for entry in crate::dex_support_matrix_entry_dtos() {
|
||||||
|
if entry.status == "supported" {
|
||||||
|
assert!(entry.decoded, "{}", entry.code);
|
||||||
|
assert!(entry.materialized, "{}", entry.code);
|
||||||
|
assert!(entry.trade_candidate, "{}", entry.code);
|
||||||
|
assert!(entry.candle_candidate, "{}", entry.code);
|
||||||
|
assert!(entry.pair_candidate, "{}", entry.code);
|
||||||
|
assert!(entry.pool_candidate, "{}", entry.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn planned_dex_matrix_entries_are_not_catalog_enabled() {
|
||||||
|
for entry in crate::dex_support_matrix_entry_dtos() {
|
||||||
|
if entry.status == "planned" || entry.status == "to_verify" {
|
||||||
|
assert!(!entry.catalog_enabled, "{}", entry.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn validation_rejects_missing_expected_dex() {
|
fn validation_rejects_missing_expected_dex() {
|
||||||
let mut summary = make_clean_summary();
|
let mut summary = make_clean_summary();
|
||||||
|
|||||||
Reference in New Issue
Block a user