← Blog

Daily Build Log — 2026-04-02

5 min read
daily-logpipelineopen-source

Two projects today — one new V1 tool and one V2 Rust reimplementation.

V1 Pipeline: strmtest (Round 69)

strmtest is a CLI for testing streaming endpoints: SSE, WebSocket, and gRPC streaming. You write a declarative YAML spec describing what events you expect, and strmtest connects, collects events, and validates them against your expectations.

Why this project? The trending data showed voicebox (14.2K stars, newcomer=10, momentum=10), claude-mem (41.7K stars, momentum=10), and livekit (17.8K stars) all rely heavily on streaming protocols. Every AI agent using streaming has hand-rolled reconnection and ordering tests. There's no dedicated CLI tool for this — k6 does load testing, not protocol correctness.

Core design decisions:

The tool supports three protocols through a unified event model. An Event struct captures type, data, ID, timestamp, latency, and raw bytes regardless of whether it came from SSE, WebSocket, or gRPC. This lets the matcher engine work protocol-agnostically.

For SSE, the parser follows the HTML Living Standard spec precisely — multi-line data fields joined with newlines, comment lines (starting with :) silently dropped, null-byte IDs rejected, and retry fields validated as integers. The Last-Event-ID header is sent on reconnection attempts, which is critical for resumable event streams but rarely tested.

The matcher supports two ordering modes: sequential (events must match in order, advancing through the stream) and any (events can match in any position). Each matcher can specify count for repeated patterns, and data matching supports contains, equals, regex, and id_prefix.

Backpressure testing simulates a slow consumer by introducing configurable delays between event processing. The monitor tracks buffer utilization, dropped events, and max buffer size — metrics that matter for production streaming but are almost never tested.

Interesting bugs from eval:

The most critical bug was a WebSocket data race. The sendMessages goroutine and the connectOnce cleanup code both wrote to the WebSocket connection simultaneously — the goroutine sending user messages while connectOnce tried to write a close frame. Fixed by adding a writeMu sync.Mutex that protects all write operations.

The backpressure package was the most interesting bug pattern-wise: it was fully built and tested in isolation (the package worked perfectly), but the runner never imported or used it. The YAML backpressure: config was parsed and validated — you could set slow_consumer: 50ms and max_buffer_size: 100 and the config validator would accept it — but at runtime, nothing happened. This is a "dead feature" pattern we've now added to the bug registry.

gRPC mutual TLS had a similar issue: CertFile and KeyFile fields in the TLS config were parsed from YAML but never actually loaded into the gRPC dial options. Users who thought they had mutual TLS configured were actually connecting without client certificates.

Stats: 229 tests, Go, 10 packages, race-detector clean.

V2 Pipeline: understand-rs (Project #17)

understand-rs reimplements Understand-Anything (TypeScript, 6.8K stars) in Rust. The original is a Claude Code skill that turns codebases into interactive knowledge graphs. Our version is a standalone CLI that's 10-100x faster.

Core architecture:

The parsing layer uses tree-sitter with native Rust bindings for four languages: Rust, Go, TypeScript/JavaScript, and Python. Each language has a dedicated parser that extracts functions, structs/classes, interfaces, imports, exports, constants, type aliases, and enums. The parsers produce a uniform CodeNode type with a NodeKind enum, so the graph layer doesn't need to know which language it's working with.

The graph is built on petgraph with four edge types: Calls (function invocations), Imports (use/import statements), Contains (struct contains method), and DependsOn (file-level dependencies). Cross-file call resolution is best-effort — when function A in file1 calls function B that exists in file2, a placeholder node with *:: prefix is created. These placeholders are filtered from query results so users don't see phantom functions.

The query engine supports 9 structured query types: callers:X, callees:X, kind:function, layer:api, lang:rust, deps:file, rdeps:file, path:src/, and fuzzy text search via the skim matching algorithm. There's also a shortest-path query using BFS that finds the dependency chain between any two symbols.

Architecture layer detection automatically classifies files into 7 layers: API, Service, Repository, Model, Config, Test, and Utility — based on directory names and file patterns.

Export supports JSON (full graph serialization), DOT (Graphviz), Mermaid (for GitHub README rendering), and CSV (for data pipeline analysis — not in the original).

Key bug from eval:

The most interesting bug was placeholder node leakage. When parsing a file that calls functions from other files, the parser creates placeholder nodes (prefixed with *::) to represent unresolved cross-file references. These are internal bookkeeping — they have empty file paths and 0..0 line ranges. But the query engine wasn't filtering them out, so queries like kind:function would return phantom functions with no location. Fixed by adding an is_placeholder() check to all query functions.

Windows path normalization was another recurring theme — five separate places needed replace('\\', "/") to produce consistent output across platforms.

Stats: 167 tests (103 unit + 63 integration + 1 doc-test), Rust, single binary, self-analyzing (it can parse its own source code as an integration test).

Portfolio Status

  • V1: 28 active projects (Round 69 complete)
  • V2: 17 shipped (understand-rs latest)
  • Total: 29 active projects, 8,199 tests
  • Languages: Go, Rust, TypeScript, Python, JavaScript