Skip to main content

TuneRunRow

Struct TuneRunRow 

Source
pub struct TuneRunRow {
Show 27 fields pub id: i64, pub loop_id: Option<i64>, pub demo_session_id: Option<i64>, pub loop_name: String, pub driver: TuneDriver, pub opc_server: Option<String>, pub bridge_host: Option<String>, pub started_at: DateTime<Utc>, pub completed_at: Option<DateTime<Utc>>, pub outcome: TuneOutcome, pub failure_reason: Option<String>, pub config: LoopConfig, pub template_origin: TemplateOrigin, pub template: DcsTemplate, pub tags: LoopTags, pub request_json: String, pub notes: Option<String>, pub initial_readings: Option<TuneRunInitialReadings>, pub allow_uncertain_quality: bool, pub timing_metrics: Option<TimingMetrics>, pub effective_tuning: Option<EffectiveTuning>, pub gateway_compatibility_json: Option<String>, pub restore_status: Option<RestoreStatus>, pub restore_detail: Option<String>, pub recovery_state: Option<TuneRecoveryState>, pub recovery_evidence_json: Option<String>, pub created_at: DateTime<Utc>,
}
Expand description

One row of tune_runs: a single MRFT (or future Step Test) execution against a loop.

Fields§

§id: i64§loop_id: Option<i64>§demo_session_id: Option<i64>§loop_name: String§driver: TuneDriver§opc_server: Option<String>

The OPC DA server ProgID this run actually used – None for a non-opcda run, or for any run started before TuneRunRow::record_connection is called (see that method’s doc comment). Flat and filterable rather than folded into request_json, since bhtune history revert must know exactly which plant a past run touched.

§bridge_host: Option<String>

The opcda-bridge gateway host this run actually used – None for a non-opcda run, or before TuneRunRow::record_connection is called. See opc_server.

§started_at: DateTime<Utc>§completed_at: Option<DateTime<Utc>>§outcome: TuneOutcome§failure_reason: Option<String>§config: LoopConfig

Snapshot of the LoopConfig this run was started with — always known up front, since it’s user/schedule input rather than something read from the driver.

§template_origin: TemplateOrigin

Where the snapshotted template below came from (see TemplateOrigin).

§template: DcsTemplate

Snapshot of the exact [DcsTemplate] this run was configured against, deserialized from template_snapshot_json. Held as the full struct rather than just its name – which is what makes a historical run stay interpretable once the template catalog changes underneath it. There’s no separate template_name field here even though the table has a template_name column: .name on this field already carries that value, and the column exists purely so it’s filterable/indexable without json_extract (see this module’s own doc comment).

§tags: LoopTags

Snapshot of the resolved [LoopTags] this run actually used, deserialized from tags_json.

§request_json: String

The complete run request exactly as submitted (CLI flags or the HTTP POST /api/runs body), before any config-driven defaulting – raw JSON rather than a typed struct, since its shape is owned by the bhtune/bhtune-server adapters, not bhtune-db. "{}" for any run started before TuneRunRow::record_connection is called. It supports last-run prefill and “duplicate this run”; never treat this as the source of truth for connection facts – that’s opc_server/bridge_host above.

§notes: Option<String>

Mutable operator notes for this run. None means no note is recorded.

§initial_readings: Option<TuneRunInitialReadings>§allow_uncertain_quality: bool

Whether this run permitted Quality::Uncertain OPC readings under the global allow_uncertain_quality policy (Quality::Bad is never accepted regardless). false for every run started before TuneRunRow::record_allow_uncertain_quality is called – see that method’s doc comment for why it’s a separate post-start() update rather than a start() parameter.

§timing_metrics: Option<TimingMetrics>

Polling-cadence diagnostics collected from successful PV samples. None for runs created before timing diagnostics existed or attempts that ended before polling began.

§effective_tuning: Option<EffectiveTuning>

Concrete timing values used by this run after configuration defaults were resolved. None for runs created before effective-tuning snapshots existed or until TuneRunRow::record_effective_tuning is called.

§gateway_compatibility_json: Option<String>

Observed opcda-bridge compatibility report, stored as the driver’s JSON snapshot. None for non-OPC runs, runs started before the snapshot existed, or until TuneRunRow::record_gateway_compatibility is called. Kept as raw JSON because the report type lives in bhtune-driver, which this crate does not depend on.

§restore_status: Option<RestoreStatus>

Outcome of the best-effort restore attempted after this run ended – None if no restore was ever attempted (the run never mutated the loop, or hasn’t ended yet). See RestoreStatus and TuneRunRow::record_restore_status.

§restore_detail: Option<String>

Set only alongside restore_status = Some(RestoreStatus::Incomplete): what a second Ctrl+C, [tuning].restore_timeout_secs, or an individual failed restore step prevented from being confirmed.

§recovery_state: Option<TuneRecoveryState>

Explicit recovery lifecycle state; absent for pre-recovery runs and ordinary terminal runs that never became eligible for restore-loop recovery.

§recovery_evidence_json: Option<String>

Structured evidence supporting the recovery state; never inferred from error text.

§created_at: DateTime<Utc>

Implementations§

Source§

impl TuneRunRow

Source

pub async fn start( pool: &SqlitePool, loop_id: Option<i64>, loop_name: &str, driver: TuneDriver, config: LoopConfig, template_origin: TemplateOrigin, template: &DcsTemplate, tags: &LoopTags, now: DateTime<Utc>, ) -> DbResult<TuneRunRow>

Starts a new run: inserts a tune_runs row with outcome = 'running' and no initial readings yet (see Self::record_initial_readings). now is used for both started_at and created_at, which are naturally the same instant for a run that’s only just begun. loop_id may be None for an ad-hoc run against tags that were never saved as a reusable LoopRow.

template_origin/template/tags snapshot exactly what this run was configured against, so a historical run stays interpretable even after the template catalog changes underneath it. Serializing template/tags returns DbError::Serialize if the JSON encoder rejects a value. Both are plain derived structures; a serialization failure indicates a persistence contract regression rather than a plant condition.

Source

pub async fn start_with_demo_session( pool: &SqlitePool, demo_session_id: Option<i64>, loop_id: Option<i64>, loop_name: &str, driver: TuneDriver, config: LoopConfig, template_origin: TemplateOrigin, template: &DcsTemplate, tags: &LoopTags, now: DateTime<Utc>, ) -> DbResult<TuneRunRow>

Source

pub async fn start_owned( pool: &SqlitePool, demo_session_id: i64, loop_name: &str, config: LoopConfig, template_origin: TemplateOrigin, template: &DcsTemplate, tags: &LoopTags, now: DateTime<Utc>, ) -> DbResult<TuneRunRow>

Starts a simulator run owned by a demo session. The database trigger rejects any attempt to attach an owner to a live OPC DA run.

Source

pub async fn get_for_demo_session( pool: &SqlitePool, run_id: i64, demo_session_id: i64, ) -> DbResult<Option<TuneRunRow>>

Source

pub async fn list_for_demo_session( pool: &SqlitePool, demo_session_id: i64, pagination: Pagination, ) -> DbResult<Vec<TuneRunRow>>

Source

pub async fn newest_for_demo_session( pool: &SqlitePool, demo_session_id: i64, ) -> DbResult<Option<TuneRunRow>>

Source

pub async fn count_for_demo_session( pool: &SqlitePool, demo_session_id: i64, ) -> DbResult<i64>

Source

pub async fn count_demo_owned(pool: &SqlitePool) -> DbResult<i64>

Counts every current Demo-owned run across all sessions and outcomes. Full-mode rows have demo_session_id = NULL and are excluded.

Source

pub async fn prune_terminal_for_demo_session( pool: &SqlitePool, demo_session_id: i64, retain: u32, ) -> DbResult<u64>

Deletes terminal history beyond the newest retain rows for one Demo owner. Running rows never consume a retention slot and are never deleted. Child samples, results, writes, and MV-actuation evidence cascade with each deleted run.

Source

pub async fn prune_terminal_demo_owned( pool: &SqlitePool, retain: u32, ) -> DbResult<u64>

Applies Self::prune_terminal_for_demo_session’s retention rule independently to every Demo owner in one statement. Intended for periodic global cleanup.

Source

pub async fn count_rows_for_demo_session( pool: &SqlitePool, demo_session_id: i64, ) -> DbResult<i64>

Source

pub async fn record_connection( pool: &SqlitePool, run_id: i64, opc_server: Option<&str>, bridge_host: Option<&str>, request_json: &str, ) -> DbResult<TuneRunRow>

Records this run’s connection provenance and the exact request it was started with: the OPC DA server ProgID and opcda-bridge gateway host actually used (None/None for a non-opcda run), and a JSON snapshot of the complete submitted request (CLI flags or the HTTP POST /api/runs body), captured before any config-driven defaulting so it reflects what the caller actually asked for.

Recorded after start() so callers that do not have connection provenance can still create a run without extra arguments. The production caller stores this immediately after start() succeeds, before any driver I/O. opc_server/bridge_host default to NULL and request_json defaults to "{}" (see the migration).

Source

pub async fn record_effective_tuning( pool: &SqlitePool, run_id: i64, effective_tuning: EffectiveTuning, ) -> DbResult<TuneRunRow>

Records the concrete tune timing policy after all configuration defaults have been resolved. This is a follow-up update rather than another Self::start parameter so existing repository callers remain source-compatible. Production orchestration should call it immediately after start() and before any driver I/O.

Source

pub async fn record_gateway_compatibility( pool: &SqlitePool, run_id: i64, gateway_compatibility_json: &str, ) -> DbResult<TuneRunRow>

Records the observed opcda-bridge compatibility snapshot for a live OPC DA run.

gateway_compatibility_json must already be valid JSON. This is a follow-up update rather than another Self::start parameter so existing repository callers remain source-compatible.

§Errors

Returns DbError::Query when the row does not exist or the JSON fails the column check.

Source

pub async fn update_notes( pool: &SqlitePool, run_id: i64, notes: Option<&str>, ) -> DbResult<TuneRunRow>

Replaces this run’s operator notes. Passing None clears the note, which is the persistence-layer implementation of the GUI’s delete-note action. This deliberately has no lifecycle restriction: notes remain editable while a run is active and after it reaches a terminal outcome.

Source

pub async fn record_initial_readings( pool: &SqlitePool, run_id: i64, readings: TuneRunInitialReadings, ) -> DbResult<TuneRunRow>

Records the driver’s initial-readings snapshot for an already-started run. Called at most once per run, right after that read succeeds and before transition_to_manual’s first mutating write. This durably preserves mode_raw/mode_attribute_raw/ setpoint_ini so a crashed run can be reconstructed and restored later via bhtune restore-loop. A run that fails before or during the read instead goes straight to Self::fail with initial_readings left None.

Source

pub async fn record_allow_uncertain_quality( pool: &SqlitePool, run_id: i64, allow_uncertain_quality: bool, ) -> DbResult<TuneRunRow>

Records whether this run permitted Quality::Uncertain OPC readings under the global configuration policy. This is a separate post-start() update because the resolved policy is available to the orchestration layer, not to every repository caller. The column defaults to 0/false (see the migration), and the production caller stores the resolved value after start() succeeds.

Source

pub async fn record_timing_metrics( pool: &SqlitePool, run_id: i64, metrics: TimingMetrics, ) -> DbResult<TuneRunRow>

Records the polling cadence observed while this run was active. Kept as one typed JSON snapshot because these diagnostics are nested, evolve together, and have no SQL-level filtering requirement. Normal completed/aborted tune orchestration uses Self::complete_with_timing_metrics or Self::abort_with_timing_metrics so the terminal outcome and diagnostics become visible atomically; this standalone update is retained for non-terminal/failure paths and direct repository consumers.

Source

pub async fn record_restore_status( pool: &SqlitePool, run_id: i64, status: RestoreStatus, detail: Option<&str>, ) -> DbResult<TuneRunRow>

Records the outcome of a best-effort loop-restore attempt made after this run ended. Called once, after complete/fail/abort (whichever applies) and after attempt_restore has actually run – never before, and never for a run that ended without ever mutating the loop (nothing to restore, so nothing to record). detail should be Some(..) whenever status is RestoreStatus::Incomplete, naming what could not be confirmed; pass None for RestoreStatus::Confirmed. A separate post-hoc update rather than a complete/fail/abort parameter, matching Self::record_allow_uncertain_quality’s precedent: the restore attempt always happens strictly after one of those three, never alongside it.

Source

pub async fn complete( pool: &SqlitePool, run_id: i64, completed_at: DateTime<Utc>, ) -> DbResult<TuneRunRow>

Marks a run completed — a full MRFT test that ran to its natural end. The calculated results themselves are recorded separately via TuneResultRow::insert.

Source

pub async fn complete_with_timing_metrics( pool: &SqlitePool, run_id: i64, completed_at: DateTime<Utc>, timing_metrics: Option<TimingMetrics>, ) -> DbResult<TuneRunRow>

Atomically marks a run completed and publishes its timing diagnostics. This prevents readers that react to the terminal outcome (notably the SSE stream) from observing a completed run before its timing snapshot is visible.

Source

pub async fn fail( pool: &SqlitePool, run_id: i64, completed_at: DateTime<Utc>, failure_reason: &str, ) -> DbResult<TuneRunRow>

Marks a run failed, recording why. Valid whether or not Self::record_initial_readings was ever called for this run — a run can fail before, during, or after the initial read.

Source

pub async fn abort( pool: &SqlitePool, run_id: i64, completed_at: DateTime<Utc>, ) -> DbResult<TuneRunRow>

Marks a run aborted — stopped deliberately by a human or by the configured run timeout rather than failing on its own.

Source

pub async fn abort_with_timing_metrics( pool: &SqlitePool, run_id: i64, completed_at: DateTime<Utc>, timing_metrics: Option<TimingMetrics>, ) -> DbResult<TuneRunRow>

Atomically marks a run aborted and publishes any timing diagnostics collected before the abort, so terminal-state readers cannot miss the final timing snapshot.

Source

pub async fn abort_with_timing_metrics_and_reason( pool: &SqlitePool, run_id: i64, completed_at: DateTime<Utc>, timing_metrics: Option<TimingMetrics>, reason: &str, ) -> DbResult<TuneRunRow>

Atomically marks a run aborted, publishes its timing diagnostics, and persists the operator-facing reason for the abort in the existing failure_reason column. This is used when an abort has a durable safety explanation (for example an MV command whose live readback did not reach its target), while preserving the database’s existing TuneOutcome::Aborted value.

Source

pub async fn get(pool: &SqlitePool, id: i64) -> DbResult<Option<TuneRunRow>>

Fetches one row by id, or None if it doesn’t exist.

Source

pub async fn list( pool: &SqlitePool, filter: &TuneRunFilter, pagination: Pagination, ) -> DbResult<Vec<TuneRunRow>>

Lists runs matching filter, newest-started first, one pagination page at a time. See Self::count for the total number of rows filter matches across all pages.

Source

pub async fn count(pool: &SqlitePool, filter: &TuneRunFilter) -> DbResult<i64>

Counts every run matching filter, ignoring pagination — the total Self::list would page through.

Source

pub async fn count_deletable_matching( pool: &SqlitePool, filter: &TuneRunFilter, ) -> DbResult<i64>

Counts runs matching a deletion filter while preserving runs with an unresolved live recovery. This is the count used by retention previews so they match the actual sweep.

Source

pub async fn delete_matching( pool: &SqlitePool, filter: &TuneRunFilter, ) -> DbResult<u64>

Deletes every run matching filter in one statement (SQLite treats a single statement as its own transaction, so no explicit BEGIN/COMMIT is needed). Returns the number of runs deleted. tune_samples/tune_results/tune_writes’s ON DELETE CASCADE foreign keys in the schema remove each deleted run’s samples, results, and write-back audit rows automatically.

Runs with recovery state eligible, running, or incomplete are retained until a recovery is confirmed. count_deletable_matching applies the same protection for retention previews.

An empty filter (every field None) matches every deletable run in the table. Callers that mean to scope a deletion must build a filter that says so explicitly; unresolved live-recovery rows remain protected even when the filter is empty.

Source

pub async fn delete(pool: &SqlitePool, id: i64) -> DbResult<bool>

Deletes exactly one run by id, as used by the browser history page’s delete action. Returns whether a row was actually deleted – false if no run has that id, letting the caller map that to a 404 rather than a silent no-op. Unlike DcsTemplateRow::delete, ordinary run children are removed by ON DELETE CASCADE. An unresolved live recovery state is excluded atomically so a concurrent delete cannot release the recovery claim.

Source

pub async fn delete_for_demo_session( pool: &SqlitePool, id: i64, demo_session_id: i64, ) -> DbResult<bool>

Trait Implementations§

Source§

impl Clone for TuneRunRow

Source§

fn clone(&self) -> TuneRunRow

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TuneRunRow

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for TuneRunRow

Source§

fn eq(&self, other: &TuneRunRow) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for TuneRunRow

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for TuneRunRow

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more