Skip to content

0017#20

Merged
christopherkarani merged 2 commits intomasterfrom
0017
Feb 18, 2026
Merged

0017#20
christopherkarani merged 2 commits intomasterfrom
0017

Conversation

@christopherkarani
Copy link
Owner

No description provided.

christopherkarani and others added 2 commits February 18, 2026 03:35
Replace minimal bullet-list doc with a structured README targeting GitHub
visitors. Key changes:

- Open with problem statement + bold BSP semantics claim (hook before docs)
- Full DSL workflow snippet (triage → ModelTurn → Branch → interrupt → resume)
- ASCII execution diagram illustrating the atomic commit barrier
- Comparison table (Hive vs ad-hoc async/await vs LangGraph) moved early
- "Try it now" section placed before Installation (eval path before commit)
- Modules, schema definition, WorkflowPatch, and status table as reference
- Fix run()/resume() calls to include required `options:` parameter
- Replace non-existent `make build/test` with actual swift build/test commands

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@christopherkarani
Copy link
Owner Author

@claude

@christopherkarani christopherkarani merged commit f90e42b into master Feb 18, 2026
1 check passed
@claude
Copy link

claude bot commented Feb 18, 2026

Claude finished @christopherkarani's task in 3m 5s —— View job


PR #20 Code Review

  • Gather context and read changed files
  • Review Memory system (HiveMemoryTypes, InMemoryHiveMemoryStore)
  • Review Subgraph DSL (Subgraph.swift)
  • Review RAGWax store (HiveRAGWaxStore.swift)
  • Review Runtime changes (HiveRuntime.swift, HiveEnvironment.swift, HiveEvents.swift, HiveRunOptions.swift)
  • Review test files
  • Compile and post final review

Overview

This PR (already merged) adds four major features: a Memory system, Subgraph DSL composition, a Wax-backed RAG store, and a streaming mode for the runtime. Below are findings by module.


Memory System (HiveMemoryTypes.swift, InMemoryHiveMemoryStore.swift)

Design is clean. The HiveMemoryStore protocol + AnyHiveMemoryStore type-eraser pattern follows the same shape as HiveCheckpointStore, keeping the API consistent.

Issues and observations:

  1. InMemoryHiveMemoryStore.recall is O(N) over all keys on every call. The full storage dict is scanned, filtered, and sorted for every query. For test use this is fine, but it's worth a comment making clear this is test-only and not suitable for production workloads.

  2. recall non-determinism in score ties. When two items have the same score, dictionary iteration order is undefined in Swift. For a test fixture this doesn't matter much, but the HiveRAGWaxStore.recall breaks score ties by frameID descending (insertion order), while InMemoryHiveMemoryStore.recall has no tie-breaking — results can vary between runs. Fix this →

  3. overwriteSameKey test is untested for score: The tests check text and metadata after overwrite but don't verify score == nil on a get (since get always returns score: nil). Minor gap.

  4. No listKeys(namespace:) operation. The protocol has no way to enumerate stored keys, which makes it difficult to build garbage collection or inspect store contents in tests without recall.


Subgraph DSL (Subgraph.swift)

Solid approach. Running the child runtime to completion inside a parent node maintains superstep isolation correctly.

Issues and observations:

  1. childThreadID collision risk. The child thread ID is derived as:

    let childThreadID = HiveThreadID("subgraph:\(input.run.threadID.rawValue):\(input.run.stepIndex)")

    If the same subgraph node runs multiple times in parallel fan-out tasks within the same step, stepIndex is identical for all of them, producing duplicate thread IDs. Checkpoint stores (keyed by threadID) would return stale data. Fix this →

  2. Child events are silently discarded. The for try await _ in handle.events {} loop drops all child events. This is intentional per the docstring, but there's no way for callers to observe child node progress. A follow-up could expose a callback or forward child events with a namespace prefix.

  3. childOutputNotFullStore unreachable arm. The comment says // Already handled above; unreachable but the code still throws HiveSubgraphError.childOutputNotFullStore rather than using assertionFailure or fatalError. This hides a logic error as a runtime exception. Consider using assertionFailure("unreachable: interrupted case already handled") + a throw of a more descriptive error.

  4. Interrupt propagation swallows checkpoint. When the child is interrupted, the parent throws HiveSubgraphError.childInterrupted. The parent node's error propagates as a task failure — the parent cannot resume the child, nor does it preserve the child's checkpoint handle in the parent's interrupt system.

  5. start() creates a full copy. The start() method creates a new Subgraph with all fields copied just to flip isStart. This pattern is fine for small structs but is error-prone if new fields are added — the copy must be kept in sync. Consider a var isStart: Bool with a mutating function or with(isStart:) helper.


HiveRAGWaxStore (HiveRAGWaxStore.swift)

Clean Wax integration. Metadata namespacing via prefixed keys (hive.memory.meta.*) is a workable pattern.

Issues and observations:

  1. latestActiveFramesByKey scans all frames on every call. wax.frameMetas() is called in get, recall, and remember (via findLatestActiveFrame). For a recall that checks many keys and then calls get for each, this can scan the full frame list multiple times. Acceptable for early versions, but recall already calls latestActiveFramesByKey — the inner frameContent fetch could be batched.

  2. isActiveCurrentFrame checks meta.supersededBy == nil but the remember logic deletes and re-inserts rather than superseding. This means the supersededBy check may be redundant (or incorrect if Wax's internal deduplication supersedes frames automatically). The intent should be documented.

  3. No test for recall ordering when scores are equal. HiveRAGWaxStore.recall breaks ties by frameID descending, but this is not tested. Fix this →

  4. Error surface on wax.commit(). Both remember and delete call try await wax.commit(). If commit() throws after wax.put() or wax.delete(), the in-memory Wax state may be partially updated. The store should document whether it's safe to retry after a commit failure.


Streaming Mode (HiveRunOptions.swift, HiveEvents.swift, HiveRuntime.swift)

Well-structured addition. The HiveStreamingMode enum cleanly separates .events, .values, .updates, and .combined.

Issues and observations:

  1. storeSnapshot is emitted as treatAsNonDroppable: true. This means the snapshot event will block if the event buffer is full. For large stores with many channels, a per-step snapshot could be large and stall the runtime. Consider whether backpressure is the right behavior or if snapshots should be droppable with a count logged in streamBackpressure. Fix this →

  2. HiveStreamingMode is not persisted in checkpoints. If a run is interrupted and resumed, the caller must re-specify streamingMode in HiveRunOptions. This is correct behavior but should be documented.

  3. Test coverage for .combined mode. The streaming mode tests cover .events, .values, and .updates but the review of the test file shows combined mode may not be fully tested. Fix this →


Test Infrastructure (general)

  1. Duplicated test helpers. TestClock/NoopClock, TestLogger/NoopLogger, makeEnvironment, and collectEvents/drainEvents are defined independently in HiveRuntimeStreamingModeTests.swift, SubgraphCompositionTests.swift, and others. A shared HiveTestSupport module or internal TestFixtures.swift would reduce duplication. Fix this →

  2. InMemoryCheckpointStore also duplicated. The same store appears in both streaming mode tests and subgraph tests. Same remedy as above.


Summary

Area Severity Issue
Subgraph High Thread ID collision in parallel fan-out
Subgraph Medium Interrupt propagation doesn't integrate with parent checkpoint system
RAGWax Medium Full frame scan on every operation (scalability)
Memory Low recall non-determinism on score ties
Streaming Low storeSnapshot as non-droppable may stall runtime
Tests Low Duplicated test helpers across suites

The thread ID collision in Subgraph is the highest-priority fix — it can cause incorrect behavior when subgraph nodes participate in parallel fan-out scenarios.

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