board

package
v0.12.1 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package board is the planner's store and rules (ADR 0005): epics, stories and subtasks for each Project, kept in one SQLite database through modernc.org/sqlite.

Every rule in ADR 0005 §1–§9 is enforced here, inside the transaction of the write it guards: the actor table, derived container status, scope and caps, holds and their single release path, requests, split, cancel, cascade, restore, the expiry sweep and purge. The package knows nothing about HTTP, Copilot, the session store or git: evidence, HEAD and working tree state are supplied by the caller.

"Task" always means a uam conversation. The leaf card kind is subtask.

Index

Constants

View Source
const (
	PrioHigh    = 1
	PrioMedium  = 2
	PrioLow     = 3
	PrioDefault = PrioLow
)

The priority scale: 1 high, 2 medium, 3 low (the default).

View Source
const (
	CapCreated     = 20 // cards a Task may create
	CapUnconfirmed = 10 // live unconfirmed children a Task may add to one container, the root included
	CapComments    = 20 // non-automatic comments a Task may add to one card
)

Caps counted per Task (ADR 0005 §4). Calls made by a Task's subagents count against the Task.

View Source
const (
	AuthorOwner = "owner"
	AuthorUAM   = "uam"
)

Comment authors.

View Source
const (
	FlagAcceptanceCouldNotRun = "acceptance_could_not_run"
	FlagNoChangeInTree        = "no_change_in_tree"
	FlagTestsOrBuildChanged   = "tests_or_build_changed"
	FlagOverlap               = "overlap"
	// FlagBaselineMissing marks evidence gathered without the hold's
	// baseline commit, which no longer exists.
	FlagBaselineMissing = "baseline_missing"
)

The flags a done request may carry. The caller gathers the evidence and decides the flags; the store only records them.

View Source
const DefaultEffort = "S"

DefaultEffort is the estimate a card takes when none is given.

View Source
const ExpiryWindow = 14 * 24 * time.Hour

ExpiryWindow is how long an agent-created card stays unconfirmed before the sweep cancels it.

View Source
const FileName = "board.db"

FileName is the planner database's file name, created beside the session store.

View Source
const SimilarityFloor = 0.34

SimilarityFloor rejects candidates sharing too little title vocabulary.

Variables

View Source
var ErrNotFound = &Error{Code: CodeNotFound}

ErrNotFound matches, with errors.Is, every not-found refusal.

Functions

func Similarity

func Similarity(a, b string) float64

Similarity is the Sørensen–Dice coefficient over normalized title token sets.

func TaskAuthor

func TaskAuthor(taskID string) string

TaskAuthor is the comment author for a Task.

Types

type Actor

type Actor struct {
	Role    Role
	TaskID  string
	AgentID string
	// Head is the Project's HEAD at the time of an owner write. Every owner
	// touch pins the touched card to it.
	Head string
	// Proposals limits an agent to proposals, as a Utility job is (ADR 0005
	// §18): its edit of a confirmed card is refused rather than filed as a
	// change request.
	Proposals bool
}

Actor is who makes a write. An agent is identified by its Task, plus the subagent's ID when a subagent made the call; caps count against the Task.

func Agent

func Agent(taskID, agentID string) Actor

Agent is the actor for a Task's agent, or one of its subagents.

func Owner

func Owner(head string) Actor

Owner is the owner actor. head is the Project's HEAD, "" when unknown.

type Baseline

type Baseline struct {
	Head  string            `json:"head"`
	Dirty []string          `json:"dirty"`
	Blobs map[string]string `json:"blobs,omitempty"`
}

Baseline is the working tree state recorded when a hold starts. Blobs maps each dirty path to the blob name of its content then, "" when the path did not exist; a dirty path missing from it counts as changed since.

type Card

type Card struct {
	ID           string
	Seq          int64
	ProjectID    string // "" is the read-only Unassigned list
	Kind         Kind
	ParentID     string // "" at the root
	Rank         int
	Title        string
	Desc         string
	WinCondition string
	Status       Status
	Progress     *Progress
	Prio         int
	Due          string
	Effort       string
	Labels       []string
	Checklist    []Check
	Blocked      bool
	BlockedBy    []string
	Blocks       []string
	// ExpiresAt is nil once the card is confirmed.
	ExpiresAt *time.Time
	HeldBy    string
	PinnedSHA string
	// AcceptCmd is nil to inherit the Project default, "" for none.
	AcceptCmd       *string
	Paths           []string
	CascadeID       string
	CreatedBy       string
	PendingRequests int
	Revision        int64
	CreatedAt       time.Time
	UpdatedAt       time.Time
	MovedAt         time.Time
}

Card is one node on a board. Status and Progress are derived for containers; Progress is nil on subtasks.

func (Card) Confirmed

func (c Card) Confirmed() bool

Confirmed reports whether the owner has saved, launched, accepted or restored the card.

type Change

type Change struct {
	ProjectID string
	Revision  int64
	Cards     []string
	Removed   []string
	Requests  []string
}

Change describes one committed write to one Project's board: the Project's new revision, the cards whose stored or derived state changed (ancestors included), the cards removed and the requests written.

type Check

type Check struct {
	Text string `json:"text"`
	Done bool   `json:"done"`
}

Check is one checklist item.

type ChecklistEdit

type ChecklistEdit struct {
	Tick   []int
	Untick []int
	Add    []string
}

ChecklistEdit ticks, unticks and appends checklist items; indexes are zero-based into the current checklist.

type Code

type Code string

Code classifies a refusal so callers can map it to their own errors.

const (
	CodeGuardOpenItems Code = "guard_open_items"
	CodeGuardBlockers  Code = "guard_blockers"
	CodeGuardBlocked   Code = "guard_blocked"
	CodeNotHeld        Code = "not_held"
	CodeReadOnly       Code = "read_only"
	CodeInvalid        Code = "invalid"
	CodeNotFound       Code = "not_found"
	CodeForbidden      Code = "forbidden"
	CodeLimit          Code = "limit"
	CodeDuplicate      Code = "duplicate"
	// The acceptance refusals (ADR 0005 §6), raised by the caller that runs
	// acceptance: the Project's runner stayed busy past the timeout, or the
	// command exited non-zero.
	CodeAcceptanceBusy   Code = "acceptance_busy"
	CodeAcceptanceFailed Code = "acceptance_failed"
)

The refusal codes. The first six are ADR 0005 §14's.

const CodeImportBusy Code = "import_busy"

CodeImportBusy refuses an import whose source kept changing while it was copied.

const CodeImportSchema Code = "import_schema"

CodeImportSchema refuses a source board at a schema version Import does not read.

func CodeOf

func CodeOf(err error) Code

CodeOf returns err's refusal code, or "" when err is not a refusal.

type Comment

type Comment struct {
	ID        int64
	CardID    string
	Author    string
	AgentID   string
	Body      string
	Automatic bool
	// Close marks the comment a card was finished with; a container's
	// roll-up is made of its children's close comments.
	Close     bool
	CreatedAt time.Time
}

Comment is one comment on a card. Automatic comments are written by uam and are exempt from the caps.

type Detail

type Detail struct {
	Card     Card
	Comments []Comment
	Requests []Request
	Holds    []Hold
}

Detail is one card with its comments, requests and hold history.

type EditResult

type EditResult struct {
	Card    Card
	Request *Request
}

EditResult is an edit's outcome: the card, and the change request filed instead when an agent edited a confirmed card.

type Error

type Error struct {
	Code    Code
	Message string
	Refs    []string
}

Error is a refusal from a board rule. Refs lists the cards or items the refusal is about, such as open checklist items or open blockers.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

Is matches another *Error with the same code, so errors.Is(err, ErrNotFound) works.

type Filter

type Filter struct {
	// Query is free text matched against title, description and labels:
	// every word must appear, the last as a prefix.
	Query  string
	Status Status
	Kind   Kind
	// Parent is a card ref; only its direct children match.
	Parent string
}

Filter narrows List. Zero fields match every card.

type Finishable

type Finishable struct {
	Card      Card
	AcceptCmd string
}

Finishable is a subtask that passed the finishing guard, with the acceptance command it resolves to ("" for none).

type Hold

type Hold struct {
	ID        string
	CardID    string
	TaskID    string
	Attempt   int
	StartedAt time.Time
	Baseline  Baseline
	EndedAt   *time.Time
	EndReason ReleaseReason
}

Hold is one attempt at a subtask by a Task.

type ImportReport

type ImportReport struct {
	Imported   int          `json:"imported"`
	Updated    int          `json:"updated"`
	Unassigned int          `json:"unassigned"`
	Comments   int          `json:"comments"`
	Links      int          `json:"links"`
	Skipped    []ImportSkip `json:"skipped"`
}

ImportReport is what one Import did. Imported counts the cards it added, Unassigned how many of those went to the Unassigned list, and Updated the existing cards it changed. Comments and Links count the comments and blocker links it copied. Skipped lists the source tasks, by their ID, that it left alone, and why.

type ImportSkip

type ImportSkip struct {
	ID     string `json:"id"`
	Reason string `json:"reason"`
}

ImportSkip is one source task an import left alone.

type Kind

type Kind string

Kind is a card's place in the tree. Kinds rank epic < story < subtask, and a parent must outrank its child.

const (
	KindEpic    Kind = "epic"
	KindStory   Kind = "story"
	KindSubtask Kind = "subtask"
)

The card kinds. Subtask is the leaf; epics and stories are containers.

type NewCard

type NewCard struct {
	ProjectID    string
	Kind         Kind
	ParentID     string // a card ref; "" creates at the root
	Title        string
	Desc         string
	WinCondition string
	Prio         int // 0 takes PrioDefault
	Due          string
	Effort       string // "" takes DefaultEffort
	Labels       []string
	Checklist    []Check
}

NewCard is a card to create. A card created by the owner is confirmed; one created by an agent expires ExpiryWindow after creation unless confirmed.

type Options

type Options struct {
	Now   func() time.Time
	NewID func() string
}

Options supplies the store's clock and ID source. Zero fields use time.Now and random UUIDs.

type Patch

type Patch struct {
	Title        *string   `json:"title,omitempty"`
	Desc         *string   `json:"desc,omitempty"`
	WinCondition *string   `json:"win_condition,omitempty"`
	Prio         *int      `json:"prio,omitempty"`
	Due          *string   `json:"due,omitempty"`
	Effort       *string   `json:"effort,omitempty"`
	Labels       *[]string `json:"labels,omitempty"`
	Checklist    *[]Check  `json:"checklist,omitempty"`
	// ParentID moves the card: a card ref, or "" for the root.
	ParentID *string `json:"parent_id,omitempty"`
	// Rank places the card at that index among its siblings.
	Rank *int `json:"rank,omitempty"`

	Blocked *bool `json:"-"`
	// AcceptCmd sets the subtask's acceptance command: an invalid
	// NullString inherits the Project default, a valid "" means none.
	AcceptCmd *sql.NullString `json:"-"`
	Paths     *[]string       `json:"-"`
	// ProjectID moves a card out of Unassigned into a Project.
	ProjectID *string `json:"-"`
}

Patch is a partial card update; nil fields are left unchanged. The owner-only fields never appear in a change request.

type Progress

type Progress struct {
	Done     int
	Total    int
	Proposed int
}

Progress is a container's done ÷ non-cancelled confirmed leaves, plus the unconfirmed leaves shown as "+N proposed".

type ProjectSettings

type ProjectSettings struct {
	ProjectID string
	AcceptCmd string
}

ProjectSettings holds a Project's planner settings. AcceptCmd is the default acceptance command, "" for none.

type ReleaseReason

type ReleaseReason string

ReleaseReason is why a hold ended. Every hold ends through ReleaseHold's single path with one of these.

const (
	ReleaseAccepted  ReleaseReason = "accepted"  // request accepted → done
	ReleaseDone      ReleaseReason = "done"      // owner marked the subtask done
	ReleaseRejected  ReleaseReason = "rejected"  // request rejected, holder not live → todo
	ReleaseSettled   ReleaseReason = "settled"   // Settle dialog released it → todo
	ReleaseEnded     ReleaseReason = "ended"     // Task archived or deleted → todo
	ReleaseOwner     ReleaseReason = "released"  // owner Release → todo
	ReleaseCancelled ReleaseReason = "cancelled" // owner cancel or cascade → cancelled
	ReleaseSplit     ReleaseReason = "split"     // the subtask became a story; the hold moved
)

The release reasons (ADR 0005 §5).

type Request

type Request struct {
	ID              string
	CardID          string
	TaskID          string
	AgentID         string
	Kind            RequestKind
	Comment         string
	Payload         json.RawMessage
	Evidence        json.RawMessage
	Flags           []string
	BaseRevision    int64
	Status          RequestStatus
	CreatedAt       time.Time
	DecidedAt       *time.Time
	DecisionComment string
}

Request is one inbox row. BaseRevision is the card's revision when it was filed.

type RequestInput

type RequestInput struct {
	Kind    RequestKind
	Comment string
	// Evidence and Flags belong to done requests.
	Evidence json.RawMessage
	Flags    []string
	// Blocker is a blocked request's optional blocking card ref; accepting
	// the request links it instead of setting the blocked flag.
	Blocker string
	// ProposedAcceptCmd is text only; it never runs until the owner copies
	// it into the subtask.
	ProposedAcceptCmd string
}

RequestInput is an agent's done, cancel or blocked request. Split requests are filed by Split and change requests by Edit.

type RequestKind

type RequestKind string

RequestKind is what an agent asks the owner to decide.

const (
	RequestDone    RequestKind = "done"
	RequestCancel  RequestKind = "cancel"
	RequestBlocked RequestKind = "blocked"
	RequestSplit   RequestKind = "split"
	RequestChange  RequestKind = "change"
)

The request kinds.

type RequestStatus

type RequestStatus string

RequestStatus is where a request stands.

const (
	RequestPending   RequestStatus = "pending"
	RequestAccepted  RequestStatus = "accepted"
	RequestRejected  RequestStatus = "rejected"
	RequestWithdrawn RequestStatus = "withdrawn"
)

The request statuses.

type Role

type Role string

Role separates the owner from agents.

const (
	RoleOwner Role = "owner"
	RoleAgent Role = "agent"
)

The roles. The zero Role is neither and is refused.

type SimilarHit

type SimilarHit struct {
	ID     string
	Seq    int64
	Title  string
	Status Status
	Score  float64
}

SimilarHit is a card whose title resembles a query. The similarity check is information only; the duplicate-title rule is the only refusal.

type Snapshot

type Snapshot struct {
	Cards    []Card
	Requests []Request
	Revision int64
}

Snapshot is one Project's board at one revision: every card, including cancelled ones, and the pending requests.

type SplitChild

type SplitChild struct {
	Title        string `json:"title"`
	WinCondition string `json:"win_condition,omitempty"`
}

SplitChild is one subtask a split creates.

type SplitResult

type SplitResult struct {
	Card    Card
	Request *Request
}

SplitResult is a split's outcome: the card as the split left it (a story, or cancelled after a split into siblings), and the split request filed instead when it did not apply.

type Stage

type Stage string

Stage is a Task's lifecycle stage as Reconcile sees it. A Task absent from the map given to Reconcile has been deleted.

const (
	StageActive   Stage = "active"
	StageSettled  Stage = "settled"
	StageArchived Stage = "archived"
)

The Task stages.

type Status

type Status string

Status is a leaf's stored status, or a container's derived one.

const (
	StatusPlanned   Status = "planned"
	StatusTodo      Status = "todo"
	StatusDoing     Status = "doing"
	StatusDone      Status = "done"
	StatusCancelled Status = "cancelled"
)

The statuses. Planned means never launched; todo means released after an attempt, or marked ready by the owner.

type Store

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

Store is the planner database. It is safe for concurrent use: the pool holds one connection, so writers serialize in-process, and a busy database held by another process is retried.

func Open

func Open(path string, opts Options) (*Store, error)

Open opens, creating when needed, the planner database at path with mode 0600, and applies pending migrations. The directory must exist.

func (*Store) Accept

func (s *Store) Accept(ctx context.Context, a Actor, id, comment string) (Request, error)

Accept accepts the pending request id. Accepting a done request needs the subtask doing and held by the requesting Task (unless a split filed it for a ticked item) and the finishing guard to pass; the claim text becomes the close comment and the acceptance is an owner touch. comment is the owner's decision note.

func (*Store) AddComment

func (s *Store) AddComment(ctx context.Context, a Actor, ref, body string) (Comment, error)

AddComment adds a's comment to the card ref. Agents may comment on cards in their scope, up to CapComments per card per Task.

func (*Store) Board

func (s *Store) Board(ctx context.Context, projectID string) (Snapshot, error)

Board returns one Project's snapshot; "" is the Unassigned list.

func (*Store) Card

func (s *Store) Card(ctx context.Context, ref string) (Card, error)

Card returns the card ref.

func (*Store) Cards

func (s *Store) Cards(ctx context.Context, ids []string) ([]Card, error)

Cards returns the cards with the given IDs that still exist, in the order given.

func (*Store) CheckFinishable

func (s *Store) CheckFinishable(ctx context.Context, a Actor, ref string) (Finishable, error)

CheckFinishable runs the finishing guard on the subtask ref for a, so the caller can refuse a claim before running acceptance. For an agent the subtask must also be doing and held by the agent's Task. FileRequest runs the same checks again inside the filing transaction.

func (*Store) Checklist

func (s *Store) Checklist(ctx context.Context, a Actor, ref string, e ChecklistEdit) (Card, error)

Checklist ticks, unticks and adds checklist items. Agents may do this on confirmed cards in their scope too.

func (*Store) Claim

func (s *Store) Claim(ctx context.Context, a Actor, ref string, base Baseline) (Card, error)

Claim starts the agent's Task's hold on the subtask ref, which must be in the Task's scope. A Task may have only one hold without a pending done, blocked or split request at a time, and a planning Task may hold nothing.

func (*Store) Close

func (s *Store) Close() error

Close closes the database.

func (*Store) Confirm

func (s *Store) Confirm(ctx context.Context, a Actor, ref string) (Card, error)

Confirm confirms a card: it stops expiring and is pinned to the owner's HEAD, and so is every unconfirmed ancestor.

func (*Store) Create

func (s *Store) Create(ctx context.Context, a Actor, in NewCard) (Card, error)

Create adds a card. Agents may create stories and subtasks under a container in their scope, and a Task with no scope may propose epics at the root, within the caps; the owner may create any kind anywhere the kind rules allow, and the owner's card confirms its unconfirmed ancestors.

func (*Store) Detail

func (s *Store) Detail(ctx context.Context, ref string) (Detail, error)

Detail returns the card ref with its comments, requests and holds.

func (*Store) Dismiss

func (s *Store) Dismiss(ctx context.Context, a Actor, ref string) (Card, error)

Dismiss cancels an unconfirmed card and everything under it, with the automatic comment "dismissed".

func (*Store) Edit

func (s *Store) Edit(ctx context.Context, a Actor, ref string, p Patch) (EditResult, error)

Edit applies p to the card ref. The owner may edit any field, and the edit confirms the card and its ancestors. An agent edits an unconfirmed card in its scope directly; its edit of a confirmed card is filed as a change request, which replaces the Task's earlier pending one. An agent patch carrying an owner-only field is refused before any write.

func (*Store) FileRequest

func (s *Store) FileRequest(ctx context.Context, a Actor, ref string, in RequestInput) (Request, error)

FileRequest files an agent's done, cancel or blocked request on the card ref. A done request needs the subtask doing and held by the agent's Task and passes the finishing guard; the caller supplies its evidence and flags. A newer request of the same kind from the same Task replaces the older pending one.

func (*Store) Held

func (s *Store) Held(ctx context.Context) ([]Card, error)

Held returns every held subtask on every board, in #seq order.

func (*Store) Import

func (s *Store) Import(ctx context.Context, src string, projects map[string]string) (ImportReport, error)

Import copies the board of the external kb app kept in the directory src, its kb.db at schema v11, into the store in one transaction. projects maps a source project name to a Project ID.

The source is never opened in place: its database, with any -wal and -shm files, is copied into a fresh owner-only temporary directory, read there read-only, and deleted. Symbolic links are refused. A copy that raced a writer is taken again, and a source that keeps changing is refused with CodeImportBusy. Any schema version but v11 is refused with CodeImportSchema.

Each task of the source's default user becomes a confirmed subtask at the root, with no pin, in the Project its project:: tag maps to, or in Unassigned. Title, description, priority, due date, effort, checklist (without blank items) and blocked flag carry over, and every tag but project:: and link:: becomes a label. Repeated titles are kept: the duplicate-title rule does not apply to imports. todo and doing become todo, done done and cancelled cancelled; a task in progress gets the automatic comment "was in progress in kb", and a done or cancelled one the automatic close comment "imported from kb". Comments and cancel reasons are copied as uam's automatic comments, naming their author, and blocker links where both cards are in one Project.

Cards are keyed on the task's UUID, so importing again adds nothing twice. A second import applies only what changed at the source since the last one, so the owner's edits stand until the source changes the same field; it moves a card still in Unassigned into a Project that now maps, copies new comments, and makes each source link not made yet, while the owner's unlinks stand. A change to a held card, to a card cancelled here, or a status the owner could not set directly is skipped and retried by the next import. A purged card is never brought back.

func (*Store) Labels

func (s *Store) Labels(ctx context.Context, projectID string) ([]string, error)

Labels lists a Project's labels, most recently used first.

func (*Store) Launch

func (s *Store) Launch(ctx context.Context, a Actor, ref, taskID string, base Baseline) (Card, error)

Launch starts taskID's hold on the subtask ref and scopes the Task to the subtask's parent. On a container it is "Do whole story": it holds the container's first pending confirmed subtask and scopes the Task to the container. Launch is an owner touch: the held subtask and its unconfirmed ancestors are confirmed and pinned. base is the working tree state the hold's evidence is measured from.

func (s *Store) Link(ctx context.Context, a Actor, blockerRef, blockedRef string) error

Link records "blocker blocks blocked". Both cards must be in the same Project, and the blocker must be confirmed. Self links, duplicates and links that would close a cycle are refused. Agents may link a blocked card in their scope.

func (*Store) List

func (s *Store) List(ctx context.Context, projectID string, f Filter) ([]Card, error)

List returns a Project's cards matching f, in outline order.

func (*Store) OnChange

func (s *Store) OnChange(fn func(Change))

OnChange registers fn to receive each committed write's changes, one per Project, after the commit and outside any transaction. Writers call fn from their own goroutines, so calls may overlap and arrive out of revision order; a Change's Revision orders them.

func (*Store) PendingLeaves

func (s *Store) PendingLeaves(ctx context.Context, ref string) ([]Card, error)

PendingLeaves returns the confirmed subtasks under the container ref that are waiting to be worked on, depth-first, with blocked ones last.

func (*Store) ProjectSettings

func (s *Store) ProjectSettings(ctx context.Context, projectID string) (ProjectSettings, error)

ProjectSettings returns projectID's settings.

func (*Store) Purge

func (s *Store) Purge(ctx context.Context, a Actor, projectID string) (int, error)

Purge deletes projectID's cancelled cards whose whole subtree is cancelled, with their comments, links, requests and holds. It is the only hard delete. It returns the number of cards deleted.

func (*Store) Reconcile

func (s *Store) Reconcile(ctx context.Context, tasks map[string]Stage, asOf time.Time, uncommitted map[string][]string) (int, error)

Reconcile releases every hold whose Task is Archived or deleted to todo, with the automatic comment "attempt #n ended, uncommitted: …". tasks maps each Task ID to its stage, as the caller read it at asOf on the store's clock; a Task missing from it has been deleted. A hold that started at or after asOf may belong to a Task the snapshot predates, so it is left alone. uncommitted maps a Project ID to its working tree's uncommitted paths, when known. It reads only stored state, so Settled Tasks keep their holds across restarts, and when nothing has ended it writes nothing. It returns the number of holds released.

func (*Store) Reject

func (s *Store) Reject(ctx context.Context, a Actor, id, reason string, holderActive bool) (Request, error)

Reject rejects the pending request id with a reason. When the requesting Task holds the card and is not Active, the hold is released to todo with the reason as a comment; while it is Active the hold stays and the caller sends the reason to the Task.

func (*Store) ReleaseHold

func (s *Store) ReleaseHold(ctx context.Context, a Actor, ref string, reason ReleaseReason, comment string) (Card, error)

ReleaseHold ends the hold on the subtask ref and returns it to todo, for the owner's Release (ReleaseOwner) or the Settle dialog's release (ReleaseSettled). A non-empty comment is added as the owner's. Every other way a hold ends goes through the same internal path.

func (*Store) Request

func (s *Store) Request(ctx context.Context, id string) (Request, error)

Request returns the request id.

func (*Store) Restore

func (s *Store) Restore(ctx context.Context, a Actor, ref, comment string) (Card, error)

Restore reopens exactly the cards cancelled with the card ref, in one cascade, and confirms each, with its unconfirmed ancestors. A subtask with an earlier attempt reopens as todo, one without as planned. It needs a comment, and is refused while a card of the cascade sits under a cancelled card outside it.

func (*Store) Revisions

func (s *Store) Revisions(ctx context.Context) (map[string]int64, error)

Revisions returns every Project's board revision, "" for Unassigned. A Project that was never written has none.

func (*Store) SetProjectAcceptCmd

func (s *Store) SetProjectAcceptCmd(ctx context.Context, a Actor, projectID, cmd string) error

SetProjectAcceptCmd sets projectID's default acceptance command; "" means none. Only the owner writes acceptance commands.

func (*Store) SetStatus

func (s *Store) SetStatus(ctx context.Context, a Actor, ref string, to Status, comment string, force bool) (Card, error)

SetStatus is the owner's direct status change. On a subtask: done needs a comment and passes the finishing guard unless force is set; cancelled needs a comment; todo marks a planned or done subtask ready, or releases a doing one. On a container only cancelled is allowed, as a cascade over its subtree; force exists on subtasks only.

func (*Store) Similar

func (s *Store) Similar(ctx context.Context, projectID, title, excludeID string, limit int) ([]SimilarHit, error)

Similar returns up to limit cards in projectID whose titles resemble title, best first, excluding excludeID.

func (*Store) Split

func (s *Store) Split(ctx context.Context, a Actor, ref string, children []SplitChild) (SplitResult, error)

Split splits the subtask ref. Under an epic or at the root it becomes a story whose children are the given ones, then its checklist items in order. Under a story, which can't hold a story, those cards become its siblings, placed right after it, and the subtask is cancelled under its own cascade with the automatic comment "split into #a, #b, …", so Restore brings it back and leaves the siblings. Unticked items become planned subtasks and ticked ones subtasks with a pending done request that cites the tick: a split never creates a done subtask. An agent's split of a confirmed or held subtask is filed as one split request instead; the owner's, and an agent's split of an unconfirmed unheld subtask, apply at once. A live hold moves to the first pending new subtask.

func (*Store) StaleCandidates

func (s *Store) StaleCandidates(ctx context.Context, projectID string) ([]Card, error)

StaleCandidates returns the subtasks staleness is computed for: confirmed, not terminal and not held.

func (*Store) StartPlanning

func (s *Store) StartPlanning(ctx context.Context, a Actor, ref, taskID string) error

StartPlanning scopes taskID, a planning Task or a Utility scout, to the container ref. Such a Task creates and edits under the container and holds nothing.

func (*Store) Sweep

func (s *Store) Sweep(ctx context.Context) (int, error)

Sweep runs the expiry sweep over every Project, as at boot. It returns the number of cards cancelled.

func (*Store) Unassign

func (s *Store) Unassign(ctx context.Context, projectID string) (int, error)

Unassign moves every card of projectID, a Project being removed, to the read-only Unassigned list, keeping its tree, comments and history. The Project's Tasks are gone with it, so its pending requests are withdrawn and a hold still open ends as an ended attempt. It returns the number of cards moved.

func (s *Store) Unlink(ctx context.Context, a Actor, aRef, bRef string) error

Unlink removes the link between two cards, whichever way it points.

Jump to

Keyboard shortcuts

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