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 (
"crypto/sha256"
"fmt"
"hash"
"strings"
"time"
)
@@ -86,109 +87,112 @@ type Issue struct {
// to ensure that identical content produces identical hashes across all clones.
func (i *Issue) ComputeContentHash() string {
h := sha256.New()
// Hash all substantive fields in a stable order
h.Write([]byte(i.Title))
h.Write([]byte{0}) // separator
h.Write([]byte(i.Description))
h.Write([]byte{0})
h.Write([]byte(i.Design))
h.Write([]byte{0})
h.Write([]byte(i.AcceptanceCriteria))
h.Write([]byte{0})
h.Write([]byte(i.Notes))
h.Write([]byte{0})
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})
w := hashFieldWriter{h}
if i.ExternalRef != nil {
h.Write([]byte(*i.ExternalRef))
}
h.Write([]byte{0})
if i.Pinned {
h.Write([]byte("pinned"))
}
h.Write([]byte{0})
if i.IsTemplate {
h.Write([]byte("template"))
}
h.Write([]byte{0})
// Hash bonded_from for compound molecules
// Core fields in stable order
w.str(i.Title)
w.str(i.Description)
w.str(i.Design)
w.str(i.AcceptanceCriteria)
w.str(i.Notes)
w.str(string(i.Status))
w.int(i.Priority)
w.str(string(i.IssueType))
w.str(i.Assignee)
w.str(i.CreatedBy)
// Optional fields
w.strPtr(i.ExternalRef)
w.flag(i.Pinned, "pinned")
w.flag(i.IsTemplate, "template")
// Bonded molecules
for _, br := range i.BondedFrom {
h.Write([]byte(br.ProtoID))
h.Write([]byte{0})
h.Write([]byte(br.BondType))
h.Write([]byte{0})
h.Write([]byte(br.BondPoint))
h.Write([]byte{0})
w.str(br.ProtoID)
w.str(br.BondType)
w.str(br.BondPoint)
}
// Hash creator for HOP entity tracking
if i.Creator != nil {
h.Write([]byte(i.Creator.Name))
h.Write([]byte{0})
h.Write([]byte(i.Creator.Platform))
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
// HOP entity tracking
w.entityRef(i.Creator)
// HOP validations
for _, v := range i.Validations {
if v.Validator != nil {
h.Write([]byte(v.Validator.Name))
h.Write([]byte{0})
h.Write([]byte(v.Validator.Platform))
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})
w.entityRef(v.Validator)
w.str(v.Outcome)
w.str(v.Timestamp.Format(time.RFC3339))
w.float32Ptr(v.Score)
}
// Hash gate fields for async coordination
h.Write([]byte(i.AwaitType))
h.Write([]byte{0})
h.Write([]byte(i.AwaitID))
h.Write([]byte{0})
h.Write([]byte(fmt.Sprintf("%d", i.Timeout)))
h.Write([]byte{0})
// Gate fields for async coordination
w.str(i.AwaitType)
w.str(i.AwaitID)
w.duration(i.Timeout)
for _, waiter := range i.Waiters {
h.Write([]byte(waiter))
h.Write([]byte{0})
w.str(waiter)
}
// Hash agent identity fields
h.Write([]byte(i.HookBead))
h.Write([]byte{0})
h.Write([]byte(i.RoleBead))
h.Write([]byte{0})
h.Write([]byte(i.AgentState))
h.Write([]byte{0})
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
// Agent identity fields
w.str(i.HookBead)
w.str(i.RoleBead)
w.str(string(i.AgentState))
w.str(i.RoleType)
w.str(i.Rig)
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)
const DefaultTombstoneTTL = 30 * 24 * time.Hour