Documentation
¶
Overview ¶
Package show implements the `aiwf show` verb (per-verb subpackage of M-0116; includes the show-scopes helpers moved from show_scopes.go).
Index ¶
- func AreaMissLine(id, actual, requested string) string
- func LastEventSHA(s *scope.Scope, match scope.State) string
- func LookupCommitDateCached(ctx context.Context, root, sha string, cache map[string]string) string
- func NewCmd(correlationID string) *cobra.Command
- func ReadEntityBody(root, relPath string) []byte
- func Run(id, root, format, area string, pretty bool, historyLimit int, ...) (code int)
- type CrossBranchView
- type ScopeView
- type ShowAC
- type ShowView
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AreaMissLine ¶ added in v0.17.0
AreaMissLine is the one-line text rendered when `aiwf show <id> --area <name>` filters the named entity out because its effective area differs (E-0043, M-0174/AC-3). `show` is single-entity, so the predicate hides the one entity (like an empty list) rather than listing — the line tells the operator the entity exists but lives elsewhere. An untagged entity (actual == "") gets its own wording.
func LastEventSHA ¶
LastEventSHA returns the SHA of the latest event in s whose state equals match, or "" when none. Used by ScopeView assembly to look up the ending commit's date (when the scope is ended).
func LookupCommitDateCached ¶
LookupCommitDateCached returns the ISO-8601 author date of the commit at sha, caching results so we never hit `git show` twice for the same SHA in one show call. Errors fall back to an empty string (the caller renders dates as omitempty in JSON).
func NewCmd ¶
NewCmd builds `aiwf show <id>`. Aggregates per-entity state from the existing data sources — frontmatter (entity), git log (history), aiwf check (findings) — into one human-readable view (or one JSON envelope when --format=json). No new state; pure projection.
For composite ids (M-NNN/AC-N), renders just the AC's slice of the parent milestone plus its history.
func ReadEntityBody ¶
ReadEntityBody reads the entity file at root/relPath and returns the body bytes (the prose after the closing `---`). Errors are swallowed — `aiwf show` already emits findings for unreadable / malformed entities via the load-error finding; surfacing the same problem on the body field would double-count. Empty body or missing file produces nil.
Entity.Path is repo-relative (the loader normalizes it that way) so callers must join with root before hitting the filesystem; doing the join in this helper keeps each caller from re-deriving it.
Types ¶
type CrossBranchView ¶ added in v0.27.0
type CrossBranchView struct {
// Ref is the ref content was read from. Empty when Collision is
// true — no single ref was chosen.
Ref string `json:"ref,omitempty"`
// Collision is true when the candidate refs carry divergent
// content (M-0259/AC-3). Title/Status/Body/ACs are left empty on
// the ShowView in that case — aiwf show declines to pick a side
// (M-0260/AC-3) rather than render one ref's content as canonical.
Collision bool `json:"collision"`
Refs []string `json:"refs"`
}
CrossBranchView carries the read-side resolution state for an id resolved from another ref (M-0260/AC-1/AC-2/AC-3). Refs always lists every candidate ref the id is known on — one entry when Collision is false, two or more when true.
type ScopeView ¶
type ScopeView struct {
AuthSHA string `json:"auth_sha"`
Entity string `json:"entity"`
Agent string `json:"agent"`
Principal string `json:"principal"`
State string `json:"state"`
Opened string `json:"opened,omitempty"`
EndedAt string `json:"ended_at,omitempty"`
EventCount int `json:"event_count"`
}
ScopeView is one scope's projection on `aiwf show`. It captures the authorization grant's metadata (SHA, agent, principal) and its current FSM state, plus the open/end dates and the count of transitions the scope has gone through.
Auth SHA is the full git SHA of the authorize-opened commit; callers that want a short form truncate. Entity is the scope- entity id at the time the scope was opened (rename-chain resolution lives in the verb gate, not here — show is descriptive, not gating).
func AssembleScopeViews ¶ added in v0.23.0
func AssembleScopeViews( id string, events []history.HistoryEvent, ownScopes []*scope.Scope, openers map[string]string, foreignScopes func(ent string) ([]*scope.Scope, error), dateOf func(sha string) string, ) ([]ScopeView, error)
AssembleScopeViews is the pure, git-free core of LoadEntityScopeViews: given an entity's loaded history events, its own scopes (source b), the repo-wide authorize-opener map, a resolver for a foreign scope-entity's scopes (source a), and a commit-date resolver, it assembles the scope-view list. The git-touching gather is the caller's job, so render's single pass (E-0054 / M-0221) assembles byte-identical views from its shared HEAD walk (opener map + replayed scopes + %aI dates) through this exact code path — no fourth copy of the assembly logic.
The M-0223 cost gates live in the caller (LoadEntityScopeViews loads ownScopes / openers only when the events warrant it); Assemble stays gate-free because the gates are pure optimizations — an empty openers map yields no foreign lookups, and empty ownScopes contributes nothing, so the assembled views are identical whether or not the caller gated.
foreignScopes is invoked only for a scope-entity that (a) an aiwf-authorized-by event references and (b) differs from id, so a caller that passes a nil openers map never triggers a foreign resolve. dateOf resolves a commit SHA to its author date (git show for the verb path; a lookup into the shared pass's %aI map for render).
func LoadEntityScopeViews ¶
LoadEntityScopeViews returns every scope that ever applied to id — scopes opened ON id (directly), plus scopes from elsewhere that authorized work touching id (via `aiwf-authorized-by:`).
Source (b) — scopes opened directly on id — comes from id's own history via cliutil.LoadEntityScopes, which is width-tolerant: this is both the single source of truth for direct scopes and the fix for the narrow-id omission (a raw-id `ent == id` compare against a canonicalized map value silently dropped `aiwf show E-14`'s table; M-0223).
Source (a) — scopes opened elsewhere that authorized work on id — is the only reason to run the repo-wide authorize-opener grep (cliutil.AuthorizeOpeners), and only when id was actually worked under a foreign scope (history.HasAuthorizedBy). An active direct-scope opener, which has no `aiwf-authorized-by`, resolves entirely from source (b) without the grep (E-0054 read-verb guard).
Empty / pre-aiwf repos return (nil, nil).
type ShowAC ¶
type ShowAC struct {
ID string `json:"id"`
Title string `json:"title"`
Status string `json:"status"`
TDDPhase string `json:"tdd_phase,omitempty"`
Description string `json:"description,omitempty"`
}
ShowAC is one AC's view inside a milestone show. Description carries the prose under the matching `### AC-N — <title>` heading in the milestone body, trimmed of surrounding whitespace; empty when the milestone body has no body section for this AC (e.g. seeded purely via frontmatter).
type ShowView ¶
type ShowView struct {
ID string `json:"id"`
Kind string `json:"kind"`
Title string `json:"title"`
Status string `json:"status"`
Path string `json:"path,omitempty"`
Parent string `json:"parent,omitempty"`
TDD string `json:"tdd,omitempty"`
// Priority carries the entity's own `priority` frontmatter
// (G-0078, E-0066, M-0263) — empty for a kind that never carries
// one (entity.CarriesOwnPriority) or an unprioritized gap/decision.
Priority string `json:"priority,omitempty"`
ACs []ShowAC `json:"acs,omitempty"`
Body map[string]string `json:"body,omitempty"`
History []history.HistoryEvent `json:"history,omitempty"`
Findings []check.Finding `json:"findings,omitempty"`
ReferencedBy []string `json:"referenced_by"`
Scopes []ScopeView `json:"scopes,omitempty"`
// Archived is true when the resolved entity's path lives under a
// per-kind `archive/` subdirectory per ADR-0004. JSON shape uses
// `omitempty` so active envelopes don't carry the field at all —
// downstream tooling treats presence as the indicator. Text
// rendering appends ` · archived` to the header line (see
// renderShowText). M-0087/AC-5.
Archived bool `json:"archived,omitempty"`
// Composite-id-only fields (when querying M-NNN/AC-N): the AC's
// own state, populated instead of (not in addition to) the
// milestone's full ACs slice.
AC *ShowAC `json:"ac,omitempty"`
ParentID string `json:"parent_id,omitempty"`
// CrossBranch is non-nil when id missed the local working tree but
// resolved live from another local or remote-tracking ref (M-0260,
// ADR-0030's read-side extension point). Nil for a locally-resolved
// entity — the JSON envelope omits the field entirely so a
// downstream consumer can treat its absence as "this is ordinary
// local state."
CrossBranch *CrossBranchView `json:"cross_branch,omitempty"`
// Area carries the resolving ref's real `area:` for a cross-branch
// hit so the `aiwf show --area` predicate can evaluate against the
// entity's actual area instead of the local-only tr.ResolvedAreaByID
// lookup, which reports any cross-branch id untagged (E-0067/M-0266,
// G-0419). In-memory only (json:"-") — the JSON envelope's shape is
// unchanged. Empty for a locally-resolved entity (the predicate uses
// the local lookup there); for a cross-branch collision (the content,
// including the area, is in dispute); and for a cross-branch
// milestone, whose own `area:` is never stored — a milestone's area
// rolls up from its parent epic, a resolution this own-field read
// deliberately does not follow across refs.
Area string `json:"-"`
}
ShowView is the aggregated per-entity state. Exported for the JSON envelope. Field-set varies by what kind of id was queried; absent fields render as empty / omitted in JSON via omitempty.
ReferencedBy is the inversion of the reference graph — every entity id that names this one as a target. Always emitted in JSON (zero- value `[]`) so downstream consumers never have to check for field presence; populated from tree.Tree.ReverseRefs at view-build time. For composite ids (M-NNN/AC-N), this lists referrers of the AC specifically; the parent milestone's referrers are not rolled in (use `aiwf show M-NNN` for that).
func BuildCompositeShowView ¶
func BuildCompositeShowView(ctx context.Context, root string, t *tree.Tree, loadErrs []tree.LoadError, id string, historyLimit int) (ShowView, bool)
BuildCompositeShowView handles `aiwf show M-NNN/AC-N`. Returns ok=false when the parent or AC doesn't exist.
func BuildShowView ¶
func BuildShowView(ctx context.Context, root string, t *tree.Tree, loadErrs []tree.LoadError, id string, historyLimit int) (ShowView, bool)
BuildShowView assembles the view for id; ok=false when no entity (or AC) matches. Composite ids resolve via the parent milestone's ACs slice.