Forks and Commands
conta-fork-yeah is designed to compose with command-based architectures (conta-command).
This page explains the relationship and the audit/replay properties that fall out of it.
Forks happen via commands
In a system built on conta-command, every state change is a Command.
A fork is no exception: it’s just a particular kind of command — one that takes a ForkSource as input and produces (potentially many) child commands as a side effect.
The library expresses this in two places:
ForkEnabled-
The marker for commands that initiate a fork. Its single method
getForkFrom()exposes the source the fork is starting from. ForkContext.spawnedBy()-
The triggering command, carried along through the operation.
ForkContext.toSpawnedByRef()renders it ascmd:<uuid>, which downstream code can stamp onto audit fields of every entity produced by the fork.
The pay-off is auditability: given any forked entity, you can answer "which command made this?" by reading its lineage and the stamped command reference.
Has the source changed since we forked?
A fork is a snapshot — it captures the source as it was at one moment. The source can keep evolving afterwards. Two questions naturally follow:
-
Has any change been applied to the source since we forked from it?
-
If yes, should the same change be applied here as well?
The library doesn’t answer either question on its own — but it gives you the primitives to answer them in your domain code.
What’s recorded
-
ForkSource.forkedAt— the timestamp of the fork. -
ForkSource.identifier— theSourceIdentifierof the source entity. -
ForkContext.toSpawnedByRef()— the command that drove the fork, ascmd:<uuid>. Stamped onto each forked entity if you wire it through.
What you build on top
If your application persists every command (see command persistence), you can answer questions like:
-
"Commands that touched the source after
forkedAt`" — query the store, scoped by `ForkSource.identifier.uuid1(). -
"Was this forked entity itself modified later?" — same query against the forked entity’s identifier.
-
"Diff between source-now and source-at-fork" — by re-projecting the source from its commands up to and after
forkedAt.
For example, listing later edits to the source ninja might look like:
select cmd_uuid, executed_at, payload
from command_store
where target_uuid = :sourceNinjaUuid -- ForkSource.identifier.uuid1()
and executed_at > :forkedAt -- ForkSource.forkedAt
order by executed_at;
The library deliberately does not auto-apply later source changes onto the fork, nor detect conflicts between concurrent edits — those are domain decisions. Sometimes a forward-port is desirable (mid-cycle correction propagates onward), sometimes the fork is meant to be a frozen snapshot for filing or compliance. The library’s job is to record enough lineage that the consumer can build whichever propagation policy fits.