- Phase 14: copy binary with .exe suffix on Windows (was creating
non-.exe copy that uninstall didn't remove)
- Phase 14e: check both .exe and non-.exe paths
- Soak latency: exclude index_repository from max query latency
(indexing 377 files is legitimately slow on Windows/MSYS2)
MinGW python3 is a native Windows binary that doesn't understand
POSIX paths like /tmp/foo.json. Piping file content through cat
(which runs in MSYS2 bash and handles path translation) to python's
stdin avoids the issue entirely.
Fixes Windows smoke test 8a and soak baseline collection.
Investigation: macOS arm64 grew 1MB (43→44MB) but slope was 1123
KB/hr. Linux amd64 grew 3MB (25→28MB) but slope was only 424 KB/hr.
The linear regression fits noise on short runs — small timing
fluctuations produce wildly different slopes on nearly flat data.
For 10-min quick soak: use RSS ceiling (200MB) + ratio (3.0x) +
FD drift + idle CPU. Slope is still reported but not enforced.
For 30+ min runs: slope enforcement at 500 KB/hr (enough samples
for reliable regression).
- Test project: 377 files (80 Python + 40 Go + 40 TSX + configs)
instead of 5 files. RSS baseline now ~47MB (real workload).
- Snapshots every 10s (was 30s) — 7+ data points in 1-min run.
- Reindex every 2min compressed (was 5min) — more cycles per run.
- heap_committed fallback: use RSS when mimalloc reports 0.
- Windows soak: added to quick soak matrix (MSYS2 + python3 + git).
- ASan soak: builds with -fsanitize=address (was building release).
- Collect snapshot with single python3 call (was 6 separate calls).
- Phase 14: detect UI vs standard variant from HTTP server contents
instead of hardcoding --standard (fixes UI smoke failure)
- Windows smoke: install zip + coreutils (sha256sum) in MSYS2
(fixes exit code 127)
- Phase 15: UI HTTP server reachability test — verifies root returns
200 and /rpc accepts POST (skips gracefully for non-UI builds)
- Fix switch fallthrough in release.yml (same MSYS2 deps)
Add isatty() checks to prompt_yn() and update variant chooser.
When stdin is not a terminal and no -y/-n or --standard/--ui flag
is provided, print a clear error and exit instead of hanging on
fgets(). Prevents agents from silently blocking when running
install/update programmatically.
Add smoke test 9b-9: verify non-interactive update fails cleanly.
Install command:
- Add cbm_kill_other_instances() to kill stale MCP servers
- Add cbm_macos_adhoc_sign() to sign binary if placed unsigned
Update command:
- Replace skills-only reinstall with full cbm_install_agent_configs()
- Replace external unzip with cbm_extract_binary_from_zip() via zlib
Refactor: extract 10-agent config loop into cbm_install_agent_configs()
called by both install and update.
New: cbm_extract_binary_from_zip() — in-memory zip extraction with
stored + deflate support, path traversal rejection, bounds checks.
4 unit tests. Smoke: add install.ps1 E2E for Windows.
install.sh: one-liner for macOS/Linux — detects OS/arch (Rosetta-
aware), downloads release, verifies checksum, extracts, signs on
macOS, runs install -y for all 10 agents. Supports --ui flag and
CBM_DOWNLOAD_URL env var for testing.
install.ps1: one-liner for Windows — Invoke-WebRequest + Expand-
Archive + Unblock-File (strips MOTW), installs to %LOCALAPPDATA%,
adds to user PATH via [Environment]::SetEnvironmentVariable.
CI pre-signing: add codesign --sign - step for macOS builds in
both dry-run.yml and release.yml, before archiving. Release
binaries now ship pre-signed.
Phase 12 smoke tests: real HTTP download via local artifact server,
checksum verification, archive extraction, binary verification.
Runs only when SMOKE_DOWNLOAD_URL is set (CI provides it).
Phase 13 smoke tests: install.sh E2E — runs full script with local
URL + isolated HOME, verifies binary placed, signed, runs, and
agent configs created.
CI HTTP server: smoke jobs start python3 HTTP server serving the
built binary as a tar.gz/zip archive + checksums.txt. Enables
Phases 12-13 in CI on all platforms.
Update security allowlist: remove system() entry (eliminated),
add cbm_popen for pgrep. Update README with one-liner Quick Start.
Make project a required parameter for all query tools (search_graph,
query_graph, trace_call_path, get_code_snippet, get_graph_schema,
get_architecture, search_code, index_status, detect_changes,
manage_adr, ingest_traces). Removes implicit fallback to session
project or last-opened store.
When project is missing or not found, return error with list of
available indexed projects so agents can self-correct.
Rename delete_project param from project_name to project for
consistency. Fix smoke test trace_call_path depth param name
(max_depth -> depth).
Expand smoke-test.sh with Phase 5 (MCP stdio transport), Phase 6
(CLI subcommands: install/uninstall/update --dry-run), and Phase 7
(MCP advanced tool calls: search_code v2, get_code_snippet).
Add smoke/smoke-amd64 services to Docker compose that build then
run all 7 smoke test phases. Include in run.sh full/all flows.
Add python3-minimal to Dockerfile for smoke test JSON parsing.
Fix Phase 4a shutdown test to use portable background+kill pattern
instead of `timeout` (not available on macOS).
Add --dry-run, --standard, --ui flags to update command. Fix
clang-tidy readability-implicit-bool-conversion in dry_run ternary.
Tests the actual agent handshake path that Claude Code, OpenCode, etc. use:
- 5a-d: initialize → notifications/initialized → tools/list via bare JSONL
- 5e: Full tool call round-trip (index + search) via JSON-RPC
- 5f: Content-Length framing (OpenCode compatibility)
Uses portable background process + kill instead of timeout command
(not available on all macOS configurations).
- Delete cmd/codebase-memory-mcp/assets/ — skills and codex instructions
are embedded as C string literals in src/cli/cli.c since v0.5.0
- Move BENCHMARK.md to docs/ to reduce root clutter
- Fix setup scripts: replace stale go build with scripts/build.sh
- THIRD_PARTY.md: replace Go module dependencies with vendored C
libraries (sqlite3, mimalloc, mongoose, yyjson, xxhash, tre),
fix CGo reference to static compilation
- Use O_NONBLOCK + clearerr() in Phase 2 fgetc probe to preserve the
60s idle eviction timeout when both kernel fd and FILE* buffer are
empty (fgetc on a blocking fd would otherwise block indefinitely,
bypassing Phase 3 poll timeout and preventing cbm_mcp_server_evict_idle)
- Add #include <fcntl.h> for fcntl()/O_NONBLOCK
- Fix comment: "two-phase" → "three-phase" (implementation has 3 phases)
- Improve Python integration test: verify id:1 (initialize) and id:2
(tools/list) response IDs are both present, not just "tools" substring
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Minified JS in dist/ contains hundreds of string-constant URLs from
bundled npm libraries (React error pages, W3C namespace URIs, CDN
references, OSS credits) that are never fetched at runtime. Scanning
them produced an endless stream of false positives requiring per-URL
allowlisting.
Fix: split the A1 URL check by directory:
- src/ (our code): strict — any external URL is blocked
- dist/ (npm build output): skip inline URL scan entirely
Structural checks (A2-A6) still apply to dist/:
- External <script>/<link> loads in HTML
- Tracking/analytics identifiers
- Iframes, eval/Function, external WebSockets
- UI audit (L6): allowlist bundled framework URLs in dist/ (React error
URLs, W3C namespace URIs, Three.js credits, Google Fonts, Tailwind).
These are embedded by npm deps during Vite build, not our code.
- Binary strings (L2): skip URLs shorter than 15 chars — Windows binary
has byte sequences that strings(1) interprets as "https://H9" etc.
- Allow Google Fonts <link> in HTML (loaded by index.html for Inter/
JetBrains Mono fonts).
MSYS2 mktemp returns /tmp/tmp.XXX but the Windows binary can't resolve
POSIX paths. Use cygpath -m to convert to C:/msys64/tmp/tmp.XXX which
works in both MSYS2 shell and Windows file APIs.
1. smoke-windows: Use CLANG64 (not UCRT64) so runtime matches the
build environment. Binary built with CLANG64 needs CLANG64 DLLs.
2. smoke-unix: Add fail-fast: false so one platform failure doesn't
cancel all 7 other smoke jobs.
3. smoke-test.sh: Capture and display stderr on indexing failure to
help debug smoke-unix errors.
4. release.yml: Same CLANG64 smoke fix.
1. Add zip to MSYS2 build packages (both dry-run and release).
2. embed-frontend.sh: replace xxd with od+sed for hex dump — xxd
requires vim which isn't in MSYS2 CLANG64 by default.
3. embed-frontend.sh: flip IS_MACOS→IS_LINUX — Linux gets ld -r -b
binary (ELF-only), everything else (macOS, Windows) gets the
portable C-array approach via od.
4. release.yml: same Windows archive fix (msys2 shell + .exe detect).
1. dry-run.yml: Add skip_tests and skip_builds workflow_dispatch inputs
for faster iteration. Build jobs use always() to run even when tests
are skipped.
2. Windows archive: Switch from PowerShell Copy-Item to MSYS2 shell
with .exe extension detection. MSYS2 Clang produces .exe suffix
that Copy-Item didn't account for.
3. Linux embed: Use absolute path for ld output when cd'd into dist
directory. Relative path build/c/embedded/*.o was invalid from
inside graph-ui/dist/.
4. release.yml: Same Windows archive fix as dry-run.
- Use env: block instead of shell quoting for WIN32_LIBS in CI
- Forward WIN32_LIBS from environment in test.sh and build.sh
- Add skip_lint input to dry-run workflow for faster iteration
MinGW GCC does not ship ASan runtime on Windows. MSYS2 CLANG64
provides full sanitizer support via compiler-rt. All platforms
now run tests with ASan + UBSan — no exceptions.
- Fix GCC -O2 warnings: calloc for cf (maybe-uninitialized),
suppress stringop-truncation/alloc-size-larger-than (false positives),
guard louvain against negative node_count
- Default compiler: cc on macOS, gcc on Linux/Windows (fixes gcc-14
not found on MSYS2)
- Docker test infra now runs BOTH test (ASan) and build (-O2 -Werror)
- Add scripts/clean.sh, test.sh, build.sh, lint.sh as single source
of truth for local and CI builds (always clean, always parallel)
- Fix -Wmissing-braces: replace {{0}} with memset for struct arrays
- Fix -Wrestrict: use intermediate buffer for same-struct snprintf
- Update dry-run.yml and release.yml to use the new scripts