Documentation
¶
Overview ¶
Package store implements the persistent memory engine for Engram.
It uses SQLite with FTS5 full-text search to store and retrieve observations from AI coding sessions. This is the core of Engram — everything else (HTTP server, MCP server, CLI, plugins) talks to this.
Index ¶
- Constants
- Variables
- func ClassifyTool(toolName string) string
- func EnsureInstanceID(dataDir string) (string, error)
- func ExtractLearnings(text string) []string
- func NormalizeProject(project string) (normalized string, warning string)
- func Now() string
- func SuggestTopicKey(typ, title, content string) string
- func ValidateCloudSessionDirectory(raw []byte) error
- func ValidateExpectedProject(expected string) (string, error)
- func ValidateObservationTitle(title string) error
- type AddObservationParams
- type AddObservationResult
- type AddPromptParams
- type BackupRelation
- type Candidate
- type CandidateOptions
- type CandidateTimings
- type CloudSyncSummary
- type CloudUpgradeLegacyMutationFinding
- type CloudUpgradeLegacyMutationReport
- type CloudUpgradeRepairReport
- type CloudUpgradeSnapshot
- type CloudUpgradeState
- type Config
- type ContextOptions
- type DeferredRow
- type DeleteProjectResult
- type DiagnosticSessionEvidence
- type EnrolledProject
- type ExplicitProjectMergePreview
- type ExportData
- type ForeignSyncTargetCleanupAction
- type ForeignSyncTargetCleanupReport
- type ImportResult
- type InvalidSessionIdentityEvidence
- type JudgeBySemanticParams
- type JudgeRelationParams
- type LegacyEmptyPromptDiscardBlocker
- type LegacyEmptyPromptDiscardPlan
- type LegacyEmptyPromptDiscardResult
- type ListDeferredOptions
- type ListRelationsOptions
- type MergeResult
- type MigrateResult
- type NetworkFilesystemError
- type Observation
- type ObservationRelations
- type ObservationRequiredFieldsEvidence
- type ObservationSnippet
- type ObservationSourceTitleRepairAction
- type ObservationSourceTitleRepairReport
- type ObservationVersion
- type ObservationVersionPage
- type OrphanedObservationSessionEvidence
- type OrphanedPendingRelationEvidence
- type OrphanedPendingRelationEvidenceBounded
- type OrphanedPendingRelationEvidenceReport
- type OrphanedPendingRelationReclassificationResult
- type OrphanedSessionPlaceholder
- type PassiveCaptureParams
- type PassiveCaptureResult
- type PendingSyncMutationProjectCount
- type ProjectNameCount
- type ProjectRescueBlocked
- type ProjectRescueParams
- type ProjectRescueResult
- type ProjectStats
- type Prompt
- type PromptSourcePreview
- type PromptTombstone
- type PruneResult
- type QuarantinedPulledSessionEvidence
- type Relation
- type RelationListItem
- type RelationStats
- type ReplayDeferredResult
- type ReviewClearEvent
- type SQLiteLockSnapshot
- type SaveRelationParams
- type ScanOptions
- type ScanResult
- type SearchOptions
- type SearchPreviewResult
- type SearchResult
- type SemanticRunner
- type SemanticVerdict
- type Session
- type SessionIdentityRepairPlan
- type SessionIdentityRepairResult
- type SessionProjectConflictError
- type SessionProjectReclassification
- type SessionProjectReclassificationCounts
- type SessionProjectReclassificationResult
- type SessionSummary
- type Stats
- type Store
- func (s *Store) AckSyncMutationSeqs(targetKey string, seqs []int64) error
- func (s *Store) AckSyncMutations(targetKey string, lastAckedSeq int64) error
- func (s *Store) AcquireSyncLease(targetKey, owner string, ttl time.Duration, now time.Time) (bool, error)
- func (s *Store) ActiveRuntimeSessions(project string, directories ...string) ([]string, error)
- func (s *Store) AddObservation(p AddObservationParams) (int64, error)
- func (s *Store) AddObservationWithResult(p AddObservationParams) (AddObservationResult, error)
- func (s *Store) AddPrompt(p AddPromptParams) (int64, error)
- func (s *Store) AddPromptIfMissing(p AddPromptParams) (int64, bool, error)
- func (s *Store) AddPromptWithResult(p AddPromptParams) (int64, bool, error)
- func (s *Store) AllObservations(project, scope string, limit int) ([]Observation, error)
- func (s *Store) AllSessions(project string, limit int) ([]SessionSummary, error)
- func (s *Store) ApplyLegacyEmptyPromptDiscard(plan LegacyEmptyPromptDiscardPlan, backupPath string) (LegacyEmptyPromptDiscardResult, error)
- func (s *Store) ApplyPulledChunk(targetKey, chunkID string, mutations []SyncMutation) error
- func (s *Store) ApplyPulledChunkForDomain(targetKey, chunkID string, mutations []SyncMutation, cloud bool) error
- func (s *Store) ApplyPulledMutation(targetKey string, mutation SyncMutation) error
- func (s *Store) ApplyPulledMutationPreservingSyncState(targetKey string, mutation SyncMutation) error
- func (s *Store) ApplySessionIdentityRepair(plan SessionIdentityRepairPlan) (SessionIdentityRepairResult, error)
- func (s *Store) ApplySessionProjectReclassification(actions []SessionProjectReclassification) (SessionProjectReclassificationResult, error)
- func (s *Store) BackupSQLite() (string, error)
- func (s *Store) CanRollbackCloudUpgrade(project string) (bool, error)
- func (s *Store) CapturePromptForSave(enabled *bool, prompt AddPromptParams) error
- func (s *Store) CleanupForeignSyncTargets(apply bool) (ForeignSyncTargetCleanupReport, error)
- func (s *Store) ClearCloudUpgradeState(project string) error
- func (s *Store) Close() error
- func (s *Store) CloudSyncSummary() (CloudSyncSummary, error)
- func (s *Store) ConfirmPromptSourceAttestation(remoteTarget string, preview PromptSourcePreview, assertedOwner string, ...) error
- func (s *Store) ContentTruncation(content string) TruncationMetadata
- func (s *Store) CountDeferredAndDead() (deferred, dead int, err error)
- func (s *Store) CountDeferredAndDeadForScope(targetKey, project string) (deferred, dead int, err error)
- func (s *Store) CountObservationsForProject(name string) (int, error)
- func (s *Store) CountPendingNonEnrolledSyncMutations(targetKey string) ([]PendingSyncMutationProjectCount, error)
- func (s *Store) CountRelationSyncMutations() (int, error)
- func (s *Store) CountRelations(opts ListRelationsOptions) (int, error)
- func (s *Store) CreateSession(id, project, directory string) error
- func (s *Store) CreateSessionWithOwnershipMode(id, project, directory, mode string) error
- func (s *Store) DB() *sql.DB
- func (s *Store) DataDir() string
- func (s *Store) DeleteObservation(id int64, hardDelete bool) error
- func (s *Store) DeleteObservationForProject(id int64, expected string, hardDelete bool) error
- func (s *Store) DeleteProject(project string, hardDelete bool) (*DeleteProjectResult, error)
- func (s *Store) DeletePrompt(id int64) error
- func (s *Store) DeleteSession(id string) error
- func (s *Store) DetectProject(directory string) project.DetectionResult
- func (s *Store) DiagnoseCloudUpgradeLegacyMutations(project string) (CloudUpgradeLegacyMutationReport, error)
- func (s *Store) EndRuntimeSession(root, project, directory, mode, summary string) (string, error)
- func (s *Store) EndSession(id string, summary string) error
- func (s *Store) EnqueueDeferredRelation(targetKey string, mutation SyncMutation) error
- func (s *Store) EnrollProject(project string) error
- func (s *Store) EnsureEnrolledProjectSyncMutations(ctx context.Context) error
- func (s *Store) EstimateSessionProjectReclassification(actions []SessionProjectReclassification) (SessionProjectReclassificationCounts, error)
- func (s *Store) Export() (*ExportData, error)
- func (s *Store) ExportLocalDeleteTombstones(project string) ([]SyncMutation, error)
- func (s *Store) ExportProject(project string) (*ExportData, error)
- func (s *Store) ExportRelationMutations(project string) ([]SyncMutation, error)
- func (s *Store) ExportReviewClearEvents() ([]ReviewClearEvent, error)
- func (s *Store) FindCandidates(savedID int64, opts CandidateOptions) ([]Candidate, error)
- func (s *Store) FormatCompactionContext(sessionID string) (string, error)
- func (s *Store) FormatContext(project, scope string) (string, error)
- func (s *Store) FormatContextWithOptions(project, scope string, opts ContextOptions) (string, error)
- func (s *Store) GenerationError() error
- func (s *Store) GetCloudUpgradeState(project string) (*CloudUpgradeState, error)
- func (s *Store) GetDeferred(syncID string) (DeferredRow, error)
- func (s *Store) GetObservation(id int64) (*Observation, error)
- func (s *Store) GetObservationBySyncID(syncID string) (*Observation, error)
- func (s *Store) GetObservationSaveResult(operationID string) (observationID int64, err error)
- func (s *Store) GetObservationVersionPage(id int64, limit int, cursor int64) (ObservationVersionPage, error)
- func (s *Store) GetObservationVersions(id int64) ([]ObservationVersion, error)
- func (s *Store) GetRelation(syncID string) (*Relation, error)
- func (s *Store) GetRelationByIntID(id int64) (*RelationListItem, error)
- func (s *Store) GetRelationStats(project string) (RelationStats, error)
- func (s *Store) GetRelationsForObservations(syncIDs []string) (map[string]ObservationRelations, error)
- func (s *Store) GetRelationsForObservationsContext(ctx context.Context, syncIDs []string) (map[string]ObservationRelations, error)
- func (s *Store) GetSession(id string) (*Session, error)
- func (s *Store) GetSyncState(targetKey string) (*SyncState, error)
- func (s *Store) GetSyncedChunks() (map[string]bool, error)
- func (s *Store) GetSyncedChunksForTarget(targetKey string) (map[string]bool, error)
- func (s *Store) HasObservationBySyncIDAnyState(syncID string) (bool, error)
- func (s *Store) HasPendingSyncMutationsForProject(project string) (bool, error)
- func (s *Store) HasProjectOwnedSessions() (bool, error)
- func (s *Store) HasProjectOwnedSessionsForProject(project string) (bool, error)
- func (s *Store) Import(data *ExportData) (*ImportResult, error)
- func (s *Store) InspectProject(directory string) project.DetectionResult
- func (s *Store) InstanceID() string
- func (s *Store) IsProjectEnrolled(project string) (bool, error)
- func (s *Store) JudgeBySemantic(p JudgeBySemanticParams) (string, error)
- func (s *Store) JudgeRelation(p JudgeRelationParams) (*Relation, error)
- func (s *Store) ListDeferred(opts ListDeferredOptions) ([]DeferredRow, error)
- func (s *Store) ListDeferredProjectsForTarget(targetKey string) ([]string, error)
- func (s *Store) ListDiagnosticObservationRequiredFields(project string) ([]ObservationRequiredFieldsEvidence, error)
- func (s *Store) ListDiagnosticSessions(project string) ([]DiagnosticSessionEvidence, error)
- func (s *Store) ListEnrolledProjects() ([]EnrolledProject, error)
- func (s *Store) ListInvalidSessionIdentityEvidence(project string) ([]InvalidSessionIdentityEvidence, error)
- func (s *Store) ListObservationSyncPayloads() ([]any, error)
- func (s *Store) ListOrphanedObservationSessionEvidence(project string) ([]OrphanedObservationSessionEvidence, error)
- func (s *Store) ListOrphanedPendingRelationEvidence() (OrphanedPendingRelationEvidenceReport, error)
- func (s *Store) ListOrphanedPendingRelationEvidenceBounded(limit int) (OrphanedPendingRelationEvidenceBounded, error)
- func (s *Store) ListPendingProjectMutations(project string) ([]SyncMutation, error)
- func (s *Store) ListPendingSyncMutations(targetKey string, limit int) ([]SyncMutation, error)
- func (s *Store) ListPendingSyncMutationsAfterSeq(targetKey string, afterSeq int64, limit int) ([]SyncMutation, error)
- func (s *Store) ListProjectNames() ([]string, error)
- func (s *Store) ListProjectsForCloudEnrollment() ([]string, error)
- func (s *Store) ListProjectsWithStats() ([]ProjectStats, error)
- func (s *Store) ListQuarantinedPulledSessionEvidence(project string) ([]QuarantinedPulledSessionEvidence, error)
- func (s *Store) ListRelations(opts ListRelationsOptions) ([]RelationListItem, error)
- func (s *Store) ListSyncStates() ([]SyncTargetState, error)
- func (s *Store) LocalPromptCreationIdentity(syncID string) (session, inbox, project string, eligible bool, err error)
- func (s *Store) LocalSessionProvenance(id string) (owner string, eligible bool, err error)
- func (s *Store) MarkReviewed(id int64) error
- func (s *Store) MarkReviewedForProject(id int64, project string) error
- func (s *Store) MarkSyncAuthRequired(targetKey, message string) error
- func (s *Store) MarkSyncBlocked(targetKey, reasonCode, message string) error
- func (s *Store) MarkSyncBlockedAfterSuccess(targetKey, reasonCode, message string) error
- func (s *Store) MarkSyncFailure(targetKey, message string, backoffUntil time.Time) error
- func (s *Store) MarkSyncFailureWithReason(targetKey, reasonCode, message string, backoffUntil time.Time) error
- func (s *Store) MarkSyncHealthy(targetKey string) error
- func (s *Store) MarkSyncPaused(targetKey, message string) error
- func (s *Store) MarkSyncPending(targetKey string) error
- func (s *Store) MaxObservationLength() int
- func (s *Store) MaxPendingSyncMutationSeq(targetKey string) (int64, error)
- func (s *Store) MergeExplicitProjectVariants(sources []string, canonical string) (*MergeResult, error)
- func (s *Store) MergeProjects(sources []string, canonical string) (*MergeResult, error)
- func (s *Store) MigrateProject(oldName, newName string) (*MigrateResult, error)
- func (s *Store) ObservationOperationRecorded(operationID string) (bool, error)
- func (s *Store) ObservationsNeedingReview(project string, limit int) ([]Observation, error)
- func (s *Store) PassiveCapture(p PassiveCaptureParams) (*PassiveCaptureResult, error)
- func (s *Store) PinObservation(id int64) error
- func (s *Store) PinnedObservations(project, scope string) ([]Observation, error)
- func (s *Store) PlanLegacyEmptyPromptDiscard(project string, seq int64) (LegacyEmptyPromptDiscardPlan, error)
- func (s *Store) PlanSessionIdentityRepair(sourceID, replacementID string) (SessionIdentityRepairPlan, error)
- func (s *Store) PreviewExplicitProjectMerge(source, canonical string) (*ExplicitProjectMergePreview, error)
- func (s *Store) PreviewPromptSource(syncID string) (PromptSourcePreview, bool, error)
- func (s *Store) ProjectExists(name string) (bool, error)
- func (s *Store) ProjectHistory(directory string) ([]string, error)
- func (s *Store) PruneProject(project string) (*PruneResult, error)
- func (s *Store) QuarantineIrreparableSyncMutations(targetKey, project string, apply bool) (SyncMutationQuarantineReport, error)
- func (s *Store) ReadSQLiteLockSnapshot(ctx context.Context) (SQLiteLockSnapshot, error)
- func (s *Store) RearmEligibleDeadRelationsForScope(targetKey, project string) (int, error)
- func (s *Store) RecentObservations(project, scope string, limit int) ([]Observation, error)
- func (s *Store) RecentPrompts(project string, limit int) ([]Prompt, error)
- func (s *Store) RecentSessions(project string, limit int) ([]SessionSummary, error)
- func (s *Store) ReclassifyOrphanedPendingRelations() (OrphanedPendingRelationReclassificationResult, error)
- func (s *Store) RecordSyncedChunk(chunkID string) error
- func (s *Store) RecordSyncedChunkForTarget(targetKey, chunkID string) error
- func (s *Store) RegisterIsolatedSession(id, project string, resume bool) (string, error)
- func (s *Store) RegisterIsolatedSessionTimed(id, project string, resume bool, timings *WriteTimings) (string, error)
- func (s *Store) ReleaseSyncLease(targetKey, owner string) error
- func (s *Store) RemirrorProject(project string) error
- func (s *Store) RepairCloudUpgrade(project string, apply bool) (CloudUpgradeRepairReport, error)
- func (s *Store) RepairObservationMutationTitles(project string, apply bool) (SyncMutationTitleRepairReport, error)
- func (s *Store) RepairObservationSourceTitles(project string, apply bool) (ObservationSourceTitleRepairReport, error)
- func (s *Store) RepairPendingSessionDirectories(project string, apply bool) ([]SyncMutationDirectoryRepairAction, error)
- func (s *Store) ReplayDeferred() (ReplayDeferredResult, error)
- func (s *Store) ReplayDeferredForScope(targetKey, project string) (result ReplayDeferredResult, err error)
- func (s *Store) RescueNullProjectOwnership(p ProjectRescueParams) (*ProjectRescueResult, error)
- func (s *Store) ResolveRuntimeSessionWithOwnershipMode(root, project, directory, mode string) (string, error)
- func (s *Store) RestoreOrphanedObservationSessions(actions []OrphanedSessionPlaceholder) ([]OrphanedSessionPlaceholder, error)
- func (s *Store) ResumeSessionWithOwnershipMode(id, project, directory, mode string) (string, error)
- func (s *Store) ResumeSessionWithOwnershipModeTimed(id, project, directory, mode string, timings *WriteTimings) (string, error)
- func (s *Store) RollbackCloudUpgrade(project string) (CloudUpgradeState, error)
- func (s *Store) SaveCloudUpgradeState(state CloudUpgradeState) error
- func (s *Store) SaveRelation(p SaveRelationParams) (*Relation, error)
- func (s *Store) ScanAllProjects(opts ScanOptions) (ScanResult, error)
- func (s *Store) ScanProject(opts ScanOptions) (ScanResult, error)
- func (s *Store) Search(query string, opts SearchOptions) ([]SearchResult, error)
- func (s *Store) SearchContext(ctx context.Context, query string, opts SearchOptions) ([]SearchResult, error)
- func (s *Store) SearchPreviewsContext(ctx context.Context, query string, opts SearchOptions) ([]SearchPreviewResult, error)
- func (s *Store) SearchPrompts(query string, project string, limit int) ([]Prompt, error)
- func (s *Store) SessionObservations(sessionID string, limit int) ([]Observation, error)
- func (s *Store) SkipAckNonEnrolledMutations(targetKey string) (int64, error)
- func (s *Store) StartSession(id, project, directory string) error
- func (s *Store) StartSessionWithOwnershipMode(id, project, directory, mode string) error
- func (s *Store) StartSessionWithOwnershipModeTimed(id, project, directory, mode string, timings *WriteTimings) error
- func (s *Store) Stats() (*Stats, error)
- func (s *Store) StatsProject(project string) (*Stats, error)
- func (s *Store) SupersedeUnenrolledLegacyMutations(targetKey, project string, apply bool) (SyncMutationSupersedeReport, error)
- func (s *Store) Timeline(observationID int64, before, after int) (*TimelineResult, error)
- func (s *Store) UnenrollProject(project string) error
- func (s *Store) UnpinObservation(id int64) error
- func (s *Store) UpdateObservation(id int64, p UpdateObservationParams) (*Observation, error)
- func (s *Store) UpdateObservationForProject(id int64, expected string, p UpdateObservationParams) (*Observation, error)
- type SyncMutation
- type SyncMutationDirectoryRepairAction
- type SyncMutationPayloadValidation
- type SyncMutationQuarantineAction
- type SyncMutationQuarantineReport
- type SyncMutationSupersedeAction
- type SyncMutationSupersedeReport
- type SyncMutationTitleRepairAction
- type SyncMutationTitleRepairReport
- type SyncState
- type SyncTargetState
- type TimelineEntry
- type TimelineResult
- type TruncationMetadata
- type UpdateObservationParams
- type WriteTimings
Constants ¶
const ( RelationPending = "pending" RelationRelated = "related" RelationCompatible = "compatible" RelationScoped = "scoped" RelationConflictsWith = "conflicts_with" RelationSupersedes = "supersedes" RelationNotConflict = "not_conflict" )
Valid relation type values. Type compatibility is NOT enforced in Phase 1; the agent does that judgment.
const ( JudgmentStatusPending = "pending" JudgmentStatusJudged = "judged" JudgmentStatusOrphaned = "orphaned" JudgmentStatusIgnored = "ignored" )
Valid judgment_status values.
const ( SessionOwnershipProjectOwned = "project_owned" )
const ( ObservationStateActive = "active" ObservationStateNeedsReview = "needs_review" )
const ( DefaultSyncTargetKey = "cloud" LocalChunkTargetKey = "local" // SyncInboxTargetKey is the reserved sync target of the cloud inbox. It owns // its own sync_state row and never represents an enrollable project. SyncInboxTargetKey = "cloud:inbox" // ReservedInboxProjectName is the project name the cloud inbox owns. Enrolling // it is rejected because its cloud:<project> target key would collide with // SyncInboxTargetKey. ReservedInboxProjectName = "inbox" SyncLifecycleIdle = "idle" SyncLifecyclePending = "pending" SyncLifecycleRunning = "running" SyncLifecycleHealthy = "healthy" SyncLifecycleDegraded = "degraded" // SyncLifecycleInbox is the fixed lifecycle of the reserved cloud inbox // target. Lifecycle setters and refresh helpers must never transition it. SyncLifecycleInbox = "inbox" SyncEntitySession = "session" SyncEntityObservation = "observation" SyncEntityPrompt = "prompt" SyncEntityRelation = "relation" SyncOpUpsert = "upsert" SyncOpDelete = "delete" SyncSourceLocal = "local" SyncSourceRemote = "remote" SyncSessionIdentityInvalidReasonCode = "sync_session_identity_invalid" SyncObservationIdentityInvalidReasonCode = "sync_observation_identity_invalid" SyncPromptIdentityInvalidReasonCode = "sync_prompt_identity_invalid" SyncParentSessionMissingReasonCode = "pulled_parent_session_missing" )
const ( SyncMutationDispositionPending = "pending" SyncMutationDispositionQuarantined = "quarantined" SyncMutationDispositionSuperseded = "superseded" SyncMutationSupersededReasonLocalEntityDeleted = "local_entity_deleted" )
const ( UpgradeStagePlanned = "planned" UpgradeStageDoctorReady = "doctor_ready" UpgradeStageDoctorBlocked = "doctor_blocked" UpgradeStageRepairApplied = "repair_applied" UpgradeStageBootstrapEnrolled = "bootstrap_enrolled" UpgradeStageBootstrapPushed = "bootstrap_pushed" UpgradeStageBootstrapVerified = "bootstrap_verified" UpgradeStageRolledBack = "rolled_back" UpgradeRepairClassNone = "none" UpgradeRepairClassReady = "ready" UpgradeRepairClassRepairable = "repairable" UpgradeRepairClassBlocked = "blocked" UpgradeRepairClassPolicy = "policy" )
const ( UpgradeReasonRepairableLegacyMutationPayload = "upgrade_repairable_legacy_mutation_payload" UpgradeReasonBlockedLegacyMutationManual = "upgrade_blocked_legacy_mutation_manual" )
const ( // RescueBlockedOwnedByOtherProject means the row itself already belongs to a // project other than the target. RescueBlockedOwnedByOtherProject = "owned_by_other_project" // RescueBlockedSessionOwnedByOtherProject means the row is unowned but its // parent session belongs to another project, so moving it would split it. RescueBlockedSessionOwnedByOtherProject = "session_owned_by_other_project" // RescueBlockedDependentRecordOwnedByOtherProject means an unowned session // was left in place because it parents a record owned by another project. RescueBlockedDependentRecordOwnedByOtherProject = "dependent_record_owned_by_other_project" // RescueBlockedMissing means the requested row does not exist. RescueBlockedMissing = "missing" )
Reasons a record or session was left behind by a rescue.
const DefaultObservationVersionPageSize = 50
DefaultObservationVersionPageSize is the bound applied to a single history page when the caller does not choose a limit; MCP include_history renders exactly this many most recent versions per call.
const DefaultScanLimit = 100
DefaultScanLimit bounds each conflict scan page and its FTS candidate queries.
const MaxObservationVersionPageSize = 100
MaxObservationVersionPageSize caps a caller-supplied history page so one bounded read stays resource-safe no matter how many snapshots are stored.
const RescueOwnershipCommand = "engram projects rescue-ownership"
RescueOwnershipCommand is the repair an operator can always run, whatever the server authorization configuration is: it reaches the local store directly and never goes through the HTTP endpoint. Every ownership error names it, so the failure carries its own remedy instead of pointing at a changelog.
Variables ¶
var ( ErrSessionNotFound = errors.New("session not found") ErrSessionIDRequired = errors.New("session id is required") ErrSessionAlreadyEnded = errors.New("session has already ended") ErrSessionHasObservations = errors.New("session still has observations") ErrSessionDeleteBlocked = errors.New("session deletion is blocked while cloud sync enrollment is active") ErrObservationNotFound = errors.New("observation not found") ErrPromptNotFound = errors.New("prompt not found") ErrPromptInboxDeleted = errors.New("prompt inbox identity was deleted") ErrProjectNotFound = errors.New("project not found") ErrProjectRequired = errors.New("project identity is required") ErrInvalidSessionOwnershipMode = errors.New("invalid session ownership mode") ErrSessionOwnershipMismatch = errors.New("session ownership does not match write project") ErrProjectRescueInvalidRequest = errors.New("project rescue request is invalid") // ErrProjectOwnershipAmbiguous is returned when an unowned session cannot // adopt a write's project because it already parents records owned by a // different one. Guessing there would split a record from its session. ErrProjectOwnershipAmbiguous = errors.New("session project ownership is ambiguous") ErrExpectedProjectRequired = errors.New("expected_project must be a valid non-empty project name") ErrObservationProjectMismatch = errors.New("expected_project does not match observation owner") ErrObservationProjectImmutable = errors.New("observation project cannot be reassigned") ErrObservationTitleRequired = errors.New("observation title is required") ErrObservationContentRequired = errors.New("observation content is required") ErrObservationOperationConflict = errors.New("observation operation id conflicts with a different payload") ErrObservationOperationExpired = errors.New("observation operation id is outside the replay horizon") ErrObservationFindReplacePairRequired = errors.New("find and replace must be provided together") ErrObservationFindReplaceContentConflict = errors.New("find and replace cannot be combined with content") ErrObservationFindReplaceInputTooLarge = errors.New("find and replace inputs exceed maximum observation length") ErrObservationFindReplaceResultTooLarge = errors.New("replacement result exceeds maximum observation length") ErrObservationFindReplaceLegacyContentLarge = errors.New("cannot partially replace oversized legacy observation") ErrPromptContentRequired = errors.New("prompt content is required") )
Sentinel errors returned by Store operations so callers can use errors.Is.
var ( // ErrRelationFKMissing is returned by applyRelationUpsertTx when one or // both observations referenced by the relation payload do not exist locally // yet. The caller must write the mutation to sync_apply_deferred and ACK // the sequence so the cursor does not stall. ErrRelationFKMissing = errors.New("relation FK precondition not met: referenced observation missing") // ErrRelationProjectMismatch reports existing endpoints outside the relation's // effective project. It shares the missing-endpoint retry/rearm lifecycle. ErrRelationProjectMismatch = errors.New("relation FK precondition not met: referenced observation effective project mismatch") // ErrCrossProjectRelation is returned by JudgeRelation when the source and // target observations belong to different projects. The write is rejected // entirely; no memory_relations row is created and no sync mutation is // enqueued. ErrCrossProjectRelation = errors.New("relation rejected: source and target observations are in different projects") // ErrApplyDead is returned when a deferred relation payload cannot be // decoded or fails a hard validation. The row is written to // sync_apply_deferred with apply_status='dead' and is never retried // automatically; Phase 3 adds a republish CLI. ErrApplyDead = errors.New("relation apply permanently failed: payload invalid or undecodable") // ErrPulledSessionIdentityInvalid identifies an invalid identity after successful decoding and legacy fallback. ErrPulledSessionIdentityInvalid = errors.New("pulled session identity is invalid") // ErrPulledObservationIdentityInvalid identifies a pulled observation whose payload and mutation identities disagree. ErrPulledObservationIdentityInvalid = errors.New("pulled observation identity is invalid") // ErrPulledPromptIdentityInvalid identifies a pulled prompt delete with an unusable keyed identity. ErrPulledPromptIdentityInvalid = errors.New("pulled prompt identity is invalid") // ErrPulledSessionDirectoryInvalid identifies a pulled or imported session that // has no concrete directory and therefore cannot be admitted as cloud state. ErrPulledSessionDirectoryInvalid = errors.New("pulled session directory is invalid") )
Sentinel errors for relation sync apply path (Phase 2).
var ErrDatabaseGenerationChanged = errors.New("Engram database generation changed; restart Engram")
ErrDatabaseGenerationChanged means Engram's SQLite files were replaced while this process was running. Restart Engram before accessing the store again.
var ErrPromptSourceConfirmation = errors.New("prompt source confirmation rejected")
var ErrRuntimeSessionScopeConflict = errors.New("runtime session scope conflict")
ErrRuntimeSessionScopeConflict refuses runtime-root reuse outside its binding.
var ErrSemanticPromptBuilderRequired = errors.New("semantic scan requires a non-nil BuildPrompt function")
ErrSemanticPromptBuilderRequired is returned by ScanProject when ScanOptions.Semantic is true but ScanOptions.BuildPrompt is nil.
var ErrSemanticRunnerRequired = errors.New("semantic scan requires a non-nil Runner")
ErrSemanticRunnerRequired is returned by ScanProject when ScanOptions.Semantic is true but ScanOptions.Runner is nil.
var ErrSessionIsolationConflict = errors.New("isolated session registration requires an empty directory; existing runtime-bound sessions cannot be reused")
ErrSessionIsolationConflict refuses reuse of a runtime-bound or shared identity as a satellite.
Functions ¶
func ClassifyTool ¶
ClassifyTool returns the observation type for a given tool name.
func EnsureInstanceID ¶
func ExtractLearnings ¶
ExtractLearnings parses structured learning items from text. It looks for sections like "## Key Learnings:" or "## Aprendizajes Clave:" and extracts numbered (1. text) or bullet (- text) items. Returns learnings from the LAST matching section (most recent output).
func NormalizeProject ¶
NormalizeProject applies canonical project name normalization: Unicode NFC + lowercase + trim whitespace + collapse consecutive hyphens/underscores. Returns the normalized name and a warning message if the name was changed (empty string if no change was needed). Exported so MCP and CLI handlers can surface the warning to users.
func Now ¶
func Now() string
Now returns the current time formatted for SQLite with persisted generation precision.
func SuggestTopicKey ¶
SuggestTopicKey generates a stable topic key suggestion from type/title/content. It infers a topic family (e.g. architecture/*, bug/*) and then appends a normalized segment from title/content for stable cross-session keys.
func ValidateCloudSessionDirectory ¶ added in v3.2.0
ValidateCloudSessionDirectory admits omitted or blank string directories for project-owned sessions, including isolated registrations. Shared and legacy sessions still require a concrete directory. Null and non-string values never stand in for a blank directory.
func ValidateExpectedProject ¶
ValidateExpectedProject validates an explicit caller-owned assertion, never a default.
func ValidateObservationTitle ¶
ValidateObservationTitle is the one definition of "an observation has a usable title", shared by every write path so the CLI, MCP and HTTP entry points can reject a titleless write before they create a session or open a transaction. It mirrors what ValidateSyncMutationPayload requires of an observation upsert: cloud sync rejects a payload whose title is empty, and because the mutation queue is an ordered log, one rejected row blocks every later mutation for the same project.
Types ¶
type AddObservationParams ¶
type AddObservationParams struct {
SessionID string `json:"session_id"`
Type string `json:"type"`
Title string `json:"title"`
Content string `json:"content"`
ToolName string `json:"tool_name,omitempty"`
Project string `json:"project,omitempty"`
Scope string `json:"scope,omitempty"`
TopicKey string `json:"topic_key,omitempty"`
OperationID string `json:"operation_id,omitempty"`
Timings *WriteTimings `json:"-"`
}
type AddObservationResult ¶ added in v3.3.0
AddObservationResult reports whether an observation save created a new logical result or returned an exact replay from the operation ledger.
type AddPromptParams ¶
type BackupRelation ¶
type BackupRelation struct {
SyncID string `json:"sync_id"`
SourceID string `json:"source_id"`
TargetID string `json:"target_id"`
Relation string `json:"relation"`
Reason *string `json:"reason,omitempty"`
Evidence *string `json:"evidence,omitempty"`
Confidence *float64 `json:"confidence,omitempty"`
JudgmentStatus string `json:"judgment_status"`
MarkedByActor *string `json:"marked_by_actor,omitempty"`
MarkedByKind *string `json:"marked_by_kind,omitempty"`
MarkedByModel *string `json:"marked_by_model,omitempty"`
SessionID *string `json:"session_id,omitempty"`
SupersededAt *string `json:"superseded_at,omitempty"`
SupersededByRelationSyncID *string `json:"superseded_by_relation_sync_id,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
BackupRelation is the lossless direct-backup representation of a memory_relations row. Relation IDs are local SQLite keys, so supersession is represented by the referenced relation's portable sync ID instead.
type Candidate ¶
type Candidate struct {
// ID is the integer primary key of the candidate observation.
ID int64
// SyncID is the TEXT sync_id of the candidate observation.
SyncID string
// Title is the candidate's title.
Title string
// Type is the candidate's observation type.
Type string
// TopicKey is the candidate's topic_key (may be nil).
TopicKey *string
// Score is the FTS5 BM25 rank; lower values are better matches.
Score float64
// JudgmentID is the sync_id of the pending memory_relations row created
// for this (source, candidate) pair.
JudgmentID string
}
Candidate represents a potential conflict candidate surfaced by FindCandidates.
type CandidateOptions ¶
type CandidateOptions struct {
// Project filters candidates to the same project as the saved observation.
Project string
// Scope filters candidates to the same scope as the saved observation.
Scope string
// Type is reserved for Phase 2 type-compatibility filtering; NOT enforced Phase 1.
Type string
// Limit caps the number of candidates returned. Default 3 when nil or <=0.
Limit int
// BM25MaxRank is the largest acceptable raw FTS5 BM25 rank. Smaller ranks
// are better matches, so candidates whose rank is greater are excluded. nil
// uses 0.0, which retains ordinary negative FTS5 ranks.
BM25MaxRank *float64
// BM25Floor preserves the deprecated legacy minimum-rank behavior. Candidates
// below this value are excluded. It cannot be combined with BM25MaxRank.
BM25Floor *float64
// Query optionally overrides the saved observation title as the candidate
// query source. Empty uses the saved title.
Query string
// RequireSaveRelevance opts into title/topic relevance filtering before the
// candidate limit and pending relation inserts. MCP saves enable it; broad
// recall scans and other callers retain their existing behavior by default.
RequireSaveRelevance bool
// SkipInsert controls whether FindCandidates inserts pending relation rows.
// When true, candidates are returned but NO rows are written to memory_relations.
// Default false preserves the existing behavior (rows are inserted).
SkipInsert bool
// Timings optionally receives per-call diagnostic durations. Use a distinct
// pointer for each concurrent call. Nil performs no timing instrumentation.
Timings *CandidateTimings
}
CandidateOptions controls the FindCandidates query.
type CandidateTimings ¶ added in v3.2.0
type CandidateTimings struct {
Lookup time.Duration
Inserts time.Duration
// RowsRead counts result rows consumed by Go, not SQLite FTS index work.
RowsRead int
}
CandidateTimings separates candidate lookup (including row consumption and closure) from pending-relation insertion. Durations include database waits; they are not CPU times or separate SQLite lock-wait measurements.
type CloudSyncSummary ¶
type CloudSyncSummary struct {
LastSuccessAt string
PendingMutations int64
LastError string
ReasonCode string
}
CloudSyncSummary is the aggregate local cloud state shown when no project is selected.
type CloudUpgradeLegacyMutationFinding ¶
type CloudUpgradeLegacyMutationFinding struct {
Seq int64 `json:"seq"`
Entity string `json:"entity"`
Op string `json:"op"`
ReasonCode string `json:"reason_code"`
Message string `json:"message"`
Repairable bool `json:"repairable"`
RepairHint string `json:"repair_hint,omitempty"`
EntityKey string `json:"entity_key,omitempty"`
TargetKey string `json:"target_key,omitempty"`
Project string `json:"project,omitempty"`
}
type CloudUpgradeLegacyMutationReport ¶
type CloudUpgradeLegacyMutationReport struct {
Project string `json:"project"`
RepairableCount int `json:"repairable_count"`
BlockedCount int `json:"blocked_count"`
Findings []CloudUpgradeLegacyMutationFinding `json:"findings,omitempty"`
}
type CloudUpgradeSnapshot ¶
type CloudUpgradeState ¶
type CloudUpgradeState struct {
Project string `json:"project"`
Stage string `json:"stage"`
RepairClass string `json:"repair_class"`
Snapshot CloudUpgradeSnapshot `json:"snapshot"`
LastErrorCode string `json:"last_error_code,omitempty"`
LastErrorMessage string `json:"last_error_message,omitempty"`
FindingsJSON string `json:"findings_json,omitempty"`
AppliedActions string `json:"applied_actions,omitempty"`
UpdatedAt string `json:"updated_at"`
}
type Config ¶
type Config struct {
DataDir string
MaxObservationLength int
MaxContextResults int
MaxSearchResults int
DedupeWindow time.Duration
}
func DefaultConfig ¶
func FallbackConfig ¶
FallbackConfig returns a Config with the given DataDir and default values. Use this when DefaultConfig fails and you have resolved the home directory through alternative means.
type ContextOptions ¶
type ContextOptions struct {
// MaxBytes caps the complete rendered context in bytes. Zero preserves the
// unbounded legacy output; a positive value returns at most that many bytes.
MaxBytes int
// Observations caps the "### Recent Observations" section (unpinned).
Observations int
// Prompts caps the "### Recent User Prompts" section.
Prompts int
// Sessions caps the "### Recent Sessions" section.
Sessions int
// Pinned caps the "### Pinned" section.
Pinned int
// Compact drops the inline content preview from observation-shaped
// bullets — both "### Pinned" and "### Recent Observations" render
// `- [type] **title**` instead of `- [type] **title**: <300 chars of
// body>`. Sessions and prompts bullets are unaffected.
Compact bool
}
ContextOptions tunes FormatContextWithOptions, capping how many rows each section of the "## Memory from Previous Sessions" block renders.
Every field follows the same convention:
- 0 uses that section's legacy default.
- >0 caps the section at that many rows.
- <0 omits the section entirely, including its "### ..." header.
The legacy defaults are Sessions 5, Prompts 10, Observations s.cfg.MaxContextResults, and Pinned unlimited (no SQL LIMIT) — exactly what FormatContext has always produced, so a zero-value ContextOptions{} reproduces FormatContext's output byte-for-byte. See issue #163 (bounded-size injection).
type DeferredRow ¶
type DeferredRow struct {
SyncID string `json:"sync_id"`
Entity string `json:"entity"`
TargetKey string `json:"target_key"`
Project string `json:"project"`
ScopeClass string `json:"scope_class"`
RemoteSeq int64 `json:"remote_seq,omitempty"`
EntityKey string `json:"entity_key,omitempty"`
Op string `json:"op,omitempty"`
ReasonCode string `json:"reason_code,omitempty"`
Payload map[string]any `json:"payload,omitempty"`
PayloadRaw string `json:"payload_raw"`
PayloadValid bool `json:"payload_valid"`
ApplyStatus string `json:"apply_status"`
RetryCount int `json:"retry_count"`
LastError *string `json:"last_error,omitempty"`
LastAttemptedAt *string `json:"last_attempted_at,omitempty"`
FirstSeenAt string `json:"first_seen_at"`
}
DeferredRow represents a row in sync_apply_deferred with the payload decoded.
type DeleteProjectResult ¶
type DeleteProjectResult struct {
Project string `json:"project"`
ObservationsDeleted int64 `json:"observations_deleted"`
PromptsDeleted int64 `json:"prompts_deleted"`
SessionsDeleted int64 `json:"sessions_deleted"`
HardDelete bool `json:"hard_delete"`
}
DeleteProjectResult summarises a cascade project deletion.
type DiagnosticSessionEvidence ¶
type DiagnosticSessionEvidence struct {
ID string `json:"id"`
Project string `json:"project"`
OwnershipMode string `json:"ownership_mode"`
Directory string `json:"directory"`
Name string `json:"name"`
}
DiagnosticSessionEvidence is the read-only session projection used by operational diagnostics. It intentionally avoids observation/prompt payloads.
type EnrolledProject ¶
type EnrolledProject struct {
Project string `json:"project"`
EnrolledAt string `json:"enrolled_at"`
}
EnrolledProject represents a project enrolled for cloud sync.
type ExplicitProjectMergePreview ¶
type ExplicitProjectMergePreview struct {
Canonical string
Source string
ObservationsUpdated int64
SessionsUpdated int64
PromptsUpdated int64
SyncIdentityChanges bool
}
ExplicitProjectMergePreview is a point-in-time estimate of source rows the merge updates. Backfill mutations are intentionally not included: apply may enqueue additional mutations and must revalidate against its own transaction.
type ExportData ¶
type ExportData struct {
PromptTombstones []PromptTombstone `json:"prompt_tombstones,omitempty"`
Version string `json:"version"`
ExportedAt string `json:"exported_at"`
Sessions []Session `json:"sessions"`
Observations []Observation `json:"observations"`
Prompts []Prompt `json:"prompts"`
Relations []BackupRelation `json:"relations,omitempty"`
}
func (ExportData) MarshalJSON ¶
func (d ExportData) MarshalJSON() ([]byte, error)
MarshalJSON projects observations through the backup-only form so direct exports include pinned state without changing Observation's sync JSON tag.
func (*ExportData) UnmarshalJSON ¶
func (d *ExportData) UnmarshalJSON(data []byte) error
UnmarshalJSON accepts both the current backup projection and legacy 0.1.0 exports, where pinned and relations are absent and therefore retain defaults.
Directory admission is part of the decode: an absent directory key is treated as missing (blank directory, accepted), a present JSON string is preserved exactly (blank and whitespace included), and JSON null or any non-string token fails the whole unmarshal with an error naming the offending session.
type ForeignSyncTargetCleanupAction ¶
type ForeignSyncTargetCleanupAction struct {
TargetKey string `json:"target_key"`
RetargetedMutations int64 `json:"retargeted_mutations"`
RetainedMutations int64 `json:"retained_mutations"`
StateRemoved bool `json:"state_removed"`
}
ForeignSyncTargetCleanupAction records one foreign target cleanup classification.
type ForeignSyncTargetCleanupReport ¶
type ForeignSyncTargetCleanupReport struct {
Applied bool `json:"applied"`
Actions []ForeignSyncTargetCleanupAction `json:"actions"`
}
ForeignSyncTargetCleanupReport is the result of planning or applying closed sync-target cleanup. Planning returns the same actions without mutating data.
type ImportResult ¶
type InvalidSessionIdentityEvidence ¶
type InvalidSessionIdentityEvidence struct {
Project string `json:"project"`
SessionID string `json:"session_id"`
ObservationCount int64 `json:"observation_count"`
PromptCount int64 `json:"prompt_count"`
InvalidJournalCount int64 `json:"invalid_journal_count"`
}
InvalidSessionIdentityEvidence describes a corrupt source session and the dependent local data that cannot be repaired without a canonical ID.
type JudgeBySemanticParams ¶
type JudgeBySemanticParams struct {
// SourceID is the TEXT sync_id of the source observation (required).
SourceID string
// TargetID is the TEXT sync_id of the target observation (required).
TargetID string
// Relation is the verdict verb (required); must be in validRelationVerbs.
// not_conflict is persisted like every other valid semantic verdict.
Relation string
// Confidence is the LLM's self-reported confidence score [0.0, 1.0].
Confidence float64
// Reasoning is the LLM's short explanation.
Reasoning string
// Model is the LLM model identifier. Stored as marked_by_model.
Model string
}
JudgeBySemanticParams holds the inputs for JudgeBySemantic.
type JudgeRelationParams ¶
type JudgeRelationParams struct {
// JudgmentID is the sync_id of the relation row to update (required).
JudgmentID string
// Relation is the verdict verb (required); must be one of validRelationVerbs.
Relation string
// Reason is an optional free-text explanation.
Reason *string
// Evidence is optional free-form JSON or text evidence.
Evidence *string
// Confidence is optional 0..1 confidence score.
Confidence *float64
// MarkedByActor is the actor identifier (e.g. "agent:claude-sonnet-4-6" or "user").
MarkedByActor string
// MarkedByKind is the actor kind ("agent", "human", "system").
MarkedByKind string
// MarkedByModel is the model ID (may be empty for human actors).
MarkedByModel string
// SessionID is the session in which the judgment was made (optional).
SessionID string
}
JudgeRelationParams holds the inputs for JudgeRelation.
type LegacyEmptyPromptDiscardBlocker ¶
LegacyEmptyPromptDiscardBlocker is a fail-closed planning or application error. Code is suitable for CLI reporting; no blocker implies remote absence.
func (*LegacyEmptyPromptDiscardBlocker) Error ¶
func (e *LegacyEmptyPromptDiscardBlocker) Error() string
type LegacyEmptyPromptDiscardPlan ¶
type LegacyEmptyPromptDiscardPlan struct {
Project string
SelectedSeq int64
PromptID int64
SyncID string
SessionID string
SourceInboxID string
Sequences []int64
// contains filtered or unexported fields
}
LegacyEmptyPromptDiscardPlan previews the exact canonical/FTS deletion, tombstone, superseded sequences and single new delete. Its private snapshot must survive unchanged from planning to apply. Plans are bound to the Store; callers cannot reconstruct a valid plan by deserializing public fields.
type LegacyEmptyPromptDiscardResult ¶
type LegacyEmptyPromptDiscardResult struct {
Status string
Sequences []int64
DeleteSeq int64
BackupPath string
}
LegacyEmptyPromptDiscardResult reports local effects, never remote delivery. BackupPath may remain populated on error: backups/reservations are not removed if creation fails or later transactional revalidation rejects the plan.
type ListDeferredOptions ¶
type ListDeferredOptions struct {
// Status filters by apply_status. Empty means no status filter.
Status string
// Limit caps the number of rows returned. 0 or negative means no limit.
Limit int
// Offset is the pagination offset.
Offset int
}
ListDeferredOptions controls ListDeferred queries.
type ListRelationsOptions ¶
type ListRelationsOptions struct {
// Project filters by the project of the source OR target observation (via JOIN).
// Empty means no project filter (return all).
Project string
// Status filters by judgment_status. Empty means no status filter.
Status string
// SinceTime filters to rows created_at >= SinceTime. Zero value means no filter.
SinceTime time.Time
// Limit caps the number of rows returned. 0 or negative means no limit.
Limit int
// Offset is the pagination offset.
Offset int
// ExcludeNotConflict omits persisted not_conflict verdicts from conflict-facing views.
ExcludeNotConflict bool
}
ListRelationsOptions controls ListRelations and CountRelations queries.
type MergeResult ¶
type MergeResult struct {
Canonical string `json:"canonical"`
SourcesMerged []string `json:"sources_merged"`
ObservationsUpdated int64 `json:"observations_updated"`
SessionsUpdated int64 `json:"sessions_updated"`
PromptsUpdated int64 `json:"prompts_updated"`
}
MergeResult summarizes the result of merging multiple project name variants into a single canonical project name.
type MigrateResult ¶
type NetworkFilesystemError ¶
NetworkFilesystemError rejects persistent SQLite WAL storage on a known remote filesystem. Callers must propagate it unchanged so CLI, server, and MCP users receive the same actionable diagnosis.
func (*NetworkFilesystemError) Error ¶
func (e *NetworkFilesystemError) Error() string
type Observation ¶
type Observation struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
SessionID string `json:"session_id"`
Type string `json:"type"`
Title string `json:"title"`
Content string `json:"content"`
ToolName *string `json:"tool_name,omitempty"`
Project *string `json:"project,omitempty"`
Scope string `json:"scope"`
TopicKey *string `json:"topic_key,omitempty"`
RevisionCount int `json:"revision_count"`
DuplicateCount int `json:"duplicate_count"`
LastSeenAt *string `json:"last_seen_at,omitempty"`
ReviewAfter *string `json:"review_after,omitempty"`
Pinned bool `json:"-"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
DeletedAt *string `json:"deleted_at,omitempty"`
}
func (Observation) State ¶
func (o Observation) State() string
State returns the virtual lifecycle state derived from review_after.
type ObservationRelations ¶
type ObservationRelations struct {
// AsSource holds relations where this observation is source_id.
AsSource []Relation
// AsTarget holds relations where this observation is target_id.
AsTarget []Relation
}
ObservationRelations groups relations for a single observation, split by role.
type ObservationRequiredFieldsEvidence ¶
type ObservationRequiredFieldsEvidence struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
Project string `json:"project"`
MissingFields []string `json:"missing_fields"`
}
ObservationRequiredFieldsEvidence identifies a corrupt source observation without exposing its content in diagnostic output.
type ObservationSnippet ¶
ObservationSnippet carries the fields needed by BuildPrompt to construct an LLM comparison prompt without importing internal/llm from this package.
type ObservationSourceTitleRepairAction ¶
type ObservationSourceTitleRepairAction struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
Project string `json:"project"`
Title string `json:"title"`
}
ObservationSourceTitleRepairAction records a title derived from a corrupt source observation's first non-empty line.
type ObservationSourceTitleRepairReport ¶
type ObservationSourceTitleRepairReport struct {
Project string `json:"project,omitempty"`
Applied bool `json:"applied"`
Actions []ObservationSourceTitleRepairAction `json:"actions"`
BackupPath string `json:"backup_path,omitempty"`
}
ObservationSourceTitleRepairReport is the local recovery result for source observation title repairs. A backup is created only when an apply changes rows.
type ObservationVersion ¶ added in v3.1.0
type ObservationVersion struct {
ID int64 `json:"id"`
ObservationID int64 `json:"observation_id"`
Title string `json:"title"`
Content string `json:"content"`
Version int `json:"version"`
CreatedAt string `json:"created_at"`
}
ObservationVersion is an immutable snapshot of an observation's title and content captured before a topic_key upsert or a content-changing mem_update overwrote it. Versions are numbered per observation starting at 1: the older the state, the lower the number.
type ObservationVersionPage ¶ added in v3.1.0
type ObservationVersionPage struct {
Versions []ObservationVersion
Total int
HasMore bool
// NextCursor is the oldest version in Versions when HasMore is true: pass
// it as the cursor argument to fetch the next (older) page.
NextCursor int64
}
ObservationVersionPage is one bounded page of an observation's captured version history, oldest first (ascending version numbers), plus the truthful total count of stored versions and a continuation cursor when older versions remain beyond the page.
type OrphanedObservationSessionEvidence ¶
type OrphanedObservationSessionEvidence struct {
Project string `json:"project"`
SessionID string `json:"session_id"`
ObservationCount int64 `json:"observation_count"`
FirstObservedAt string `json:"first_observed_at"`
}
OrphanedObservationSessionEvidence identifies observations whose stored session reference has no matching local session. It is grouped so diagnostics can report the affected reference without exposing observation payloads.
type OrphanedPendingRelationEvidence ¶
type OrphanedPendingRelationEvidence struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
SourceID string `json:"source_id"`
TargetID string `json:"target_id"`
}
OrphanedPendingRelationEvidence identifies one legacy pending relation whose source and target observations are both absent from the active observation set. Such a row can never show a title in `engram conflicts show` and no verdict can ever be recorded against it.
type OrphanedPendingRelationEvidenceBounded ¶
type OrphanedPendingRelationEvidenceBounded struct {
CandidateCount int64
OneEndpointMissing int64
LivePending int64
Sample []OrphanedPendingRelationEvidence
}
OrphanedPendingRelationEvidenceBounded is the bounded diagnostic read for the doctor check: the total candidate count plus only the first `limit` evidence rows, so a large legacy backlog cannot force the check to materialize every candidate. CandidateCount always spans all candidates, while Sample is the id-ordered head of the same list.
type OrphanedPendingRelationEvidenceReport ¶
type OrphanedPendingRelationEvidenceReport struct {
Candidates []OrphanedPendingRelationEvidence `json:"candidates"`
OneEndpointMissing int64 `json:"one_endpoint_missing"`
LivePending int64 `json:"live_pending"`
}
OrphanedPendingRelationEvidenceReport is the read-only doctor evidence for unreviewable pending relations. Candidates and counts deliberately span all projects: a relation whose endpoints are both absent belongs to no project, so a project-scoped query could never return the rows it exists to surface.
type OrphanedPendingRelationReclassificationResult ¶
type OrphanedPendingRelationReclassificationResult struct {
Reclassified int64 `json:"reclassified"`
CandidatesAtApply int64 `json:"candidates_at_apply"`
OneEndpointMissing int64 `json:"one_endpoint_missing"`
LivePending int64 `json:"live_pending"`
BackupPath string `json:"backup_path,omitempty"`
}
OrphanedPendingRelationReclassificationResult reports one audited apply of the orphaned-pending-relations repair. Reclassified counts the rows actually moved into the `orphaned` disposition; CandidatesAtApply is the predicate re-derived inside the apply transaction, so a row judged between evidence and apply is never reclassified behind a reviewer's verdict.
type OrphanedSessionPlaceholder ¶
type OrphanedSessionPlaceholder struct {
SessionID string `json:"session_id"`
Project string `json:"project"`
ObservationCount int64 `json:"observation_count"`
StartedAt string `json:"started_at"`
}
OrphanedSessionPlaceholder is the minimal local-only session record used to restore an observation foreign-key reference without fabricating sync state.
type PassiveCaptureParams ¶
type PassiveCaptureParams struct {
SessionID string `json:"session_id"`
Content string `json:"content"`
Project string `json:"project,omitempty"`
Source string `json:"source,omitempty"` // e.g. "subagent-stop", "session-end"
Timings *WriteTimings `json:"-"`
}
PassiveCaptureParams holds the input for passive memory capture.
type PassiveCaptureResult ¶
type PassiveCaptureResult struct {
Extracted int `json:"extracted"` // Total learnings found in text
Saved int `json:"saved"` // New observations created
Duplicates int `json:"duplicates"` // Skipped because already existed
}
PassiveCaptureResult holds the output of passive memory capture.
type ProjectNameCount ¶
ProjectNameCount holds a project name and how many observations it has.
type ProjectRescueBlocked ¶
type ProjectRescueBlocked struct {
// Kind is "session", "observation", or "prompt".
Kind string `json:"kind"`
// ID is the session id or the decimal record id.
ID string `json:"id"`
// Reason is one of the RescueBlocked* constants.
Reason string `json:"reason"`
// OwnedBy is the conflicting project, when one is known.
OwnedBy string `json:"owned_by,omitempty"`
}
ProjectRescueBlocked names one row the rescue deliberately did not move, and why. It is what lets an operator tell "everything moved" apart from "some things were left behind" without guessing from counters.
type ProjectRescueParams ¶
type ProjectRescueParams struct {
TargetProject string
ObservationIDs []int64
SessionIDs []string
PromptIDs []int64
}
ProjectRescueParams identifies historical rows whose missing project ownership or blank same-project ownership mode was explicitly confirmed by an operator.
type ProjectRescueResult ¶
type ProjectRescueResult struct {
RescuedObservations int64 `json:"rescued_observations"`
RescuedSessions int64 `json:"rescued_sessions"`
RescuedPrompts int64 `json:"rescued_prompts"`
ConflictingRecords int64 `json:"conflicting_records"`
SkippedRecords int64 `json:"skipped_records"`
Journaled bool `json:"journaled"`
// Complete is true only when every requested row now belongs to the target
// project and nothing was left behind.
Complete bool `json:"complete"`
// Blocked lists exactly what was left behind, and why.
Blocked []ProjectRescueBlocked `json:"blocked"`
}
ProjectRescueResult reports local ownership recovery. Journaled means a canonical pending local mutation exists after the call, whether newly inserted or already pending; it does not imply a cloud acknowledgement.
func (ProjectRescueResult) Rescued ¶
func (r ProjectRescueResult) Rescued() int64
type ProjectStats ¶
type ProjectStats struct {
Name string `json:"name"`
ObservationCount int `json:"observation_count"`
SessionCount int `json:"session_count"`
PromptCount int `json:"prompt_count"`
Directories []string `json:"directories"` // unique directories from sessions
}
ProjectStats holds aggregate statistics for a single project.
type PromptSourcePreview ¶
type PromptSourcePreview struct {
SessionID string
SourceInboxID string
Project string
SyncID string
Kind string // live or deleted
}
PromptSourcePreview describes observed prompt data, not ownership or authority.
type PromptTombstone ¶
type PromptTombstone struct {
SyncID string `json:"sync_id"`
SessionID string `json:"session_id"`
Project *string `json:"project,omitempty"`
SourceInboxID string `json:"source_inbox_id,omitempty"`
DeletedAt string `json:"deleted_at"`
}
ExportData is the full serializable direct-backup dump of the engram database.
type PruneResult ¶
type PruneResult struct {
Project string `json:"project"`
SessionsDeleted int64 `json:"sessions_deleted"`
PromptsDeleted int64 `json:"prompts_deleted"`
}
PruneResult holds the outcome of pruning a single project.
type QuarantinedPulledSessionEvidence ¶
type QuarantinedPulledSessionEvidence struct {
SyncID string `json:"sync_id"`
TargetKey string `json:"target_key"`
Project string `json:"project"`
EntityKey string `json:"entity_key"`
Op string `json:"op"`
RemoteSeq int64 `json:"remote_seq"`
ReasonCode string `json:"reason_code"`
FirstSeenAt string `json:"first_seen_at"`
}
QuarantinedPulledSessionEvidence describes a pulled session mutation that was skipped because its identity is blank or inconsistent. The pull cursor advances past such a mutation instead of halting, so this row is the only record that remote data was dropped.
type Relation ¶
type Relation struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
SourceID string `json:"source_id"`
TargetID string `json:"target_id"`
Relation string `json:"relation"`
Reason *string `json:"reason,omitempty"`
Evidence *string `json:"evidence,omitempty"`
Confidence *float64 `json:"confidence,omitempty"`
JudgmentStatus string `json:"judgment_status"`
MarkedByActor *string `json:"marked_by_actor,omitempty"`
MarkedByKind *string `json:"marked_by_kind,omitempty"`
MarkedByModel *string `json:"marked_by_model,omitempty"`
SessionID *string `json:"session_id,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
// Annotation fields — populated by GetRelationsForObservations via LEFT JOIN.
// Excluded from JSON output (used only for in-process annotation building).
// REQ-005, REQ-012 | Design §7, §8.
SourceIntID int64 `json:"-"` // integer primary key of source observation
SourceTitle string `json:"-"` // title of source observation; empty if missing/deleted
SourceMissing bool `json:"-"` // true if source is soft-deleted or not found
TargetIntID int64 `json:"-"` // integer primary key of target observation
TargetTitle string `json:"-"` // title of target observation; empty if missing/deleted
TargetMissing bool `json:"-"` // true if target is soft-deleted or not found
}
Relation represents a row in memory_relations.
type RelationListItem ¶
type RelationListItem struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
Relation string `json:"relation"`
JudgmentStatus string `json:"judgment_status"`
SourceID string `json:"source_id"`
SourceTitle string `json:"source_title"`
TargetID string `json:"target_id"`
TargetTitle string `json:"target_title"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
RelationListItem represents a single row in a ListRelations result, enriched with observation titles via JOIN (no full Relation struct).
type RelationStats ¶
type RelationStats struct {
Project string `json:"project"`
ByRelation map[string]int `json:"by_relation"`
ByJudgmentStatus map[string]int `json:"by_judgment_status"`
DeferredCount int `json:"deferred"`
DeadCount int `json:"dead"`
}
RelationStats holds aggregate counts of relations for a project.
type ReplayDeferredResult ¶
ReplayDeferredResult holds counts returned by ReplayDeferred.
type ReviewClearEvent ¶ added in v3.3.0
ReviewClearEvent is local-only intent; it is never part of cloud payloads.
type SQLiteLockSnapshot ¶
type SQLiteLockSnapshot struct {
JournalMode string `json:"journal_mode"`
BusyTimeoutMS int `json:"busy_timeout_ms"`
CheckpointBusy int `json:"checkpoint_busy"`
CheckpointLog int `json:"checkpoint_log"`
CheckpointedFrames int `json:"checkpointed_frames"`
}
SQLiteLockSnapshot captures conservative SQLite lock/contention indicators. wal_checkpoint(PASSIVE) is an observational probe for this diagnostic surface; callers must not interpret it as a repair action.
type SaveRelationParams ¶
type SaveRelationParams struct {
// SyncID is the unique identifier for this relation row (format: rel-<16hex>).
SyncID string
// SourceID is the TEXT sync_id of the source observation.
SourceID string
// TargetID is the TEXT sync_id of the target observation.
TargetID string
}
SaveRelationParams holds the inputs for SaveRelation.
type ScanOptions ¶
type ScanOptions struct {
// Project is required — scopes the observation walk.
Project string
// Since filters observations to created_at >= Since. Zero value means no filter.
Since time.Time
// Limit caps this scan page. Zero uses DefaultScanLimit.
Limit int
// Cursor resumes after this observation ID. Zero starts from the first row.
Cursor int64
// Apply controls whether new relation rows are inserted.
// When false (dry-run, default), candidates are reported but not written.
Apply bool
// MaxInsert caps the number of new relation rows inserted in a single Apply run.
// Default 100 when 0 or negative.
MaxInsert int
// Semantic controls whether the worker pool LLM-judge step runs.
// When false (default), ScanProject behaves exactly as Phase 3.
Semantic bool
// Concurrency is the worker pool size for semantic calls. Default 5 if 0.
Concurrency int
// TimeoutPerCall is the per-pair context timeout for runner.Compare.
// Default 60s if zero.
TimeoutPerCall time.Duration
// MaxSemantic caps the number of LLM calls in a single semantic scan. Default 100 if 0.
MaxSemantic int
// Runner is the SemanticRunner used for LLM comparison. Required when Semantic=true.
Runner SemanticRunner
// BuildPrompt constructs the LLM prompt for a given (a, b) pair.
// Required when Semantic=true.
BuildPrompt func(a, b ObservationSnippet) string
}
ScanOptions controls a ScanProject call.
type ScanResult ¶
type ScanResult struct {
Project string `json:"project"`
Inspected int `json:"inspected"`
RankedQueries int `json:"ranked_queries"`
CandidatesFound int `json:"candidates_found"`
NextCursor *int64 `json:"next_cursor,omitempty"`
AlreadyRelated int `json:"already_related"`
RelationsInserted int `json:"inserted"`
// Capped means work remains but this result has no continuation cursor. Re-run
// the same incoming observation cursor with a higher applicable cap.
Capped bool `json:"capped"`
DryRun bool `json:"dry_run"`
// Semantic counters — populated only when ScanOptions.Semantic is true.
// Zero-value is safe for existing JSON consumers.
SemanticJudged int `json:"semantic_judged"`
SemanticSkipped int `json:"semantic_skipped"`
SemanticErrors int `json:"semantic_errors"`
}
ScanResult holds the output of a ScanProject call.
type SearchOptions ¶
type SearchPreviewResult ¶
type SearchPreviewResult struct {
ID int64 `json:"id"`
SyncID string `json:"sync_id"`
Type string `json:"type"`
Title string `json:"title"`
Preview string `json:"preview"`
Truncated bool `json:"truncated"`
Project *string `json:"project,omitempty"`
TopicKey *string `json:"topic_key,omitempty"`
Scope string `json:"scope"`
ReviewAfter *string `json:"review_after,omitempty"`
Pinned bool `json:"-"`
CreatedAt string `json:"created_at"`
Rank float64 `json:"rank"`
}
SearchPreviewResult is the bounded result shape used by preview-only callers. Content is deliberately excluded so those callers do not hydrate full bodies.
func (SearchPreviewResult) State ¶
func (r SearchPreviewResult) State() string
State returns the virtual lifecycle state derived from review_after.
type SearchResult ¶
type SearchResult struct {
Observation
Rank float64 `json:"rank"`
}
type SemanticRunner ¶
type SemanticRunner interface {
Compare(ctx context.Context, prompt string) (SemanticVerdict, error)
}
SemanticRunner is a duck-typed interface satisfied by *llm.ClaudeRunner and *llm.OpenCodeRunner without requiring this package to import internal/llm. Any value whose Compare method matches this signature satisfies the interface.
type SemanticVerdict ¶
type SemanticVerdict struct {
// Relation is one of: conflicts_with, supersedes, scoped, related, compatible, not_conflict.
Relation string
// Confidence is a 0.0–1.0 score from the runner.
Confidence float64
// Reasoning is a short human-readable explanation (≤200 chars).
Reasoning string
// Model is the model identifier reported by the CLI (e.g. "claude-haiku-4-5").
Model string
// DurationMS is wall-clock time for the CLI invocation in milliseconds.
DurationMS int64
}
SemanticVerdict is the result of a semantic comparison between two observations. It mirrors llm.Verdict but lives in this package to avoid a store→llm import cycle.
type Session ¶
type Session struct {
ID string `json:"id"`
Project string `json:"project"`
OwnershipMode string `json:"ownership_mode,omitempty"`
Directory string `json:"directory"`
StartedAt string `json:"started_at"`
EndedAt *string `json:"ended_at,omitempty"`
Summary *string `json:"summary,omitempty"`
RuntimeLeaseExpiresAt *string `json:"-"`
}
type SessionIdentityRepairPlan ¶
type SessionIdentityRepairPlan struct {
SourceID string `json:"source_id"`
ReplacementID string `json:"replacement_id"`
Project string `json:"project"`
Observations int64 `json:"observations"`
Prompts int64 `json:"prompts"`
RetiredMutations int64 `json:"retired_mutations"`
Enrolled bool `json:"enrolled"`
// contains filtered or unexported fields
}
SessionIdentityRepairPlan records the read-only impact of replacing one blank identity. Apply rechecks the complete evidence under the SQLite writer lock.
type SessionIdentityRepairResult ¶
type SessionIdentityRepairResult struct {
SessionIdentityRepairPlan
BackupPath string `json:"backup_path"`
PublishedMutations int64 `json:"published_mutations"`
}
type SessionProjectConflictError ¶
type SessionProjectConflictError struct {
SessionID string
OwnerProject string
RequestedProject string
}
SessionProjectConflictError identifies a strict registration that would reuse a persisted session under another project while preserving errors.Is behavior.
func (*SessionProjectConflictError) Error ¶
func (e *SessionProjectConflictError) Error() string
func (*SessionProjectConflictError) Unwrap ¶
func (e *SessionProjectConflictError) Unwrap() error
type SessionProjectReclassificationResult ¶
type SessionProjectReclassificationResult struct {
Counts SessionProjectReclassificationCounts
BackupPath string
}
type SessionSummary ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
func (*Store) AckSyncMutationSeqs ¶
AckSyncMutationSeqs acknowledges specific mutation sequence numbers without requiring them to be contiguous.
func (*Store) AckSyncMutations ¶
func (*Store) AcquireSyncLease ¶
func (*Store) ActiveRuntimeSessions ¶
MostRecentActiveSession resolves the active (un-ended) session for a project from the persisted sessions table. It returns the session ID and ok=true when such a session exists, or ok=false when none does.
This is the cross-process resolution that fixes issue #386: the SessionStart hook registers a UUID session via the HTTP server (POST /sessions) in one process, while mem_save runs in the separate MCP (stdio) process. The two share only the SQLite store, so the active session must be read from disk — never from in-memory state.
Candidate rules:
- Scope to the (normalized) project.
- Scope to the current runtime directory.
- Require ended_at IS NULL — ended sessions are never returned.
- A nonblank runtime lease is authoritative: return it only while it is valid and unexpired. Expired or malformed leases are excluded.
- A live lease suppresses unleased legacy candidates in its directory only. Where no live lease exists, preserve the legacy effective-activity window: the latest observation, falling back to started_at, must be recent.
- Exclude the manual-save fallback sessions (id LIKE 'manual-save%'); those are created by the fallback path itself and must not be resolved as "the active session", which would make resolution circular.
ActiveRuntimeSessions returns active, non-manual sessions for a project and runtime directories. The directories narrow candidates; callers must not treat them as session identity. Selection is read-only: it never ends or repairs historical rows.
func (*Store) AddObservation ¶
func (s *Store) AddObservation(p AddObservationParams) (int64, error)
AddObservation preserves the legacy ID-only API for callers that do not need to distinguish a new save from an exact operation replay.
func (*Store) AddObservationWithResult ¶ added in v3.3.0
func (s *Store) AddObservationWithResult(p AddObservationParams) (AddObservationResult, error)
AddObservationWithResult persists an observation or returns an exact replay outcome from the operation ledger in the same transaction.
func (*Store) AddPromptIfMissing ¶
func (s *Store) AddPromptIfMissing(p AddPromptParams) (int64, bool, error)
func (*Store) AddPromptWithResult ¶
func (s *Store) AddPromptWithResult(p AddPromptParams) (int64, bool, error)
AddPromptWithResult reports whether a prompt was inserted rather than replayed.
func (*Store) AllObservations ¶
func (s *Store) AllObservations(project, scope string, limit int) ([]Observation, error)
AllObservations returns recent observations ordered by most recent first (for TUI browsing).
func (*Store) AllSessions ¶
func (s *Store) AllSessions(project string, limit int) ([]SessionSummary, error)
AllSessions returns recent sessions ordered by most recent first (for TUI browsing). A database upgraded from the schema where sessions.project was nullable still carries rows that identify no project, so the column is read through ifnull(): an unscoped listing reads every session row and must not die on one of them.
func (*Store) ApplyLegacyEmptyPromptDiscard ¶
func (s *Store) ApplyLegacyEmptyPromptDiscard(plan LegacyEmptyPromptDiscardPlan, backupPath string) (LegacyEmptyPromptDiscardResult, error)
ApplyLegacyEmptyPromptDiscard backs up first, then independently rederives eligibility inside the single mutation transaction. A changed/repeated plan fails with stale_plan and queues no duplicate. A preflight stale plan creates no backup; a change after backup may leave that backup on disk. There is no fencing of concurrent/in-flight exporters and no remote delivery guarantee.
func (*Store) ApplyPulledChunk ¶
func (s *Store) ApplyPulledChunk(targetKey, chunkID string, mutations []SyncMutation) error
ApplyPulledChunk atomically applies all mutations contained in a pulled chunk under the local import domain and records the chunk as synced in the same transaction. This guarantees retry safety: a failed chunk import leaves no partial semantic mutations.
It shares ApplyPulledMutation's skip-plus-evidence rule for invalid session and observation identities, plus deferred handling for observation and prompt upserts whose parent session is absent, so either condition cannot block the chunk forever. A payload that does not even decode stays fail-closed and rolls back the whole chunk, because an undecodable payload is a transport-level fault rather than known-corrupt historical data.
func (*Store) ApplyPulledChunkForDomain ¶
func (s *Store) ApplyPulledChunkForDomain(targetKey, chunkID string, mutations []SyncMutation, cloud bool) error
ApplyPulledChunkForDomain is ApplyPulledChunk with an explicit import domain. The domain must be carried explicitly by the caller; it is never inferred from the target key, because a cloud chunk's tracking key and its admission rule answer different questions. cloud=true runs the strict cloud-inbound directory admission (validatePulledSessionDirectory), so a shared session upsert with a blank or missing directory fails the whole chunk atomically — no session persisted, chunk not recorded. Only per-mutation Cloud pull admits a blank or omitted directory (validatePulledSessionDirectoryCloudMutation). cloud=false keeps the local partial-session domain: blank directories are accepted and the skip-plus-evidence quarantine ladder behaves exactly as before.
func (*Store) ApplyPulledMutation ¶
func (s *Store) ApplyPulledMutation(targetKey string, mutation SyncMutation) error
ApplyPulledMutation applies one remote mutation and advances the pull cursor.
Session and observation identity semantics are skip-plus-evidence, not fail-closed. A blank or inconsistent session identity, or an inconsistent observation identity, in a pulled mutation is quarantined through deadLetterPulledIdentityTx and the cursor still advances past it. Failing closed here would be a permanent retry loop: immutable remote data cannot become valid through local retries, so halting would pin the cursor forever and block every later mutation behind it. Quarantining keeps the dropped data visible in `engram conflicts deferred`.
Every other apply failure keeps its existing fail-closed behavior.
func (*Store) ApplyPulledMutationPreservingSyncState ¶
func (s *Store) ApplyPulledMutationPreservingSyncState(targetKey string, mutation SyncMutation) error
ApplyPulledMutationPreservingSyncState advances the pull cursor without changing the current lifecycle, reason, or failure state. It is used when inbound replication succeeds while outbound sync remains policy-blocked.
func (*Store) ApplySessionIdentityRepair ¶
func (s *Store) ApplySessionIdentityRepair(plan SessionIdentityRepairPlan) (SessionIdentityRepairResult, error)
ApplySessionIdentityRepair leaves its pre-apply backup on disk even if the transaction fails. No corrected mutation is published before commit.
func (*Store) ApplySessionProjectReclassification ¶
func (s *Store) ApplySessionProjectReclassification(actions []SessionProjectReclassification) (SessionProjectReclassificationResult, error)
func (*Store) BackupSQLite ¶
func (*Store) CanRollbackCloudUpgrade ¶
func (*Store) CapturePromptForSave ¶ added in v3.2.0
func (s *Store) CapturePromptForSave(enabled *bool, prompt AddPromptParams) error
CapturePromptForSave applies the shared per-save prompt policy. An omitted option enables capture; false or missing prompt content is a no-op. The caller supplies the current prompt for the observation's session/project; persisted history is not a substitute for current runtime context. Call only after a successful observation save, and treat capture errors as nonfatal. This stores an independent prompt row, not an observation-ID link.
func (*Store) CleanupForeignSyncTargets ¶
func (s *Store) CleanupForeignSyncTargets(apply bool) (ForeignSyncTargetCleanupReport, error)
CleanupForeignSyncTargets retargets pending foreign rows to cloud and removes their state only when no terminal journal rows remain.
func (*Store) ClearCloudUpgradeState ¶
func (*Store) CloudSyncSummary ¶
func (s *Store) CloudSyncSummary() (CloudSyncSummary, error)
CloudSyncSummary returns status across project-scoped cloud targets only. It deliberately excludes the legacy global cloud target because explicit cloud sync records state under cloud:<project>, and the reserved cloud inbox target because the inbox is not a project.
func (*Store) ConfirmPromptSourceAttestation ¶
func (s *Store) ConfirmPromptSourceAttestation(remoteTarget string, preview PromptSourcePreview, assertedOwner string, remoteAttestationID int64) error
ConfirmPromptSourceAttestation records an explicit owner assertion only after the caller reports remote attestation success. The observed tuple is not ownership proof. A tuple recheck cannot detect change-away-and-back without a revision; autosync must revalidate cloud authorization before using it. Newer IDs are safe only within the same remote target while it retains the same Postgres identity sequence. Callers must supply an endpoint identity independent of local sync TargetKey and recheck cloud state before use.
func (*Store) ContentTruncation ¶
func (s *Store) ContentTruncation(content string) TruncationMetadata
ContentTruncation returns the byte-based truncation metadata used by storage writes.
func (*Store) CountDeferredAndDead ¶
CountDeferredAndDead returns global administrative totals, including legacy unscoped rows that normal scoped imports intentionally leave untouched.
func (*Store) CountDeferredAndDeadForScope ¶
func (s *Store) CountDeferredAndDeadForScope(targetKey, project string) (deferred, dead int, err error)
CountDeferredAndDeadForScope returns queue totals for an optional target and project. Scoped totals exclude legacy-unscoped rows; empty filters return the global administrative totals.
func (*Store) CountObservationsForProject ¶
CountObservationsForProject returns the number of non-deleted observations for the given project name. Used by handleSave for the similar-project warning instead of the heavier ListProjectsWithStats.
func (*Store) CountPendingNonEnrolledSyncMutations ¶
func (s *Store) CountPendingNonEnrolledSyncMutations(targetKey string) ([]PendingSyncMutationProjectCount, error)
func (*Store) CountRelationSyncMutations ¶
CountRelationSyncMutations returns the number of sync_mutations rows whose entity is NOT 'session', 'observation', or 'prompt'. Used by integration tests to verify the enrollment gate: an UNENROLLED project must never enqueue relation sync mutations (the enqueue in JudgeBySemantic/JudgeRelation is guarded by an enrollment check). The test that calls this uses an unenrolled store, so the count must remain zero.
Note: relation sync mutations ARE valid for enrolled projects (#313/#379/#383 enabled cloud relation sync; #496 extends it with backfill). This function is not a blanket "relations are local-only" check — it is an enrollment-gate regression guard scoped to the unenrolled test context that uses it.
func (*Store) CountRelations ¶
func (s *Store) CountRelations(opts ListRelationsOptions) (int, error)
CountRelations returns the total number of relation rows matching opts. Uses the same WHERE conditions as ListRelations.
func (*Store) CreateSession ¶
func (*Store) CreateSessionWithOwnershipMode ¶
CreateSessionWithOwnershipMode creates a session with an explicit persisted ownership policy. CreateSession remains the compatibility wrapper for shared runtime sessions.
func (*Store) DB ¶
DB returns the underlying *sql.DB. Intended for test helpers and integration tests that need to inject raw rows (e.g. legacy data with non-normalized project names) without going through the Store's public API.
func (*Store) DeleteObservation ¶
func (*Store) DeleteObservationForProject ¶
DeleteObservationForProject asserts ownership before soft or hard deletion in the same transaction.
func (*Store) DeleteProject ¶
func (s *Store) DeleteProject(project string, hardDelete bool) (*DeleteProjectResult, error)
DeleteProject removes all data associated with a project in a single transaction.
When hardDelete is true: observation rows are permanently removed, prompts are hard-deleted, and sessions are hard-deleted. memory_relations that reference any removed observation are marked orphaned (audit history).
When hardDelete is false: observations are soft-deleted (deleted_at set), and prompts are hard-deleted. Sessions are NOT removed in this path because observations.session_id is a NOT NULL FK to sessions — removing sessions while soft-deleted observation rows still reference them would violate the FK constraint. The session rows remain and can be cleaned up with engram delete session <id> once the observations are purged.
Returns ErrProjectNotFound when no sessions or observations exist for the given project name.
func (*Store) DeletePrompt ¶
DeletePrompt hard-deletes a single prompt by ID and records a sync tombstone. It returns ErrPromptNotFound if no prompt with that ID exists.
func (*Store) DeleteSession ¶
DeleteSession hard-deletes a session and its prompts. It returns ErrSessionHasObservations if the session has any observations (including soft-deleted ones) to prevent orphaned rows. It returns ErrSessionNotFound if no session with that ID exists.
When the session belongs to an enrolled project, this operation also enqueues a session/delete mutation so cloud replicas can remove the session.
func (*Store) DetectProject ¶ added in v3.1.0
func (s *Store) DetectProject(directory string) project.DetectionResult
DetectProject applies the first-Git-binding precaution using this local store.
func (*Store) DiagnoseCloudUpgradeLegacyMutations ¶
func (s *Store) DiagnoseCloudUpgradeLegacyMutations(project string) (CloudUpgradeLegacyMutationReport, error)
func (*Store) EndRuntimeSession ¶ added in v3.2.0
EndRuntimeSession resolves and ends within one writer reservation. Generic EndSession retains its exact-ID behavior for all existing callers.
func (*Store) EnqueueDeferredRelation ¶
func (s *Store) EnqueueDeferredRelation(targetKey string, mutation SyncMutation) error
EnqueueDeferredRelation durably records a relation upsert as deferred retry state before its chunk applies (issue #1135): when the cloud import skips an edge as permanently unsatisfiable, this row is what keeps the skip recoverable — ReplayDeferredForScope re-applies the edge once its endpoint reappears, and the apply's success path deletes the row. It writes exactly the row recordRelationApplyFailureTx writes for a deferred FK miss, so a later delivery of the same edge collapses onto this row instead of queueing it twice. Re-enqueueing a live deferred row never resets its retry state; re-enqueueing a row that died at the replay retry cap re-arms it to 'deferred' with retry_count reset to 0, giving the edge a fresh bounded replay window. Hash-keyed dead evidence is never re-armed.
func (*Store) EnrollProject ¶
EnrollProject registers a project for cloud sync. Idempotent — re-enrolling an already-enrolled project is a no-op.
func (*Store) EnsureEnrolledProjectSyncMutations ¶
EnsureEnrolledProjectSyncMutations repairs legacy enrolled-project journal entries before a sync operation reads them. A successful repair is memoized for this Store's lifetime; failures are returned to callers and retried by a later synchronization attempt.
func (*Store) EstimateSessionProjectReclassification ¶
func (s *Store) EstimateSessionProjectReclassification(actions []SessionProjectReclassification) (SessionProjectReclassificationCounts, error)
func (*Store) Export ¶
func (s *Store) Export() (*ExportData, error)
func (*Store) ExportLocalDeleteTombstones ¶
func (s *Store) ExportLocalDeleteTombstones(project string) ([]SyncMutation, error)
ExportLocalDeleteTombstones projects locally retained hard-delete intent into canonical mutations.
func (*Store) ExportProject ¶
func (s *Store) ExportProject(project string) (*ExportData, error)
ExportProject returns an export restricted to records relevant to a single normalized project. This avoids full-database exports when only one project needs to sync.
func (*Store) ExportRelationMutations ¶
func (s *Store) ExportRelationMutations(project string) ([]SyncMutation, error)
ExportRelationMutations returns relation upsert mutations for non-orphaned relation rows whose source and target observations are available locally.
func (*Store) ExportReviewClearEvents ¶ added in v3.3.0
func (s *Store) ExportReviewClearEvents() ([]ReviewClearEvent, error)
ExportReviewClearEvents returns retained events whose observation is still live and undated. Restoring a date or deleting the observation suppresses it.
func (*Store) FindCandidates ¶
func (s *Store) FindCandidates(savedID int64, opts CandidateOptions) ([]Candidate, error)
FindCandidates runs a post-transaction FTS5 candidate query for the given savedID and returns at most opts.Limit candidates satisfying the rank predicate and, when opted in, the save relevance gate.
For each candidate, a pending memory_relations row is inserted and the row's sync_id is exposed as Candidate.JudgmentID. Candidates with an existing judged relation in either direction are excluded.
Errors from this method are expected to be logged and swallowed by callers — detection failure must never fail the originating save.
func (*Store) FormatCompactionContext ¶
FormatCompactionContext returns runtime context that is strictly limited to one persisted session. The session's project is derived from the store and is never supplied by the caller.
func (*Store) FormatContext ¶
FormatContext is a thin wrapper around FormatContextWithOptions using a zero-value ContextOptions, preserving the pre-ContextOptions call signature so existing callers and tests keep working unchanged.
func (*Store) FormatContextWithOptions ¶
func (s *Store) FormatContextWithOptions(project, scope string, opts ContextOptions) (string, error)
FormatContextWithOptions renders the "## Memory from Previous Sessions" markdown block for the given project/scope, honoring the per-section caps and Compact rendering in opts. See ContextOptions for the cap convention.
func (*Store) GenerationError ¶ added in v3.1.0
GenerationError returns only an already observed permanent invalidation. It performs no filesystem probes and does not initiate a generation check.
func (*Store) GetCloudUpgradeState ¶
func (s *Store) GetCloudUpgradeState(project string) (*CloudUpgradeState, error)
func (*Store) GetDeferred ¶
func (s *Store) GetDeferred(syncID string) (DeferredRow, error)
GetDeferred returns a single row from sync_apply_deferred by sync_id. Returns an error wrapping "not found" when no row exists (matches FindCandidates style).
func (*Store) GetObservation ¶
func (s *Store) GetObservation(id int64) (*Observation, error)
func (*Store) GetObservationBySyncID ¶
func (s *Store) GetObservationBySyncID(syncID string) (*Observation, error)
func (*Store) GetObservationSaveResult ¶ added in v3.3.0
GetObservationSaveResult returns the committed observation ID for a previous observation save operation, if any. It is intended for clients that lost the response and want to recover without replaying the write. A zero result with a nil error means no operation was recorded. ErrObservationOperationExpired means the operation is retained but its observation was deleted, so it must not be replayed.
func (*Store) GetObservationVersionPage ¶ added in v3.1.0
func (s *Store) GetObservationVersionPage(id int64, limit int, cursor int64) (ObservationVersionPage, error)
GetObservationVersionPage returns one bounded page of an observation's version history, oldest first (ascending version number) so rendering stays chronological. Cursor 0 starts from the most recent versions; a cursor from a previous page's NextCursor (set only when HasMore is true) fetches the older page continuing before it. Total is the full stored count and is truthful even when the page is truncated. Versions survive soft deletes and a missing or untouched observation yields an empty page with Total 0, never an error.
limit must be between 1 and MaxObservationVersionPageSize; cursor must be non-negative.
func (*Store) GetObservationVersions ¶ added in v3.1.0
func (s *Store) GetObservationVersions(id int64) ([]ObservationVersion, error)
GetObservationVersions returns every captured version for an observation, oldest first, numbering starting at 1. Versions survive soft deletes: they are immutable history, read directly from the version table. A missing or untouched observation yields an empty slice, never an error.
Callers serving one bounded response should prefer GetObservationVersionPage, which never materializes the full unbounded history.
func (*Store) GetRelation ¶
GetRelation retrieves a single relation row by its sync_id.
func (*Store) GetRelationByIntID ¶
func (s *Store) GetRelationByIntID(id int64) (*RelationListItem, error)
GetRelationByIntID retrieves a single relation enriched with source/target observation titles by its integer primary key. Returns a *RelationListItem (same shape as ListRelations rows) so HTTP handlers share one response type. Returns an error wrapping "not found" when the id does not exist.
func (*Store) GetRelationStats ¶
func (s *Store) GetRelationStats(project string) (RelationStats, error)
GetRelationStats returns aggregate counts for a project's relations plus the deferred and dead queue totals. Two queries are executed: one GROUP BY and one delegated to CountDeferredAndDead.
func (*Store) GetRelationsForObservations ¶
func (s *Store) GetRelationsForObservations(syncIDs []string) (map[string]ObservationRelations, error)
GetRelationsForObservations returns a map of observation sync_id → ObservationRelations for all observations in syncIDs. Relations with judgment_status='orphaned' are excluded.
A single SQL query with IN/OR and LEFT JOINs avoids N+1 queries. The returned Relation values are enriched with source/target integer IDs and titles via LEFT JOIN, used by the MCP annotation builder (REQ-005, REQ-012). Missing or soft-deleted observations set the corresponding *Missing flag to true.
func (*Store) GetRelationsForObservationsContext ¶
func (s *Store) GetRelationsForObservationsContext(ctx context.Context, syncIDs []string) (map[string]ObservationRelations, error)
GetRelationsForObservationsContext enriches observations with relations while honoring cancellation from the caller, including while materializing rows.
func (*Store) GetSyncedChunks ¶
GetSyncedChunks returns local-target chunk IDs for backwards compatibility.
func (*Store) GetSyncedChunksForTarget ¶
GetSyncedChunksForTarget returns chunk IDs tracked for a specific sync target.
func (*Store) HasObservationBySyncIDAnyState ¶
HasObservationBySyncIDAnyState reports whether an observation with the given sync_id exists locally in any deletion state, tombstones included. It mirrors the tombstone-inclusive relation FK precondition (getObservationBySyncIDTx with includeDeleted) for callers outside Store transactions and answers through the idx_obs_sync_id index without materializing an export.
func (*Store) HasPendingSyncMutationsForProject ¶
func (*Store) HasProjectOwnedSessions ¶
HasProjectOwnedSessions reports whether any session requires ownership-mode sync.
func (*Store) HasProjectOwnedSessionsForProject ¶
HasProjectOwnedSessionsForProject reports whether project requires ownership-mode sync.
func (*Store) Import ¶
func (s *Store) Import(data *ExportData) (*ImportResult, error)
func (*Store) InspectProject ¶ added in v3.1.0
func (s *Store) InspectProject(directory string) project.DetectionResult
InspectProject cannot create a binding or elevate an unbound Git candidate.
func (*Store) InstanceID ¶
InstanceID returns this store's stable local-server identity.
func (*Store) JudgeBySemantic ¶
func (s *Store) JudgeBySemantic(p JudgeBySemanticParams) (string, error)
JudgeBySemantic persists a semantic verdict produced by an AgentRunner into the memory_relations table with system provenance (marked_by_kind="system", marked_by_actor="engram", marked_by_model=params.Model).
Idempotency: if a row already exists for (source_id, target_id) in either direction, the existing row is updated (UPSERT). The returned sync_id is always the canonical row's sync_id.
Returns ErrCrossProjectRelation when source and target belong to different projects. Returns a validation error when required fields are missing or Confidence is out of [0.0, 1.0].
func (*Store) JudgeRelation ¶
func (s *Store) JudgeRelation(p JudgeRelationParams) (*Relation, error)
JudgeRelation records a verdict on an existing pending relation row.
Re-judge policy: OVERWRITE the existing row (design decision). The updated row is returned on success.
Phase 2: wraps the UPDATE in a transaction to atomically enqueue a sync mutation when the source observation's project is enrolled for cloud sync. Returns ErrCrossProjectRelation if source and target belong to different projects.
Returns an error if the judgment_id is unknown or the relation verb is invalid.
func (*Store) ListDeferred ¶
func (s *Store) ListDeferred(opts ListDeferredOptions) ([]DeferredRow, error)
ListDeferred returns rows from sync_apply_deferred with optional status filter and pagination. The payload field is decoded to map[string]any; on malformed JSON, PayloadValid is false and PayloadRaw is preserved.
func (*Store) ListDeferredProjectsForTarget ¶
func (*Store) ListDiagnosticObservationRequiredFields ¶
func (s *Store) ListDiagnosticObservationRequiredFields(project string) ([]ObservationRequiredFieldsEvidence, error)
ListDiagnosticObservationRequiredFields reports active source observations whose cloud-required title, content, or type is NULL, empty, or whitespace. It is deliberately independent of sync_mutations so doctor can find source corruption even when no journal row remains.
func (*Store) ListDiagnosticSessions ¶
func (s *Store) ListDiagnosticSessions(project string) ([]DiagnosticSessionEvidence, error)
ListDiagnosticSessions returns session evidence scoped by project when provided. The query is read-only and ordered for deterministic diagnostics.
project is read through ifnull() for the same reason directory already is: a database upgraded from the schema where sessions.project was nullable still carries NULL ownership, and no migration rewrites the column. Scanning that raw would abort every diagnostic on exactly the databases doctor exists to report on. NULL and blank both mean "identifies no project" to every caller here, so collapsing them to the empty string loses nothing.
func (*Store) ListEnrolledProjects ¶
func (s *Store) ListEnrolledProjects() ([]EnrolledProject, error)
ListEnrolledProjects returns all projects currently enrolled for cloud sync, ordered alphabetically by project name.
func (*Store) ListInvalidSessionIdentityEvidence ¶
func (s *Store) ListInvalidSessionIdentityEvidence(project string) ([]InvalidSessionIdentityEvidence, error)
ListInvalidSessionIdentityEvidence reports blank source session IDs together with affected references and invalid session journal entries. It is read-only.
The source-row predicate uses the shared whitespace trim set rather than SQLite's bare trim(), so a legacy identity made of tabs, newlines or carriage returns cannot bypass the scan while still being rejected by the Go guards.
project is read through ifnull() because a corrupt session row on an upgraded database can also carry the legacy NULL ownership; reporting the corrupt identity must not depend on whether that row's project survived the upgrade.
func (*Store) ListObservationSyncPayloads ¶
ListObservationSyncPayloads returns the decoded payloads of all sync_mutations rows whose entity = 'observation'. Used by integration tests to assert that local-only observation columns (expires_at, embedding*) remain absent from the sync wire format; review_after is replicated.
func (*Store) ListOrphanedObservationSessionEvidence ¶
func (s *Store) ListOrphanedObservationSessionEvidence(project string) ([]OrphanedObservationSessionEvidence, error)
ListOrphanedObservationSessionEvidence reports grouped observation references whose parent sessions are absent. It includes soft-deleted observations because they remain local data that can block inspection or recovery.
func (*Store) ListOrphanedPendingRelationEvidence ¶
func (s *Store) ListOrphanedPendingRelationEvidence() (OrphanedPendingRelationEvidenceReport, error)
ListOrphanedPendingRelationEvidence reports legacy pending relation rows whose source and target observations are both absent from the active observation set. It additionally counts pending rows missing exactly one endpoint and fully live pending rows, so a finding can show that a repair will not touch still-reviewable relations. The listing is deliberately unscoped: a relation with both endpoints absent belongs to no project.
func (*Store) ListOrphanedPendingRelationEvidenceBounded ¶
func (s *Store) ListOrphanedPendingRelationEvidenceBounded(limit int) (OrphanedPendingRelationEvidenceBounded, error)
ListOrphanedPendingRelationEvidenceBounded reports the same evidence as ListOrphanedPendingRelationEvidence with the candidate rows bounded: it returns the total candidate count plus only the first limit evidence rows, so the doctor check can render a large legacy backlog without materializing every candidate. The full candidate set remains available to the repair planner and apply path through ListOrphanedPendingRelationEvidence. The listing is deliberately unscoped: a relation with both endpoints absent belongs to no project.
func (*Store) ListPendingProjectMutations ¶
func (s *Store) ListPendingProjectMutations(project string) ([]SyncMutation, error)
ListPendingProjectMutations returns pending cloud mutations for one project, or all projects when project is empty, without enrollment filtering. Doctor needs to diagnose blocked metadata even when a project is not enrolled.
func (*Store) ListPendingSyncMutations ¶
func (s *Store) ListPendingSyncMutations(targetKey string, limit int) ([]SyncMutation, error)
func (*Store) ListPendingSyncMutationsAfterSeq ¶
func (*Store) ListProjectNames ¶
ListProjectNames returns all distinct project names from observations, ordered alphabetically. Used for fuzzy matching and consolidation.
func (*Store) ListProjectsForCloudEnrollment ¶
ListProjectsForCloudEnrollment returns every local identity that can be enrolled, normalized and ordered deterministically for the cloud TUI.
func (*Store) ListProjectsWithStats ¶
func (s *Store) ListProjectsWithStats() ([]ProjectStats, error)
ListProjectsWithStats returns all projects with aggregated counts. Ordered by observation count descending.
func (*Store) ListQuarantinedPulledSessionEvidence ¶
func (s *Store) ListQuarantinedPulledSessionEvidence(project string) ([]QuarantinedPulledSessionEvidence, error)
ListQuarantinedPulledSessionEvidence returns the pulled session mutations the apply path skipped because their identity is blank or inconsistent.
The pull deliberately does not fail closed on these mutations: halting would pin the cursor forever on a historical chunk written before the identity rule existed. Instead each one is quarantined here so doctor can report exactly what remote data was dropped. It is read-only.
func (*Store) ListRelations ¶
func (s *Store) ListRelations(opts ListRelationsOptions) ([]RelationListItem, error)
ListRelations returns a paginated list of relation rows filtered by the given options. Project filtering is done via LEFT JOIN to observations (no schema change). Uses idx_memrel_status_created for efficient status+date ordering.
func (*Store) ListSyncStates ¶
func (s *Store) ListSyncStates() ([]SyncTargetState, error)
ListSyncStates returns every sync_state row with its pending mutation count, ordered by target key. Doctor uses it to verify the closed set of legitimate sync targets.
func (*Store) LocalPromptCreationIdentity ¶
func (s *Store) LocalPromptCreationIdentity(syncID string) (session, inbox, project string, eligible bool, err error)
LocalPromptCreationIdentity returns verified local creation identity by exact sync ID. A tombstone is eligible only when its separately recorded local origin matches.
func (*Store) LocalSessionProvenance ¶
LocalSessionProvenance returns the persisted owner and whether this store independently created the session. An unknown or absent row is never eligible for automatic cloud registration; project ownership alone is not proof.
func (*Store) MarkReviewed ¶
MarkReviewed resets an observation's review_after using its type's configured decay offset. Types without a decay offset return to a NULL review_after value. The reset and its sync upsert are committed atomically.
func (*Store) MarkReviewedForProject ¶
MarkReviewedForProject resets an observation's review lifecycle only when it remains owned by project at the mutation boundary.
func (*Store) MarkSyncAuthRequired ¶
func (*Store) MarkSyncBlocked ¶
func (*Store) MarkSyncBlockedAfterSuccess ¶
MarkSyncBlockedAfterSuccess atomically records a successful inbound poll while retaining the final degraded state that blocks outbound replication.
func (*Store) MarkSyncFailure ¶
func (*Store) MarkSyncFailureWithReason ¶
func (s *Store) MarkSyncFailureWithReason(targetKey, reasonCode, message string, backoffUntil time.Time) error
MarkSyncFailureWithReason records a degraded failure while preserving its reason code.
func (*Store) MarkSyncHealthy ¶
func (*Store) MarkSyncPaused ¶
func (*Store) MarkSyncPending ¶
func (*Store) MaxObservationLength ¶
MaxObservationLength returns the configured maximum content length for observations.
func (*Store) MaxPendingSyncMutationSeq ¶
MaxPendingSyncMutationSeq returns the highest sequence eligible for pending sync on targetKey, or zero when none exists. Like ListPendingSyncMutationsAfterSeq, only unacknowledged pending mutations for enrolled or global projects qualify; sync_state counters do not determine this bound.
func (*Store) MergeExplicitProjectVariants ¶
func (s *Store) MergeExplicitProjectVariants(sources []string, canonical string) (*MergeResult, error)
MergeExplicitProjectVariants admits explicitly named separator and normalization variants for admin use.
func (*Store) MergeProjects ¶
func (s *Store) MergeProjects(sources []string, canonical string) (*MergeResult, error)
MergeProjects migrates all records from each source project name into the canonical name. Every source must normalize to the canonical name; sources that exactly equal the canonical name or have no records are skipped. All updates are performed inside a single transaction for atomicity.
func (*Store) MigrateProject ¶
func (s *Store) MigrateProject(oldName, newName string) (*MigrateResult, error)
func (*Store) ObservationOperationRecorded ¶ added in v3.3.0
ObservationOperationRecorded is a cheap existence probe for the operation ledger. It returns true when any row exists for the operation ID, including tombstones left by hard deletion, so callers can short-circuit session ownership pre-validation for committed operations.
func (*Store) ObservationsNeedingReview ¶
func (s *Store) ObservationsNeedingReview(project string, limit int) ([]Observation, error)
ObservationsNeedingReview returns non-deleted observations whose review_after has passed. An empty project searches all projects, matching existing browse/search conventions.
func (*Store) PassiveCapture ¶
func (s *Store) PassiveCapture(p PassiveCaptureParams) (*PassiveCaptureResult, error)
PassiveCapture extracts learnings from text and saves them as observations. It deduplicates against existing observations using content hash matching.
func (*Store) PinObservation ¶
func (*Store) PinnedObservations ¶
func (s *Store) PinnedObservations(project, scope string) ([]Observation, error)
PinnedObservations returns every pinned observation for project/scope, most-recent-first, with no row limit — pinning is an explicit, hand-bounded action, so returning all pinned rows has always been the legacy default. Callers that need a cap (e.g. FormatContextWithOptions via ContextOptions.Pinned) use the unexported pinnedObservationsLimit helper, which this delegates to with limit=0 ("no LIMIT clause", i.e. unbounded).
func (*Store) PlanLegacyEmptyPromptDiscard ¶
func (s *Store) PlanLegacyEmptyPromptDiscard(project string, seq int64) (LegacyEmptyPromptDiscardPlan, error)
PlanLegacyEmptyPromptDiscard is database- and filesystem-read-only. It accepts one exact project and journal sequence, never an implicit bulk selection.
func (*Store) PlanSessionIdentityRepair ¶
func (s *Store) PlanSessionIdentityRepair(sourceID, replacementID string) (SessionIdentityRepairPlan, error)
func (*Store) PreviewExplicitProjectMerge ¶
func (s *Store) PreviewExplicitProjectMerge(source, canonical string) (*ExplicitProjectMergePreview, error)
PreviewExplicitProjectMerge reads one consistent SQLite transaction without writing. A later apply can observe different data and return different counts.
func (*Store) PreviewPromptSource ¶
func (s *Store) PreviewPromptSource(syncID string) (PromptSourcePreview, bool, error)
PreviewPromptSource reads one exact sync ID from live prompts or tombstones. Ambiguous or incomplete observations return no preview; project is prompt data only.
func (*Store) ProjectExists ¶
ProjectExists returns true if the named project has at least one record in any of observations, sessions, prompts, or enrollment tables. Uses a single UNION ALL LIMIT 1 query for efficiency (REQ-315). The sync_enrolled_projects branch ensures a project enrolled via EnrollProject() without any other data is still recognized (JC1).
func (*Store) ProjectHistory ¶ added in v3.1.0
ProjectHistory returns weak scope evidence for an exact directory. Session history can be explicit or imported; it does not establish project ownership. This query is needed only before first binding creation, not on each read.
func (*Store) PruneProject ¶
func (s *Store) PruneProject(project string) (*PruneResult, error)
PruneProject removes prompts and sessions without observations for a project that has zero active observations. Soft-deleted observations and their sessions are retained.
func (*Store) QuarantineIrreparableSyncMutations ¶
func (s *Store) QuarantineIrreparableSyncMutations(targetKey, project string, apply bool) (SyncMutationQuarantineReport, error)
QuarantineIrreparableSyncMutations explicitly disposes of pending mutations the existing legacy validator proves cannot be repaired from local state. It never acknowledges, rewrites, or deletes a mutation.
func (*Store) ReadSQLiteLockSnapshot ¶
func (s *Store) ReadSQLiteLockSnapshot(ctx context.Context) (SQLiteLockSnapshot, error)
ReadSQLiteLockSnapshot returns SQLite lock-related PRAGMA values without starting an application write transaction.
func (*Store) RearmEligibleDeadRelationsForScope ¶
RearmEligibleDeadRelationsForScope gives a retry-cap dead relation one fresh replay window only when its original retryable mutation is now satisfiable in this exact target/project scope. Terminal dead evidence is deliberately left untouched: malformed payloads, mismatched identities, unsupported operations, hash-keyed rows, session dead letters, and non-FK failures cannot satisfy every eligibility predicate below.
func (*Store) RecentObservations ¶
func (s *Store) RecentObservations(project, scope string, limit int) ([]Observation, error)
func (*Store) RecentPrompts ¶
func (*Store) RecentSessions ¶
func (s *Store) RecentSessions(project string, limit int) ([]SessionSummary, error)
A database upgraded from the schema where sessions.project was nullable still carries rows that identify no project, so the column is read through ifnull(): an unscoped listing reads every session row and must not die on one of them.
func (*Store) ReclassifyOrphanedPendingRelations ¶
func (s *Store) ReclassifyOrphanedPendingRelations() (OrphanedPendingRelationReclassificationResult, error)
ReclassifyOrphanedPendingRelations moves every pending relation whose source AND target observations are absent from the active observation set into the audited `orphaned` disposition, the same terminal state the hard-delete orphaning writers already produce. The SQLite writer lock is acquired first and covers both the pre-apply backup and the reclassification, so no concurrent write can land between the snapshot and the apply it protects (the backup comes from a separate connection — the store pool is single-connection and is pinned by the held transaction). The predicate is revalidated inside the transaction so a stale or concurrent judgment can never be overwritten, and — matching those existing orphaning writers — no sync journal mutation is emitted: the reclassification is local audit hygiene, not replicated state. The operation is idempotent; a second run finds no pending candidates and changes nothing.
func (*Store) RecordSyncedChunk ¶
RecordSyncedChunk marks a local-target chunk as imported/exported.
func (*Store) RecordSyncedChunkForTarget ¶
RecordSyncedChunkForTarget marks a chunk as imported/exported for a target.
func (*Store) RegisterIsolatedSession ¶
RegisterIsolatedSession atomically validates the root and selected continuation before any ownership repair, sync mutation, or lease renewal. It never clears a nonblank directory and uses project-owned registration rules with no directory. An existing shared row is refused whatever produced it (runtime registration, Cloud pull or local import), because isolated registration never changes a persisted ownership mode and a shared lease would accept cross-project writes.
func (*Store) RegisterIsolatedSessionTimed ¶ added in v3.3.0
func (s *Store) RegisterIsolatedSessionTimed(id, project string, resume bool, timings *WriteTimings) (string, error)
RegisterIsolatedSessionTimed records database-stage timings without changing isolated-session validation or persistence.
func (*Store) ReleaseSyncLease ¶
func (*Store) RemirrorProject ¶
RemirrorProject enqueues a fresh current-state replay for an enrolled project. It leaves historical delivery rows untouched so recovery remains auditable.
func (*Store) RepairCloudUpgrade ¶
func (s *Store) RepairCloudUpgrade(project string, apply bool) (CloudUpgradeRepairReport, error)
func (*Store) RepairObservationMutationTitles ¶
func (s *Store) RepairObservationMutationTitles(project string, apply bool) (SyncMutationTitleRepairReport, error)
RepairObservationMutationTitles restores a missing payload title from a matching local observation's current title, or derives a blank source title from its content. It deliberately does not enqueue a replacement mutation: the existing journal row keeps its sequence and all delivery state while only its frozen payload is corrected.
func (*Store) RepairObservationSourceTitles ¶
func (s *Store) RepairObservationSourceTitles(project string, apply bool) (ObservationSourceTitleRepairReport, error)
RepairObservationSourceTitles restores only source titles that can be derived from the first non-empty line of their own content. It never invents content or type. When no pending local mutation exists and the repaired row is otherwise sync-valid, it emits one canonical upsert for the local repair.
func (*Store) RepairPendingSessionDirectories ¶
func (s *Store) RepairPendingSessionDirectories(project string, apply bool) ([]SyncMutationDirectoryRepairAction, error)
RepairPendingSessionDirectories plans or applies only session directory backfills. It does not require cloud enrollment and leaves journal metadata unchanged.
func (*Store) ReplayDeferred ¶
func (s *Store) ReplayDeferred() (ReplayDeferredResult, error)
ReplayDeferred retries every deferred row, including legacy-unscoped rows. It is reserved for deliberate administrative operations such as conflict recovery.
func (*Store) ReplayDeferredForScope ¶
func (s *Store) ReplayDeferredForScope(targetKey, project string) (result ReplayDeferredResult, err error)
ReplayDeferredForScope retries deferred rows for one sync target and optional project. An empty project includes all safely target-scoped rows for that target; an empty target is reserved for ReplayDeferred's administrative global replay. Legacy-unscoped rows are excluded whenever a target or project scope is supplied.
It retries rows with apply_status='deferred' (up to 50 per call, ordered by first_seen_at). For each row:
- Calls applyPulledMutationTx inside a transaction.
- On success: the apply itself deletes the deferred row (applyRelationUpsertTx already includes DELETE FROM sync_apply_deferred on success path).
- On ErrRelationFKMissing or ErrRelationProjectMismatch: increments retry_count; if retry_count reaches 5, marks apply_status='dead'. Otherwise updates last_error + last_attempted_at.
- On ErrApplyDead or other decode errors: marks apply_status='dead'.
Dead rows are never retried. Idempotent: calling twice in one cycle does not double-retry because successful rows are deleted and failed rows update retry_count in place.
Returns counts (retried, succeeded, failed, dead) for caller logging.
func (*Store) RescueNullProjectOwnership ¶
func (s *Store) RescueNullProjectOwnership(p ProjectRescueParams) (*ProjectRescueResult, error)
RescueNullProjectOwnership assigns an explicit project only to selected legacy records with NULL ownership and enqueues their missing canonical mutations.
func (*Store) ResolveRuntimeSessionWithOwnershipMode ¶ added in v3.2.0
func (s *Store) ResolveRuntimeSessionWithOwnershipMode(root, project, directory, mode string) (string, error)
ResolveRuntimeSessionWithOwnershipMode reads the authoritative live binding; unlike resume registration it cannot create or advance a continuation.
func (*Store) RestoreOrphanedObservationSessions ¶
func (s *Store) RestoreOrphanedObservationSessions(actions []OrphanedSessionPlaceholder) ([]OrphanedSessionPlaceholder, error)
RestoreOrphanedObservationSessions creates immediately-ended, local-only placeholders for confirmed missing session references. It validates the current observation evidence and any existing session ownership inside one transaction, so a stale or direct caller cannot attach a session ID to the wrong project. The placeholder's observation count and start time are re-derived from the current observations in the same transaction, so stale planned metadata can never persist. It never updates observations or emits sync mutations.
func (*Store) ResumeSessionWithOwnershipMode ¶
ResumeSessionWithOwnershipMode atomically selects and registers a live runtime identity. Ended rows remain terminal; ordinary and MCP registrations do not opt in.
func (*Store) ResumeSessionWithOwnershipModeTimed ¶ added in v3.3.0
func (s *Store) ResumeSessionWithOwnershipModeTimed(id, project, directory, mode string, timings *WriteTimings) (string, error)
ResumeSessionWithOwnershipModeTimed records database-stage timings without changing runtime-session continuation selection.
func (*Store) RollbackCloudUpgrade ¶
func (s *Store) RollbackCloudUpgrade(project string) (CloudUpgradeState, error)
func (*Store) SaveCloudUpgradeState ¶
func (s *Store) SaveCloudUpgradeState(state CloudUpgradeState) error
func (*Store) SaveRelation ¶
func (s *Store) SaveRelation(p SaveRelationParams) (*Relation, error)
SaveRelation inserts a new pending relation row. The SyncID field must be unique (enforced by the UNIQUE constraint on memory_relations.sync_id).
func (*Store) ScanAllProjects ¶
func (s *Store) ScanAllProjects(opts ScanOptions) (ScanResult, error)
func (*Store) ScanProject ¶
func (s *Store) ScanProject(opts ScanOptions) (ScanResult, error)
ScanProject walks one ID-ordered observation page in the given project (filtered by Since) and calls FindCandidates with SkipInsert=true for each row. If Apply is true and below MaxInsert cap, each new candidate pair is inserted as a pending relation (after a pre-check to skip already-related pairs).
Phase 4 extension: when ScanOptions.Semantic is true, after the FTS5 candidate collection a bounded worker pool calls Runner.Compare on each pair. Applied scans persist judged verdicts via JudgeBySemantic, while dry-runs report their semantic results without persistence. Semantic=false (zero value) preserves Phase 3 behaviour exactly.
Returns a ScanResult with counts, a continuation cursor when another page remains, and whether an insert or semantic cap was hit.
func (*Store) Search ¶
func (s *Store) Search(query string, opts SearchOptions) ([]SearchResult, error)
Search preserves the original non-context API for callers that do not need cancellation.
func (*Store) SearchContext ¶
func (s *Store) SearchContext(ctx context.Context, query string, opts SearchOptions) ([]SearchResult, error)
SearchContext searches observations while honoring cancellation from the caller, including while materializing rows.
func (*Store) SearchPreviewsContext ¶
func (s *Store) SearchPreviewsContext(ctx context.Context, query string, opts SearchOptions) ([]SearchPreviewResult, error)
SearchPreviewsContext searches using the same ranking and filters as SearchContext while selecting only a bounded Unicode-safe content preview.
func (*Store) SearchPrompts ¶
func (*Store) SessionObservations ¶
func (s *Store) SessionObservations(sessionID string, limit int) ([]Observation, error)
SessionObservations returns all observations for a specific session.
func (*Store) SkipAckNonEnrolledMutations ¶
SkipAckNonEnrolledMutations acks (marks as skipped) all pending mutations that belong to non-enrolled projects, preventing journal bloat. Empty-project mutations are never skipped — they always sync regardless of enrollment.
func (*Store) StartSession ¶
StartSession registers a shared runtime session or renews its local lease.
func (*Store) StartSessionWithOwnershipMode ¶
StartSessionWithOwnershipMode registers a runtime session or renews its local lease. It preserves the existing session identity and refuses to reopen an ended session; EndSession remains terminal truth.
func (*Store) StartSessionWithOwnershipModeTimed ¶ added in v3.3.0
func (s *Store) StartSessionWithOwnershipModeTimed(id, project, directory, mode string, timings *WriteTimings) error
StartSessionWithOwnershipModeTimed records database-stage timings without changing session-registration behavior.
func (*Store) StatsProject ¶
StatsProject returns aggregate counts restricted to one project. Selection policy belongs to callers; this method only applies the supplied scope.
func (*Store) SupersedeUnenrolledLegacyMutations ¶
func (s *Store) SupersedeUnenrolledLegacyMutations(targetKey, project string, apply bool) (SyncMutationSupersedeReport, error)
SupersedeUnenrolledLegacyMutations retires pending local upserts only when local delete evidence proves the entity is no longer current. It preserves the mutation, acknowledgement state, and recorded evidence; it never claims cloud delivery. An empty project evaluates every unenrolled project for doctor.
func (*Store) Timeline ¶
func (s *Store) Timeline(observationID int64, before, after int) (*TimelineResult, error)
func (*Store) UnenrollProject ¶
UnenrollProject removes a project from cloud sync enrollment. Idempotent — unenrolling a non-enrolled project is a no-op.
func (*Store) UnpinObservation ¶
func (*Store) UpdateObservation ¶
func (s *Store) UpdateObservation(id int64, p UpdateObservationParams) (*Observation, error)
func (*Store) UpdateObservationForProject ¶
func (s *Store) UpdateObservationForProject(id int64, expected string, p UpdateObservationParams) (*Observation, error)
UpdateObservationForProject atomically asserts stored ownership and updates the row.
type SyncMutation ¶
type SyncMutation struct {
Seq int64 `json:"seq"`
TargetKey string `json:"target_key"`
Entity string `json:"entity"`
EntityKey string `json:"entity_key"`
Op string `json:"op"`
Payload string `json:"payload"`
Source string `json:"source"`
Project string `json:"project"`
OccurredAt string `json:"occurred_at"`
AckedAt *string `json:"acked_at,omitempty"`
Disposition string `json:"disposition"`
DispositionReason string `json:"disposition_reason,omitempty"`
DispositionEvidence string `json:"disposition_evidence,omitempty"`
DispositionAt *string `json:"disposition_at,omitempty"`
}
type SyncMutationDirectoryRepairAction ¶
type SyncMutationDirectoryRepairAction struct {
Seq int64 `json:"seq"`
Project string `json:"project"`
EntityKey string `json:"entity_key"`
}
SyncMutationDirectoryRepairAction identifies a pending session payload repaired from local state.
type SyncMutationPayloadValidation ¶
type SyncMutationPayloadValidation struct {
Entity string `json:"entity"`
Op string `json:"op"`
EntityKey string `json:"entity_key,omitempty"`
MissingFields []string `json:"missing_fields,omitempty"`
ReasonCode string `json:"reason_code,omitempty"`
Message string `json:"message,omitempty"`
}
SyncMutationPayloadValidation describes deterministic required-field issues in a pending sync mutation payload.
func ValidateSyncMutationPayload ¶
func ValidateSyncMutationPayload(entity, op, payload, entityKey string) SyncMutationPayloadValidation
ValidateSyncMutationPayload performs pure required-field validation for sync payloads. It is intentionally conservative: malformed/empty/unsupported payloads are reported as manual blocks, while complete payloads return an empty validation.
type SyncMutationQuarantineAction ¶
type SyncMutationQuarantineAction struct {
Seq int64 `json:"seq"`
Project string `json:"project"`
Entity string `json:"entity"`
EntityKey string `json:"entity_key"`
Op string `json:"op"`
ReasonCode string `json:"reason_code"`
Message string `json:"message"`
Evidence string `json:"evidence"`
}
SyncMutationQuarantineAction records one deterministic local quarantine.
type SyncMutationQuarantineReport ¶
type SyncMutationQuarantineReport struct {
Project string `json:"project,omitempty"`
Applied bool `json:"applied"`
Actions []SyncMutationQuarantineAction `json:"actions"`
}
SyncMutationQuarantineReport is the explicit local recovery result.
type SyncMutationSupersedeAction ¶
type SyncMutationSupersedeAction struct {
Seq int64 `json:"seq"`
Project string `json:"project"`
Entity string `json:"entity"`
EntityKey string `json:"entity_key"`
Op string `json:"op"`
ReasonCode string `json:"reason_code"`
Evidence string `json:"evidence"`
}
SyncMutationSupersedeAction records a local journal row retired because a tombstone or deleted source row proves that its prior upsert is obsolete.
type SyncMutationSupersedeReport ¶
type SyncMutationSupersedeReport struct {
Project string `json:"project,omitempty"`
Applied bool `json:"applied"`
Actions []SyncMutationSupersedeAction `json:"actions"`
}
SyncMutationSupersedeReport is the explicit, non-acknowledging local recovery result for stale pending upserts.
type SyncMutationTitleRepairAction ¶
type SyncMutationTitleRepairAction struct {
Seq int64 `json:"seq"`
Project string `json:"project"`
Entity string `json:"entity"`
EntityKey string `json:"entity_key"`
Op string `json:"op"`
Title string `json:"title"`
}
SyncMutationTitleRepairAction records a title restored from its matching local observation without creating another sync mutation.
type SyncMutationTitleRepairReport ¶
type SyncMutationTitleRepairReport struct {
Project string `json:"project,omitempty"`
Applied bool `json:"applied"`
Actions []SyncMutationTitleRepairAction `json:"actions"`
}
SyncMutationTitleRepairReport is the local recovery result for title-only observation upserts. Repairs remain pending so the original sequence is delivered normally.
type SyncState ¶
type SyncState struct {
TargetKey string `json:"target_key"`
Lifecycle string `json:"lifecycle"`
LastEnqueuedSeq int64 `json:"last_enqueued_seq"`
LastAckedSeq int64 `json:"last_acked_seq"`
LastPulledSeq int64 `json:"last_pulled_seq"`
ConsecutiveFailures int `json:"consecutive_failures"`
BackoffUntil *string `json:"backoff_until,omitempty"`
LeaseOwner *string `json:"lease_owner,omitempty"`
LeaseUntil *string `json:"lease_until,omitempty"`
ReasonCode *string `json:"reason_code,omitempty"`
ReasonMessage *string `json:"reason_message,omitempty"`
LastError *string `json:"last_error,omitempty"`
LastSuccessAt *string `json:"last_success_at,omitempty"`
UpdatedAt string `json:"updated_at"`
}
type SyncTargetState ¶
type SyncTargetState struct {
TargetKey string `json:"target_key"`
Lifecycle string `json:"lifecycle"`
UnackedMutations int `json:"unacked_mutations"`
}
SyncTargetState summarizes one sync_state row for diagnostics. UnackedMutations counts journal rows still awaiting delivery for the target: rows stored directly under the target key, plus the project-scoped journal rows for cloud:<project> targets (those mutations live under the default cloud key and carry the project in their own column).
type TimelineEntry ¶
type TimelineEntry struct {
ID int64 `json:"id"`
SessionID string `json:"session_id"`
Type string `json:"type"`
Title string `json:"title"`
Content string `json:"content"`
ToolName *string `json:"tool_name,omitempty"`
Project *string `json:"project,omitempty"`
Scope string `json:"scope"`
TopicKey *string `json:"topic_key,omitempty"`
RevisionCount int `json:"revision_count"`
DuplicateCount int `json:"duplicate_count"`
LastSeenAt *string `json:"last_seen_at,omitempty"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
DeletedAt *string `json:"deleted_at,omitempty"`
IsFocus bool `json:"is_focus"` // true for the anchor observation
}
type TimelineResult ¶
type TimelineResult struct {
Focus Observation `json:"focus"` // The anchor observation
Before []TimelineEntry `json:"before"` // Observations before the focus (chronological)
After []TimelineEntry `json:"after"` // Observations after the focus (chronological)
SessionInfo *Session `json:"session_info"` // Session that contains the focus observation
TotalInRange int `json:"total_in_range"`
}
type TruncationMetadata ¶
type TruncationMetadata struct {
OriginalBytes int `json:"original_bytes"`
LimitBytes int `json:"limit_bytes"`
Truncated bool `json:"truncated"`
}
TruncationMetadata describes storage content processing after private-tag redaction.
type UpdateObservationParams ¶
type UpdateObservationParams struct {
Type *string `json:"type,omitempty"`
Title *string `json:"title,omitempty"`
Content *string `json:"content,omitempty"`
Find *string `json:"find,omitempty"`
Replace *string `json:"replace,omitempty"`
Project *string `json:"project,omitempty"`
Scope *string `json:"scope,omitempty"`
TopicKey *string `json:"topic_key,omitempty"`
}
Source Files
¶
- candidate_relevance.go
- diagnostic.go
- filesystem_policy.go
- filesystem_policy_linux.go
- generation_fence.go
- instance.go
- migration_lock.go
- migration_lock_unix.go
- project_history.go
- prompt_capture.go
- prompt_discard.go
- prompt_source_confirmation.go
- relations.go
- relations_scan_batch.go
- runner.go
- session_identity_repair.go
- store.go