feat: add session_id field to issue close/update mutations (bd-tksk)

Adds closed_by_session tracking for entity CV building per Gas Town
decision 009-session-events-architecture.md.

Changes:
- Add ClosedBySession field to Issue struct
- Add closed_by_session column to issues table (migration 034)
- Add --session flag to bd close command
- Support CLAUDE_SESSION_ID env var as fallback
- Add --session flag to bd update for status=closed
- Display closed_by_session in bd show output
- Update Storage interface to include session parameter in CloseIssue

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

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

Executed-By: beads/crew/dave
Rig: beads
Role: crew
This commit is contained in:
beads/crew/dave
2025-12-31 13:13:49 -08:00
committed by Steve Yegge
parent 7c9b975436
commit b362b36824
42 changed files with 165 additions and 82 deletions

View File

@@ -515,7 +515,7 @@ func TestDeepHierarchyBlocking(t *testing.T) {
}
// Now close the blocker and verify all levels become ready
store.CloseIssue(ctx, blocker.ID, "Done", "test-user")
store.CloseIssue(ctx, blocker.ID, "Done", "test-user", "")
ready, err = store.GetReadyWork(ctx, types.WorkFilter{Status: types.StatusOpen})
if err != nil {
@@ -564,7 +564,7 @@ func TestGetReadyWorkIncludesInProgress(t *testing.T) {
store.UpdateIssue(ctx, issue3.ID, map[string]interface{}{"status": types.StatusInProgress}, "test-user")
store.CreateIssue(ctx, issue4, "test-user")
store.CreateIssue(ctx, issue5, "test-user")
store.CloseIssue(ctx, issue5.ID, "Done", "test-user")
store.CloseIssue(ctx, issue5.ID, "Done", "test-user", "")
// Add dependency: issue3 blocks on issue4
store.AddDependency(ctx, &types.Dependency{IssueID: issue3.ID, DependsOnID: issue4.ID, Type: types.DepBlocks}, "test-user")
@@ -1018,7 +1018,7 @@ func TestGetReadyWorkExternalDeps(t *testing.T) {
}
// Close the capability issue
if err := externalStore.CloseIssue(ctx, capabilityIssue.ID, "Shipped", "test-user"); err != nil {
if err := externalStore.CloseIssue(ctx, capabilityIssue.ID, "Shipped", "test-user", ""); err != nil {
t.Fatalf("failed to close capability issue: %v", err)
}
@@ -1246,7 +1246,7 @@ func TestGetBlockedIssuesFiltersExternalDeps(t *testing.T) {
}
// Close the capability issue
if err := externalStore.CloseIssue(ctx, capabilityIssue.ID, "Shipped", "test-user"); err != nil {
if err := externalStore.CloseIssue(ctx, capabilityIssue.ID, "Shipped", "test-user", ""); err != nil {
t.Fatalf("failed to close capability issue: %v", err)
}
@@ -1371,7 +1371,7 @@ func TestGetBlockedIssuesPartialExternalDeps(t *testing.T) {
if err := externalStore.AddLabel(ctx, cap1Issue.ID, "provides:cap1", "test-user"); err != nil {
t.Fatalf("failed to add provides label: %v", err)
}
if err := externalStore.CloseIssue(ctx, cap1Issue.ID, "Shipped", "test-user"); err != nil {
if err := externalStore.CloseIssue(ctx, cap1Issue.ID, "Shipped", "test-user", ""); err != nil {
t.Fatalf("failed to close cap1 issue: %v", err)
}