Files
Emilio López 0da0cbfde9 Merge remote-tracking branch 'origin/refactor/campaign-decomposition' into dev-agents
The decomposition is a slice cut out of this branch and reworked on its own, so
it wins every conflict: the agent layer is rebuilt on top of it rather than
alongside it. Both sides had split Echidna.Campaign the same way under different
names, and keeping both copies would have meant carrying the same code twice and
replaying this merge when the slice lands in master.

  Echidna.Execution        -> Echidna.Worker.Sequence + Echidna.Test.State
  Echidna.Agent.Fuzzer     -> Echidna.Worker.Fuzz
  Echidna.Agent.Symbolic   -> Echidna.Worker.Symbolic
  Campaign.spawnListener   -> Worker.spawnListener

Worker.Sequence keeps the two things Execution had added: callseq's isReplaying
flag with the NewCoverageInfo bus broadcast, and the sampledFunctions update
behind a Map.null guard. Everything else it duplicated is gone, including the
second copy of updateTests that Shrink was already importing from Test.State.

The workers keep the bus and message handling that made them agents, and lose
the helpers the decomposition had already factored out: the hand-rolled
WorkerState is initialWorkerState, the local shrinkable and final predicates are
isShrinkable and isConclusiveFailure, and the inlined assertion-test updates are
setAssertionTestState. That drops three defects the agent copies had picked up:
an unbounded shrinkable predicate, a shrinkAndRandomlyExplore that recursed on
the same counter, and a symexecTxs call passing Nothing where the CLI-selected
contract belonged.

The symbolic worker goes back to the event queue. Its bus listener counted
Broadcast WorkerStopped to know when to exit, but nothing has ever sent that
message, so it would have blocked on readTChan once the fuzzers finished. The
ToSymbolic commands it also handled have no senders either; a listener that can
block on the queue and the bus at once is what they need.

Config, Solidity, Test and the foundry fixtures take the decomposition's version
of the verification test mode and the Foundry check/prove handling, which is the
reworked form of what this branch had drafted.

Agent.runAgent now returns WorkerStopReason instead of pushing WorkerStopped
itself. An agent killed by the campaign timeout never reaches its own last line,
so spawnWorker had to push the event too, and the shrink-only pass it then runs
pushed a second one for the same worker. Listeners retire a worker per event, so
that shrink pass could end a campaign early. Reporting the reason to the caller,
as runWorker did, keeps it to one event per worker.
2026-08-12 19:51:07 -03:00
..