Phase 3.5 extraction & assembly

Three-way concurrent retrieval (directive Redis, hot memories HTTP, cold search HTTP) with per-branch timeouts, outer IBEX_CONTEXT_TIMEOUT (45ms) fail-open, and history_tokens from request recent_messages.

Milestone 3.5.C.2 — Parallel Retrieval Orchestration

Status: Completed Goal: Track C — Context Assembly Engine
Phase: 3.5 — Extraction & Context Assembly
Estimated effort: 3 days
Track: Track C — Context Assembly Engine
Depends on: 3.5.C.1, Phase 3 exit (HNSW vector store)


Why This Milestone Exists

The Phase 3 Track B work already specified the ContextRetriever.retrieve() component well — launching directive/hot-cache/embedding concurrently via asyncio.gather(..., return_exceptions=True), only starting cold search once the query embedding is ready, merging and deduplicating hot/cold results. This milestone wires it into the assembly pipeline directly and adds the pieces the original spec left implicit.


Non-Goals

  • Scoring and ranking (3.5.C.3)
  • Packing (3.5.C.4)
  • gRPC ContextAssemblyService wiring (3.5.C.6)
  • Postgres/session-checkpoint history fetch (impossible — see Additions §1)

Orientation (indicative)

Named paths, package layouts, libraries, schemas, env vars, and commands anywhere on this page are rough sketches for orientation — inspiration and a baseline, not a required change list.

During implementation, expect to:

  • open the live tree and follow existing patterns before inventing new ones
  • research current constraints (latency, tenancy, deploy shape, libraries) more deeply than this page can
  • advance the design beyond the sketch where measurement or code reality says so
  • land work in different filenames, merged packages, deferred docs, or new surfaces when the situation calls for it

Prefer outcomes over matching any particular file tree or command sequence.

Areas that may be involved (situational — not a checklist):

  • Context assembly library (services/context)
  • Memory hot-cache HTTP surface
  • Token budget calculator (3.5.C.1)

Suggested naming (provisional)

Rename freely to match the change that actually lands.

  • Branch: feature/m3-5-c2-parallel-retrieval
  • PR title: feat(context): parallel retrieval orchestration with three-way concurrency (m3.5.C.2)

Additions on Top of the Existing Retriever Design

1. History is request input — not a fourth I/O branch (correction)

An earlier sketch proposed a fourth concurrent history_task reading conversation text from the session-checkpoint store. That branch must not be implemented:

  1. AssembleContextRequest.recent_messages already carries history (zero I/O).
  2. ibex_core.checkpoints stores messages_hash only — not message text.
  3. packages/session.Store has no history-read API (proxy owns session checkpoints).

Fix: treat recent_messages as already-available input; count tokens into history_tokens via BudgetCalculator (3.5.C.1). The orchestrator has exactly three concurrent I/O branches: directive (Redis cache envelope), hot memories (GET /v1/memories/hot), and cold search (POST /v1/memories/search, which embeds server-side — context must not pre-embed).

2. Outer deadline + per-branch timeouts

IBEX_CONTEXT_TIMEOUT defaults to 45ms (fail-open). Directive (~5ms) and hot (~15ms) use tighter budgets; cold uses the outer budget and often times out when the embedder is 100–500ms — partial results (directive + hot) are the intended degradation.

3. Tenant scoping enforced at the data layer

Every hot-cache key and cold-search query is namespaced ({org_id}:hot_memories:{agent_id}) / filtered by token org_id. Directive Redis keys use {org_id}:directive:{agent_id}.

4. RetrievalResult (internal Python; proto mapping deferred to 3.5.C.6)

Python
@dataclass
class RetrievalResult:
    directive: ResolvedDirective | None
    directive_outcome: BranchOutcome
    hot_memories: list[MemoryHit]
    hot_outcome: BranchOutcome
    cold_memories: list[MemoryHit]
    cold_outcome: BranchOutcome
    recent_messages: list[Message]
    history_tokens: int
    sources_available: frozenset[str]  # subset of {"directive","hot","cold"}

Success signals

Outcome-oriented signals that the milestone is in good shape. Exact filenames, package layouts, and commands may differ from any sketches above.

  • Three-way concurrent retrieval (directive, hot memories, cold search — cold embeds server-side)
  • Each branch has its own timeout; total wall-clock bounded by outer IBEX_CONTEXT_TIMEOUT (45ms)
  • RetrievalResult with history_tokens / recent_messages (not a Postgres history fetch)
  • Integration test: memory HTTP failure / timeout → retriever returns partial results without crashing
Edit on GitHub

Last updated on