pub struct TuneRunRow {Show 24 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 restore_status: Option<RestoreStatus>,
pub restore_detail: 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: LoopConfigSnapshot 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: TemplateOriginWhere the snapshotted template below came from (see TemplateOrigin).
template: DcsTemplateSnapshot 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 (safety-run-snapshot). 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).
Snapshot of the resolved LoopTags this run actually used, deserialized from
tags_json.
request_json: StringThe 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 bhtune-cli/bhtune-server, not
bhtune-db. "{}" for any run started before
TuneRunRow::record_connection is called. Powers ui-prefill-last-run 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: boolWhether this run permitted Quality::Uncertain OPC readings under the global
allow_uncertain_quality policy (finding 5 of the live-plant safety review;
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.
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.
created_at: DateTime<Utc>Implementations§
Source§impl TuneRunRow
impl TuneRunRow
Sourcepub 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>
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 (safety-run-snapshot), so a historical run stays interpretable even after
the template catalog changes underneath it. Serializing template/tags is treated
as infallible here, the same way enum_to_text treats enum serialization as
infallible: both types are plain, derived, string/enum-only structures with no maps,
and every f32 field they can carry is validated finite well before a run reaches
this call (see safety-validation) – a panic here would mean that contract regressed
upstream, not a normal runtime failure this function’s DbResult should model.
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>
Sourcepub 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>
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.
pub async fn get_for_demo_session( pool: &SqlitePool, run_id: i64, demo_session_id: i64, ) -> DbResult<Option<TuneRunRow>>
pub async fn list_for_demo_session( pool: &SqlitePool, demo_session_id: i64, pagination: Pagination, ) -> DbResult<Vec<TuneRunRow>>
pub async fn newest_for_demo_session( pool: &SqlitePool, demo_session_id: i64, ) -> DbResult<Option<TuneRunRow>>
pub async fn count_for_demo_session( pool: &SqlitePool, demo_session_id: i64, ) -> DbResult<i64>
Sourcepub async fn count_demo_owned(pool: &SqlitePool) -> DbResult<i64>
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.
Sourcepub async fn prune_terminal_for_demo_session(
pool: &SqlitePool,
demo_session_id: i64,
retain: u32,
) -> DbResult<u64>
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.
Sourcepub async fn prune_terminal_demo_owned(
pool: &SqlitePool,
retain: u32,
) -> DbResult<u64>
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.
pub async fn count_rows_for_demo_session( pool: &SqlitePool, demo_session_id: i64, ) -> DbResult<i64>
Sourcepub async fn record_connection(
pool: &SqlitePool,
run_id: i64,
opc_server: Option<&str>,
bridge_host: Option<&str>,
request_json: &str,
) -> DbResult<TuneRunRow>
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
(db-run-request-snapshot): 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.
A separate post-start() update rather than three more start() parameters, matching
Self::record_allow_uncertain_quality’s precedent – start() already has 8
positional parameters across dozens of call sites in this workspace’s test suites
alone, and three more would make every one of them noisier for no benefit, since none
of those tests care about connection provenance. Unlike that method, this data is
normally known the instant a run begins; the one production caller (bhtune-cli’s
prepare()) calls 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), so every existing start() call site keeps compiling and
behaving exactly as before.
Sourcepub async fn record_effective_tuning(
pool: &SqlitePool,
run_id: i64,
effective_tuning: EffectiveTuning,
) -> DbResult<TuneRunRow>
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.
Sourcepub async fn update_notes(
pool: &SqlitePool,
run_id: i64,
notes: Option<&str>,
) -> DbResult<TuneRunRow>
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.
Sourcepub async fn record_initial_readings(
pool: &SqlitePool,
run_id: i64,
readings: TuneRunInitialReadings,
) -> DbResult<TuneRunRow>
pub async fn record_initial_readings( pool: &SqlitePool, run_id: i64, readings: TuneRunInitialReadings, ) -> DbResult<TuneRunRow>
Records the driver’s initial-readings snapshot (ReadInitialOPCvalues in the legacy
app) for an already-started run. Called at most once per run, right after that read
succeeds – and, deliberately, before transition_to_manual’s first mutating write
rather than after it (safety-restore-guard, finding 3 of the live-plant safety
review), so mode_raw/mode_attribute_raw/setpoint_ini are always durably
persisted before the loop is touched at all, letting a crashed run 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.
Sourcepub async fn record_allow_uncertain_quality(
pool: &SqlitePool,
run_id: i64,
allow_uncertain_quality: bool,
) -> DbResult<TuneRunRow>
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 (finding 5 of the live-plant safety review). A separate
post-start() update rather than a new start() parameter deliberately: start()
already has 8 positional parameters across 28 call sites in this crate’s own test
suite alone, and this is a rarely-used escape hatch, not information every caller
naturally has on hand at the moment a run begins the way template_origin/template/
tags are. The column defaults to 0/false (see the migration), so every existing
start() call site keeps compiling and behaving exactly as before; only the one
production caller in bhtune-cli’s run() needs to call this, right after start()
succeeds.
Sourcepub async fn record_timing_metrics(
pool: &SqlitePool,
run_id: i64,
metrics: TimingMetrics,
) -> DbResult<TuneRunRow>
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.
Sourcepub async fn record_restore_status(
pool: &SqlitePool,
run_id: i64,
status: RestoreStatus,
detail: Option<&str>,
) -> DbResult<TuneRunRow>
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
(safety-restore-guard, finding 3 of the live-plant safety review). 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.
Sourcepub async fn complete(
pool: &SqlitePool,
run_id: i64,
completed_at: DateTime<Utc>,
) -> DbResult<TuneRunRow>
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.
Sourcepub async fn complete_with_timing_metrics(
pool: &SqlitePool,
run_id: i64,
completed_at: DateTime<Utc>,
timing_metrics: Option<TimingMetrics>,
) -> DbResult<TuneRunRow>
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.
Sourcepub async fn fail(
pool: &SqlitePool,
run_id: i64,
completed_at: DateTime<Utc>,
failure_reason: &str,
) -> DbResult<TuneRunRow>
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.
Sourcepub async fn abort(
pool: &SqlitePool,
run_id: i64,
completed_at: DateTime<Utc>,
) -> DbResult<TuneRunRow>
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 cli-safety’s
wall-clock timeout guardrail) rather than failing on its own.
Sourcepub async fn abort_with_timing_metrics(
pool: &SqlitePool,
run_id: i64,
completed_at: DateTime<Utc>,
timing_metrics: Option<TimingMetrics>,
) -> DbResult<TuneRunRow>
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.
Sourcepub 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>
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.
Sourcepub async fn get(pool: &SqlitePool, id: i64) -> DbResult<Option<TuneRunRow>>
pub async fn get(pool: &SqlitePool, id: i64) -> DbResult<Option<TuneRunRow>>
Fetches one row by id, or None if it doesn’t exist.
Sourcepub async fn list(
pool: &SqlitePool,
filter: &TuneRunFilter,
pagination: Pagination,
) -> DbResult<Vec<TuneRunRow>>
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.
Sourcepub async fn count(pool: &SqlitePool, filter: &TuneRunFilter) -> DbResult<i64>
pub async fn count(pool: &SqlitePool, filter: &TuneRunFilter) -> DbResult<i64>
Counts every run matching filter, ignoring pagination — the total Self::list
would page through.
Sourcepub async fn delete_matching(
pool: &SqlitePool,
filter: &TuneRunFilter,
) -> DbResult<u64>
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 (see db-schema’s migration) remove each deleted run’s samples,
results, and write-back audit rows automatically.
Shares [push_filter] with Self::list/Self::count, so “what a --dry-run
preview reports” and “what an actual sweep deletes” can never disagree — used this way
by history-retention’s automatic sweep and bhtune history prune.
An empty filter (every field None) matches and deletes every run in the table —
callers that mean to scope a deletion must build a filter that says so explicitly;
this function has no separate “are you sure” guard of its own, matching count/list
treating an empty filter as “everything” rather than “nothing”.
Sourcepub async fn delete(pool: &SqlitePool, id: i64) -> DbResult<bool>
pub async fn delete(pool: &SqlitePool, id: i64) -> DbResult<bool>
Deletes exactly one run by id (history-explorer-ui’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, no foreign key ever blocks this: tune_runs has no
parent-side RESTRICT reference pointing at it, only the ON DELETE CASCADE
children (tune_samples/tune_results/tune_writes, see db-schema’s migration),
which SQLite removes automatically as part of the same statement.
pub async fn delete_for_demo_session( pool: &SqlitePool, id: i64, demo_session_id: i64, ) -> DbResult<bool>
Trait Implementations§
Source§impl Clone for TuneRunRow
impl Clone for TuneRunRow
Source§fn clone(&self) -> TuneRunRow
fn clone(&self) -> TuneRunRow
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for TuneRunRow
impl Debug for TuneRunRow
Source§impl PartialEq for TuneRunRow
impl PartialEq for TuneRunRow
Source§fn eq(&self, other: &TuneRunRow) -> bool
fn eq(&self, other: &TuneRunRow) -> bool
self and other values to be equal, and is used by ==.impl StructuralPartialEq for TuneRunRow
Auto Trait Implementations§
impl Freeze for TuneRunRow
impl RefUnwindSafe for TuneRunRow
impl Send for TuneRunRow
impl Sync for TuneRunRow
impl Unpin for TuneRunRow
impl UnsafeUnpin for TuneRunRow
impl UnwindSafe for TuneRunRow
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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