feat: add owner field for human attribution in HOP CV chains

Add 'owner' field to Issue struct for tracking the human responsible
for the issue, distinct from 'created_by' which tracks the executor.
Owner is populated from git author email (GIT_AUTHOR_EMAIL or git
config user.email), per Decision 008 for CV accumulation.

Changes:
- Add Owner field to types.Issue with omitempty JSON tag
- Include Owner in content hash computation
- Add owner column migration (036_owner_column.go)
- Update all SQL queries to include owner field
- Add getOwner() helper using git author email fallback chain
- Populate owner in bd create command
- Add owner to RPC CreateArgs protocol

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
2026-01-10 19:28:08 -08:00
committed by Steve Yegge
parent 1039a69186
commit ceb5769c75
13 changed files with 109 additions and 23 deletions

View File

@@ -143,6 +143,27 @@ func getActorWithGit() string {
return "unknown"
}
// getOwner returns the human owner for CV attribution.
// Priority: GIT_AUTHOR_EMAIL env > git config user.email > "" (empty)
// This is the foundation for HOP CV (curriculum vitae) chains per Decision 008.
// Unlike actor (which tracks who executed), owner tracks the human responsible.
func getOwner() string {
// Check GIT_AUTHOR_EMAIL first - this is set during git commit operations
if authorEmail := os.Getenv("GIT_AUTHOR_EMAIL"); authorEmail != "" {
return authorEmail
}
// Fall back to git config user.email - the natural default
if out, err := exec.Command("git", "config", "user.email").Output(); err == nil {
if gitEmail := strings.TrimSpace(string(out)); gitEmail != "" {
return gitEmail
}
}
// Return empty if no email found (owner is optional)
return ""
}
func init() {
// Initialize viper configuration
if err := config.Initialize(); err != nil {