Documentation
¶
Overview ¶
Package notebook composes workspaces, Git state, and storage into the safe pull and optimistic commit operations of architecture sections 10-15. It is the only consumer of the storage protocol besides cleanup: Pull reads and validates the authoritative manifest and imports packs; Commit builds proposals, uploads immutable packs before their manifest CAS, and resolves contention, ambiguity, and recovery.
The package consumes narrow consumer-owned interfaces (Workspace and the storage.ObjectStore boundary). All CGo and libgit2 types stay inside internal/git2; the notebook speaks only the git seam.
Index ¶
- Constants
- func LoggerFrom(ctx context.Context) *slog.Logger
- func WithLogger(ctx context.Context, logger *slog.Logger) context.Context
- type BackoffWaiter
- type Code
- type Config
- type ConflictFile
- type Error
- type Failpoints
- type Metrics
- type Notebook
- type RecoveryReport
- type RemoteAccepted
- type Result
- type Workspace
Constants ¶
const ( MaxRetryLimit = 100 MinCheckpointPacks = 1 MaxRetainedCheckpoints = 64 )
MaxRetryLimit, MinCheckpointPacks, and MaxRetainedCheckpoints are the documented operational ranges (architecture section 17). The application package validates its flags against the same values, so the two range checks cannot drift.
const DefaultCheckpointPacks = 1024
DefaultCheckpointPacks is the application-resolved checkpoint threshold: the active tail length that schedules one checkpoint effort.
const DefaultRetainedCheckpoints = 1
DefaultRetainedCheckpoints is the application-resolved retention count: the number of previous checkpoint generations kept in addition to the active generation.
const DefaultRetryLimit = 8
DefaultRetryLimit is the application-resolved CAS retry bound.
const MaxMessageBytes = 16384
MaxMessageBytes is the notes_commit message byte bound (architecture section 2). The MCP schema advertises the same value.
Variables ¶
This section is empty.
Functions ¶
func LoggerFrom ¶
LoggerFrom returns the logger attached by WithLogger, or a discard logger when none is attached. It never returns nil, so callers can log unconditionally.
func WithLogger ¶
WithLogger attaches logger to ctx for notebook background-effort records (checkpoint and cleanup warnings). The MCP layer attaches the request-scoped logger carrying the mcpReqID attribute, so a warning from a best-effort checkpoint or cleanup stays correlated with the tool call that scheduled it.
Types ¶
type BackoffWaiter ¶
BackoffWaiter waits between CAS retries. The notebook resolves the wait policy; tests inject a deterministic waiter so retry bounds are exact.
type Code ¶
type Code string
Code is the stable error taxonomy of notebook operations. The MCP layer maps each code to the structured tool error; the text of an error can change, its code cannot.
const ( // CodeInvalidRequest reports invalid tool input or a state the // operation refuses before any Git or S3 work: a blank commit // message, a commit without a managed pull, or invalid visible // content. CodeInvalidRequest Code = "INVALID_REQUEST" // CodeContentConflict reports a three-tree merge conflict. L is // rewritten with the full materialized result and the exact conflicted // paths and marker ranges are part of the error. CodeContentConflict Code = "CONTENT_CONFLICT" // CodeStorageIntegrity reports stored state that failed validation: // a corrupt pack, a pack that contradicts its descriptor, a missing // object in the accepted history, or a cache that cannot be trusted. CodeStorageIntegrity Code = "STORAGE_INTEGRITY" // CodeStorageFailure reports an object-store operation that failed // without a known accepted result: a pack download or upload, a // manifest read, or a CAS whose acceptance cannot be proved. CodeStorageFailure Code = "STORAGE_FAILURE" // CodeRemoteBusy reports that the CAS lost the configured retry // bound. Visible files are preserved for another attempt. CodeRemoteBusy Code = "REMOTE_BUSY" // CodeRecoveryFailure reports an unexpected failure after local // mutation started. The generic recovery path ran; the error carries // the recovery report. CodeRecoveryFailure Code = "RECOVERY_FAILURE" )
type Config ¶
type Config struct {
// Workspace is the managed visible path.
Workspace Workspace
// Store is the semantic object-store boundary.
Store storage.ObjectStore
// RetryLimit bounds CAS retries after the first attempt.
RetryLimit int
// CheckpointPacks triggers one checkpoint effort when the active tail
// length reaches this count.
CheckpointPacks int
// RetainedCheckpoints keeps this many previous checkpoint generations
// as cleanup roots in addition to the active generation.
RetainedCheckpoints int
// NewID produces protocol publication and checkpoint IDs.
NewID func() (storage.UUID, error)
// Now is the operation-attempt clock for commit timestamps.
Now func() time.Time
// Waiter sleeps between CAS retries; nil uses bounded full-jitter
// exponential backoff. Tests inject a deterministic waiter.
Waiter BackoffWaiter
// Failpoints injects deterministic failures; nil disables injection.
Failpoints *Failpoints
}
Config wires one notebook. RetryLimit is the number of CAS attempts after the first (the application resolves the default; the notebook validates the range 0..100, where 0 means a single attempt). CheckpointPacks is the active-tail length that triggers one checkpoint effort (the application resolves the default 1,024; the notebook requires at least 1, so an explicitly configured zero fails). RetainedCheckpoints is the number of previous checkpoint generations kept as cleanup roots (the application resolves the default 1; the notebook validates 0..64). NewID and Now default to storage.NewUUIDv7 and time.Now; tests inject deterministic sources.
type ConflictFile ¶
type ConflictFile struct {
Path string
Ranges []git.MarkerRange
}
ConflictFile names one conflicted path and the one-based inclusive marker ranges inside it (architecture section 12). A path with no marker range (a file/directory conflict) has an empty Ranges slice.
type Error ¶
type Error struct {
Code Code
Message string
Files []ConflictFile
Recovery *RecoveryReport
Cause error
}
Error is a notebook domain error. Files is present only for CodeContentConflict; Recovery only for CodeRecoveryFailure. Cause keeps the underlying failure for diagnostics and errors.Is.
type Failpoints ¶
type Failpoints struct {
// CAS fires after the manifest CAS accepted the proposal and before
// the local acceptance begins. A failure leaves the remote accepted
// and P/L unadvanced: the exact window the generic recovery path
// repairs, with remote acceptance known to be yes.
CAS func() error
}
Failpoints injects deterministic failures at the notebook orchestration boundaries. A nil hook means no injection. The workspace mutation boundaries keep their own failpoints; the notebook maps their errors to the generic recovery path.
type Metrics ¶
type Metrics struct {
// TailCount is the active increment count of the last observed
// authoritative manifest. Retained tails do not count.
TailCount atomic.Uint64
// TailBytes is the sum of the active increment pack sizes of the last
// observed authoritative manifest.
TailBytes atomic.Uint64
// CheckpointRuns counts scheduled checkpoint efforts.
CheckpointRuns atomic.Uint64
// CheckpointFailures counts checkpoint efforts that ended without a
// successful manifest replacement. The failure never changes an
// already accepted commit result.
CheckpointFailures atomic.Uint64
// CheckpointCASAttempts counts manifest CAS attempts by checkpoint
// workers.
CheckpointCASAttempts atomic.Uint64
// CheckpointSize is the byte size of the last successfully indexed
// checkpoint pack.
CheckpointSize atomic.Uint64
// CheckpointDurationNanos is the wall duration of the last successful
// checkpoint effort, from selection to manifest acceptance.
CheckpointDurationNanos atomic.Int64
// CleanupRuns counts cleanup runs after a successful checkpoint CAS.
CleanupRuns atomic.Uint64
// CleanupCandidates counts listed pack keys at or before the cleanup
// cutoff.
CleanupCandidates atomic.Uint64
// CleanupDeleted counts pack keys deleted by cleanup.
CleanupDeleted atomic.Uint64
// CleanupErrors counts failed delete batches and aborted cleanup
// runs. A failed batch may have deleted part of its keys; the
// semantic boundary cannot name them, so the error is recorded at
// batch granularity and retried on a later checkpoint cleanup.
CleanupErrors atomic.Uint64
}
Metrics exposes the operational measurements of architecture sections 13 and 16: the active tail shape, checkpoint efforts, and cleanup results. The notebook records every value; tests read them and a later MCP or observability layer can sample them. Values are monotonic counters or last-value gauges, safe for concurrent use.
type Notebook ¶
type Notebook struct {
// contains filtered or unexported fields
}
Notebook executes pull and commit against one workspace and one store. All methods are safe for concurrent use; per-path serialization comes from the workspace operation lock. Checkpoint scheduling is opportunistic and never determines commit success (architecture section 13).
func (*Notebook) Commit ¶
Commit publishes the caller's changes and incorporates concurrent, non-conflicting changes (architecture section 11). It requires a non-blank message and a managed pull, validates every visible file and rejects complete conflict-marker blocks before any Git or S3 work, then merges the accepted baseline, L, and R. A clean result creates a commit whose parent is the observed R head (or none for the first publication), uploads one immutable pack before its manifest CAS, and rewrites L and P to the accepted state only after acceptance is proved. A CAS loss imports the new remote tail, merges again, and retries with a new publication ID, generation, key, commit, and pack up to the configured bound. A no-change result synchronizes L and P to R without any remote mutation.
The returned Result reports the accepted generation and the diffstat of the published increment: the observed remote parent tree versus the accepted merged tree. A no-op commit returns the remote generation with an empty stat. A conflict or any error returns the zero Result with the existing error.
func (*Notebook) Pull ¶
Pull validates and ingests the visible directory, reads and validates the authoritative manifest, downloads only missing packs, imports the accepted state, and merges the accepted baseline, L, and R (architecture section 10). L is rewritten with the full merge result and R becomes the new baseline. A conflicting pull writes the markers and non-conflicting results to L, records R as the baseline, and returns the exact conflicted paths and ranges; it never reverts L.
The returned Result reports the accepted remote generation and the diffstat of the on-disk delta between the visible state the pull observed and the materialized result. A conflict or any error returns the zero Result with the existing error.
type RecoveryReport ¶
type RecoveryReport struct {
Stage string
RemoteAccepted RemoteAccepted
Resynchronized bool
}
RecoveryReport describes one generic recovery run (architecture section 15): the failed stage, whether remote acceptance is known, and whether resynchronization from authoritative current succeeded.
type RemoteAccepted ¶
type RemoteAccepted string
RemoteAccepted is the recovery report's statement about remote acceptance: the proposal landed, never landed, or cannot be proved.
const ( RemoteAcceptedYes RemoteAccepted = "yes" RemoteAcceptedNo RemoteAccepted = "no" RemoteAcceptedUnknown RemoteAccepted = "unknown" )
type Result ¶ added in v0.1.4
Result is the success summary of one pull or commit: the accepted remote generation after the operation and the per-file line-change diffstat of what the operation changed. Pull reports the delta between the visible state it observed and the materialized result; commit reports the increment the publication added over the observed remote parent tree, empty for a no-op synchronization. The zero Result is always paired with a non-nil error; consumers read Result only when err is nil.
type Workspace ¶
type Workspace interface {
Snapshot(ctx context.Context) (git.Snapshot, error)
Baseline() workspace.Baseline
Repo() git.Repository
Accept(ctx context.Context, baseline workspace.Baseline) error
Materialize(ctx context.Context, baseline workspace.Baseline, tree git.OID) error
Recover(ctx context.Context, baseline workspace.Baseline) error
RecoveryRequired() bool
CacheDir() string
Pulled() bool
MarkPulled(ctx context.Context) error
}
Workspace is the notebook's narrow view of a managed visible path. The interface is consumer-owned and path-free: the notebook never touches the caller's path directly, only the workspace's locked operations. The real implementation is internal/workspace.Workspace; tests use the real workspace over a fake engine, so only the Git engine and the object store are ever faked.