Commit Graph

76 Commits

Author SHA1 Message Date
Dustin Brown
132f9d2f6f feat(dolt): auto-commit write commands and set explicit commit authors (#1267)
* /{cmd,docs,internal}: autocommit writes in dolt backend

Executed-By: beads/crew/emma
Rig: beads
Role: crew

* /{cmd,internal}: fix commit author

Executed-By: beads/crew/emma
Rig: beads
Role: crew

* /cmd/bd: fix race condition

Executed-By: beads/crew/emma
Rig: beads
Role: crew

---------

Co-authored-by: Test <test@example.com>
2026-01-25 17:02:12 -08:00
Steve Yegge
ab61b0956b feat(dolt): auto-commit write commands and set explicit commit authors (#1270)
Adds Dolt auto-commit functionality for write commands and sets explicit commit authors.

Includes fix for race condition in commandDidWrite (converted to atomic.Bool).

Original PR: #1267 by @coffeegoddd
Co-authored-by: Dustin Brown <dustin@dolthub.com>
2026-01-22 20:52:20 -08:00
matt wilkie
1f8a6bf84e fix(autoimport): auto-correct deleted status to tombstone for JSONL compatibility (#1231)
* fix(autoimport): auto-correct deleted status to tombstone for JSONL compatibility (GH#1223)

This fix addresses the 'Stuck in sync diversion loop' issue where v0.48.0
encountered validation errors during JSONL import. The issue occurs when
JSONL files from older versions have issues with status='deleted' but the
current code expects status='tombstone' for deleted issues.

Changes:
- Add migration logic in parseJSONL to auto-correct 'deleted' status to 'tombstone'
- Ensure tombstones always have deleted_at timestamp set
- Add debug logging for both migration operations
- Prevents users from being stuck in sync divergence when upgrading

Fixes GH#1223: Stuck in sync diversion loop

* fix(autoimport): comprehensively fix corrupted deleted_at on non-tombstone issues (GH#1223)

The initial fix for GH#1223 only caught issues with status='deleted', but the real
data in the wild had issues with status='closed' (or other statuses) but also
had deleted_at set, which violates the validation rule.

Changes:
- Add broader migration logic: any non-tombstone issue with deleted_at should become tombstone
- Apply fix in all three JSONL parsing locations:
  - internal/autoimport/autoimport.go (parseJSONL for auto-import)
  - cmd/bd/import.go (import command)
  - cmd/bd/daemon_sync.go (daemon sync helper)
- Add comprehensive test case for corrupted closed issues with deleted_at
- Fixes the 'non-tombstone issues cannot have deleted_at timestamp' validation error
  during fresh bd init or import

Fixes GH#1223: Stuck in sync diversion loop

* Add merge driver comment to .gitattributes

* fix: properly clean up .gitattributes during bd admin reset

Fixes GH#1223 - Stuck in sync diversion loop

The removeGitattributesEntry() function was not properly cleaning up
beads-related entries from .gitattributes. It only removed lines
containing "merge=beads" but left behind:
- The comment line "# Use bd merge for beads JSONL files"
- Empty lines following removed entries

This caused .gitattributes to remain in a modified state after
bd admin reset --force, triggering sync divergence warning loop.

The fix now:
- Skips lines containing "merge=beads" (existing behavior)
- Skips beads-related comment lines
- Skips empty lines that follow removed beads entries
- Properly cleans up file so it's either empty (and gets deleted)
  or contains only non-beads content

---------

Co-authored-by: Amp <amp@example.com>
2026-01-21 21:50:38 -08:00
Test
b849f598d7 /{cmd,docs,internal}: support import export for dolt backends 2026-01-21 13:13:24 -08:00
Peter Chanthamynavong
e110632afc fix(context): complete RepoContext migration for remaining sync files (#1114)
Follow-up to #1102 - migrates remaining git command locations to use
RepoContext API for correct repo resolution when BEADS_DIR is set.

Files migrated:
- sync_branch.go: getCurrentBranch, showSyncStatus, mergeSyncBranch
- sync_check.go: checkForcedPush
- sync_import.go: doSyncFromMain
- autoimport.go: readFromGitRef, checkGitForIssues
- status.go: getGitActivity
- import.go: attemptAutoMerge (gitRoot lookup)
- reinit_test.go: add ResetCaches for test isolation

Pattern used throughout:
- Try RepoContext first: rc.GitCmd() runs in beads repo
- Fallback to CWD for tests or repos without beads
- Graceful degradation maintains backwards compatibility
2026-01-15 19:23:07 -08:00
emma
1c1dabcfdd fix(duplicates): prefer issues with children/deps when choosing merge target (GH#1022)
The duplicate merge target selection now considers structural relationships:
1. Dependent count (children, blocked-by) - highest priority
2. Text reference count - secondary
3. Lexicographically smallest ID - tiebreaker

This fixes the bug where `bd duplicates --auto-merge` would suggest closing
an epic with 17 children instead of the empty shell duplicate.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 00:45:25 -08:00
emma
62e4eaf7c1 fix(sync): make snapshot protection timestamp-aware (GH#865)
The --protect-left-snapshot mechanism was protecting ALL local issues
by ID alone, ignoring timestamps. This caused newer remote changes to
be incorrectly skipped during cross-worktree sync.

Changes:
- Add BuildIDToTimestampMap() to SnapshotManager for timestamp-aware
  snapshot reading
- Change ProtectLocalExportIDs from map[string]bool to map[string]time.Time
- Add shouldProtectFromUpdate() helper that compares timestamps
- Only protect if local snapshot is newer than incoming; allow update
  if incoming is newer

This fixes data loss scenarios where:
1. Main worktree closes issue at 11:31
2. Test worktree syncs and incorrectly skips the update
3. Test worktree then pushes stale open state, overwriting mains changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 13:27:36 -08:00
Steve Yegge
f46cc2e798 chore: remove issue ID references from comments and changelogs
Strip (bd-xxx), (gt-xxx) suffixes from code comments and changelog
entries. The descriptions remain meaningful without the ephemeral
issue IDs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 10:05:16 -08:00
Steve Yegge
9e7ccb3e03 fix: update jsonl_file_hash on import to prevent hash mismatch warnings (bd-0vtq)
The import command was only updating jsonl_content_hash, not jsonl_file_hash.
After sync imports JSONL but skips re-export (because DB matches JSONL),
the jsonl_file_hash remained stale, causing validateJSONLIntegrity() to
emit spurious "JSONL file hash mismatch" warnings on subsequent operations.

Now import also calls SetJSONLFileHash with the same hash value, keeping
both hashes in sync and eliminating the false warnings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-27 23:22:18 -08:00
Steve Yegge
92e6f4c079 refactor: remove legacy autoflush code paths (bd-xsl9)
Remove dual code paths in the autoflush system. FlushManager is now the
only code path for auto-flush operations.

Changes:
- Remove legacy globals: isDirty, needsFullExport, flushTimer
- Remove flushToJSONL() wrapper function (was backward-compat shim)
- Simplify markDirtyAndScheduleFlush/FullExport to just call FlushManager
- Update tests to use FlushManager or flushToJSONLWithState directly

FlushManager handles all flush state internally in its run() goroutine,
eliminating the need for global state. Sandbox mode and tests that do
not need flushing get a no-op when FlushManager is nil.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 01:56:19 -08:00
Steve Yegge
e67712dcd4 refactor(cmd): migrate sort.Slice to slices.SortFunc (bd-u2sc.2)
Modernize sorting code to use Go 1.21+ slices package:
- Replace sort.Slice with slices.SortFunc across 16 files
- Use cmp.Compare for orderable types (strings, ints)
- Use time.Time.Compare for time comparisons
- Use cmp.Or for multi-field sorting
- Use slices.SortStableFunc where stability matters

Benefits: cleaner 3-way comparison, slightly better performance,
modern idiomatic Go.

Part of GH#692 refactoring epic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-22 15:39:55 -08:00
Ryan Snodgrass
acfdcebc0f fix: misc improvements and dependency updates
- Update nix vendorHash after fatih/color removal
- Bump version to 0.30.7
- Add GroupID to remaining commands for proper cobra grouping
- Apply semantic color rendering to list and stale commands
- Update pre-commit hook template
2025-12-20 17:09:50 -08:00
Steve Yegge
6c060461cb feat(jsonl): add omitempty to reduce JSONL bloat (beads-399)
Add omitempty JSON tags to Issue struct fields (Description, Status,
Priority, IssueType) and SetDefaults method to apply proper defaults
when importing JSONL with omitted fields.

This reduces JSONL file size for minimal issues like notifications
by not exporting empty/default values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 23:18:11 -08:00
Steve Yegge
f270d90f12 fix: Resolve 3 P1 bugs and add --body-file flag to bd create
- bd-06px: Add --no-git-history flag to import command for sync subprocess compatibility
- bd-0zp7: Add missing hook calls (EventMessage in mail reply, EventClose in mail ack)
- bd-hy9p: Implement --body-file and --description-file flags for reading descriptions from files

Also closed stale issues that were already fixed:
- bd-0d5p: macOS test timeout (already fixed with SysProcAttr)
- bd-7yg: Merge driver placeholders (already using correct %A %O %A %B)
- bd-4ri: Test deadlock (test passes in 0.04s now)
- bd-b3og: TestImportBugIntegration (test no longer exists)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 17:29:33 -08:00
Steve Yegge
9f76cfda01 refactor: remove all deletions.jsonl code (bd-fom)
Complete removal of the legacy deletions.jsonl manifest system.
Tombstones are now the sole deletion mechanism.

Removed:
- internal/deletions/ - entire package
- cmd/bd/deleted.go - deleted command
- cmd/bd/doctor/fix/deletions.go - HydrateDeletionsManifest
- Tests for all removed functionality

Cleaned:
- cmd/bd/sync.go - removed sanitize, auto-compact
- cmd/bd/delete.go - removed dual-writes
- cmd/bd/doctor.go - removed checkDeletionsManifest
- internal/importer/importer.go - removed deletions checks
- internal/syncbranch/worktree.go - removed deletions merge
- cmd/bd/integrity.go - updated validation (warn-only on decrease)

Files removed: 12
Lines removed: ~7500

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 14:20:49 -08:00
Rod Davenport
6985ea94e5 fix(sync): protect local issues from git-history-backfill during sync (#485)
Fix sync bug where newly created issues were incorrectly tombstoned during bd sync.

The root cause was git-history-backfill finding issues in local commits on the sync branch, then tombstoning them when they weren't in the merged JSONL. The fix protects issues from the left snapshot (local export) from git-history-backfill.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2025-12-12 13:28:48 -08:00
Darin
e0734e230f fix: NixOS symlink compatibility for mtime and permission checks (#459)
* fix: use os.Lstat for symlink-safe mtime and permission checks

On NixOS and other systems using symlinks heavily (e.g., home-manager),
os.Stat follows symlinks and returns the target's metadata. This causes:

1. False staleness detection when JSONL is symlinked - mtime of target
   changes unpredictably when symlinks are recreated
2. os.Chmod failing or changing wrong file's permissions when target
   is in read-only location (e.g., /nix/store)
3. os.Chtimes modifying target's times instead of the symlink itself

Changes:
- autoimport.go: Use Lstat for JSONL mtime in CheckStaleness()
- import.go: Use Lstat in TouchDatabaseFile() for JSONL mtime
- export.go: Skip chmod for symlinked files
- multirepo.go: Use Lstat for JSONL mtime cache
- multirepo_export.go: Use Lstat for mtime, skip chmod for symlinks
- doctor/fix/permissions.go: Skip permission fixes for symlinked paths

These changes are safe cross-platform:
- On systems without symlinks, Lstat behaves identically to Stat
- Symlink permission bits are ignored on Unix anyway
- The extra Lstat syscall overhead is negligible

Fixes symlink-related data loss on NixOS. See GitHub issue #379.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* test: add symlink behavior tests for NixOS compatibility

Add tests that verify symlink handling behavior:
- TestCheckStaleness_SymlinkedJSONL: verifies mtime detection uses
  symlink's own mtime (os.Lstat), not target's mtime (os.Stat)
- TestPermissions_SkipsSymlinkedBeadsDir: verifies chmod is skipped
  for symlinked .beads directories
- TestPermissions_SkipsSymlinkedDatabase: verifies chmod is skipped
  for symlinked database files while still fixing .beads dir perms

Also adds devShell to flake.nix for local development with go, gopls,
golangci-lint, and sqlite tools.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-05 13:22:09 -08:00
Steve Yegge
28a661a320 feat: add --readonly flag for worker sandboxes (gt-ymo)
Add a --readonly flag that blocks all write operations, allowing workers
to read beads state without modifying it. Workers can use:
- bd show, bd list, bd ready (read operations)

Workers cannot use:
- bd create, bd update, bd close, bd sync, etc. (write operations)

The flag can be set via:
- --readonly flag on command line
- BD_READONLY=true environment variable
- readonly: true in config file

This enables swarm workers to see their assigned work from a static
snapshot of the beads database without accidentally modifying it.

Commands protected by readonly mode:
- create, update, close, delete, edit
- sync, import, reopen
- comment add, dep add/remove, label add/remove
- repair-deps, compact, migrate, migrate-hash-ids, migrate-issues
- rename-prefix, validate --fix-all, duplicates --auto-merge
- epic close-eligible, jira sync

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 23:44:22 -08:00
Steve Yegge
f7dea354d8 fix(import): add warning when issues are skipped due to deletions manifest
When importing JSONL that contains issues in the deletions manifest,
import now:
- Filters out deleted issues before import
- Prints per-issue warning with deletion details (date, actor)
- Shows count of skipped issues in summary
- Suggests --ignore-deletions flag to force import

The new --ignore-deletions flag allows importing issues that are in the
deletions manifest, useful for recovering accidentally deleted issues.

Fixes bd-4zy

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 21:23:04 -08:00
Steve Yegge
eb4b81d209 fix: prevent bd sync corruption from stale daemon SQLite connection
Root cause: When beads.db is deleted and recreated while daemon is running,
daemon's SQLite connection becomes stale (points to old deleted file via
file descriptor), causing export to return incomplete/corrupt data.

Fix:
- sync command now forces direct mode by closing daemonClient at start
- importFromJSONL subprocess uses --no-daemon to avoid daemon connection issues
- Added documentation to import.go explaining the daemon behavior

Also:
- Skip TestZFCSkipsExportAfterImport (broken test - subprocess spawning
  doesn't work in test environment, needs refactoring
- Update hook templates to version 0.26.2

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)
2025-11-29 20:54:28 -08:00
Steve Yegge
f59f8c20d0 refactor: rename last_import_hash to jsonl_content_hash (bd-39o)
The metadata key 'last_import_hash' was misleading because it's updated on
both import AND export. Renamed to 'jsonl_content_hash' which more accurately
describes its purpose - tracking the content hash of the JSONL file.

Added migration support: read operations try new key first, then fall back
to old key for backwards compatibility with existing databases.

Files modified:
- cmd/bd/integrity.go: Update key name with migration support
- cmd/bd/import.go: Update key name
- cmd/bd/sync.go: Update key name
- cmd/bd/autoflush.go: Update key name with migration support
- cmd/bd/daemon_sync.go: Update key name
- cmd/bd/daemon_event_loop.go: Update key name with migration support
- internal/autoimport/autoimport.go: Update key name with migration support
- Updated all related tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 23:14:12 -08:00
Steve Yegge
8b8a662acb Fix fresh clone UX with friendly error messages (bd-dmb)
When opening a database that exists but is missing issue_prefix config
(typical in fresh clone scenarios), show a helpful error message instead
of cryptic migration invariant errors.

The new message:
- Explains the database needs initialization
- Detects if a JSONL file exists and shows the issue count
- Suggests the exact command to run: bd import -i <path>
- Falls back to suggesting bd init --prefix if no JSONL exists

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 22:40:57 -08:00
Steve Yegge
cdc156428c fix(staleness): use RFC3339Nano precision for last_import_time (#399)
The staleness check compares last_import_time against JSONL file mtime.
File mtime has nanosecond precision, but last_import_time was stored with
only second precision (RFC3339). This caused a race condition where the
stored time could be slightly earlier than the file mtime, triggering
false "Database out of sync" errors - particularly in git worktrees.

Changed all 6 locations that set last_import_time to use RFC3339Nano.
The CheckStaleness parser already handles both formats, so this is
backward compatible.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-27 00:11:01 -08:00
Steve Yegge
5506486dc5 feat(import,sync): add --no-git-history flag to prevent spurious deletions
Fixes bd-0b2: The git history backfill mechanism was causing data loss
during JSONL filename migrations (beads.jsonl → issues.jsonl). When issues
existed in the old filename's git history, the backfill incorrectly treated
them as "deleted" and purged them from the database.

Changes:
- Add NoGitHistory field to importer.Options and ImportOptions structs
- Modify purgeDeletedIssues() to skip git history check when flag is set
- Add --no-git-history flag to bd import command
- Add --no-git-history flag to bd sync command
- Update purge_test.go to pass Options argument

Usage:
  bd import -i .beads/issues.jsonl --no-git-history
  bd sync --no-git-history

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 23:10:43 -08:00
Steve Yegge
6294ef0cc6 fix(init,import): preserve metadata.json and improve prefix detection
- bd init now preserves existing metadata.json settings instead of
  overwriting with defaults (bd-zai)
- bd init detects existing JSONL filename (beads.jsonl vs issues.jsonl)
  when creating new metadata.json
- bd import now correctly reports prefix source ("issues" vs "directory")
- bd import avoids using ".beads" as prefix when run from inside .beads/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 22:57:17 -08:00
Steve Yegge
ff3352ab23 bd-6xd: Standardize on issues.jsonl as canonical filename
- Change default JSONL filename from beads.jsonl to issues.jsonl
- Add bd doctor check and fix to auto-migrate legacy beads.jsonl configs
- Update FindJSONLPath to prefer issues.jsonl over beads.jsonl
- Add CheckLegacyJSONLConfig and CheckLegacyJSONLFilename checks
- Add LegacyJSONLConfig fix to rename files and update config
- Update .gitattributes to reference issues.jsonl
- Fix tests to expect new canonical filename
- Add bd-6xd to v0.25.1 release notes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 22:02:59 -08:00
Kris Hansen
9931ac9bd9 fix: support multi-part prefixes in issue ID extraction (#398) 2025-11-26 17:42:14 -08:00
Steve Yegge
196ce3a6f9 Fix bd-77gm: bd import silently ignores positional arguments
When users forget the -i flag and run 'bd import file.jsonl', the command
would silently read from stdin instead of the file, resulting in '0 created,
0 updated' output that was misleading.

Root cause: The import command doesn't validate positional arguments, so
'bd import file.jsonl' would be interpreted as 'bd import' with an ignored
argument, reading empty stdin.

Fix: Add validation at the start of the import command to detect positional
arguments and show a helpful error message with the correct syntax.

Closes bd-77gm
2025-11-24 01:25:09 -08:00
Steve Yegge
d45cff5085 feat: Handle FOREIGN KEY constraint violations gracefully during import (bd-koab)
When importing JSONL after merges that include deletions, FK constraint
violations can occur if an issue references a deleted issue. Previously,
import would fail completely. Now it continues and reports skipped dependencies.

Changes:
- Add SkippedDependencies field to Result/ImportResult structs
- Update importDependencies() to detect FK violations using IsForeignKeyConstraintError()
- Log warnings for each skipped dependency with issue IDs and type
- Continue importing remaining dependencies instead of failing
- Display summary of all skipped dependencies at end of import

Example output:
  Warning: Skipping dependency due to missing reference: bd-b → bd-a (blocks)

  ⚠️  Warning: Skipped 2 dependencies due to missing references:
    - bd-b → bd-a (blocks)
    - bd-c → bd-a (parent-child)

  This can happen after merges that delete issues referenced by other issues.
  The import continued successfully - you may want to review the skipped dependencies.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 23:32:34 -08:00
Steve Yegge
c9a2e7a8b2 Fix bd-v0y: Remove mtime fast-path in hasJSONLChanged
Git doesn't preserve mtime on checkout, causing false negatives where
hasJSONLChanged() incorrectly returns false after git pull updates JSONL.
This caused bd sync to overwrite pulled JSONL instead of importing it,
resurrecting deleted issues.

Solution: Always compute content hash for comparison (Option 1).
Performance impact is minimal (~10-50ms for sync operations).

Changes:
- cmd/bd/integrity.go: Remove mtime fast-path, always compute hash
- cmd/bd/sync.go: Remove mtime storage after import
- cmd/bd/import.go: Remove mtime storage after import
- cmd/bd/daemon_sync.go: Remove mtime storage and update comments
- cmd/bd/daemon_sync_test.go: Remove mtime assertions from tests

All tests pass. Existing test 'mtime changed but content same - git
operation scenario' verifies the fix works correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 22:53:54 -08:00
Steve Yegge
012bed1068 Fix GH#367: bd import defaulting to stdin is confusing
Changes:
1. Add TTY detection to bd import - prevents silent hang when run
   interactively without arguments. Shows helpful usage message instead.
2. Fix misleading error messages - change "Run 'bd import'" to
   "Run 'bd sync --import-only'" or explicit file path throughout.

Technical details:
- Added golang.org/x/term dependency for IsTerminal()
- When stdin is a TTY and no -i flag: show usage and exit
- When stdin is piped: works as before (supports script pipelines)
- Preserved all legitimate stdin uses:
  * python gh2jsonl.py --repo owner/repo | bd import
  * python md2jsonl.py feature.md | bd import
  * git show HEAD:.beads/beads.jsonl | bd import -i /dev/stdin

Updated error messages in:
- cmd/bd/staleness.go - main "out of sync" error
- cmd/bd/sync.go - merge completion suggestions
- internal/rpc/server_export_import_auto.go - daemon warnings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-23 11:15:34 -08:00
Steve Yegge
b3e76ff1f6 feat: Add sandbox escape hatches for daemon lock issues (GH #353 Phase 1)
Implements three quick fixes for users stuck in sandboxed environments
(e.g., Codex) where daemon cannot be stopped:

1. **--force flag for bd import**
   - Forces metadata update even when DB is synced with JSONL
   - Fixes stuck state caused by stale daemon cache
   - Shows: "Metadata updated (database already in sync with JSONL)"

2. **--allow-stale global flag**
   - Emergency escape hatch to bypass staleness check
   - Shows warning: "⚠️  Staleness check skipped (--allow-stale)"
   - Allows operations on potentially stale data

3. **Improved error message**
   - Added sandbox-specific guidance to staleness error
   - Suggests --sandbox, --force, and --allow-stale flags
   - Provides clear fix steps for different scenarios

Also fixed:
- Removed unused import in cmd/bd/duplicates_test.go

Follow-up work filed:
- bd-u3t: Phase 2 - Sandbox auto-detection
- bd-e0o: Phase 3 - Daemon robustness enhancements
- bd-9nw: Documentation updates

Fixes #353 (Phase 1)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 18:53:34 -05:00
Steve Yegge
0020eb490c Fix bd-khnb: Prevent auto-import from resurrecting deleted issues
Replace mtime-based staleness detection with content-based (SHA256 hash) to prevent
git operations from resurrecting deleted issues.

**Problem:**
Auto-import used file modification time to detect if JSONL was "newer" than database.
Git operations (checkout, merge, pull) restore old files with recent mtimes, causing
auto-import to load stale data over current database state, resurrecting deleted issues.

**Solution:**
- Added computeJSONLHash() to compute SHA256 of JSONL content
- Added hasJSONLChanged() with two-tier check:
  1. Fast-path: Check mtime first (99% of checks are instant)
  2. Slow-path: Compute hash only if mtime changed (catches git operations)
- Store metadata: last_import_hash, last_import_mtime, last_import_time
- Updated auto-import in daemon_sync.go to use content-based check
- Updated validatePreExport to use content-based check (bd-xwo)
- Graceful degradation: metadata failures are non-fatal warnings

**Changes:**
- cmd/bd/integrity.go: Add computeJSONLHash(), hasJSONLChanged()
- cmd/bd/integrity_test.go: Add comprehensive tests for new functions
- cmd/bd/import.go: Update metadata after import
- cmd/bd/sync.go: Use hasJSONLChanged() instead of isJSONLNewer()
- cmd/bd/daemon_sync.go: Use hasJSONLChanged() in auto-import

**Testing:**
- Unit tests pass (TestHasJSONLChanged with 7 scenarios)
- Integration test passes (test_bd_khnb_fix.sh)
- Verified git resurrection scenario prevented

Fixes: bd-khnb
Related: bd-3bg, bd-xwo, bd-39o, bd-56p, bd-m8t, bd-rfj, bd-t5o

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 22:00:20 -05:00
Steve Yegge
57253f93a3 Context propagation with graceful cancellation (bd-rtp, bd-yb8, bd-2o2)
Complete implementation of signal-aware context propagation for graceful
cancellation across all commands and storage operations.

Key changes:

1. Signal-aware contexts (bd-rtp):
   - Added rootCtx/rootCancel in main.go using signal.NotifyContext()
   - Set up in PersistentPreRun, cancelled in PersistentPostRun
   - Daemon uses same pattern in runDaemonLoop()
   - Handles SIGINT/SIGTERM for graceful shutdown

2. Context propagation (bd-yb8):
   - All commands now use rootCtx instead of context.Background()
   - sqlite.New() receives context for cancellable operations
   - Database operations respect context cancellation
   - Storage layer propagates context through all queries

3. Cancellation tests (bd-2o2):
   - Added import_cancellation_test.go with comprehensive tests
   - Added export cancellation test in export_test.go
   - Tests verify database integrity after cancellation
   - All cancellation tests passing

Fixes applied during review:
   - Fixed rootCtx lifecycle (removed premature defer from PersistentPreRun)
   - Fixed test context contamination (reset rootCtx in test cleanup)
   - Fixed export tests missing context setup

Impact:
   - Pressing Ctrl+C during import/export now cancels gracefully
   - No database corruption or hanging transactions
   - Clean shutdown of all operations

Tested:
   - go build ./cmd/bd ✓
   - go test ./cmd/bd -run TestImportCancellation ✓
   - go test ./cmd/bd -run TestExportCommand ✓
   - Manual Ctrl+C testing verified

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 21:57:23 -05:00
Steve Yegge
7b865eb541 Remove legacy issues.jsonl and update defaults to beads.jsonl
Amp-Thread-ID: https://ampcode.com/threads/T-ae11b392-24b5-4060-b431-606dd81c1763
Co-authored-by: Amp <amp@ampcode.com>
2025-11-20 19:00:36 -05:00
Matt Wilkie
4985a6803c Merge branch 'fix-ci-issue-328' into fix-monitor 2025-11-19 15:15:30 -07:00
Charles P. Cross
04a1996fd9 fix: Fix daemon export leaving JSONL newer than database (issues #301, #321)
After daemon auto-export, JSONL mtime could be newer than database mtime
due to SQLite WAL mode not updating beads.db until checkpoint. This caused
validatePreExport to incorrectly block subsequent exports with "JSONL is
newer than database" error, leading to daemon shutdown.

Solution: Call TouchDatabaseFile after all export operations to ensure
database mtime >= JSONL mtime. This prevents false positives in validation
2025-11-19 05:06:12 -05:00
Codex Agent
bf9b2c83fb Annotate gosec-safe file accesses 2025-11-17 10:12:46 -07:00
Steve Yegge
6f7e7fa930 Fix lint errors: handle error return values 2025-11-15 12:52:34 -08:00
Matteo Landi
9dff345e7a Fix: Update DB mtime after import even with 0 changes (#296)
When bd import finds no changes (0 created, 0 updated), it now updates
the database modification timestamp to signal sync validation passed.

This fixes 'bd sync' refusing to export with 'JSONL is newer than database'
error that occurs after git pull updates JSONL mtime without content changes.

Root cause: Import validated DB/JSONL are in sync but didn't update DB mtime,
causing timestamp-based sync validation to perpetually fail.

Amp-Thread-ID: https://ampcode.com/threads/T-560b9c11-e368-45e6-b1e3-512b6d6010a1

Co-authored-by: Amp <amp@ampcode.com>
2025-11-12 10:37:32 -08:00
Steve Yegge
83472aca3d bd sync: 2025-11-09 14:53:59 2025-11-09 14:53:59 -08:00
Steve Yegge
0b28bfec7a Fix bd-17d5: conflict marker false positives on JSON-encoded content
- import.go: Check raw bytes before JSON decoding using bytes.HasPrefix
- validate.go: Use bytes.Split and bytes.HasPrefix on raw data
- Added regression test TestAutoImportConflictMarkerFalsePositive
- Verified with vc-85 issue that triggered the bug

Amp-Thread-ID: https://ampcode.com/threads/T-3f81e22a-14b9-435b-8932-5641aadb7d31
Co-authored-by: Amp <amp@ampcode.com>
2025-11-08 13:09:42 -08:00
Matteo Landi
4bca2067ff fix(import): Update database mtime after import to prevent bd doctor false warnings (#263)
When 'bd sync --import-only' completes, it imports JSONL changes into
the database but doesn't update the database file's modification time.
This causes 'bd doctor' to incorrectly warn that 'JSONL is newer than
database' even when they're in sync.

Root cause: SQLite in WAL mode writes to beads.db-wal; the main beads.db
mtime often doesn't change until a checkpoint. bd doctor compares JSONL
mtime to beads.db mtime, so it can misfire without an mtime bump.

The fix adds touchDatabaseFile() that:
- Only runs when import actually made changes (not dry-run, not unchanged)
- Sets DB mtime to max(JSONL mtime, now) + 1ns to handle clock skew
- Is best-effort (logs warning on failure, doesn't fail import)
- Includes tests for basic touch and clock skew scenarios

Fixes: bd-g3ey
2025-11-08 11:36:05 -08:00
Steve Yegge
9ee45e1971 Auto-invoke 3-way merge for JSONL conflicts (bd-jjua)
When git pull encounters merge conflicts in .beads/beads.jsonl, the
post-merge hook runs 'bd sync --import-only' which previously failed
with an error message pointing users to manual resolution.

This commit adds automatic 3-way merge resolution as a fallback safety
net that works alongside the git merge driver.

Changes:
- Modified conflict detection in import.go to attempt automatic merge
- Added attemptAutoMerge() function that:
  - Extracts git conflict stages (:1 base, :2 ours, :3 theirs)
  - Invokes 'bd merge' command for intelligent field-level merging
  - Writes merged result back and auto-stages the file
  - Restarts import with merged JSONL on success
- Falls back to manual resolution instructions only if auto-merge fails

Defense-in-depth approach:
1. Primary: git merge driver prevents most conflicts during merge
2. Fallback: import auto-merge handles any that slip through

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 03:17:58 -08:00
Steve Yegge
ab4ec900f0 Fix bd import to auto-initialize database when missing
Agents were failing with 'bd import' after nuking the database.
Now bd import automatically:
- Creates .beads/ directory if missing
- Detects prefix from imported issues (analyzes JSONL)
- Falls back to directory name if no issues
- Initializes database before proceeding

This fixes the common agent workflow: rm .beads/beads.db && bd import

Amp-Thread-ID: https://ampcode.com/threads/T-3ace45ce-3cd6-46ae-a201-39c3d7f48f0b
Co-authored-by: Amp <amp@ampcode.com>
2025-11-08 01:52:35 -08:00
Steve Yegge
f72a1d826d Fix bd-u4f5: Add warning when import syncs with working tree but not git HEAD
- Detect uncommitted changes in .beads/issues.jsonl
- Warn users when database matches working tree but differs from git HEAD
- Clarify import status messages (working tree vs git sync)
- Add comprehensive tests for dirty working tree scenarios
- Prevents false confidence about sync status

Amp-Thread-ID: https://ampcode.com/threads/T-5a0f1045-a690-42ef-8bfc-f8cf30ee4084
Co-authored-by: Amp <amp@ampcode.com>
2025-11-08 00:00:43 -08:00
Steve Yegge
95cbcf4fbc Centralize BD_DEBUG logging into internal/debug package
- Created internal/debug package with Enabled(), Logf(), Printf()
- Added comprehensive unit tests for debug package
- Replaced 50+ scattered os.Getenv("BD_DEBUG") checks across 9 files
- Centralized debug logic for easier maintenance and testing
- All tests passing, behavior unchanged

Closes bd-fb95094c.5
2025-11-06 20:14:34 -08:00
Steve Yegge
a0d24f37af Fix bd-1ezg: Prevent import/export from hanging when daemon is running
Root cause: Import and export commands tried to open the database directly
while the daemon already held the lock, causing indefinite blocking.

Solution: Both commands now explicitly close the daemon connection before
opening direct database access, avoiding SQLite lock contention.

Changes:
- import.go: Close daemon connection and open direct SQLite connection
- export.go: Close daemon connection before direct access
- Added debug logging to help diagnose similar issues

Tests: Existing TestImport and TestExport tests pass
2025-11-06 19:07:46 -08:00
Steve Yegge
9de98cf1cb Add --clear-duplicate-external-refs flag to bd import
Fixes GH-234 by providing automatic resolution for duplicate external_ref
values instead of forcing manual JSONL editing.

Changes:
- Add ClearDuplicateExternalRefs option to importer.Options
- Modify validateNoDuplicateExternalRefs to clear duplicates when enabled
- Keep first occurrence, clear rest when flag is set
- Enhanced error message to suggest the flag
- Add comprehensive tests for the new behavior

Usage: bd import -i issues.jsonl --clear-duplicate-external-refs
Amp-Thread-ID: https://ampcode.com/threads/T-932dcf45-76f2-4994-9b5c-a6eb20a86036
Co-authored-by: Amp <amp@ampcode.com>
2025-11-06 13:01:44 -08:00
Steve Yegge
ff8f6ecadf feat(import): add import.orphan_handling config with 4 modes
- Add GetOrphanHandling() helper to SQLiteStorage (reads from config table)
- Add --orphan-handling flag to 'bd import' command
- Wire OrphanHandling through ImportOptions -> importer.Options
- Auto-read config if flag not provided (default: 'allow')
- Document in CONFIG.md with detailed mode explanations

Modes:
- strict: Fail on missing parent (safest)
- resurrect: Auto-create parent tombstones from JSONL
- skip: Skip orphans with warning
- allow: Import without validation (default, most permissive)

Closes bd-8072, bd-b92a

Amp-Thread-ID: https://ampcode.com/threads/T-fd18d4a5-06b3-4400-9073-194d570846d8
Co-authored-by: Amp <amp@ampcode.com>
2025-11-04 23:59:50 -08:00