pub struct WaveStore {
conn: Mutex<Connection>,
registry: Mutex<Option<Arc<Registry>>>,
}Expand description
SQLite-backed object store for WaveObj types.
Fields§
§conn: Mutex<Connection>§registry: Mutex<Option<Arc<Registry>>>Cross-version named-agent registry. None for in-memory test
stores; Some for production srv. Mutations to
db_agent_instances parallel-write to this registry when set.
See docs/specs/SPEC_SHARED_AGENT_REGISTRY_2026_05_12.md.
Implementations§
Source§impl WaveStore
impl WaveStore
Sourcepub fn open(path: &Path) -> Result<Self, StoreError>
pub fn open(path: &Path) -> Result<Self, StoreError>
Open a WaveStore backed by a file on disk. Configures WAL mode and 5s busy timeout (matching Go).
Sourcepub fn open_in_memory() -> Result<Self, StoreError>
pub fn open_in_memory() -> Result<Self, StoreError>
Open an in-memory WaveStore for testing.
Sourcepub(crate) fn conn(&self) -> &Mutex<Connection>
pub(crate) fn conn(&self) -> &Mutex<Connection>
Crate-internal accessor for sibling modules that maintain their
own per-table CRUD via the DroneStore extension trait
pattern (see agentmux-srv/src/drone/storage.rs). Outside
callers must use the typed methods on this impl.
Sourcepub fn run_agents_consolidate(
&self,
data_dir: Option<&Path>,
) -> Result<ConsolidateStats, StoreError>
pub fn run_agents_consolidate( &self, data_dir: Option<&Path>, ) -> Result<ConsolidateStats, StoreError>
Run the Phase 3a db_agents consolidation backfill under the
wstore’s exclusive connection lock. Idempotent — gated by a
marker file in data_dir (skip with None for tests).
fn configure_and_migrate(conn: Connection) -> Result<Self, StoreError>
Sourcepub fn set_registry(&self, registry: Arc<Registry>)
pub fn set_registry(&self, registry: Arc<Registry>)
Attach a shared cross-version agent registry. Called once on
srv startup after WaveStore::open and before the store is
wrapped in Arc. Mutations to db_agent_instances will then
parallel-write to the registry; the SQLite table remains the
authoritative read path for PR A.
fn registry(&self) -> Option<Arc<Registry>>
Public accessor for the cross-version named-agent registry.
Returns None when the registry couldn’t be resolved at
startup (CI / unusual envs); callers must handle the absent
case by falling back to SQLite.
Sourcefn table_name<T: WaveObj>() -> String
fn table_name<T: WaveObj>() -> String
Table name for a WaveObj type: db_<otype>.
Sourcepub fn get<T: WaveObj>(&self, oid: &str) -> Result<Option<T>, StoreError>
pub fn get<T: WaveObj>(&self, oid: &str) -> Result<Option<T>, StoreError>
Get a single object by OID. Returns None if not found.
Sourcepub fn must_get<T: WaveObj>(&self, oid: &str) -> Result<T, StoreError>
pub fn must_get<T: WaveObj>(&self, oid: &str) -> Result<T, StoreError>
Get a single object, returning StoreError::NotFound if missing.
Sourcepub fn get_raw(
&self,
otype: &str,
oid: &str,
) -> Result<Option<Value>, StoreError>
pub fn get_raw( &self, otype: &str, oid: &str, ) -> Result<Option<Value>, StoreError>
Get a single object as raw JSON Value by otype and OID. Used by GetObject/GetObjects to return data without strict struct deserialization.
Sourcepub fn exists_raw(&self, otype: &str, oid: &str) -> Result<bool, StoreError>
pub fn exists_raw(&self, otype: &str, oid: &str) -> Result<bool, StoreError>
Check if an object exists (by otype and OID).
Sourcepub fn insert<T: WaveObj>(&self, obj: &mut T) -> Result<(), StoreError>
pub fn insert<T: WaveObj>(&self, obj: &mut T) -> Result<(), StoreError>
Insert a new object. Sets version to 1.
Sourcepub fn update<T: WaveObj>(&self, obj: &mut T) -> Result<i64, StoreError>
pub fn update<T: WaveObj>(&self, obj: &mut T) -> Result<i64, StoreError>
Update an existing object. Increments version atomically. Returns the new version number.
Sourcepub fn update_raw(
&self,
otype: &str,
oid: &str,
value: &Value,
) -> Result<i64, StoreError>
pub fn update_raw( &self, otype: &str, oid: &str, value: &Value, ) -> Result<i64, StoreError>
Update an object using raw JSON (bypasses struct deserialization). Used by UpdateObject where the frontend sends the full replacement object. This matches Go’s generic map-based UpdateObject behavior.
Sourcepub fn delete_by_otype(&self, otype: &str, oid: &str) -> Result<(), StoreError>
pub fn delete_by_otype(&self, otype: &str, oid: &str) -> Result<(), StoreError>
Delete by otype string and OID (for dynamic dispatch).
Validates otype against VALID_OTYPES to prevent SQL injection.
Sourcepub fn get_all<T: WaveObj>(&self) -> Result<Vec<T>, StoreError>
pub fn get_all<T: WaveObj>(&self) -> Result<Vec<T>, StoreError>
Get all objects of a given type.
Sourcepub fn with_tx<F, R>(&self, f: F) -> Result<R, StoreError>
pub fn with_tx<F, R>(&self, f: F) -> Result<R, StoreError>
Execute multiple operations in a single SQLite transaction. Acquires the Mutex once, wraps all operations in BEGIN/COMMIT. On error, rolls back and returns the error.
This is the key performance primitive — reduces N lock acquisitions and N fsyncs to 1 each.
Source§impl WaveStore
impl WaveStore
Sourcepub fn user_clone_defs_for_template(
&self,
template_id: &str,
) -> Result<Vec<AgentDefinition>, StoreError>
pub fn user_clone_defs_for_template( &self, template_id: &str, ) -> Result<Vec<AgentDefinition>, StoreError>
List all agent definitions, most-recently-used first.
Phase 3b: read from the consolidated db_agents table. Order is
most-recently-touched first (updated_at DESC) then stable on
creation (created_at ASC). Dual-write keeps db_agents.updated_at
fresh on every definition mutation AND every instance lifecycle
touch, so this approximates the old “MAX(started_at)” ordering
without joining the instances table — recency on a row tracks the
last time the agent was either edited or launched.
Result-set shape: every row in db_agents is returned. Under the
fold rule (agents_consolidate.rs):
- Templates (
is_template = 1) appear once each. - User-cloned defs (
is_template = 0, id matches olddb_agent_definitions.id) appear once each — instance bindings, when present, are folded into this same row. - Template-instances (
is_template = 0, id matches olddb_agent_instances.id) appear once each as first-class user agents.parent_idon the returned struct is sourced fromdb_agents.parent_template_id— the dual-write preserves the legacy semantics (def.parent_id for user-clones, template id for instance projections), so existing handlers that look up the parent template by id continue to work. Find user-clone definitions for a given seeded template (rows indb_agent_definitionswithis_seeded = 0andparent_id = <template.id>). Returns the most-recent-first.
Reads db_agent_definitions directly — NOT the db_agents
consolidated view — because the latter surfaces template-
instance projection rows under the same
is_template = 0 AND parent_template_id = <tpl> shape as
user-clone defs, which would conflate two distinct things.
Sole production caller today is the template_promote
migration’s “did the user delete the deterministic-id
clone?” diagnostic logging and its tests. Kept public so
follow-up callers (e.g. a cleanup pass that GCs orphaned
pre-deterministic-id clones from earlier migration code)
can use it without re-deriving the schema.
Sourcepub fn agent_def_get(
&self,
id: &str,
) -> Result<Option<AgentDefinition>, StoreError>
pub fn agent_def_get( &self, id: &str, ) -> Result<Option<AgentDefinition>, StoreError>
Fetch a single agent definition by primary key. Reads
db_agent_definitions directly (not the db_agents
consolidated view that agent_def_list reads), so it
returns user-clone definitions and seeded templates, never
template-instance projection rows.
Used by the template_promote migration’s deterministic-id
idempotency check (see
migrate_promote_template_sessions_v1): every retry asks
“does the promote-target clone for this template already
exist?” and either reuses it or inserts it.
pub fn agent_def_list(&self) -> Result<Vec<AgentDefinition>, StoreError>
Sourcepub fn agent_def_count(&self) -> Result<i64, StoreError>
pub fn agent_def_count(&self) -> Result<i64, StoreError>
Count agent rows (used by seed engine to check if seeding is needed).
Phase 3b: reads from the consolidated db_agents table — every
definition AND every template-instance projection counts, mirroring
the new shape of agent_def_list. The seed engine only cares about
== 0 to decide “fresh database, seed templates”, so the broader
count doesn’t false-positive that branch (an empty db_agents
guarantees an empty db_agent_definitions).
Sourcepub fn agent_def_delete_seeded(&self) -> Result<usize, StoreError>
pub fn agent_def_delete_seeded(&self) -> Result<usize, StoreError>
Delete all seeded agents (is_seeded=1). Used by reseed to clear built-in agents.
Sourcepub fn agent_def_insert(
&self,
agent: &mut AgentDefinition,
) -> Result<(), StoreError>
pub fn agent_def_insert( &self, agent: &mut AgentDefinition, ) -> Result<(), StoreError>
Insert a new agent definition. Auto-derives slug from name if empty,
resolves collisions by appending -2, -3, etc., and mutates
agent.slug so the caller sees the resolved value (important
for handlers that serialize the struct back to the frontend
after insert).
The collision check + insert run under a single mutex lock, so this is race-safe against concurrent inserts on the same connection.
Set the user_hidden flag on a single agent definition. Phase 2
of the two-tier picker (Q2 Decision Y). Returns:
Ok(true) — row updated.
Ok(false) — no row with that id exists.
Err(...) — the row exists but is NOT a seeded template
(is_seeded != 1). User-owned definitions go
through agent_def_delete, not hide.
Does NOT bump updated_at: hide is a per-user view-state flag,
not a definition-content edit. Keeps updated_at faithful to the
agent’s payload (the manifest re-sync compares description etc.
against the canonical row).
Sourcepub fn agent_def_update(
&self,
agent: &mut AgentDefinition,
) -> Result<bool, StoreError>
pub fn agent_def_update( &self, agent: &mut AgentDefinition, ) -> Result<bool, StoreError>
Update an existing agent definition (all fields except id, created_at, is_seeded).
parent_id and branch_label are NOT updatable post-insert — they
describe the agent’s provenance; renaming or re-branching is done by
creating a new fork, not mutating the original.
Self-stamps updated_at with the current time and writes it back into
agent.updated_at, so the caller’s struct (e.g. an RPC response body)
reflects exactly what landed in the database.
Sourcepub fn agent_def_delete(&self, id: &str) -> Result<bool, StoreError>
pub fn agent_def_delete(&self, id: &str) -> Result<bool, StoreError>
Delete a agent definition by id. Returns true if a row was deleted.
Sourcepub fn agent_content_get(
&self,
agent_id: &str,
content_type: &str,
) -> Result<Option<AgentContent>, StoreError>
pub fn agent_content_get( &self, agent_id: &str, content_type: &str, ) -> Result<Option<AgentContent>, StoreError>
Get a single content blob for an agent.
Sourcepub fn agent_content_set(
&self,
content: &AgentContent,
) -> Result<(), StoreError>
pub fn agent_content_set( &self, content: &AgentContent, ) -> Result<(), StoreError>
Upsert a content blob for an agent.
Sourcepub fn agent_content_get_all(
&self,
agent_id: &str,
) -> Result<Vec<AgentContent>, StoreError>
pub fn agent_content_get_all( &self, agent_id: &str, ) -> Result<Vec<AgentContent>, StoreError>
Get all content blobs for an agent.
Sourcepub fn agent_content_delete(
&self,
agent_id: &str,
content_type: &str,
) -> Result<bool, StoreError>
pub fn agent_content_delete( &self, agent_id: &str, content_type: &str, ) -> Result<bool, StoreError>
Delete a specific content blob. Returns true if a row was deleted.
Sourcepub fn agent_skill_list(
&self,
agent_id: &str,
) -> Result<Vec<AgentSkill>, StoreError>
pub fn agent_skill_list( &self, agent_id: &str, ) -> Result<Vec<AgentSkill>, StoreError>
List all skills for an agent, ordered by created_at ascending.
Sourcepub fn agent_skill_get(
&self,
id: &str,
) -> Result<Option<AgentSkill>, StoreError>
pub fn agent_skill_get( &self, id: &str, ) -> Result<Option<AgentSkill>, StoreError>
Get a single skill by id.
Sourcepub fn agent_skill_insert(&self, skill: &AgentSkill) -> Result<(), StoreError>
pub fn agent_skill_insert(&self, skill: &AgentSkill) -> Result<(), StoreError>
Insert a new skill.
Sourcepub fn agent_skill_update(&self, skill: &AgentSkill) -> Result<bool, StoreError>
pub fn agent_skill_update(&self, skill: &AgentSkill) -> Result<bool, StoreError>
Update an existing skill (all fields except id, agent_id, created_at).
Sourcepub fn agent_skill_delete(&self, id: &str) -> Result<bool, StoreError>
pub fn agent_skill_delete(&self, id: &str) -> Result<bool, StoreError>
Delete a skill by id. Returns true if a row was deleted.
Sourcepub fn agent_history_append(
&self,
agent_id: &str,
entry: &str,
) -> Result<AgentHistory, StoreError>
pub fn agent_history_append( &self, agent_id: &str, entry: &str, ) -> Result<AgentHistory, StoreError>
Append a history entry for an agent. Auto-sets session_date (today) and timestamp.
Sourcepub fn agent_history_list(
&self,
agent_id: &str,
session_date: Option<&str>,
limit: i64,
offset: i64,
) -> Result<Vec<AgentHistory>, StoreError>
pub fn agent_history_list( &self, agent_id: &str, session_date: Option<&str>, limit: i64, offset: i64, ) -> Result<Vec<AgentHistory>, StoreError>
List history entries for an agent, with optional date filter and pagination.
Sourcepub fn agent_history_search(
&self,
agent_id: &str,
query: &str,
limit: i64,
) -> Result<Vec<AgentHistory>, StoreError>
pub fn agent_history_search( &self, agent_id: &str, query: &str, limit: i64, ) -> Result<Vec<AgentHistory>, StoreError>
Search history entries for an agent using LIKE-based matching.
Source§impl WaveStore
impl WaveStore
Sourcepub fn identity_list(
&self,
provider: Option<&str>,
) -> Result<Vec<IdentityAccount>, StoreError>
pub fn identity_list( &self, provider: Option<&str>, ) -> Result<Vec<IdentityAccount>, StoreError>
List identity accounts. If provider is Some, filter to that
provider; otherwise return every account, ordered by most recent
update first (so the identity panel shows live accounts on top).
pub fn identity_get( &self, id: &str, ) -> Result<Option<IdentityAccount>, StoreError>
Sourcepub fn identity_upsert(
&self,
account: &IdentityAccount,
) -> Result<(), StoreError>
pub fn identity_upsert( &self, account: &IdentityAccount, ) -> Result<(), StoreError>
Upsert an identity account. If account.id is empty the caller
must generate one first (we don’t silently mint ids here — callers
should know whether they’re creating vs updating).
pub fn identity_delete(&self, id: &str) -> Result<bool, StoreError>
Sourcepub fn agent_identity_link(
&self,
agent_id: &str,
account_id: &str,
provider: &str,
) -> Result<(), StoreError>
pub fn agent_identity_link( &self, agent_id: &str, account_id: &str, provider: &str, ) -> Result<(), StoreError>
Link an agent to an identity for a given provider. Overwrites any existing link for the same (agent_id, provider) — each agent has at most one account per provider.
Sourcepub fn agent_identity_unlink(
&self,
agent_id: &str,
provider: &str,
) -> Result<bool, StoreError>
pub fn agent_identity_unlink( &self, agent_id: &str, provider: &str, ) -> Result<bool, StoreError>
Remove the identity link for a given (agent_id, provider). Returns true iff a link existed.
Sourcepub fn agent_identity_list_for_agent(
&self,
agent_id: &str,
) -> Result<Vec<AgentIdentityLink>, StoreError>
pub fn agent_identity_list_for_agent( &self, agent_id: &str, ) -> Result<Vec<AgentIdentityLink>, StoreError>
List all (agent_id, account_id, provider) triples for an agent.
Sourcepub fn instance_list(
&self,
definition_id: Option<&str>,
status: Option<&str>,
) -> Result<Vec<AgentInstance>, StoreError>
pub fn instance_list( &self, definition_id: Option<&str>, status: Option<&str>, ) -> Result<Vec<AgentInstance>, StoreError>
List instances. Both filters are optional — pass None to scan all
instances. Ordered by created_at descending (most recent first).
pub fn instance_get( &self, id: &str, ) -> Result<Option<AgentInstance>, StoreError>
Sourcepub fn instance_create(&self, inst: &AgentInstance) -> Result<(), StoreError>
pub fn instance_create(&self, inst: &AgentInstance) -> Result<(), StoreError>
Insert a new instance row. Caller is responsible for the id (UUID).
Set the display_hidden flag on an existing instance row. Used
by the “Forget agent” affordance — soft-delete only; the row +
working directory remain on disk for audit + recovery.
Cross-version case: an agent migrated into the registry from
another version’s SQLite won’t have a row in the current
version’s SQLite. The UPDATE returns 0 rows, but the registry
still needs to flip — otherwise “Forget agent” silently no-ops
on cross-version entries. Returns true if either side acted.
Sourcepub fn instance_list_named(
&self,
limit: usize,
definition_id: Option<&str>,
include_continuations: bool,
) -> Result<Vec<AgentInstance>, StoreError>
pub fn instance_list_named( &self, limit: usize, definition_id: Option<&str>, include_continuations: bool, ) -> Result<Vec<AgentInstance>, StoreError>
List named instances for the launch-modal “Continue agent”
dropdown (include_continuations = false) or the picker
“My Agents” surface (include_continuations = true). Filters
to non-hidden + named rows, sorted by started_at DESC,
capped by limit.
definition_id, when provided, restricts the result to
instances of that definition. Server-side filtering is
necessary because the launch modal opens per-definition: a
user with 200+ named agents across many definitions could
have the current definition’s older instances cut off by a
purely global limit otherwise.
include_continuations controls whether rows with
parent_instance_id != '' (continuation chains) are
returned:
-
false(legacy “head-of-chain only”). Pre-Option-E semantics: hides continuation rows so the launch-modal dropdown shows one entry per chain root.listnamedagentsALSO uses this mode for its same-version SQLite enrichment of registry-sourced rows — the registry mirror filter atregistry_upsert_if_namedexcludes continuations symmetrically, and breaking that symmetry under alimittruncation would let continuation rows displace registry-head rows in the top-N and miss the merge-by-id enrichment. (Codex P1 on PR #1016 first cut: regresses running-state badges and focus-existing-pane hints for any user whose latest instance is a continuation.) -
true(Option-E “include continuations”). For the picker’slistrecentsessionsflow and thetemplate_promotemigration’s instance-name lookup. Under Option E the session zone is anchored ondefinition_id, so a continuation row is simply the most-recent named instance of an agent the user actively used — exactly what those callers want visible. Excluding them hides real agents (the original 2026-05-24 “Maks doesn’t appear under My Agents” report) and makestemplate_promote’s name lookup miss the realinstance_name, falling back to the template name.
Sourcepub fn instance_get_by_name(
&self,
instance_name: &str,
) -> Result<Option<AgentInstance>, StoreError>
pub fn instance_get_by_name( &self, instance_name: &str, ) -> Result<Option<AgentInstance>, StoreError>
Look up the most recent (by started_at) named instance that
matches the given instance_name. Used by the launch modal to
detect name collisions (“did you mean to continue?”) and by
ContinueNamedAgentCommand to resolve the canonical row when
the caller only knows the name. Hidden rows are excluded.
Sourcepub fn instance_update(&self, inst: &AgentInstance) -> Result<bool, StoreError>
pub fn instance_update(&self, inst: &AgentInstance) -> Result<bool, StoreError>
Update mutable instance fields. id, definition_id,
parent_instance_id, started_at, created_at are immutable
after insert (they describe provenance, not state).
Sourcepub fn instance_repoint_definition(
&self,
old_def_id: &str,
new_def_id: &str,
) -> Result<usize, StoreError>
pub fn instance_repoint_definition( &self, old_def_id: &str, new_def_id: &str, ) -> Result<usize, StoreError>
Repoint every instance currently referencing old_def_id to
new_def_id. Used by the Phase 1 two-tier-picker migration
(SPEC_AGENT_PICKER_TWO_TIER_2026_05_24.md): when a seeded
template has been used directly (carries an agent:<id>:current
zone), the migration clones the template into a user agent and
repoints any instances so the existing reattach flow
(continueOfInstanceId) keeps working against the new
definition_id. Returns the number of rows updated.
definition_id is declared immutable post-insert on the normal
instance_update path. This is the migration escape hatch.
pub fn instance_delete(&self, id: &str) -> Result<bool, StoreError>
Sourcepub fn instance_backfill_identity_id(
&self,
new_identity_id: &str,
) -> Result<usize, StoreError>
pub fn instance_backfill_identity_id( &self, new_identity_id: &str, ) -> Result<usize, StoreError>
Back-fill db_agent_instances.identity_id for legacy rows that
have either the empty string (post-v7 default before the launch
modal required Identity) or the literal "blank" sentinel
(pre-v8 placeholder for “use ambient creds”). Both shapes map
to “no Identity bundle assigned” and the OAuth-bundles startup
migration (PR E, spec §5) routes them to the newly-seeded
Default bundle so the resolver can inject env vars from the
captured ambient credentials at the next spawn.
Returns the number of rows touched. Caller must verify that
new_identity_id is a real db_identity_bundles.id — this
method does NOT enforce FK validity (the column has no FK
constraint per the v7 migration). Mis-use would orphan the
rows to a non-existent bundle; the OAuth-bundles migration
guards against this by only calling here when it just upserted
the bundle row.
Sourcefn registry_upsert_if_named(&self, inst: &AgentInstance)
fn registry_upsert_if_named(&self, inst: &AgentInstance)
Mirror a db_agent_instances mutation into the cross-version
registry. Only fires for named rows. Routes by
display_hidden so the registry file ends up in the tree
matching SQLite’s dropdown filter:
- hidden = true → upsert (atomic write to active/) then
retire (atomic rename to retired/). Net: file lives in
retired/<id>.jsonwith the freshest content. Preventsinstance_updateon a previously-hidden row from resurrecting an active registry file, AND keeps the retired tombstone’s content current. - hidden = false → unretire (no-op if not retired) then
upsert. Net: file in
active/<id>.json, no orphan retired.
Failures are logged, never propagated: SQLite remains authoritative.
Sourcepub fn instance_get_active_for_block(
&self,
block_id: &str,
) -> Result<Option<AgentInstance>, StoreError>
pub fn instance_get_active_for_block( &self, block_id: &str, ) -> Result<Option<AgentInstance>, StoreError>
Look up the most-recently-created active instance for a
block — active = status in (running, paused). Stopped and
crashed instances are skipped: when a user closes a pane and
re-opens it (creating a fresh instance), the resolver should
see the NEW row’s identity_id / memory_id, not bleed creds
from the prior stopped one. Reagent P2 (PR #751).
Sourcepub(crate) fn agents_dual_write_definition_upsert(
&self,
def: &AgentDefinition,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_definition_upsert( &self, def: &AgentDefinition, ) -> Result<(), StoreError>
Mirror a db_agent_definitions row into db_agents as the
canonical row for that definition.
is_seeded = 1rows becomeis_template = 1(canonical template; bindings stay empty).is_seeded = 0rows becomeis_template = 0withparent_template_id = parent_id(user-cloned from a template; bindings come from the matching instance, if any — handled byagents_dual_write_instance_createupdating in place).
Idempotent: uses INSERT … ON CONFLICT(id) DO UPDATE. Existing
bindings on the row (written previously by an instance dual-write)
are preserved — only definition-side fields are overwritten.
Phase 3b: returns Err on failure (previously logged + continued).
Phase 3b readers see db_agents, so a silent dual-write failure
would leak stale data into the picker.
Sourcepub(crate) fn agents_dual_write_definition_delete(
&self,
def_id: &str,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_definition_delete( &self, def_id: &str, ) -> Result<(), StoreError>
Mirror a db_agent_definitions DELETE into db_agents. The
definition row itself is removed; any user-cloned children (rows
with parent_template_id = old_id) are left intact because the
FK cascade on the OLD schema only deletes instances, not other
definitions.
Sourcepub(crate) fn agents_dual_write_seeded_delete(
&self,
cascaded_inst_ids: &[String],
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_seeded_delete( &self, cascaded_inst_ids: &[String], ) -> Result<(), StoreError>
Bulk dual-write: mirror agent_def_delete_seeded. Deletes:
- every
is_template = 1row (the template projections), AND - every
db_agentsrow whoseidis in thecascaded_inst_idsset (template-instance projections that were just removed by the FK cascade ondb_agent_instances).
User-clone DEFINITION projections (is_template = 0, id is a
def_id in db_agent_definitions) are NOT touched — those rows
represent persistent user agents and live or die with their
db_agent_definitions row, not with the seeded-template bulk
delete. Reagent P1 round 4 on #1013: the previous version
scoped by parent_template_id and over-deleted user-clone DEF
projections too. Idempotent.
Sourcepub(crate) fn agents_dual_write_instance_create(
&self,
inst: &AgentInstance,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_instance_create( &self, inst: &AgentInstance, ) -> Result<(), StoreError>
Mirror a db_agent_instances INSERT into db_agents. Always
creates a NEW row in db_agents whose id == instance id.
The row’s identity comes from the instance (id, name, bindings).
Its template-config fields are copied from the parent definition;
parent_template_id points at that definition.
Continuation rows (parent_instance_id non-empty) are skipped —
they’re not “agents” in the new model, they’re a vestigial
pre-Option-E continuation chain that the consolidation retires.
Sourcepub(crate) fn agents_dual_write_instance_update(
&self,
inst: &AgentInstance,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_instance_update( &self, inst: &AgentInstance, ) -> Result<(), StoreError>
Mirror a db_agent_instances UPDATE into db_agents. Touches
only the fields that instance_update writes (block + session +
status + github_context + ended_at) — name/bindings come from
the original create.
Mirror instance_set_hidden into db_agents.user_hidden.
Sourcepub(crate) fn agents_dual_write_instance_repoint(
&self,
old_def_id: &str,
new_def_id: &str,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_instance_repoint( &self, old_def_id: &str, new_def_id: &str, ) -> Result<(), StoreError>
Mirror instance_repoint_definition into db_agents. The
parent_template_id of every user-clone row that pointed at
old_def_id is updated to new_def_id.
Sourcepub(crate) fn agents_dual_write_instance_delete(
&self,
id: &str,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_instance_delete( &self, id: &str, ) -> Result<(), StoreError>
Mirror instance_delete into db_agents.
Sourcepub(crate) fn agents_dual_write_backfill_identity(
&self,
new_identity_id: &str,
) -> Result<(), StoreError>
pub(crate) fn agents_dual_write_backfill_identity( &self, new_identity_id: &str, ) -> Result<(), StoreError>
Mirror instance_backfill_identity_id into db_agents. Same
filter (empty or "blank" identity_id) restricted to user-clone
rows.
Sourcefn agents_projection_key_for_inst(
conn: &Connection,
inst_id: &str,
) -> Option<(String, bool)>
fn agents_projection_key_for_inst( conn: &Connection, inst_id: &str, ) -> Option<(String, bool)>
Reagent P1 round 4 on #1013 — fold-aware projection key lookup.
Resolves “for an instance with this id, which db_agents row
represents it post-create?”. Returns Some((key, is_folded)):
is_folded = true→ key is the parent definition id (the user-clone-def projection absorbs the instance’s bindings).is_folded = false→ key is the instance id (template-instance projection is its own row). ReturnsNoneif the instance no longer exists indb_agent_instances(e.g. already deleted by FK cascade).
Sourcefn load_definition_for_dual_write(
conn: &Connection,
id: &str,
) -> Result<Option<AgentDefinition>>
fn load_definition_for_dual_write( conn: &Connection, id: &str, ) -> Result<Option<AgentDefinition>>
Helper: re-read a definition row from inside an active connection
lock (used by agents_dual_write_instance_create to avoid
re-locking the mutex recursively).
Sourcepub fn bundle_identity_list(&self) -> Result<Vec<Identity>, StoreError>
pub fn bundle_identity_list(&self) -> Result<Vec<Identity>, StoreError>
List all Identity bundles, blank singleton last so the picker shows user-defined bundles first.
pub fn bundle_identity_get( &self, id: &str, ) -> Result<Option<Identity>, StoreError>
Sourcepub fn bundle_identity_upsert(
&self,
identity: &Identity,
) -> Result<(), StoreError>
pub fn bundle_identity_upsert( &self, identity: &Identity, ) -> Result<(), StoreError>
Upsert an Identity bundle. Caller mints the id (no silent generation).
The is_blank flag is reserved for the seeded singleton — callers
should pass false for user-created identities.
Sourcepub fn bundle_identity_delete(&self, id: &str) -> Result<bool, StoreError>
pub fn bundle_identity_delete(&self, id: &str) -> Result<bool, StoreError>
Delete an Identity bundle. Refuses to delete the blank singleton — the launch UI depends on it as the always-present default option.
Sourcepub fn bundle_identity_bind(
&self,
identity_id: &str,
provider: &str,
account_id: &str,
) -> Result<(), StoreError>
pub fn bundle_identity_bind( &self, identity_id: &str, provider: &str, account_id: &str, ) -> Result<(), StoreError>
Set the account for (identity_id, provider). Overwrites any
existing binding for the same (identity, provider).
Sourcepub fn bundle_identity_unbind(
&self,
identity_id: &str,
provider: &str,
) -> Result<bool, StoreError>
pub fn bundle_identity_unbind( &self, identity_id: &str, provider: &str, ) -> Result<bool, StoreError>
Remove the binding for (identity_id, provider). Returns whether a
row was deleted.
Sourcepub fn bundle_identity_bindings(
&self,
identity_id: &str,
) -> Result<Vec<IdentityBinding>, StoreError>
pub fn bundle_identity_bindings( &self, identity_id: &str, ) -> Result<Vec<IdentityBinding>, StoreError>
List bindings for an Identity bundle.
pub fn bundle_memory_list(&self) -> Result<Vec<Memory>, StoreError>
pub fn bundle_memory_get(&self, id: &str) -> Result<Option<Memory>, StoreError>
pub fn bundle_memory_upsert(&self, memory: &Memory) -> Result<(), StoreError>
Sourcepub fn bundle_memory_delete(&self, id: &str) -> Result<bool, StoreError>
pub fn bundle_memory_delete(&self, id: &str) -> Result<bool, StoreError>
Delete a Memory bundle. Refuses to delete the blank singleton.
Trait Implementations§
Source§impl DroneStore for WaveStore
impl DroneStore for WaveStore
fn drone_list(&self) -> Result<Vec<DroneDefinition>, StoreError>
fn drone_get(&self, id: &str) -> Result<Option<DroneDefinition>, StoreError>
fn drone_upsert(&self, wf: &DroneDefinition) -> Result<(), StoreError>
fn drone_delete(&self, id: &str) -> Result<bool, StoreError>
fn drone_run_insert(&self, run: &DroneRun) -> Result<(), StoreError>
Source§fn drone_run_update(&self, run: &DroneRun) -> Result<usize, StoreError>
fn drone_run_update(&self, run: &DroneRun) -> Result<usize, StoreError>
run.id). Used to flip a placeholder
running row into its terminal state once the drain task
completes, so the row exists from the moment the RPC returns.fn drone_runs_for( &self, drone_id: &str, limit: i64, ) -> Result<Vec<DroneRun>, StoreError>
Auto Trait Implementations§
impl !Freeze for WaveStore
impl RefUnwindSafe for WaveStore
impl Send for WaveStore
impl Sync for WaveStore
impl Unpin for WaveStore
impl UnwindSafe for WaveStore
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
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.