Skip to content

feat(memory): add QdrantMemoryService implementation (Phase 1)#100

Closed
dgarson wants to merge 5 commits intodgarson/forkfrom
feat/memory-architecture-2
Closed

feat(memory): add QdrantMemoryService implementation (Phase 1)#100
dgarson wants to merge 5 commits intodgarson/forkfrom
feat/memory-architecture-2

Conversation

@dgarson
Copy link
Owner

@dgarson dgarson commented Feb 23, 2026

Summary

  • Add QdrantMemoryService implementing full IMemoryService interface
  • Wire up Qdrant client for production vector storage
  • Add OpenAI embedding integration for Qdrant backend
  • Fix TypeScript null safety issue in memory-tool.ts
  • Update architecture tests to use in-memory config (avoid Qdrant dependency)

Phase 1 Status

✅ Schema + interfaces + shadow-write wiring
✅ InMemoryMemoryService implementation
✅ QdrantMemoryService implementation
⏳ Hybrid read path + eval harness hooks (Phase 2)
⏳ Policy enforcement hardening + cutover plan (Phase 3)

Test Plan

  • All 11 architecture tests pass
  • Build succeeds
  • Integration tests with Qdrant (requires running instance)

Related: bs-tim-3 Memory Architecture 2.0

- Add QdrantMemoryService with full IMemoryService interface
- Wire up Qdrant client for vector storage
- Add OpenAI embedding integration for Qdrant backend
- Fix TypeScript errors in memory-tool.ts (null safety)
- Update architecture tests to use in-memory config

Phase 1 scaffolding complete: both InMemoryMemoryService and
QdrantMemoryService implementations now available.
dgarson added a commit that referenced this pull request Feb 23, 2026
Resolves five issues identified in code review of feat/hitl-gateway:

1. Wire approvalManager into HitlGateway lifecycle
   checkAndGate now calls approvalManager.create()+register() so callers
   can block on approvalManager.awaitDecision(requestId). recordDecision
   now calls approvalManager.resolve() to unblock them. Previously the
   in-memory promise lifecycle was completely disconnected from the SQLite
   store, meaning any caller awaiting a decision would hang forever.

2. Require policy to be present for authorization in recordDecision
   Previously, if request.policyId was not in policiesById, the entire
   authorization block was silently skipped, allowing any actor to
   approve/deny with no role or actor checks. Now returns an explicit
   error when the policy is not found.

3. Fix expireRequest escalation threshold to measure from expiresAtMs
   afterTimeoutMs is documented as 'after the timeout' but was measured
   from createdAtMs, causing escalation to fire well before the request
   even expired. Now measures from expiresAtMs so afterTimeoutMs=30_000
   means 'escalate 30s after the approval window closes'.

4. Reject decisions on requests past their expiresAtMs deadline
   recordDecision only checked request.status, not the clock. Without a
   running timeout sweep (Phase 5), status stays 'pending' past expiry,
   so a late approver could bypass the timeout policy. Now returns an
   explicit 'expired' error when the deadline has passed.

5. Fix listPendingRequests to query by status instead of post-filter
   The prior implementation fetched the latest 100 records and filtered
   in memory, silently dropping pending requests older than #100. Now
   queries each status (pending, escalated) explicitly with limit=500.

Additional fixes:
- Fix requireDifferentActor type in HitlPolicyDefinition: string|boolean
  -> boolean, consistent with types.approvals.ts and the Zod schema.
- Fix extractShellCommandFromArgv to join all args after cmd.exe /c
  instead of taking only argv[idx+1], so multi-token cmd.exe commands
  are validated and matched correctly against rawCommand.
- Add HitlEscalationSchema + maxApprovalChainDepth to zod-schema.approvals
  to resolve schema/type drift between runtime types and Zod validation.
- Add test coverage for all fixed behaviors (31 gateway tests total).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dgarson dgarson changed the base branch from main to dgarson/fork February 24, 2026 01:04
dgarson added a commit that referenced this pull request Feb 24, 2026
Resolves five issues identified in code review of feat/hitl-gateway:

1. Wire approvalManager into HitlGateway lifecycle
   checkAndGate now calls approvalManager.create()+register() so callers
   can block on approvalManager.awaitDecision(requestId). recordDecision
   now calls approvalManager.resolve() to unblock them. Previously the
   in-memory promise lifecycle was completely disconnected from the SQLite
   store, meaning any caller awaiting a decision would hang forever.

2. Require policy to be present for authorization in recordDecision
   Previously, if request.policyId was not in policiesById, the entire
   authorization block was silently skipped, allowing any actor to
   approve/deny with no role or actor checks. Now returns an explicit
   error when the policy is not found.

3. Fix expireRequest escalation threshold to measure from expiresAtMs
   afterTimeoutMs is documented as 'after the timeout' but was measured
   from createdAtMs, causing escalation to fire well before the request
   even expired. Now measures from expiresAtMs so afterTimeoutMs=30_000
   means 'escalate 30s after the approval window closes'.

4. Reject decisions on requests past their expiresAtMs deadline
   recordDecision only checked request.status, not the clock. Without a
   running timeout sweep (Phase 5), status stays 'pending' past expiry,
   so a late approver could bypass the timeout policy. Now returns an
   explicit 'expired' error when the deadline has passed.

5. Fix listPendingRequests to query by status instead of post-filter
   The prior implementation fetched the latest 100 records and filtered
   in memory, silently dropping pending requests older than #100. Now
   queries each status (pending, escalated) explicitly with limit=500.

Additional fixes:
- Fix requireDifferentActor type in HitlPolicyDefinition: string|boolean
  -> boolean, consistent with types.approvals.ts and the Zod schema.
- Fix extractShellCommandFromArgv to join all args after cmd.exe /c
  instead of taking only argv[idx+1], so multi-token cmd.exe commands
  are validated and matched correctly against rawCommand.
- Add HitlEscalationSchema + maxApprovalChainDepth to zod-schema.approvals
  to resolve schema/type drift between runtime types and Zod validation.
- Add test coverage for all fixed behaviors (31 gateway tests total).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dgarson dgarson closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant