Use sha256-based deterministic block IDs

- NextBlockID now uses sha256(sessionID:agentID:counter)[:8] for deterministic,
  collision-resistant block IDs across sessions and agents
- Remove blockCounter reset on Clear() to maintain ID stability
This commit is contained in:
Levi Neely 2026-10-09 17:01:22 +02:00
parent 5f67d44e27
commit c186c87525
2 changed files with 15 additions and 6 deletions

View File

@ -77,7 +77,7 @@ type Agent struct {
chatSignalMu sync.Mutex chatSignalMu sync.Mutex
chatSignalCh chan struct{} // closed on new chat data; replaced with fresh channel chatSignalCh chan struct{} // closed on new chat data; replaced with fresh channel
plan []byte // agent's plan file contents plan []byte // agent's plan file contents
blockCounter uint64 // monotonic counter for generating stable block IDs blockCounter uint64 // monotonic counter for block ID generation
} }
// Backend returns the active backend from the runtime. // Backend returns the active backend from the runtime.
@ -316,7 +316,6 @@ func (ag *Agent) Clear() error {
ag.chatLog = nil ag.chatLog = nil
ag.chatStart = 0 ag.chatStart = 0
ag.chatVers++ ag.chatVers++
ag.blockCounter = 0
ag.chatMu.Unlock() ag.chatMu.Unlock()
ag.chatCond.Broadcast() ag.chatCond.Broadcast()
if ag.onClear != nil { if ag.onClear != nil {

View File

@ -8,6 +8,8 @@ package agent
import ( import (
"bytes" "bytes"
"crypto/sha256"
"encoding/hex"
"fmt" "fmt"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -17,11 +19,19 @@ import (
const maxChatLogBytes = 16 * 1024 * 1024 const maxChatLogBytes = 16 * 1024 * 1024
// NextBlockID returns the next block ID and increments the counter. // NextBlockID returns the next deterministic block ID and increments the counter.
// Block IDs are sequential integers formatted as hex strings. // Block IDs are sha256(sessionID + agentID + counter)[:8] — deterministic given
// the same session, agent, and sequence. Counter starts at 0 for fresh agents,
// or at the replayed block count after session restore.
func (ag *Agent) NextBlockID() string { func (ag *Agent) NextBlockID() string {
id := atomic.AddUint64(&ag.blockCounter, 1) - 1 n := atomic.AddUint64(&ag.blockCounter, 1) - 1
return fmt.Sprintf("%x", id) h := sha256.New()
h.Write([]byte(ag.sessionID))
h.Write([]byte(":"))
h.Write([]byte(ag.id))
h.Write([]byte(":"))
h.Write([]byte(fmt.Sprintf("%d", n)))
return hex.EncodeToString(h.Sum(nil))[:8]
} }
// AppendChat appends data to the chat log and notifies stream readers. // AppendChat appends data to the chat log and notifies stream readers.