contract

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: 15 Imported by: 0

Documentation

Overview

Package contract owns a topic's selection contract (spec §5.1): the five-part scope that relevance and classification questions are judged against. It parses, validates, hashes and renders the contract, imports it from an existing CLAUDE.md section, and reads and writes the topic.yaml settings that carry it (contract, drafts, vocabulary draft, decisions block) without disturbing any other key.

Index

Constants

View Source
const (
	ModeShadow   = "shadow"
	ModeApply    = "apply"
	RelevanceOn  = "on"
	RelevanceOff = "off"
)

Decision mode values accepted in topic.yaml `decisions:`.

View Source
const SectionHeading = "## Selection contract"

SectionHeading is the CLAUDE.md heading that carries the contract.

Variables

View Source
var ErrNoDraft = errors.New("contract: topic.yaml has no contract_draft; run `kb topic contract <topic> --draft` or `--import-claude` first")

ErrNoDraft is returned by ActivateDraft when topic.yaml has no contract_draft.

View Source
var ErrNoSection = errors.New("contract: CLAUDE.md has no ## Selection contract section")

ErrNoSection is returned when a CLAUDE.md has no `## Selection contract`.

Functions

func ClearVocabularyDraft

func ClearVocabularyDraft(topicRoot string) error

ClearVocabularyDraft removes topic.yaml `vocabulary_draft:` (no-op when absent).

func MatchPath

func MatchPath(pattern, topicRelPath string) bool

MatchPath matches a topic-relative path against a glob with segment semantics: `*` matches within one segment, `?` one rune, `[...]` a class, and a `**` segment any number of segments (including none). Invalid patterns never match.

func RenderIntoClaude

func RenderIntoClaude(claudeMarkdown string, c *Contract) string

RenderIntoClaude returns claudeMarkdown with its `## Selection contract` section replaced by the rendering of c (up to the next H1/H2 heading), or with the section inserted before the first `## ` heading (appended at the end when there is none). Every other byte is preserved.

func RenderSection

func RenderSection(c *Contract) string

RenderSection renders the `## Selection contract` markdown section for c, ending with a single newline. List items are joined with "; " inside one bullet (the format used by existing vault topics); a list whose items contain a top-level ";" is rendered as nested sub-bullets so it re-imports losslessly. A nil or empty contract renders placeholder bullets.

func SaveContractDraft

func SaveContractDraft(topicRoot string, c *Contract) error

SaveContractDraft writes c under topic.yaml `contract_draft:` (drafts are not validated; ActivateDraft validates).

func SaveVocabularyDraft

func SaveVocabularyDraft(topicRoot string, items []VocabularyItem) error

SaveVocabularyDraft writes items under topic.yaml `vocabulary_draft:`.

func SetContract

func SetContract(topicRoot string, c *Contract) error

SetContract validates c and writes it as the active topic.yaml `contract:`.

func SetThresholds

func SetThresholds(topicRoot string, thresholds map[string]float64) error

SetThresholds replaces topic.yaml `decisions.thresholds:`, keeping every other `decisions` key. An empty map removes the thresholds key.

func SettingsPath

func SettingsPath(topicRoot string) string

SettingsPath returns <topicRoot>/topic.yaml.

func SyncClaude

func SyncClaude(topicRoot string) error

SyncClaude re-renders the `## Selection contract` section of <topicRoot>/CLAUDE.md from the active topic.yaml contract. It is called after a contract is accepted. The file is only rewritten when it changes.

func ValidatePattern

func ValidatePattern(pattern string) error

ValidatePattern reports whether a topic-relative glob compiles: it must be non-empty, relative, free of `.`/`..` segments, use `**` only as a whole segment, and every other segment must be a valid path.Match pattern.

Types

type Contract

type Contract struct {
	Purpose                 string   `yaml:"purpose" json:"purpose"`
	Core                    []string `yaml:"core" json:"core"`
	Adjacent                []string `yaml:"adjacent" json:"adjacent"`
	CollectedOnPurpose      []string `yaml:"collected_on_purpose" json:"collected_on_purpose"`
	CollectedOnPurposePaths []string `yaml:"collected_on_purpose_paths,omitempty" json:"collected_on_purpose_paths,omitempty"`
	OutOfScope              []string `yaml:"out_of_scope" json:"out_of_scope"`
}

Contract is the selection contract stored under topic.yaml `contract:`.

func ActivateDraft

func ActivateDraft(topicRoot string) (*Contract, error)

ActivateDraft validates topic.yaml `contract_draft:`, moves it to `contract:` and removes the draft key. Nothing is written when the draft is missing or invalid. Callers re-render CLAUDE.md with SyncClaude afterwards.

func ParseClaudeSection

func ParseClaudeSection(claudeMarkdown string) (*Contract, error)

ParseClaudeSection parses the `## Selection contract` section of a topic CLAUDE.md into a contract. Bullets `Purpose`, `Core` (or `Central`), `Adjacent (keep)` (or `Adjacent`), `Collected on purpose`, `Collected on purpose (paths)` and `Out of scope` are read; inline list values are split on top-level ";" (never inside parentheses or brackets) and nested sub-bullets are taken as items. A missing section returns ErrNoSection.

func (*Contract) Empty

func (c *Contract) Empty() bool

Empty reports whether the contract carries no text at all.

func (*Contract) Hash

func (c *Contract) Hash() string

Hash is the sha256 hex digest of the canonical JSON of the normalized contract. It is "" for a nil or empty contract.

func (*Contract) MatchesCollectedPath

func (c *Contract) MatchesCollectedPath(topicRelPath string) bool

MatchesCollectedPath reports whether a topic-relative path matches one of the collected_on_purpose_paths globs.

func (*Contract) Normalized

func (c *Contract) Normalized() Contract

Normalized returns a copy with every string trimmed, empty list items dropped and every list non-nil (so a YAML render always shows all fields). A nil contract normalizes to the empty contract.

func (*Contract) QuestionState

func (c *Contract) QuestionState() map[string]any

QuestionState is the contract fragment every relevance question carries. Path globs are resolved by code and never sent.

func (*Contract) Validate

func (c *Contract) Validate() error

Validate checks the rules of spec §5.1: a non-empty purpose and core, no line shared (trimmed, case-insensitive) between core/adjacent and out_of_scope, and collected_on_purpose_paths globs that compile.

type DecisionSettings

type DecisionSettings struct {
	// Mode is the body-link insertion mode: "" (inherit), shadow or apply.
	Mode string `yaml:"mode,omitempty" json:"mode,omitempty"`
	// Gates is the relevance gate mode: "" (inherit), shadow or apply.
	Gates string `yaml:"gates,omitempty" json:"gates,omitempty"`
	// Relevance is "" (on), on or off.
	Relevance string `yaml:"relevance,omitempty" json:"relevance,omitempty"`
	// Thresholds override [decisions.thresholds] by name.
	Thresholds map[string]float64 `yaml:"thresholds,omitempty" json:"thresholds,omitempty"`
	// Exclude globs keep matching topic-relative files out of every call.
	Exclude []string `yaml:"exclude,omitempty" json:"exclude,omitempty"`
}

DecisionSettings is topic.yaml `decisions:`.

type Settings

type Settings struct {
	Contract        *Contract        `yaml:"contract,omitempty" json:"contract,omitempty"`
	ContractDraft   *Contract        `yaml:"contract_draft,omitempty" json:"contract_draft,omitempty"`
	VocabularyDraft []VocabularyItem `yaml:"vocabulary_draft,omitempty" json:"vocabulary_draft,omitempty"`
	Decisions       DecisionSettings `yaml:"decisions,omitempty" json:"decisions"`
}

Settings is the part of topic.yaml read by the decision pipeline.

func LoadSettings

func LoadSettings(topicRoot string) (Settings, error)

LoadSettings reads the decision settings from <topicRoot>/topic.yaml. A missing file or missing keys yield zero values; enum values, thresholds and exclude globs are validated.

func (Settings) Accepted

func (s Settings) Accepted() bool

Accepted reports whether the topic has an active, valid contract.

type VocabularyItem

type VocabularyItem struct {
	Title     string `yaml:"title" json:"title"`
	Criterion string `yaml:"criterion" json:"criterion"`
	Mentions  int    `yaml:"mentions,omitempty" json:"mentions,omitempty"`
}

VocabularyItem is one proposed concept of topic.yaml `vocabulary_draft:`.

Directories

Path Synopsis
Package topicyaml edits a topic's topic.yaml at the yaml.Node level so every key, comment and key order that the caller does not touch survives a write.
Package topicyaml edits a topic's topic.yaml at the yaml.Node level so every key, comment and key order that the caller does not touch survives a write.

Jump to

Keyboard shortcuts

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