ocpm-engine 1.0.0 product and engineering specification¶
Status: proposed implementation contract
Owner: ocpm-engine maintainers
Target release: 1.0.0
Snapshot date: 2026-08-03
1. Decision¶
ocpm-engine 1.0.0 is a standalone, source-neutral Rust process-mining engine.
It must work against files or in-memory data without PostgreSQL. When a
compatible pg_ocpm provider is configured, the same public operations must
transparently push selective scans, relationship traversal, and sufficient
statistics into PostgreSQL.
The engine is the primary public entry point. Applications, Python clients, and external adapters call the engine, never extension-specific SQL. Provider choice can change the physical plan, latency, memory, and transfer volume, but not result semantics.
This replaces the 0.10 architecture in which OcpmEngine requires an installed
pg_ocpm instance and exposes PostgreSQL capability details in its public
Python API. It preserves the useful 0.10 native kernels and database pushdown,
but makes them implementations of a complete provider contract.
2. Product objective¶
Provide one embeddable OCPM runtime that covers the common operational use cases documented by OCPQ, Rust4PM, and OCPA:
- lossless OCEL and conventional event-log access;
- object-centric filtering, relationship queries, and process executions;
- descriptive discovery and model discovery;
- conformance checking;
- performance enhancement and drift monitoring;
- next-activity, remaining-time, and outcome/risk prediction; and
- stable model/result serialization for applications and LLM tools.
Version 1.0.0 is complete only when every mandatory capability has a local
implementation. pg_ocpm is an accelerator, not a feature gate.
3. Why this architecture is differentiated¶
The differentiation is not Rust alone, SQL alone, or any single mining algorithm. Those all have prior art. The product contribution is the following combination:
- one source-neutral logical OCPM plan and result model;
- equivalent local and PostgreSQL-backed physical providers;
- cost- and capability-aware partitioning of a query between exact data-proximate reduction and stateless Rust algorithms;
- compact sufficient-statistic and factorized relationship exchanges instead of mandatory event-table hydration; and
- first-class plan evidence showing what ran where, how much data moved, and which exact fallback was selected.
No benchmark-specific query IDs, dataset names, expected answers, or result caches may participate in planning or execution.
4. Reference capability baseline¶
The baseline is capability coverage, not source-code or API parity. The three comparison systems below are black-box benchmark labels only. They are not architecture, API, test-fixture, or implementation references. Every engine algorithm must be derived from a peer-reviewed paper listed in the academic provenance ledger and independently engineered in this repository.
| Reference | Required capability signal |
|---|---|
| OCPQ black-box arm | Object-centric querying workloads supported by the peer-reviewed OCPQ paper |
| Rust4PM black-box arm | General process-mining workloads that also have an independent peer-reviewed basis |
| OCPA black-box arm | Object-centric workloads that also have an independent peer-reviewed basis |
5. Current-state gap¶
The 0.10 workspace contains ocpm-core, ocpm-postgres, and ocpm-python.
Its README requires pg_ocpm, and its public Python surface exposes
PgOcpmCapabilities. Native analytics currently include frequency-based DFG
and variant conformance, deterministic next activity, bottleneck ranking, and
frequency drift. The Python planner covers several dynamic PostgreSQL query
shapes, but some paths fully materialize result rows and the process-map planner
supports only one included edge.
Therefore 1.0 is a product-boundary change, not a version-label change.
6. Architecture¶
flowchart TD
A["Rust, Python, or service client"] --> B["ocpm-engine typed API"]
B --> C["Canonical validation and logical planner"]
C --> D["Capability and cost-based physical planner"]
D --> E["Local provider"]
D --> F["Optional pg_ocpm provider"]
E --> G["Streaming events and local indexes"]
F --> H["Exact SQL filters and compact capsules"]
G --> I["Shared discovery, conformance, enhancement, prediction kernels"]
H --> I
I --> J["Canonical results, models, provenance, and execution diagnostics"]
6.1 Workspace crates¶
| Crate | Responsibility |
|---|---|
ocpm-core |
Canonical event, object, relationship, attribute-history, lifecycle, model, error, provenance, and result types |
ocpm-io |
Canonical/OCEL JSON, OCEL SQLite, XES, CSV mapping, validation, import/export, and streaming readers/writers; OCEL 2.0 XML is evidence-deferred |
ocpm-provider |
Provider traits, capability descriptors, logical/physical operators, batches, statistics, and cost estimates |
ocpm-local |
Complete in-memory/file provider, bounded local indexes, spill-to-disk execution, and local sufficient statistics |
ocpm-postgres |
Optional pg_ocpm >= 1.0.0 provider and compatibility fallback for supported 0.x releases |
ocpm-query |
Typed object-centric query AST, validation, logical planning, binding execution, and result labeling |
ocpm-discovery |
DFG/OC-DFG, variants, declarative and procedural discovery |
ocpm-conformance |
Replay, alignment, constraint, and quality metrics |
ocpm-enhancement |
Performance measures, organizational analysis, drift, and anomaly features |
ocpm-prediction |
Leakage-safe features, baseline models, prediction artifacts, scoring, and evaluation |
ocpm-python |
Stable Python bindings over the source-neutral engine API; heavy native work releases the GIL |
Crates may be consolidated during implementation only when the public layering and optional PostgreSQL dependency remain intact.
6.2 Dependency rule¶
All algorithm crates depend on ocpm-core and provider abstractions. None may
depend on ocpm-postgres. ocpm-postgres depends inward on provider and core
contracts. Python and future service adapters depend only on the engine facade.
6.3 Canonical semantics¶
The canonical data model must represent, without loss:
- unique events with stable IDs, activities, nanosecond UTC timestamps, original offset/lexical timestamp provenance, and typed attributes;
- unique objects with stable IDs, object types, and time-varying attributes;
- qualified event-to-object and object-to-object relationships;
- deterministic ordering for equal timestamps using an explicit sequence and stable ID fallback;
- lifecycle transitions without inventing start or completion events; and
- dataset, tenant, schema, source, and transformation provenance.
All time ranges are half-open [start, end) in new 1.0 APIs. Compatibility
adapters must translate the inclusive 0.x PostgreSQL contract explicitly.
Null, absent, empty, and unknown values are distinct. Counts use unsigned
64-bit values unless a format boundary cannot represent them.
7. Public engine contract¶
The Rust facade is the normative API. Python mirrors its requests and results. Names below are binding-level contracts; exact module organization may evolve.
pub enum DataSource {
OcelFile { uri: String, format: OcelFormat },
XesFile { uri: String },
Csv { uri: String, mapping: CsvMapping },
InMemory(CanonicalLog),
Postgres(PostgresSource),
}
pub struct EngineOptions {
pub memory_budget_bytes: u64,
pub temp_directory: Option<String>,
pub max_parallelism: usize,
pub timeout_ms: Option<u64>,
}
impl OcpmEngine {
pub async fn open(source: DataSource, options: EngineOptions) -> Result<Self>;
pub async fn describe(&self, request: DescribeRequest) -> Result<DatasetProfile>;
pub async fn query(&self, request: QueryRequest) -> Result<QueryResult>;
pub async fn discover(&self, request: DiscoveryRequest) -> Result<ModelArtifact>;
pub async fn conformance(&self, request: ConformanceRequest) -> Result<ConformanceResult>;
pub async fn enhance(&self, request: EnhancementRequest) -> Result<EnhancementResult>;
pub async fn predict(&self, request: PredictionRequest) -> Result<PredictionResult>;
pub async fn monitor(&self, request: MonitoringRequest) -> Result<MonitoringResult>;
pub async fn explain(&self, request: ExplainRequest) -> Result<ExecutionPlan>;
}
Every request contains a DatasetView with tenant/dataset identity, time range,
object types, projection rules, and filters. Every result includes semantic
version, deterministic content hash, source watermark, warnings, and execution
diagnostics. Diagnostics identify providers and fallbacks but never alter the
domain result.
The 0.x OcpmEngine(dataset_id, tenant_id) constructor and public
PgOcpmCapabilities type are deprecated for the 1.x compatibility window.
8. Provider and planner contract¶
8.1 Required provider operations¶
Every provider implements streaming or bounded-batch forms of:
trait OcpmProvider {
async fn capabilities(&self) -> ProviderCapabilities;
async fn profile(&self, view: &DatasetView) -> DatasetProfile;
async fn scan_events(&self, plan: EventScan) -> EventBatchStream;
async fn scan_objects(&self, plan: ObjectScan) -> ObjectBatchStream;
async fn scan_e2o(&self, plan: RelationScan) -> E2oBatchStream;
async fn scan_o2o(&self, plan: RelationScan) -> O2oBatchStream;
async fn process_executions(&self, plan: ExecutionPlan) -> ExecutionBatchStream;
async fn aggregate(&self, plan: AggregatePlan) -> AggregateBatchStream;
async fn evaluate_bindings(&self, plan: BindingPlan) -> BindingBatchStream;
}
The local provider implements all operations. The PostgreSQL provider can advertise only operations with exact semantic equivalence and must fall back to bounded canonical streams for everything else.
8.2 Logical operators¶
The initial stable logical operator set is:
- event/object/relation scan;
- activity, type, time, attribute, qualifier, and ID filter;
- temporal ordering and eventually/directly-follows;
- relationship traversal with direction, depth, and cycle semantics;
- group, distinct, count, sum, minimum, maximum, quantile, and histogram;
- process-execution extraction;
- DFG, variant, duration, rework, feature, and time-window aggregation;
- binding join, child-binding count, boolean composition, label, and violation;
- model-kernel invocation; and
- bounded sort, top-k, project, union, and export.
8.3 Planning¶
The physical planner partitions the logical plan using provider capability, estimated cardinality, selectivity, bytes transferred, memory budget, and available parallelism. It may not use dataset names or benchmark query IDs.
explain() returns, for each physical operator: provider, algorithm, input and
estimated output rows/bytes, pushed predicates, fallback reason, materialization
boundary, memory budget, parallelism, and cache generation. Actual diagnostics
add elapsed time, rows, bytes, peak tracked memory, spill bytes, and cancellation
state.
9. Mandatory 1.0 capability matrix¶
Legend: MUST blocks 1.0; SHOULD can ship experimentally behind a stable data
contract but cannot be silently omitted; POST is not part of 1.0.
| Family | Capability | 1.0 | Preferred layer |
|---|---|---|---|
| IO | OCEL JSON and SQLite import/export | MUST | ocpm-io |
| IO | OCEL 2.0 XML import/export | DEFERRED | ocpm-io after eligible peer-reviewed evidence |
| IO | XES import/export and CSV mapping | MUST | ocpm-io |
| IO | Schema/type/qualifier validation and deterministic ordering | MUST | core/IO |
| IO | Incremental append and source watermarks | MUST | provider |
| Views | Flatten/project by object type without losing provenance | MUST | query/provider |
| Views | Connected-component and leading-object process executions | MUST | provider/query |
| Filtering | Time, activity, object type, IDs, attributes, duration, status, qualifiers, and relationships | MUST | query/provider |
| Query | Object/event variables, E2O/O2O, temporal predicates, nested boolean trees, child counts, labels, violations | MUST | query/provider |
| Query | Constraint auto-discovery from a dataset profile | SHOULD | query |
| Descriptive | Counts, activity/start/end profiles, DFG/OC-DFG, linear and graph variants | MUST | provider/discovery |
| Descriptive | Process maps, timelines, throughput, rework, histograms, dotted-chart data | MUST | enhancement |
| Organizational | Resource/activity/case profiles, handover, and workload | MUST | enhancement |
| Discovery | Alpha-class case-centric discovery and inductive process tree | MUST | discovery |
| Discovery | Petri net and OCPN discovery | MUST | discovery |
| Discovery | OC-DECLARE discovery | MUST | discovery |
| Conformance | DFG/variant frequency coverage | MUST | conformance |
| Conformance | Token replay and alignments | MUST | conformance |
| Conformance | OCPN fitness/precision and OC-DECLARE checking | MUST | conformance |
| Conformance | Constraint monitoring with witnesses/violations | MUST | conformance/query |
| Enhancement | Activity/arc frequency and object counts | MUST | provider/enhancement |
| Enhancement | Waiting, service, sojourn, synchronization, pooling, lagging, and flow time | MUST | enhancement |
| Enhancement | Bottlenecks, performance overlays, rework, and time series | MUST | enhancement |
| Monitoring | DFG, variant, activity, and performance drift with localized contributions | MUST | enhancement |
| Prediction | Next activity with ranked calibrated probabilities | MUST | prediction |
| Prediction | Remaining time with interval estimates | MUST | prediction |
| Prediction | Outcome/risk with probabilities and feature provenance | MUST | prediction |
| Prediction | Graph, sequential, and tabular feature encodings | MUST | prediction |
| Models | Canonical JSON, DOT, PNML, and SVG serialization where applicable | MUST | core/discovery |
| Simulation | Stochastic simulation and prescriptive optimization | POST | extension crate/service |
| ML | General-purpose deep-learning training runtime | POST | external adapter |
10. Object-centric query language¶
QueryRequest contains a typed AST, not raw SQL or provider expressions:
pub enum Constraint {
Event(EventPredicate),
Object(ObjectPredicate),
E2o(RelationPredicate),
O2o(RelationPredicate),
Temporal(TemporalPredicate),
ChildCount { child: Box<Constraint>, range: CountRange },
And(Vec<Constraint>),
Or(Vec<Constraint>),
Not(Box<Constraint>),
Label { name: String, child: Box<Constraint> },
}
pub struct QueryRequest {
pub view: DatasetView,
pub variables: Vec<Variable>,
pub constraint: Constraint,
pub output: QueryOutput,
pub limit: Option<u64>,
}
Bindings retain multiplicity, variable identity, qualifiers, and witnesses. Compact factorized results are normative; row expansion is explicit and bounded. The planner may reorder commutative predicates by selectivity but must preserve multiplicity and labels. Result ordering is deterministic.
11. Discovery and conformance contracts¶
DiscoveryRequest.algorithm initially supports Dfg, OcDfg, Alpha,
InductiveProcessTree, PetriNet, ObjectCentricPetriNet, and OcDeclare.
Parameters are typed and versioned. Discovered artifacts record algorithm,
parameters, dataset view hash, source watermark, and implementation version.
ConformanceRequest.method supports FrequencyCoverage, TokenReplay,
Alignment, OcpnQuality, OcDeclare, and Constraints. Results return both
aggregate metrics and bounded per-execution diagnostics. Search-based methods
must accept state, time, and memory limits and report Exact, OptimalWithin,
or Truncated; they may never present a truncated result as exact.
Fitness, precision, generalization, and simplicity definitions are versioned in the result. Model parsers reject ambiguous or unsupported constructs rather than silently changing semantics.
12. Enhancement and monitoring contracts¶
Performance measures use explicit lifecycle semantics and return sample count, units, missingness, and aggregation method. Quantiles must identify the exact or approximate algorithm and error bound. Object-centric measures identify both the focal object type and synchronization/interaction scope.
Drift compares two or more half-open windows. It returns a bounded global score, per-relation/activity/variant contributions, signed share change, support, and multiple-comparison metadata where significance testing is requested. Small or empty samples produce a typed insufficiency result.
13. Prediction is a first-class 1.0 capability¶
Prediction is not an endpoint-specific frequency lookup. The engine owns a versioned predictor contract and ships reproducible baselines that work with either provider.
pub enum PredictionTarget {
NextActivity { object_type: String, top_k: usize },
RemainingTime { object_type: String, quantiles: Vec<f64> },
Outcome { label: OutcomeLabel },
Risk { event: RiskEvent, horizon: Duration },
}
pub enum PredictorSelection {
Baseline(BaselinePredictor),
Artifact(ModelArtifactId),
}
pub struct PredictionRequest {
pub view: DatasetView,
pub target: PredictionTarget,
pub state: PredictionState,
pub predictor: PredictorSelection,
pub as_of: Timestamp,
}
13.1 Built-in baselines¶
- next activity: smoothed n-gram/Markov counts over execution prefixes, with object-type and activity backoff;
- remaining time: conditional empirical distribution by prefix/activity and object type, returning median and requested intervals;
- outcome/risk: regularized frequency/logistic baseline over a documented tabular feature set, with missing-value indicators.
These are legitimate general baselines, not benchmark shortcuts. Ties are stable. Probabilities are normalized. Unseen states back off through declared levels and expose the selected level.
13.2 Features and artifacts¶
Feature extraction supports sequential prefixes, heterogeneous event/object
graphs, and tabular execution summaries. Each feature vector records its
as_of timestamp and lineage. No feature may read events or object-attribute
changes after as_of.
Model artifacts contain model kind, schema, feature contract, training view and window hashes, source watermark, code version, seed, metrics, calibration data, and serialized parameters. Third-party ML runtimes integrate through an artifact adapter; they are not dependencies of the core engine.
13.3 Evaluation¶
Time-ordered train/validation/test splitting is the default. Next activity reports top-1 accuracy, top-k recall, log loss, and Brier score. Remaining time reports MAE, median absolute error, and interval coverage. Outcome/risk reports class balance, AUROC where defined, average precision, log loss, Brier score, and calibration error. Metrics must include support and uncertainty intervals.
14. Resource, concurrency, and failure model¶
- All scans and intermediates are streaming or bounded by
memory_budget_bytes. - Operators that support spilling use an engine-owned temporary directory and
account for spill bytes. Unsupported spill under insufficient memory returns
ResourceLimit, never an uncontrolled allocation. - Cancellation and deadlines propagate through provider calls and Rust kernels.
- No global mutable dataset cache is required for correctness. Shared caches are generation-keyed, size-bounded, observable, and disableable.
- Providers are safe for concurrent reads. Mutable imports use snapshot/source watermarks so one request observes one consistent generation.
- Panics may not cross FFI. Python receives stable typed exceptions.
15. Performance requirements¶
Performance gates apply after exact semantic parity and include cold and warm runs. They are general workload classes, not fixed query IDs.
- Local standalone DFG and variant computations must not regress by more than 10% in median latency or throughput from the pinned Rust4PM common-workload baseline on the same canonical input.
- With
pg_ocpm, any selective workload whose pushed plan transfers at most 10% of source rows must transfer fewer bytes than the local full scan and must not be slower by more than 10% at p50; otherwise the planner must select local/factorized fallback. - Eight-worker read throughput for DFG, variants, query bindings, and prediction scoring must be at least 90% of the faster applicable pinned reference arm, unless the release report identifies a semantic capability the reference did not execute.
- Peak tracked engine memory must remain within the configured budget plus 10% allocator overhead. Process RSS and PostgreSQL backend memory are reported separately.
- Persistent PostgreSQL acceleration storage, load time, and WAL must be reported separately from source data. No latency gate can hide a storage or ingest regression greater than 15% without an explicit release exception.
The release suite includes OCPQ Q1-Q7, SAP O2C/P2P common workloads, the
Rust4PM fixture/workloads, the OCPA fixture/workloads, Logistics or Order
Management conformance, and Angular GitHub Commits as a non-ERP generalization
dataset. Only workloads with equivalent semantics are compared numerically;
inapplicable cells are N/A.
16. Correctness and test plan¶
16.1 Unit tests¶
- canonical ordering, null/absent semantics, type conversion, and qualifier preservation;
- AST validation, predicate laws, multiplicity, factorized expansion, and deterministic ordering;
- discovery/conformance measures on hand-checkable fixtures;
- prediction backoff, probability normalization, leakage prevention, metrics, and stable seeded artifacts;
- memory accounting, cancellation, timeout, and spill behavior.
16.2 Provider contract tests¶
Run the same generated and curated requests against ocpm-local and
ocpm-postgres, comparing canonical serialized results byte-for-byte after
removing execution diagnostics. Include selective/unselective predicates,
empty inputs, equal timestamps, cycles, duplicate relationships, qualifiers,
attribute histories, multiple tenants, and concurrent refresh/read snapshots.
16.3 Differential and property tests¶
- OCEL round trips retain every canonical entity and relationship;
- query-plan rewrites preserve bindings and multiplicity;
- PM4Py is an independent oracle where semantic equivalence exists;
- published OCPQ expected answers are exact and duplicate-preserving;
- discovery artifacts reparse and preserve behavior;
- model scores remain finite, normalized, and deterministic.
16.4 Integration and benchmarks¶
All performance environments are pinned Docker images with immutable source, dataset, and dependency hashes. Runs record CPU/memory limits, host, cold/warm state, repetitions, raw samples, answer hashes, load/WAL/storage, transfer bytes, process RSS, PostgreSQL backend memory, and concurrency. Release claims require clean committed revisions and machine-readable artifacts.
17. Compatibility and migration¶
- 0.10 PostgreSQL-first Python calls remain available for one 1.x deprecation
window through an adapter that constructs
DataSource::Postgres. - 1.0 models and results carry semantic schema versions independent of crate versions.
- The engine negotiates
pg_ocpmcapabilities; it never assumes version alone proves a callable or semantic contract. - Unsupported 0.x extension operations use exact canonical streaming fallback.
- Release notes list every renamed type, changed time-boundary rule, and migration example.
18. Security and privacy¶
- The typed query API has no raw SQL, arbitrary file read, or shell escape.
- Tenant and dataset scopes are mandatory at source boundaries and included in every cache key.
- Attribute values are untrusted data. Rendering layers and downstream adapters must not interpret them as instructions.
- Provenance and diagnostics redact credentials, DSNs, filesystem secrets, and attribute values by default.
- Parsers enforce byte, nesting, entity, relationship, and decompression limits.
- Dependencies require license, vulnerability, and provenance review before release.
19. Delivery sequence¶
Implementation was delivered in staged phases from contract freeze through release qualification; the staged plan and its per-phase definitions of done are maintained internally.
20. Exit criteria¶
The 1.0.0 release is accepted when:
- the default Rust and Python installations run all mandatory use cases without PostgreSQL;
- connecting
pg_ocpmchanges physical plans but produces canonically equal results for the full provider suite; - all mandatory capability rows have public APIs, documentation, examples, and correctness tests;
- prediction includes next activity, remaining time, and outcome/risk with leakage-safe evaluation and versioned artifacts;
- resource limits, cancellation, concurrency, snapshot, and security tests pass;
- the full benchmark report includes exactness, latency, concurrency, storage, ingest/WAL, transfer, and memory evidence without benchmark-specific code;
- both repositories have an approved open-source license, contribution policy, code of conduct, security policy, and third-party notices; and
- release artifacts are built from clean signed tags with checksums and an SBOM.
21. Explicit non-goals for 1.0¶
- a graphical process-mining application;
- an embedded general-purpose neural-network training framework;
- stochastic simulation or prescriptive optimization;
- provider-specific behavior in the public result contract;
- arbitrary SQL or LLM-authored executable plans; and
- performance claims from unmatched semantics, altered datasets, hidden indexes, warm-only measurements, or uncommitted revisions.
22. Normative implementation manifest¶
The subsections below fix the normative 1.0.0 implementation decisions; the per-file delivery tracking used during implementation is maintained internally.
No compatibility support is promised for versions older than pg_ocpm 0.8.0
or ocpm-engine 0.10.0. The 0.10 Python facade is removed in 2.0, no earlier
than 12 months after 1.0 general availability.
22.1 Canonical batches¶
The provider boundary uses typed Rust batches, not provider payload bytes:
pub struct EventBatch {
pub event_id: Vec<u64>,
pub external_event_id: Vec<String>,
pub activity: Vec<String>,
pub timestamp_nanos_utc: Vec<i128>,
pub source_timestamp: Vec<Option<String>>,
pub sequence: Vec<u64>,
pub lifecycle: Vec<Option<String>>,
pub attributes: Vec<CanonicalMap>,
}
pub struct ObjectBatch {
pub object_id: Vec<u64>,
pub external_object_id: Vec<String>,
pub object_type: Vec<String>,
}
pub struct E2oBatch {
pub event_id: Vec<u64>,
pub object_id: Vec<u64>,
pub qualifier: Vec<String>,
}
pub struct O2oBatch {
pub source_object_id: Vec<u64>,
pub target_object_id: Vec<u64>,
pub qualifier: Vec<String>,
pub valid_from_micros_utc: Vec<Option<i64>>,
pub valid_to_micros_utc: Vec<Option<i64>>,
}
Vectors in one batch have equal length. Providers target 8 MiB and never exceed
16 MiB encoded input per batch; an individual oversize value returns
InputLimit. Strings are UTF-8. Attribute maps use canonical typed JSON values.
Provider-specific capsules are decoded and validated inside the provider before
these types cross the boundary.
22.2 Canonical serialization and equality¶
Canonical JSON is UTF-8 without a byte-order mark or insignificant whitespace. Object keys sort by Unicode code point. Integers use base-10 without leading zeros. Finite floats use the shortest round-trip decimal, normalize negative zero to zero, and reject NaN/infinity. Timestamps serialize in UTC RFC 3339 with exactly nine fractional digits; accepted source lexical forms remain in provenance for source-format round trips. Sets and maps sort by their stable keys; ordered execution/activity paths retain order. Optional absent fields are omitted; explicit domain nulls serialize as JSON null.
Warnings sort by (code, field_path, message). Execution diagnostics are never
part of semantic equality or the content hash. Approximation algorithm/error
metadata is part of equality. Model nodes and arcs receive canonical IDs from
their sorted semantic tuple, not discovery traversal order. Search results sort
by cost, then canonical move sequence. This makes local/PostgreSQL and repeated
seeded runs byte-comparable.
22.3 Stable errors¶
Public operations return one of:
InvalidRequest, UnsupportedSemanticVersion, UnsupportedFormat,
InvalidData, NotFound, UnauthorizedScope, ProviderUnavailable,
ProviderContractViolation, ResourceLimit, InputLimit, Timeout,
Cancelled, InsufficientData, SearchTruncated, ArtifactIncompatible, or
Internal.
Every error includes a stable code, request ID, retryable boolean, redacted
field/operator path, and optional limit/current value. Internal never exposes
credentials, DSNs, paths, process attributes, or a Rust backtrace through a
public binding.
22.4 Default resources and cancellation¶
EngineOptions::default() means 512 MiB tracked memory, 8 MiB target batches,
16 MiB maximum batches, min(available_parallelism, 8) workers, no embedded
deadline, a 4 GiB spill quota, and a process-specific temporary directory with
owner-only permissions. Python uses the same defaults. Service adapters set
a 30-second deadline unless a lower policy applies.
Hash aggregation, external sort, binding joins, variant grouping, and alignment open/closed sets must spill. Algorithms without a correct spill path reject a plan whose worst-case estimate exceeds the remaining memory budget. Cancellation is checked at least every 4,096 records or 10 milliseconds of CPU work, whichever comes first. A cancelled provider call must return control within 100 ms p95 after the provider acknowledges cancellation.
Shared caches default off. When enabled they are LRU, byte-bounded to 25% of the engine memory budget, and keyed by semantic request hash, source watermark, provider capability versions, and artifact version. Cache hits are diagnostic only and all benchmark suites report cache-disabled and cache-enabled runs.
22.5 Process-execution and variant semantics¶
ConnectedComponent treats E2O as an undirected event-object incidence graph
and includes O2O edges active at each event timestamp when requested. Each
connected component is an execution. LeadingObject creates one execution per
object of the selected type and includes events/related objects reached by the
declared relationship directions and maximum depth; overlapping executions are
allowed and retain provenance.
A linear variant is the ordered activity sequence for one declared projection,
ordered by (timestamp, sequence, external_event_id). A graph variant is the
canonical labeled partial-order graph whose event nodes are connected by
per-object directly-follows edges and whose labels contain activity plus the
sorted participating object types/qualifiers. Isomorphism ignores internal IDs
and preserves labels, edge kinds, and multiplicity.
22.6 Algorithm registry and required defaults¶
Every algorithm request contains an explicit algorithm_version; omission uses
the following v1 entries and records them in the artifact:
| Operation | v1 semantics/default |
|---|---|
| DFG/OC-DFG | Complete-lifecycle event order; count each adjacent pair per projected object execution; retain object type |
| Alpha | Classic Alpha relations on one explicit flattened object-type view; no noise filtering |
| Inductive process tree | Infrequent variant with noise threshold 0.0; stable activity tie order |
| OCPN | Discover a v1 inductive Petri net per object-type projection, merge visible transitions by activity label, and retain typed object arcs; return unsupported when sound merging cannot be represented |
| OC-DECLARE | Templates existence, absence, exactly, init, end, response, precedence, succession, coexistence, not_coexistence, choice, and exclusive_choice; minimum support 1.0, confidence 1.0 unless supplied |
| Token replay | Deterministic lowest-transition-ID choice for duplicate enabled labels; report missing/remaining/consumed/produced tokens |
| Alignment | A* over synchronous/log/model moves; unit log/model cost, zero synchronous cost; stable move tie order; exact unless a declared state/time limit is reached |
| Fitness | Replay fitness 0.5*(1-missing/consumed)+0.5*(1-remaining/produced), with zero-denominator rules recorded |
| Precision | Escaping-edges precision over replayed states; undefined with typed InsufficientData when no visited states exist |
| Drift | Jensen-Shannon divergence with natural logs divided by ln(2), additive smoothing 1e-12, score in [0,1], and per-dimension contributions |
| Exact quantile | Stable sorted nearest-rank quantile; approximate quantiles require explicit algorithm and error bound |
Every formula and unsupported construct receives a focused golden fixture before implementation. Changing a v1 formula or template set requires a new algorithm version, not a patch-level behavior change.
Performance measures use these lifecycle definitions: service is start-to-end for the same activity instance; waiting is previous completion to current start; sojourn is enablement/arrival to completion when enablement exists; flow is execution start to end; synchronization is last required-object arrival minus first required-object arrival; pooling is time from first related-object arrival to activity start; lagging is the difference between the focal-object and last related-object arrival. Missing required lifecycle events produce missing values and support counts, never inferred timestamps.
22.7 Prediction fitting and lifecycle¶
The facade adds:
pub async fn fit_predictor(&self, request: FitPredictionRequest)
-> Result<ModelArtifact>;
pub async fn evaluate_predictor(&self, request: EvaluatePredictionRequest)
-> Result<PredictionEvaluation>;
pub async fn load_artifact(&self, artifact: ModelArtifact)
-> Result<ModelArtifactId>;
FitPredictionRequest requires target, feature schema version, training
half-open window, validation/test windows or an explicit time-split ratio,
predictor kind, seed, minimum support, and artifact destination. Default split
is chronological 70/15/15, seed 0, minimum support 20. Splits sharing an
execution are moved wholly into the earliest partition containing its first
event. Feature extraction is performed independently per partition and enforces
feature_timestamp <= prediction_as_of.
Built-in next-activity uses order-2 additive-smoothed n-grams with alpha 1 and
backs off to order 1, activity, object type, then global. Remaining time uses an
empirical conditional distribution with the same backoff and requires support
20 before a level is used. The outcome/risk baseline is L2 logistic regression,
regularization 1.0, standardized numeric inputs fitted on training data only,
one-hot categorical values with an unknown bucket, and a documented 1,000
iteration convergence cap. Nonconvergence returns SearchTruncated and cannot
be promoted as a complete artifact.
Artifacts are immutable content-addressed files or caller-provided stores.
ModelArtifactId is the SHA-256 canonical content hash. The engine does not
define production promotion/deletion; adapters may manage aliases outside the
artifact. Loading verifies semantic version, feature schema, target, checksum,
and required engine compatibility.
22.8 Planner formula and deterministic fallback¶
Each provider estimate returns calibrated nanosecond/byte terms. The planner computes:
total = startup_ns
+ rows_read * cpu_ns_per_row
+ bytes_transferred * transfer_ns_per_byte
+ spill_bytes * spill_ns_per_byte
+ contention_ns
Hard constraints eliminate plans that exceed memory, spill, deadline, semantic capability, or snapshot requirements. Among remaining plans, choose the lowest total cost. If costs differ by less than 10%, prefer local for file/in-memory sources and PostgreSQL for PostgreSQL sources to avoid plan flapping. Final ties sort by the canonical physical-plan string.
Provider estimates are trained only from generic operator/size telemetry. They cannot use dataset names, activities, query IDs, or expected results. After the calibration suite, median actual/estimated operator time must be within 2x and p90 within 4x; otherwise the affected pushdown is disabled by default. Runtime feedback updates process-local exponentially weighted operator coefficients and is cleared/segmented by provider version and hardware class.
22.9 Per-capability acceptance rule¶
Each individual capability in section 9 gets one row in
tests/golden/capabilities.toml, even when the table groups related features.
A row names request schema, smallest positive fixture, empty/invalid fixture,
golden result, local test, PostgreSQL equivalence test when applicable, Python
test, documentation example, resource test, and benchmark workload where
meaningful. A MUST capability is incomplete if any named artifact is absent.
Discovery/conformance searches are deterministic under the request seed and limits. If multiple valid models have equal objective value, canonical model serialization selects the smallest byte sequence. Nondeterministic external artifacts are permitted only when their adapter declares tolerance-based metrics; they are never used for byte-exact provider equality.
22.10 Benchmark manifest and statistics¶
benchmarks/manifests/1.0.0.toml is frozen before release-candidate timing and
contains, for every arm: git commit/tag, dirty=false assertion, Dockerfile/image
digest, compiler/runtime/PostgreSQL/PM4Py versions, dataset origin/hash/byte
size, loader options, schema/index DDL hash, workload definitions, expected
answer hashes, CPU architecture/model, allocated cores, memory/swap limits,
storage type, OS/kernel, cache state, and environment variables.
Each timed workload uses one correctness run, three untimed warmups, and at least 30 measured repetitions per serial configuration. Concurrency levels 1/2/4/8/16 run for at least 30 seconds after a 10-second ramp and complete at least 100 requests. Report raw samples, median, p95, p99, bootstrap 95% confidence intervals, geometric mean only over semantically matched workloads, and failure/timeout counts. Arms share the same host, cgroup limits, data bytes, and answer contract. Cold runs restart containers/drop only experiment-owned caches by a documented non-destructive procedure.
The manifest's actual pins are a release deliverable. No numeric 1.0 claim or release candidate is valid before those hashes exist. Release exceptions require a linked maintainer decision that names the failed threshold, measured tradeoff, scope, expiry/revisit version, and why correctness or a mandatory capability justifies it.