Skip to content

Lens-core fold onto persist: drop legacy fallback path + identify persist API gaps #8

Description

@emooreatx

Summary

Lens-core still has direct write/delete/update sites against persist-owned tables that should fold onto Engine API once persist exposes the right primitives. This issue tracks the fold as a unit + names the persist asks needed to complete it.

The PoB §3.1 trajectory says "lens-core folds into agent" — that fold is much cleaner if every persist-substrate touch goes through Engine instead of direct SQL, because Engine survives the move and direct SQL doesn't.

Direct-touch inventory (lens-core only)

Site                                          Disposition         Persist API exists?
─────────────────────────────────────────────────────────────────────────────────────
Reads from accord_traces / accord_public_keys Stay on db_pool;    n/a
                                              owner relationship —
                                              no security boundary
                                              between lens-core and
                                              persist (same trust)

INSERT accord_traces                          DROP — legacy        n/a
   (accord_api.py:2369)                       fallback ingestion
                                              path; CIRISLENS_USE_
                                              PERSIST_ENGINE has
                                              been on in production
                                              since the v0.2.x
                                              cutover, this is dead
                                              code

INSERT accord_public_keys                     KEEP for now;        Engine.put_public_key
   (accord_api.py:2629                        document v0.4.0      exists (already mirrored
   register_public_key handler)               retirement timing    via federation_mirror).
                                                                   Direct INSERT stays as
                                                                   defense-in-depth until
                                                                   v0.4.0 retires the
                                                                   dual-read fallback in
                                                                   persist's verify path.

DELETE accord_traces                          NEEDS persist API    NO — no Engine
   (accord_api.py:2880,2891                                        primitive for DSAR-
   dsar_delete_traces handler)                                     style row deletion
                                                                   today. See §"Persist
                                                                   asks" below.

UPDATE accord_traces                          MOVE to lens-derived NO — and shouldn't
   (accord_api.py:3570,3636                   schema (cirislens_   exist on persist's
   set_trace_public_sample,                    derived.trace_       side. partner_access
   partner_access)                            visibility, joined   and public_sample are
                                              to accord_traces)    lens-policy decisions
                                                                   on persist's data; they
                                                                   shouldn't co-locate
                                                                   with substrate columns

INSERT accord_traces_mock                     dev-only path; not   n/a
   (accord_api.py:1323)                       in production

Recommended scope for the actual fold (separate PRs)

  1. Drop the legacy fallback ingestion path. The if not _persist_engine_active() branch in receive_accord_events is dead code in production (Phase 2a flag has been on since v0.2.x cutover). Connectivity-event handling and mock-LLM filtering — which are NOT dead — need to be teased out and kept as their own routes/checks rather than living inside the legacy fallback. ~200-300 lines net delete after the connectivity/mock split.

  2. Move partner_access + public_sample to a lens-derived schema. New table cirislens_derived.trace_visibility(trace_id, partner_access, public_sample, set_at, set_by) joined to accord_traces at query time. Removes lens's UPDATE on persist's substrate columns. ~150 lines + a migration.

  3. Wait for persist's DSAR primitive (see asks below) before migrating DELETE.

  4. Wait for persist v0.4.0 (drop dual-read fallback) before stopping accord_public_keys writes.

Asks for persist (file separately if/when they pick this up)

Ask 1: Engine.delete_traces_for_agent_id_hash(agent_id_hash) -> DeleteSummary

GDPR right-to-erasure (DSAR) primitive. Lens currently does direct DELETE on accord_traces; with trace_events post-cutover that path needs an Engine equivalent.

pub struct DeleteSummary {
    pub trace_events_deleted: u64,
    pub trace_llm_calls_deleted: u64,
    pub federation_keys_deleted: u64,  // if revoking the agent's key too
    pub deleted_at: DateTime<Utc>,
    // Audit: lens consumes this for its own DSAR ledger;
    //        persist returns the row counts, lens records
    //        the request envelope.
}

Mission-aligned because GDPR Article 17 is a federation-grade ethical requirement, not a lens-side convenience. Persist owns substrate row deletion; lens orchestrates the audit + signature verification of the DSAR request.

Ask 2: v0.4.0 retirement plan

What's the timeline for persist dropping the accord_public_keys dual-read fallback in Backend::lookup_public_key? Lens-core's direct INSERT into accord_public_keys can retire the same release. Coordinate.

Ask 3 (deferred until needed): bulk-iter primitive for analytical reads

Engine.iterate_trace_events(filter, callback) for streaming analytical work that doesn't fit the SQL-via-cirislens_reader pattern. Not blocking; the export script's asyncpg-cursor pattern works fine for now. Mention only if persist team wants to standardize.

What's NOT in this issue's scope

  • Reads stay on db_pool. No security boundary between lens-core and persist; routing in-process analytical reads through cirislens_reader is plumbing without benefit. The peer/owner distinction matters: cirislens_reader is for OUT-OF-PROCESS consumers (export script, future federation peers), not lens-core itself.
  • Lens-derived tables stay lens-owned. coherence_ratchet_alerts, pdma_events, wbd_deferrals, creator_ledger, sunset_ledger — these are lens's analytical output, not persist's substrate. They don't fold.

References

  • PoB §3.1 — lens-core folds into agent
  • v0.3.4 commit (5fcd550) — pin bump for deployment_profile wire-format compatibility
  • v0.2.x cutover — Phase 2a flag flip that made the legacy ingestion path dead code
  • CIRISPersist v0.4.0 roadmap — accord_public_keys dual-read retirement

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions