RollingSink

Moved here from the implementations package, because it is not one.

NullSink, MemorySink and TabularSink are about where rows go — destinations, and genuinely implementations. This is about a sink's lifetime: it makes a fresh delegate per experiment and closes it, which is the beginExperiment/endExperiment protocol TransitionSink already defines. It is a decorator over the contract with no knowledge of any destination, and it belongs beside the contract.

It also had to move. captureTo in the declaration DSL attaches one, so while this lived downstream the element referred to the implementations package by fully-qualified name — a real compile-time dependency in both directions, and exactly the cycle §7.2 claims is inverted. The layering test could not see it, because it inspected imports and a qualified name is not one.

A sink that makes a fresh delegate for every experiment and closes it when that experiment ends (§4.8.2).

What it is for

A durable sink writes an artifact, and an artifact belongs to one run. TabularSink names its file from the provenance — which carries the experiment name — precisely so that §4.9's k-rule comparison, which runs one model k times under k policies, leaves k trajectories instead of overwriting one. A single long-lived TabularSink attached across those k runs cannot do that: its file was chosen before the first run.

So the per-experiment factory survives — as a sink, rather than as a second mechanism on the element. DecisionElement has exactly one way to be captured (attach a sink), and "a new file each run" is an ordinary decorator over it, the way ksl.animation layers ReplicationSelectingSink and WindowedAnimationSink over its base sinks. captureTo in the builder DSL is one line that attaches one of these.

Ownership

This sink DID construct its delegate, so this sink closes it — at endExperiment, not at close, because the delegate's life is the run's. close is idempotent and releases a delegate only if a run was cut short before endExperiment arrived.

Constructors

Link copied to clipboard
constructor(factory: (RunProvenance) -> TransitionSink)

Properties

Link copied to clipboard

The delegate for the run in progress, or null between runs. For tests and diagnostics.

Functions

Link copied to clipboard
open override fun beginExperiment(provenance: RunProvenance)

A run is beginning. Called once per experiment, per attachment, before any write.

Link copied to clipboard
open override fun close()
Link copied to clipboard
open override fun endExperiment()

The run is over and no further write will arrive for it. Flush here. The sink may be told beginExperiment again for the next run — attachments outlive experiments.

Link copied to clipboard
open override fun write(record: TransitionRecord)