Skip to content

Deferred perf/memory follow-ups from the 2026-07 audit (#12) #13

Description

@senamakel

Follow-ups deferred from the 2026-07 audit remediation (#12). These are the performance and memory-growth findings that were verified during the audit but intentionally not fixed in that PR — either they need design work beyond a minimal patch or they're low-priority cold paths.

Deferred from the hot-path package (need design decisions)

  • Parallel tool execution — tool calls still run serially despite parallel_tool_calls: true in the provider profile (src/harness/agent_loop/). Blocked on design: the wrapped-tool execution and its before/after middleware onion take &mut RunContext (event emission, per-call limit/deadline tracking, cancellation), so a join_all needs the context split into shared/per-call parts first. Latency today is sum-of-tools instead of max.
  • True fire-and-forget DurabilityMode::Async — checkpoint put I/O now runs on the blocking pool, but Async mode still awaits persistence inline at each superstep (src/graph/compiled/). Handing the cloned state to a spawned task requires defining and testing failure semantics (what happens to a run whose background checkpoint write fails).
  • Langfuse zero-duration timings — every generation/tool observation exports startTime == endTime because AgentObservation only carries a single completion timestamp; ModelCompleted/ToolCompleted events don't capture a start time. Needs a start-time field threaded through the event model.
  • SSE per-chunk copy — the byte stream maps bytes::Bytes to Vec<u8> to keep bytes out of the public API, costing one copy per network chunk (src/harness/providers/openai/). Avoiding it means either exposing Bytes or an internal seam.

Deferred from the memory-growth package (unbounded growth in long-lived processes)

  • InMemoryAppendStore never evicts (src/harness/store/).
  • InMemoryGraphStatusStore never evicts and list_by_thread is an O(all-runs) scan (src/graph/observability/).
  • JsonlTaskStore clones the full in-memory history per transition and does sync write+flush under a mutex (src/graph/orchestration/store.rs).
  • Per-thread lock maps leak one Arc<Mutex<()>> per thread id forever (src/graph/goals/store.rs, src/graph/todos/store.rs) — evict at strong_count == 1 or use a weak-value map.
  • REPL command history unbounded with full JSON-arg clones (src/repl/types.rs) — cap with a VecDeque.

Deferred cold-path scans (cheap fixes, low impact)

  • Checkpointer::copy_thread default impl is O(H²) via per-checkpoint get (src/graph/checkpoint/mod.rs).
  • blueprint_diff O(old × new) nested scans (src/language/diff.rs) — reachable per-turn via the REPL graph_diff builtin; use per-side HashMaps.
  • compile_graph per-node linear edge scan (src/language/compiler.rs).
  • InMemoryVectorStore linear dedup per insert + full metadata clone before top-k truncation (src/harness/embeddings/).
  • Retriever accepts wrong-length embeddings and returns arbitrary top-k with all-zero scores instead of erroring (src/harness/embeddings/) — arguably a correctness bug, smallest fix in this list.

Deferred low-priority harness items

  • MockModel scripted-index race under concurrent calls (src/harness/providers/).
  • Event journal offset/ordering: listeners can observe offset 1 before 0; replay_from returns completion order (src/harness/events/).
  • RedactionMiddleware mask self-matching (pattern matching inside [REDACTED]) and tool-call arguments/raw never scrubbed (src/harness/middleware/library/).
  • Sub-agent run-id collisions: "{name}-d{depth}" reused across invocations, interleaving journals keyed by run id (src/harness/subagent/).
  • Poisoned-lock expects on reachable paths (src/harness/observability/, src/harness/steering/) — inconsistent with the same files' poisoned() mapping.
  • RateLimit Wait livelock when refill_per_sec = 0.0, plus waited_ms reports intended not actual wait (src/harness/middleware/library/).
  • Explicit model override silently falls through to defaults when ineligible (src/harness/model/).
  • Prompt fingerprint misses tool schemas/images/roles and uses unstable DefaultHasher for a serialized fingerprint (src/harness/prompt/).
  • cache_key doc says 16-hex but returns 64 (src/harness/cache/).

Line numbers omitted intentionally — #12 restructured most of these files; the module paths above are post-refactor.

https://claude.ai/code/session_01Ca2v3JeHcZvpYYsEX4WpcN

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions