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
- Variables
- func ClearVocabularyDraft(topicRoot string) error
- func MatchPath(pattern, topicRelPath string) bool
- func RenderIntoClaude(claudeMarkdown string, c *Contract) string
- func RenderSection(c *Contract) string
- func SaveContractDraft(topicRoot string, c *Contract) error
- func SaveVocabularyDraft(topicRoot string, items []VocabularyItem) error
- func SetContract(topicRoot string, c *Contract) error
- func SetThresholds(topicRoot string, thresholds map[string]float64) error
- func SettingsPath(topicRoot string) string
- func SyncClaude(topicRoot string) error
- func ValidatePattern(pattern string) error
- type Contract
- type DecisionSettings
- type Settings
- type VocabularyItem
Constants ¶
const ( ModeShadow = "shadow" ModeApply = "apply" RelevanceOn = "on" RelevanceOff = "off" )
Decision mode values accepted in topic.yaml `decisions:`.
const SectionHeading = "## Selection contract"
SectionHeading is the CLAUDE.md heading that carries the contract.
Variables ¶
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.
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 ¶
ClearVocabularyDraft removes topic.yaml `vocabulary_draft:` (no-op when absent).
func MatchPath ¶
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 ¶
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 ¶
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 ¶
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 ¶
SetContract validates c and writes it as the active topic.yaml `contract:`.
func SetThresholds ¶
SetThresholds replaces topic.yaml `decisions.thresholds:`, keeping every other `decisions` key. An empty map removes the thresholds key.
func SettingsPath ¶
SettingsPath returns <topicRoot>/topic.yaml.
func SyncClaude ¶
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 ¶
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 ¶
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 ¶
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) Hash ¶
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 ¶
MatchesCollectedPath reports whether a topic-relative path matches one of the collected_on_purpose_paths globs.
func (*Contract) Normalized ¶
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 ¶
QuestionState is the contract fragment every relevance question carries. Path globs are resolved by code and never sent.
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 ¶
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.
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. |