0.5.1-pre.005

This commit is contained in:
2026-08-10 01:36:42 +02:00
parent ec07ddbd80
commit b6a286a4df
54 changed files with 6236 additions and 5569 deletions

View File

@@ -1,29 +1,50 @@
<!-- file: config/README.md -->
<!-- version: 19 -->
<!-- version: 20 -->
# Configuration locale
Ce dossier contient les exemples et le schéma de configuration JSON.
Ce dossier contient les deux documents de configuration runtime, leurs exemples et leurs schémas JSON indépendants.
## Règles
## Fichiers chargés par défaut
- Le fichier versionné doit rester sans secret.
- Les placeholders de clés restent directement dans les URLs.
- Le champ `active_profile` sélectionne un seul profil actif.
- Un profil actif doit être présent et unique.
- Les profils non actifs peuvent rester dans le fichier pour les tests devnet, mainnet lecture seule, backfill ou future production.
- Le contrat courant couvre HTTP JSON-RPC Solana et WebSocket JSON-RPC générique.
- Helius `transactionSubscribe` et Yellowstone gRPC seront ajoutés plus tard dans `ks_onchain_transport`, avec évolution explicite du schéma quand les transports seront réellement utilisés.
- Les IDLs restent des artefacts de développement et ne font pas partie de la configuration runtime.
- `app.config.json` : configuration générale Khadhroony Solana ;
- `logging.config.json` : configuration logging/tracing ;
- `schemas/app.config.schema.json` : schéma du document général ;
- `schemas/logging.config.schema.json` : schéma du document logging.
## Fichiers
Les chemins par défaut peuvent être remplacés indépendamment par :
- `example.config.json` : exemple complet avec profils `local_devnet`, `mainnet_research` et `mainnet`.
- `schema.config.json` : JSON Schema de validation du fichier de configuration.
```text
KS_CONFIG_PATH
KS_LOGGING_CONFIG_PATH
```
## Variables denvironnement de lexemple
## Exemples conformes
`example.config.json` conserve la topologie des profils et référence les valeurs locales avec des placeholders :
- `example.app.config.json` : exemple général minimal conforme ;
- `example.logging.config.json` : exemple logging minimal conforme.
Les exemples servent de référence de structure. Ils ne sont pas sélectionnés automatiquement au démarrage.
## Sélection indépendante des profils
Chaque document possède son propre `active_profile` :
```text
app.config.json
active_profile = mainnet_research
logging.config.json
active_profile = mainnet_research
```
Ces valeurs sont indépendantes. Changer le profil applicatif ne change pas implicitement le profil logging, et inversement. Les noms peuvent être identiques pour faciliter lexploitation sans créer de couplage contractuel.
Le document général ne contient plus de propriété `logging`. Les routes, niveaux, formats et filtres sont exclusivement possédés par `logging.config.json` et `ks-logging`.
## Variables denvironnement
`app.config.json` référence notamment :
```text
KS_SECRET_HELIUS_API_KEY
@@ -31,73 +52,35 @@ KS_SECRET_POSTGRES_MAINNET_URL
KS_SECRET_POSTGRES_DEVNET_URL
```
`KS_SECRET_POSTGRES_TEST_URL` nest pas utilisé par un profil runtime : il reste réservé aux tests dintégration PostgreSQL. Le profil `local_devnet` utilise `KS_SECRET_POSTGRES_DEVNET_URL`; les profils `mainnet_research` et `mainnet` utilisent `KS_SECRET_POSTGRES_MAINNET_URL`. Les trois bases doivent être distinctes.
`KS_SECRET_POSTGRES_TEST_URL` reste réservé aux tests dintégration PostgreSQL. Le fichier réel `.env` reste local et ignoré par Git ; `.env.example` est le modèle versionné.
Le fichier réel `.env` reste local et ignoré par Git. `.env.example` est le seul modèle dotenv versionné.
La classification `KS_SECRET_*` / `KS_PUBLIC_*` / `KS_*` et `KB_SECRET_*` / `KB_PUBLIC_*` / `KB_*` est normative. Le camouflage et la propagation de sensibilité dans les valeurs composées sont traités dans la prerelease suivante ; aucun secret ne doit être écrit en clair dans un fichier versionné.
## Phase `0.3.x`
## Schémas
`0.3.x` utilise les endpoints HTTP des profils de recherche existants pour :
Les schémas runtime sont localisés exclusivement sous `config/schemas/`.
```text
getSignaturesForAddress
getTransaction
getSignatureStatuses
```
`ks-config` embarque `schemas/app.config.schema.json`. `ks-logging` embarque `schemas/logging.config.schema.json`. Les fichiers embarqués et leurs versions sur disque doivent rester identiques.
Aucun profil Helius payant ou Yellowstone nest activé à ce stade.
## Migration depuis le format combiné
Les sources futures devront déclarer séparément :
Lancien `example.config.json` combinait configuration générale et logging dans chaque profil. La migration consiste à :
- provider ;
- protocole ;
- rôle ;
- limites de streams et filtres ;
- authentification ;
- région éventuelle.
## Évolution du schéma
`schema.config.json` est le contrat de validation runtime. Il évolue seulement lorsquun champ est réellement utilisé par lexécution.
1. conserver dans `app.config.json` les sections `app`, `database`, `data`, `solana`, `wallet`, `execution` et `demo` ;
2. extraire chaque ancien bloc `logging` vers le profil homonyme de `logging.config.json` ;
3. sélectionner explicitement un `active_profile` dans chacun des deux documents ;
4. supprimer lancien fichier combiné une fois la migration validée.
## Logging de développement
Lexemple configure, pour chacun des trois profils, quatre fichiers globaux puis trois fichiers dédiés par crate opérationnelle utilisant `tracing` : `debug.log`, `info.log` et `error.jsonl`.
Le fichier `logging.config.json` conserve actuellement les routes globales ainsi que trois fichiers dédiés par crate opérationnelle utilisant `tracing` : `debug.log`, `info.log` et `error.jsonl`.
Les matérialisateurs natifs consolidés rejoignent la console et disposent de leurs routes propres sous :
Les matérialisateurs consolidés disposent de leurs routes sous les targets `ks-lib-materializer.*`. Les tests de `ks-logging` découvrent dynamiquement les crates déclarant `tracing.workspace = true` et vérifient les routes canoniques du document logging par défaut.
```text
logs/<profil>/ks-lib/materializer/admin/
logs/<profil>/ks-lib/materializer/compliance/audit/
logs/<profil>/ks-lib/materializer/lifecycle/
logs/<profil>/ks-lib/materializer/risk/
logs/<profil>/ks-lib/materializer/staking/
logs/<profil>/ks-lib/materializer/token/accounts/
logs/<profil>/ks-lib/materializer/transaction/annotations/
```
Le test de configuration découvre dynamiquement toutes les crates déclarant `tracing.workspace = true` et vérifie leurs trois routes dans chaque profil. Les logs ne doivent contenir ni secret, ni DSN non masqué, ni payload Config ou bytecode complet.
Les logs ne doivent contenir ni secret, ni DSN non masqué, ni keypair, ni payload de configuration résolue complet.
## Limites du profil public Devnet
`api.devnet.solana.com` est un endpoint public partagé. Les limites configurées par rôle ne sont pas des quotas indépendants fournis par le serveur : leur débit cumulé doit rester sous la limite globale de lendpoint, et chaque méthode RPC doit également rester sous sa propre limite.
Lexemple `local_devnet` utilise donc volontairement des valeurs conservatrices :
```text
http_queries:
requests_per_second: 3
burst_capacity: 3
max_concurrent_requests: 2
pause_after_rate_limit_ms: 10000
http_transactions:
requests_per_second: 1
burst_capacity: 1
max_concurrent_requests: 1
pause_after_rate_limit_ms: 10000
```
Un fichier de configuration local déjà créé nest pas modifié automatiquement lorsque `example.config.json` évolue. Lopérateur doit reporter explicitement ces valeurs dans son profil `local_devnet`.
Un warning `retry_http_json_rpc_after_rate_limit` reste possible sur un service public partagé. Il indique que le cooldown et le retry borné ont été activés ; il ne constitue un échec que si les tentatives finissent par être épuisées.
Le profil `local_devnet` de `app.config.json` utilise donc volontairement des valeurs conservatrices pour les rôles HTTP. Un warning `retry_http_json_rpc_after_rate_limit` reste possible sur un service partagé ; il indique que le cooldown et le retry borné ont été activés.

1110
config/app.config.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,240 @@
{
"active_profile": "local_devnet",
"profiles": [
{
"name": "local_devnet",
"app": {
"name": "khadhroony-bot3",
"environment": "development",
"auto_reconnect_default": false
},
"database": {
"enabled": true,
"backend": "postgres",
"postgres": {
"url": "${KS_SECRET_POSTGRES_DEVNET_URL}",
"max_connections": 8,
"connect_timeout_ms": 5000,
"auto_initialize_schema": true
},
"sqlite": {
"path": "data/local.sqlite",
"create_if_missing": true,
"busy_timeout_ms": 5000,
"max_connections": 1,
"auto_initialize_schema": true,
"use_wal": true
}
},
"data": {
"wallets_directory": "wallets",
"logs_directory": "logs"
},
"solana": {
"http_endpoints": [
{
"name": "devnet_public_http",
"enabled": true,
"provider": "solana-public",
"cluster": "devnet",
"url": "https://api.devnet.solana.com",
"connect_timeout_ms": 4000,
"request_timeout_ms": 10000,
"max_idle_connections_per_host": 4,
"roles": [
{
"role": "http_queries",
"enabled": true,
"request_kinds": [
"get_account_info",
"get_balance",
"get_block_commitment",
"get_block_height",
"get_block_production",
"get_blocks",
"get_blocks_with_limit",
"get_cluster_nodes",
"get_epoch_info",
"get_epoch_schedule",
"get_fee_for_message",
"get_first_available_block",
"get_genesis_hash",
"get_health",
"get_highest_snapshot_slot",
"get_identity",
"get_inflation_governor",
"get_inflation_rate",
"get_inflation_reward",
"get_largest_accounts",
"get_latest_blockhash",
"get_leader_schedule",
"get_max_retransmit_slot",
"get_max_shred_insert_slot",
"get_minimum_balance_for_rent_exemption",
"get_multiple_accounts",
"get_recent_performance_samples",
"get_recent_prioritization_fees",
"get_signature_statuses",
"get_slot",
"get_slot_leader",
"get_slot_leaders",
"get_stake_activation",
"get_stake_minimum_delegation",
"get_supply",
"get_token_account_balance",
"get_token_accounts_by_delegate",
"get_token_accounts_by_owner",
"get_token_largest_accounts",
"get_token_supply",
"get_transaction",
"get_transaction_count",
"get_version",
"get_vote_accounts",
"is_blockhash_valid",
"request_airdrop"
],
"priority": 10,
"requests_per_second": 3,
"burst_capacity": 3,
"max_concurrent_requests": 2,
"max_subscriptions": 0,
"pause_after_rate_limit_ms": 10000
},
{
"role": "http_transactions",
"enabled": true,
"request_kinds": [
"simulate_transaction",
"send_transaction",
"get_signature_statuses"
],
"priority": 20,
"requests_per_second": 1,
"burst_capacity": 1,
"max_concurrent_requests": 1,
"max_subscriptions": 0,
"pause_after_rate_limit_ms": 10000
}
]
}
],
"ws_endpoints": [
{
"name": "devnet_public_ws",
"enabled": true,
"provider": "solana-public",
"cluster": "devnet",
"url": "wss://api.devnet.solana.com",
"connect_timeout_ms": 5000,
"request_timeout_ms": 10000,
"unsubscribe_timeout_ms": 1500,
"write_channel_capacity": 256,
"event_channel_capacity": 1024,
"auto_reconnect": false,
"roles": [
{
"role": "slot_notifications",
"enabled": true,
"request_kinds": [
"slot_subscribe",
"slots_updates_subscribe"
],
"priority": 10,
"requests_per_second": 4,
"burst_capacity": 8,
"max_concurrent_requests": 4,
"max_subscriptions": 16,
"pause_after_rate_limit_ms": 3000
},
{
"role": "program_logs",
"enabled": true,
"request_kinds": [
"logs_subscribe_mentions",
"program_subscribe",
"account_subscribe",
"signature_subscribe",
"block_subscribe",
"vote_subscribe"
],
"priority": 20,
"requests_per_second": 2,
"burst_capacity": 4,
"max_concurrent_requests": 2,
"max_subscriptions": 64,
"pause_after_rate_limit_ms": 3000
},
{
"role": "root_notifications",
"enabled": true,
"request_kinds": [
"root_subscribe"
],
"priority": 15,
"requests_per_second": 4,
"burst_capacity": 8,
"max_concurrent_requests": 4,
"max_subscriptions": 16,
"pause_after_rate_limit_ms": 3000
}
]
}
],
"listeners": {
"enabled": true,
"default_commitment": "confirmed",
"log_listeners": [
{
"name": "pump_swap_logs",
"enabled": false,
"endpoint_role": "program_logs",
"program_id": "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA",
"purpose": "Détecter les swaps, créations de pool et changements de liquidité Pump Swap."
}
],
"program_listeners": [
{
"name": "pump_fun_program_accounts",
"enabled": false,
"endpoint_role": "program_logs",
"program_id": "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P",
"purpose": "Détecter les changements de comptes utiles à la création ou migration de tokens Pump Fun."
}
],
"account_listeners": []
}
},
"wallet": {
"wallet_dir": "wallets/temporary/local_devnet",
"cluster": "devnet",
"temporary_wallet_enabled": true,
"temporary_wallet_alias": "local-devnet-operator",
"temporary_wallet_persist": true,
"localnet_send_enabled": false,
"devnet_send_enabled": true,
"testnet_send_enabled": false,
"mainnet_send_enabled": false
},
"execution": {
"dry_run_default": true,
"require_simulation": true,
"require_operator_confirmation": true,
"localnet_max_spend_lamports": 0,
"devnet_max_spend_lamports": 100000000,
"testnet_max_spend_lamports": 0,
"mainnet_max_spend_lamports": 0,
"max_fee_lamports": 1000000,
"max_compute_unit_price_micro_lamports": 100000,
"recent_blockhash_max_age_slots": 150,
"send_max_retries": 3,
"confirmation_poll_interval_ms": 500,
"confirmation_max_attempts": 120,
"devnet_airdrop_max_lamports": 2000000000
},
"demo": {
"live_demo_enabled": true,
"trading_demo_enabled": false
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
{
"active_profile": "local_devnet",
"profiles": [
{
"name": "local_devnet",
"default_level": "warn",
"targets": [
{
"name": "console_local_devnet_compact",
"enabled": true,
"sink": "console",
"level": "debug",
"path": "",
"rotation": "none",
"format": "compact",
"ansi": true,
"targets": [
"*"
]
},
{
"name": "file_local_devnet_debug",
"enabled": true,
"sink": "file",
"level": "debug",
"path": "logs/devnet/debug.log",
"rotation": "daily",
"format": "human",
"ansi": false,
"targets": [
"*"
]
}
],
"target_filters": [
{
"target": "hyper",
"level": "warn"
},
{
"target": "reqwest",
"level": "warn"
},
{
"target": "tao",
"level": "warn"
},
{
"target": "wry",
"level": "warn"
}
]
}
]
}

3557
config/logging.config.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://khadhroony.local/schema/config.schema.json",
"title": "Khadhroony Bot3 configuration",
"$id": "https://khadhroony.local/schema/app.config.schema.json",
"title": "Khadhroony Solana application configuration",
"type": "object",
"additionalProperties": false,
"required": [
@@ -25,24 +25,12 @@
"type": "string",
"minLength": 1
},
"log_level": {
"type": "string",
"enum": [
"trace",
"debug",
"info",
"warn",
"error",
"off"
]
},
"profile": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"app",
"logging",
"database",
"data",
"solana",
@@ -57,9 +45,6 @@
"app": {
"$ref": "#/$defs/app_section"
},
"logging": {
"$ref": "#/$defs/logging"
},
"database": {
"$ref": "#/$defs/database"
},
@@ -100,112 +85,6 @@
}
}
},
"logging": {
"type": "object",
"additionalProperties": false,
"required": [
"default_level",
"targets",
"target_filters"
],
"properties": {
"default_level": {
"$ref": "#/$defs/log_level"
},
"targets": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/log_target"
}
},
"target_filters": {
"type": "array",
"items": {
"$ref": "#/$defs/log_target_filter"
}
}
}
},
"log_target": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"enabled",
"sink",
"level",
"path",
"rotation",
"format",
"ansi",
"targets"
],
"properties": {
"name": {
"$ref": "#/$defs/non_empty_string"
},
"enabled": {
"type": "boolean"
},
"sink": {
"type": "string",
"enum": [
"console",
"file"
]
},
"level": {
"$ref": "#/$defs/log_level"
},
"path": {
"type": "string"
},
"rotation": {
"type": "string",
"enum": [
"none",
"never",
"daily",
"hourly"
]
},
"format": {
"type": "string",
"enum": [
"human",
"compact",
"pretty",
"json"
]
},
"ansi": {
"type": "boolean"
},
"targets": {
"type": "array",
"items": {
"$ref": "#/$defs/non_empty_string"
}
}
}
},
"log_target_filter": {
"type": "object",
"additionalProperties": false,
"required": [
"target",
"level"
],
"properties": {
"target": {
"$ref": "#/$defs/non_empty_string"
},
"level": {
"$ref": "#/$defs/log_level"
}
}
},
"database": {
"type": "object",
"additionalProperties": false,

View File

@@ -0,0 +1,150 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://khadhroony.local/schema/logging.config.schema.json",
"title": "Khadhroony Solana logging configuration",
"type": "object",
"additionalProperties": false,
"required": [
"active_profile",
"profiles"
],
"properties": {
"active_profile": {
"$ref": "#/$defs/non_empty_string"
},
"profiles": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/logging_profile"
}
}
},
"$defs": {
"non_empty_string": {
"type": "string",
"minLength": 1
},
"log_level": {
"type": "string",
"enum": [
"trace",
"debug",
"info",
"warn",
"error",
"off"
]
},
"logging_profile": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"default_level",
"targets",
"target_filters"
],
"properties": {
"name": {
"$ref": "#/$defs/non_empty_string"
},
"default_level": {
"$ref": "#/$defs/log_level"
},
"targets": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/log_target"
}
},
"target_filters": {
"type": "array",
"items": {
"$ref": "#/$defs/log_target_filter"
}
}
}
},
"log_target": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"enabled",
"sink",
"level",
"path",
"rotation",
"format",
"ansi",
"targets"
],
"properties": {
"name": {
"$ref": "#/$defs/non_empty_string"
},
"enabled": {
"type": "boolean"
},
"sink": {
"type": "string",
"enum": [
"console",
"file"
]
},
"level": {
"$ref": "#/$defs/log_level"
},
"path": {
"type": "string"
},
"rotation": {
"type": "string",
"enum": [
"none",
"never",
"daily",
"hourly"
]
},
"format": {
"type": "string",
"enum": [
"human",
"compact",
"pretty",
"json"
]
},
"ansi": {
"type": "boolean"
},
"targets": {
"type": "array",
"items": {
"$ref": "#/$defs/non_empty_string"
}
}
}
},
"log_target_filter": {
"type": "object",
"additionalProperties": false,
"required": [
"target",
"level"
],
"properties": {
"target": {
"$ref": "#/$defs/non_empty_string"
},
"level": {
"$ref": "#/$defs/log_level"
}
}
}
}
}