OCLP Core Specification¶
Status: Experimental draft 0.3 (0.3.0-draft).
1. Purpose and conformance language¶
OCLP specifies a durable, typed description of a computation and its lifecycle. It lets a producer describe a reusable computation, each concrete execution of it, the selected implementation, inputs and outputs, and checks performed on those records. It does not define a workflow language, scheduler, storage service, container format, or domain-specific semantics.
The key words MUST, MUST NOT, SHOULD, and MAY in this document
are normative. A core record is one of artifact, artifact_set,
computation, execution, evidence, or event. Producers MUST emit
records that satisfy the applicable rules below. Consumers MUST reject unknown
fields and invalid values, and MUST preserve the distinction between an opaque
record UUID, an Artifact payload digest, and catalog-local integrity metadata.
The published JSON Schemas and cross-language conformance vectors are derived, executable conformance artifacts. They do not replace the field semantics defined here. SDKs, including the Python reference implementation, are implementations of this specification and MUST NOT define additional protocol meaning.
2. Design rationale (non-normative)¶
This section explains the consequential design choices in this draft. It does not alter the normative requirements in the preceding sections.
| Decision | Rationale and consequence |
|---|---|
| Core UUIDs and Artifact payload digests are separate. | Each Core record receives one opaque UUID and never has revisions under that identity. Artifact payload SHA-256 identifies described bytes independently of record metadata. Names and annotations carry producer semantics rather than becoming reference keys. |
| Canonical record hashes are catalog integrity data. | RFC 8785 gives implementations a reproducible byte representation that a catalog or bundle can verify. That hash is not embedded in parent-record references, avoiding a second identity layer and reference/cycle confusion. |
| Core objects are closed and extension data is bounded. | Permissive top-level fields make independently produced records ambiguous and difficult to validate. Namespaced extension objects retain local flexibility while keeping the portable core legible. |
| A Computation and Execution are distinct; an Execution is one actual run. | A reusable computation is not a particular run with concrete inputs. Every retry, migration, or re-run is a new Execution. OCLP therefore does not create a second Attempt identity beneath Execution; producers preserve retry relationships through parentage, annotations, or producer-defined Events when needed. |
| Evidence carries its source-bound evaluator directly. | A clean runtime exit and an evaluated quality or release gate are different claims. A Computation declares the evaluator implementations required for success, while Evidence records each evaluator's actual outcome. This avoids a separate naming record for a fact that Evidence already represents. Core validates the binding and outcome, not the evaluator's domain logic. |
| Derivation is a DAG, while references and audit facts are not. | Scheduling, cache invalidation, and human lineage views need a topological order. Input and output bindings therefore form an acyclic Artifact/ArtifactSet-to-Execution graph; Events, Evidence, annotations, and collections remain flexible overlays rather than hidden derivation edges. |
| Execution parentage is explicit and separate from derivation. | A parent flow can orchestrate child Executions without claiming their outputs as its own. The execution hierarchy supports scheduler and human views while leaving the Artifact/ArtifactSet-to-Execution derivation DAG acyclic. |
| Every Implementation declares an explicit source basis; a dirty Git overlay is bound to that basis. | Consumers must be able to distinguish Git source, a bound package Artifact, a versioned service, and unavailable provenance. A Git commit is the reviewed baseline; an optional, exact ArtifactSet overlay makes source edits content-addressable without pretending to resolve a whole dependency closure. Machine-local checkout facts remain on Events. |
| Diagnostics are a shared typed value, not an application-specific detail shape. | Events describe execution state and Evidence describes evaluator results; both can carry the same compact code, message, stage, and optional detail Artifact. Consumers can display those fields without learning a producer's private JSON conventions. |
| ArtifactSet is logical and non-nested in draft 0.3. | Releases need a durable named collection, but archive formats, directory layouts, and recursive collection semantics are storage concerns. A flat UUID-member list is simple to traverse and can be composed by publishing another explicit set or profile later. |
| Profiles compose rather than extend Core records. | Datasets, agents, model services, and MCP tools need richer domain semantics, but not every OCLP consumer should implement them. Explicit profile declarations and dependencies make those layers interoperable without turning Core into a domain framework. |
These choices favor durable auditability and cross-language traversal over implicit runtime behavior. The dogfood implementations and conformance corpus are expected to reveal where their costs outweigh their benefits before 1.0.
3. JSON and canonical form¶
Records use the I-JSON data model. Strings are JSON strings; arrays are ordered;
objects have string keys; integer values have no fractional component. Values in
annotations, parameters, details, and data MAY be any JSON value.
profiles is always either null or a non-empty JSON object whose values are
JSON objects.
Draft 0.3 uses RFC 8785 JSON Canonicalization Scheme (JCS) to produce canonical record bytes. YAML MAY be an authoring format, but it MUST first be converted to JSON before validation or hashing. Protocol Buffer bindings, if introduced, are not canonical record bytes.
The tables below describe accepted input. A field marked default may be
omitted on input; the default is present in the expanded canonical record. A
field marked optional is omitted from canonical output when absent or null.
kind and oclp_version have protocol defaults to make compact authored
records unambiguous, but producers SHOULD emit them explicitly when
interchanging raw JSON. A consumer that expands defaults MUST use the values
stated here before canonicalizing. An implementation MAY require explicit
discriminators at a parsing boundary, provided its serializer emits the same
canonical record.
All record and value-object objects are closed: fields not defined by this
specification are invalid. Use annotations for extension data until a
profile or later draft defines a field.
4. Shared values and core envelope¶
4.1 Digest¶
A Digest identifies immutable Artifact payload bytes.
| Field | Input status and JSON type | Constraints and use |
|---|---|---|
algorithm |
default; string | MUST be "sha256". Its explicit label leaves room for a future algorithm migration. |
value |
required; string | Exactly 64 lowercase hexadecimal characters: the SHA-256 digest, without an algorithm prefix. |
An Artifact's digest hashes its described content bytes. Implementations MAY
also hash canonical Core-record bytes for catalog integrity, but that hash is
not a Core field or a reference target.
4.2 RecordReference¶
A RecordReference names another OCLP record.
| Field | Input status and JSON type | Constraints and use |
|---|---|---|
id |
required; UUID string | The opaque UUID of one Core record. It is the only Core-record lookup and reference key. |
References do not carry canonical-record hashes. A storage implementation MAY verify its local canonical bytes independently before returning a record.
4.3 Record resolution¶
Core records are portable descriptions, not a storage API. An implementation
MAY provide a record resolver, registry, bundle reader, or other lookup service
for RecordReference values. Such a service does not change record meaning.
A resolver MUST resolve the UUID to exactly one Core record and reject an absent, malformed, or duplicate binding. A resolver MAY verify a catalog-local canonical-record hash after parsing, but that integrity mechanism does not alter the protocol reference.
Resolving an Artifact record is distinct from retrieving its content bytes. A resolver MAY maintain current storage-location hints indexed by an Artifact's content digest, but those hints are implementation metadata rather than Core record fields. A consumer that retrieves bytes MUST verify the bytes against the Artifact content digest before treating them as the bound Artifact.
4.4 Core record envelope¶
Every core record has this envelope. The record-specific table adds its fields.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
oclp_version |
default; string | MUST be "0.3.0-draft". It selects the core vocabulary and validation rules. |
kind |
default; string | One of the record-kind constants stated below. It discriminates the record shape. |
id |
required; UUID string | Opaque, globally unique identity for this one immutable record. A changed record MUST receive a fresh UUID. |
name |
optional; string | Non-empty, producer-supplied concise human-readable label. It is not an identity, unique key, or reference target. A consumer MAY display it. |
description |
optional; string | Non-empty plain-text human-readable explanation of the record's purpose, interpretation, or intended use. It is longer-form metadata than name, not a markup-rendering contract, identity, unique key, or reference target. |
profiles |
default; null or non-empty object |
A producer MUST emit null when no profile applies. Otherwise keys are non-empty Profile IDs and each value is a profile-owned JSON object. A key claims that the record follows that profile's binding rules. Core validates only this container shape; a profile consumer validates the named value. An empty object is invalid. |
annotations |
default; object | Empty object by default. Producer-defined JSON extension data. Keys SHOULD be namespaced, for example "example.org/owner". Annotations do not claim a normative profile contract. |
Core-record identity and Artifact payload identity are deliberately separate.
A record name, when present, is a concise human-facing label; description
is longer-form plain-text explanation; and annotations carry producer-defined
structured semantics. They are immutable metadata, not mutable registry aliases
or substitutes for identity. A supplied description participates in canonical
record bytes; changing it creates a distinct immutable record that MUST receive
a fresh UUID.
4.5 PortDefinition¶
A PortDefinition declares an input or output interface of a Computation.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
name |
required; string | Non-empty port name used as the key in an Execution's inputs or outputs. |
cardinality |
default; string | "one" or "many"; default "one". It declares whether the application interface expects one or multiple values. |
required |
default; boolean | Default true. It distinguishes an optional interface port from a port that must be bound for a successful execution. |
media_types |
default; array of strings | Empty array by default. Acceptable media types, if the Computation declares them. Empty means no media-type restriction is declared by the core record. |
4.6 ParameterDefinition¶
A ParameterDefinition declares one non-Artifact argument in a Computation interface. It is deliberately distinct from a PortDefinition: ports bind durable Artifacts or ArtifactSets, while parameters bind small JSON values such as a fold count, locale, or execution mode.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
name |
required; string | Non-empty parameter name used as the key in an Execution's parameters. A name MUST be unique within the Computation and MUST NOT overlap an input-port name. |
schema |
required; object | A JSON Schema subschema that describes the parameter value. Its standard vocabulary, including type, enum, default, and description, avoids an OCLP-specific type DSL and remains usable across languages. |
required |
default; boolean | Default true. When false, the Computation accepts an Execution without a concrete value; a JSON Schema default, if supplied, describes the implementation's effective default. |
Parameter declarations describe the reusable interface, not a particular
language's calling syntax. A producer MUST represent durable content consumed
by a Computation as an input-port Artifact or ArtifactSet rather than copying
that content into parameters.
4.7 Implementation¶
An Implementation tells a consumer what executable realization a Computation selects. It is descriptive: the protocol does not require a consumer to fetch or execute it.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
kind |
required; string | "python-callable", "container", "command", or "other". It makes the locator interpretable without prescribing one runtime. |
locator |
required; string | Non-empty runtime-specific location, such as an import target, image name, or command identifier. It is not itself immutable. |
source |
required; ImplementationSource | The declared basis for this implementation. It is a discriminated GitSource, ArtifactSource, ServiceSource, or OpaqueSource; it MUST NOT be omitted. |
digest |
optional; Digest | A runtime fingerprint, such as an image digest or implementation hash. Its exact semantics are declared by the producer. A producer MUST omit it when it would merely restate the linked Artifact's content digest. |
artifact |
optional; RecordReference | An Artifact representing code or a runtime package, such as a source bundle, wheel, or container manifest. |
source, digest, and artifact identify distinct concerns. source
declares where the implementation comes from; digest is a producer-defined
runtime fingerprint; and artifact can make separately selected package or
runtime bytes available as an ordinary Artifact. Producers MUST NOT represent
an ad-hoc selected-file hash as a source bundle merely to approximate dependency
closure. If the runtime fingerprint is simply the linked Artifact's content
digest, producers MUST omit digest; consumers resolve the Artifact record to
obtain that content identity. The Artifact record is selected by its UUID,
which is distinct from the Artifact's payload-content digest.
GitSource¶
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
kind |
default; string | MUST be "git". |
repository |
required; string | Non-empty canonical repository location or identifier selected by the producer. |
commit |
required; string | A complete, lowercase hexadecimal Git object ID: 40 characters for SHA-1 repositories or 64 characters for SHA-256 repositories. A branch, tag, or abbreviated hash is invalid. |
path |
default; string | Repository-relative source or build-context path. Default ".". |
dirty |
default; boolean | true when the source was observed from a checkout with uncommitted changes relative to commit; default false. It makes the incomplete source basis explicit rather than forbidding development observations. |
overlay |
optional; RecordReference | An exact ArtifactSet describing uncommitted source changes relative to commit. Omit it when the selected source is exactly the Git commit. |
repository identifies the canonical source project, not an execution-local
checkout path or merely a configured remote name. A Git commit describes the
reviewed base revision. A dirty: true source is valid provenance: it reports
that the observed implementation may differ from that base and MUST NOT be
treated as reproducible from the commit alone. When overlay is present,
dirty MUST be true; the Git source basis is then the commit plus that
immutable overlay and produces a distinct Computation revision. An overlay is a
bounded source delta, not an inferred dependency closure: a producer SHOULD
include a binary Git patch for tracked changes and MAY include selected
untracked source files. Ignored/generated files and secrets MUST NOT be
captured implicitly. Runtime configuration and dependencies belong in their own
input Artifacts or profiles. A Git source does not claim to identify every
runtime dependency or the checkout used by one Execution.
ArtifactSource¶
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
kind |
default; string | MUST be "artifact". |
artifact |
required; RecordReference | An Artifact such as a wheel, container manifest, or intentional source archive. |
ServiceSource¶
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
kind |
default; string | MUST be "service". |
locator |
required; string | Non-empty service identity or endpoint selected by the producer. |
version |
required; string | Non-empty provider or deployment version. |
OpaqueSource¶
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
kind |
default; string | MUST be "opaque". |
reason |
required; string | Non-empty explanation for why a stronger source basis is unavailable. It makes the provenance limitation explicit. |
4.8 Diagnostic¶
A Diagnostic is a compact portable explanation attached to an Event or Evidence. It does not replace a producer's structured detail data or a full log/report Artifact. Its fields let a generic consumer present a useful execution or evaluation summary without interpreting application-owned JSON.
| Field | Input status and JSON type | Constraints and use |
|---|---|---|
code |
optional; string | Non-empty producer-defined machine-readable identifier, such as "input-unavailable" or "validation/duplicate-key". Consumers MUST treat it as an opaque identifier unless they implement the producer's vocabulary. |
message |
optional; string | Non-empty concise human-readable explanation. Producers SHOULD omit secrets and large stack traces. |
stage |
optional; string | Non-empty producer-defined execution or evaluation stage, such as "preflight", "transform", or "validation". It is not a workflow language or a globally enumerated vocabulary. |
artifact |
optional; RecordReference | A durable Artifact containing richer diagnostic material, such as a log, traceback, or structured report. |
At least one Diagnostic field MUST be present. The Diagnostic's artifact, if
present, is a reference to diagnostic content; its own Artifact record and
payload digest remain the integrity boundary for that content.
5. Core records¶
5.1 Artifact (kind: "artifact")¶
An Artifact describes one immutable byte sequence. It is the basic unit for inputs, outputs, code packages, manifests, reports, and other durable content.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
id |
required; UUID string | Opaque identity of this immutable Artifact record. It has no payload or domain semantics. |
media_type |
required; string | Non-empty media type describing the content bytes, normally an IANA or vendor media type. |
digest |
required; Digest | SHA-256 of the exact content bytes. This, rather than a location, establishes content identity. |
size |
required; integer | Non-negative byte count of the content. It supports retrieval checks without reading all bytes. |
created_at |
optional; string (date-time) |
RFC 3339 timestamp with an explicit UTC offset at which the producer created this immutable Artifact record/materialization. It is part of the record revision when supplied. |
locations |
default; array of strings | Empty array by default. Replaceable retrieval hints such as object-store URLs. They MUST NOT determine identity and MAY become stale. |
schema_uri |
optional; string | Identifies a schema or profile governing the content when applicable. It does not validate the bytes by itself. |
The envelope kind MUST be "artifact". Its UUID identifies this immutable
Artifact record; digest identifies its exact payload bytes. Publishing the
same bytes under another UUID or retrieval location does not create different
content. For very large or remote data, an
Artifact MAY describe an immutable manifest or snapshot instead of hashing a
whole live service.
created_at is deliberately narrower than a generic date field. It is not the
source content's original creation time or filesystem mtime, a storage upload
time, a retrieval time, or the time a consumer observed the Artifact. Producers
MUST omit it when they cannot assert their own creation/materialization time.
Availability, retries, and other execution chronology belong in immutable Event
records instead.
5.2 ArtifactSet (kind: "artifact_set")¶
An ArtifactSet is an immutable, named logical collection of exact Artifacts. It is suitable for a release containing a schema, configuration, metrics, and other independently retrievable files. It does not imply an archive, directory, or retrieval layout and it does not nest sets in draft 0.3.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
members |
required; non-empty array of ArtifactSetMember | The ordered collection. Member names MUST be unique; each member MUST reference an Artifact. |
created_at |
optional; string (date-time) |
RFC 3339 timestamp with an explicit UTC offset at which the producer created this immutable named collection. It is part of the record revision when supplied. |
Each ArtifactSetMember has:
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
name |
required; string | Non-empty stable member name within the set. It makes a logical release navigable independent of storage layout. |
artifact |
required; RecordReference | Reference to an Artifact by its UUID. |
role |
optional; string | Non-empty semantic role such as "schema", "configuration", or "metrics". |
required |
default; boolean | Default true. It states whether a consumer needs this member to use the set for its intended purpose. |
ArtifactSet created_at has the same narrow meaning as Artifact created_at:
it describes creation of this exact collection record, not the age of its
members, an archive upload, or later publication. Producers MUST omit it when
that time is unavailable; Events remain the execution chronology.
5.3 Computation (kind: "computation")¶
A Computation declares a reusable computation. It describes what may be executed; it is not a concrete execution.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
implementation |
required; Implementation | The selected executable realization, required source basis, and optional immutable package/runtime binding. |
input_ports |
default; array of PortDefinition | Empty array by default. Declared input interface. Names MUST be unique within this direction. |
output_ports |
default; array of PortDefinition | Empty array by default. Declared output interface. Names MUST be unique within this direction. |
parameter_definitions |
default; array of ParameterDefinition | Empty array by default. Declared JSON-valued argument interface. Names MUST be unique and MUST NOT overlap input_ports. |
required_evidence |
optional; array of Implementation | One or more distinct source-bound evaluator implementations that must each produce passing Evidence before an Execution can claim status: "succeeded". Omit it when the Computation has no Core-level acceptance requirements. |
The same port name MAY appear once among inputs and once among outputs because the directions are separate namespaces. A Computation UUID identifies one immutable interface and source basis. Port and parameter declarations express the intended interface. In a resolved record collection, an Execution's parameter keys MUST be declared by its selected Computation; every required declared parameter MUST be present and its value MUST validate against the declared JSON Schema. A runtime MAY validate those rules before publication, but a consumer validating a resolved collection MUST reject a violated binding.
required_evidence are success gates, not a second lifecycle mechanism.
It applies only when an Event claims an Execution succeeded. An Execution can
finish its runtime work yet fail, error, or omit an acceptance check; in that
case its terminal Event MUST NOT claim status: "succeeded". Producers SHOULD
publish the Evidence that satisfies every required evaluator before the
successful terminal Event. A Computation without required_evidence makes no Core-level
acceptance claim beyond its lifecycle status.
Core does not prescribe evaluator scheduling or short-circuit behavior. An implementation MAY stop once success is impossible, but it SHOULD evaluate and publish every declared evaluator when practical so operators receive a complete diagnostic picture. Regardless of strategy, a successful terminal Event still requires every declared evaluator to have passed.
5.4 Execution (kind: "execution")¶
An Execution is one durable, concrete run of one Computation with parameter, input, and output bindings. A retry, migration, or rerun MUST be a separate Execution; OCLP does not define a nested Attempt record.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
computation |
required; RecordReference | Computation being executed. Its UUID identifies one immutable Computation record. |
parent_execution |
optional; RecordReference | The Execution that directly orchestrated this Execution. It is an execution-hierarchy relationship, not an input, output, or derivation edge. It MUST resolve to an Execution when the surrounding record collection is resolved. |
parameters |
default; object | Empty object by default. Concrete JSON values bound by name to the selected Computation's parameter_definitions. Parameter keys MUST be declared, required definitions MUST be present, and values MUST validate against their declared JSON Schema when the referenced Computation is resolved. |
inputs |
default; object of arrays of RecordReference | Empty object by default. Keys are declared input-port names; each value is an ordered list of direct Artifact or ArtifactSet references bound at execution time. An ArtifactSet input records use of the exact named package; its members remain a collection overlay rather than individual derivation edges. |
outputs |
optional; object of arrays of RecordReference | Keys are declared output-port names; each value is an ordered list of direct Artifact or ArtifactSet results. A producer MUST bind every durable direct result it publishes for the Execution. An ArtifactSet output records that this Execution published the exact named package; its member references remain an overlay, not a second derivation path. |
requested_outputs |
default; array of strings | Empty array by default. Names of outputs requested by the caller. It records intent, not proof of publication. |
outputs is the durable derivation binding; it is distinct from
requested_outputs, which records caller intent. A lifecycle Event MAY repeat
output references to record an operational publication fact, but Event data
MUST NOT be the only durable output binding for a published Artifact or
ArtifactSet.
parent_execution forms an optional execution hierarchy. A child has at most
one direct parent; a parent may have many children. A resolved hierarchy MUST
be acyclic. Parentage MUST NOT be interpreted as a data-production claim or be
included in derivation-DAG validation. This permits a parent to publish a
manifest Artifact containing child records while each child uses the parent's
UUID reference.
5.5 Evidence (kind: "evidence")¶
Evidence records the result of applying a source-bound evaluator to a subject
record. The outcome states the evaluation result; an optional Diagnostic gives
a compact portable explanation, while details retains domain-specific data.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
subject |
required; RecordReference | Record checked by the evaluator. Its UUID identifies one immutable subject record. |
evaluator |
required; Implementation | The exact evaluator realization and required source basis. Its locator identifies an executable evaluator, command, service, or another implementation form; Core does not impose the evaluator's input or result DSL. |
outcome |
required; string | "pass", "fail", or "error". "error" means the evaluation could not complete or produce a reliable result. |
observed_at |
required; string, date-time |
Time at which the result was observed. Use an RFC 3339 timestamp with an offset for portable interchange. |
diagnostic |
optional; Diagnostic | A compact code, message, stage, or rich-detail Artifact reference associated with this evaluator result. It MUST NOT be used to redefine outcome. |
details |
default; object | Empty object by default. Domain-specific evaluation data, including a richer status such as a warning, without extending the core outcome vocabulary. Generic consumers MUST NOT infer portable diagnostic semantics from it. |
An Evidence record is the complete portable validation claim: it identifies the
subject, the exact evaluator implementation, when the evaluator observed the
subject, and the resulting outcome. The source and optional runtime/package
bindings in evaluator distinguish revisions without a second validation record.
5.6 Event (kind: "event")¶
An Event records an observed durable fact about an Execution. The event
vocabulary is intentionally extensible; producers SHOULD
document their event types and their data shape.
| Field | Input status and JSON type | Constraints and rationale |
|---|---|---|
execution |
required; RecordReference | Execution to which the fact belongs. |
event_type |
required; string | Non-empty producer-defined event name, such as "outputs-published". It identifies the meaning of data. |
occurred_at |
required; string, date-time |
Time the event fact occurred. Use an RFC 3339 timestamp with an offset for portable interchange. |
sequence |
required; integer | Non-negative sequence number. Events for one Execution are ordered by this value; producers MUST NOT give two distinct Events for an Execution the same sequence. |
runtime |
optional; ExecutionContext | Execution-local observations. A producer SHOULD attach the checkout observed for an Execution to its execution-started Event rather than put machine-specific facts in the Computation. A producer that needs portable runtime/configuration provenance SHOULD bind an execution-context profile to the Execution. |
status |
optional; string | The terminal execution status: "succeeded", "failed", or "skipped". A producer MUST use it only on an Event that reports a terminal Execution result. Its absence means the Event does not make a portable terminal-status claim. |
diagnostic |
optional; Diagnostic | A compact code, message, stage, or rich-detail Artifact reference associated with this Event. It commonly explains a failed or skipped terminal event, but MAY also annotate another notable lifecycle observation. |
data |
default; object | Empty object by default. JSON event payload. For an output-publication event, it SHOULD name the published Artifact references. |
ExecutionContext.git_checkout, when present, records a Git worktree, full
observed commit, and dirty state. The worktree is a local URI or locator and
MAY be omitted when it would disclose sensitive machine layout. It is distinct
from GitSource.repository: the former says where this Execution ran; the latter
names the portable source project selected by the Computation.
status describes an Execution and belongs on an Event; it is distinct from
Evidence outcome, which describes an evaluator result. A failed execution
MAY also publish Evidence, but a consumer MUST NOT require Evidence in order to
identify the execution state. If the selected Computation declares
required_evidence, however, a terminal status: "succeeded" claim MUST
have Evidence for every declared evaluator with outcome: "pass". A producer MAY define its
event-type vocabulary through a profile; Core does not reserve event-type
strings.
6. Lineage and publication invariants¶
Lineage is derived from explicit bindings, not from a separate mutable graph. The derivation graph contains Artifact, ArtifactSet, and Execution nodes:
The Computation binding, implementation Artifact and Git source overlay,
Execution parentage, ArtifactSet membership, Evidence, Events, profile
content, annotations, and arbitrary Event data are
reference or audit overlays, not derivation edges. They MAY be traversed by
consumers, but do not participate in derivation-DAG validation.
Draft 0.3 establishes these invariants:
- Published Artifacts and ArtifactSets are immutable.
- Execution input bindings do not change after execution begins.
- Execution output bindings do not change after publication.
- In a resolved record collection, every Execution Computation, input, and output reference used for derivation MUST resolve by UUID. Inputs MUST resolve to Artifacts or ArtifactSets. Outputs MUST resolve to Artifacts or ArtifactSets.
- The derivation graph MUST be acyclic. A consumer validating a resolved record collection MUST reject a missing binding, a wrong-kind binding, or a cycle.
- Each retry, migration, or rerun is a distinct Execution; an Execution has no separate Attempt identity.
- A terminal Event that claims
status: "succeeded"for an Execution whose Computation declaresrequired_evidenceMUST be accompanied in the resolved record collection by Evidence that references the exact Execution UUID, names every declared evaluator, and hasoutcome: "pass". A producer SHOULD publish that Evidence before the successful terminal Event. - Mutable names such as
latestorcurrentare retrieval references, never artifact identities. - Replaying an already accepted event MUST be idempotent.
- In a resolved Execution hierarchy, every
parent_executionMUST resolve to an Execution and the hierarchy MUST be acyclic. It is validated independently from the derivation graph. - In a resolved record collection, every Execution parameter key MUST be a ParameterDefinition on its selected Computation; required definitions MUST be bound and every bound value MUST validate against the declared JSON Schema.
Implementations MAY build indexes for traversal, but those indexes are not canonical protocol truth and MUST be rebuildable from immutable records.
7. Extensions and profiles¶
Unknown top-level fields are invalid. Producers SHOULD put experimental,
namespaced extension data under annotations. A profile is a versioned,
optional layer of normative specifications that composes with this Core. It
adds a bounded interoperability contract for one concern—such as dataset
snapshots or agent execution—without changing the Core record vocabulary.
The Core-owned profiles field is the standard claim surface for a profile
that applies to a Core record. It is null when no profile applies and a
non-empty object otherwise. Its keys are Profile IDs and its values are the
binding objects defined by those profiles. The key already identifies the
profile, so a binding object MUST NOT need to repeat that ID. annotations
remain free-form producer metadata and MUST NOT by themselves claim a profile.
7.1 Profile declaration¶
A published profile specification MUST declare all of the following:
| Declaration | Requirement |
|---|---|
| Profile ID | A non-empty stable identifier, unique within the profile publisher's namespace. When a profile binds to a Core record, this is its key in that record's profiles object. A profile Artifact MAY also carry it in a profile-defined oclp_profile field. |
| Profile version | A non-empty version identifier. A profile version is independent of the OCLP Core version. |
| Core compatibility | The OCLP Core version or versions for which the profile is defined. |
| Dependencies | The exact profile IDs and compatible versions on which it depends, or an explicit declaration that it has none. |
| Extension surfaces | The Core locations whose content it defines: an Artifact's bytes, a named Event data payload, a profiles binding object, or namespaced keys within an existing JSON extension object. |
| Conformance package | A normative profile specification, published schema or schemas where applicable, and valid/invalid vectors with canonical bytes and digests whenever the profile defines canonical JSON. |
The normative profile specification is authoritative. Schemas, vectors, and SDK bindings are derived conformance artifacts.
7.2 Profile surfaces¶
A profile MAY define one or more of these surfaces:
- Profile binding. It defines the value at
profiles[profile-id]for one or more Core record kinds. The binding object MUST declare the profile version when the profile has more than one version. A consumer MUST apply that profile only after validating this binding object. - Artifact content. It defines an Artifact payload format and MUST declare
the required
media_type. It SHOULD declare the requiredschema_uri. The profile MUST state whether the Artifact digest hashes the payload bytes, a canonical manifest, or another bounded immutable representation. - Event convention. It defines one or more
event_typevalues and the schema and semantics of theirdataobjects. It MUST state whether event ordering, Execution binding, or referenced Artifacts are required. - Extension-object convention. It defines namespaced keys and value shapes
within
annotations,parameters,details, ordata. It MUST NOT assign meaning to an unnamespaced key outside a profile-owned object.
A profile MUST NOT add arbitrary top-level fields to a Core record, weaken a Core invariant, redefine a Core field, or require a consumer that does not claim that profile to implement its domain behavior.
7.3 Composition¶
Profiles compose by explicit dependency, not by implicit convention. A profile that relies on another profile MUST declare its dependency and the compatible version or versions. A producer MAY apply independent profiles to the same computation graph when their declared surfaces do not conflict. A consumer claims support for a profile only when it implements that profile's conformance package and all declared dependencies.
Core-only consumers MAY retain, index, and traverse profile-bearing records without understanding profile semantics. They MUST continue to enforce Core validation and integrity rules. A profile consumer MUST reject a record or payload that claims the profile but violates its declared schema or semantic rules.
OCLP Core owns this framework but no domain profile definitions. Profile publishers independently own their specifications, schemas, fixtures, and semantic verifiers. An OCLP-maintained profile catalog may provide optional dataset, execution, or lifecycle profiles without making them Core requirements.
8. Conformance¶
A draft-0.3 producer is conformant when its emitted core records validate against the published core JSON Schema and satisfy this specification. A consumer is conformant when it accepts every valid fixture, rejects every invalid fixture, and reproduces published JCS canonical JSON and catalog integrity digests for the digest vectors. Runtime behavior and scheduler interoperability are intentionally outside draft-0.3 conformance.