worktreecollab

package
v0.175.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package worktreecollab owns the opt-in current owner, participants, and private local inbox for one corroborated worktree. It never changes a Work Log claim or interprets historical owner events as simultaneous owners.

Index

Constants

View Source
const (
	SchemaVersion       = 1
	MaxMessageBodyBytes = 64 << 10
	MaxPendingPerPeer   = 128
	MaxStoredMessages   = 4096
	NoOwner             = "none"
)

Variables

View Source
var ErrConflict = errors.New("worktree coordination conflict")

Functions

This section is empty.

Types

type Checkout

type Checkout struct {
	ID        string `json:"id"`
	Root      string `json:"root"`
	GitDir    string `json:"git_dir"`
	CommonDir string `json:"common_dir"`
}

Checkout binds coordination state to Git's registered worktree identity. Root is presentation/relocation evidence; GitDir and CommonDir identify the linked checkout and canonical repository independently of path aliases.

func (Checkout) Validate

func (checkout Checkout) Validate() error

type InboxView

type InboxView struct {
	Messages []Message    `json:"messages"`
	Notice   *OwnerChange `json:"owner_notice,omitempty"`
}

type Member

type Member struct {
	JoinedAt time.Time `json:"joined_at"`
}

type Message

type Message struct {
	ID         string    `json:"id"`
	Sequence   uint64    `json:"sequence"`
	Sender     string    `json:"sender"`
	Recipient  string    `json:"recipient"`
	Kind       string    `json:"kind"`
	Body       string    `json:"body"`
	Digest     string    `json:"digest"`
	OwnerEpoch uint64    `json:"owner_epoch"`
	RecordedAt time.Time `json:"recorded_at"`
	ConsumedAt time.Time `json:"consumed_at,omitempty"`
}

type ObservedOwner

type ObservedOwner struct {
	ID        string
	SessionID string
	Status    string // live, inactive, or unknown
}

ObservedOwner is an exact observation of legacy custody before the first coordination state is published. ID is opaque when WB cannot bind a live registered session to the historical event.

type OwnerChange

type OwnerChange struct {
	Epoch    uint64    `json:"epoch"`
	Previous string    `json:"previous"`
	Current  string    `json:"current"`
	Actor    string    `json:"actor"`
	Reason   string    `json:"reason,omitempty"`
	Forced   bool      `json:"forced,omitempty"`
	At       time.Time `json:"at"`
}

type Participant

type Participant struct {
	SessionID string    `json:"session_id"`
	JoinedAt  time.Time `json:"joined_at"`
	Live      bool      `json:"live"`
}

type SendReceipt

type SendReceipt struct {
	MessageID  string   `json:"message_id"`
	Sender     string   `json:"sender"`
	Recipients []string `json:"recipients"`
	Kind       string   `json:"kind"`
	Body       string   `json:"body"`
	Digest     string   `json:"digest"`
	OwnerEpoch uint64   `json:"owner_epoch"`
}

type SendRequest

type SendRequest struct {
	Sender         string
	Recipients     []string
	IdempotencyKey string
	MessageID      string
	Kind           string
	Body           string
	At             time.Time
}

type Service

type Service struct {
	Store Store
	Ports ServicePorts
}

func (Service) Ack

func (service Service) Ack(ctx context.Context, idOrPath, messageID string) (uint64, error)

func (Service) Inbox

func (service Service) Inbox(ctx context.Context, idOrPath string) (InboxView, error)

func (Service) Inspect

func (service Service) Inspect(ctx context.Context, idOrPath string) (View, error)

func (Service) Join

func (service Service) Join(ctx context.Context, idOrPath string) (State, error)

func (Service) Leave

func (service Service) Leave(ctx context.Context, idOrPath string) (State, error)

func (Service) Send

func (service Service) Send(ctx context.Context, idOrPath, key string, recipients []string, body string) (SendReceipt, bool, error)

func (Service) Take

func (service Service) Take(ctx context.Context, idOrPath, expected string, force bool, reason string) (State, error)

func (Service) Transfer

func (service Service) Transfer(ctx context.Context, idOrPath, successor string) (State, error)

type ServicePorts

type ServicePorts struct {
	Resolve                    func(context.Context, string) (Checkout, error)
	Caller                     func() (string, error)
	Live                       func(string) (bool, error)
	OwnerStatus                func(string) (string, error) // live, inactive, or unknown
	ObserveLegacy              func(Checkout) (ObservedOwner, error)
	ObserveLegacyForInspection func(Checkout) (ObservedOwner, error)
	Now                        func() time.Time
	NewMessageID               func() (string, error)
}

ServicePorts bind one CLI invocation to a corroborated checkout, its registered ancestor, recipient liveness, and the historical custody store. None of these observations is supplied by an untrusted command argument.

type State

type State struct {
	Version      int                    `json:"version"`
	Checkout     Checkout               `json:"checkout"`
	Revision     uint64                 `json:"revision"`
	Owner        string                 `json:"owner"`
	OwnerEpoch   uint64                 `json:"owner_epoch"`
	Members      map[string]Member      `json:"members"`
	OwnerChanges []OwnerChange          `json:"owner_changes"`
	Notices      map[string]OwnerChange `json:"notices"`
	Inboxes      map[string][]Message   `json:"inboxes"`
	Requests     map[string]SendReceipt `json:"requests"`
	Cursors      map[string]uint64      `json:"cursors"`
}

State is one atomically published private snapshot. Owner notices and audit are separate from ordinary inbox capacity, so a full user inbox cannot prevent a transfer or recovery.

func New

func New(checkout Checkout) (State, error)

func (*State) Ack

func (state *State) Ack(recipient, messageID, messageDigest string, at time.Time) (uint64, error)

func (*State) Inbox

func (state *State) Inbox(recipient string) ([]Message, error)

func (*State) Join

func (state *State) Join(caller string, at time.Time) error

func (*State) Leave

func (state *State) Leave(caller string) error

func (*State) Send

func (state *State) Send(request SendRequest) (SendReceipt, bool, error)

func (*State) Take

func (state *State) Take(request TakeRequest) error

func (*State) Transfer

func (state *State) Transfer(caller, successor string, successorLive bool, at time.Time) error

func (State) Validate

func (state State) Validate(checkout Checkout) error

type Store

type Store struct {
	Home  string
	Ports StorePorts
}

Store keeps one checkout's snapshot under WB's private state directory. A stable per-checkout lock serializes all changes; the lock file is retained so another process cannot acquire a different inode for the same identity.

func NewStore

func NewStore(home string) Store

func (Store) Load

func (store Store) Load(checkout Checkout) (State, bool, error)

Load reads an atomically published snapshot through held private directories. It never creates the home, coordination directory, lock file, or snapshot. Mutations must still use WithLocked and recheck all authority under its lock.

func (Store) WithLocked

func (store Store) WithLocked(ctx context.Context, checkout Checkout, change func(*State, bool) error) (result State, returnErr error)

WithLocked loads, validates, and optionally publishes a snapshot while one cross-process lock is held. The callback must not mutate external authority before it returns: a failed callback never writes coordination state. A missing snapshot is distinct from an initialized but unowned state.

type StorePorts

type StorePorts struct {
	OpenHome  func(string, bool) (*os.File, error)
	OpenChild func(*os.File, string, bool, worktreesecure.ValidSegment) (*os.File, error)
	Read      func(*os.File, string, any) error
	Write     func(*os.File, string, any, os.FileMode) error
	Lock      func(string) lockFile
}

StorePorts are one store invocation's durable boundaries. Callers normally use NewStore; tests can fail a specific boundary without global hooks.

type TakeRequest

type TakeRequest struct {
	Caller        string
	ExpectedOwner string
	Legacy        ObservedOwner
	OwnerStatus   string
	Force         bool
	Reason        string
	At            time.Time
}

type View

type View struct {
	Checkout    Checkout      `json:"checkout"`
	Owner       string        `json:"owner"`
	OwnerStatus string        `json:"owner_status"`
	OwnerEpoch  uint64        `json:"owner_epoch"`
	Joined      []Participant `json:"joined_sessions"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL