Skip to content

Conversation

@groblegark
Copy link
Contributor

Summary

  • Add DecisionPoint and DecisionOption types for human-in-the-loop gates
  • Implement Storage and Transaction interface methods for decision points
  • Create SQLite implementation with decision_points table and migrations
  • Add stub implementations for Dolt and Memory backends

Details

This PR adds the foundation types and storage support for decision points - structured
human-in-the-loop gates that enable requesting and tracking human decisions during
agent workflows.

Types (internal/types/types.go):

  • `DecisionPoint`: Core decision gate with prompt, options, iteration support
  • `DecisionOption`: Structured choice with ID, short label, full description
  • Helper functions for the special `_accept` option in iterative decisions

Storage Interface (internal/storage/storage.go):

  • `CreateDecisionPoint`, `GetDecisionPoint`, `UpdateDecisionPoint`, `ListPendingDecisions`
  • Added to both `Storage` and `Transaction` interfaces

SQLite Implementation:

  • `decision_points.go`: Full CRUD implementation
  • `transaction.go`: Transaction-safe decision point operations
  • `migrations/041_decision_points_table.go`: Creates table with FK to issues
  • `migrations/046_decision_requested_by_column.go`: Adds requested_by for wake notifications

Backend Stubs:

  • Dolt: Placeholder returning not implemented (full implementation in future PR)
  • Memory: Placeholder returning not supported in --no-db mode

Test plan

  • All existing SQLite storage tests pass
  • Build succeeds for all packages
  • Manual testing of decision point CRUD operations

gastown/crew/validator and others added 30 commits January 18, 2026 18:54
When a rig's beads prefix equals its name (e.g., "spa" rig with "spa-"
prefix), Gas Town deduplicates agent IDs to avoid redundancy:
- spa-witness instead of spa-spa-witness
- spa-crew-ubuntu instead of spa-spa-crew-ubuntu

This updates ValidateAgentID to accept these deduplicated formats:
- <prefix>-<role> for rig-level singletons (witness, refinery)
- <prefix>-<role>-<name> for named agents (crew, polecat)

The validation now treats the prefix as both prefix and rig when the
rig component is missing but a valid rig-level or named role is found.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Two fixes for Dolt backend stability:

1. **Dolt connection handling** (store.go): Use single connection with USE
   instead of creating two connections where closing the first affects
   the second. The Dolt embedded driver shares internal state between
   connections to the same path.

2. **Create command store lifecycle** (create.go): Remove defer that closes
   targetStore after assigning it to global store. When routing to a
   different repo, the global store was being closed before
   PersistentPostRun's auto-flush, causing "sql: database is closed".

3. **Daemon event-driven mode** (daemon.go, bd-dli): Allow event-driven mode
   for Dolt backends without JSONL. Dolt uses RPC mutation events and
   native change tracking instead of JSONL file watching.

Additional changes:
- autoflush.go: Add debug logging for store state
- concurrent_test.go: Fix Merge() return value signature

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement native Dolt sync functions that bypass JSONL entirely:

- Add DoltSyncer interface (Commit/Push/Pull methods)
- Add createDoltExportFunc for native Dolt commit/push
- Add createDoltAutoImportFunc for native Dolt pull
- Add createDoltSyncFunc for full Dolt sync cycle
- Update daemon to detect Dolt backend and use native sync
- Add unit tests for DoltSyncer interface

When daemon detects Dolt backend:
- Polling mode: uses createDoltSyncFunc instead of JSONL-based sync
- Event-driven mode: uses createDoltExportFunc/createDoltAutoImportFunc

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Skip JSONL file watcher setup for Dolt (uses RPC mutations)
- Skip import debouncer for Dolt (uses periodic remote sync)
- Add Dolt-specific log messages for clarity
- Add nil checks for importDebouncer safety

Dolt backend now uses a cleaner event loop:
- RPC mutation events trigger Dolt commits
- Periodic ticker triggers Dolt pull from remote
- No wasteful file watcher or fallback ticker

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- feat(formula): add upgrade-beads formula for CLI updates
- feat(daemon): add native Dolt sync support (bd-z6d.2)
- feat(daemon): optimize event loop for Dolt backend (bd-z6d.3)

MR: bd-82ld6
Co-Authored-By: quartz <matthew.baker@pihealth.ai>
Implement Dolt-native mode by detecting the backend type and skipping
auto-import and staleness checks when using Dolt as the database backend.

Changes:
- Add getBackendType() helper to detect backend from metadata.json
- Skip auto-import in AutoImportIfNewer() for Dolt backend
- Skip staleness check in CheckStaleness() for Dolt (always return false)
- Add documentation noting Dolt is source of truth, not JSONL

Dolt is a persistent database that doesn't need JSONL import like SQLite.
This eliminates false "Database out of sync" errors when using Dolt.

Fixes: rig-ebcddd

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
GetRoutedStorageForID was hardcoded to use SQLite for routed storage,
which broke bd show for Dolt-backed beads directories. Now uses
factory.NewFromConfig to respect the backend type from metadata.json,
with SQLite fallback for backwards compatibility.

Fixes: bd show failing on gastown9 hq- and rig- prefixed issues

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
… auto-detection

- Modified defaultSearchPaths() in internal/formula/parser.go to auto-detect
  town root when GT_ROOT is not set
- Modified getFormulaSearchPaths() in cmd/bd/formula.go with same logic
- Exported routing.FindTownRoot() for use by formula package
- Formula resolution now works from any rig directory without GT_ROOT

This fixes issues where witness/refinery/crew agents couldn't find town-level
formulas when GT_ROOT was not set in their environment.

Fixes: hq-ec1067, hq-8d2d01, hq-3d07b9, hq-bd2c80

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add extensive test coverage for lock and timeout behavior in Dolt storage backend:

Bootstrap Lock Tests:
- Lock acquisition and release
- Blocking behavior with concurrent access
- Sequential lock operations
- Double release safety
- Nil file handling

Context Timeout Tests:
- Query timeout with context cancellation
- Transaction timeout behavior
- Commit operation timeout
- Context cancellation during operations

Transaction Lock Tests:
- Transaction serializability
- Rollback on error
- Long-running transaction behavior
- Short transaction contention

RWMutex Tests:
- Concurrent read operations
- Read/write locking behavior

File-Based Lock Tests:
- Low-level flock operations

All 15 tests pass successfully, providing robust validation of lock
and timeout handling in the Dolt backend.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Git uses atomic writes with rename() to update config files, so making
just the config file read-only doesn't prevent writes. The fix changes
the test to make the .git directory read-only instead, which properly
causes git config to fail with a permission error.

Closes: bd-6qgj

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Previously, ValidateAgentID accepted deduplicated format for witness
and refinery roles (e.g., "gt-witness"), but TestValidateAgentID
expected these roles to always require an explicit rig name.

This change removes the deduplicated format support for rig-level
roles, ensuring witness and refinery agent IDs must include an
explicit rig: <prefix>-<rig>-witness or <prefix>-<rig>-refinery.

Fixes: bd-sp1t

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Previously, ValidateAgentID accepted deduplicated format for witness
and refinery roles (e.g., "gt-witness"), but TestValidateAgentID
expected these roles to always require an explicit rig name.

This change removes the deduplicated format support for rig-level
roles, ensuring witness and refinery agent IDs must include an
explicit rig: <prefix>-<rig>-witness or <prefix>-<rig>-refinery.

Fixes: bd-sp1t

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
fix(validation): require explicit rig for witness and refinery agents
TestFindBeadsRepoRoot was failing in the 'not_in_repo' case because /tmp
contained a .beads directory, causing findBeadsRepoRoot to return "/tmp"
instead of an empty string. Added isTemporaryDir() check to skip /tmp and
/var/tmp as valid repo roots since beads repos should never be rooted there.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements automatic retry for Dolt lock contention to prevent
'database is read only' errors when lock acquisition fails.

Changes:
- Add LockRetries and LockRetryDelay to Config struct
- Implement exponential backoff retry loop in dolt.New()
- Add isLockError() helper to detect lock-related errors
- Log lock contention for debugging
- Pass LockTimeout from factory Options to Dolt Config
- Add comprehensive tests for retry behavior

Default configuration:
- 30 retries with 100ms initial delay
- Exponential backoff (doubles each retry)
- Total timeout of ~6 seconds

Resolves: rig-358fc7

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The three agent routing tests (TestAgentStateWithRouting, TestAgentHeartbeatWithRouting,
TestAgentShowWithRouting) were failing because findTownRootFromCWD() was finding the real
Gas Town directory instead of the test's temporary directory.

Fixed by:
1. Creating mayor/town.json in the test's tmpDir to mark it as a town root
2. Changing working directory to tmpDir before routing operations

This ensures routing code correctly resolves routes within the test environment.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Work completed in gastown repository: polecat/pearl/bd-hdzi@mklra1ie

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…teveyegge#1139)

The RecordSyncFailure and ResetBackoffOnDaemonStart functions had a
TOCTOU (time-of-check-time-of-use) race condition. They called
LoadSyncState (which locks, reads, unlocks) then modified the state,
then called SaveSyncState (which locks, writes, unlocks).

Between LoadSyncState returning and SaveSyncState being called, another
goroutine could load the old state, modify it, and save it - then this
goroutine's save would overwrite those changes.

Fix: Create internal unlocked helper functions (loadSyncStateUnlocked,
saveSyncStateUnlocked) and have RecordSyncFailure and
ResetBackoffOnDaemonStart hold the lock for the entire load-modify-save
operation.

Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…veyegge#1140)

The debouncer's timer callback used a pattern that could cause a
double-unlock panic if the action function panicked:

  d.mu.Lock()
  defer d.mu.Unlock()
  if d.seq == currentSeq {
      d.mu.Unlock()  // Manual unlock
      d.action()     // If this panics...
      d.mu.Lock()    // ...this never runs
  }                  // ...but defer still tries to unlock

Fix: Remove the defer and manually manage lock state. Now if the
action panics, the lock is already released, preventing a
double-unlock panic that would mask the original panic.

Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…rts-with matching (steveyegge#1137)

When creating issues with explicit IDs like `bd create --id hq-cv-test`,
the prefix validation was failing even when `hq-cv` was in `allowed_prefixes`.

Root cause: `ExtractIssuePrefix("hq-cv-test")` returns `"hq"` (not `"hq-cv"`)
because "test" looks like an English word, causing the algorithm to fall back
to the first hyphen. The validation then checked if `"hq"` was in the allowed
list containing `"hq-cv"` - which failed.

The fix adds `ValidateIDPrefixAllowed()` which validates the full ID using
"starts with" matching (the same approach the importer uses successfully).
This correctly handles multi-hyphen prefixes like `hq-cv-` regardless of
what the suffix looks like.

Fixes steveyegge#1135

Co-authored-by: Steven Syrek <steven.syrek@deepl.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Problem:
- Diagnostic fix messages were restricted to single lines
- Inconsistent file path formatting in database sync issues
- Outdated cleanup command suggested in maintenance fixes

Solution:
- Implement multiline support for doctor fix messages
- Standardize issue file paths across database diagnostics
- Update maintenance fix instructions to use 'bd admin cleanup'

Impact:
- Clearer and more accurate recovery instructions for users
- Better readability of complex diagnostic output

Fixes: GH#1170, GH#1171, GH#1172
…egge#1185)

When no git remote is configured, DetectUserRole() now defaults to
Maintainer instead of Contributor. This fixes issue routing for:

1. New personal projects (no remote configured yet)
2. Intentionally local-only repositories

Previously, issues would silently route to ~/.beads-planning instead
of the local .beads/ directory.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…es (steveyegge#1176)

The scanIssues() function and multiple SQL queries were not selecting or
scanning agent-related fields (hook_bead, role_bead, agent_state, last_activity,
role_type, rig, mol_type) and time-based scheduling fields (due_at, defer_until).

This caused bd list --json to return null for last_activity even when the
database contained valid timestamps, preventing proper agent health monitoring.

Updated files:
- dependencies.go: scanIssues() variable declarations, scan calls, assignments
- queries.go: SearchIssues query
- labels.go: GetIssuesByLabel query
- ready.go: GetReadyWork and GetNewlyUnblockedByClose queries
- transaction.go: GetIssue query, SearchIssues query, scanIssueRow()

Fixes steveyegge#1175
…ge#1166) (steveyegge#1168)

* fix(config): validate sync-branch at config time

Add sync-branch validation to validateYamlConfigValue() to reject
main/master at config time, preventing the validation bypass in GH#1166.

- Add case for sync-branch and sync.branch keys
- Inline validation logic to avoid import cycle (config <-> syncbranch)
- Add unit tests for rejection (main/master) and acceptance (valid names)

Part of: steveyegge#1166

* fix(sync): add runtime guard for sync-branch == current-branch

Add dynamic runtime check before worktree operations to catch cases
where sync-branch matches the current branch. This provides defense
in depth for manual YAML edits, pre-fix configs, or non-main/master
branch names (trunk, develop, production, etc.).

- Check IsSyncBranchSameAsCurrent() after hasSyncBranchConfig is set
- Position check BEFORE worktree entry (CWD changes inside worktree)
- Add integration test TestSync_FailsWhenOnSyncBranch

Part of: steveyegge#1166

* docs: note main/master restriction in sync-branch FAQ

Clarifies that git worktrees cannot checkout the same branch in
multiple locations, so main/master cannot be used as sync branch.
…veyegge#1160)

* fix(config): remove duplicate declarations between config.go and sync.go

Commit e82e15a created sync.go with typed constants (SyncMode,
ConflictStrategy, Sovereignty) but didn't remove the original untyped
constants from config.go that were added in 16f8c3d. This caused
redeclaration errors preventing the project from building.

Changes:
- Remove duplicate SyncMode, ConflictStrategy, Sovereignty constants
  from config.go (keep typed versions in sync.go)
- Remove duplicate GetSyncMode, GetConflictStrategy, GetSovereignty
  functions from config.go (keep sync.go versions with warnings)
- Update SyncConfig, ConflictConfig, FederationConfig structs to use
  typed fields instead of string
- Add IsSyncModeValid, IsConflictStrategyValid, IsSovereigntyValid
  wrapper functions that use sync.go's validation maps
- Update cmd/bd/sync.go to use typed ConflictStrategy parameter
- Update tests to work with typed constants

* fix(dolt): handle Merge return values in concurrent test

* fix(test): add --repo flag to show_test.go to bypass auto-routing

The tests were failing because the create command was routing issues
to ~/.beads-planning instead of the test's temp directory. Adding
--repo . overrides auto-routing and creates issues in the test dir.
…eyegge#1158)

Fresh clones with sync-branch configured in .beads/config.yaml would show
.beads/issues.jsonl as modified in git status because the git index flags
(skip-worktree, assume-unchanged) are local-only and don't transfer via clone.

This fix ensures bd init sets these flags in two scenarios:
1. `bd init --branch <name>` - when user explicitly sets sync branch
2. `bd init` on cloned repo - when sync-branch already exists in config.yaml

Added SetSyncBranchGitignoreFlags() helper and two tests for coverage.
The Dolt implementation of AddLabel and RemoveLabel was not using
transactions, causing label changes to not persist. This fix:

1. Wraps label operations in proper transactions with commit
2. Records events when labels change (matching SQLite behavior)
3. Marks issues as dirty for incremental export
4. Adds error logging in decision_respond.go instead of silently
   discarding errors from label operations

Fixes label updates not persisting when responding to decisions
(decision:pending → decision:resolved).

Part of hq-946577.36 (E2E review of decision implementation).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Dolt implementation of CreateDecisionPoint and UpdateDecisionPoint
was not using transactions, causing decision point changes to not persist.
This was discovered when iterative refinement created new decision
iterations but the decision_point record wasn't being saved.

This fix wraps both operations in proper transactions with commit,
consistent with how CloseIssue and other write operations work in the
Dolt storage layer.

Part of hq-946577.36 (E2E review of decision implementation).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
groblegark pushed a commit to groblegark/beads that referenced this pull request Jan 26, 2026
Add configuration and lifecycle support for decision points:

Config (internal/config/decision.go):
- Decision routing configuration (default, urgent channels)
- Timing settings (timeout, reminder interval, max iterations)
- Helper functions for accessing decision settings

Hooks (internal/hooks/decision.go):
- DecisionHookPayload for hook scripts
- RunDecision/RunDecisionSync for executing decision lifecycle hooks
- Support for create, respond, and timeout events

Notification (internal/notification/):
- Dispatcher for multi-channel notifications (email, webhook, SMS, log)
- Route-based notification dispatch
- Email template rendering support

Depends on: steveyegge#1327 (Types & Storage), steveyegge#1328 (RPC & Protocol)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When multiple writers access the Dolt database concurrently,
serialization conflicts can occur (Error 1213, Error 1105).
These errors indicate the transaction should be retried.

Changes:
- Add isSerializationError() to detect Error 1213 and 1105
- Add retry logic to RunInTransaction with exponential backoff
- Max 5 retries with initial 50ms delay, capped at 2s
- Add test cases for serialization error detection

Fixes: hq-a0ef40

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
groblegark pushed a commit to groblegark/beads that referenced this pull request Jan 26, 2026
Add CLI commands for managing decision points:
- bd decision create: Create a decision point for human input
- bd decision list: List pending decisions
- bd decision show: Show decision details
- bd decision respond: Record a human response
- bd decision await: Wait for decision resolution
- bd decision check: Check if decision is ready
- bd decision cancel: Cancel a pending decision
- bd decision remind: Send reminder notifications

Supporting infrastructure:
- internal/decision/iterate.go: Iteration logic for refinement loops
- internal/hooks/hooks.go: Added decision event constants

Documentation:
- website/docs/workflows/decisions.md: User guide

Depends on: steveyegge#1327, steveyegge#1328, steveyegge#1329

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
decision and others added 21 commits January 26, 2026 04:55
Systematic audit of Dolt storage layer found additional write operations
that were not using proper transaction handling:

- dependencies.go: AddDependency, RemoveDependency
- events.go: AddComment, ImportIssueComment
- config.go: SetConfig, DeleteConfig, SetMetadata

All now use BeginTx/Commit pattern, consistent with other Dolt operations.
Also added markDirty calls where appropriate for incremental export.

Part of hq-946577.36 (E2E review of decision implementation).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test expected routes to be imported during bootstrap, but route
importing was intentionally disabled to avoid an import cycle
(routing -> factory -> dolt -> routing).

Updated TestBootstrapWithRoutesAndInteractions to expect 0 routes,
matching the actual implementation behavior documented at
bootstrap.go:246-248.

Fixes: hq-f4fdd5

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When GetNextChildID is called with a non-existent parent ID, the FK
constraint on child_counters fails with a confusing error (Error 1452).

Now we explicitly check if the parent issue exists before attempting
to insert into child_counters, providing a clear error message.

Added TestGetNextChildID_ParentNotExists to verify the behavior.

Fixes: hq-e6988b

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
External dependencies (e.g., external:project:capability) don't exist
in the local issues table. This caused FK violations when:
1. The depends_on_id FK constraint tried to reference a non-existent row
2. markDirty tried to insert the external ref into dirty_issues

Changes:
- Remove FK constraint on depends_on_id in schema
- Add migration to drop existing FK constraint
- Skip markDirty for external references (prefix: external:)
- Add test for external dependency creation

Fixes: bd-3q6.6-1

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove duplicate test function declarations in config_test.go
  (TestGetCustomTypesFromYAML, TestGetFieldStrategies, etc. were duplicated)
- Add explicit string() casts for SyncMode, ConflictStrategy, and
  Sovereignty constants used in test structs
- Add missing GetEpicProgress method to mockStorage in storage_test.go

Note: Some config tests fail due to local .beads/config.yaml setting
sync.mode=dolt-native, overriding the expected default. This is a
pre-existing test isolation issue, not introduced by this fix.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests checking default values were failing when run in directories
with .beads/config.yaml files that override defaults.

Fixes:
- TestSyncConfigDefaults: add t.Chdir(t.TempDir()) for isolation
- TestGetSyncMode: add t.Chdir(t.TempDir()) for isolation
- TestGetSovereigntyInvalid: add isolation + fix expectation
  (invalid sovereignty should return T1, not empty string)

Closes: hq-ff52bd

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add proper BeginTx/Commit transaction handling to:
- dirty.go: ClearDirtyIssuesByID, SetExportHash, ClearAllExportHashes
- credentials.go: AddFederationPeer, RemoveFederationPeer, UpdatePeerLastSync
- federation.go: setLastSyncTime

These functions were using s.db.ExecContext() without transactions,
which can cause changes to not persist in Dolt's MySQL-compatible mode.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
bd decision create now requires the --options flag with at least one
option. Previously, decisions could be created without options, which
resulted in malformed decisions that couldn't be resolved through the
TUI or gt decision commands.

Validation added:
- Error if --options flag is missing
- Error if options array is empty after parsing
- Helpful example shown in error messages

Closes: hq-5f80e6

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Upstream changes:
- gitignore export-state directory
- formula dev build handling in local-install
- Go 1.24 in CI release workflow
- Version bump to 0.49.1
- Various Dolt and daemon fixes
- bd list --json optimization
- activity --details flag
- import custom issue types support
- list watch mode nil pointer fix

Conflicts resolved:
- .gitignore: kept Gas Town paths (.beads/, .logs/)
- version.go: kept our 0.50.0 version
- transaction.go: kept our ID generation fix (hq-8af330.10),
  added PrefixOverride support from upstream

Test fixes:
- direct_mode_test.go: fixed metadata.json database name mismatch
- validators_test.go: adjusted test for Gas Town built-in types

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix 42 lint issues to pass CI:
- errcheck: Add explicit error handling for json.Unmarshal, conn.Write,
  SetDeadline, server.Shutdown, gateway.close, json.Encoder.Encode, etc.
- misspell: Use American spelling "canceled" instead of "cancelled"
  (keep "cancelled" in JSON tags for API compatibility with nolint)
- gosec G304: Add nolint comments for trusted file path operations
- gosec G204: Add nolint comments for intentional subprocess commands
- gosec G202: Add nolint comments for safe SQL placeholder concatenation
- gosec G306: Add nolint comments for skill files that need to be readable
- unparam: Add nolint comments for interface consistency and future use

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Updates bd decision check --inject to use injection queue instead of
direct stdout. This prevents API 400 concurrency errors when the
UserPromptSubmit hook runs while Claude is mid-tool-use.

The inject queue is shared with gastown's gt inject command:
- bd decision check --inject queues content to .runtime/inject-queue/
- gt inject drain outputs the queued content from PostToolUse hook

Fixes: gt-ukf

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Dolt commit operation can fail with "optimistic lock failed on
database Root update" errors when multiple writers try to commit
simultaneously. This is a transient error that can be resolved by
retrying with exponential backoff.

Changes:
- Add isSerializationError() to detect Dolt optimistic lock failures
  (Error 1105, Error 1213, "optimistic lock failed")
- Update isTransientDoltError() to include serialization errors
- Add retry logic to DoltStore.Commit() with exponential backoff
- Store lockRetries and lockRetryDelay in DoltStore struct
- Add comprehensive tests for serialization error detection

This fix resolves intermittent failures in commands like `gt decision
request` and `gt sling` that depend on reliable Dolt commits.

Fixes: hq-jkr56x

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The isSerializationError function was incorrectly matching "Error 1105:
nothing to commit" as a serialization error, causing infinite retries
when there was genuinely nothing to commit.

Changes:
- Add explicit check to exclude "nothing to commit" and "no changes"
  from serialization error detection
- Add comprehensive tests for commit retry behavior
- Add TestConcurrentCommits integration test
- Add TestCommitRetryConfig and TestCommitRetryDefaults tests
- Add test cases for "nothing to commit" error exclusion

This fix ensures that the retry logic only triggers for actual
optimistic lock failures, not for benign "nothing to commit" situations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add text utilities for smart truncation of long text content:
- TruncateLines: show beginning and end with "..." in middle
- TruncateChars: smart word-boundary truncation
- TruncateSimple: basic end truncation with "..."
- WrapText: word-wrap aware line wrapping

Update bd show command:
- Add --full/-f flag to show complete text without truncation
- Default to smart truncation for description, design, notes, and
  acceptance criteria fields when they exceed 15 lines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, RenderMarkdown returned raw text without word wrapping
when running in agent mode (CLAUDE_CODE env set). This caused long
lines to go off the edge of the screen.

Now text is always wrapped at terminal width (max 100 chars), even
in agent mode - just without glamour styling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The inline post-merge hook created by `bd init` was using `bd import -i`
which can fail in various scenarios. Changed to use the more robust
`bd sync --import-only --no-git-history --no-daemon` which:
- Forces direct mode properly
- Handles store initialization
- Has more robust error handling

Also removed duplicate Dolt backend check.

Fixes: hq-bokgaz

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
FindJSONLInDir was incorrectly picking routes.jsonl as the JSONL target
when issues.jsonl didn't exist. This caused the bd export to write
issue data to routes.jsonl, corrupting the route definitions.

The bug manifested when:
1. A .beads directory had only routes.jsonl (no issues.jsonl)
2. FindJSONLInDir glob matched routes.jsonl
3. The fallback logic returned routes.jsonl as the export target
4. Issue data was written over route definitions

Fix: Add routes.jsonl to the skip list alongside deletions.jsonl,
interactions.jsonl, and merge artifacts.

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

Executed-By: gastown/crew/upstream_merger
Rig: gastown
Role: crew
Add comprehensive documentation for the decision points feature:
- Create docs/DECISIONS.md with full feature documentation
- Add feature bullet to README.md
- Add Decision Points section to CLI_REFERENCE.md

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

Executed-By: gastown/crew/upstream_merger
Rig: gastown
Role: crew
Add foundation types and storage support for decision points - human-in-the-loop
gates that enable structured input during agent workflows.

Types:
- DecisionPoint: human-in-the-loop decision gate with iteration support
- DecisionOption: structured option with ID, short label, and description

Storage interface:
- CreateDecisionPoint, GetDecisionPoint, UpdateDecisionPoint, ListPendingDecisions
- Added to both Storage and Transaction interfaces

SQLite implementation:
- decision_points table with FK to issues, iteration chain via prior_id
- Migration 041 creates table, 046 adds requested_by column
- Full CRUD support in both storage.go and transaction.go

Dolt/Memory stubs:
- Added placeholder implementations returning "not implemented" errors
- Full Dolt support planned for separate PR

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

Executed-By: gastown/crew/upstream_merger
Rig: gastown
Role: crew
@groblegark groblegark force-pushed the decision-pr1-types-storage branch from e404f31 to 51ceabf Compare January 27, 2026 03:01
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.