You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Récapitulatif de l'état au moment de la clôture de la session du 2026-08-13, couvrant la lane C5 (ContractState ≠ storage EVM), la lane forEach/refactor, et les lots orphelins à arbitrer.
Lane C5 — un seul map avec layout Solidity, lenses comme seule API
Fait (mergé)
Étape 1 (feat(core): storage-lens API freeze — C5 step 1 #2323) : gel de l'API — gate à cliquet scripts/check_storage_lens_freeze.py dans make check (tout nouveau site brut échoue ; baseline par fichier qui ne peut que décroître).
Étape 2.5 (PR feat(core): storage-lens burn-down — C5 step 2.5 (pre-flip) #2329, ⚠️à merger après CI verte — validation locale complète interrompue par la clôture, tous les modules touchés verts individuellement) : burn-down 304 → 63 sites bruts. Nouvelles lenses : bulk (writeSlots/modifySlots/writeTransientSlots/modifyTransientSlots/writeAddrSlots), withStorageChannel, ContractState.ofChannels. Baseline restante justifiée : Core (39, implémentations), Denote (6, faux positifs + bras find?), Owned/Basic (8, lane composition concurrente), TypedIRTests (3, faux positifs IRState), SourceSemantics (7, writers =-guardés dont le re-guard reshaperait GenericInduction).
Reste — Étape 3 (flip de représentation)
Design arrêté (informé par une recon complète de la dérivation de slots — voir ci-dessous) :
StorageKey inductif injectif (| slot n | contractSlot c n | transient n | addr n | map n key | mapUint n k | map2 n k1 k2), DecidableEq ; ContractState.storageWords : StorageKey → Uint256 remplace les 7 champs de canaux. Le layout Solidity vit dans la structure de la clé ; l'effondrement keccak vers Nat reste côté compilateur — c'est ce qui préserve les lois storage_simps inconditionnellement (l'injectivité keccak n'est PAS prouvable et le repo la remplace déjà par des certificats non-alias finis).
Les lectures restent stables : accesseurs def storage/storageAddr/storageMap/... aux anciens noms (dot-notation intacte) ⇒ les specs _meets_spec ne changent pas de forme, comme promis par le plan.
storageArray (List, pas un mot) et knownAddresses (bookkeeping de preuve) restent des champs ce round.
Séquence : flip dans Core + réimplémentation des lenses + repreuve des lois par injectivité de constructeurs → vague de réparation (résidus baseline + les ~60 sites simp [ContractState.writeX] explicites de l'étape 2, greppables) → baseline réduite à Core seul.
Prérequis restants avant flip : migrer les writers =-guardés de SourceSemantics (impact GenericInduction), le bras find? de Denote, et statuer sur les 8 sites Owned (lane concurrente).
Reste — Étape 4 (correspondance lens-slot = slot CompilationModel/Yul)
Recon faite (résultats clés à réutiliser) :
La dérivation canonique est Compiler.Proofs.abstractMappingSlot (= solidityMappingSlot, keccak kernel-computable, MappingSlot.lean:57) ∘ wordNormalize, + wordOffset pour struct members ; double mapping = composition ; chaînes = foldl.
Les mappings sont déjà comparés dans le canal plat à des slots keccak (sourceResultMatchesIRResult ne compare que finalStorage ; finalMappings est une projection dérivée). Les canaux storageMap* sont des ombres write-only — encodeStorageAt ne les lit jamais.
Le vrai trou : aucune cohérence prouvée entre les canaux ombre (ce que lisent readMap/les specs) et le canal plat aux slots dérivés. Livrable étape 4 : storageKeySlot : List Field → StorageKey → Option (Channel × Nat) + invariant MappingCoherent (ombre = plat au slot dérivé) + preuve que les write-helpers le préservent + lecture lens = encodeStorageAt sous cohérence.
⚠️ Divergence connue à trancher : les éléments de dynamic array utilisent solidityMappingSlot base idx dans le modèle source (findDynamicArrayElementAtSlot) mais keccak(slot)+i (layout Solidity réel) côté Yul/StructArrayStorage.
Déjà prouvé et réutilisable : compiledMappingSlotPointer_eq_sourceMappingSlotRead (SolidityStorage.lean:92), les lemmes encodeStorageAt_write*_singleton_eq_written (GenericInduction/Storage.lean), les ponts packed/struct/array de StructArrayStorage.lean.
Toucher la surface layout du compilateur ⇒ coordonner avec la lane forEach (Compile.lean/SupportedFragment.lean).
Lane refactor/forEach (session concurrente)
Arc admission forEach (design complet en mémoire de session) :
PR-A en cours de ship : CompiledNameDiscipline.lean (toolkit préfixes + loopFreeCheck/soundness + gate décidable forEachCompiledBodyChecks). Reste : forEach_loop_coupling (induction sur N−k ; corps via exec_compileStmtList_generic_sizeOf_extraFuel [Helpers.lean:3210], fuel via execIRStmt_boundedFor_stable [feat(proofs): fuel stability for literal-bound forEach loops #2328], shrink de scope via bindingsExactlyMatchIRVarsOnScope_of_included) + compiledStmtStep_forEach_literal (généralise Loops.lean:949/992).
PR-B : constructeur forEachLiteralBounded.literal 0 → .literal n (SupportedFragment.lean:373) + 7 sites consommateurs (Helpers.lean:1718/1866/2204, SupportedSpec.lean:3902/4096/6171/6296, EndToEnd/Base) + prédicat de surface (SupportedSpec.lean:1491) + enregistrement du checker.
PR-C optionnelle : lemme générique de discipline de noms (35 constructeurs SupportedStmtList) pour éliminer le decide du gate.
Limitation documentée : corps loop-free uniquement (les for_ imbriqués sont rejetés par varUntouchedCheck/LoopFree) — extension nested = chantier ultérieur.
Items de rotation restants : 7 (réduction allowlist proof-length, ~15 entrées), 8 (#2000 stores binding-aware pour payloads d'événements dynamiques), 9 (#1987 doc-sync — attention lane invisible active), 11 (identité Yul #2058/#2059), 3 (éclatement IRExecResult.outOfFuel, ~727 usages — à faire en dernier, décision actée), 5 (retrait lock-free erasure — uniquement sur décision explicite).
Une session « invisible » (hors ListAgents) travaille dans le même arbre : lane Ownable/OwnedCounterComposed/Specs.Composition/modifiers Macro + refactor owner.slot. Ses fichiers étaient non commités à la clôture.
Patches sauvegardés dans le scratchpad de session (orphan-lanes/) : laneA-owned-slot-composition.patch (+ Composition.lean, Smoke-Include.lean), laneC-macro-modifiers.patch (883 lignes).
⚠️Perte assumée : le lot docsync non commité (docs-site/*.mdx, ROADMAP, VERIFICATION_STATUS, docsync.py) a été écrasé par un checkout groupé dont la sauvegarde avait échoué en silence — en grande partie régénérable par les scripts generate_*.
Récapitulatif de l'état au moment de la clôture de la session du 2026-08-13, couvrant la lane C5 (ContractState ≠ storage EVM), la lane forEach/refactor, et les lots orphelins à arbitrer.
Lane C5 — un seul map avec layout Solidity, lenses comme seule API
Fait (mergé)
scripts/check_storage_lens_freeze.pydansmake check(tout nouveau site brut échoue ; baseline par fichier qui ne peut que décroître).@[simp]global ;storage_simpsreste laws-only (survivra au flip) ; ~25 fichiers de preuves réparés, zéro énoncé changé.writeSlots/modifySlots/writeTransientSlots/modifyTransientSlots/writeAddrSlots),withStorageChannel,ContractState.ofChannels. Baseline restante justifiée : Core (39, implémentations), Denote (6, faux positifs + bras find?), Owned/Basic (8, lane composition concurrente), TypedIRTests (3, faux positifs IRState), SourceSemantics (7, writers=-guardés dont le re-guard reshaperait GenericInduction).Reste — Étape 3 (flip de représentation)
Design arrêté (informé par une recon complète de la dérivation de slots — voir ci-dessous) :
StorageKeyinductif injectif (| slot n | contractSlot c n | transient n | addr n | map n key | mapUint n k | map2 n k1 k2),DecidableEq;ContractState.storageWords : StorageKey → Uint256remplace les 7 champs de canaux. Le layout Solidity vit dans la structure de la clé ; l'effondrement keccak vers Nat reste côté compilateur — c'est ce qui préserve les loisstorage_simpsinconditionnellement (l'injectivité keccak n'est PAS prouvable et le repo la remplace déjà par des certificats non-alias finis).def storage/storageAddr/storageMap/...aux anciens noms (dot-notation intacte) ⇒ les specs_meets_specne changent pas de forme, comme promis par le plan.storageArray(List, pas un mot) etknownAddresses(bookkeeping de preuve) restent des champs ce round.simp [ContractState.writeX]explicites de l'étape 2, greppables) → baseline réduite à Core seul.=-guardés de SourceSemantics (impact GenericInduction), le bras find? de Denote, et statuer sur les 8 sites Owned (lane concurrente).Reste — Étape 4 (correspondance lens-slot = slot CompilationModel/Yul)
Recon faite (résultats clés à réutiliser) :
Compiler.Proofs.abstractMappingSlot(=solidityMappingSlot, keccak kernel-computable,MappingSlot.lean:57) ∘wordNormalize, +wordOffsetpour struct members ; double mapping = composition ; chaînes = foldl.sourceResultMatchesIRResultne compare quefinalStorage;finalMappingsest une projection dérivée). Les canauxstorageMap*sont des ombres write-only —encodeStorageAtne les lit jamais.readMap/les specs) et le canal plat aux slots dérivés. Livrable étape 4 :storageKeySlot : List Field → StorageKey → Option (Channel × Nat)+ invariantMappingCoherent(ombre = plat au slot dérivé) + preuve que les write-helpers le préservent + lecture lens =encodeStorageAtsous cohérence.solidityMappingSlot base idxdans le modèle source (findDynamicArrayElementAtSlot) maiskeccak(slot)+i(layout Solidity réel) côté Yul/StructArrayStorage.compiledMappingSlotPointer_eq_sourceMappingSlotRead(SolidityStorage.lean:92), les lemmesencodeStorageAt_write*_singleton_eq_written(GenericInduction/Storage.lean), les ponts packed/struct/array de StructArrayStorage.lean.Lane refactor/forEach (session concurrente)
Arc admission forEach (design complet en mémoire de session) :
CompiledNameDiscipline.lean(toolkit préfixes + loopFreeCheck/soundness + gate décidableforEachCompiledBodyChecks). Reste :forEach_loop_coupling(induction sur N−k ; corps viaexec_compileStmtList_generic_sizeOf_extraFuel[Helpers.lean:3210], fuel viaexecIRStmt_boundedFor_stable[feat(proofs): fuel stability for literal-bound forEach loops #2328], shrink de scope viabindingsExactlyMatchIRVarsOnScope_of_included) +compiledStmtStep_forEach_literal(généralise Loops.lean:949/992).forEachLiteralBounded.literal 0 → .literal n(SupportedFragment.lean:373) + 7 sites consommateurs (Helpers.lean:1718/1866/2204, SupportedSpec.lean:3902/4096/6171/6296, EndToEnd/Base) + prédicat de surface (SupportedSpec.lean:1491) + enregistrement du checker.decidedu gate.for_imbriqués sont rejetés par varUntouchedCheck/LoopFree) — extension nested = chantier ultérieur.Items de rotation restants : 7 (réduction allowlist proof-length, ~15 entrées), 8 (#2000 stores binding-aware pour payloads d'événements dynamiques), 9 (#1987 doc-sync — attention lane invisible active), 11 (identité Yul #2058/#2059), 3 (éclatement
IRExecResult.outOfFuel, ~727 usages — à faire en dernier, décision actée), 5 (retrait lock-free erasure — uniquement sur décision explicite).Lane événements / Lido (contexte)
externalCall+ checked arithmetic + préservation guarded des events : mergés (feat(proofs): guarded whole-contract event preservation + checked arithmetic completion #2321, feat(core): storage lenses off default simp — C5 step 2 #2326-era). Côté Lido : bump du pin, remplacer la CalleeInterface par AdversaryModel/journal.emitimbriqué, events dans les fonctions lockées ;notModeledEventEmissionconservé sciemment (ne couvre querawLog, borne documentée dans TRUST_ASSUMPTIONS §Event Emission).Lots orphelins / à arbitrer
OwnedCounterComposed/Specs.Composition/modifiers Macro + refactorowner.slot. Ses fichiers étaient non commités à la clôture.orphan-lanes/) :laneA-owned-slot-composition.patch(+Composition.lean,Smoke-Include.lean),laneC-macro-modifiers.patch(883 lignes).generate_*.Ordre suggéré à la reprise
storageKeySlot), coordonnée avec la surface layout.