refactor: Extract hashFieldWriter to reduce ComputeContentHash repetition (bd-1tkd)

- Created hashFieldWriter struct with typed helper methods
- Methods: str, int, strPtr, float32Ptr, duration, flag, entityRef
- Reduced ~100 lines of repetitive h.Write() patterns to ~55 lines
- All hash tests pass, output unchanged (backwards compatible)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-28 16:10:09 -08:00
parent e6ff1e89f0
commit 2d92b452c9

View File

@@ -4,6 +4,7 @@ package types
import ( import (
"crypto/sha256" "crypto/sha256"
"fmt" "fmt"
"hash"
"strings" "strings"
"time" "time"
) )
@@ -86,109 +87,112 @@ type Issue struct {
// to ensure that identical content produces identical hashes across all clones. // to ensure that identical content produces identical hashes across all clones.
func (i *Issue) ComputeContentHash() string { func (i *Issue) ComputeContentHash() string {
h := sha256.New() h := sha256.New()
w := hashFieldWriter{h}
// Hash all substantive fields in a stable order // Core fields in stable order
h.Write([]byte(i.Title)) w.str(i.Title)
h.Write([]byte{0}) // separator w.str(i.Description)
h.Write([]byte(i.Description)) w.str(i.Design)
h.Write([]byte{0}) w.str(i.AcceptanceCriteria)
h.Write([]byte(i.Design)) w.str(i.Notes)
h.Write([]byte{0}) w.str(string(i.Status))
h.Write([]byte(i.AcceptanceCriteria)) w.int(i.Priority)
h.Write([]byte{0}) w.str(string(i.IssueType))
h.Write([]byte(i.Notes)) w.str(i.Assignee)
h.Write([]byte{0}) w.str(i.CreatedBy)
h.Write([]byte(i.Status))
h.Write([]byte{0})
h.Write([]byte(fmt.Sprintf("%d", i.Priority)))
h.Write([]byte{0})
h.Write([]byte(i.IssueType))
h.Write([]byte{0})
h.Write([]byte(i.Assignee))
h.Write([]byte{0})
h.Write([]byte(i.CreatedBy))
h.Write([]byte{0})
if i.ExternalRef != nil { // Optional fields
h.Write([]byte(*i.ExternalRef)) w.strPtr(i.ExternalRef)
} w.flag(i.Pinned, "pinned")
h.Write([]byte{0}) w.flag(i.IsTemplate, "template")
if i.Pinned {
h.Write([]byte("pinned")) // Bonded molecules
}
h.Write([]byte{0})
if i.IsTemplate {
h.Write([]byte("template"))
}
h.Write([]byte{0})
// Hash bonded_from for compound molecules
for _, br := range i.BondedFrom { for _, br := range i.BondedFrom {
h.Write([]byte(br.ProtoID)) w.str(br.ProtoID)
h.Write([]byte{0}) w.str(br.BondType)
h.Write([]byte(br.BondType)) w.str(br.BondPoint)
h.Write([]byte{0})
h.Write([]byte(br.BondPoint))
h.Write([]byte{0})
} }
// Hash creator for HOP entity tracking
if i.Creator != nil { // HOP entity tracking
h.Write([]byte(i.Creator.Name)) w.entityRef(i.Creator)
h.Write([]byte{0})
h.Write([]byte(i.Creator.Platform)) // HOP validations
h.Write([]byte{0})
h.Write([]byte(i.Creator.Org))
h.Write([]byte{0})
h.Write([]byte(i.Creator.ID))
h.Write([]byte{0})
}
// Hash validations for HOP proof-of-stake
for _, v := range i.Validations { for _, v := range i.Validations {
if v.Validator != nil { w.entityRef(v.Validator)
h.Write([]byte(v.Validator.Name)) w.str(v.Outcome)
h.Write([]byte{0}) w.str(v.Timestamp.Format(time.RFC3339))
h.Write([]byte(v.Validator.Platform)) w.float32Ptr(v.Score)
h.Write([]byte{0})
h.Write([]byte(v.Validator.Org))
h.Write([]byte{0})
h.Write([]byte(v.Validator.ID))
h.Write([]byte{0})
}
h.Write([]byte(v.Outcome))
h.Write([]byte{0})
h.Write([]byte(v.Timestamp.Format(time.RFC3339)))
h.Write([]byte{0})
if v.Score != nil {
h.Write([]byte(fmt.Sprintf("%f", *v.Score)))
}
h.Write([]byte{0})
} }
// Hash gate fields for async coordination
h.Write([]byte(i.AwaitType)) // Gate fields for async coordination
h.Write([]byte{0}) w.str(i.AwaitType)
h.Write([]byte(i.AwaitID)) w.str(i.AwaitID)
h.Write([]byte{0}) w.duration(i.Timeout)
h.Write([]byte(fmt.Sprintf("%d", i.Timeout)))
h.Write([]byte{0})
for _, waiter := range i.Waiters { for _, waiter := range i.Waiters {
h.Write([]byte(waiter)) w.str(waiter)
h.Write([]byte{0})
} }
// Hash agent identity fields
h.Write([]byte(i.HookBead)) // Agent identity fields
h.Write([]byte{0}) w.str(i.HookBead)
h.Write([]byte(i.RoleBead)) w.str(i.RoleBead)
h.Write([]byte{0}) w.str(string(i.AgentState))
h.Write([]byte(i.AgentState)) w.str(i.RoleType)
h.Write([]byte{0}) w.str(i.Rig)
h.Write([]byte(i.RoleType))
h.Write([]byte{0})
h.Write([]byte(i.Rig))
h.Write([]byte{0})
// Note: LastActivity is a timestamp, excluded from hash like other timestamps
return fmt.Sprintf("%x", h.Sum(nil)) return fmt.Sprintf("%x", h.Sum(nil))
} }
// hashFieldWriter provides helper methods for writing fields to a hash.
// Each method writes the value followed by a null separator for consistency.
type hashFieldWriter struct {
h hash.Hash
}
func (w hashFieldWriter) str(s string) {
w.h.Write([]byte(s))
w.h.Write([]byte{0})
}
func (w hashFieldWriter) int(n int) {
w.h.Write([]byte(fmt.Sprintf("%d", n)))
w.h.Write([]byte{0})
}
func (w hashFieldWriter) strPtr(p *string) {
if p != nil {
w.h.Write([]byte(*p))
}
w.h.Write([]byte{0})
}
func (w hashFieldWriter) float32Ptr(p *float32) {
if p != nil {
w.h.Write([]byte(fmt.Sprintf("%f", *p)))
}
w.h.Write([]byte{0})
}
func (w hashFieldWriter) duration(d time.Duration) {
w.h.Write([]byte(fmt.Sprintf("%d", d)))
w.h.Write([]byte{0})
}
func (w hashFieldWriter) flag(b bool, label string) {
if b {
w.h.Write([]byte(label))
}
w.h.Write([]byte{0})
}
func (w hashFieldWriter) entityRef(e *EntityRef) {
if e != nil {
w.str(e.Name)
w.str(e.Platform)
w.str(e.Org)
w.str(e.ID)
}
}
// DefaultTombstoneTTL is the default time-to-live for tombstones (30 days) // DefaultTombstoneTTL is the default time-to-live for tombstones (30 days)
const DefaultTombstoneTTL = 30 * 24 * time.Hour const DefaultTombstoneTTL = 30 * 24 * time.Hour