Skip to content

[dactyl] Replace every direct .decapod/data/*.db access in src/decapod/ with a dactyl::read / dactyl::write call #1111

Description

@alexhraber

Summary

Once dactyl is published with the public API dactyl::read(datastore, query, optimize) / dactyl::write(datastore, query, optimize) and dactyl::init(cfg), every direct read/write of .decapod/data/*.db (and .decapod/data/*.jsonl) inside src/decapod/ must be replaced with a dactyl call.

Goal

By the end of this issue, Decapod contains no direct SQLite or HTTP-to-Neon call sites at store boundaries. Every store interaction goes through dactyl, with a universal SQL-flavored query authored at the call site and a datastore value forwarded from dactyl::active_datastore().

Call shape (authoritative)

// Per-function call site in src/decapod/
let datastore = dactyl::active_datastore();                          // "sqlite" | "neon"
let query = "select id, title, status from todos where assignee = $1"; // universal SQL-flavored
let optimize = true;                                                  // let dactyl rewrite for the active datastore
dactyl::read(datastore, query, optimize)

Notes:

  • datastore MUST come from dactyl::active_datastore(). Call sites must NOT re-derive datastore from repo.effective_backend() — that translation is owned exclusively by #1112 in src/decapod/dactyl_bridge.rs. Duplicating the translation at a call site re-introduces the leak this epic exists to remove.
  • The query string is authored in Decapod, per function, in universal SQL. dactyl parses it and (when optimize = true) rewrites it for the active datastore.
  • For hard-coded queries, prefer dactyl::query!("select ...") so dialect/datastore mismatches are caught at compile time. optimize defaults to true inside the macro; pass optimize = false to require verbatim forward.

Scope of files to migrate

Audit src/decapod/core/ for any direct .decapod/data/*.db / *.jsonl access:

  • core/db.rs
  • core/broker.rs (writes broker_dedupe.db, appends broker.events.jsonl)
  • core/knowledge.rs (writes knowledge.db)
  • core/governance_artifacts.rs (writes governance.db)
  • core/memory.rs (writes memory.db)
  • core/automation.rs (writes automation.db)
  • core/lcm.rs (writes lcm.db)
  • core/federation.rs (reads/writes federation/_graph.json, _index.md)
  • core/todo.rs (writes todo.db, appends todo.events.jsonl)
  • core/flight_recorder.rs (appends traces.jsonl, verification_events.jsonl, external_actions.events.jsonl)
  • core/repomap.rs if it touches data files
  • any other module that opens a SQLite handle or appends to a .events.jsonl

Acceptance criteria

  • grep -RIn "rusqlite\|sqlx::\|Connection::open\|\\.events\\.jsonl" src/decapod/ returns no matches outside of src/decapod/dactyl_bridge.rs (the single allowed call site that initializes dactyl and forwards backend -> datastore).
  • Every store call in src/decapod/ uses the form dactyl::read(datastore, query, optimize) or dactyl::write(datastore, query, optimize), with datastore sourced from dactyl::active_datastore().
  • Every query is authored in universal SQL-flavored syntax at the call site, with parameters passed alongside.
  • No call site contains its own effective_backend() -> datastore translation. That logic lives only in #1112.
  • decapod validate passes for both backend = "local" and backend = "cloud".
  • cargo test --lib passes.

Out of scope

Related

Metadata

Metadata

Assignees

Labels

archArchitectural changes and decompositiondactylWork related to the standalone dactyl persistence-adapter craterefactorCode restructuring without changing behavior

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions