Documentation
¶
Overview ¶
Package store defines the two ports the engine is built against (ManifestStore and OperationalStore) and the record shapes they persist. The SQLite adapter (package sqlite) and the in-memory adapter (package memory) both satisfy these interfaces and are proven equivalent by the conformance suite in package conformance.
Index ¶
- type ApplyFile
- type ApplyJournal
- type ApplyUnit
- type Bundle
- type BundleStore
- type ConflictError
- type Exclusion
- type ManifestDraft
- type ManifestStore
- type NotFoundError
- type Op
- type OpLog
- type OperationalStore
- type ProjectStateEntry
- type Ref
- type RefFilter
- type StateStore
- type Summary
- type UnappliedRef
- type VaultIndex
- type Version
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type ApplyFile ¶
type ApplyFile struct {
Path string // Path relative to vault root (e.g., "vault.yaml" or "Goal/some-goal.yaml")
SHA256 string // SHA-256 hash of content (hex, 64 chars)
Content []byte // File content
}
ApplyFile is one file write within an ApplyUnit: path relative to vault root, sha256 hash of content (for idempotence during replay), and the content itself.
type ApplyJournal ¶
type ApplyJournal interface {
// PutUnit writes a new unit with applied=false.
PutUnit(ctx context.Context, unit ApplyUnit) error
// MarkApplied marks a unit as applied and updates the index. Called in the
// same transaction as index updates (rebuild, rehydration, reference indexing).
MarkApplied(ctx context.Context, unitID string) error
// ListUnapplied returns every unit with applied=false, oldest first.
ListUnapplied(ctx context.Context) ([]ApplyUnit, error)
// PruneOld removes applied units older than the given count (keeps the most
// recent `keepCount` applied units). A keepCount of 0 or less means unlimited.
PruneOld(ctx context.Context, keepCount int) error
// WithinTransaction runs fn against the journal in a transaction (adapters
// that support transactions). Idempotent with database adapters.
WithinTransaction(ctx context.Context, fn func(ctx context.Context, tx ApplyJournal) error) error
}
ApplyJournal records every mutation (apply, exclude, recover, etc.) with a two-phase commit: write the unit (applied=false), commit files to disk, then mark applied and update the index in one transaction.
type ApplyUnit ¶
type ApplyUnit struct {
ID string // Unique identifier for this unit (uuid)
On time.Time // When the mutation happened
Operator string // Who performed it (actor, "local" for file operations)
Reason string // Why (for exclusion, recovery, or user-supplied reason)
Files []ApplyFile // Files to write: {path, sha256, content}
Applied bool // Whether this unit was applied (committed to files and index)
}
ApplyUnit is one mutation: a set of file writes recorded first with applied=false, then files written (temp file and rename, vault.yaml last), then marked applied and the index updated in one transaction. On open, replay every unit not applied.
type Bundle ¶
Bundle is where a handoff's files went. Location is what the state history records: a path relative to the vault root for the vault adapter, an opaque name for others. Paths maps each file name to where a person can find it, for the command line to print.
type BundleStore ¶
type BundleStore interface {
// PutBundle stores files (name to content) for one project at one
// version, all or nothing, and returns where they went.
PutBundle(ctx context.Context, projectID string, version int, files map[string][]byte) (Bundle, error)
}
BundleStore keeps the files a handoff produces (the rendered charter in its formats) beside the version they were rendered from. The vault adapter writes them under .cartograph/handoff; the memory adapter keeps them in memory, which is what tests need.
type ConflictError ¶
ConflictError is returned by PutVersion when a manifest's file on disk has changed since it was last read, indicating concurrent edits that need reconciliation. Both Ours (the version being written) and Theirs (the current file on disk) carry the full YAML text.
func (*ConflictError) Error ¶
func (e *ConflictError) Error() string
type Exclusion ¶
type Exclusion struct {
Kind string // Manifest kind
ID string // Manifest id
Name string // Manifest name at time of exclusion
On time.Time // When excluded
Reason string // Why excluded
Operator string // Who excluded it
}
Exclusion is one manifest that has been excluded from the live state.
type ManifestDraft ¶
ManifestDraft is a manifest's working copy: the YAML as last saved with the draft header, never validated beyond its basic shape, never versioned. Keyed by Kind and ID (I3a.1: generalized from the Project-only project_draft table).
type ManifestStore ¶
type ManifestStore interface {
// PutVersion appends a new version. The caller is responsible for
// computing Number as one more than the current version (or 1 for a
// new manifest); an adapter rejects a Number that is not exactly that,
// which is what guards immutability under concurrent writers.
PutVersion(ctx context.Context, v Version) error
// GetCurrent returns the highest-numbered version of a manifest.
GetCurrent(ctx context.Context, kind, id string) (Version, bool, error)
// GetVersion returns one specific historical version.
GetVersion(ctx context.Context, kind, id string, number int) (Version, bool, error)
// ListVersions returns every version of a manifest, oldest first.
ListVersions(ctx context.Context, kind, id string) ([]Version, error)
// ListAllVersions returns every version of every manifest across all
// kinds, newest first, with optional pagination (limit defaults to 20,
// cursor is opaque and returned by the preceding call). Used by the
// snapshots list endpoint.
ListAllVersions(ctx context.Context, limit int, cursor string) (versions []Version, nextCursor string, err error)
// ListSummaries returns the current version of every manifest of a
// kind, optionally filtered by a case-insensitive substring match over
// id and name (query, ignored when empty) and by zero or more
// reference filters (refs; a manifest must have a current outgoing
// reference matching every one of them - logical AND, ignored when
// empty). Always returns a non-nil, possibly empty, slice.
ListSummaries(ctx context.Context, kind, query string, refs []RefFilter) ([]Summary, error)
// ListIDs returns the id of every manifest of a kind that has a
// current version.
ListIDs(ctx context.Context, kind string) ([]string, error)
// Counts returns the number of manifests (by id, not by version) for
// every kind that has at least one.
Counts(ctx context.Context) (map[string]int, error)
// IndexReferences replaces the recorded outgoing references for one
// manifest's current version. The engine calls this once per commit,
// right after PutVersion, inside the same transaction, with every
// x-cartograph-ref value found by walking that kind's schema.
IndexReferences(ctx context.Context, fromKind, fromID string, refs []Ref) error
// ListReferencedBy returns every outgoing reference recorded for one
// manifest's current version.
ListReferencedBy(ctx context.Context, fromKind, fromID string) ([]Ref, error)
// ListReferencing returns the current summary of every manifest that
// has an outgoing reference to toKind/toID.
ListReferencing(ctx context.Context, toKind, toID string) ([]Summary, error)
// PutWorking writes a manifest's YAML as the working copy without creating
// a version. Used for autosave writes that don't create an explicit
// snapshot. The working copy is updated, but no version entry is created.
PutWorking(ctx context.Context, kind, id string, yamlBytes []byte) error
// GetWorking returns a manifest's working copy (the file on disk that may
// not yet be versioned). Returns found=false when no working copy exists.
GetWorking(ctx context.Context, kind, id string) ([]byte, bool, error)
// WithinTransaction runs fn against a ManifestStore that commits all of
// its writes together, or none of them if fn returns an error.
WithinTransaction(ctx context.Context, fn func(ctx context.Context, tx ManifestStore) error) error
// Exclude removes a manifest from vault.yaml and records the exclusion.
// The file remains on disk. Returns an error if the manifest does not exist
// (use GetCurrent to check first). Refused if the manifest is referenced by
// a live manifest (call ListReferencing first).
Exclude(ctx context.Context, kind, id, name, reason, operator string) error
// ListExcluded returns every excluded manifest, newest first.
ListExcluded(ctx context.Context) ([]Exclusion, error)
// Recover re-adds an excluded manifest to vault.yaml and removes the
// exclusion record. Returns an error if the file is missing from disk.
Recover(ctx context.Context, kind, id, reason, operator string) error
}
ManifestStore holds every manifest version ever committed. Rows are immutable: once written, a version is never updated or deleted.
type NotFoundError ¶
ErrNotFound is returned by Get-style methods is expressed with the bool "found" return instead of a sentinel error, to keep call sites simple; this type exists only for adapters that need a concrete not-found error internally (for example inside a transaction helper).
func (*NotFoundError) Error ¶
func (e *NotFoundError) Error() string
type Op ¶
Op is one write to one leaf of one manifest's shared working document, as the op log keeps it: the merge op plus where it belongs and when it arrived. Seq is the log's own order, assigned on append, dense per manifest; clients catch up by asking for everything after the last Seq they saw.
type OpLog ¶
type OpLog interface {
// Append records ops for one manifest and returns the Seq of the
// first, with the rest following in order. Every op must name the
// same kind and id.
Append(ctx context.Context, ops []Op) (firstSeq int64, err error)
// Since returns ops for one manifest with Seq greater than after,
// oldest first, at most limit (0 means no limit). Always a non-nil
// slice.
Since(ctx context.Context, kind, id string, after int64, limit int) ([]Op, error)
// Latest returns the highest Seq for one manifest, 0 when it has none.
Latest(ctx context.Context, kind, id string) (int64, error)
// Compact removes ops at or before seq for one manifest, after the
// state they produced has been committed as a version.
Compact(ctx context.Context, kind, id string, seq int64) error
}
OpLog is the port under multiplayer editing: an append-only log of leaf writes per manifest. Reads are by position, so a client that was away (a TUI that lost its connection, a browser tab that slept) asks for what it missed and merges it; because the ops form a CRDT, the order it receives them in does not matter.
The log is not the record of truth: that is the committed version. The log is the shared draft between versions, and Compact may drop everything at or before the op that became a version.
type OperationalStore ¶
type OperationalStore interface {
// PutProjectStateTransition appends one row to a project's state
// history (the table is append-only; the current state is the most
// recent row). A project with no rows is implicitly "draft".
PutProjectStateTransition(ctx context.Context, e ProjectStateEntry) error
// ListProjectStateHistory returns every state transition for a
// project, oldest first. Empty (never nil) when the project has never
// moved out of the implicit "draft" state.
ListProjectStateHistory(ctx context.Context, projectID string) ([]ProjectStateEntry, error)
}
OperationalStore holds facts about manifests: project state history and project drafts. Later increments add readings and data-quality check results.
type ProjectStateEntry ¶
type ProjectStateEntry struct {
ProjectID string
State string
Actor string
Reason string
On time.Time
Snapshot int
Bundle string
}
ProjectStateEntry is one row of a project's state history: at On, Actor moved the project to State, giving Reason (required only for a move to cancelled; empty otherwise). Snapshot and Bundle are set when state is handed off: Snapshot is the version number, Bundle is the directory path where the charter bundle was written (relative to vault root).
type Ref ¶
Ref is one outgoing reference recorded for a manifest: at Path (a JSON pointer within it) it names ToKind/ToID.
type RefFilter ¶
RefFilter narrows ListSummaries to manifests with an outgoing reference to Kind/ID.
type StateStore ¶
type StateStore interface {
// Name is the state manifest's own id (metadata.id).
Name() string
// Included returns every ref ("Kind/id") the state manifest includes,
// in the order it lists them.
Included(ctx context.Context) ([]string, error)
// ListUnapplied returns every manifest the adapter can see that is
// neither included nor excluded: what a person could apply next.
ListUnapplied(ctx context.Context) ([]UnappliedRef, error)
// Apply includes the given refs. Applying a ref that is already
// included is quiet; a ref the adapter cannot find is refused with
// an error that names it. Returns how many refs were newly included.
Apply(ctx context.Context, refs []string) (added int, err error)
// StateYAML returns the state manifest's own bytes, or found=false
// when the adapter has not written one yet.
StateYAML(ctx context.Context) (yaml []byte, found bool, err error)
// Rehydrate reloads the live state from the adapter's source of
// truth. Called after Apply or Recover changed what is included.
Rehydrate(ctx context.Context) error
}
StateStore is the apply gate: an adapter keeps a state manifest (an include list) over manifests that can exist before they are included. The vault adapter implements it over vault.yaml. A database adapter where every row is live has no need for it.
type Summary ¶
type Summary struct {
Kind string
ID string
Name string
Version int
UpdatedOn time.Time
// Labels is metadata.labels, carried on the summary so a list can be
// grouped and filtered by them. Nil where the manifest sets none.
Labels map[string]string
// Draft is true only for a synthetic Summary standing in for a
// project that has only ever been saved as a draft, never committed
// (I3a.1, includeDrafts=true): Version is then 0 and UpdatedOn is the
// draft's own save time. False (the zero value) for every ordinary,
// committed Summary a store adapter's own ListSummaries builds.
Draft bool
}
Summary is the list-view projection of a manifest's current version.
type UnappliedRef ¶
UnappliedRef is one manifest that could be applied.
type VaultIndex ¶
type VaultIndex interface {
ManifestStore // versions, summaries, references, working copies, exclusions
Journal() ApplyJournal // the two-phase apply journal
Operational() OperationalStore // project state history (same database)
// File hashes: what the vault compares a file against on open and on a watcher event.
GetFileHash(ctx context.Context, kind, id string) (sha256 string, found bool, err error)
PutFileHash(ctx context.Context, kind, id, sha256, mtime string) error
DeleteFileHash(ctx context.Context, kind, id string) error
// Meta: small key/value facts about the index itself (the recorded vault.yaml hash, rebuild time).
GetMeta(ctx context.Context, key string) (value string, found bool, err error)
PutMeta(ctx context.Context, key, value string) error
Close() error
}
VaultIndex is everything the vault adapter keeps beside its files: the rebuildable cache a database holds for it. SQLite implements it today; any adapter that passes conformance.RunVaultIndex may.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package conformance is the one test suite that both the SQLite and the in-memory store adapters must pass, proving they are interchangeable behind the store.ManifestStore and store.OperationalStore ports.
|
Package conformance is the one test suite that both the SQLite and the in-memory store adapters must pass, proving they are interchangeable behind the store.ManifestStore and store.OperationalStore ports. |
|
Package manifestmeta reads metadata.name and metadata.labels out of a manifest's text, for the store adapters that index both beside each version.
|
Package manifestmeta reads metadata.name and metadata.labels out of a manifest's text, for the store adapters that index both beside each version. |
|
Package memory is the in-memory ManifestStore and OperationalStore adapter used by tests and by the conformance suite.
|
Package memory is the in-memory ManifestStore and OperationalStore adapter used by tests and by the conformance suite. |
|
Package sqlite is the SQLite adapter for both store.ManifestStore and store.OperationalStore, backed by modernc.org/sqlite (a pure-Go driver, no cgo).
|
Package sqlite is the SQLite adapter for both store.ManifestStore and store.OperationalStore, backed by modernc.org/sqlite (a pure-Go driver, no cgo). |
|
Package vault implements store.ManifestStore over a directory tree: files are the source of truth.
|
Package vault implements store.ManifestStore over a directory tree: files are the source of truth. |