v0.3.14-pre.009

This commit is contained in:
2026-09-12 11:22:53 +02:00
parent bf394e0e4b
commit 4bcd942928
10 changed files with 853 additions and 58 deletions

270
deltas/0.3.14/pre.009.md Normal file
View File

@@ -0,0 +1,270 @@
<!-- file: deltas/0.3.14/pre.009.md -->
<!-- version: 1 -->
# Delta `0.3.14-pre.009` — health policy multi-source
## Base requise
```text
0.3.14-pre.008-fix.002
workspace.package.version = 0.3.14-pre.8.fix.2
deltas/0.3.14/pre.008-fix.002.md présent
```
## Gate de la base
Le gate opérateur de `0.3.14-pre.008-fix.002` est validé avant ouverture de cette tranche :
```text
cargo fmt --all : PASS
cargo fmt --all -- --check : PASS
audit Rust workspace rules : PASS
audit Markdown tables : PASS
cargo check --workspace : PASS
cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS
cargo test -p ksp-worker-raw-transaction-ingest-lib --all-targets --all-features : PASS
```
Le gate Worker comprend notamment :
```text
139 unit tests : PASS
cross_layer_completeness : 8 PASS
dependency_boundary : 19 PASS
hardening : 33 PASS
public_api : 20 PASS
release_completeness : 10 PASS
```
## Objectif
Implémenter strictement la tranche `pre.009` du plan `035` :
```text
projeter Healthy / Degraded / Unhealthy depuis des preuves de coverage présentes et futures
conserver Faulted comme état lifecycle terminal du Worker
ne jamais rendre Healthy sur le seul fait qu'un Transport ait reconnecté
rendre Healthy uniquement lorsque toutes les sources attendues sont Active et que les gaps sont fermés
rendre Degraded lorsqu'une source reste perdue mais que le présent est réconcilié et TargetCoverage reste couvert pour la suite
rendre Unhealthy pendant une réconciliation non prouvée, avec gap ouvert ou coverage future insuffisante
ne créer aucune health source/provider spécifique publique
```
## Projection de health fondée sur la continuité
Le ledger de `pre.008` expose maintenant une projection privée et source-neutral :
```text
continuity_frontier
has_open_gaps
future_target_coverage
failed_source_losses_reconciled
```
Pour chaque source projetée `Failed`, `failed_source_losses_reconciled` exige un gap `SourceFailure` effectivement enregistré puis fermé par une preuve run-local. Une source simplement marquée `Failed` dans l'inventaire ne suffit donc jamais à autoriser `Degraded`.
`future_target_coverage` est calculé uniquement depuis les sources réellement `Active` et les relations `Exact` / `Superset` déjà validées par `TargetCoverage`.
La configuration d'une source ne constitue toujours pas une preuve historique. Le présent reste gouverné par :
```text
aucun gap ouvert
continuity frontier == processing frontier
```
Les deux dimensions sont volontairement distinctes :
```text
coverage future disponible != gap historique réparé
gap historique réparé != coverage future encore disponible
```
## Pont Inventory -> Continuity -> Snapshot
Chaque publication agrégée de l'inventaire multi-source calcule désormais, après libération du lock Inventory :
```text
ensemble exact des sources Active
processing frontier agrégé
projection continuity/TargetCoverage sous le lock continuity séparé
projection health privée ajoutée au message latest-value
```
Aucun `MutexGuard` n'est conservé à travers un `await` et aucun client Transport/Store n'est exposé dans la snapshot publique.
La source HTTP full-ledger republie sa projection après l'enregistrement d'un coverage epoch afin qu'une fermeture de gap puisse mettre à jour la health sans attendre une transaction ou un slot produit supplémentaire.
## Politique Running
Lorsque la projection de continuité est disponible, la health suit la politique conservative suivante :
```text
source Reconnecting
-> Unhealthy tant que la continuité de l'incident n'est pas explicitement réconciliée
gap ouvert
ou continuity frontier != processing frontier
ou TargetCoverage future non couverte par les sources Active
-> Unhealthy
toutes les sources attendues Active
+ aucun gap ouvert
+ continuity frontier rattrapé
+ TargetCoverage future couverte
-> Healthy
une source reste perdue/Failed
+ son gap SourceFailure a été enregistré et réconcilié
+ aucune source Reconnecting
+ aucun gap ouvert
+ continuity frontier rattrapé
+ TargetCoverage future couverte
-> Degraded
```
Une source perdue n'est donc jamais transformée en source optionnelle. `Degraded` indique uniquement que le service du run reste couvert malgré son absence ; les observations spécifiques que cette source aurait produites ne sont pas inventées.
## Faulted reste un état lifecycle
`ksp-worker-api::WorkerHealth` reste inchangé et conserve :
```text
Unknown
Healthy
Degraded
Unhealthy
```
La quatrième politique terminale du plan est représentée par :
```text
WorkerState::Faulted(error_code)
WorkerHealth::Unhealthy
```
Aucune nouvelle variante `WorkerHealth::Faulted` ni extension de l'API générique Worker n'est introduite.
## Retour à Healthy
Le retour à `Healthy` exige simultanément :
```text
toutes les sources attendues projetées Active
aucune source projetée Reconnecting
aucun gap run-local ouvert
continuity frontier == processing frontier
TargetCoverage future couverte par les sources Active
```
Le simple passage Transport `Reconnecting -> Active` ne constitue pas une preuve suffisante si le continuity ledger n'est pas réconcilié.
## Tests ajoutés
Les unit tests couvrent notamment :
```text
projection health séparant future TargetCoverage et gap historique ouvert
rejet des ensembles Active dupliqués ou inconnus
pont Inventory -> continuity health avec gap puis coverage epoch de réconciliation
Reconnecting -> Unhealthy tant que la preuve de continuité manque
sources Active + gap ouvert -> Unhealthy
sources Active + gaps fermés + coverage future -> Healthy
source Failed sans gap SourceFailure réconcilié -> Unhealthy
source Failed avec gap SourceFailure réconcilié et présent/futur couverts -> Degraded
publication supervisor immédiate après réconciliation réussie de la perte de source
coverage future insuffisante -> Unhealthy
WorkerState::Faulted -> WorkerHealth::Unhealthy
```
Les canaris `hardening` et `release_completeness` vérifient en plus :
```text
health fondée sur continuity frontier + gaps + TargetCoverage
aucune health provider/source-key spécifique publique
aucune variante WorkerHealth::Faulted ajoutée
aucune croissance de la surface publique TargetCoverage
```
## Hors périmètre inchangé
```text
aucune fairness spécifique nominal/repair de pre.010
aucune observabilité publique détaillée des gaps/repair de pre.011
aucun nouveau mécanisme de replay/reconnect Worker
aucun respawn de source
aucun EARLY/shred
aucun Job Backfill depuis Worker
aucun nouveau provider ou SDK
```
## Fichiers ajoutés
```text
deltas/0.3.14/pre.009.md
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-worker-raw-transaction-ingest-lib/src/continuity.rs
crates/ksp-worker-raw-transaction-ingest-lib/src/runtime_resources.rs
crates/ksp-worker-raw-transaction-ingest-lib/src/snapshot.rs
crates/ksp-worker-raw-transaction-ingest-lib/tests/hardening.rs
crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/continuity.rs
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/runtime_resources.rs
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/snapshot.rs
```
## Fichiers supprimés
```text
aucun
```
## Version Cargo
Conformément à `VER-ID-009` :
```text
header Cargo.toml : 578 -> 579
workspace.package.version : 0.3.14-pre.8.fix.2 -> 0.3.14-pre.9
```
Versions des fichiers modifiés :
```text
continuity.rs : 8 -> 9
runtime_resources.rs : 36 -> 37
snapshot.rs : 5 -> 6
unit_tests/continuity.rs : 6 -> 7
unit_tests/runtime_resources.rs : 30 -> 31
unit_tests/snapshot.rs : 5 -> 6
tests/hardening.rs : 32 -> 33
tests/release_completeness.rs : 27 -> 28
```
## Validation exécutée dans l'environnement de préparation
```text
python3 scripts/audit_rust_workspace_rules.py : PASS
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas : PASS
scan des frontières Worker/Transport/Backfill/Store : PASS
scan de la crate-root historique : PASS
comparaison exacte pre.008-fix.002 -> pre.009 : PASS
```
Les gates Cargo ne sont pas déclarés PASS dans l'environnement de préparation lorsqu'ils ne peuvent pas y être exécutés. Ils restent obligatoires côté opérateur avant `pre.010`.
## Décisions prises
```text
la health est une projection de preuves run-local, pas un statut provider
le futur est prouvé par TargetCoverage sur les sources Active
le présent est prouvé par continuity frontier + absence de gap ouvert
Reconnecting reste Unhealthy tant que l'incident n'est pas réconcilié
Failed ne devient Degraded qu'après enregistrement et fermeture effective de son gap SourceFailure
une source perdue mais réellement redondante maintient Degraded, jamais Healthy
Faulted reste un WorkerState terminal avec WorkerHealth::Unhealthy
```