Map needs remove and iteration for the kernel models
The bounded Map lowering ships and works — conformance/map_kv.th is a real Map<u64,u64> over the Vec-of-pairs TMap backing, grounded by forge/tests/map_conformance.rs. This is about what the kernel subsystem models need on top of insert/get/contains_key/len.
Measured rather than guessed: every BTreeMap call site across the 19 model files in thermite-kernel, scored against the shipped surface. 257 sites, 150 covered.
What is not covered, and what that is worth
Four of the uncovered operations are idioms rather than capabilities, and need nothing:
| op |
sites |
why it needs nothing |
get_mut |
48 |
read-modify-write on a &mut binding, which is get then insert in a value-semantics language |
entry |
4 |
get-or-insert, same |
is_empty |
2 |
len() == 0 |
clear |
2 |
a fresh Map::new() |
That leaves two genuine capabilities:
| missing |
sites |
files |
remove |
24 |
frame 12, dma 4, irq 2, memory 2, services 2, smp 2 |
iteration (iter 17, values 8) |
25 |
frame 10, memory 5, scheduler 4, smp 2, sync 2, services 2 |
Plus two singletons, clone (dma) and take (scheduler), which look like local refactors rather than requests.
Why these two specifically
remove is revocation and free. capability.rs revokes, frame.rs frees, irq.rs unroutes, dma.rs unpins. There is no way to express any of them with the current surface — a tombstone value would change what contains_key means, and len with it.
Iteration is traversal. scheduler.rs picks over its runqueue, frame.rs and memory.rs walk their extents, smp.rs fans out. These are the loops whose invariants are the interesting proofs.
The design question, which is yours rather than ours
remove looks mechanical against a Vec-of-pairs backing — swap-remove plus a spec_dom adjustment.
Iteration may not need an exec-position primitive at all. Every use we have is either a fold whose contract is a forall over the domain, or a search that could be expressed as such. If the spec surface can quantify over the map's domain, the contracts might be writable without an iterator, and the exec side could stay a bounded for over an index. That would be a much smaller change, and it is the kind of thing worth deciding before either of us writes code against the wrong shape.
Consumer-side effect
For a downstream kernel these two decide which subsystems can be modelled at all:
| needs |
subsystems |
| neither |
the capability ledger — its only uncovered op is get_mut |
remove |
irq, device, dma |
remove and iteration |
frame, memory, smp, sync |
Note this is independent of #122, which blocks all of them today for a different reason. The two are additive: #122 stops the structs from certifying, and this stops the maps inside them from being manipulated.
Happy to supply the per-call-site breakdown if it is useful for scoping.
🤖 Generated with Claude Code
Mapneedsremoveand iteration for the kernel modelsThe bounded
Maplowering ships and works —conformance/map_kv.this a realMap<u64,u64>over the Vec-of-pairsTMapbacking, grounded byforge/tests/map_conformance.rs. This is about what the kernel subsystem models need on top ofinsert/get/contains_key/len.Measured rather than guessed: every
BTreeMapcall site across the 19 model files inthermite-kernel, scored against the shipped surface. 257 sites, 150 covered.What is not covered, and what that is worth
Four of the uncovered operations are idioms rather than capabilities, and need nothing:
get_mut&mutbinding, which isgettheninsertin a value-semantics languageentryis_emptylen() == 0clearMap::new()That leaves two genuine capabilities:
removeiter17,values8)Plus two singletons,
clone(dma) andtake(scheduler), which look like local refactors rather than requests.Why these two specifically
removeis revocation and free.capability.rsrevokes,frame.rsfrees,irq.rsunroutes,dma.rsunpins. There is no way to express any of them with the current surface — a tombstone value would change whatcontains_keymeans, andlenwith it.Iteration is traversal.
scheduler.rspicks over its runqueue,frame.rsandmemory.rswalk their extents,smp.rsfans out. These are the loops whose invariants are the interesting proofs.The design question, which is yours rather than ours
removelooks mechanical against a Vec-of-pairs backing — swap-remove plus aspec_domadjustment.Iteration may not need an exec-position primitive at all. Every use we have is either a fold whose contract is a
forallover the domain, or a search that could be expressed as such. If the spec surface can quantify over the map's domain, the contracts might be writable without an iterator, and the exec side could stay a boundedforover an index. That would be a much smaller change, and it is the kind of thing worth deciding before either of us writes code against the wrong shape.Consumer-side effect
For a downstream kernel these two decide which subsystems can be modelled at all:
get_mutremoveremoveand iterationNote this is independent of #122, which blocks all of them today for a different reason. The two are additive: #122 stops the structs from certifying, and this stops the maps inside them from being manipulated.
Happy to supply the per-call-site breakdown if it is useful for scoping.
🤖 Generated with Claude Code