Documentation
¶
Overview ¶
Package external resolves whether a CANARY requirement ID is satisfied as an external dependency — one owned by a ticket-source (e.g. JIRA) or a peer project (see resolvePeer) rather than this project's own flatfile series. It answers purely from on-disk sources: the remote-status cache (.canary/remote-status.json, written by `canary ticket sync --apply` and `canary ticket status --refresh` in pkg/cmds/ticket) and configured peers' status.json files. This package performs NO network I/O, ever — a missing or stale cache, or an unreachable/malformed peer file, degrades to State=unknown (or falls through to the next source) rather than blocking or erroring. CANARY: REQ=ENG-3959; FEATURE="ExternalResolve"; ASPECT=Engine; STATUS=TESTED; TEST=TestCANARY_ENG_3959_Cache_RoundTrip,TestCANARY_ENG_3959_Cache_LoadMissing_NoError,TestCANARY_ENG_3959_Cache_LoadCorrupt_Error,TestCANARY_ENG_3959_Resolve_FlatfileSource_Unknown,TestCANARY_ENG_3959_Resolve_UnresolvedPrefix_Unknown,TestCANARY_ENG_3959_Resolve_NilRegistry_Unknown,TestCANARY_ENG_3959_Resolve_NoCacheFile_Unknown,TestCANARY_ENG_3959_Resolve_CachedDone_Satisfied,TestCANARY_ENG_3959_Resolve_CachedNotDone_Unsatisfied,TestCANARY_ENG_3959_Resolve_AbsentFromCache_Unknown,TestCANARY_ENG_3959_Resolve_CustomStatusMap_DoneSet,TestCANARY_ENG_3959_Resolve_StaleCache_DetailNote,TestCANARY_ENG_3959_Resolve_FreshCache_NoStaleNote,TestCANARY_ENG_3960_Resolution_IsExternal,TestCANARY_ENG_3960_Resolution_ShortDetail; UPDATED=2026-08-29 CANARY: REQ=ENG-3961; FEATURE="PeerProjects"; ASPECT=Engine; STATUS=TESTED; TEST=TestCANARY_ENG_3961_Resolve_PeerSatisfied,TestCANARY_ENG_3961_Resolve_PeerUnsatisfied,TestCANARY_ENG_3961_Resolve_PeerNotFound,TestCANARY_ENG_3961_Resolve_PeerMissingFile,TestCANARY_ENG_3961_Resolve_PeerMalformedJSON,TestCANARY_ENG_3961_Resolve_PeerRelativeRoot,TestCANARY_ENG_3961_Resolve_PeerBeatsTicketCache,TestCANARY_ENG_3961_Resolve_UnknownPrefixResolvedByPeer,TestCANARY_ENG_3961_Resolve_LocalFlatfileNeverConsultsPeer,TestCANARY_ENG_3961_Resolve_SecondPeerFallsThroughFirst; UPDATED=2026-08-29
Index ¶
Constants ¶
const ( StateSatisfied = "satisfied" StateUnsatisfied = "unsatisfied" StateUnknown = "unknown" )
State values for Resolution.State.
const CacheFileName = "remote-status.json"
CacheFileName is the remote-status cache's basename under .canary/.
Variables ¶
This section is empty.
Functions ¶
func SaveCache ¶
SaveCache writes statuses to root's .canary/remote-status.json with fetchedAt (converted to UTC) as fetched_at, creating .canary/ if needed. Written with mode 0600 — this file only ever holds ticket-system status names, but is treated as project-local state, not something to expose group/world-readable.
Types ¶
type Cache ¶
type Cache struct {
FetchedAt string `json:"fetched_at"`
Statuses map[string]string `json:"statuses"`
}
Cache is the on-disk shape of .canary/remote-status.json: the last time a fetch succeeded, and the issue-key -> remote-status-name snapshot it produced.
type Resolution ¶
type Resolution struct {
ID string
State string // satisfied | unsatisfied | unknown
Detail string
}
Resolution is the outcome of resolving one requirement ID as a possible external dependency.
func Resolve ¶
func Resolve(id string, reg *sources.Registry, root string) Resolution
Resolve determines whether id is satisfied as an external dependency.
- id is external (resolves to a non-flatfile source) OR has an unknown prefix (resolves to no configured source at all, including when reg is nil): every configured peer project is consulted, in declaration order, BEFORE the ticket cache below. This is the inter-dependent-repos case: a peer may own an id under a key this project's own sources: list never heard of. Peers are drawn from reg.Peers() when reg != nil (no additional config.Load); otherwise peers are loaded fresh from root's .canary/project.yaml for backward compatibility. A known local (flatfile) id never consults peers — it is unambiguously this project's own. See resolvePeer for the peer-file contract.
- id resolves to a flatfile source, or to no configured source at all (and no peer claimed it): State=unknown, Detail="not external" — callers treat this as a local requirement, not an external one.
- id resolves to a ticket-source (jira/github/gitlab) and no peer claimed it: the cache is read (never fetched — this package performs no network I/O). - No cache file, or the cache holds no entry for id: State=unknown, Detail points at `canary ticket status --refresh`. - id's cached status is in the source's done-set (its StatusMap's TESTED/BENCHED names, defaulting to {"Done"}): State=satisfied, Detail is the cached status name. - id's cached status is present but not in the done-set: State=unsatisfied, Detail is the cached status name.
Whenever a cache file exists and its fetched_at is more than 24h old (relative to CANARY_TEST_TIMESTAMP when set, else now in UTC), a staleness note is appended to Detail — the cache is still used; a stale answer is strictly better than none (degradation is sacred).
func (Resolution) IsExternal ¶
func (r Resolution) IsExternal() bool
IsExternal reports whether r describes an actual external (ticket-source) dependency, as opposed to a local/flatfile id or an unconfigured prefix — the case Resolve marks with Detail "not external". Callers (deps/next/view) use this to decide whether to apply external-dependency display/blocking rules at all.
func (Resolution) ShortDetail ¶
func (r Resolution) ShortDetail() string
ShortDetail returns a short, display-friendly rendering of r.Detail: the cached remote-status name (with any appended staleness note stripped) for satisfied/unsatisfied, or the fixed short note "no cached ticket status" for unknown — dropping the longer refresh-hint command suggestion so callers like `deps check` and `view` stay on one line.