Documentation
¶
Overview ¶
Package diff compares two normalized documents and emits a structured change set: numeric statement deltas matched by concept (labels drift, concepts are stable) and narrative changes matched by item id and diffed at paragraph granularity. It is a pure function over two *model.Document values — it never fetches or re-parses — so a diff is just another schema-stamped artifact the same way a document is. It depends only on internal/model and the standard library.
Index ¶
- Variables
- func DiffLexical(prev, curr string) string
- func DiffWithLayer(prev, curr *model.Document, layer Layer) (*ChangeSet, []LexicalSectionDiff, error)
- type CellDelta
- type ChangeKind
- type ChangeSet
- type FilingRef
- type JSON
- type Layer
- type LexicalParagraph
- type LexicalRenderer
- type LexicalSectionDiff
- type Markdown
- type ParagraphChange
- type Renderer
- type RowDelta
- type SectionDiff
- type StatementDiff
Constants ¶
This section is empty.
Variables ¶
var ErrNilDocument = errors.New("diff: nil document")
ErrNilDocument is returned when either side of the diff is nil.
var ErrSemanticNotImplemented = errors.New(
"sec-cli: --layer semantic is not yet implemented; use --layer structural (default) or --layer lexical. " +
"Semantic embedding-distance ranking is planned for v1.0.1.",
)
ErrSemanticNotImplemented is returned when --layer semantic is requested. Semantic (embedding-distance) ranking is deferred to v1.0.1: shipping a half-baked embedding pipeline would compromise the "no LLM dependency in the core" principle. The structural layer surfaces what changed; the lexical layer shows exactly how. The semantic ranking layer (which paragraphs changed the most in meaning, noise-filtered) is a planned follow-up.
var ErrUnknownFormat = errors.New("diff: unknown format")
ErrUnknownFormat is returned by RendererFor for an unrecognized format name.
Functions ¶
func DiffLexical ¶
DiffLexical returns a human-readable word-level diff between two paragraph texts. Equal spans are shown in-line; insertions are wrapped in [+...+] and deletions in [-...-]. The result is suitable for the --layer lexical view where an analyst wants to compare specific wording changes.
func DiffWithLayer ¶
func DiffWithLayer(prev, curr *model.Document, layer Layer) (*ChangeSet, []LexicalSectionDiff, error)
DiffWithLayer runs a structural diff and, for the lexical layer, annotates modified paragraphs with word-level diffs. The semantic layer returns ErrSemanticNotImplemented.
Types ¶
type CellDelta ¶
type CellDelta struct {
Period string `json:"period"`
Prev *float64 `json:"prev"`
Curr *float64 `json:"curr"`
Abs *float64 `json:"abs"`
Pct *float64 `json:"pct"`
}
CellDelta is the change to one concept in one overlapping period: the two values and their absolute and percentage change. Any field is null when it cannot be computed — a missing value is null (never 0), and Pct is null when the previous value is absent or zero. Pct is a percentage (e.g. 11.5 means +11.5%), not a fraction.
type ChangeKind ¶
type ChangeKind string
ChangeKind classifies a single change. A row or paragraph is added when it appears only in the current filing, removed when only in the previous, changed when present in both with differing values, and unchanged when present in both with identical values.
const ( Added ChangeKind = "added" Removed ChangeKind = "removed" Changed ChangeKind = "changed" Unchanged ChangeKind = "unchanged" )
Change kinds.
type ChangeSet ¶
type ChangeSet struct {
SchemaVersion string `json:"schema_version"`
Prev FilingRef `json:"prev"`
Curr FilingRef `json:"curr"`
Statements []StatementDiff `json:"statements"`
Sections []SectionDiff `json:"sections"`
}
ChangeSet is the structured result of diffing two documents: what filings were compared, the per-statement numeric deltas, and the per-section narrative changes. It carries its own SchemaVersion so a rendered diff is a versioned artifact like a Document.
type FilingRef ¶
type FilingRef struct {
Company string `json:"company,omitempty"`
Ticker string `json:"ticker,omitempty"`
Form string `json:"form,omitempty"`
Accession string `json:"accession,omitempty"`
FilingDate string `json:"filing_date,omitempty"`
PeriodEnd string `json:"period_end,omitempty"`
}
FilingRef identifies one side of the comparison — enough to label the report without carrying the whole document.
type JSON ¶
type JSON struct{}
JSON renders the canonical, schema-stable serialization of a change set: deterministic field order, HTML left unescaped so paragraph text stays readable, and a trailing newline.
type Layer ¶
type Layer string
Layer selects the granularity of the narrative diff.
const ( LayerStructural Layer = "structural" // subsection-grain add/remove/modify (default) LayerSemantic Layer = "semantic" // embedding-distance ranking (v1.0.1, not yet implemented) LayerLexical Layer = "lexical" // word-level diff via diffmatchpatch )
Layer constants match the --layer flag values from DESIGN.md.
type LexicalParagraph ¶
type LexicalParagraph struct {
Text string `json:"text"`
}
LexicalParagraph is one paragraph's word-level diff. Text carries the annotated form: equal spans are plain, insertions are [+..+], deletions [-...-].
type LexicalRenderer ¶
type LexicalRenderer struct{}
LexicalRenderer writes a lexical diff report — per-section word-level diffs — as plain Markdown. It is used when --layer lexical is requested and wraps both the structural ChangeSet header and the word-level paragraph diffs.
func (LexicalRenderer) Render ¶
func (LexicalRenderer) Render(cs *ChangeSet, lexical []LexicalSectionDiff, w io.Writer) error
Render writes the lexical diff as Markdown.
type LexicalSectionDiff ¶
type LexicalSectionDiff struct {
Item string `json:"item,omitempty"`
Title string `json:"title,omitempty"`
Paragraphs []LexicalParagraph `json:"paragraphs,omitempty"`
}
LexicalSectionDiff is the lexical-layer change to one section: the section coordinates and the word-level diff strings for paragraphs that changed.
func DiffLexicalSections ¶
func DiffLexicalSections(cs *ChangeSet, prev, curr []string) []LexicalSectionDiff
DiffLexicalSections produces a word-level diff for the modified sections from a structural ChangeSet. Added/removed sections are omitted (their full text appears in the structural report); only sections with at least one changed paragraph are included.
type Markdown ¶
type Markdown struct{}
Markdown renders the human- and LLM-facing "what changed" report: a heading naming the two filings, a deltas table per statement (changed/added/removed rows only — unchanged lines are omitted so the change stands out), and a bulleted list of added/removed paragraphs per section.
type ParagraphChange ¶
type ParagraphChange struct {
Kind ChangeKind `json:"kind"`
Text string `json:"text"`
}
ParagraphChange is one paragraph added or removed from a section's free text.
type Renderer ¶
Renderer writes one serialization of a ChangeSet to w. It mirrors the shape of internal/render's Renderer (a total function over the artifact) so a diff renders the same way a document does — JSON is the canonical contract, Markdown the human- and LLM-facing "what changed" report.
func RendererFor ¶
RendererFor returns the renderer for a format name: "json" (the default) or "md"/"markdown". Text is intentionally not offered — a diff is a report, and its two useful forms are the canonical JSON and the Markdown summary.
type RowDelta ¶
type RowDelta struct {
Concept string `json:"concept,omitempty"`
Label string `json:"label"`
Status ChangeKind `json:"status"`
Cells []CellDelta `json:"cells"`
}
RowDelta is one statement line matched across the two filings by concept (so a relabeled line still matches). Status summarizes the row; Cells carries the per-period numbers.
type SectionDiff ¶
type SectionDiff struct {
Item string `json:"item,omitempty"`
Title string `json:"title,omitempty"`
Paragraphs []ParagraphChange `json:"paragraphs,omitempty"`
}
SectionDiff is the narrative change to one section, matched between filings by item id. Paragraphs lists the added and removed paragraphs in merge order; a reworded paragraph surfaces as a removed/added pair.
type StatementDiff ¶
type StatementDiff struct {
Title string `json:"title,omitempty"`
RoleURI string `json:"role_uri,omitempty"`
Periods []string `json:"periods"`
Rows []RowDelta `json:"rows"`
}
StatementDiff is the change to one financial statement, matched between the two filings by role URI (or title when no role). Periods are the reporting periods present in both filings, in current-filing order; every RowDelta's cells align to them.