Skip to content

feat: add has_metadata_key to bd query DSL#2

Open
turian wants to merge 130 commits intofeat/metadata-queryablefrom
feat/metadata-has-key-dsl
Open

feat: add has_metadata_key to bd query DSL#2
turian wants to merge 130 commits intofeat/metadata-queryablefrom
feat/metadata-has-key-dsl

Conversation

@turian
Copy link
Owner

@turian turian commented Feb 20, 2026

Summary

  • Add has_metadata_key=<keyname> field to the bd query DSL
  • Works in filter mode (AND chains) and predicate mode (OR queries)
  • Added to KnownFields registry for documentation
  • Reuses existing IssueFilter.HasMetadataKey and SQL JSON_EXTRACT IS NOT NULL

Base: feat/metadata-queryable (PR steveyegge#1908 against upstream)

Test plan

  • TestEvaluatorHasMetadataKeyQueries — 4 cases: basic, combined with status, OR predicate, invalid key
  • TestHasMetadataKeyPredicateEvaluation — predicate mode with key present, absent, and OR fallback

🤖 Generated with Claude Code

@turian turian force-pushed the feat/metadata-queryable branch from 58f05e6 to ca318fe Compare February 22, 2026 20:58
@steveyegge steveyegge force-pushed the feat/metadata-queryable branch from ca318fe to 5ba0887 Compare February 22, 2026 23:30
turian and others added 5 commits February 22, 2026 15:30
…teveyegge#1908)

Add SQL-level metadata filtering using Dolt's JSON_EXTRACT/JSON_UNQUOTE
with parameterized queries. New CLI flags: --metadata-field key=value
(repeatable, AND semantics) and --has-metadata-key key. Add metadata.<key>
support to bd query DSL. Strict key validation prevents JSON path injection.

Remove //go:build cgo tag from metadata_filter_test.go (CGO bifurcation
was removed in c4010c1).
…e#1900)

* Fix waits-for readiness in ready and molecule analysis

- enforce waits-for gates in Dolt ready-work blocker computation

- honor waits-for in molecule parallel/ready analysis

- dedupe waits-for gate metadata parser into internal/types

- add regression tests and short-mode skip/subtests improvements

* docs(waits-for): clarify canonical spawner identity (steveyegge#1899)
Adds bd setup mux with support for layered AGENTS.md installation
(root, project .mux/, global ~/.mux/) and managed hook files
(.mux/init, .mux/tool_post, .mux/tool_env). Makes AGENTS removal
non-destructive (preserves user content outside managed markers).

From: PR steveyegge#1888 by alexx-ftw (cherry-picked, rebased onto current main)

Co-Authored-By: Alexx <alexx-ftw@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(otel): comprehensive OpenTelemetry instrumentation

Phase 1 (telemetry foundation + SQL + CLI + AI):
- Add internal/telemetry package: Init/Shutdown, Tracer/Meter helpers,
  stdout + OTLP/gRPC exporters, noop providers when disabled
- Add internal/telemetry/storage.go: InstrumentedStorage decorator for
  SDK consumers with bd.storage.* counters and duration histograms
- Instrument DoltStore SQL layer (execContext, queryContext, queryRowContext)
  with dolt.exec / dolt.query / dolt.query_row spans
- Instrument Anthropic API calls in compact/haiku.go and find_duplicates.go
  with bd.ai.input_tokens, bd.ai.output_tokens, bd.ai.request.duration
- Add bd.command.<name> span in PersistentPreRun/PostRun with actor attribute

Phase 2 (VC ops, hooks, sync, metrics):
- Add dolt.commit / dolt.push / dolt.force_push / dolt.pull / dolt.branch /
  dolt.checkout / dolt.merge spans for Dolt version-control procedures
  (these bypass execContext so needed dedicated spans)
- Add bd.db.retry_count counter in withRetry (server mode retries)
- Add bd.db.lock_wait_ms histogram in AcquireAccessLock (flock contention)
- Add ephemeral.count / ephemeral.nuke spans for SQLite ephemeral store
- Add hook.exec spans in hooks_unix/windows runHook (background root spans)
- Add tracker.sync / tracker.pull / tracker.push / tracker.detect_conflicts
  spans with per-phase stats attributes in tracker/engine.go
- Add bd.issue.count gauge (by status) in InstrumentedStorage.GetStatistics
- Fix: call initAIMetrics via sync.Once in newHaikuClient so ai metrics
  are actually registered

Configuration:
  BD_OTEL_ENABLED=true              enable (default: off, zero overhead)
  BD_OTEL_STDOUT=true               write to stdout for dev/debug
  OTEL_EXPORTER_OTLP_ENDPOINT=...  ship to Jaeger/Grafana/Honeycomb/etc.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(otel): align with VictoriaMetrics HTTP stack

- Switch metric exporter: gRPC → HTTP (otlpmetrichttp)
- Activation: BD_OTEL_METRICS_URL presence (no more BD_OTEL_ENABLED flag)
  matches GT_OTEL_METRICS_URL convention from the local observability stack
- BD_OTEL_METRICS_URL=http://localhost:8428/opentelemetry/api/v1/push
- BD_OTEL_LOGS_URL=http://localhost:9428/insert/opentelemetry/v1/logs (reserved)
- Traces: stdout only (BD_OTEL_STDOUT=true); noop otherwise since VictoriaMetrics
  is a metrics-only backend — no trace overhead in production
- Remove: otlptracegrpc, otlpmetricgrpc
- Update docs/OBSERVABILITY.md to match the diffusiontown README style

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(otel): capture hook stdout/stderr and bd.args in spans

- hook.exec span now records stdout and stderr as span events after
  the hook process exits (including partial output on timeout)
- Output is truncated to 1024 bytes; the event carries both the text
  (output) and the original size (bytes) as attributes
- bd.command.<name> span now includes bd.args with the raw CLI
  arguments (e.g. "create 'title' -p 2")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(otel): address review feedback — stale comment, span leak, hot-path alloc

1. Fix stale BD_OTEL_ENABLED comment in main.go (actual env vars are
   BD_OTEL_METRICS_URL and BD_OTEL_STDOUT)
2. Use defer+named returns in Merge() to prevent span leaks
3. Cache doltSpanAttrs() via sync.Once to avoid per-call allocation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: beads/crew/emma <steve.yegge@gmail.com>
Every RunInTransaction call now provides a descriptive commit message
and the transaction includes a DOLT_COMMIT call before SQL commit,
making writes atomically visible in Dolt version history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/jasper
Rig: beads
Role: polecats
@turian turian force-pushed the feat/metadata-has-key-dsl branch 2 times, most recently from 5f5e145 to 3df9753 Compare February 23, 2026 00:16
renovate bot and others added 21 commits February 23, 2026 00:19
Add beforeTestsHook implementation that starts a dedicated Dolt
sql-server in a temp directory on a dynamic port. Tests now create
testdb_* databases on this isolated server instead of the production
one, preventing lock contention and server crashes.

Also fix telemetry/storage.go RunInTransaction signature to match
the updated Storage interface (commitMsg parameter).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/obsidian
Rig: beads
Role: polecats
…rrency

- Wrap RunInTransaction with withRetry for automatic transient error recovery
- Add transact() helper that marks commandDidExplicitDoltCommit, preventing
  redundant maybeAutoCommit in PersistentPostRun
- Remove BD_BRANCH env var handling (all writers now operate on main)
- Batch-wrap label add/remove, single-issue delete, and markdown create
  in single transactions for atomicity

Closes: gt-bewatn.3, gt-bewatn.4, gt-bewatn.5, gt-bewatn.15

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- queryContext: close leaked sql.Rows on retry (bd-bdfoe)
- CreateIssue, UpdateIssue, ClaimIssue, CloseIssue, DeleteIssue,
  CreateIssuesWithFullOptions, DeleteIssues: add DOLT_COMMIT inside
  transaction so writes are visible in Dolt version history (bd-zscqd)
- UpdateIssue: move GetIssue inside transaction to fix TOCTOU (bd-1x1q9)
- ClaimIssue: move GetIssue and assignee query inside transaction to
  fix TOCTOU race and CAS consistency (bd-o8kqq, bd-p61yo, bd-rvfau)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sweep 65 markdown files across docs/, website/, claude-plugin/, examples/,
integrations/, and root to replace removed `bd daemon` references with
current Dolt server mode equivalents. CHANGELOG.md preserved per policy.

Key replacements:
- `bd daemon start/stop/status` → `bd dolt start/stop` / `bd doctor`
- `bd daemons killall/health/logs` → `bd dolt stop` / `bd doctor`
- `--no-daemon` flag → removed (embedded mode is default)
- `BEADS_NO_DAEMON` / `BEADS_DAEMON_MODE` env vars → removed
- `.beads/bd.sock` → removed
- "daemon mode" / "direct mode" → "server mode" / "embedded mode"
- daemon.pid/daemon.log → .beads/dolt/sql-server.pid/.log

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/topaz
Rig: beads
Role: polecats
… tags

- mol_squash.go: replace --delete-children with --keep-children in help
  text (the flag is --keep-children, deletion is the default)
- markdown.go: fix dead code where Description=="" guard made the inner
  Description!="" check unreachable, truncating multi-line descriptions
- internal/storage/dolt/*_test.go: remove stale //go:build cgo tags
  since embedded Dolt was replaced with server-mode (pure Go)

Closes: bd-rw2tf, bd-8o2le, bd-lrl7u

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…abels, deps

Previously cookFormula performed two separate committed operations:
1. CreateIssuesWithFullOptions (own internal transaction)
2. transact() for labels and dependencies

If phase 2 failed, orphaned template issues would remain in the database
with no labels or dependencies, and the best-effort cleanup could also fail.

Now all three operations (issue creation, label addition, dependency creation)
happen in a single transact() call. If anything fails, the entire transaction
rolls back cleanly — no orphaned issues possible.

Closes: bd-5cyte

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add TestMain to internal/storage/dolt/ that starts a dedicated Dolt server
in a temp directory on a dynamic port, preventing tests from creating
testdb_* databases on the production Dolt server. Uses BEADS_DOLT_PORT
env var (already wired by mayor in applyConfigDefaults).

Also fix missing dbPath assignment in newServerMode (lost during
embedded-to-server refactoring), which caused store.Path() to return "".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…d-4kgbq)

bondProtoMolWithSubgraph: spawn and dependency attachment now happen in a
single transaction via CloneOptions.AttachToID, preventing orphaned issues
if the attach step fails.

squashMolecule: digest creation, child deletion, and root close all happen
in a single transaction instead of three separate operations, preventing
inconsistent state on partial failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…H#1237, GH#1234)

GH#1237: When --sort is specified, defer LIMIT from SQL to Go so sorting
operates on the full result set before truncation.

GH#1234: TrimSpace the edited value before saving, not just for empty check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The daemon was removed in v0.50. Remove remaining references from
NEWSLETTER.md, docs/LINTING.md, website sidebar, and llms.txt files.
Regenerated llms-full.txt from clean source docs. CHANGELOG.md
historical entries preserved.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… propagate blocked status to children (GH#2009, GH#1495)

Two bugs fixed:

1. GH#2009: bd ready --parent filter was silently ignored. The ParentID
   field was parsed from CLI flags and set on WorkFilter but never used
   in the SQL query. Added parent filtering to both GetReadyWork and
   GetBlockedIssues, mirroring the existing logic in SearchIssues.

2. GH#1495: Children of blocked parents appeared in bd ready because
   blocked status did not propagate to children. Now GetReadyWork excludes
   children of blocked parents. Also fixed stale blocked-IDs cache:
   CloseIssue, UpdateIssue (status changes), and ClaimIssue now
   invalidate the cache so waits-for gate changes take effect immediately.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…#1945, GH#1524)

Two bug fixes:

1. GH#1945: bd repo sync now iterates additional repos from config.yaml,
   parses their issues.jsonl files, and imports cross-prefix issues with
   source_repo set. Uses repo_mtimes cache to skip unchanged repos.
   Also fixes duplicate key error on re-sync by adding ON DUPLICATE KEY
   UPDATE to insertIssue().

2. GH#1524: IsBlocked() now uses computeBlockedIDs() as the single source
   of truth, consistent with GetReadyWork. This ensures close guard
   respects waits-for dependencies, not just direct blocks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…, GH#2007)

GH#1981: (b) Replace stale 'bd sync' advice in doctor messages with
correct commands (bd import, bd init, bd doctor). (c) Fix noms LOCK
false positive — run CheckLockHealth before any embedded Dolt opens
so doctor's own flock()s don't trigger warnings. Remove age-based
noms LOCK detection from CheckStaleLockFiles (redundant with flock
probing in CheckLockHealth).

GH#2007: Remove stale 'bd sync --status' and 'bd sync' references
from bd prime output. Replace with bd dolt push/pull, bd export,
bd search. Simplify close protocol (beads auto-commit to Dolt).
Update onboard and init_team references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…it hook body

The preCommitHookBody() inline template still used 'bd hook pre-commit'
after the command was renamed to 'bd hooks run'. The template files in
cmd/bd/templates/hooks/ were already fixed (a7e1203) but this inline
path used by bd init was missed.

Fixes: gt-0qii3n, gt-sue187, gt-u7qk7q, gt-e9wkz0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: gastown/crew/gus
Rig: gastown
Role: crew
1. FORMATTING: gofmt 14 files.

2. LINT:
   - Delete dead code cmd/bd/bootstrap.go (unused bootstrapEmbeddedDolt)
   - Prefix unused 'actor' param in wisps.go updateWisp with _
   - Prefix unused 'ctx' param in telemetry.go buildTraceProvider with _

3. TESTS: Add skipIfNoDolt to test helpers that call dolt.New() without
   a running test server. In CI (no dolt installed), these tests now skip
   instead of failing with "server unreachable at 127.0.0.1:3307".
   Delete TestOpenFromConfig_Embedded and TestOpenFromConfig_DefaultsToEmbedded
   which tested removed embedded Dolt functionality.

   Fixed packages: beads_test, cmd/bd, cmd/bd/doctor, cmd/bd/doctor/fix,
   internal/tracker, internal/utils

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regression tests were connecting to the production Dolt server on port
3307, polluting it with test databases. Start a dedicated Dolt server
on a dynamic port in TestMain and pass BEADS_DOLT_PORT to all bd
subprocess invocations via runEnv().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/crew/emma
Rig: beads
Role: crew
Delete fork_protection.go and its test — these only protected
.beads/issues.jsonl from being committed by forks, which is no
longer relevant with Dolt-native storage. Remove ensureForkProtection()
call from main.go PersistentPreRun.

Part of bd-9ni (JSONL removal Phase 2+3).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/crew/emma
Rig: beads
Role: crew
v0.56.0 release failed because verify-cgo.sh was added to darwin and
freebsd builds which intentionally use CGO_ENABLED=0. Bump to v0.56.1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/crew/emma
Rig: beads
Role: crew
…G-4)

The --status flag filters by the stored status column, but dependency-
blocked issues keep status "open" — they only appear via 'bd blocked'.
The old help text listed "blocked" without explaining this distinction,
leading users to expect 'bd list --status blocked' to find dependency-
blocked issues.

Updated help text for list, count, search, and query to say "stored
status" and point to 'bd blocked' for dependency-blocked issues.

Adds TestBUG4_BlockedStatusVsBlocked protocol test documenting the
distinction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
steveyegge and others added 5 commits February 23, 2026 17:45
Under Gas Town (GT_ROOT set), all dolt server operations now resolve to
$GT_ROOT/.beads/ with fixed port 3307, so N worktrees share one server
instead of spawning N servers (was accumulating 62 servers / 9GB RAM).

- Add resolveServerDir/ResolveServerDir for canonical path resolution
- DefaultConfig uses fixed port 3307 under Gas Town, DerivePort standalone
- EnsureRunning resolves internally; bd dolt start/stop/status resolve at CLI
- Add bd dolt killall to find and kill orphan dolt sql-server processes
- Extract shared test server helper (internal/testutil/testdoltserver.go)
  with PID file tracking, stale cleanup, and signal handler for Ctrl+C
- Refactor 3 test files to use shared helper (-224 lines of duplication)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both cmd/bd/doctor and cmd/bd/doctor/fix had test helpers that fell back
to port 3307 (production) when BEADS_DOLT_PORT was not set. Added TestMain
server startup to both packages so they get their own isolated test servers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
beads_test.go was hardcoded to 127.0.0.1:3307, hitting the production
server. Added TestMain that starts its own test server via testutil.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents beads from accidentally killing or stopping the daemon-managed
shared dolt server:

- Stop() refuses under GT_ROOT (use --force or gt dolt stop)
- KillStaleServers() checks both .beads/dolt-server.pid and
  daemon/dolt.pid to avoid killing the daemon-managed server
- bd dolt start detects daemon-managed server via TCP probe
- Idle monitor not forked under GT_ROOT (daemon manages lifecycle)

Based on vulnerability report from beads/emma.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge with upstream daemon-aware changes and add additional guardrails:

- Idle monitor: never forked under Gas Town (forkIdleMonitor + RunIdleMonitor)
- KillStaleServers: refuse to kill when no canonical PID found under Gas Town
- Consolidate on IsDaemonManaged() (remove duplicate isExternallyManaged)
- Remove redundant CLI guards where library-level guards already protect

Upstream already added: StopWithForce, daemon PID lookup in killall,
nuanced bd dolt start (allows emergency start when daemon server is down).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@turian turian force-pushed the feat/metadata-has-key-dsl branch from 778d259 to 3e49f00 Compare February 24, 2026 02:52
steveyegge and others added 23 commits February 23, 2026 19:13
Per Tim Sehn (Dolt CEO): DOLT_COMMIT() implicitly commits the SQL
transaction, so calling tx.Commit() afterward is redundant and "adds
raciness." Under high concurrent load (~20 agents), this raciness
may have contributed to a complete server hang that bricked the town.

The fix: after DOLT_COMMIT succeeds, return immediately without calling
tx.Commit(). When no DOLT_COMMIT is requested (empty commitMsg), the
explicit tx.Commit() is still used.

Also adds a repro script (scripts/repro-dolt-hang/) that compares the
old (with tx.Commit) vs new (without) patterns under concurrent load,
plus an incident report documenting the 2026-02-23 server hang.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…abases

bd doctor --server now checks for leftover test/polecat databases
(testdb_*, doctest_*, doctortest_*) on the shared Dolt server and
warns when found. These accumulate from interrupted test runs and
waste server memory, potentially degrading performance under load.

New command: bd dolt clean-databases [--dry-run]
  Drops all stale test/polecat databases from the Dolt server.

Also exposes DoltStore.DB() accessor for direct SQL queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…roliferation

The old findAvailablePort() tried the next 9 ports when the canonical port
was busy, silently spawning orphan servers that were never cleaned up. This
caused the 62-server / 9GB RAM incident.

New behavior (reclaimPort):
- Port free → use it
- Orphan dolt server on port → kill it, reclaim the port
- Non-dolt process on port → fail loudly with diagnostics
- Never silently fall back to a different port

Also adds:
- Process census: refuses to start if >= max servers running (1 under
  Gas Town, 3 standalone)
- Server adoption: if our data dir is already being served, adopt the
  existing process instead of starting a duplicate
- findPIDOnPort via lsof for port-to-process identification
- isDoltProcessWithDataDir for data-dir matching

Addresses P0 items from beads-9tz.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/crew/emma
Rig: beads
Role: crew
The reclaimPort function had a broken isDoltProcessWithDataDir check that
inspected command-line args for the data directory path. Since dolt sql-server
is launched with cmd.Dir (working directory), the path never appears in args,
so adoption always failed and our own servers were killed as "orphans".

Replace isDoltProcessWithDataDir with isProcessInDir using lsof CWD lookup.
Refactor reclaimPort to return (adoptPID, error) instead of using fragile
error string matching for the adoption path. Add daemon PID file check under
Gas Town so the daemon-managed server is adopted rather than killed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/obsidian
Rig: beads
Role: polecats
Without BEADS_TEST_MODE=1, applyConfigDefaults() uses the shared "beads"
database instead of deriving unique testdb_<hash> names from temp paths.
This caused tracker tests to see 400+ pre-existing issues from prior runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/quartz
Rig: beads
Role: polecats
Each newWorkspace() now generates a random prefix (e.g. "t1a2b3c4d")
instead of the shared "test" prefix, so each test gets its own database
(beads_t<random>) on the shared Dolt server. This prevents cross-test
pollution where tests see issues from other concurrent or prior test runs.

Fixes: beads-sqv

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/jasper
Rig: beads
Role: polecats
…tions

CreateIssue() and UpdateIssue() auto-commit via DOLT_COMMIT, so subsequent
calls to store.Commit() would fail with 'nothing to commit'. Use the existing
isDoltNothingToCommit() helper to treat this as a no-op, matching the pattern
already used in transaction.go and issues.go. Also fix TestCommitPending
subtests that incorrectly used CreateIssue() (which auto-commits) to set up
pending changes — replaced with raw SQL inserts.

Fixes: beads-84s

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/opal
Rig: beads
Role: polecats
bd dolt clean-databases called getStore() which returns nil for dolt
subcommands since the store is not initialized in that code path.
Replace with direct MySQL connection using config, matching the pattern
used by bd dolt show and bd dolt test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/obsidian
Rig: beads
Role: polecats
Increase WaitForServer timeout from 10s to 30s for slow/loaded systems.
Add retry loop (3 attempts) around port allocation + server start to
handle the race window where FindFreePort() releases the socket before
dolt binds it. Make "dolt not found" failure path loud by default
(was previously silent).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/onyx
Rig: beads
Role: polecats
…OFF safety

ChildParentDependencies and OrphanedDependencies used db.Exec() for DELETEs
without explicit transactions. When the Dolt server runs with --no-auto-commit,
these stayed in implicit transactions that were never committed, causing the
fix to report success while data remained unchanged.

Also fixes setupStaleClosedTestDB raw SQL operations (UPDATE closed_at, bulk
INSERT, UPDATE pinned) with the same explicit transaction pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/garnet
Rig: beads
Role: polecats
…bd export

The bd export command was removed in commit 1e1568f as part of the
JSONL-to-Dolt-native refactor, breaking 11 protocol tests. Rewrite all
affected tests to verify data persistence via bd show --json instead of
export roundtrip. Remove unused parseJSONLByID helper.

Fixes: beads-iyu

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/topaz
Rig: beads
Role: polecats
…atabases

Add beads_pt* (gastown patrol tests) and beads_vr* (gastown mail router
tests) to staleDatabasePrefixes in both dolt.go and doctor/server.go.
These test-generated databases were accumulating on the shared Dolt server
with no cleanup path.

Also fix clean-databases timeout: was using a single 30s context for all
DROP DATABASE operations, causing timeouts after ~2 drops. Now uses a
per-operation 30s timeout so each drop gets its full allowance.

Closes beads-zj5

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When GT_ROOT is set, check $GT_ROOT/daemon/dolt.pid first before falling
back to .beads/dolt-server.pid. This matches what reclaimPort() already
does and fixes false 'not running' reports when the daemon manages the
dolt server.

Also unset GT_ROOT in existing IsRunning tests to isolate them from the
real daemon environment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/quartz
Rig: beads
Role: polecats
isDoltProcess() used 'ps -p PID -o command=' which matches zombie (Z state)
processes. These defunct processes have no listening port but still count
against maxDoltServers and can be mistakenly adopted.

Now checks process state via 'ps -o state=' first and rejects Z (zombie) and
X (dead) states before checking the command line.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/jasper
Rig: beads
Role: polecats
All uncommitted working set changes were lost on server restart because
Stop() sent SIGTERM without first committing pending changes. Add
FlushWorkingSet() that connects to the running server and commits all
dirty databases before shutdown. Integrated into StopWithForce() so both
explicit stops and idle-monitor stops are protected.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/obsidian
Rig: beads
Role: polecats
Bulk DROP DATABASE operations (125+ databases) overwhelmed the Dolt server,
causing connection exhaustion and context deadline failures. Added three
backpressure mechanisms:

- Rate limiting: batch 5 drops, pause 2s between batches
- Circuit breaker: back off 10s after 3 consecutive timeouts
- Abort threshold: stop after 10 consecutive failures

Fixes beads-bn7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/onyx
Rig: beads
Role: polecats
…PID files

Three bugs fixed:
1. Legacy PID files (/tmp/dolt-test-server-*.pid) invisible to cleanup because
   only the new prefix (beads-test-dolt-) was scanned. Now scans both prefixes.
2. Orphaned temp dirs (beads-test-dolt-*, beads-bd-tests-*, fix-test-dolt-*,
   doctor-test-dolt-*) accumulated forever because cleanup only handled PID
   files. Now removes dirs older than 5 minutes whose server PID is dead.
3. Go module caches in test dirs have read-only perms preventing rm -rf.
   Now chmod u+w before removal.

Found 94 stale test dirs (4.6GB) + 85 dolt data dirs (549MB) + 1 rogue
test server + 21 dead PID files on production machine.

Closes beads-8yk beads-4rj beads-str

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add TestMain wrappers for molecules and tracker packages to spin up
  isolated test Dolt servers instead of hitting prod on port 3307
- Harden applyConfigDefaults: in test mode, BEADS_DOLT_PORT always
  overrides cfg.ServerPort (even if set from metadata.json)
- Add hard panic guard in dolt.New() if test mode tries to use prod port
- Clear GT_ROOT in TestDoltServerIsRunning to avoid finding daemon PID
- Set BEADS_DOLT_PORT in cmd/bd test server setup for bd init path

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Protocol tests were the source of ~35 beads_t* databases on the prod
Dolt server per test run. Each test called bd init with a random prefix
(t + 8 hex chars), creating beads_t<hex> databases on port 3307.

- Add TestMain to protocol tests that starts a dedicated test Dolt server
- Pass BEADS_DOLT_PORT and BEADS_TEST_MODE through workspace env() so
  the compiled bd subprocess connects to the test server
- Add beads_t to staleDatabasePrefixes in both dolt.go and doctor/server.go
  as a safety net for cleaning legacy pollution

Verified: full go test ./... now creates zero test databases on prod.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When issue_prefix is stored with a trailing hyphen (e.g. 'gt-' instead
of 'gt'), all generated bead IDs get double-hyphened: 'gt--zmw',
'gt--wisp-abc'. Defense-in-depth fix:

- Read-time: TrimSuffix("-") after reading configPrefix from DB in
  CreateIssue and createWisp
- Write-time: TrimSuffix("-") in SetConfig when key is issue_prefix

Fixes: bd-6uly

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Executed-By: beads/polecats/obsidian
Rig: beads
Role: polecats
Support metadata existence checks in the query DSL:
  bd query "has_metadata_key=team AND status=open"

Completes the list/search/query triangle for metadata existence
filtering. Uses existing IssueFilter.HasMetadataKey field and
SQL-level JSON_EXTRACT IS NOT NULL from PR2.

Implements GH#1406.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@turian turian force-pushed the feat/metadata-has-key-dsl branch from 3e49f00 to 9457158 Compare February 24, 2026 17:43
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.

7 participants