← Driving RustL4 · The Questions Your Agent Will Ask
Score 0
1/8 Two designs — pick one

“String or &str?”

A function formats a greeting from a name and returns the text. It only reads the name. Your agent asks which parameter type to take. Choose.

the designL4·1
A · fn greet(name: &str)caller ownsString "gui"caller hasliteral "ana"greet(&str)&ownedB · fn greet(name: String)caller ownsString "gui"caller hasliteral "ana"greet(String)owned.clone()?.to_string()
2/8 Judge the agent

“Do you want this async?”

A CLI tool: read a config file, call one HTTP API, print the result. Your agent proposes the shape of the code. Judge it.

the designL4·2
main()run()read_config()fetch_price()tokio runtime
The agent says

I’ll make it async with tokio and reqwest. It’s the modern default, and it lets us add concurrency later without a rewrite.

3/8 Judge the agent

The convenience that is a commitment

Your agent is building the ingest path for a service reading 40,000 sensor frames a second. Frames get parsed, filtered, and dropped: nothing downstream keeps them. It has made one call and explained itself.

the designL4·3
receiveparsefilter⧉ by value96Binvariant: nothing downstream keeps a framesecond caller: metrics96B
The agent says

I’ll take the frame by value, fn parse(frame: Frame), rather than by reference. It keeps lifetime annotations out of the public API, and Frame is only 96 bytes, so at 40k/s the copy is around 3.8 MB/s. Negligible. I’ll also derive Clone on Frame so callers can keep their own copy if they need one.

4/8 Two designs — pick one

“Box or generics?”

Deploy notifications go to email, Telegram, or both, chosen from a config file at startup. Your agent asks how to type the notifier. Choose.

the designL4·4
A · Vec<Box<dyn Notifier>>config:[email, telegram]one Vec, mixedvtable hop(nanoseconds)B · fn send<N: Notifier>(n: &N)compiler stampsa copy per typebinary sizea Vec of both?
5/8 Two designs — pick one

“Channel or shared state?”

Webhook workers, like the HelloHarel sync, process events in parallel and update one job ledger. Your agent offers two shapes. Choose.

the designL4·5
A · Arc<Mutex<Ledger>> shared by workersw1w2w3w4MutexLedgerB · one owner task, workers send messagesw1w2w3w4queueownerLedger
6/8 Judge the agent

“One crate or a workspace?”

A new sync service, about 3,000 lines, written by your agents. Your agent proposes the repository layout. Judge it.

the designL4·6
domainportsadapters-httpadapters-dbconfigerrorsapprebuild after a 1-line change
The agent says

I’ll set up a workspace with seven crates: domain, ports, adapters-http, adapters-db, config, errors, and app. Clean architecture from day one; it will scale as the team grows.

7/8 Judge the agent

“Is this error recoverable?”

The sync cannot reach HelloHarel for one order in a batch of a thousand. Your agent proposes what the HTTP adapter should do. Judge it.

the designL4·7
batch of1,000 ordersHTTP adapterretry ×3HelloHarelorders synced0
The agent says

I’ll retry three times with backoff inside the HTTP adapter, then panic. This should never happen in production, and a panic makes it loud.

Level 4 cleared

What survives this level

defaultflips only when you can name…the other borrowed (&str, &T)the place that stores itowned syncmany things waiting at onceasync + a runtime enumwho else adds variantstrait Box<dyn Trait>the hot path with one known typegenerics one owner + channelsmall, read-mostly, uncontended stateArc<Mutex> one cratethe second agent who must own a pieceworkspace derive nothing extrathe caller who askedClone, Copy, …
You can now say to a coding agent“Default to borrowed, sync, enum, one crate, a channel and no extra derives; flip any of those only when you can name the caller who needs the other.”
Added to your ledger
Owned type vs borrowed view (String / &str)Take a borrowed view when you only read; take ownership only when you store it.
Trait objects vs genericsChosen at runtime or mixed in one collection: Box<dyn>. Known at compile time and hot: generics.
Send and SyncA Send/Sync error names what may not cross threads; fix the design, never the marker.
Arc<Mutex<_>> vs channels vs actorsDefault to one owner behind a channel; a shared lock is for small, rarely contended, read-mostly state.
Sync vs async and the colour problemasync only when many things wait at once; it colours every caller and commits you to a runtime.
"Fearless concurrency" is a compile-time claimThe compiler proves the absence of data races, not of deadlocks, contention or a bad design.
Crates and workspaces as module boundaries with teethSplit a crate where a second agent needs to own something; not before.
Zero-cost abstraction — what it promisesZero-cost means no runtime cost; you pay in compile time, binary size and reading generic signatures.
Compile time as a project-management costEvery generic and every crate split adds to the loop your agents run all day; budget it like CI time.
Workspace boundaries as the unit of delegationOne agent, one crate, one public surface; agents meet at crate edges, not inside modules.

Back to the map Next: L5 The Boundary →

What clearing this level buys you
“Default to borrowed, sync, enum, one crate, a channel and no extra derives; flip any of those only when you can name the caller who needs the other.”