Documentation
¶
Overview ¶
Package plan enriches agent-generated implementation plans with SageOx team context. ox computes DETERMINISTIC badges locally (zero LLM tokens) and assembles a context bundle; the client agent does any inference. ox NEVER makes an LLM or network call in this path.
Architecture:
- Detectors produce deterministic Annotations from local data (collision, prior-art, expert-routing). They are fail-open: missing/unreadable data returns (nil, nil), never an aborting error.
- Retrievers assemble a context bundle ([]ContextItem) the client agent reasons over to author judgment badges (aligns/conflicts, expert perspective). Also fail-open.
- Enrich() orchestrates registered detectors and retrievers, aggregating results into a Result with a deterministic SignalSummary.
Round 2 agents implement detectors/retrievers in collision.go, expert.go, priorart.go (and a context-bundle assembler) and register them via init().
Index ¶
- Constants
- func AppendResolution(planDir string, r Resolution, now time.Time) error
- func FeedbackDigest(items []MergedItem) string
- func Load(gitRoot, slug string) (string, Result, PlanInfo, error)
- func MutatePlanMeta(ctx context.Context, planDir string, mutate func(*Meta) (*Meta, error)) error
- func PlanHTMLPath(dir string) (path string, ref lfs.FileRef, isPointer, exists bool)
- func ReconcileSessionOutcome(gitRoot, slug, sessionID, outcome string) error
- func RecordPlanGenerated(res Result, saved bool)
- func RegisterDetector(d Detector)
- func RegisterRetriever(r Retriever)
- func RenderHTML(in Input, res Result) ([]byte, error)
- func RenderHTMLOpts(in Input, res Result, opts RenderOptions) ([]byte, error)
- func RenderViz(pattern string, data []byte) (string, error)
- func Save(gitRoot string, in Input, res Result, html []byte, meta Meta) (string, error)
- func SaveFeedback(planDir string, set FeedbackSet, now time.Time) (string, error)
- func SetSessionOutcome(gitRoot, slug, outcome string) error
- func SetStatus(gitRoot, slug string, status PlanStatus) error
- func Slugify(topic string) string
- type Annotation
- type BadgeKind
- type BadgeType
- type BrandingFinding
- type CollabSignals
- type ContextItem
- type Detector
- type DiagramHint
- type DiagramKind
- type FeedbackItem
- type FeedbackSet
- type FeedbackStatus
- type Finding
- type Input
- type MergedItem
- type Meta
- type PlanInfo
- type PlanStatus
- type Provenance
- type RenderOptions
- type Resolution
- type ResolutionState
- type Result
- type Retriever
- type Section
- type SignalSummary
- type VizPattern
Constants ¶
const ( // NonTrivialMinFiles: a multi-file plan (>= 2 distinct files) is non-trivial. // Exported as the single source of truth: the plan-exit hook mirrors these // for wording and a drift test asserts the copies stay equal. NonTrivialMinFiles = 2 // NonTrivialMinSteps: a ~5+ step plan is non-trivial, matching the prime // "~5+ steps" criterion. H2 sections are the step proxy. NonTrivialMinSteps = 5 )
const ( SessionOutcomeActive = "active" SessionOutcomeStopped = "stopped" SessionOutcomeAborted = "aborted" )
Session-outcome values for Provenance.SessionOutcome. "" == unknown.
const SchemaVersion = "v1"
SchemaVersion is the on-disk schema version stamped into both annotations.json (Result.SchemaVersion) and meta.json (Meta.SchemaVersion) on write. These are long-lived ledger artifacts a future ox may need to migrate; an explicit version lets a reader detect and adapt to an older layout instead of guessing. Bump this when the serialized shape of Result or Meta changes incompatibly.
Variables ¶
This section is empty.
Functions ¶
func AppendResolution ¶
func AppendResolution(planDir string, r Resolution, now time.Time) error
AppendResolution adds one agent disposition to the append log.
func FeedbackDigest ¶
func FeedbackDigest(items []MergedItem) string
FeedbackDigest renders a compact, agent-readable summary from the merged view: open/addressed/verified/wontfix counts, then every OPEN actionable item with its anchor (the id to resolve), section, label, and note. Returns "" when there is no feedback.
func Load ¶
Load reads a captured plan by slug. The slug matches either the meta.json slug or the directory's trailing slug segment (the YYYY-MM-DD- prefix is optional in the lookup). Returns the raw plan markdown, the stored Result, and the listing info.
func MutatePlanMeta ¶
MutatePlanMeta runs an exclusive read-modify-write under an advisory flock on a plan's meta.json — the direct mirror of lfs.MutateSessionMeta. Every write to meta.json AFTER the initial Save (status changes, session-outcome reconciliation) MUST go through this so a re-save and a concurrent session-stop/doctor write serialize at the filesystem level instead of clobbering each other.
The mutator receives the on-disk Meta (nil if the file is missing) and returns the Meta to write, or nil to leave the file untouched (an "only if exists" guard). Returning an error aborts the write.
func PlanHTMLPath ¶
PlanHTMLPath returns the absolute path to a captured plan's plan.html, the referenced FileRef when it is an LFS pointer, and whether the file exists. The view path uses this to decide between opening a plain HTML file and hydrating a pointer first.
func ReconcileSessionOutcome ¶
ReconcileSessionOutcome backfills the producing session's canonical id and final outcome onto a plan (by slug) at session-stop, where both are known. sessionID is the ses_<UUIDv7> minted at stop (skipped when ""); outcome is a SessionOutcome* constant. Single flocked write so it can't race a re-save.
func RecordPlanGenerated ¶
RecordPlanGenerated emits a single-line, key=value structured metric for a completed `ox plan` enrichment. It is purely local observability — there is no server LLM in this path, so there is nothing to meter server-side. The counts let us see, in aggregate, how often plans fire collision / prior-art / expert signals and how much context the bundle carried, without recording any plan content.
saved reports whether the enriched plan was captured to the ledger. It is a separate boolean (not derived from res) because auto-save is gated on config and on a configured ledger, independent of the signal summary.
func RegisterDetector ¶
func RegisterDetector(d Detector)
RegisterDetector adds a deterministic detector to the global registry. Call from an init() in the detector's file. Nil detectors are ignored.
func RegisterRetriever ¶
func RegisterRetriever(r Retriever)
RegisterRetriever adds a context-bundle retriever to the global registry. Call from an init() in the retriever's file. Nil retrievers are ignored.
func RenderHTML ¶
RenderHTML renders a resolved plan + its enrichment Result into a single self-contained HTML document. Deterministic and network-free at render time (Mermaid loads from CDN only when the page is viewed).
func RenderHTMLOpts ¶
func RenderHTMLOpts(in Input, res Result, opts RenderOptions) ([]byte, error)
RenderHTMLOpts is RenderHTML with optional render-time context (e.g. the slug for the review layer). RenderHTML delegates here with zero options.
func RenderViz ¶
RenderViz renders one parameterized pattern from its JSON data into an HTML fragment. Returns an error for an unknown pattern or malformed data so the command layer can show an actionable message.
func Save ¶
Save writes a captured plan into the ledger under data/plans/<dated-slug>/. It writes plan.md (from in.Raw), annotations.json (res), and meta.json as plain git-tracked text. plan.html is written ONLY when html != nil: plain when small, as an LFS pointer when it exceeds htmlLFSThreshold. Save never renders HTML and never commits — it only materializes files in the working tree. Returns the absolute plan directory.
gitRoot is the producing project's git root; the ledger path is resolved from it via ProjectContext. Returns an error if no ledger is configured (the caller decides whether that is fatal — the porcelain path treats it as "nothing to save").
func SaveFeedback ¶
SaveFeedback writes a review round under <planDir>/feedback/. now controls the timestamp (tests stay deterministic). Returns the written path.
func SetSessionOutcome ¶
SetSessionOutcome reconciles the producing session's lifecycle onto the plan (by slug) under the meta flock — written only by session-stop / `ox doctor`, never by Save. Use the SessionOutcome* constants. No-op if no meta.json.
func SetStatus ¶
func SetStatus(gitRoot, slug string, status PlanStatus) error
SetStatus updates a saved plan's lifecycle status (by slug) under the meta flock. No-op if the plan dir has no meta.json. Use the PlanStatus* constants.
Types ¶
type Annotation ¶
type Annotation struct {
Section string `json:"section,omitempty"`
Kind BadgeKind `json:"kind"`
Type BadgeType `json:"type"`
Why string `json:"why"`
SourceURL string `json:"source_url,omitempty"`
Expert string `json:"expert,omitempty"`
Files []string `json:"files,omitempty"`
}
Annotation is a single badge attached to a plan section.
type BadgeKind ¶
type BadgeKind string
BadgeKind distinguishes who produces an annotation: ox locally (deterministic, zero tokens) versus the client agent (judgment, reasoned from the bundle).
type BadgeType ¶
type BadgeType string
BadgeType is the specific signal an annotation carries.
const ( // BadgeCollision: plan touches files in an open PR, hotspot, or recent murmur. BadgeCollision BadgeType = "collision" // BadgePriorArt: a teammate already did or planned this. BadgePriorArt BadgeType = "prior-art" // BadgeExpertRoute: who owns this area + their relevant work (deterministic). BadgeExpertRoute BadgeType = "expert-routing" // BadgeAligns: plan aligns with ADRs, decisions, conventions (judgment). BadgeAligns BadgeType = "aligns" // BadgeConflicts: plan conflicts with ADRs, decisions, conventions (judgment). BadgeConflicts BadgeType = "conflicts" // BadgeExpertPersp: synthesized expert stance, cited (judgment). BadgeExpertPersp BadgeType = "expert-perspective" // BadgeRigor: collaboration-rigor stance synthesized from CollabSignals — // how thoughtful the human↔agent path to this plan was (judgment). ox emits // the raw counts (CollabSignals); the agent/cloud authors this badge. BadgeRigor BadgeType = "rigor" )
type BrandingFinding ¶
type BrandingFinding = Finding
BrandingFinding is retained as an alias so existing callers/tests keep compiling; new code should use Finding.
func LintBranding ¶
func LintBranding(html []byte, res Result) []BrandingFinding
LintBranding verifies a rendered plan HTML carries the conditional SageOx attribution the html-plan skill is spec'd to produce. The contract (extensions/claude/skills/ox-plan/SKILL.md, "SageOx attribution — subtle, earned, conditional"):
- EARNED: when the plan carried enrichment — any deterministic badges OR context-bundle items were present — the render MUST credit it: a footer line ("…enriched by SageOx") and, when there are deterministic badges, at least one anchored OX marker.
- NO OVERCLAIM: an un-enriched plan (no badges, empty context) must NOT carry SageOx credit — there is nothing to credit.
- SELF-CONTAINED: the OX marker's avatar must never be a live remote <img src>; it is data:-inlined or an inline-SVG monogram. Always checked.
Returns nil when the page satisfies the contract. Fail-open: callers warn, never block.
type CollabSignals ¶
type CollabSignals struct {
UserPrompts int `json:"user_prompts"` // distinct human turns before the plan
AgentQuestions int `json:"agent_questions"` // AskUserQuestion / clarifying tool calls
ToolCalls int `json:"tool_calls"` // exploration-depth proxy
DurationSeconds int `json:"duration_seconds"` // first user prompt → plan finalized
}
CollabSignals are deterministic, locally-counted facts about the human↔agent collaboration that produced the plan — effort proxies, NOT a score. Scoring (a rigor judgment) is authored by the agent now / a cloud judge later, per ADR-021. Signal COUNTS (collisions/prior-art/expert-routes) deliberately live in annotations.json (Result.Signals), not here, to avoid duplication.
type ContextItem ¶
type ContextItem struct {
Kind string `json:"kind"` // murmur|session|decision|adr|commit|discussion
Title string `json:"title"`
Ref string `json:"ref"`
Snippet string `json:"snippet,omitempty"`
Score float64 `json:"score"`
Author string `json:"author,omitempty"`
When string `json:"when,omitempty"`
}
ContextItem is one ranked, pre-retrieved slice of ledger / team context / code the client agent reasons over to author judgment badges.
type Detector ¶
type Detector interface {
Name() string
Detect(ctx context.Context, in Input, gitRoot string) ([]Annotation, error)
}
Detector produces deterministic annotations from local data. MUST be fail-open: on missing/unreadable data return (nil, nil), never an error that aborts enrichment.
type DiagramHint ¶
type DiagramHint struct {
Section string `json:"section"` // H2 heading the hint applies to
SuggestedType DiagramKind `json:"suggested_type"` // the diagram form that fits
Reason string `json:"reason"` // what structure was detected, in one clause
}
DiagramHint is a deterministic, per-section suggestion of which diagram form best captures the structure ox detected in that section. Rendering an HTML plan is now deterministic and free, so the only remaining lever on diagram QUALITY is the Mermaid the agent authors into the plan markdown — these hints point any agent (Claude, Codex, Gemini, …) at the right diagram for THIS plan, per section, instead of defaulting every section to a flowchart. Computed locally with zero LLM/network calls, same lane as the badge detectors.
type DiagramKind ¶
type DiagramKind string
DiagramKind is a suggested diagram form for a plan section. The values are the literal Mermaid diagram keyword (or "swimlane-timeline" for the hand-built CSS timeline) so the agent can paste the suggestion straight into a fenced block.
const ( DiagramSequence DiagramKind = "sequenceDiagram" // ordered call/response path DiagramState DiagramKind = "stateDiagram-v2" // states + time-bounded transitions DiagramSwimlane DiagramKind = "swimlane-timeline" // phased/parallel work (CSS, not Mermaid) DiagramTopology DiagramKind = "flowchart-LR" // dependency/topology graph DiagramFlowchart DiagramKind = "flowchart-TB" // branching procedure (hero default) )
type FeedbackItem ¶
type FeedbackItem struct {
Anchor string `json:"anchor"` // stable content-hash id, e.g. "h3f9a1c2"
Section string `json:"section,omitempty"` // section heading the element sits under
Label string `json:"label"` // short text of the element
Status FeedbackStatus `json:"status"` // approve | request-change | flag | comment
Note string `json:"note,omitempty"` // the reviewer's comment
}
FeedbackItem is one anchored review mark. Anchor is a CONTENT hash of the element (section heading + element text), computed page-side, so it survives a re-render and only disappears when the agent rewrites that text — which is itself the signal the item was addressed. Anchor doubles as the item id used by `ox plan feedback resolve`.
type FeedbackSet ¶
type FeedbackSet struct {
Slug string `json:"slug"`
Reviewer string `json:"reviewer,omitempty"`
CreatedAt time.Time `json:"created_at"`
Items []FeedbackItem `json:"items"`
}
FeedbackSet is one review round (one submit from the page).
func LoadAllFeedback ¶
func LoadAllFeedback(planDir string) ([]FeedbackSet, error)
LoadAllFeedback reads every review round under a plan dir, oldest first. A missing feedback/ dir is not an error. resolutions.json is skipped (it is not a round).
func ParseFeedback ¶
func ParseFeedback(raw []byte) (FeedbackSet, error)
ParseFeedback decodes and validates a review-round JSON (the page submit/export). Fail-loud on malformed input, an unknown status, or an unsafe slug.
type FeedbackStatus ¶
type FeedbackStatus string
FeedbackStatus is the reviewer's verdict on one anchored element.
const ( FeedbackApprove FeedbackStatus = "approve" FeedbackRequestChange FeedbackStatus = "request-change" FeedbackFlag FeedbackStatus = "flag" FeedbackComment FeedbackStatus = "comment" )
type Finding ¶
type Finding struct {
Rule string // stable id, e.g. "branding.footer-credit" / "mermaid.arrow-in-label"
Message string // human-readable, actionable
}
Finding is one advisory lint result on a rendered plan HTML — attribution (branding.*) or diagram (mermaid.*). All findings are warn-level: linting NEVER blocks a render or a save (fail-open agent UX). A non-empty slice means the render did not honor the html-plan contract or carries a diagram that will not render.
func LintMermaid ¶
LintMermaid extracts every Mermaid diagram from a rendered/saved plan HTML and returns one Finding per high-confidence problem. Fail-open: no diagrams (or none broken) returns nil.
func LintMermaidMarkdown ¶
LintMermaidMarkdown is the same check over raw plan markdown (```mermaid fences), for the render-time path where the source is in hand before the page is built.
func LintRender ¶
LintRender runs the full advisory contract over a rendered plan HTML: SageOx attribution (LintBranding) plus diagram validity (LintMermaid). It is the single entrypoint `ox plan lint` / `ox plan save` call. Fail-open: an empty page returns nil.
type Input ¶
Input is a resolved plan: its source path (if any), raw markdown, and parsed sections.
func Parse ¶
Parse splits markdown into Sections on "## " H2 headings and extracts the file references cited in each section. Content before the first H2 becomes a preamble Section with an empty Heading (only emitted when it has content).
func Resolve ¶
Resolve reads a plan from --file if set, otherwise from a piped stdin, and parses it into an Input. When neither is provided it best-effort auto-discovers the active plan-mode file: the newest *.md under ~/.claude/plans/ (the dir Claude Code plan-mode writes to). Precedence is --file > piped stdin > auto-discovery. An empty/unfound source yields an Input with empty Raw and no sections (the enrich path must stay fail-open on empty input); the caller is expected to surface a clear "no plan found" message rather than enrich nothing.
type MergedItem ¶
type MergedItem struct {
FeedbackItem
RaisedAt time.Time
Resolution *Resolution
Open bool
}
MergedItem is a review item joined with its latest resolution and a computed open/closed state. Open = no resolution, or the item was re-raised after the last resolution (CreatedAt newer than the resolution's At).
func AssembleReview ¶
func AssembleReview(planDir string) ([]MergedItem, error)
AssembleReview joins every review item (latest mark per anchor across rounds) with its latest resolution, computing open/closed. This is the single source the digest and the render read. An item is OPEN when it has no resolution, or when it was re-raised after the latest resolution (supporting the verify loop).
type Meta ¶
type Meta struct {
// SchemaVersion stamps the meta.json shape (set to SchemaVersion on write)
// so a future reader can detect and migrate an older layout.
SchemaVersion string `json:"schema_version,omitempty"`
Topic string `json:"topic"`
Slug string `json:"slug"`
Authors []string `json:"authors,omitempty"`
CreatedAt time.Time `json:"created_at"`
SourcePlanPath string `json:"source_plan_path,omitempty"`
// Status is the plan's lifecycle. Missing == "draft" for legacy plans.
Status PlanStatus `json:"status,omitempty"`
// Provenance links the plan to its producing session/agent/repo (forward).
Provenance *Provenance `json:"provenance,omitempty"`
// Collaboration holds the deterministic collaboration-effort counts.
Collaboration *CollabSignals `json:"collaboration,omitempty"`
}
Meta is the git-tracked descriptor written as meta.json alongside a captured plan. It carries the searchable, hydration-free facts about the plan: who authored it, when, where it came from, which session/agent produced it, and how thoughtful the collaboration was.
func ReadPlanMeta ¶
ReadPlanMeta returns the stored Meta for a saved plan (by slug), including provenance, collaboration signals, and status. Used by the view path to surface the link without re-deriving it.
type PlanInfo ¶
type PlanInfo struct {
Slug string
Topic string
Dir string
CreatedAt time.Time
Authors []string
HasHTML bool
}
PlanInfo is the listing-level view of a captured plan, assembled from meta.json. Dir is the absolute path to the plan folder.
type PlanStatus ¶
type PlanStatus string
PlanStatus is the plan's own lifecycle, independent of the producing session. A plan is worth keeping even if never built — it is a decision record and prior-art seed — so status lets UI/search weight rather than discard. v1: a plain writable field; no CLI auto-detection of "implemented" (that correlation is inference and belongs in the cloud judge per ADR-021).
const ( PlanStatusDraft PlanStatus = "draft" PlanStatusApproved PlanStatus = "approved" // reviewer signed off via the review loop PlanStatusImplemented PlanStatus = "implemented" PlanStatusAbandoned PlanStatus = "abandoned" PlanStatusSuperseded PlanStatus = "superseded" )
type Provenance ¶
type Provenance struct {
// Join keys (may dangle if the session was aborted / never uploaded).
//
// Two-phase population, because the canonical ses_ SessionID is minted
// fresh at session-STOP and is NOT knowable mid-recording:
// - SessionName is the durable identifier available at plan-save time
// (the recording's folder name, what `ox session view <name>` resolves).
// It is the primary join key and is always set when a recording is live.
// - SessionID (ses_<UUIDv7>) is BACKFILLED at session-stop, in the same
// reconciliation that sets SessionOutcome=stopped — we have the real id
// and the produced-plan slugs in hand there. Empty for aborted sessions
// (no stop) and for plans saved outside a recording.
SessionName string `json:"session_name,omitempty"`
SessionID string `json:"session_id,omitempty"` // ses_<UUIDv7>, backfilled at stop
AgentID string `json:"agent_id,omitempty"` // Ox#### stable agent instance
RepoID string `json:"repo_id,omitempty"`
// Denormalized snapshot — renders without the session present.
AgentType string `json:"agent_type,omitempty"` // claude-code, codex, ...
Model string `json:"model,omitempty"`
AuthorName string `json:"author_name,omitempty"` // privacy-safe display name at save time
// SessionOutcome is RECONCILED SYSTEM STATE, not authored provenance:
// "" (unknown) | "active" | "stopped" | "aborted". Written only by
// session-stop / `ox doctor` through MutatePlanMeta, never by Save.
SessionOutcome string `json:"session_outcome,omitempty"`
}
Provenance ties a saved plan back to the session/agent/repo that produced it. It is DENORMALIZED on purpose: the join keys (SessionID/AgentID/RepoID) are the precise link, but a session can be aborted, never uploaded, or GC'd, so the snapshot fields (AgentType/Model/AuthorName) let a plan render fully without the session present. Duplication is the feature, not a smell.
type RenderOptions ¶
type RenderOptions struct {
Slug string
// Review is the merged review state (rounds + resolutions) for this plan, so
// the render can show each item's open/addressed state inline and in a
// summary. Empty for a plan with no review yet.
Review []MergedItem
// ReviewEndpoint + ReviewToken are set ONLY when the page is served by the
// ephemeral `ox plan review` server: the page POSTs marks to the endpoint
// with the token. Empty for a static file:// render (clipboard fallback).
ReviewEndpoint string
ReviewToken string
}
RenderOptions carries optional render-time context that isn't part of the enrichment Result.
type Resolution ¶
type Resolution struct {
Anchor string `json:"anchor"` // the item it resolves
State ResolutionState `json:"state"` // addressed | wontfix | verified
Commit string `json:"commit,omitempty"` // commit SHA that made the change
Note string `json:"note,omitempty"` // what the agent did / why wontfix
At time.Time `json:"at"`
}
Resolution is one agent disposition of a review item, append-logged.
func LoadResolutions ¶
func LoadResolutions(planDir string) ([]Resolution, error)
LoadResolutions reads the append log (latest entries last). Missing is empty.
type ResolutionState ¶
type ResolutionState string
ResolutionState is the agent's disposition of a review item.
const ( ResolutionAddressed ResolutionState = "addressed" // agent made the change ResolutionWontfix ResolutionState = "wontfix" // agent declined, with reason ResolutionVerified ResolutionState = "verified" // human confirmed the fix )
type Result ¶
type Result struct {
// SchemaVersion stamps the serialized annotations.json shape (set to
// SchemaVersion on write) so a future reader can detect an older layout.
SchemaVersion string `json:"schema_version,omitempty"`
Annotations []Annotation `json:"annotations"`
Context []ContextItem `json:"context"`
Signals SignalSummary `json:"signals"`
// DiagramHints are deterministic per-section diagram suggestions (which
// Mermaid/timeline form fits the structure ox detected). Empty when no
// section had strong enough structure to suggest one.
DiagramHints []DiagramHint `json:"diagram_hints,omitempty"`
// Guidance is a concise, cross-agent authoring contract for rendering a
// fantastic HTML plan (decision-first, ten-minute reader, diagrams over
// prose). It folds in the DiagramHints so the agent gets plan-specific
// direction, not a generic spec. Empty for a trivial/empty plan.
Guidance string `json:"guidance,omitempty"`
}
Result is the full output of Enrich: deterministic annotations, the context bundle, and the signal summary.
func Enrich ¶
Enrich runs every registered detector and retriever against the plan, FAIL-OPEN: a panic or error in any one detector/retriever is logged and skipped, never aborting the others. It aggregates the annotations and context items, computes a deterministic SignalSummary, and returns a sorted, deduped Result.
ox makes NO network or LLM call here — detectors and retrievers read only local data. Round 2 owns their implementations.
type Retriever ¶
type Retriever interface {
Name() string
Retrieve(ctx context.Context, in Input, gitRoot string) ([]ContextItem, error)
}
Retriever produces context-bundle items. Also fail-open.
type SignalSummary ¶
type SignalSummary struct {
Collisions int `json:"collisions"`
PriorArt int `json:"prior_art"`
ExpertRoutes int `json:"expert_routes"`
Material bool `json:"material"`
Files int `json:"files"`
Steps int `json:"steps"`
NonTrivial bool `json:"non_trivial"`
}
SignalSummary is the deterministic rollup of which signals fired.
Material is the TEAM-CONTEXT axis: true when the plan warrants surfacing a nudge because team context had something to say (any collision OR expert-route OR at least one strong prior-art hit).
NonTrivial is the STRUCTURAL axis, independent of team context: true when the plan is substantial enough to warrant an enriched HTML render for human review even on greenfield work where zero team-context signals fire — multi-file (Files >= 2) OR many-step (Steps >= 5). Files counts distinct file references cited across all sections; Steps counts H2 sections (excluding the preamble). These mirror the prime non-triviality criteria; hotspot/open-PR is already covered by Material, and "architectural" is left to agent judgment.
type VizPattern ¶
type VizPattern struct {
ID string `json:"id"` // stable slug, e.g. "sparkline"
Use string `json:"use"` // when to reach for it
Why string `json:"why"` // the cognitive payoff
Param string `json:"param,omitempty"` // data-shape hint when `ox plan viz render <id> --data` is supported
Body string `json:"body"` // copy-paste snippet(s) + any notes
}
VizPattern is one catalog entry.
func VizCatalog ¶
func VizCatalog() []VizPattern
VizCatalog parses and returns every visualization pattern, in document order.
func VizPatternByID ¶
func VizPatternByID(id string) (VizPattern, bool)
VizPatternByID returns the pattern with the given id (case-insensitive), or ok=false when none matches.