Documentation
¶
Overview ¶
Package contextstore holds the just-in-time context units the harness routes to stages (SPEC-ADDITIONS §10): a large navigable store and a small active working set selected by an arc's labels and touched paths. Routing is a pure function; Load is the thin I/O shell.
Index ¶
- Constants
- func AppendIntegrity(path string, records ...IntegrityRecord) error
- func AppendMiss(path string, miss *Miss) error
- func ApplyFreshness(units []Unit, records []IntegrityRecord)
- func AreaLabels(paths []string) []string
- func Content(dir string, unit *Unit) (string, error)
- func DanglingSources(units []Unit, exists func(string) bool) []string
- func DanglingSupersessions(units []Unit) []string
- func DuplicateIDs(units []Unit) []string
- func Index(units []Unit) string
- func IntegrityLogFor(storeDir string) string
- func InvalidKPIs(units []Unit) []string
- func InvalidTrust(units []Unit) []string
- func LooksLikePath(source string) bool
- func Orphans(units []Unit) []string
- func RecordVerification(path string, event verification.Event) error
- func Stratum(t time.Time) string
- func UnitPath(storeDir, id string) string
- func UnverifiedClaims(units []Unit, read func(string) (string, error)) []string
- type Claim
- type Freshness
- type IntegrityRecord
- type Miss
- type RouteProposal
- type RoutingCase
- type RoutingReport
- type Trust
- type TrustTier
- type Unit
Constants ¶
const ( // DefaultStoreDir is the conventional repo path the context store lives under // (SPEC-ADDITIONS §10). DefaultStoreDir = ".adh/context" // DefaultWorkingSet is the default cap on how many units Route returns for a // single stage's working set. DefaultWorkingSet = 8 )
const ( ResultOK = "ok" ResultDrift = "drift" ResultUnverified = "unverified" )
Integrity result values, as recorded by `context verify`.
const IntegrityFile = ".adh/context-integrity.jsonl"
IntegrityFile is the conventional repo path the integrity-verification log lives under. Kept distinct from the miss log and the evidence trail: a verification is neither a learning signal nor a gate decision, it is an observation about whether a unit still describes what it claims to.
const MissFile = ".adh/context-misses.jsonl"
MissFile is the conventional repo path the routing-miss log lives under. It is kept distinct from the evidence trail (§10.3): a miss is a learning signal — an arc that declared a footprint the store could not route — not an audit record.
Variables ¶
This section is empty.
Functions ¶
func AppendIntegrity ¶
func AppendIntegrity(path string, records ...IntegrityRecord) error
AppendIntegrity records verification events to the append-only log at path, creating the parent directory and file if needed. It is the I/O shell to ApplyFreshness' pure core.
func AppendMiss ¶
AppendMiss records one routing miss to the append-only log at path, creating the parent directory and file if needed. It is the I/O shell to ProposeRoutes' pure core; a caller records misses so the router can later learn from them.
func ApplyFreshness ¶
func ApplyFreshness(units []Unit, records []IntegrityRecord)
ApplyFreshness fills each unit's derived Fresh field from the verification log. Pure: it mutates only the slice the caller owns and reads no clock or filesystem.
The newest record for a unit wins, which is the append-only log's own order. A unit declaring no integrity tool is not applicable rather than unknown — nothing could have checked it, so nothing is missing.
func AreaLabels ¶
AreaLabels derives coarse area labels from repository paths: the top-level directory of each (e.g. "cmd/step/x.go" -> "cmd"), deduplicated and sorted. A top-level file (no directory) yields no label. Execution labels an arc by the areas it touched so the cold critic's context can route (§19.1); this mirrors the top-level-dir keying that `adh init` scaffolds context units by.
func Content ¶
Content reads the unit's text from its ContentPath, resolved under dir (the store directory). It is the I/O shell to routing's pure core: an empty ContentPath yields no content and no error (a metadata-only unit), while a set path that does not resolve is an error — the routing promised text that is not there. The path is cleaned and kept within dir so a unit cannot route to a file outside the store.
func DanglingSources ¶
DanglingSources returns "id: source" for each unit provenance source that looks like a repo path but does not resolve, per the injected exists predicate (§10.4 receipt verification): a promoted unit citing a source that is not there is a provenance defect. URL and prose sources are skipped. It is pure — the caller injects the filesystem check so the core stays testable. Sorted.
func DanglingSupersessions ¶
DanglingSupersessions returns the ids of units whose SupersededBy names a unit that does not exist — a broken lifecycle reference (§10.4). Sorted. Pure.
func DuplicateIDs ¶
DuplicateIDs returns the unit ids that appear more than once, sorted and each reported once. A duplicate id makes routing ambiguous (two units answer to the same name), so it is a cross-unit consistency defect (§10.4). It is pure.
func Index ¶
Index renders the read-first routing catalog (§10 compounding-wiki): one line per routable (non-superseded) unit — id, kind, trust tier, labels, and the one-line provenance — the JIT grounding preview a worker reads before pulling any unit's text. Sorted by id. Pure.
func IntegrityLogFor ¶
IntegrityLogFor returns the verification log that pairs with a store directory.
The pairing is the naming convention -- ".adh/context" pairs with ".adh/context-integrity.jsonl" -- rather than a second path a caller has to know and could get wrong. It holds for a temp store in a test as readily as for the conventional one, which is why LoadFresh needs no repo root.
func InvalidKPIs ¶
InvalidKPIs returns the ids of units declaring a malformed KPI (§16/§18) — an empty metric or an unknown direction — so a silently-ignored indicator is caught rather than never firing. A unit is listed once however many KPIs are malformed. Sorted. Pure.
func InvalidTrust ¶
InvalidTrust returns the ids of units whose trust tier is outside the taxonomy (§10.4). Sorted. Pure.
func LooksLikePath ¶
LooksLikePath reports whether a provenance source is a repo-relative path — a candidate for existence checking — rather than a URL or a prose citation: it has no URL scheme, no whitespace, and contains a path separator or a file extension.
func Orphans ¶
Orphans returns the ids of units that can never route — no labels and no paths — so they are unreachable pages in the store (§10.4 wiki-lint): adh routes only by label or path, so a unit with neither is dead weight. Sorted. Pure.
func RecordVerification ¶
func RecordVerification(path string, event verification.Event) error
RecordVerification appends a verification event to the unit stored at path.
**It edits the `verified` key and nothing else.** The file is decoded into raw messages and re-encoded, so a unit carrying fields adh does not model keeps them: a store is a team's curated knowledge base, and a harness that silently drops what it does not understand is one nobody can extend. This is the first thing in adh that writes a unit, which is why the care is worth stating.
A unit still storing a bare tier is refused. The legacy string asserts a conclusion with no actor and no date, and there is no honest way to fold it into an event list -- inventing an actor for it is exactly what Valid rejects, and dropping it would silently discard a human's judgement. Converting is a person's decision, because only a person knows who the original reviewer was.
**By is config-derived, and the record is attributable rather than authenticated.** The actor must come from the repository's configured identity, never from a flag on the invocation: a caller-supplied actor would let anyone mint a `human:` event, which makes the fold in Tier worth defeating and is the same reason an actorless event is invalid. Config-derived is still self-asserted -- it establishes who the harness was configured as, not who was at the keyboard -- and that limit is stated rather than implied, the same narrowing already accepted for content-addressing detecting accidents rather than tampering. Anything stronger needs a signing identity adh does not have and should not invent.
The policy lives here rather than on skillet's Event because it is a rule about who may write the field, not a property of the record, and skillet has no view on it.
func Stratum ¶
Stratum is the year-month time stratum a miss belongs to (§10.3). The shell passes time.Now(); keeping the format here and the clock in the shell leaves the routing core clock-free.
func UnverifiedClaims ¶
UnverifiedClaims returns "id: quote" for each unit claim whose source looks like a repo path but whose file cannot be read or does not contain the quoted text, per the injected read function (§10.4 receipt verification): the receipt half of provenance, beyond DanglingSources' check that the path resolves. A claim citing a URL or prose source is skipped — its quote cannot be traced deterministically. It is pure — the caller injects the file read so the core stays testable. Sorted.
Types ¶
type Claim ¶
Claim is one verifiable citation inside a unit (§10.4 receipt verification): a Quote the unit asserts and the Source it should be found in. When Source is a repo path, `context verify` traces the quote back to the file — the receipt half of provenance, beyond the path merely resolving.
type Freshness ¶
type Freshness string
Freshness is whether a unit still matches what its integrity tool attests.
const ( // FreshnessUnknown is the zero value on purpose: a unit nothing has verified must // read as unchecked, never as clean. §12's applicability rule in a constant. FreshnessUnknown Freshness = "" FreshnessFresh Freshness = "fresh" FreshnessDrifted Freshness = "drifted" FreshnessNotApplicable Freshness = "not_applicable" )
Freshness states for a context unit, four of them, and the fourth is the point.
`unknown` (never evaluated) and `not_applicable` (declares no integrity tool) are distinct from `drifted`, and collapsing them would make a hand-written unit that nothing could check look the same as one nobody has checked yet. Absence of a comparison is not a passing comparison.
type IntegrityRecord ¶
type IntegrityRecord struct {
Unit string `json:"unit"`
Tool string `json:"tool,omitempty"`
Result string `json:"result"`
}
IntegrityRecord is one verification event: at some point, this unit's integrity tool was run and produced this result.
An event, not a conclusion. The log is append-only and the newest record for a unit wins, so the file's own order carries the recency and nothing here needs a clock — which is what keeps the fold below pure.
func LoadIntegrity ¶
func LoadIntegrity(path string) ([]IntegrityRecord, error)
LoadIntegrity reads the verification log at path. An absent file is no records, not an error — a repository that has never run `context verify` is a valid one. A corrupt line is a hard error, matching the miss log and the evidence trail: the log's integrity is its whole value.
type Miss ¶
type Miss struct {
Arc string `json:"arc"`
Labels []string `json:"labels,omitempty"`
Paths []string `json:"paths,omitempty"`
Stratum string `json:"stratum,omitempty"`
}
Miss is one recorded routing miss: an arc whose labels/paths routed no context (the §19.1 routing gap), stamped with the time Stratum (year-month) it occurred in. Accumulated misses are the signal that the store is missing a route the arcs keep asking for.
func LoadMisses ¶
LoadMisses reads the routing-miss log at path. An absent file is no misses, not an error. A corrupt line is a hard error — the log's integrity is its value.
type RouteProposal ¶
type RouteProposal struct {
Key string `json:"key"`
Kind string `json:"kind"`
Count int `json:"count"`
Strata int `json:"strata"`
}
RouteProposal is a proposed deterministic route the miss log has earned: a label or path the arcs missed on at least a threshold number of times across at least minStrata distinct time strata, so authoring a unit for it would convert the sustained miss into a route. Kind is "label" or "path"; Count is how many recorded misses named Key; Strata is how many distinct strata they spanned.
func ProposeRoutes ¶
func ProposeRoutes(misses []Miss, threshold int) []RouteProposal
ProposeRoutes turns the accumulated misses into route proposals: any label or path missed on at least threshold times AND across at least minStrata distinct time strata (§10.3 — a sustained pattern, not a one-day burst), ranked by recurrence (then kind, then key). It is pure — the caller decides what to do with a proposal (author a unit, gated at §11); nothing is auto-routed.
type RoutingCase ¶
type RoutingCase struct {
Name string `json:"name"`
Labels []string `json:"labels,omitempty"`
Paths []string `json:"paths,omitempty"`
Want []string `json:"want,omitempty"`
}
RoutingCase is one routing-eval fixture (§10): the labels and paths an arc declares and the unit ids that should route for them. An empty Want asserts that nothing should route (the correct NONE case).
type RoutingReport ¶
type RoutingReport struct {
Cases int `json:"cases"`
Passed int `json:"passed"`
Precision float64 `json:"precision"`
Recall float64 `json:"recall"`
Failures []string `json:"failures,omitempty"`
}
RoutingReport aggregates a routing eval: how many cases routed exactly their Want set, and the precision/recall of the routed ids against the expected ones summed across cases — so a routing regression is a measured drop, not a vibe. Failures names the cases that did not route exactly.
func EvaluateRouting ¶
func EvaluateRouting(units []Unit, cases []RoutingCase, maxUnits int) RoutingReport
EvaluateRouting runs each case through Route and scores it (§10): a case passes when the routed id set equals its Want set (an empty Want must route nothing). Precision and recall aggregate the true/false positives and false negatives over all cases; an empty denominator is vacuously 1.0 (nothing predicted or nothing wanted is not a miss). It is pure — the caller supplies the units and cases.
type Trust ¶
type Trust struct {
// Events is the OKF §5.2 list. Empty when the stored form was a bare tier.
//
// The element type is skillet's, shared with gnosis since v0.31.0. What is *not* shared
// is the fold below: Tier answers human-or-machine for a context unit, while gnosis
// closes its actor vocabulary to three kinds to count distinct humans. The record was
// promoted and the judgement deliberately was not.
Events []verification.Event
// Stated is a tier stored directly, including an unrecognised one: an unknown value
// has to survive parsing so Valid reports it as a taxonomy problem, which is what
// `context lint` and the wiki index already do with it. Rejecting it at parse time
// would turn a lint finding into a load failure.
Stated TrustTier
}
Trust is a unit's verification record: the events, with the tier derived from them.
It accepts both stored shapes. A list of events is the OKF form. A bare string is the form adh wrote before events were expressible, and reading it is **permanent rather than transitional** -- nothing in this repository has ever written the field, so there is no migration event after which the legacy branch could be deleted. Both forms keep asserting exactly what they asserted before, so no store gains or loses standing by being read with this type.
func (Trust) MarshalJSON ¶
MarshalJSON writes back whichever shape the record holds: the event list when it has events, else the bare tier.
Nothing in adh writes a unit today, so this exists to keep the type honest rather than to serve a caller. Note that encoding/json cannot omit an empty struct field, so a writer added later will emit `"verified":""` for an unverified unit -- semantically the same as omitting it, and worth deciding deliberately at that point.
func (Trust) Tier ¶
Tier is the trust tier this record implies (OKF §5.3): derived from the events when there are any, otherwise the stored tier, otherwise Unverified.
**Unverified is the zero value on purpose.** No events and no stored tier means nobody has confirmed the unit, never that a confirmation passed.
func (*Trust) UnmarshalJSON ¶
UnmarshalJSON accepts either stored shape.
type TrustTier ¶
type TrustTier string
TrustTier records how a unit's content was earned (§10.4).
const ( Unverified TrustTier = "unverified" // agent-proposed, not confirmed MachineConfirmed TrustTier = "machine-confirmed" // a check/tool confirmed it HumanReviewed TrustTier = "human-reviewed" // a human reviewed and accepted it )
Trust tiers (§10.4, the OKF `verified` dimension): how a unit's content was earned, so routing can weight a human-reviewed unit over an unverified one. An empty tier is treated as Unverified.
type Unit ¶
type Unit struct {
ID string `json:"id"`
Kind string `json:"kind"`
Labels []string `json:"labels,omitempty"`
Paths []string `json:"paths,omitempty"`
Owner string `json:"owner,omitempty"`
ContentPath string `json:"content_path,omitempty"`
Provenance string `json:"provenance,omitempty"`
Sources []string `json:"sources,omitempty"`
Claims []Claim `json:"claims,omitempty"`
KPIs []adh.KPI `json:"kpis,omitempty"`
Integrity string `json:"integrity,omitempty"`
Verified Trust `json:"verified,omitempty"`
SupersededBy string `json:"superseded_by,omitempty"`
// Fresh is derived from the integrity log by ApplyFreshness, never persisted.
// json:"-" is load-bearing: it makes it impossible for a unit whose tier was
// suppressed by recorded drift to be written back with that suppression baked in.
Fresh Freshness `json:"-"`
}
Unit is one routable piece of context: a runbook, skill, domain note, or an executable nonfunctional-requirement check. It routes by its labels and the repository paths it governs. ContentPath is the store-relative route to the unit's text — routing previews the unit and the worker pulls the text just in time (§10.4); Provenance is a one-line summary and Sources are the proven origins it derives from; Integrity is the §13 tool id that proves the unit has not drifted (`context verify`, §10.4 anti-drift). Verified is the trust tier (weights routing); SupersededBy is the unit id that has replaced this one (a superseded unit no longer routes). Claims are verifiable quote/source citations traced back to their source (§10.4 receipt verification). KPIs are declared performance indicators whose breach proposes a change to the unit (§16/§18). The optional fields let a metadata-only unit route with no text of its own.
func Load ¶
Load reads context units from JSON files under dir. An absent directory yields no units and no error.
func LoadFresh ¶
LoadFresh reads the context units under storeDir with their derived freshness already applied from the paired verification log.
This is what routing callers want, and Load is what everything else wants. Splitting them rather than adding freshness to Load keeps the choice visible: a caller that ranks units by trust must account for recorded drift, and one that merely lists or counts them has nothing to account for.
func Route ¶
Route selects up to maxUnits whose labels or governed paths match the arc's labels or touched paths, most-specific (highest match count) first; ties break by trust tier (a human-reviewed unit outranks an unverified one, §10.4), then by ID. A superseded unit never routes — it has been replaced. It never mutates its inputs.
The tier it compares is the *effective* one, so a unit the integrity log records as drifted stops outranking a clean unit. Callers that have not run ApplyFreshness route exactly as before: the zero freshness suppresses nothing.
func (*Unit) EffectiveTier ¶
EffectiveTier is the trust tier a unit routes at, after recorded drift is taken into account.
Recorded drift suppresses the authored tier to Unverified rather than overwriting it. The authored value is a human's judgement about the unit and is not adh's to destroy; drift is an observation that the thing judged has since moved. Keeping both means re-verifying a unit restores its standing with no edit, and it is why Fresh is derived and never serialised — a suppressed unit written back to disk cannot silently lose the authored tier, because there is nothing to write back.