Documentation
¶
Overview ¶
Package toolsnap captures ephemeral workspace snapshots around agent-executed tool windows. Snapshots are Git trees stored in an isolated bare object store under .semantica, with the user repository's object database as a read-only alternate. The user repository's objects and refs are never modified.
Index ¶
- Constants
- Variables
- func GroupPostRef(worktreeID, groupID string) string
- func SnapshotRef(worktreeID, groupID, toolUseID string) string
- type Actor
- type CaptureResult
- type CompletionInfo
- type Delta
- type FileChange
- type FileDelta
- type FinalizeResult
- type GroupFinal
- type GroupMeta
- type Hunk
- type Limits
- type MaintenanceReport
- type PartialError
- type PendingFinalization
- type PendingPartialRecord
- type PendingToolSnapshot
- type ReclaimedGroup
- type Registry
- func (r *Registry) Begin(ctx context.Context, entry PendingToolSnapshot) (string, error)
- func (r *Registry) CaptureAndBegin(ctx context.Context, s *Store, key ToolKey, toolName string, startedAt int64) (PendingToolSnapshot, error)
- func (r *Registry) Complete(ctx context.Context, key ToolKey, info CompletionInfo, ...) (bool, error)
- func (r *Registry) HasTombstone(key ToolKey) (bool, error)
- func (r *Registry) ListTombstones() (tombs []Tombstone, malformed []string, err error)
- func (r *Registry) LoadOrRecordPendingPartial(rec PendingPartialRecord) (PendingPartialRecord, error)
- func (r *Registry) PendingFinalizations(ctx context.Context) ([]PendingFinalization, error)
- func (r *Registry) PendingPartialRecords() ([]PendingPartialRecord, error)
- func (r *Registry) ReclaimSealedGroups(ctx context.Context, now int64) ([]ReclaimedGroup, error)
- func (r *Registry) RemoveGroup(ctx context.Context, groupID string) error
- func (r *Registry) RemovePendingPartial(eventID string) error
- func (r *Registry) RemoveTombstone(key ToolKey) error
- func (r *Registry) ResumeFinalization(ctx context.Context, groupID string, ...) (bool, error)
- func (r *Registry) Stale(ctx context.Context, cutoff int64) ([]PendingToolSnapshot, error)
- func (r *Registry) WriteTombstone(key ToolKey, at int64) error
- type RegistrySnapshot
- type RepoContext
- type Snapshot
- type Store
- func (s *Store) CaptureAfter(ctx context.Context, before Snapshot) (CaptureResult, error)
- func (s *Store) CaptureBefore(ctx context.Context) (Snapshot, error)
- func (s *Store) CreateRef(ctx context.Context, ref, tree string) error
- func (s *Store) DeleteRef(ctx context.Context, ref, expectedTree string) error
- func (s *Store) DeltaBetweenTrees(ctx context.Context, beforeTree, afterTree string) ([]FileDelta, int64, bool, error)
- func (s *Store) DiffTrees(ctx context.Context, beforeTree, afterTree string) ([]FileChange, error)
- func (s *Store) EnsureRef(ctx context.Context, ref, tree string) error
- func (s *Store) ListRefs(ctx context.Context) (map[string]string, error)
- func (s *Store) Maintain(ctx context.Context, reg *Registry, grace time.Duration) (MaintenanceReport, error)
- func (s *Store) ReadBlob(ctx context.Context, hash string) ([]byte, error)
- func (s *Store) WorktreeID() string
- type Tombstone
- type ToolKey
- type ToolUse
- type Window
Constants ¶
const ( // DefaultMaxCandidatePaths bounds nominated paths per snapshot. DefaultMaxCandidatePaths = 5000 // DefaultMaxBytesRead bounds newly read file content per snapshot. DefaultMaxBytesRead = 128 << 20 )
Default capture limits bound per-snapshot work and storage.
const ( ReasonFileLimit = "file_limit" ReasonByteLimit = "byte_limit" ReasonUnsupportedPath = "unsupported_path" ReasonMalformedStatus = "malformed_status" ReasonHeadChanged = "head_changed" ReasonAlternateGone = "alternate_object_missing" ReasonTimeout = "timeout" ReasonLockTimeout = "registry_lock_timeout" // ReasonPostSnapshotLost marks a retry without durable post state. ReasonPostSnapshotLost = "post_snapshot_lost" // ReasonStaleActiveWindow marks evidence from a sealed group. // Its unbounded span contributes no attribution. ReasonStaleActiveWindow = "stale_active_window" )
Partial reason strings are persisted and must remain stable.
const DefaultPruneGrace = DefaultStaleWindowAge
DefaultPruneGrace protects objects for at least the pending-snapshot period.
const DefaultStaleActiveAge = time.Hour
DefaultStaleActiveAge bounds a group's join horizon. Later completions produce partial evidence.
const DefaultStaleWindowAge = 24 * time.Hour
DefaultStaleWindowAge is the retention period for pending snapshots.
const DeltaVersion = 1
DeltaVersion is the canonical tool-delta schema version.
Variables ¶
var ErrNoPendingSnapshot = errors.New("toolsnap: no pending snapshot for key")
ErrNoPendingSnapshot reports a post hook without a matching registered window; callers degrade to pre_snapshot_missing.
var ErrRegistryCorrupt = errors.New("toolsnap: registry state corrupt")
ErrRegistryCorrupt reports invalid persisted window or final state.
var ErrStoreIncompatible = errors.New("toolsnap: snapshot store incompatible with repository")
ErrStoreIncompatible reports an object-format mismatch between the snapshot store and repository.
var ErrWindowSealed = errors.New("toolsnap: window group sealed")
ErrWindowSealed reports a post hook for a sealed group.
var ErrWindowTombstoned = errors.New("toolsnap: window tombstoned")
ErrWindowTombstoned reports a post hook for an abandoned window.
Functions ¶
func GroupPostRef ¶
GroupPostRef returns the ref that protects a group's post tree.
func SnapshotRef ¶
SnapshotRef returns the private pre-snapshot ref for a tool window.
Types ¶
type CaptureResult ¶
CaptureResult contains a post-tool snapshot and its bounded delta.
type CompletionInfo ¶
CompletionInfo carries what a post hook knows about its member at completion time.
type Delta ¶
type Delta struct {
Version int `json:"version"`
Kind string `json:"kind"`
Scope string `json:"scope"` // "tool" or "concurrent_group"
Status string `json:"status"` // "complete" or "partial"
Reason string `json:"reason,omitempty"`
Window Window `json:"window"`
Actors []Actor `json:"actors"`
ToolUses []ToolUse `json:"tool_uses"`
Files []FileDelta `json:"files"`
Limits Limits `json:"limits"`
}
Delta is canonical evidence for one tool window or concurrency group. Equivalent values serialize identically for content addressing.
func ParseDelta ¶
ParseDelta accepts only the canonical encoding for this schema version.
func (*Delta) CanonicalBytes ¶
CanonicalBytes validates, normalizes, and serializes the delta.
type FileChange ¶
type FileChange struct {
Path string
Op byte // A, D, M, T (typechange)
BeforeMode string
AfterMode string
BeforeHash string
AfterHash string
}
FileChange is one raw tree-level difference between two snapshots. Only path, mode, and object identity come from Git; content loading, binary detection, and line diffing happen under Semantica's own versioned rules so repository diff configuration can never shape evidence.
type FileDelta ¶
type FileDelta struct {
Path string `json:"path"`
Operation string `json:"operation"` // create, edit, delete, typechange
BeforeHash string `json:"before_hash"`
AfterHash string `json:"after_hash"`
BeforeMode string `json:"before_mode"`
AfterMode string `json:"after_mode"`
Binary bool `json:"binary,omitempty"`
Truncated bool `json:"truncated,omitempty"`
OldNoEOFNewline bool `json:"old_no_eof_newline,omitempty"`
NewNoEOFNewline bool `json:"new_no_eof_newline,omitempty"`
Hunks []Hunk `json:"hunks,omitempty"`
}
FileDelta records one file change. Modes are Git octal strings. Binary and truncated files carry file-level evidence without hunks.
type FinalizeResult ¶
type FinalizeResult struct {
// Done means the group's evidence is fully durable; the group is
// removed in the same registry transaction.
Done bool
// Final preserves captured state for retry. A zero value requires
// deterministic partial evidence instead of another workspace read.
Final GroupFinal
}
FinalizeResult is the outcome of one finalization attempt.
type GroupFinal ¶
type GroupFinal struct {
// PostTreeHash identifies the final workspace tree. The caller
// must have made it reachable (post ref) before returning it.
PostTreeHash string `json:"post_tree_hash,omitempty"`
// DeltaHash identifies the canonical delta when it was computed.
DeltaHash string `json:"delta_hash,omitempty"`
// PartialReason marks a group whose final capture is permanently
// unavailable; retries finalize deterministic partial evidence.
PartialReason string `json:"partial_reason,omitempty"`
CapturedAt int64 `json:"captured_at,omitempty"`
}
GroupFinal preserves a group's closing state across finalization retries.
type GroupMeta ¶
type GroupMeta struct {
CreatedAt int64 `json:"created_at"`
JoinUntil int64 `json:"join_until"`
// Sealed groups accept no members and produce only partial evidence.
Sealed bool `json:"sealed,omitempty"`
}
GroupMeta records an immutable join horizon and seal state.
type Hunk ¶
type Hunk struct {
OldStart int `json:"old_start"`
OldCount int `json:"old_count"`
NewStart int `json:"new_start"`
NewCount int `json:"new_count"`
OldLines []string `json:"old_lines"`
NewLines []string `json:"new_lines"`
}
Hunk is a contiguous, context-free change between two text blobs. Lines omit trailing newlines, and positions are 1-based.
type MaintenanceReport ¶
type MaintenanceReport struct {
// Deferred reports an incomplete pass. Counters include completed work.
Deferred bool
ActiveWindows int
RefsDeleted int
RefsKept int
MarkersPruned int
PruneRan bool
// StoreBytes is the store object size after the pass.
StoreBytes int64
}
MaintenanceReport describes one maintenance pass.
type PartialError ¶
PartialError reports a capture that must degrade to partial evidence with a stable reason instead of guessing.
func (*PartialError) Error ¶
func (e *PartialError) Error() string
type PendingFinalization ¶
type PendingFinalization struct {
GroupID string
Members []PendingToolSnapshot
Final *GroupFinal
}
PendingFinalization is a group whose members are all complete but whose finalization has not durably finished.
type PendingPartialRecord ¶
type PendingPartialRecord struct {
Key ToolKey `json:"key"`
EventID string `json:"event_id"`
Reason string `json:"reason"`
ToolName string `json:"tool_name"`
CommandSummary string `json:"command_summary,omitempty"`
Timestamp int64 `json:"timestamp"`
}
PendingPartialRecord preserves canonical inputs for a groupless partial. Retries rebuild evidence from this record instead of a reparsed hook.
type PendingToolSnapshot ¶
type PendingToolSnapshot struct {
Key ToolKey `json:"key"`
ToolName string `json:"tool_name"`
SnapshotRef string `json:"snapshot_ref"`
TreeHash string `json:"tree_hash"`
HeadHash string `json:"head_hash"`
ObjectFormat string `json:"object_format"`
StartedAt int64 `json:"started_at"`
CompletedAt int64 `json:"completed_at,omitempty"`
// Seq is the registry-local capture order. Wall clocks can
// collide within a millisecond; the sequence, assigned under the
// lock, identifies the earliest captured snapshot.
Seq int64 `json:"seq"`
// EventID and CommandSummary are recorded at completion so group
// closure can link and describe every member without loading its
// event.
EventID string `json:"event_id,omitempty"`
CommandSummary string `json:"command_summary,omitempty"`
GroupID string `json:"group_id"`
Status string `json:"status"` // "active" or "complete"
}
PendingToolSnapshot is one registered tool window.
type ReclaimedGroup ¶
type ReclaimedGroup struct {
GroupID string
// Completed members converted to pending partials.
Completed int
// Tombstoned member identities.
Tombstoned int
}
ReclaimedGroup summarizes one removed sealed group.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry coordinates repository-scoped tool windows across hook processes.
func OpenRegistry ¶
OpenRegistry prepares the registry directories under semDir.
func (*Registry) Begin ¶
Begin registers a pre-existing snapshot. Hook callers use CaptureAndBegin so capture and registration share one lock.
func (*Registry) CaptureAndBegin ¶
func (r *Registry) CaptureAndBegin(ctx context.Context, s *Store, key ToolKey, toolName string, startedAt int64) (PendingToolSnapshot, error)
CaptureAndBegin captures and registers a pre-tool snapshot while holding the registry lock. Duplicate deliveries reuse the existing entry.
func (*Registry) Complete ¶
func (r *Registry) Complete(ctx context.Context, key ToolKey, info CompletionInfo, persistMember func(PendingToolSnapshot) error, finalize func(members []PendingToolSnapshot, prior *GroupFinal, retry bool, recordIntent func() error) (FinalizeResult, error)) (bool, error)
Complete persists a member and finalizes its group in capture order. Retries must use durable state rather than recapturing the workspace.
func (*Registry) HasTombstone ¶
HasTombstone reports whether a window is ineligible. Probe errors fail closed.
func (*Registry) ListTombstones ¶
ListTombstones returns valid records and the names of malformed entries. Each record must match its filename identity.
func (*Registry) LoadOrRecordPendingPartial ¶
func (r *Registry) LoadOrRecordPendingPartial(rec PendingPartialRecord) (PendingPartialRecord, error)
LoadOrRecordPendingPartial creates or returns an event's first record. Existing records are validated before use.
func (*Registry) PendingFinalizations ¶
func (r *Registry) PendingFinalizations(ctx context.Context) ([]PendingFinalization, error)
PendingFinalizations lists complete groups awaiting finalization.
func (*Registry) PendingPartialRecords ¶
func (r *Registry) PendingPartialRecords() ([]PendingPartialRecord, error)
PendingPartialRecords lists the records for recovery sweeps.
func (*Registry) ReclaimSealedGroups ¶
ReclaimSealedGroups records partial evidence, tombstones every member, and removes sealed groups. Recovery writes occur outside the registry lock. Removal revalidates the captured member state before publication.
func (*Registry) RemoveGroup ¶
RemoveGroup deletes stale group members and their pending final identity.
func (*Registry) RemovePendingPartial ¶
RemovePendingPartial deletes a recovery record after its link is durable.
func (*Registry) RemoveTombstone ¶
RemoveTombstone deletes a tombstone after its partial evidence is durable.
func (*Registry) ResumeFinalization ¶
func (r *Registry) ResumeFinalization(ctx context.Context, groupID string, finalize func(members []PendingToolSnapshot, prior *GroupFinal, retry bool, recordIntent func() error) (FinalizeResult, error)) (bool, error)
ResumeFinalization retries a complete group from durable state.
type RegistrySnapshot ¶
type RegistrySnapshot struct {
// Exists reports whether the registry directory is present.
Exists bool
Windows []PendingToolSnapshot
Groups map[string]GroupMeta
Finals map[string]GroupFinal
Partials []PendingPartialRecord
Tombstones []Tombstone
MalformedTombstones []string
}
RegistrySnapshot is a read-only view used by diagnostics and dry runs.
func InspectRegistry ¶
func InspectRegistry(semDir string) (RegistrySnapshot, error)
InspectRegistry validates registry state and overlays receipts in memory. It does not create, consume, or publish files.
func (RegistrySnapshot) CompleteGroups ¶
func (s RegistrySnapshot) CompleteGroups() []PendingFinalization
CompleteGroups returns groups whose members are all complete.
type RepoContext ¶
type RepoContext struct {
// WorktreeRoot is the top-level directory of the active worktree.
WorktreeRoot string
// GitDir is the worktree's git directory (per-worktree for linked
// worktrees).
GitDir string
// CommonDir is the shared git directory holding the object database.
CommonDir string
// ObjectFormat is "sha1" or "sha256".
ObjectFormat string
// WorktreeID is a stable identifier for this worktree, used to
// namespace snapshot refs.
WorktreeID string
// HeadCommit and HeadTree are resolved with the same rev-parse
// invocation when HEAD exists; both are empty on an unborn branch.
// The values can go stale before capture reads the worktree, so
// CaptureBefore cross-checks them against the branch.oid reported
// by status and degrades to partial on mismatch.
HeadCommit string
HeadTree string
}
RepoContext identifies the worktree and object database a snapshot operates against. All paths are absolute and symlink-canonicalized.
func ResolveRepoContext ¶
func ResolveRepoContext(ctx context.Context, dir string) (RepoContext, error)
ResolveRepoContext discovers the repository context for the given directory. It fails on bare repositories: snapshots capture worktree state, so a worktree is required.
type Store ¶
type Store struct {
// Dir is the bare store's git directory.
Dir string
// MaxCandidatePaths and MaxBytesRead bound one snapshot; zero
// values apply the package defaults.
MaxCandidatePaths int
MaxBytesRead int64
// contains filtered or unexported fields
}
Store is the isolated bare Git object store holding ephemeral snapshot trees. It reads the user repository's objects through a read-only alternate but never writes to them.
func OpenStore ¶
OpenStore opens or initializes the isolated snapshot store for the repository, wiring the repository's common object directory as a read-only alternate. semDir is the repository's .semantica directory.
func (*Store) CaptureAfter ¶
CaptureAfter compares the post-tool workspace with a prior snapshot. Capture limits and unavailable evidence return typed partial errors.
func (*Store) CaptureBefore ¶
CaptureBefore builds a workspace tree from HEAD and current changes. Unchanged subtrees retain their existing object IDs.
func (*Store) CreateRef ¶
CreateRef atomically publishes a tree ref without replacing an existing ref.
func (*Store) DeltaBetweenTrees ¶
func (s *Store) DeltaBetweenTrees(ctx context.Context, beforeTree, afterTree string) ([]FileDelta, int64, bool, error)
DeltaBetweenTrees computes bounded file deltas between captured trees.
func (*Store) DiffTrees ¶
DiffTrees compares two snapshot trees with fixed raw plumbing. Renames are never inferred; a rename appears as delete plus create. Git patch output is never consulted.
func (*Store) Maintain ¶
func (s *Store) Maintain(ctx context.Context, reg *Registry, grace time.Duration) (MaintenanceReport, error)
Maintain removes stale refs and prunes expired objects from the isolated store. It holds the registry lock and defers while capture is active.
func (*Store) ReadBlob ¶
ReadBlob loads blob content from the store, resolving through the repository alternate when the blob belongs to a committed tree.
func (*Store) WorktreeID ¶
WorktreeID returns the store's worktree identity.
type ToolKey ¶
type ToolKey struct {
RepositoryID string `json:"repository_id"`
Provider string `json:"provider"`
SessionID string `json:"session_id"`
TurnID string `json:"turn_id"`
ToolUseID string `json:"tool_use_id"`
}
ToolKey identifies a tool window. Only hook events enter the registry.