3 Commits

Author SHA1 Message Date
Graeme Foster 1cf7490c71 refactor(telemetry): adopt standard OTel SDK env vars with BD_OTEL_* back-compat (#3859)
* refactor(telemetry): adopt standard OpenTelemetry SDK env vars with explicit BD_OTEL_ENABLED gate

Telemetry configuration moves from BD_OTEL_* data variables to the
standard OTEL_* environment variables. Activation now requires
BD_OTEL_ENABLED=true so a machine-global OTEL_* setting (for some other
instrumented tool) cannot silently turn bd telemetry on.

The resource picks up resource.WithFromEnv() so OTEL_SERVICE_NAME and
OTEL_RESOURCE_ATTRIBUTES take effect — users can override service.name
or stamp deployment.environment without forking.

Backwards compatibility: BD_OTEL_METRICS_URL, BD_OTEL_LOGS_URL, and
BD_OTEL_STDOUT continue to work and activate telemetry on their own.
Each translates to its OTEL_* equivalent unconditionally — a legacy
value wins over a pre-existing OTEL_* value so cross-tool environments
don't redirect bd traffic. Every invocation that sees a BD_OTEL_*
variable logs a one-line deprecation warning to stderr.

OTLP endpoint discovery is delegated to the SDK; the explicit URL
helper in internal/telemetry/otlp.go is removed.

OTEL_SDK_DISABLED=true forces telemetry off even when an opt-in is in
effect, matching SDK conventions.

Tests cover: legacy var translation + override semantics, master-switch
activation, OTEL_*-alone-doesn't-activate, OTEL_SDK_DISABLED override,
WithFromEnv resource attribute merge, deprecation warning emission, and
otlpMetricsEndpointSet detection (specific endpoint, generic endpoint,
negative).

Part of the gastownhall/beads PR #3475 split: isolates the OTEL_* env
var standardisation from the WrapStorage wiring (#3858) and the
bd.prefix attribute work (separate follow-up).

* refactor(cmd/bd): extract command-telemetry wiring into testable helpers

cmd/bd/main.go's PreRunE block contained two pieces of OTel wiring —
telemetry.Init and the bd.command.<name> root span construction — that
silently decay if a future refactor drops them. Same regression class
as the WrapStorage bug (telemetry implemented but never called) —
wiring buried in cobra PreRunE escapes review.

Extract two helpers in cmd/bd/command_telemetry.go:

  - commandSpanAttrs(cmdName, version, args): pure function returning
    the initial attribute set for the bd.command.<name> span. The
    bd.actor attribute is stamped later via SetAttributes once
    getActorWithGit() resolves.
  - startCommandTelemetry(...): composes Init + Tracer.Start. Single
    callable line in main.go.

Three tests cover the commandSpanAttrs output (full attrs and the
empty-args edge case) and the startCommandTelemetry wiring contract:
it must always return a non-nil context and span, since the
bd.command.<name> span is the parent for every storage and AI span
downstream — silently returning nil would break trace nesting across
the whole invocation. Whether the span actually records is governed
by telemetry.Init which is covered in internal/telemetry/telemetry_test.go.

main.go shrinks by 10 lines.

* fixup(cmd/bd): stage command_telemetry.go split omitted from merge commit

The previous merge commit (def9f97a4) resolved main.go's PersistentPreRunE
conflict to call initTelemetry()/startCommandSpan() but the working-tree edit
to cmd/bd/command_telemetry.go that defines those two helpers was never
staged, so the merge commit as recorded does not compile:

  cmd/bd/main.go:680:3: undefined: initTelemetry
  cmd/bd/main.go:706:26: undefined: startCommandSpan

This stages that omitted edit: command_telemetry.go now defines
initTelemetry (the Init half) and startCommandSpan (the span-start half,
using commandSpanAttrs) as separate functions, with startCommandTelemetry
kept as their combined form for callers/tests that don't need to interleave
other setup between the two steps. See the merge commit message for why the
split is necessary (main's usage-metrics bootstrap block sits between the
two steps for one internal subcommand).

Verified: CGO_ENABLED=0 go build -tags gms_pure_go ./... now succeeds.

Agent-Signature: claude-fable-5-high on behalf of matt wilkie
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(telemetry): gate the OTLP metric exporter on OTEL_METRICS_EXPORTER

A console-only or none selection — including the legacy BD_OTEL_STDOUT=true
translation — previously still installed an OTLP reader whenever a
machine-global OTEL_EXPORTER_OTLP_ENDPOINT existed, silently exporting bd
metrics to an endpoint configured for some other tool. The selector is now
parsed per the SDK spec (comma-separated; unset defaults to otlp; none
disables) and the OTLP reader requires the selection to include otlp.

The BD_OTEL_STDOUT translation keeps both destinations when
BD_OTEL_METRICS_URL is also set (console,otlp), preserving the existing
both-exporters behavior for that combination.

Also bound the test-cleanup Shutdown with a 2s context so suites configured
with unreachable endpoints (example.invalid) don't spend ~30s in OTLP
retries.

Both issues found by a cross-vendor (Codex) review of the rebased branch.

Agent-Signature: claude-fable-5-high on behalf of matt wilkie

---------

Co-authored-by: matt wilkie <maphew@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 00:05:06 -07:00
Chris Sells 69e33099b8 docs: apply PR #4722 review feedback to user docs
- FAQ: fix bulk migration/export commands (tracker pull/push need explicit
  IDs; bulk lives on sync --pull-only / --pull / --push-only / --push) and
  correct the cross-project isolation claim (hydration + external targets)
- quickstart: replace the broken DOLT.md blob URL with site links
- installation: Quick Install Script heading matches its macOS/Linux/FreeBSD
  body
- rewrite 33 stale SCREAMING_CASE link labels to the target pages' titles
- add description frontmatter to the 55 authored pages missing it
- docs.json: wildcard redirects for the old /next/ and version-prefixed
  route spaces (1.0.0, 1.0.4, 1.0.5)
2026-07-12 11:06:57 -07:00
Chris Sells a86a2c5dfc docs: port user docs into the Mintlify site tree under docs/
Port the website's current (non-versioned) authored pages into docs/ as
Mintlify pages: frontmatter title as H1 (body H1s removed), Docusaurus
admonitions converted to Mintlify components, root-relative extensionless
links, mermaid fences kept as-is. website/docs/** is untouched and keeps
serving the Docusaurus site until cutover.

git-mv the user-facing docs/ originals with no website twin into the new
IA (core-concepts/, architecture/, workflows/, recovery/, multi-agent/,
integrations/, reference/), converted to Mintlify form. The six files
previously mirrored by sync-website-docs.sh now live once in the site.
ERROR_HANDLING.md and CONTRIBUTOR_NAMESPACE_ISOLATION.md move to engdocs/
(contributor pattern guide and design doc per content review).

Pointer stubs remain at docs/{DOLT,STORAGE-BACKENDS,PLUGIN,RECOVERY,
JSON_SCHEMA}.md because released bd binaries print those paths; QUICKSTART
and DOLT-BACKEND stay as existing pointer stubs.

Corrected while porting: the intro's storage diagram claimed data lives at
.beads/dolt/; embedded mode (the default) uses .beads/embeddeddolt/
(internal/storage/embeddeddolt/store.go), server mode uses .beads/dolt/.
2026-07-12 10:37:07 -07:00