engine

package
v2.0.0 Latest Latest
Warning

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

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

Documentation

Overview

Package engine is the kind-agnostic manifest engine: it validates manifests against their schema, references and kind rules, stores immutable versions, computes diffs, and indexes cross-manifest references. Adding a kind never changes this package; it changes only contract/schemas and internal/kinds.

Index

Constants

View Source
const (
	ProjectStateDraft     = "draft"
	ProjectStateDefined   = "defined"
	ProjectStateHandedOff = "handed off"
	ProjectStateCancelled = "cancelled"
)

ProjectStateDraft and the other project states: draft, defined (set automatically at the first snapshot), handed off, and cancelled.

Variables

View Source
var (
	ErrUnknownKind = errors.New("unknown kind")
	ErrNotFound    = errors.New("not found")
	ErrConflict    = errors.New("conflict")
)

Sentinel errors an API or CLI layer can classify with errors.Is.

View Source
var ErrNoShared = errors.New("engine: shared drafts are not configured")

ErrNoShared is returned by Shared methods when the engine was built without the three ports shared drafts need.

View Source
var ErrNoState = errors.New("this store has no state manifest")

ErrNoState is returned by the state methods when the manifest store has no apply gate: every manifest it holds is live, so there is nothing to apply, exclude or recover.

View Source
var ErrReadOnly = errors.New("engine: the principal may not change this document")

ErrReadOnly is returned when a sync message from a principal who may not write carries changes.

Functions

func DocTopic

func DocTopic(docID string) string

DocTopic is the fan-out topic a document's "changed" hints go to, and EphemeralTopic the one its presence travels on.

func EphemeralTopic

func EphemeralTopic(docID string) string

func IsPresence

func IsPresence(kind, id string) bool

IsPresence reports whether a manifest name returned by ManifestFor is the presence document's.

func NewDocumentID

func NewDocumentID() string

NewDocumentID returns a random automerge-repo document id: sixteen random bytes in base58check, as automerge-repo writes them, so the stock libraries accept it.

func RefIsSet

func RefIsSet(v any) bool

RefIsSet reports whether a reference field names anything.

func RefLabel

func RefLabel(v any, spec map[string]any) string

RefLabel renders a reference field as the text a document shows, given the spec it lives in so local references can resolve. Exported for the charter renderer, which prints references and lives in its own package. A field that is not a reference at all renders empty rather than guessing, so a stale document shows a gap instead of a wrong name.

func StandardUnitIDs

func StandardUnitIDs() []string

StandardUnitIDs names the units a vault is seeded with, so a test can hold the example instance to the same set.

Types

type Bus

type Bus interface {
	Publish(ev Event)
	// Subscribe delivers events for one manifest, or for every manifest
	// when kind is empty. A slow subscriber drops events rather than
	// blocking the publisher; it reads the state again when it next needs it.
	Subscribe(ctx context.Context, kind, id string) *Subscription
}

Bus fans events out to subscribers in one process. It is the port a multi-process deployment replaces (the Postgres index's LISTEN/NOTIFY, a broker); the engine only ever calls Publish and Subscribe.

type Change

type Change struct {
	Path string `json:"path"`
	Op   string `json:"op"` // add, remove, replace
	From any    `json:"from,omitempty"`
	To   any    `json:"to,omitempty"`
}

Change is one difference between two versions of a manifest, at Path (a JSON pointer, or a pointer using an array element's own id in place of its index for arrays of objects that carry one, see diff.go).

type Changed

type Changed struct {
	Replica string `json:"replica"`
	Seq     int64  `json:"seq"`
}

Changed is the hint published on DocTopic after a replica stores a change: which replica, and the chunk it stored.

type DependencyEdge

type DependencyEdge struct {
	FromKind string `json:"fromKind"`
	FromID   string `json:"fromId"`
	FromName string `json:"fromName"`
	ToKind   string `json:"toKind"`
	ToID     string `json:"toId"`
	ToName   string `json:"toName"`
	NeedBy   string `json:"needBy,omitempty"`
	Why      string `json:"why,omitempty"`
}

DependencyEdge is one resolved link: who waits, on what, and by when.

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is the kind-agnostic manifest engine. Construct with New. It talks to the outside world through ports only: the two stores every deployment has, and the optional ones an adapter may offer (the apply gate, the bundle store). It never touches a file system or a browser itself.

func New

func New(manifests store.ManifestStore, ops store.OperationalStore, opts ...Option) (*Engine, error)

New builds an Engine over the given stores, compiling every kind's JSON Schema and precomputing its reference rules. An adapter that offers more than the two required ports is attached with options; a store that satisfies StateStore or BundleStore itself is attached automatically.

func (*Engine) Apply

func (e *Engine) Apply(ctx context.Context, refs []string) (State, error)

Apply includes refs ("Kind/id") in the live state, then reloads and reindexes once for the whole batch. A malformed ref, or one the store cannot find, is a ValidationError naming it; nothing is applied then. Applying what is already applied is quiet.

func (*Engine) Bus

func (e *Engine) Bus() Bus

Bus returns the event bus.

func (*Engine) Codec

func (e *Engine) Codec() codec.Codec

Codec is the manifest syntax this engine reads and writes, for the drivers that turn a request body into text and back.

func (*Engine) Commit

func (e *Engine) Commit(ctx context.Context, kind, id string, yamlBytes []byte, actor, reason string) (Version, error)

Commit validates a manifest and, if it is valid, stores it as the next immutable version. The id in the manifest's metadata must match id. actor is recorded as given (see checkActor's own doc comment for why actor validation was removed).

func (*Engine) CommitProject

func (e *Engine) CommitProject(ctx context.Context, id string, yamlBytes []byte, actor, reason string) (Version, error)

CommitProject validates and stores a new version of a Project, exactly like the generic Commit.

func (*Engine) Delete

func (e *Engine) Delete(ctx context.Context, kind, id, actor, reason string) error

Delete excludes a manifest from the live state. Allowed only when nothing currently references it (leaf rule). Returns ValidationError listing every referencing manifest when the manifest is not a leaf; ErrNotFound when the manifest does not exist.

func (*Engine) DeleteGoal

func (e *Engine) DeleteGoal(ctx context.Context, id, actor, reason string) error

DeleteGoal deletes a goal (goals are easily mutable), allowed only when nothing currently references it (a child goal's own parent, a Project/Programme/Operation/KPI's own alignment, or anything else the generic reference index tracks). Refused with a *ValidationError listing every referencing manifest when the goal is not empty of references; ErrNotFound when the goal does not exist. Calls Exclude to remove from vault.yaml while keeping the file.

func (*Engine) DependencyCycles

func (e *Engine) DependencyCycles(ctx context.Context) ([][]string, error)

DependencyCycles returns every cycle in the graph, each as the ids it runs through, starting from the lowest for a stable reading. Two pieces of work each waiting on the other is a fact neither definition shows.

func (*Engine) DependencyGraph

func (e *Engine) DependencyGraph(ctx context.Context) ([]DependencyEdge, error)

DependencyGraph reads every edge in the vault, normalised so they all point the same way: from the thing that waits, to the thing waited on. A "neededBy" edge is stored on the far end, so it is turned around here rather than leaving two conventions in one graph.

func (*Engine) DependencyScheduleConflicts

func (e *Engine) DependencyScheduleConflicts(ctx context.Context) ([]ScheduleConflict, error)

DependencyScheduleConflicts is the check the edge exists for. It needs both ends to carry a timeline, so it is a project-to-project answer today; a programme schedules nothing, and a dependency on one is reported as unschedulable rather than as a conflict.

func (*Engine) Diff

func (e *Engine) Diff(ctx context.Context, kind, id string, from, to int) ([]Change, error)

Diff computes the structural difference between two versions of a manifest.

func (*Engine) DiscardWorking

func (e *Engine) DiscardWorking(ctx context.Context, kind, id string) error

DiscardWorking throws away a staged draft, putting back whatever the store holds as saved. Stores that keep no staging directory have nothing to discard, so this is a no-op for them rather than an error: the caller asked for the draft to be gone, and it is.

func (*Engine) ExportDir

func (e *Engine) ExportDir(ctx context.Context, dir string) error

ExportDir writes the current version of every manifest to <dir>/<kind>/<id>.yaml, using the exact YAML text that was committed, so export is byte-for-byte reproducible. If the vault is vault-backed, also exports vault.yaml.

func (*Engine) ExportDirAs

func (e *Engine) ExportDirAs(ctx context.Context, dir string, target codec.Codec) error

ExportDirAs is ExportDir in another syntax: the migration path between codecs. With the engine's own codec the committed text is written byte for byte; with another, every manifest is decoded and re-encoded, so the export opens as a vault of that codec and nothing else changes.

func (*Engine) FlowJSON

func (e *Engine) FlowJSON(kind string) ([]byte, bool, error)

FlowJSON returns a kind's flow document exactly as written in the contract, or found=false for a kind that is a plain sheet. Served raw for the same reason schemas are: the order of steps and fields is the document's meaning.

func (*Engine) FlowKinds

func (e *Engine) FlowKinds() []string

FlowKinds lists the kinds that have a flow, in registry order.

func (*Engine) GapChecks

func (e *Engine) GapChecks(ctx context.Context, id string) ([]ProgrammeCheck, error)

GapChecks says whether a gap can be used for what a gap register is for.

All advisory, and none of them blocks: every one reads a manifest other than this gap, so a gap that saved yesterday must not be refused today because somebody edited a project.

func (*Engine) GapCoverageFor

func (e *Engine) GapCoverageFor(ctx context.Context, id string) (GapCoverage, error)

GapCoverageFor reads one gap's scope and everything that cites it.

func (*Engine) Get

func (e *Engine) Get(ctx context.Context, kind, id string) (Version, error)

Get returns the current version of a manifest.

func (*Engine) GetProjectState

func (e *Engine) GetProjectState(ctx context.Context, id string) (ProjectState, error)

GetProjectState returns a project's current state and its history. The project itself must exist (committed or draft-only is not enough: state applies to a committed project).

func (*Engine) GetSettings

func (e *Engine) GetSettings(ctx context.Context) (Settings, error)

GetSettings returns the current Settings, defaulted where the imported document (if any) leaves a field empty.

func (*Engine) GetState

func (e *Engine) GetState(ctx context.Context) (State, error)

GetState returns the state manifest: its name and its include list.

func (*Engine) GetVersion

func (e *Engine) GetVersion(ctx context.Context, kind, id string, number int) (Version, error)

GetVersion returns one specific historical version.

func (*Engine) GetWorking

func (e *Engine) GetWorking(ctx context.Context, kind, id string) ([]byte, bool, 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.

func (*Engine) GoalChecks

func (e *Engine) GoalChecks(ctx context.Context, id string) ([]GoalCheck, error)

GoalChecks reports whether a goal can be assessed: a title, a qualitative objective, a goal parent for an objective or an objective parent for an outcome, one to three key results each with a baseline (or an admitted unknown) and a target, scoring evidence, and at least one KPI referencing it. No check mentions a team or a cycle: the goal is the root of the dependency tree and never references a lower component, so nothing here reads spec.team or spec.reviewCycle, both removed from the schema.

func (*Engine) GoalTree

func (e *Engine) GoalTree(ctx context.Context) (GoalTree, error)

GoalTree computes the goal tree from every current Goal manifest plus the reference index (which counts as aligned to a goal).

func (*Engine) Handoff

func (e *Engine) Handoff(ctx context.Context, projectID, actor string, req HandoffRequest) (HandoffResult, error)

Handoff records a project's handoff and stores the charter bundle through the BundleStore port. It passes HandoffGate first, writes the bundle, then records the state transition with the version and the bundle's location. Refused when nowhere keeps bundles.

func (*Engine) HandoffGate

func (e *Engine) HandoffGate(ctx context.Context, projectID string) (snapshot int, err error)

HandoffGate is the rule a handoff must pass, and the version it hands off: no blocking check, at least one saved version, and that version not already handed off. Callers that render a document before handing off ask this first, so nothing is rendered for a project that would be refused. Handoff asks it again; the rule lives here once.

func (*Engine) HasState

func (e *Engine) HasState() bool

HasState reports whether the store offers an apply gate.

func (*Engine) ImportDir

func (e *Engine) ImportDir(ctx context.Context, dir, actor, reason string) (Report, error)

ImportDir reads every .yaml/.yml file under dir (recursively; a manifest's own kind and metadata.id decide where it goes, not its file path), validates the whole set together so members can reference each other, and if every file is valid commits them all in one transaction. If any file has a problem, nothing is written.

func (*Engine) Kinds

func (e *Engine) Kinds() []KindInfo

Kinds lists every registered kind and how many manifests exist for it. A store failure degrades to a zero count rather than an error, since the kind registry itself never fails and this method has no error return.

func (*Engine) List

func (e *Engine) List(ctx context.Context, kind string, f Filter, includeDrafts bool) ([]Summary, error)

List returns summaries of every manifest of a kind matching f. Sorted by id throughout, the same order ListSummaries's own committed results already use.

func (*Engine) ListAllVersions

func (e *Engine) ListAllVersions(ctx context.Context, limit int, cursor string) ([]store.Version, string, error)

ListAllVersions returns every version across all kinds, newest first, with pagination.

func (*Engine) ListExcluded

func (e *Engine) ListExcluded(ctx context.Context) ([]store.Exclusion, error)

ListExcluded lists every excluded manifest, newest first.

func (*Engine) ListUnapplied

func (e *Engine) ListUnapplied(ctx context.Context) ([]UnappliedRef, error)

ListUnapplied lists every manifest present but not yet included and not excluded. An empty list, never nil.

func (*Engine) OperationChecks

func (e *Engine) OperationChecks(ctx context.Context, id string) ([]ProgrammeCheck, error)

OperationChecks says whether an operation is described well enough to be run and measured, step by step. Advisory only, like a programme's (D6): an operation is a service that already runs, and nothing about how it is written down should stop anything.

func (*Engine) ProgrammeChecks

func (e *Engine) ProgrammeChecks(ctx context.Context, id string) ([]ProgrammeCheck, error)

ProgrammeChecks reads one programme and everything that points at it.

func (*Engine) ProjectChecks

func (e *Engine) ProjectChecks(ctx context.Context, id string, draft bool) (ProjectChecks, error)

ProjectChecks computes every per-section check for a project, evaluating the current committed version. Checks never block a save; they only report, and drive the draft-to-in-review submission gate (Blocking == 0).

func (*Engine) PutWorking

func (e *Engine) PutWorking(ctx context.Context, kind, id string, yamlBytes []byte) 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. It also re-indexes the manifest's outgoing references.

func (*Engine) Recover

func (e *Engine) Recover(ctx context.Context, ref, actor, reason string) (State, error)

Recover re-includes an excluded manifest, then reloads and reindexes.

func (*Engine) References

func (e *Engine) References(ctx context.Context, kind, id string) (Refs, error)

References returns what a manifest points to (Outgoing) and what points back at it (Incoming).

func (*Engine) Reindex

func (e *Engine) Reindex(ctx context.Context) error

Reindex walks every current manifest and indexes its outgoing references. Called after the vault rehydrates to rebuild the reference index from scratch. Also stores working copies so ListReferencing can find them.

func (*Engine) SaveWorking

func (e *Engine) SaveWorking(ctx context.Context, kind, id string, text []byte, actor string) error

SaveWorking writes a whole working copy, as an autosave or an import does, and folds it into the manifest's shared draft, so a client that saves whole documents and one that syncs end in the same draft.

func (*Engine) Schema

func (e *Engine) Schema(kind string) (map[string]any, error)

func (*Engine) SchemaJSON

func (e *Engine) SchemaJSON(kind string) ([]byte, error)

Schema returns the raw JSON Schema document for a kind. SchemaJSON returns a kind's schema exactly as it is written on disk.

Schema() decodes into a map, which loses the order the properties were written in; the interface builds a sheet's columns from that order, so serving the decoded map alphabetised every sheet. This serves the file.

func (*Engine) SeedStandardUnits

func (e *Engine) SeedStandardUnits(ctx context.Context) ([]string, error)

SeedStandardUnits writes the standard units into a store that holds no Unit at all, and reports which it wrote.

Guarded twice, and the second guard is the one that matters. The first is "none at all" rather than each one, so a vault that has dropped a unit it does not want keeps it dropped. The second refuses to write over a manifest that already exists, because the first guard reads a listing, and a listing is empty for two different reasons: the vault holds no units, or the vault's index has not been built yet. Opening the Strategic Plan vault without its (generated, uncommitted) index took the second for the first and rewrote all nine of its unit files, reordering their keys and dropping their quoting, on a read-only visit (2026-09-29).

Writes through the ordinary commit path, so a seeded unit is a manifest like any other and can be edited, renamed or deleted.

func (*Engine) Shape

func (e *Engine) Shape(kind string) crdt.Shape

Shape says how a kind's manifests map onto a CRDT document, read from the kind's schema so the engine and every interface agree without either deciding it by hand:

  • A list of objects is keyed by x-cartograph-list-key when the schema names one, otherwise by "id" when its items have an id. A keyed item keeps its identity when other items move, so an edit inside it is never lost to a reorder.
  • A string is a text, merged character by character, when it is free prose: no enum, const, format, pattern, or x-cartograph-ref. Everything else (an id, a reference, a date, a choice) is a scalar, where the last write wins and a concurrent one is kept as a conflict, because merging two ids character by character would produce an id nobody wrote.

func (*Engine) Shared

func (e *Engine) Shared() *Shared

Shared returns the shared-draft service, or nil when the engine has no CRDT, document store or fan-out.

func (*Engine) Snapshot

func (e *Engine) Snapshot(ctx context.Context, kind, id string, yamlBytes []byte, reason, operator string) (Version, error)

Snapshot validates a manifest and, if it is valid, stores it as a new immutable version with the reason and operator as the actor. Similar to Commit but used explicitly for creating snapshots. The manifest's metadata.id must match id. operator is recorded as the actor. For a Project with no state history, appends a "defined" state entry.

func (*Engine) TransitionProjectState

func (e *Engine) TransitionProjectState(ctx context.Context, id, to, actor, reason string) (ProjectState, error)

TransitionProjectState moves a project to state to, recording actor and reason. draft to in review is allowed only when the project's checks (against its current committed version) have zero blocking items; otherwise this returns a *ValidationError carrying those blocking items as problems, for a 422 response. cancelled requires a reason, from any non-terminal state. Every other move must be exactly the next state in the fixed sequence.

func (*Engine) Validate

func (e *Engine) Validate(ctx context.Context, kind string, yamlBytes []byte) ([]Problem, error)

Validate checks a manifest's schema, its references and its kind's rules, in that order, against the current store state (no in-flight import batch).

func (*Engine) Versions

func (e *Engine) Versions(ctx context.Context, kind, id string) ([]Version, error)

Versions returns every version of a manifest, oldest first.

type Event

type Event struct {
	Type string    `json:"type"` // version, state
	Kind string    `json:"kind,omitempty"`
	ID   string    `json:"id,omitempty"`
	On   time.Time `json:"on"`
	// Seq is the version number for a version event.
	Seq int64 `json:"seq,omitempty"`
	// Actor is who did it.
	Actor string `json:"actor,omitempty"`
	// Field is where, when the event concerns one field.
	Field string `json:"field,omitempty"`
}

Event is one thing that happened to a manifest that an open interface wants to know about without asking: a version saved, its state changed. Interfaces subscribe through the Bus; transports (an SSE stream, an in-process channel) carry what the bus emits. Live edits and presence are not events: they travel on the sync socket.

type FileProblems

type FileProblems struct {
	File     string    `json:"file"`
	Problems []Problem `json:"problems"`
}

type Filter

type Filter struct {
	Q    string
	Refs []Ref
}

Filter narrows List: Q is a case-insensitive substring over id and name; every entry in Refs must match one of the manifest's outgoing references (logical AND).

type GapClaim

type GapClaim struct {
	Kind string `json:"kind"`
	ID   string `json:"id"`
	Name string `json:"name"`
	// Segments of the gap this work reaches. Empty means the whole gap,
	// which is what an unqualified citation says.
	Segments []string `json:"segments,omitempty"`
	// Whole is true when the citation named no segments.
	Whole bool `json:"whole"`
}

GapClaim is one piece of work addressing one gap.

type GapCoverage

type GapCoverage struct {
	Gap string `json:"gap"`
	// Segments in the gap's own order, each with the work addressing it.
	Segments []GapSegmentCoverage `json:"segments"`
	// Claims on the gap as a whole: citations that named no segments.
	Whole []GapClaim `json:"whole,omitempty"`
}

GapCoverage is a gap's scope and what reaches each part of it.

type GapSegmentCoverage

type GapSegmentCoverage struct {
	Segment   string     `json:"segment"`
	Name      string     `json:"name"`
	Addressed []GapClaim `json:"addressedBy,omitempty"`
}

GapSegmentCoverage is one of a gap's segments and who is addressing it.

type GoalAligned

type GoalAligned struct {
	Projects   int `json:"projects"`
	Programmes int `json:"programmes"`
	Operations int `json:"operations"`
	KPIs       int `json:"kpis"`
}

GoalAligned is how many manifests of each kind reference a goal, by referencing kind. Anything that references a goal counts as aligned to it; kinds outside this set are not counted here.

type GoalCheck

type GoalCheck struct {
	ID      string        `json:"id"`
	State   string        `json:"state"` // ok, warn
	Message string        `json:"message"`
	Fix     *GoalCheckFix `json:"fix,omitempty"`
}

GoalCheck is one assessability check on a Goal. Checks never block a save; they only report.

type GoalCheckFix

type GoalCheckFix struct {
	Section string `json:"section"`
}

GoalCheckFix names which section of the goal editor addresses a check.

type GoalGap

type GoalGap struct {
	ID      string `json:"id"`
	Name    string `json:"name"`
	Current string `json:"current,omitempty"`
	Desired string `json:"desired,omitempty"`
}

GoalGap is a gap that names this goal as the outcome that closes it.

type GoalLink struct {
	Goal    string `json:"goal" yaml:"goal"`
	Because string `json:"because,omitempty" yaml:"because"`
}

GoalLink is an outcome leading to a higher objective, and why.

type GoalNode

type GoalNode struct {
	ID         string      `json:"id"`
	Name       string      `json:"name"`
	Level      string      `json:"level"`
	Parent     string      `json:"parent,omitempty"`
	KeyResults int         `json:"keyResults"`
	Aligned    GoalAligned `json:"aligned"`
	Children   []*GoalNode `json:"children"`
	// What the Strategy view reads (D24): the statement, why it matters,
	// what else it leads to, and the gaps it would close.
	Objective     string     `json:"objective,omitempty"`
	Why           string     `json:"why,omitempty"`
	ContributesTo []GoalLink `json:"contributesTo,omitempty"`
	Gaps          []GoalGap  `json:"gaps,omitempty"`
	// Which SMART letters it meets (D25), for a mark on every card.
	Smart Smart `json:"smart"`
	// The role accountable for it, and the period it covers (its own or
	// its parent's), so every card carries its context (D26).
	Owner   string   `json:"owner,omitempty"`
	Horizon *Horizon `json:"horizon,omitempty"`
}

GoalNode is one record in the tree, with its objectives nested as Children (for a goal) or its outcomes nested as Children (for an objective), or no children (for an outcome).

type GoalTree

type GoalTree struct {
	Levels []string    `json:"levels"`
	Nodes  []*GoalNode `json:"nodes"`
}

GoalTree is the whole tree: every level's display name, and the root goals, each carrying its objectives as Children, and each objective carrying its outcomes as Children.

type HandoffRequest

type HandoffRequest struct {
	HtmlBytes []byte // Rendered HTML charter
	JsonBytes []byte // Rendered JSON charter
	PdfBytes  []byte // Rendered PDF charter (optional, can be nil)
}

HandoffRequest carries the rendered charter a handoff stores.

type HandoffResult

type HandoffResult struct {
	HtmlPath string
	JsonPath string
	PdfPath  string
	Bundle   string // what the state history records: the bundle's location
}

HandoffResult is returned by Handoff on success: where the charter bundle went (HTML, JSON, and PDF when one was printed).

type Horizon

type Horizon struct {
	Start string `json:"start"`
	End   string `json:"end"`
	// Inherited is true when the aim has none of its own and takes its
	// parent's.
	Inherited bool `json:"inherited,omitempty"`
}

Horizon is the period an aim covers, as "YYYY-MM" at each end.

type ImportedItem

type ImportedItem struct {
	Kind    string `json:"kind"`
	ID      string `json:"id"`
	Version int    `json:"version"`
}

type KindInfo

type KindInfo struct {
	Kind  string `json:"kind"`
	Count int    `json:"count"`
}

KindInfo is one row of GET /api/v1/kinds.

type MemoryBus

type MemoryBus struct {
	// contains filtered or unexported fields
}

MemoryBus is the in-process Bus.

func NewMemoryBus

func NewMemoryBus() *MemoryBus

NewMemoryBus returns an empty bus.

func (*MemoryBus) Publish

func (b *MemoryBus) Publish(ev Event)

func (*MemoryBus) Subscribe

func (b *MemoryBus) Subscribe(ctx context.Context, kind, id string) *Subscription

type Option

type Option func(*Engine)

Option configures an Engine beyond its two required stores.

func WithBundles

func WithBundles(b store.BundleStore) Option

WithBundles attaches where handoff bundles are kept. Without it, a handoff is refused.

func WithBus

func WithBus(b Bus) Option

WithBus sets the event bus; the in-process one when none is given.

func WithCRDT

func WithCRDT(c crdt.Engine) Option

WithCRDT, WithDocStore and WithFanout give the engine what shared drafts need (docs/adr/0007, 0008). All three, or shared drafts are off.

func WithCodec

func WithCodec(c codec.Codec) Option

WithCodec sets the manifest syntax. Every store carries text in this codec; the engine never parses a syntax itself.

func WithDocStore

func WithDocStore(d store.DocStore) Option

func WithFanout

func WithFanout(f fanout.Bus) Option

func WithState

func WithState(s store.StateStore) Option

WithState attaches the apply gate (store.StateStore) the manifest store offers. Without it, the state endpoints answer ErrNoState.

type Problem

type Problem struct {
	Path    string `json:"path"`
	Message string `json:"message"`
}

Problem is one validation failure. Path is a JSON pointer into the manifest.

type ProgrammeCheck

type ProgrammeCheck struct {
	ID      string `json:"id"`
	Section string `json:"section"`
	State   string `json:"state"`
	Message string `json:"message"`
}

ProgrammeCheck is one advisory line about a programme, and the step of the walk a reader would go to about it.

type ProjectCheckFix

type ProjectCheckFix struct {
	Phase   string `json:"phase"`
	Section string `json:"section"`
}

ProjectCheckFix names where in the definition journey a check's problem is fixed. It usually matches the check's own Phase/Section, except for a handful of checks (for example the operational owner binding, edited in the People section of Initiation even though the check itself belongs to the Landing phase) where the editable field lives elsewhere.

type ProjectCheckItem

type ProjectCheckItem struct {
	ID      string          `json:"id"`
	Section string          `json:"section"`
	Phase   string          `json:"phase"`
	State   string          `json:"state"`
	Message string          `json:"message"`
	Fix     ProjectCheckFix `json:"fix"`
}

ProjectCheckItem is one row of GET /manifests/Project/{id}/checks. State block stops submission (draft to in review); warn never does.

type ProjectChecks

type ProjectChecks struct {
	DerivedEnd string             `json:"derivedEnd,omitempty"`
	Blocking   int                `json:"blocking"`
	Items      []ProjectCheckItem `json:"items"`
}

ProjectChecks is the full result: the derived end month (empty when the timeline cannot be computed), how many items block submission, and every check.

type ProjectState

type ProjectState struct {
	State   string              `json:"state"`
	History []ProjectStateEntry `json:"history"`
}

ProjectState is the result of GET and POST .../state: the current state (a project with no history is implicitly draft) and its full history, oldest first.

type ProjectStateEntry

type ProjectStateEntry struct {
	State    string    `json:"state"`
	Actor    string    `json:"actor"`
	Reason   string    `json:"reason,omitempty"`
	On       time.Time `json:"on"`
	Snapshot int       `json:"snapshot,omitempty"`
	Bundle   string    `json:"bundle,omitempty"`
}

ProjectStateEntry is one row of a project's state history.

type Purpose

type Purpose struct {
	Vision  string `json:"vision,omitempty" yaml:"vision"`
	Mission string `json:"mission,omitempty" yaml:"mission"`
	Source  string `json:"source,omitempty" yaml:"source"`
}

Purpose is the vault's vision and mission, stated once above every goal.

type Ref

type Ref struct {
	Kind string `json:"kind"`
	ID   string `json:"id"`
	Path string `json:"path,omitempty"`
}

Ref is one reference between manifests. Used both as a filter (only Kind and ID are read) and as an outgoing reference (Path populated too).

type Refs

type Refs struct {
	Outgoing []Ref     `json:"outgoing"`
	Incoming []Summary `json:"incoming"`
}

Refs is the result of References: what a manifest points to, and what points back at it.

type Report

type Report struct {
	Imported []ImportedItem `json:"imported"`
	Problems []FileProblems `json:"problems"`
	Notes    []FileProblems `json:"notes,omitempty"` // one per file that needed a legacy-field rewrite (see rewriteLegacyFields)
}

Report is the result of ImportDir. When any file has problems, nothing in the batch is written: Imported is empty and Problems lists what to fix.

type ScheduleConflict

type ScheduleConflict struct {
	Edge     DependencyEdge `json:"edge"`
	NeedByOn string         `json:"needByOn"`
	ReadyOn  string         `json:"readyOn"`
}

ScheduleConflict is a dependency that cannot land in time: the work waiting needs it by a phase that ends before the work it waits on finishes.

type Settings

type Settings struct {
	GoalLevels       []string `json:"goalLevels"`
	ProjectLevelName string   `json:"projectLevelName"`
	Operator         string   `json:"operator"`
	Chromium         string   `json:"chromium"`
	// Examples a vault supplies per field, in its own words (TAXONOMY.md
	// D20). Empty when the vault supplies none.
	Examples map[string][]string `json:"examples,omitempty"`
	// Why everything below exists: the vision and mission (D24).
	Purpose *Purpose `json:"purpose,omitempty"`
}

Settings is the one singleton configuration manifest (kind Settings, id "default"), read from an optional settings.yaml at an import directory's root. Defaults apply when none was imported.

type Shared

type Shared struct {
	// contains filtered or unexported fields
}

Shared is the shared draft of every manifest: one CRDT document each, held in the DocStore, edited by every interface over the sync protocol, and materialised into the working copy so everything that reads working copies keeps working.

It is stateless in the sense the process model needs. The documents it holds are a cache: before every use it folds in whatever chunks other replicas have stored since, so a request served by any replica sees the same document, and a replica that starts empty, or is killed, loses nothing.

func (*Shared) Conflicts

func (s *Shared) Conflicts(ctx context.Context, kind, id string) ([]crdt.Conflict, error)

Conflicts returns the fields of a manifest's draft that hold concurrent values: the conflict notes, derived on read, so no replica keeps them.

func (*Shared) DocumentFor

func (s *Shared) DocumentFor(ctx context.Context, kind, id string) (string, error)

DocumentFor returns the id of a manifest's shared draft, creating it from the working copy or the current version on first use. When the working copy has changed outside the draft (a file edited in a vault, an import), the change is folded in first, so the draft never shows less than the working copy does.

func (*Shared) Forget

func (s *Shared) Forget(docID string)

Forget drops a document from this replica's cache. Nothing is lost: the next use loads it from the store.

func (*Shared) Generate

func (s *Shared) Generate(ctx context.Context, docID string, peer crdt.SyncState) ([]byte, bool, error)

Generate returns the next sync message for a peer, after folding in what other replicas stored; ok is false when the peer is up to date.

func (*Shared) ManifestFor

func (s *Shared) ManifestFor(ctx context.Context, docID string) (kind, id string, err error)

ManifestFor names the manifest a document is the draft of. The presence document answers kind "" and id "presence".

func (*Shared) NewSyncState

func (s *Shared) NewSyncState() (crdt.SyncState, error)

NewSyncState returns the sync state for a new peer of a document.

func (*Shared) PresenceDocument

func (s *Shared) PresenceDocument(ctx context.Context) (string, error)

PresenceDocument returns the id of the document that routes presence on screens not about one manifest.

func (*Shared) Receive

func (s *Shared) Receive(ctx context.Context, docID string, peer crdt.SyncState, msg []byte, canWrite bool) (changed bool, err error)

Receive applies a sync message from a peer. A principal who may not write may still sync, to read; a message of theirs that would change the document is refused, and the document is left as it was. The presence document takes no changes from anyone.

func (*Shared) Reconcile

func (s *Shared) Reconcile(ctx context.Context, kind, id string, content map[string]any, message string) error

Reconcile folds a whole document into a manifest's shared draft as one change: what SaveWorking, an import or a changed file means for the draft. It creates the draft when the manifest has none yet.

func (*Shared) Replica

func (s *Shared) Replica() string

Replica is this process's id on the fan-out, so it can tell its own hints from others'.

type Smart

type Smart struct {
	Specific   bool `json:"specific"`
	Measurable bool `json:"measurable"`
	Attainable bool `json:"attainable"`
	Relevant   bool `json:"relevant"`
	TimeBound  bool `json:"timeBound"`
}

Smart is how far one goal, objective or outcome meets the SMART criteria (Doran, "There's a S.M.A.R.T. way to write management's goals and objectives", Management Review, 1981; the current reading, Specific, Measurable, Attainable, Relevant, Time-bound). TAXONOMY.md D25, D26.

Each letter is read from what the record already holds, never typed:

  • Specific: a statement, with the numbers left to the measures.
  • Measurable: at least one measure, a key result of its own or an indicator (KPI) aligned to it, with a target.
  • Attainable: the target can reasonably be reached: every measure has today's figure (or an admitted unknown), dated before its target, and the target moves the way the measure says it should. Cartograph cannot judge ambition; it catches a target that cannot be reached as written.
  • Relevant: it sits under the right level (a goal under the vault's vision and mission) and says why it matters.
  • Time-bound: every target has an end date, inside the aim's horizon when it has one (its own, or its parent's).

type State

type State struct {
	Name     string
	Included []string
}

State is the apply gate as the API presents it: the state manifest's id and what it includes.

type Subscription

type Subscription struct {
	C <-chan Event
	// contains filtered or unexported fields
}

Subscription is one listener on the bus.

func (*Subscription) Close

func (s *Subscription) Close()

Close stops the subscription.

type Summary

type Summary = store.Summary

Version and Summary are exactly the records store.ManifestStore and store.OperationalStore persist; the engine re-exports them by alias so callers only need one set of names, and so store adapters (which must be usable without importing the engine) stay the source of truth for their own shapes.

type UnappliedRef

type UnappliedRef = store.UnappliedRef

UnappliedRef is one manifest that could be applied.

type ValidationError

type ValidationError struct {
	Problems []Problem
}

ValidationError carries the problems found by schema, reference or kind rule validation. Commit and Propose return it (wrapped) instead of a separate problems slice, since their public signatures return only a value and an error; an API handler recovers it with errors.As and answers 422 with {problems: [...]}.

func (*ValidationError) Error

func (e *ValidationError) Error() string

type Version

type Version = store.Version

Version and Summary are exactly the records store.ManifestStore and store.OperationalStore persist; the engine re-exports them by alias so callers only need one set of names, and so store adapters (which must be usable without importing the engine) stay the source of truth for their own shapes.

Jump to

Keyboard shortcuts

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