Skip to content

Native: read workflow descriptions from one bounded coherent snapshot #1075

Closed

Description

@rmcdaniel

Delivered in Native 3.3.2 — November 9, 2026

Released and Latest, exact source 660217dd1ac62701eb1fc26b08fbbaf825e777d1, image sha256:4aeceb423ee4c8931f00ec2936149ac6b2a75479243b3930f9c6336ccdebf912. Final cross-repository delivery evidence.

Maintained source: PR#1112: one bounded read-only connection/snapshot, actual MySQL/MariaDB READ COMMITTED countercontrol, generation consistency and checkout/query/connection-release controls. Source/backend/main checks and published-image compatibility are accepted. Publication/provenance, protected corpus/Compose, default resolution, published PHP and Sample App's full runtime/developer-image follow-through passed on the supported tuple. Both registries' rolling aliases and the full GitHub Release are verified.

General closes this item's delivery criteria as completed. No workload timing or benchmark speedup is inferred. Earlier source/download NONPASSs and original WIP refs remain preserved; the other Native P0s and Cloud adoption retain their separate work.

Original requirement and evidence

External report topic 21, accepted for P0 intake at the user's direction. The proposal, timings and supplied test results are unverified reference evidence. No patch was applied or executed during intake.

Implementation owner: general. The owning agent drives source, release and applicable published-artifact verification. Existing release, operating and credential gates remain in force.

Problem and proposed scope

The report says GET /api/workflows/{id} performs roughly thirteen pool checkouts, two empty read transactions and three start-payload reads. Read a complete description through one short read-only connection/snapshot and reuse the already-read start payload where its routing authority permits it.

Acceptance

  • Prove a coherent description under each supported backend's actual isolation rules. Do not assume that merely opening a transaction guarantees one snapshot.
  • Preserve authorization, definition-routing inspection, absent/deleted-run behavior, projections and all existing describe/query DTOs.
  • Add concurrent transition/describe controls showing that responses do not mix incompatible row generations; verify SQLite, MySQL and PostgreSQL.
  • Keep connection/snapshot lifetime bounded to one description, release it on every failure, and measure checkout/query reduction without changing durability or pool limits.
  • Preserve existing schedule-summary work in server#1014; this issue concerns workflow-description snapshot ownership, not the separate schedule-list contract.

Reporter measurement: 14.53→14.37 seconds, four interleaved MySQL rounds, not independently reproduced.

Reported workload and evidence limits

The report describes 200 workflows, six PHP worker processes, five sequential 20 ms activities or five local activities, last-close wall time, and three or four interleaved A/B rounds. MySQL session-to-session drift is reported as high as 11%. Stock database durability, network placement and the absence of deferred projections are reporter conditions, not independently verified facts. The headline run covers topics 1–24; topic 25 has only a MySQL five-steps A/B. No speedup, production readiness or suite pass is accepted from this intake.

Sanitized reference data

The supplied Server series targets reported base d4c6de8d; the SDK reference targets 96dc061. Maintained heads were independently read as Server c3bbfa5 and SDK c87eae37. These cumulative references are not current-main patches or maintained qualification.

  • 0003-Describe-a-run-in-one-read-only-snapshot-on-one-conn.patch — 16,009 bytes / SHA-256 e67896e4d65d19afe959cecbc626aea63ffcb74b9b525ec00a7778a771f07d27.

Bench-only Server0001 is retained as diagnostic context, not a separate production change. Complete sanitized diff references, shared bundle identity and source-review findings are linked in the intake index and the issue comments. Original mail headers, author/date metadata, application commands and runner instructions are omitted.

Activity

  1. added
    kind:featureA public product capability or experience is requested
    priority:P0Immediate release or data-integrity risk
    repo:serverOwned by the standalone server repository
    completion:evidence-requiredClose only after all explicit acceptance and operational evidence is public
    on Nov 6, 2026
  2. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    Sanitized external reference for topic 21: 0003-Describe-a-run-in-one-read-only-snapshot-on-one-conn.patch, part 1/1. Complete sanitized diff: 16,009 bytes / SHA-256 e67896e4d65d19afe959cecbc626aea63ffcb74b9b525ec00a7778a771f07d27. Ordered parts preserve the complete diff bytes; none was applied or executed. The patch is a cumulative older-source draft, not maintained implementation or qualification. Mail headers/author/date/message/application instructions were removed.

    diff --git a/rust/src/runtime/run_describe.rs b/rust/src/runtime/run_describe.rs
    index d76a21f2..e76e3c5a 100644
    --- a/rust/src/runtime/run_describe.rs
    +++ b/rust/src/runtime/run_describe.rs
    @@ -11,6 +11,7 @@ use super::{
         backend::Backend,
         store::{Store, now},
         task_queues::json_time,
    +    transaction::Transaction,
     };
     use chrono::{DateTime, Utc};
     use serde_json::{Map, Value, json};
    @@ -76,21 +77,38 @@ where
         /// The registered query route for a run row, with workers whose
         /// heartbeat is newer than `stale_after` seconds.
         pub(super) async fn query_route(&self, run: &DB::Row, stale_after: i64) -> Result<super::query_route::QueryRoute> {
    -        let task_queue = super::query_route::trimmed(DB::optional_string(run, "queue")?.as_deref()).unwrap_or("default").to_owned();
    -        let workflow_type = DB::optional_string(run, "workflow_type")?;
    -        let compatibility = DB::optional_string(run, "compatibility")?;
    -        let started = Self::query("SELECT payload FROM workflow_history_events WHERE workflow_run_id=$1 AND event_type='WorkflowStarted' ORDER BY sequence LIMIT 1")
    -            .bind(DB::string(run, "id")?)
    -            .fetch_optional(&self.pool)
    +        let mut connection = self.pool.acquire().await?;
    +        let started = Self::started_payload(&mut connection, &DB::string(run, "id")?).await?;
    +        self.query_route_on(&mut connection, run, stale_after, &started).await
    +    }
    +
    +    /// The run's `WorkflowStarted` payload, or null.
    +    async fn started_payload(connection: &mut DB::Connection, run_id: &str) -> Result<Value> {
    +        Ok(Self::query("SELECT payload FROM workflow_history_events WHERE workflow_run_id=$1 AND event_type='WorkflowStarted' ORDER BY sequence LIMIT 1")
    +            .bind(run_id)
    +            .fetch_optional(&mut *connection)
                 .await?
                 .map(|row| DB::document_row(&row, "payload"))
                 .transpose()?
    -            .unwrap_or(Value::Null);
    +            .unwrap_or(Value::Null))
    +    }
    +
    +    /// `query_route` on a given connection, with the run's start payload.
    +    async fn query_route_on(
    +        &self,
    +        connection: &mut DB::Connection,
    +        run: &DB::Row,
    +        stale_after: i64,
    +        started: &Value,
    +    ) -> Result<super::query_route::QueryRoute> {
    +        let task_queue = super::query_route::trimmed(DB::optional_string(run, "queue")?.as_deref()).unwrap_or("default").to_owned();
    +        let workflow_type = DB::optional_string(run, "workflow_type")?;
    +        let compatibility = DB::optional_string(run, "compatibility")?;
             let fresh_after = now() - chrono::Duration::seconds(stale_after.max(1));
             let rows = Self::query("SELECT capabilities,supported_workflow_types,build_id,workflow_definition_fingerprints,last_heartbeat_at FROM workflow_worker_registrations WHERE namespace=$1 AND task_queue=$2 AND status='active' ORDER BY worker_id")
                 .bind(self.namespace.as_ref())
                 .bind(task_queue.as_str())
    -            .fetch_all(&self.pool)
    +            .fetch_all(&mut *connection)
                 .await?;
             let mut workers = Vec::with_capacity(rows.len());
             for row in rows {
    @@ -109,16 +127,15 @@ where
                 &task_queue,
                 super::query_route::trimmed(workflow_type.as_deref()),
                 super::query_route::trimmed(compatibility.as_deref()),
    -            &started,
    +            started,
                 &workers,
             ))
         }
     
         /// `WorkflowRun::typedSearchAttributes`, sorted by key; PHP renders an
         /// empty set as `[]`.
    -    async fn typed_search_attributes(&self, run_id: &str) -> Result<Value> {
    -        let mut connection = self.pool.acquire().await?;
    -        let rows = Self::typed_rows(&mut connection, run_id).await?;
    +    async fn typed_search_attributes(connection: &mut DB::Connection, run_id: &str) -> Result<Value> {
    +        let rows = Self::typed_rows(connection, run_id).await?;
             Ok(if rows.is_empty() {
                 json!([])
             } else {
    @@ -186,7 +203,7 @@ where
                 ..Default::default()
             };
             rows.summary = next().into_iter().next();
    -        rows.search_attributes = self.typed_search_attributes(run_id).await?;
    +        rows.search_attributes = Self::typed_search_attributes(&mut *self.pool.acquire().await?, run_id).await?;
             if let Some(summary) = &rows.summary {
                 rows.task_problem_badge = super::run_diagnostics::task_problem_badge(
                     summary["task_problem"].as_bool().unwrap_or(false),
    @@ -198,10 +215,10 @@ where
         }
     
         /// `runUpdateDiagnostics`: the run's updates in command order.
    -    async fn update_diagnostics(&self, run_id: &str) -> Result<Vec<Value>> {
    +    async fn update_diagnostics(connection: &mut DB::Connection, run_id: &str) -> Result<Vec<Value>> {
             let rows = Self::query("SELECT id,workflow_command_id,workflow_instance_id,workflow_run_id,target_scope,requested_workflow_run_id,resolved_workflow_run_id,update_name,status,outcome,command_sequence,workflow_sequence,rejection_reason,validation_errors,failure_id,failure_message,accepted_at,applied_at,rejected_at,closed_at FROM workflow_updates WHERE workflow_run_id=$1 ORDER BY command_sequence,created_at,id")
                 .bind(run_id)
    -            .fetch_all(&self.pool)
    +            .fetch_all(&mut *connection)
                 .await?;
             let mut updates = Vec::with_capacity(rows.len());
             for row in rows {
    @@ -227,9 +244,14 @@ where
         /// A run's compatibility marker and whether the live fleet supports it,
         /// as describe and history report them.
         pub(super) async fn compatibility_fields(&self, run: &DB::Row) -> Result<Map<String, Value>> {
    +        self.compatibility_fields_on(&mut *self.pool.acquire().await?, run).await
    +    }
    +
    +    /// `compatibility_fields` on a given connection.
    +    async fn compatibility_fields_on(&self, connection: &mut DB::Connection, run: &DB::Row) -> Result<Map<String, Value>> {
             let compatibility = DB::optional_string(run, "compatibility")?;
             let queue = DB::optional_string(run, "queue")?;
    -        let snapshots = self.fleet_snapshots(now()).await?;
    +        let snapshots = self.fleet_snapshots_on(connection, now()).await?;
             let (supported, fleet_reason) = super::run_diagnostics::fleet_supports(
                 &snapshots,
                 compatibility.as_deref().map(str::trim).filter(|value| !value.is_empty()),
    @@ -243,9 +265,11 @@ where
             ]))
         }
     
    -    /// The fields `formatRun` adds for a described run row.
    +    /// The fields `formatRun` adds for a described run row, read in
    +    /// describe's snapshot.
         pub(super) async fn describe_fields(
             &self,
    +        tx: &mut Transaction<'_, DB>,
             run: &DB::Row,
             current: bool,
             terminal: bool,
    @@ -255,27 +279,21 @@ where
         ) -> Result<Map<String, Value>> {
             let run_id = DB::string(run, "id")?;
             let status = DB::string(run, "status")?;
    -        let started = Self::query("SELECT payload FROM workflow_history_events WHERE workflow_run_id=$1 AND event_type='WorkflowStarted' ORDER BY sequence LIMIT 1")
    -            .bind(run_id.as_str())
    -            .fetch_optional(&self.pool)
    -            .await?
    -            .map(|row| DB::document_row(&row, "payload"))
    -            .transpose()?
    -            .unwrap_or(Value::Null);
    +        let started = Self::started_payload(tx, &run_id).await?;
             let summary = Self::query("SELECT wait_kind,wait_reason FROM workflow_run_summaries WHERE id=$1")
                 .bind(run_id.as_str())
    -            .fetch_optional(&self.pool)
    +            .fetch_optional(&mut **tx)
                 .await?;
             let (wait_kind, wait_reason) = match summary {
                 Some(row) => (DB::optional_string(&row, "wait_kind")?, DB::optional_string(&row, "wait_reason")?),
                 None => (None, None),
             };
    -        let compatibility = self.compatibility_fields(run).await?;
    +        let compatibility = self.compatibility_fields_on(tx, run).await?;
             // `canServeQuery`: failed, cancelled and terminated runs refuse
             // queries; others need a registered route.
             let query_servable = current
                 && (!terminal || status == "completed")
    -            && self.query_route(run, stale_after).await?.servable;
    +            && self.query_route_on(tx, run, stale_after, &started).await?.servable;
             let archived = DB::optional_instant(run, "archived_at")?.is_some();
             let (input_omitted, output_omitted) = (oversized(input), oversized(output));
             let mut fields = Map::new();
    @@ -293,10 +311,7 @@ where
             let routing = if DB::optional_string(run, "import_source")?.as_deref() == Some(super::waterline_import::IMPORT_SOURCE) {
                 Value::Null
             } else {
    -            let mut tx = self.begin_read().await?;
    -            let routing = self.definition_inspect(&mut tx, run, None).await?;
    -            tx.commit().await?;
    -            routing
    +            self.definition_inspect(tx, run, None).await?
             };
             fields.insert("definition_routing".into(), routing);
             fields.insert("payload_previews".into(), json!({"input_omitted":input_omitted,"output_omitted":output_omitted,
    @@ -304,14 +319,12 @@ where
             fields.insert("last_progress_at".into(), iso8601(DB::optional_instant(run, "last_progress_at")?));
             fields.insert("wait_kind".into(), json!(wait_kind));
             fields.insert("wait_reason".into(), json!(wait_reason));
    -        fields.insert("search_attributes".into(), self.typed_search_attributes(&run_id).await?);
    +        fields.insert("search_attributes".into(), Self::typed_search_attributes(tx, &run_id).await?);
             fields.insert("actions".into(), actions(current, terminal, archived, query_servable));
             fields.insert("updates_scope".into(), json!("selected_run"));
    -        fields.insert("updates".into(), json!(self.update_diagnostics(&run_id).await?));
    +        fields.insert("updates".into(), json!(Self::update_diagnostics(tx, &run_id).await?));
             // `terminalFailurePayload`: a failed run's failure, last (Server #967).
    -        let mut tx = self.begin_read().await?;
    -        let failure = Self::terminal_failure_describe(&mut tx, &run_id, DB::string(run, "status")?.as_str()).await?;
    -        tx.commit().await?;
    +        let failure = Self::terminal_failure_describe(tx, &run_id, DB::string(run, "status")?.as_str()).await?;
             for (key, value) in failure.into_iter().flatten() {
                 fields.insert(key.into(), value);
             }
    diff --git a/rust/src/runtime/run_diagnostics.rs b/rust/src/runtime/run_diagnostics.rs
    index 03c4bca7..aa413fae 100644
    --- a/rust/src/runtime/run_diagnostics.rs
    +++ b/rust/src/runtime/run_diagnostics.rs
    @@ -428,8 +428,17 @@ where
         /// `WorkflowCompatibilityFleet::detailsForNamespace` from the
         /// registrations whose heartbeat is within the fleet window.
         pub(super) async fn fleet_snapshots(&self, at: DateTime<Utc>) -> Result<Vec<(String, Option<String>, Vec<String>, DateTime<Utc>)>> {
    +        self.fleet_snapshots_on(&mut *self.pool.acquire().await?, at).await
    +    }
    +
    +    /// `fleet_snapshots` on a given connection.
    +    pub(super) async fn fleet_snapshots_on(
    +        &self,
    +        connection: &mut DB::Connection,
    +        at: DateTime<Utc>,
    +    ) -> Result<Vec<(String, Option<String>, Vec<String>, DateTime<Utc>)>> {
             let rows = Self::query("SELECT worker_id,task_queue,build_id,last_heartbeat_at FROM workflow_worker_registrations WHERE namespace=$1 AND last_heartbeat_at IS NOT NULL")
    -            .bind(self.namespace.as_ref()).fetch_all(&self.pool).await?;
    +            .bind(self.namespace.as_ref()).fetch_all(&mut *connection).await?;
             let mut snapshots = Vec::new();
             for row in rows {
                 let Some(heartbeat) = DB::optional_instant(&row, "last_heartbeat_at")? else { continue };
    diff --git a/rust/src/runtime/store.rs b/rust/src/runtime/store.rs
    index b2b5b71c..64765366 100644
    --- a/rust/src/runtime/store.rs
    +++ b/rust/src/runtime/store.rs
    @@ -773,6 +773,19 @@ where
                 .bind(run_id)
                 .fetch_all(&self.pool)
                 .await?;
    +        self.decoded_memo(memo_rows).await
    +    }
    +
    +    /// `run_memo` on a given connection.
    +    async fn run_memo_on(&self, connection: &mut DB::Connection, run_id: &str) -> Result<Value> {
    +        let memo_rows = Self::query(DB::MEMO_READ)
    +            .bind(run_id)
    +            .fetch_all(&mut *connection)
    +            .await?;
    +        self.decoded_memo(memo_rows).await
    +    }
    +
    +    async fn decoded_memo(&self, memo_rows: Vec<DB::Row>) -> Result<Value> {
             let mut stored = Vec::with_capacity(memo_rows.len());
             for memo in memo_rows {
                 let portable = if DB::optional_number(&memo, "portable_value_sequence")?
    @@ -801,11 +814,15 @@ where
         /// The run description; with a worker stale window it also carries the
         /// fields PHP's `formatRun` adds (actions, fleet, wait and updates).
         pub(crate) async fn describe_with(&self, workflow_id: &str, run_id: Option<&str>, stale_after: Option<i64>) -> Result<Value> {
    +        // Every read of a description shares one read-only snapshot and one
    +        // pool connection, so a described run is consistent and describing
    +        // takes the pool's connections from transitions as little as it can.
    +        let mut tx = self.begin_read().await?;
             let row = Self::query("SELECT r.*,i.execution_timeout_seconds,i.current_run_id,(SELECT parent_workflow_run_id FROM workflow_links l WHERE l.child_workflow_run_id=r.id AND l.link_type='continue_as_new' LIMIT 1) AS continued_from_run_id,(SELECT COUNT(*) FROM workflow_runs counted WHERE counted.workflow_instance_id=i.id) AS run_count FROM workflow_runs r JOIN workflow_instances i ON i.id=r.workflow_instance_id WHERE i.id=$1 AND r.id=COALESCE($2,i.current_run_id) AND r.namespace=$3")
    -            .bind(workflow_id).bind(run_id).bind(self.namespace.as_ref()).fetch_optional(&self.pool).await?
    +            .bind(workflow_id).bind(run_id).bind(self.namespace.as_ref()).fetch_optional(&mut *tx).await?
                 .ok_or_else(|| refuse(StatusCode::NOT_FOUND, if run_id.is_some() {"run_not_found"} else {"instance_not_found"}))?;
             let output = DB::optional_string(&row, "output")?;
    -        let memo = self.run_memo(&DB::string(&row, "id")?).await?;
    +        let memo = self.run_memo_on(&mut tx, &DB::string(&row, "id")?).await?;
             let status = DB::string(&row, "status")?;
             let terminal = matches!(
                 status.as_str(),
    @@ -818,7 +835,7 @@ where
             // Only a stored external reference is read, to tell whether its preview
             // is omitted; inline payloads stay unread.
             let command_rows = Self::query(DB::RUN_COMMANDS_SQL)
    -            .bind(DB::string(&row, "id")?).bind(workflow_id).fetch_all(&self.pool).await?;
    +            .bind(DB::string(&row, "id")?).bind(workflow_id).fetch_all(&mut *tx).await?;
             let mut commands = Vec::with_capacity(command_rows.len());
             let mut reason_codec = None;
             for command in command_rows {
    @@ -889,10 +906,11 @@ where
                 "run_deadline_at": super::run_describe::iso8601(DB::optional_instant(&row,"run_deadline_at")?)});
             if let Some(stale_after) = stale_after {
                 let fields = self
    -                .describe_fields(&row, current, terminal, &described["input_envelope"], &described["output_envelope"], stale_after)
    +                .describe_fields(&mut tx, &row, current, terminal, &described["input_envelope"], &described["output_envelope"], stale_after)
                     .await?;
                 described.as_object_mut().expect("description object").extend(fields);
             }
    +        tx.commit().await?;
             // `formatRun` for a Waterline v1 projection: no control-plane
             // description, every action off, the stored codec and progress time,
             // and the projection's metadata.
  3. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    Intake is filed as P0, owner server. Shared index, allocation and static review findings.

    Complete sanitized diff reference(s): 0003 part 1/1.

    Shared Lockbox bundle: lab4/general/dw-performance-intake/2026-11-06/sanitized-tricks-20-25.zip (101,306 bytes; SHA-256 3e5b593ed89536451be1c8d74abf2ee6e4782cd3f7a75fe5fc9a645d648a52da). Its roundtrip and member hashes are verified. The supplied patches and benchmark results remain external reference data; no patch was applied or executed during intake. Existing issue acceptance and subsequent owner review remain in force.

  4. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    An implementation is prepared locally and not yet published: commit 581e08c4, tree 8a6223469151ff699b4f50ec9375c24609c0c017, on main 1c34f3b7 (branch feat/server-1075-describe-snapshot). It follows the #325 runner successor and #1093 in General's Source-train ordering.

    What it does

    • describe_with opens one begin_read transaction and routes every description read through that one connection: run row, memo, commands, summary wait fields, fleet snapshots, query route, definition routing, typed search attributes, updates, terminal failure, and v1 projection metadata/failure.
    • The snapshot primitives are the existing ones: PostgreSQL REPEATABLE READ READ ONLY, MySQL START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY, SQLite deferred BEGIN on a WAL database.
    • An error drops the transaction, which rolls it back. The connection lives for exactly one description, and nothing inside takes a second pool connection.
    • The WorkflowStarted payload is read once and passed to the query route and definition routing. Other callers of those helpers keep their own reads through unchanged pool wrappers.
    • DTOs, authorization, routing and absent-run refusals are unchanged.

    Controls (qualify_describe_snapshot, wired for SQLite, PostgreSQL and MySQL)

    • One start-payload read per describe; it was 2 before this change.
    • Inside one snapshot, after describe has started, the test commits changes to workflow_runs.business_key and workflow_run_summaries.wait_reason from another connection. A second describe in the same snapshot is byte-identical to the first, and a fresh describe shows the change.
    • Negative control: moving only the run-row read back to the pool makes this test fail.

    Local result (lab4, CI's pinned Rust image): 413 runtime library tests and the full SQLite execution suite (738 passed, 1 existing ignore). PostgreSQL/MySQL coverage comes from the normal PR checks. Measured checkout/query reduction under load is not claimed here.

    Owner: Server.

  5. rmcdaniel commented on Nov 8, 2026

    @rmcdaniel
    MemberAuthor

    Operator nudge: this benchmax ticket (P0) has had no linked PR and no activity for about 8 h. Please pick it up next, after the current work on #1057. Suggested order for the stalled server tickets: #1063, #1068, #1075, #1077, #1078, #1079, then #1081 (P2); this one is 3 of 7. Open a draft PR as soon as work starts so the tracker shows it. If it is blocked, add the status:blocked label with a one-line reason.

  6. rmcdaniel commented on Nov 9, 2026

    @rmcdaniel
    MemberAuthor

    General reviewed the preserved WIP 581e08c4 against maintained Server main 603f9f5c. The original WIP ref is unchanged; no cherry-pick, build, test or push ran.

    One acceptance gap must be fixed when porting it: WIP describe_with calls the ordinary begin_read. On current MySQL/MariaDB that uses START TRANSACTION WITH CONSISTENT SNAPSHOT, READ ONLY, which preserves the session isolation level and does not fix a snapshot under READ COMMITTED. Main already has a causal backend control, qualification_repeatable_snapshot_is_fixed_under_a_read_committed_session, proving that the ordinary begin sees a later commit while REPEATABLE_READ_SNAPSHOT_BEGIN does not.

    Use the existing Store::begin_repeatable_read for the description instead of changing global/session defaults. PostgreSQL's helper already selects a repeatable read-only snapshot; SQLite retains its existing transaction form. The WIP's test currently checks two descriptions in one default-session transaction and does not force the MySQL/MariaDB READ COMMITTED counterexample.

    The port therefore needs an actual concurrent transition/describe control on each backend, explicitly including READ COMMITTED MySQL/MariaDB; one start-payload read; a single-connection description path; and bounded connection return on success, missing/deleted-run errors and cancellation. Preserve all DTO, authorization, routing and projection behavior. The WIP is still unqualified. This remains behind the current 3.3.1 consumer follow-through and #1068 correction, with no new source train selected.

  7. rmcdaniel commented on Nov 9, 2026

    @rmcdaniel
    MemberAuthor

    General has ported the preserved preparation to maintained source, locally only. Original WIP 581e08c4 is unchanged.

    Candidate 684f1d478ab3693affedda71718d3f85deb7081b, tree 390625347736ff62a7e1cf250c4ef9b98ab95493, parent/main 603f9f5c. Delta35,191 bytes / SHA-256 5e3a7d1a03affa3c4ac3ec8d040ad27016579d67940e04781c4ddd52e0a18b15, ten runtime files. It uses the existing begin_repeatable_read, not the preparation's ordinary begin_read, so MySQL/MariaDB READ COMMITTED sessions get a fixed snapshot. Every description read uses that connection; native start payload is shared with query/definition routing. The projection's first-event metadata read retains its distinct authority.

    The old preparation's two-describe control is replaced by a test-only, task-local pause immediately after the run row. A real close_workflow(Terminate) commits through an independent writer pool before description resumes. New controls compare the complete description with its pre-transition value, require one pool checkout and one native start-payload read, observe the fresh terminal state, and verify connection return after missing instance/run, a real stored-memo decoding error and cancellation. Readers have a one-connection pool. MySQL/MariaDB exercise explicit REPEATABLE READ plus READ COMMITTED; an ordinary-read counterexample must mix the later command journal, before and after the one-transaction repeatable override. PostgreSQL and read-only SQLite use the same concurrent transition control.

    Only source/diff/privacy checks ran. No compile, runtime test, local daemon or hosted push is claimed. First compile and execution will be the normal source train after #1110's integration/main custody; it is the only current integration train. This item is outside released3.3.1 and has no benchmark claim.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:generalcompletion:evidence-requiredClose only after all explicit acceptance and operational evidence is publickind:featureA public product capability or experience is requestedpriority:P0Immediate release or data-integrity riskrepo:serverOwned by the standalone server repository

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions