refs

package
v0.0.11 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package refs finds the inbound references to a topic document and moves a source into and out of quarantine without leaving dead links (spec §7.1).

References are resolved with internal/resolve exactly like lint does: topic-relative path, topic-slug-prefixed path, vault-relative path or file stem, with Obsidian semantics (titles and aliases never resolve a link).

Index

Constants

View Source
const (
	OpMove    = "move"
	OpEdit    = "edit"
	OpRestore = "restore"
)

Ledger operations.

View Source
const (
	// MarkerIndex marks an index-line removal.
	MarkerIndex = "index"
	// MarkerMove marks the file move (and, on restore rows, the move back).
	MarkerMove = "move"
)

Ledger line_or_key markers.

View Source
const (
	TriageQuarantined = "quarantined"
	TriageKept        = "kept"
)

Triage values written on quarantine and restore (spec §6).

View Source
const (
	// KindIndexLine is a list item, numbered item or table row of a
	// `wiki/index/` document that links to the target.
	KindIndexLine = "index-line"
	// KindFrontmatter is a frontmatter value that links to the target.
	KindFrontmatter = "frontmatter"
	// KindBody is a body wikilink or markdown link to the target.
	KindBody = "body"
)

Reference kinds.

View Source
const IndexDir = "wiki/index/"

IndexDir is the topic-relative directory whose list items and table rows are removed when every link they carry points to quarantined files.

View Source
const LedgerFile = "quarantine-ledger.jsonl"

LedgerFile is the quarantine ledger inside <topic>/.decisions/.

Variables

View Source
var ErrLocked = errors.New("refs: file is locked (locked: true); not quarantined")

ErrLocked is returned when the file to quarantine carries `locked: true`: kb never moves or edits a locked file.

View Source
var RemovableKeys = []string{
	"sources", "related", "extends", "prerequisite", "example_of", "contradicts",
	"affects", "supersedes", "concepts", "informed_by",
}

RemovableKeys are the frontmatter list keys whose items pointing to a quarantined file are removed (spec §7.1).

Functions

func LedgerPath

func LedgerPath(topicRoot string) string

LedgerPath returns <topic>/.decisions/quarantine-ledger.jsonl.

Types

type LedgerEntry

type LedgerEntry struct {
	QuarantineID string `json:"quarantine_id"`
	Time         string `json:"time"`
	Op           string `json:"op"`
	File         string `json:"file"`
	Original     string `json:"original,omitempty"`
	LineOrKey    string `json:"line_or_key"`
	Line         int    `json:"line,omitempty"`
	Before       string `json:"before,omitempty"`
	After        string `json:"after,omitempty"`
	HashBefore   string `json:"hash_before,omitempty"`
	HashAfter    string `json:"hash_after,omitempty"`
	Reason       string `json:"reason,omitempty"`
}

LedgerEntry is one row of the quarantine ledger. Edit rows record the exact bytes removed (Before) and written instead (After, "" for a pure deletion) at 1-based Line, plus the whole-file sha256 before and after the edit. The move row records the quarantine path in File, the original path in Original, and the file hash before and after the triage keys were set.

func LoadLedger

func LoadLedger(topicRoot string) ([]LedgerEntry, error)

LoadLedger reads every well-formed ledger row in file order (a missing ledger is empty).

type Options

type Options struct {
	// VaultPath is the vault root (the parent of the topic directories).
	VaultPath string
	// TopicRoot is the topic directory.
	TopicRoot string
	// Path is the topic-relative file: `raw/...` for Quarantine; the original
	// or the quarantine path for Restore (used when ID is empty).
	Path string
	// Reason is the triage_reason written on quarantine (off_topic, thin, ...).
	Reason string
	// ID is the quarantine id; Quarantine derives one when empty.
	ID string
	// Writer writes the triage keys; one is opened on the topic when nil.
	Writer *corpus.Writer
	// State, when set, keeps the state row's written hashes in step with the
	// removal of items from kb-owned list keys, so a kb-written relation
	// stays kb-owned after quarantine and restore.
	State *corpus.StateStore
	// Now defaults to time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

Options configures Quarantine and Restore.

type Quarantined

type Quarantined struct {
	ID       string `json:"id"`
	Path     string `json:"path"`
	Original string `json:"original"`
	Reason   string `json:"reason"`
	Time     string `json:"time"`
	Edits    int    `json:"edits"`
}

Quarantined is one active quarantine.

func List

func List(topicRoot string) ([]Quarantined, error)

List returns the active quarantines of a topic (move rows without a matching restore of the move), oldest first.

type Ref

type Ref struct {
	// File is the topic-relative path of the referring document.
	File string `json:"file"`
	// Kind is KindIndexLine, KindFrontmatter or KindBody.
	Kind string `json:"kind"`
	// Key is the frontmatter key for KindFrontmatter references.
	Key string `json:"key,omitempty"`
	// Line is the 1-based line number in the referring file.
	Line int `json:"line"`
	// Text is the referring line (index lines, frontmatter items) or the
	// link markup (body links).
	Text string `json:"text"`
}

Ref is one inbound reference to a topic document.

func Scan

func Scan(vaultPath, topicRoot, target string) ([]Ref, error)

Scan returns the inbound references to target (a topic-relative path such as `raw/articles/x.md`) from every other non-quarantined document of the topic at topicRoot, in file then line order.

type RestoreResult

type RestoreResult struct {
	ID string
	// Restored lists the ledger rows that were replayed.
	Restored []LedgerEntry
	// Manual lists edit rows that were not replayed because the touched file
	// changed since the quarantine; they are ready to print for manual repair.
	Manual []LedgerEntry
	// Path is the topic-relative path the file was moved back to.
	Path string
}

RestoreResult reports a restore.

func Restore

func Restore(ctx context.Context, opts Options) (RestoreResult, error)

Restore replays the ledger of one quarantine in reverse: every removed span is put back at its recorded line when the touched file still hashes to the recorded hash_after (otherwise the row is returned in Manual and the file is not touched), the file is moved back, `triage: kept` is written and `triage_reason` removed through the corpus writer, and `restore` rows are appended. After a quarantine and restore with no edits in between, every touched index and frontmatter file is byte-identical to the original; the restored file itself differs only in its triage keys (`triage: kept` instead of no key or another value, `triage_reason` removed).

type Result

type Result struct {
	ID string
	// NewPath is the topic-relative quarantine path.
	NewPath string
	// Removed lists the ledger rows of every removal (move row first).
	Removed []LedgerEntry
	// BodyRefs are references left in place: body links and index lines that
	// also link to files that are not quarantined. Lint reports them as
	// link-to-quarantined.
	BodyRefs []Ref
	// Unremoved are frontmatter references that could not be removed line by
	// line (flow-style or scalar values, keys outside RemovableKeys, locked
	// documents); they are left for the owner.
	Unremoved []Ref
	// SkippedUserKeys lists triage keys the writer left alone because the
	// user owns them.
	SkippedUserKeys []string
}

Result reports a quarantine.

func Quarantine

func Quarantine(ctx context.Context, opts Options) (Result, error)

Quarantine moves a source to raw/_quarantine/ and removes the references that would otherwise dangle (spec §7.1):

  1. `triage: quarantined` and `triage_reason` are written through the corpus writer (a locked file returns ErrLocked and nothing changes);
  2. the file is moved to raw/_quarantine/<path without raw/> (refused when the destination exists);
  3. index lines in wiki/index/ whose every link points to quarantined files are removed;
  4. items of RemovableKeys frontmatter lists pointing to the file are removed from other topic documents, deleting exactly their lines;
  5. body links are left in place and returned in BodyRefs.

Recovery information is durable before each mutation: the move row is appended before the file moves and every edit row before its file is rewritten, so Restore can always undo what happened. A row whose mutation never took place (the process failed in between) is recognized by Restore from the file state: the quarantined file is still at its original path, or a touched file still hashes to the row's hash_before. When the move row cannot be recorded, or the move itself fails, the triage keys are rolled back and nothing is left moved.

Jump to

Keyboard shortcuts

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