link

package
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package link answers one question: what else is connected to this ticket, and where does it live now.

It exists as its own package because four callers need the same answer — the gate, validate, the CLI and the TUI — and three copies of it would be three truths. The gate in particular must not learn to read the filesystem (see core/gate's doc comment), so it takes the one predicate it needs as an injected function rather than importing this package's index wholesale.

The connections are of five kinds and every one of them is read in both directions:

blocked-by / blocks   a hard dependency, the only kind a gate enforces
parent / children     containment, stored only on the child
related               a loose association, stored on whichever side was edited
follows / followed-by a follow-up produced by a review

Children are never stored. A children list on the parent could not be written at all in the common case — the parent may be in the logbook, in the archive, or on a ref with no file here — and two sessions adding two children would collide on one line. The child names its parent, one writer per file, and the tree is rebuilt by reading.

Index

Constants

This section is empty.

Variables

Order is the order the kinds are shown in, strongest obligation first. It lives here rather than in each view because two copies of it drift, and a reader comparing the CLI with the board would then see the same links in two different orders.

Functions

This section is empty.

Types

type Entry

type Entry struct {
	Kind Kind
	Ref  Ref
}

Entry pairs a ref with the relation that produced it.

type Index

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

Index holds every ticket this repository can see, whichever of the four places it lives in.

Building it reads the board eagerly (it is already in memory for every caller) and the filed-away directories lazily: a logbook grows without bound, and paying for it on every board render would break the promise that the board opens instantly. Nothing here reads a filed file until a question is asked that only the file can answer.

func Build

func Build(s *ticket.Store, lanes *lane.Set, board []*ticket.Ticket) *Index

Build indexes what the store can see. The tickets are passed in rather than listed here because every caller has already listed them and a second walk would double the cost of opening the board.

func (*Index) Known

func (ix *Index) Known(id string) bool

Known reports whether the id resolves to a ticket anywhere. Existing is a question the directory listing already answers, so nothing is read.

func (*Index) Relations

func (ix *Index) Relations(id string) []Entry

Relations lists every connection of one ticket, in both directions, grouped kind by kind in a fixed order so the view does not reshuffle between openings.

func (*Index) Satisfied

func (ix *Index) Satisfied(id string) bool

Satisfied reports whether a ticket may be treated as a cleared dependency: it exists somewhere and it is finished.

This is the whole of what the gate needs, which is why it is a single boolean: core/gate stays free of the filesystem and takes this as an injected function.

It is asked once per blocker on every board render, so it answers without opening a file wherever it can: a ticket on the board is already in memory, and one in the logbook is finished by the fact of being there. Only the archive — a drawer, not a verdict — has to be read.

type Kind

type Kind string

Kind names one direction of one relation. Both directions are separate kinds: "blocks" and "blocked by" read as opposite facts to whoever is looking, and collapsing them would hide which way the arrow points.

const (
	KindBlockedBy  Kind = "blocked-by"
	KindBlocks     Kind = "blocks"
	KindParent     Kind = "parent"
	KindChild      Kind = "child"
	KindRelated    Kind = "related"
	KindFollows    Kind = "follows"
	KindFollowedBy Kind = "followed-by"
)

func (Kind) Title

func (k Kind) Title() string

Title is how a kind is written out for a reader.

type Place

type Place string

Place is where a ticket was found. A link whose other end has left the board is still a link, and saying only "not found" is what made every connection rot the moment the work it pointed at finished.

const (
	// PlaceBoard means the ticket has a file under .jaira/tickets/.
	PlaceBoard Place = "board"
	// PlaceRef means the board can see it but nobody here has pulled it in.
	PlaceRef Place = "ref"
	// PlaceLogbook means it is finished and filed under .jaira/logbook/.
	PlaceLogbook Place = "logbook"
	// PlaceArchive means it was taken off the board into .jaira/archive/.
	PlaceArchive Place = "archive"
	// PlaceUnknown means the id resolves to nothing here at all.
	PlaceUnknown Place = "unknown"
)

type Ref

type Ref struct {
	ID    string
	Title string
	Lane  string
	Place Place
	// Path is the file, empty for a ticket that only exists on a ref.
	Path string
	// Done means the ticket sits in a terminal lane. A blocker that is done
	// no longer blocks, wherever it is filed.
	Done bool
	// Depth is how far below the subject a child sits: 0 for a direct child,
	// 1 for its child, and so on. Zero for every other kind.
	Depth int
}

Ref is one end of a link: enough to show it and to find it again, without the caller having to know which of the four places it came out of.

func (Ref) Label

func (r Ref) Label() string

Label is the ticket as one line: handle and title, with a stand-in when the title is only readable where the ticket actually lives.

func (Ref) Whereabouts

func (r Ref) Whereabouts() string

Whereabouts says where a linked ticket lives now, in the words a reader needs. It is here rather than in each view because the CLI and the TUI must not disagree about it: "logbook · done" is the difference between a dependency that cleared and one that is still owed, and two spellings of that would be two answers.

Jump to

Keyboard shortcuts

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