ExtractionRun

class ExtractionRun constructor(val contextId: <Error class: unknown class>, val lineage: ExtractionRunLineage, val status: ExtractionRunStatus, val startedAt: Instant, val finishedAt: Instant? = null, val profile: ExtractionContentProfileRef? = null, sourceRevisions: List<SourceRevisionRef> = emptyList(), val fingerprints: ExtractionRunFingerprints = ExtractionRunFingerprints(), val runtime: ExtractionRuntimeIdentity = ExtractionRuntimeIdentity(), val requestedModel: ExtractionRequestedModelConfig? = null, val subjectRefs: ExtractionRunSubjectRefs = ExtractionRunSubjectRefs(), val experimentRef: ExtractionExperimentRef? = null, val cohortRef: ExtractionCohortRef? = null, val replayFidelity: ExtractionReplayFidelity = ExtractionReplayFidelity.NONE, val counts: ExtractionRunCounts = ExtractionRunCounts(), invocations: List<ExtractionInvocationRecord> = emptyList(), failures: List<ExtractionFailure> = emptyList(), val version: Long = 0)

The durable record of one extraction execution.

A run answers "what produced this claim, under what, and how did it go?" — the profile and prompt and schema versions in force, which revisions of which sources were read, which model was asked for and what the provider reported back, how far it got, and what went wrong. It is the header; the propositions it produced are attributed to it by a separate relation, and source grounding stays what it was.

Two rules shape the type.

The first is that requested and observed are different types. What a run asked a model for is requestedModel, one ExtractionRequestedModelConfig on the header. What actually happened is an ExtractionInvocationRecord per attempt, holding usage, timing, the service it went to, and whatever the provider reported. An invocation record has no field that can hold a requested value, so nothing can quietly present a setting as an observation.

The second is that the run holds no content. No prompts, no source text, no responses, no user or session objects, no provider SDK payloads, no extension maps. What a host would have needed those for is covered by digests it can compare (fingerprints) and by bounded pseudonymous tokens it can group by (subjectRefs). Failures are said in a closed vocabulary of codes, stages and numbers, so there is no text field on a run for an exception message to land in.

What is not decided here. Which status transitions are legal, which are compare-and-set, and what a store does with a repeated terminal write belong to the run store contract in the next slice. This type checks that a finish does not precede a start and stops there; it does not require, for instance, that a ExtractionRunStatus.COMPLETED run has a finishedAt, so the state machine defines that once instead of twice.

Collections are copied on the way in, always, including empty ones — an empty mutable list a caller keeps a handle on is the same aliasing bug as a full one, and it fails later and stranger. The copies are unmodifiable, so the run a caller reads back cannot be edited through the list either.

This is a plain class rather than a data class on purpose. A data class has to declare its collection parameters as properties, which means the field is the caller's list and there is nowhere to copy it; its generated copy and componentN methods would also pin an ABI across eighteen fields while #67 is still moving. Equality and hash are written out over every component instead.

EXPERIMENTAL. The shape may still change while extraction runs (DICE #67) land.

Constructors

Link copied to clipboard
constructor(contextId: <Error class: unknown class>, lineage: ExtractionRunLineage, status: ExtractionRunStatus, startedAt: Instant, finishedAt: Instant? = null, profile: ExtractionContentProfileRef? = null, sourceRevisions: List<SourceRevisionRef> = emptyList(), fingerprints: ExtractionRunFingerprints = ExtractionRunFingerprints(), runtime: ExtractionRuntimeIdentity = ExtractionRuntimeIdentity(), requestedModel: ExtractionRequestedModelConfig? = null, subjectRefs: ExtractionRunSubjectRefs = ExtractionRunSubjectRefs(), experimentRef: ExtractionExperimentRef? = null, cohortRef: ExtractionCohortRef? = null, replayFidelity: ExtractionReplayFidelity = ExtractionReplayFidelity.NONE, counts: ExtractionRunCounts = ExtractionRunCounts(), invocations: List<ExtractionInvocationRecord> = emptyList(), failures: List<ExtractionFailure> = emptyList(), version: Long = 0)

Types

Link copied to clipboard
object Companion

Properties

Link copied to clipboard

The arm within that experiment

Link copied to clipboard
val contextId: <Error class: unknown class>

The tenant that owns this run

Link copied to clipboard

How much the run got through

Link copied to clipboard

The experiment this run belongs to

Link copied to clipboard

What went wrong, bounded and said in the failure vocabulary.

Link copied to clipboard

Digests of the prompt, schema and metamodel in force

Link copied to clipboard
val finishedAt: Instant? = null

When it reached a terminal state, or null while it has not

Link copied to clipboard

One record per attempt at each planned call, always in plan order: call 0 before call 1, and within a call, first attempt before second.

Link copied to clipboard

True when this run starts its lineage.

Link copied to clipboard

This run's reference, its root, its parent, what it supersedes, and its pass

Link copied to clipboard

The run this one continues from, or null.

Link copied to clipboard

The content profile version in force

Link copied to clipboard

This run's reference.

Link copied to clipboard

How much of this run someone could set up again from what it recorded

Link copied to clipboard

What the run asked a model for

Link copied to clipboard

The oldest run in this run's lineage, which is ref itself when this run has no parent.

Link copied to clipboard

What code ran it, and where

Link copied to clipboard

Which revisions of which sources this run read, in order.

Link copied to clipboard

When the run began

Link copied to clipboard

Where the run stands

Link copied to clipboard

Pseudonymous references to whose work this was

Link copied to clipboard
val version: Long = 0

The compare-and-set generation ExtractionRunStore.save checks this header against. A run that has never been saved, and the run its first accepted save produces, both carry 0 — the first save inserts the row, and there is no earlier generation for it to raise past. A store rejects a first save naming any other value. Every later save save accepts that actually changes the header raises it by one; a save whose content already matches what is stored is accepted too, as a no-op replay, and leaves the generation exactly where it stood. ExtractionRunStore.recordInvocation never changes it, since an invocation record writes a child row of its own — and ExtractionRunTransition.applyTo carries whatever value the run already has, because a terminal run takes no more saves and nothing compares its version again

Functions

Link copied to clipboard

Every attempt at the call at invocationIndex, earliest attempt first.

Link copied to clipboard
open operator override fun equals(other: Any?): Boolean
Link copied to clipboard

The tenant id as a plain string, for Java callers, since ContextId is a value class.

Link copied to clipboard
open override fun hashCode(): Int
Link copied to clipboard

The invocation records ordered by the plan: call 0 before call 1, and within a call, first attempt before second.

Link copied to clipboard

The tenant-qualified identity a store keys this run on.

Link copied to clipboard
open override fun toString(): String

A summary: identity, lineage, state, and sizes.