0.7.56
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_56_METEORA_DBC.md -->
|
||||
|
||||
# Prompt de reprise — khadhroony-bobobot 0.7.56 — meteora_dbc
|
||||
|
||||
Tu reprends le workspace Rust/Tauri `khadhroony-bobobot` après clôture technique de `0.7.55 pump_fees`.
|
||||
@@ -210,7 +212,7 @@ Fournir un delta zip contenant uniquement les fichiers modifiés/ajoutés.
|
||||
Nom recommandé :
|
||||
|
||||
```text
|
||||
khadhroony-bobobot-v0.7.56-meteora_dbc-delta-N-files.zip
|
||||
khadhroony-bobobot-v0.7.56-meteora_dbc-delta-pre.xxx.zip
|
||||
```
|
||||
|
||||
Inclure dans chaque livraison : résumé des changements, liste exacte des fichiers modifiés, commandes `cargo fmt`, `cargo test -p kb_lib`, `cargo clippy -p kb_lib --all-targets -- -D warnings`, replay recommandé, SQL à exécuter et résultats attendus.
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
<!-- file: docs/prompts/PROMPT_0_7_57_METEORA_DLMM_FULL_DECODE_MATERIALIZATION.md -->
|
||||
|
||||
# Prompt de reprise — khadhroony-bobobot `0.7.57` — `meteora_dlmm` full decode / full materialization
|
||||
|
||||
Tu reprends le workspace Rust/Tauri `khadhroony-bobobot` après clôture de `0.7.56 meteora_dbc`.
|
||||
|
||||
## 1. Archive et fichiers à fournir
|
||||
|
||||
Utiliser l'archive la plus récente après application des docs `0.7.56 final`.
|
||||
|
||||
Fichiers à lire en priorité :
|
||||
|
||||
- `README.md` ;
|
||||
- `ROADMAP.md` ;
|
||||
- `CHANGELOG.md` ;
|
||||
- `docs/DEX_DECODER_MATRIX.md` ;
|
||||
- `docs/DEX_EVENT_COVERAGE_MATRIX.md` ;
|
||||
- `docs/reports/METEORA_DBC_EVENT_COVERAGE_REPORT.md` ;
|
||||
- `docs/reports/FEE_EVENT_AMOUNTS_MODEL_NOTE_0_7_56.md` ;
|
||||
- `docs/VALIDATION_STATUS_0_7_56_FINAL.md` ;
|
||||
- `validation_sql/SQL_VALIDATION_METEORA_DBC_0_7_56.sql` ;
|
||||
- `validation_sql/SQL_VALIDATION_METEORA_DLMM_0_7_57.sql` ;
|
||||
- `idls/**`, en particulier `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json` ;
|
||||
- `kb_lib/src/dex/meteora_dlmm.rs` ;
|
||||
- `kb_lib/src/non_trade_event_materialization.rs` ;
|
||||
- `kb_lib/src/db/queries/fee_event_amount.rs`.
|
||||
|
||||
Ne pas supposer que l'ancien support `0.7.45 meteora_dlmm` est suffisant : il était partiel. `0.7.57` doit viser la parité IDL/corpus complète.
|
||||
|
||||
## 2. État validé avant cette version
|
||||
|
||||
`0.7.56 meteora_dbc` est clos.
|
||||
|
||||
Build final :
|
||||
|
||||
```text
|
||||
cargo test -p kb_lib -> 446 passed / 0 failed
|
||||
cargo clippy -p kb_lib --all-targets -- -D warnings -> OK
|
||||
```
|
||||
|
||||
Replay final DBC :
|
||||
|
||||
```text
|
||||
480 replayed
|
||||
0 decode skipped
|
||||
480 ledger upserts
|
||||
454 unsafe ledger rows
|
||||
264 trades
|
||||
1 liquidity
|
||||
122 lifecycle
|
||||
1056 candle upserts
|
||||
instructionObservations = 7167
|
||||
catalog = 86 tokens / 60 pools / 60 pairs
|
||||
```
|
||||
|
||||
Socle fee final :
|
||||
|
||||
```text
|
||||
k_sol_fee_events meteora_dbc = 89 parents
|
||||
k_sol_fee_event_amounts meteora_dbc = 96 legs
|
||||
parent scalar without leg = empty
|
||||
orphan fee amount legs = empty
|
||||
```
|
||||
|
||||
Règles fee à préserver :
|
||||
|
||||
- parent fee scalaire -> leg `k_sol_fee_event_amounts` automatique ;
|
||||
- fee multi-leg/multi-mint -> parent sans agrégation artificielle, legs explicites ;
|
||||
- pas de montant depuis `maxAmount`, `u64::MAX`, bornes ou limites de claim ;
|
||||
- recovery CPI SPL générique uniquement si policy/allowlist explicite ;
|
||||
- aucun futur decoder ne doit hériter de `allowlisted_inner_spl_transfer` par défaut.
|
||||
|
||||
## 3. Objectif de `0.7.57 meteora_dlmm`
|
||||
|
||||
Program id cible :
|
||||
|
||||
```text
|
||||
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo
|
||||
```
|
||||
|
||||
IDL locale prioritaire :
|
||||
|
||||
```text
|
||||
idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json
|
||||
```
|
||||
|
||||
Nom IDL : `lb_clmm`.
|
||||
|
||||
Surface IDL :
|
||||
|
||||
```text
|
||||
76 instructions
|
||||
30 events Anchor
|
||||
12 accounts
|
||||
```
|
||||
|
||||
Objectif : **full decode + full materialization**.
|
||||
|
||||
Règle forte :
|
||||
|
||||
> Tout ce qui peut être décodé doit être décodé. Tout ce qui peut être matérialisé de façon fiable doit être matérialisé. Ce qui ne peut pas être matérialisé doit rester decoded-only/audit-only avec `skip*Reason` explicite. les instructions/events/anchors/discriminator non observés aprés backfill sur une base de donnée vierge devront avoir des tests syntetiques.
|
||||
|
||||
## 4. Méthode obligatoire
|
||||
|
||||
Créer une nouvelle DB dédiée à `0.7.57 meteora_dlmm`.
|
||||
|
||||
Après chaque backfill ou patch decoder :
|
||||
|
||||
```text
|
||||
skipDexDecode=no
|
||||
forceDexDecode=yes
|
||||
deferInstructionObservations=yes
|
||||
```
|
||||
|
||||
Puis : refresh catalog, replay local, SQL validation, note des compteurs.
|
||||
|
||||
Ne pas rouvrir `meteora_dbc`, Pump ou Raydium sauf bug prouvé par SQL.
|
||||
|
||||
## 5. Sources à comparer
|
||||
|
||||
Comparer au minimum :
|
||||
|
||||
- IDL locale `idls/meteora_dlmm.LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo.json` ;
|
||||
- Carbon Meteora DLMM decoder ;
|
||||
- Pinax/Substreams Solana IDLs ;
|
||||
- Solana Streamer / sol-parser-sdk si DLMM y apparaît ;
|
||||
- code local historique `kb_lib/src/dex/meteora_dlmm.rs` ;
|
||||
- coverage existante `k_sol_dex_event_coverage_entries` ;
|
||||
- corpus SQLite neuf ;
|
||||
- anciens rapports `0.7.45` et matrices pour comprendre ce qui était déjà validé.
|
||||
|
||||
## 6. Checklist d'instructions IDL à inventorier
|
||||
|
||||
| Instruction | Discriminator hex |
|
||||
|---|---|
|
||||
| `add_liquidity` | `b59d59438fb63448` |
|
||||
| `add_liquidity2` | `e4a24e1c46db7473` |
|
||||
| `add_liquidity_by_strategy` | `0703967f94283dc8` |
|
||||
| `add_liquidity_by_strategy2` | `03dd95da6f8d76d5` |
|
||||
| `add_liquidity_by_strategy_one_side` | `2905eeaf64e106cd` |
|
||||
| `add_liquidity_by_weight` | `1c8cee63e7a21595` |
|
||||
| `add_liquidity_by_weight2` | `d13b3f5b6fc899e4` |
|
||||
| `add_liquidity_one_side` | `5e9b6797465fdca5` |
|
||||
| `add_liquidity_one_side_precise` | `a1c26754ab47fa9a` |
|
||||
| `add_liquidity_one_side_precise2` | `2133a3c975627de7` |
|
||||
| `cancel_limit_order` | `849c841f4328e861` |
|
||||
| `claim_fee` | `a9204f8988e84689` |
|
||||
| `claim_fee2` | `70bf65ab1c907fbb` |
|
||||
| `claim_reward` | `955fb5f25e5a9ea2` |
|
||||
| `claim_reward2` | `be037f77b2579db7` |
|
||||
| `close_bin_array` | `44ae5850b5cc13e0` |
|
||||
| `close_claim_fee_operator_account` | `b8d5581fb3658224` |
|
||||
| `close_limit_order_if_empty` | `397c249b7ef95dab` |
|
||||
| `close_operator_account` | `ab09d54a7817031d` |
|
||||
| `close_position` | `7b86510031446262` |
|
||||
| `close_position2` | `ae5a2373ba2893e2` |
|
||||
| `close_position_if_empty` | `3b7cd4765b986e9d` |
|
||||
| `close_preset_parameter` | `04949164861ab53d` |
|
||||
| `close_preset_parameter2` | `27195f6b7411731c` |
|
||||
| `close_token_badge` | `6c92566eb3fe0a68` |
|
||||
| `create_operator_account` | `dd40f695f099e5a3` |
|
||||
| `decrease_position_length` | `c2db882019606925` |
|
||||
| `for_idl_type_generation_do_not_call` | `b46945505f32496c` |
|
||||
| `fund_reward` | `bc32f9a55d97263f` |
|
||||
| `go_to_a_bin` | `9248aee028fd54ae` |
|
||||
| `increase_oracle_length` | `be3d7d57674f9ead` |
|
||||
| `increase_position_length` | `505375d3420d2195` |
|
||||
| `increase_position_length2` | `ffd2cc477389e171` |
|
||||
| `initialize_bin_array` | `235613b94ed44bd3` |
|
||||
| `initialize_bin_array_bitmap_extension` | `2f9de2b40cf02147` |
|
||||
| `initialize_customizable_permissionless_lb_pair` | `2e2729876fb7c840` |
|
||||
| `initialize_customizable_permissionless_lb_pair2` | `f349817e3313f16b` |
|
||||
| `initialize_lb_pair` | `2d9aedd2dd0fa65c` |
|
||||
| `initialize_lb_pair2` | `493b2478ed536cc6` |
|
||||
| `initialize_permission_lb_pair` | `6c66d555fb033515` |
|
||||
| `initialize_position` | `dbc0ea47bebf6650` |
|
||||
| `initialize_position2` | `8f13f291d50f6873` |
|
||||
| `initialize_position_by_operator` | `fbbdbef475fe2394` |
|
||||
| `initialize_position_pda` | `2e527d92558de499` |
|
||||
| `initialize_preset_parameter` | `42bc47d3626d0eba` |
|
||||
| `initialize_reward` | `5f87c0c4f281e644` |
|
||||
| `initialize_token_badge` | `fd4dcd5f1be059df` |
|
||||
| `place_limit_order` | `6cb021ba92e501c5` |
|
||||
| `rebalance_liquidity` | `5c04b0c177b95309` |
|
||||
| `remove_all_liquidity` | `0a333d2370691855` |
|
||||
| `remove_liquidity` | `5055d14818ceb16c` |
|
||||
| `remove_liquidity2` | `e6d7527ff165e392` |
|
||||
| `remove_liquidity_by_range` | `1a526698f04a691a` |
|
||||
| `remove_liquidity_by_range2` | `cc02c391359191cd` |
|
||||
| `set_activation_point` | `5bf90fa51a81fe7d` |
|
||||
| `set_pair_status` | `43f8e7899a95d9ae` |
|
||||
| `set_pair_status_permissionless` | `4e3b98d346b72ed0` |
|
||||
| `set_permissionless_operation_bits` | `543acb8ba351beba` |
|
||||
| `set_pre_activation_duration` | `a53dc9f4829f1664` |
|
||||
| `set_pre_activation_swap_address` | `398b2f7bd850df0a` |
|
||||
| `swap` | `f8c69e91e17587c8` |
|
||||
| `swap2` | `414b3f4ceb5b5b88` |
|
||||
| `swap_exact_out` | `fa49652126cf4bb8` |
|
||||
| `swap_exact_out2` | `2bd7f784893cf351` |
|
||||
| `swap_with_price_impact` | `38ade6d0ade49ccd` |
|
||||
| `swap_with_price_impact2` | `4a62c0d6b1334b33` |
|
||||
| `update_base_fee_parameters` | `4ba8dfa110c3032f` |
|
||||
| `update_dynamic_fee_parameters` | `5ca12ef6ffbd1616` |
|
||||
| `update_fees_and_reward2` | `208eb89a6741b858` |
|
||||
| `update_fees_and_rewards` | `9ae6fa0decd14bdf` |
|
||||
| `update_position_operator` | `cab8678fb4bf74d9` |
|
||||
| `update_reward_duration` | `8aaec4a9d5ebfe6b` |
|
||||
| `update_reward_funder` | `d31c3020d7a02317` |
|
||||
| `withdraw_ineligible_reward` | `94ce2ac3f7316708` |
|
||||
| `withdraw_protocol_fee` | `9ec99ebd215da267` |
|
||||
| `zap_protocol_fee` | `d59bbb2238b65bf0` |
|
||||
|
||||
## 7. Checklist d'events Anchor IDL à inventorier
|
||||
|
||||
| Event | Discriminator hex |
|
||||
|---|---|
|
||||
| `AddLiquidity` | `1f5e7d5ae3343dba` |
|
||||
| `CancelLimitOrderEvt` | `83eac285090ebdd1` |
|
||||
| `ClaimFee` | `4b7a9a308c4a7ba3` |
|
||||
| `ClaimFee2` | `e8abf2613a4d232d` |
|
||||
| `ClaimReward` | `947486cc16ab555f` |
|
||||
| `ClaimReward2` | `1b8ff421502b6e92` |
|
||||
| `CloseLimitOrderEvt` | `8e87084c5c3f7653` |
|
||||
| `CompositionFee` | `80977b6a1166718e` |
|
||||
| `DecreasePositionLength` | `3476eb55aca90f80` |
|
||||
| `DynamicFeeParameterUpdate` | `5858b287c2925bf3` |
|
||||
| `FeeParameterUpdate` | `304cf17590d7f22c` |
|
||||
| `FundReward` | `f6e43a8291aa4fcc` |
|
||||
| `GoToABin` | `3b8a4c448a83b043` |
|
||||
| `IncreaseObservation` | `63f91179a69ccfd7` |
|
||||
| `IncreasePositionLength` | `9def2acc1e38df2e` |
|
||||
| `InitializeReward` | `d399583e953cb146` |
|
||||
| `LbPairCreate` | `b94afc7d1bd7bc6f` |
|
||||
| `PlaceLimitOrderEvt` | `2b4f1ba9f41ce13f` |
|
||||
| `PositionClose` | `ffc4106b1cca3580` |
|
||||
| `PositionCreate` | `908efc549d352579` |
|
||||
| `Rebalancing` | `006d75b33d5bc7c8` |
|
||||
| `RemoveLiquidity` | `74f461e8671f983a` |
|
||||
| `SetPositionPermissionlessOperationBitsEvt` | `c3e593f51d7d30a8` |
|
||||
| `Swap` | `516ce3becdd00ac4` |
|
||||
| `Swap2Evt` | `2e7452d7941b544d` |
|
||||
| `UpdatePositionLockReleasePoint` | `85d642e0400c07bf` |
|
||||
| `UpdatePositionOperator` | `277330ccf62f4239` |
|
||||
| `UpdateRewardDuration` | `dff5e099311da3ac` |
|
||||
| `UpdateRewardFunder` | `e0b2ae4afca555b4` |
|
||||
| `WithdrawIneligibleReward` | `e7bd419566d79af4` |
|
||||
|
||||
## 8. Matérialisation attendue
|
||||
|
||||
### Swaps
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
swap
|
||||
swap2
|
||||
swap_exact_out
|
||||
swap_exact_out2
|
||||
swap_with_price_impact
|
||||
swap_with_price_impact2
|
||||
Swap
|
||||
Swap2Evt
|
||||
```
|
||||
|
||||
Décision :
|
||||
|
||||
- `k_sol_trade_events` + candles uniquement si montants exécutés, sens, pool, token X/Y et mints sont fiables ;
|
||||
- les events Anchor swap ne doivent pas double-compter une instruction swap déjà matérialisée ;
|
||||
- exact-out et price-impact ne doivent pas utiliser des bornes comme montants exécutés ;
|
||||
- si le contexte n'est pas fiable : `skipTradeReason` + `skipCandleReason`.
|
||||
|
||||
### Liquidity / bins / positions
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
add_liquidity*
|
||||
remove_liquidity*
|
||||
remove_all_liquidity
|
||||
rebalance_liquidity
|
||||
initialize_position*
|
||||
close_position*
|
||||
position create/close/update events
|
||||
initialize_bin_array*
|
||||
close_bin_array
|
||||
```
|
||||
|
||||
Décision :
|
||||
|
||||
- `k_sol_liquidity_events` quand les montants token X/Y, pool, position et acteur sont fiables ;
|
||||
- lifecycle pour création/fermeture position/bin/pair ;
|
||||
- skip reason explicite pour position/bin sans montants exploitables.
|
||||
|
||||
### Pools / catalog
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
initialize_lb_pair
|
||||
initialize_lb_pair2
|
||||
initialize_permission_lb_pair
|
||||
initialize_customizable_permissionless_lb_pair
|
||||
initialize_customizable_permissionless_lb_pair2
|
||||
LbPairCreate
|
||||
```
|
||||
|
||||
Décision : lifecycle/catalog/pool/pair si mints X/Y, pool, config/preset et comptes vault sont fiables.
|
||||
|
||||
### Fees
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
claim_fee
|
||||
claim_fee2
|
||||
withdraw_protocol_fee
|
||||
zap_protocol_fee
|
||||
ClaimFee
|
||||
ClaimFee2
|
||||
CompositionFee
|
||||
```
|
||||
|
||||
Décision :
|
||||
|
||||
- `k_sol_fee_events` + `k_sol_fee_event_amounts` obligatoires si montant/mint fiable ;
|
||||
- utiliser parent scalaire + leg automatique pour mono-fee ;
|
||||
- utiliser multi-leg sans agrégation parent si plusieurs mints/composants ;
|
||||
- ne pas confondre composition fee inclus dans swap/liquidity avec claim fee matérialisable ;
|
||||
- déclarer explicitement toute policy de recovery ; ne pas ajouter DLMM à l'allowlist générique sans preuve et tests.
|
||||
|
||||
### Rewards
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
initialize_reward
|
||||
fund_reward
|
||||
claim_reward
|
||||
claim_reward2
|
||||
withdraw_ineligible_reward
|
||||
ClaimReward
|
||||
ClaimReward2
|
||||
FundReward
|
||||
InitializeReward
|
||||
WithdrawIneligibleReward
|
||||
```
|
||||
|
||||
Décision : `k_sol_reward_events` si montant/mint/reward index fiables ; decoded-only sinon.
|
||||
|
||||
### Admin/config/status/operator/token badge
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
update_base_fee_parameters
|
||||
update_dynamic_fee_parameters
|
||||
update_fees_and_rewards
|
||||
update_fees_and_reward2
|
||||
set_pair_status
|
||||
set_pair_status_permissionless
|
||||
set_activation_point
|
||||
set_pre_activation_duration
|
||||
set_pre_activation_swap_address
|
||||
set_permissionless_operation_bits
|
||||
create_operator_account
|
||||
close_operator_account
|
||||
close_claim_fee_operator_account
|
||||
initialize_token_badge
|
||||
close_token_badge
|
||||
initialize_preset_parameter
|
||||
close_preset_parameter
|
||||
close_preset_parameter2
|
||||
```
|
||||
|
||||
Décision : `k_sol_pool_admin_events` si acteur/cible fiables ; decoded-only avec raison sinon.
|
||||
|
||||
### Limit orders / orderbook-like events
|
||||
|
||||
Cibles :
|
||||
|
||||
```text
|
||||
place_limit_order
|
||||
cancel_limit_order
|
||||
close_limit_order_if_empty
|
||||
PlaceLimitOrderEvt
|
||||
CancelLimitOrderEvt
|
||||
CloseLimitOrderEvt
|
||||
```
|
||||
|
||||
Décision : `k_sol_orderbook_events` si sémantique fiable ; pas de trade/candle sans fill exact.
|
||||
|
||||
## 9. SQL de validation attendu
|
||||
|
||||
Créer/mettre à jour :
|
||||
|
||||
```text
|
||||
validation_sql/SQL_VALIDATION_METEORA_DLMM_0_7_57.sql
|
||||
```
|
||||
|
||||
Le fichier doit vérifier au minimum :
|
||||
|
||||
1. fallback upstream DLMM ;
|
||||
2. instruction observations DLMM ;
|
||||
3. coverage DLMM ;
|
||||
4. decoded DLMM sans coverage ;
|
||||
5. successful non-materialized sans skip reason ;
|
||||
6. failed tx materialization ;
|
||||
7. multi-target materialization ;
|
||||
8. trade/candle sur non-swap ;
|
||||
9. fee parent/legs ;
|
||||
10. orphan fee legs ;
|
||||
11. reward/fee separation ;
|
||||
12. orderbook/limit-order sans double-count ;
|
||||
13. watchlist globale.
|
||||
|
||||
## 10. Invariants de fermeture
|
||||
|
||||
`0.7.57 meteora_dlmm` ne peut être clôturé que si :
|
||||
|
||||
- les `76` instructions et `30` events Anchor IDL sont dans la coverage ou explicitement non observés avec tests synthétiques ;
|
||||
- aucun fallback upstream DLMM ne reste pour les entrées couvertes localement ;
|
||||
- aucun decoded DLMM local sans coverage ;
|
||||
- aucune tx failed n'alimente une table métier ;
|
||||
- aucun event multi-target incohérent ;
|
||||
- aucune ligne successful non-materialized sans `skip*Reason` ou policy explicite ;
|
||||
- aucun non-swap ne produit trade/candle ;
|
||||
- aucun fee parent scalaire sans leg ;
|
||||
- aucun leg fee orphelin ;
|
||||
- aucun reward n'est classé fee par défaut ;
|
||||
- aucun limit/order event ne produit une candle sans fill exact ;
|
||||
- la watchlist globale ne contient plus de backlog dominant `meteora_dlmm`.
|
||||
|
||||
## 11. Contraintes de code à respecter
|
||||
|
||||
- Rust 2024 ;
|
||||
- async-first ;
|
||||
- tracing obligatoire ;
|
||||
- pas de `?`, pas de `unwrap/expect` en production ;
|
||||
- pas de `anyhow` / `thiserror` ;
|
||||
- pas de `mod.rs` ;
|
||||
- pas de `pub mod` : utiliser `mod` + `pub use` ;
|
||||
- imports seulement pour les traits ;
|
||||
- `#![deny(unreachable_pub)]`, `#![warn(missing_docs)]` ;
|
||||
- tests offline ;
|
||||
- pas de macro DB/coverage ;
|
||||
- après modification DB : re-exports `kb_lib/src/db.rs` et `kb_lib/src/lib.rs` ;
|
||||
- après modification decoder : vérifier `kb_lib/src/dex.rs`, `kb_lib/src/lib.rs`, coverage et tests synthétiques.
|
||||
|
||||
## 12. Format de livraison attendu
|
||||
|
||||
Livrer des deltas successifs :
|
||||
|
||||
```text
|
||||
khadhroony-bobobot-v0.7.57-meteora_dlmm-delta-pre.xxx.zip
|
||||
```
|
||||
|
||||
Chaque réponse doit indiquer : fichiers modifiés, raisons, tests à lancer, SQL à exécuter, résultat attendu, et risques éventuels.
|
||||
Reference in New Issue
Block a user