Documentation
¶
Overview ¶
Package docsync is the library behind the `ds` tool: it keeps documentation bound to the code, configuration, and facts it describes, and reports when the thing behind a sentence changed (docs/SPEC.md).
The package is stdlib-only and pure over its inputs (§37): a System is built from an fs.FS, a parsed config, the previous ledger, and optional hooks; every operation returns values and never writes a file, reads the environment, or touches the network. The CLI owns paths, git, and printing.
Index ¶
- Constants
- Variables
- func CheckRule(l ledger.Ledger, r ledger.Refs) error
- func LineCR(line string) string
- func Tokens(s string) int
- type AckRequest
- type AdoptResult
- type AuditOptions
- type BlameResult
- type CheckOptions
- type Classifier
- type ContextItem
- type ContextOptions
- type ContextResult
- type CopyNote
- type DefineOptions
- type DefineResult
- type Edit
- type Envelope
- type Fact
- type FindOptions
- type Graph
- type GraphEdge
- type GraphNode
- type ImpactGroup
- type ImpactResult
- type KeySpec
- type Literal
- type ManualFix
- type MapChain
- type MapDef
- type MapOptions
- type MapPage
- type MapResult
- type Notifier
- type Observer
- type Omitted
- type Option
- func WithAcks(a ledger.Acks) Option
- func WithBodyAt(f func(hash string) (string, bool)) Option
- func WithClassifier(c Classifier) Option
- func WithClock(f func() time.Time) Option
- func WithCommandName(name string) Option
- func WithCommit(sha string) Option
- func WithCommitLookup(f func(sha string) bool) Option
- func WithConfig(c config.Config) Option
- func WithExtractCache(c scan.Cache) Option
- func WithExtractor(es ...extract.Extractor) Option
- func WithFS(fsys fs.FS) Option
- func WithForeignLink(f func(b block.Block) (string, bool)) Option
- func WithForeignSnapshot() Option
- func WithLocalReader(f func(path string) ([]byte, error)) Option
- func WithMerged(blocks ...block.Block) Option
- func WithMergedRefs(rows ...ledger.RefRow) Option
- func WithNotifier(n Notifier) Option
- func WithObserver(o Observer) Option
- func WithOldContent(f func(row ledger.Row) (string, bool)) Option
- func WithPicker(p Picker) Option
- func WithPrevious(l ledger.Ledger, r ledger.Refs) Option
- func WithPreviousForeign(rows ...ledger.Row) Option
- func WithRecords(f func(args map[string]string) ([]map[string]string, error)) Option
- func WithRegistry(r *extract.Registry) Option
- func WithRemoved(ids map[string]string) Option
- func WithRenderer(r Renderer) Option
- func WithRepo(name string) Option
- func WithResolver(r check.Resolver) Option
- func WithSnapshot(f func(id, sha string) (string, bool)) Option
- func WithSnapshotBlock(f func(id, sha string) (block.Block, bool)) Option
- func WithStore(st Store) Option
- func WithStoredHashes(m map[string]string) Option
- func WithTestResults(m map[string]check.TestOutcome) Option
- func WithURLCheck(f func(href string) check.URLResult) Option
- func WithVerb(names ...string) Option
- func WithVerbHandler(v Verb) Option
- type OwnerMetrics
- type Picker
- type Prefix
- type RemoteCiter
- type RenameResult
- type RenderOptions
- type Renderer
- type RepairResult
- type Report
- type ReportOptions
- type ReportResult
- type Stale
- type Store
- type System
- func (s *System) Ack(res scan.Result, req AckRequest) (ledger.Ack, error)
- func (s *System) Adopt(_ context.Context, res scan.Result) (AdoptResult, error)
- func (s *System) Audit(opts AuditOptions) []ledger.Ack
- func (s *System) Blame(rep Report, doc string, line int) (BlameResult, error)
- func (s *System) Bodies(res scan.Result) map[string]string
- func (s *System) Check(ctx context.Context, opts CheckOptions) (Report, error)
- func (s *System) Config() config.Config
- func (s *System) Context(ctx context.Context, target string, opts ContextOptions) (ContextResult, error)
- func (s *System) ContextFor(rep Report, target string, opts ContextOptions) ContextResult
- func (s *System) Define(_ context.Context, target string, opts DefineOptions) (DefineResult, error)
- func (s *System) ExtractFile(ctx context.Context, path string, src []byte) ([]block.Block, error)
- func (s *System) Facts(res scan.Result) []Fact
- func (s *System) Fences(res scan.Result, doc string, src []byte) ([]byte, int)
- func (s *System) FencesReport(res scan.Result, doc string, src []byte) ([]byte, int, []CopyNote)
- func (s *System) Find(res scan.Result, query string) []block.Block
- func (s *System) FindBy(res scan.Result, opts FindOptions) []block.Block
- func (s *System) FixDuplicates(res scan.Result) (RenameResult, error)
- func (s *System) Graph(rep Report) Graph
- func (s *System) Impact(ctx context.Context) (ImpactResult, error)
- func (s *System) LocateID(res scan.Result, id string) (block.Block, bool)
- func (s *System) Map(ctx context.Context, opts MapOptions) (MapResult, error)
- func (s *System) Notify(ctx context.Context, rep Report) error
- func (s *System) Read(res scan.Result, id, lines string) (string, error)
- func (s *System) Registry() *extract.Registry
- func (s *System) Rename(res scan.Result, oldPrefix, newPrefix string) (RenameResult, error)
- func (s *System) Render(ctx context.Context, doc string, opts RenderOptions) ([]byte, []render.Note, error)
- func (s *System) Repair(res scan.Result) RepairResult
- func (s *System) Report(rep Report, opts ReportOptions) ReportResult
- func (s *System) SaveState(ctx context.Context, res scan.Result, acks ledger.Acks) error
- func (s *System) Scan(ctx context.Context) (scan.Result, error)
- func (s *System) ScanFull(ctx context.Context) (scan.Result, error)
- func (s *System) Snapshot(res scan.Result) (ledger.Ledger, ledger.Refs)
- func (s *System) Why(res scan.Result, target string) (Why, error)
- type TriageGroup
- type Unmarked
- type Unresolved
- type Verb
- type VerbState
- type Why
Constants ¶
const ( ModeAuto = "auto" ModeFull = "full" ModeDiff = "diff" ModeValue = "value" ModeLine = "line" )
Content modes for Context items (§26.4).
const ( ReasonOverBudget = "over budget" ReasonUnchanged = "unchanged since ack; over budget" )
Omission reasons.
const ( NodeDef = "def" NodeDoc = "doc" EdgeCite = "cites" EdgeFrom = "from" EdgeCov = "covers" EdgeAbt = "about" )
Graph node and edge kinds (§22 `ds graph`).
const BytesPerToken = 4
BytesPerToken is the estimate behind every `tokens` field (§26.2): four bytes per token is the usual English-and-code average and errs high for prose, so a budget is never exceeded by the estimate being optimistic.
const JSONFormat = 1
JSONFormat is the version of the JSON contract (§26.2). It changes only additively within a major version.
const SinceAck = "ack"
SinceAck asks Context for diffs since the last ack; any other non-empty Since value is a commit, answered through ContextOptions.OldBody.
const SpecVersion = "1.0"
SpecVersion is the specification this library implements (§37.7).
const TriageThreshold = match.DefaultFuzzyThreshold
TriageThreshold is the diff similarity at or above which two unacked findings are one decision (§19 `ds triage`). It reuses the fuzzy-match ratio so "similar" means the same thing everywhere in the tool.
Variables ¶
var ( ErrNoFS = errors.New("docsync: WithFS is required") ErrNotFound = errors.New("docsync: not found") ErrDelegationRequired = errors.New("docsync: an agent ack needs delegated_by (§26.7)") // ErrDelegateNotOwner refuses an agent ack whose delegated_by is not a // person listed in [owners] (§26.7): the delegate is who judged, and a // name nobody vouches for records no judgment at all. ErrDelegateNotOwner = errors.New("docsync: delegated_by must name a person listed in [owners] (§26.7)") ErrNoReference = errors.New("docsync: no reference at that doc line") // ErrNoCarrier is returned instead of writing a directive into a file whose // type has no comment syntax in extract.Styles. It exists because the // alternative that shipped was writing the directive bare, which is invalid // syntax in every such format. ErrNoCarrier = errors.New("docsync: no comment carrier for this file type") // ErrGeneratedPath refuses to mint a def in a file under [scan] generated // (Part VII: "Generated paths refuse minting"). The next generation // rewrites the file and the directive with it, so the id would vanish // while every sentence citing it stayed; scan reports such a def after // the fact (scan.ErrDefInGenerated), and minting one is how it gets there. ErrGeneratedPath = errors.New("docsync: generated file; a def written here is overwritten by the next generation") // ErrWouldNotBind is returned instead of writing a directive the scan // could not bind. Define checks by extracting the edited source in memory // with the scan's own extractor, so the refusal comes before the file is // touched and `--dry-run` reports it too. ErrWouldNotBind = errors.New("docsync: the directive would not bind") // ErrRange is a `path:start-end` target that no def can bind exactly: // the tier's block from start ends elsewhere and no span= moves it to // end. Refused rather than narrowed, because the old reading -- the // first line only, silently -- defined a block nobody asked for. ErrRange = errors.New("docsync: no def binds exactly that line range") // ErrBadLabel is a rename target that is not a label: lowercase // words joined by single dashes. A label with a space was written into // every def and citation, and each came out as a broken directive. ErrBadLabel = errors.New("docsync: not a label") ErrHashMismatch = errors.New("docsync: reference is not to that id") // ErrBadLines is a `lines` fragment outside the grammar a citation // uses: `a` or `a-b`, digits only, 1 <= a <= b. A well-formed range // past the block's end is ErrNotFound instead: those lines do not exist. ErrBadLines = errors.New("docsync: bad lines") // ErrNoPageReview is a page review requested for a doc that declares // no review_every, or that the scan does not know. ErrNoPageReview = errors.New("docsync: page has no review_every to record a review against") // ErrNewerRule refuses this repo's ledger or refs when they record an // extraction rule newer than this build implements (§33 Versioning: an // older tool refuses a newer format by name, never by misparsing). Those // hashes cannot be compared with the ones this build computes: reading them // would report unchanged blocks as drift, and a scan would rewrite the // files under the older rule. The remedy is a newer ds. // // Pre-release builds stamped extract=2 to 4 for what is now rule 1 (the // counter was reset for the first release). Such a repository sees this // refusal once; setting extract=1 on the header line of .ds/ledger.tsv and // .ds/refs.tsv, then running `ds scan`, is the whole fix. ErrNewerRule = errors.New("docsync: recorded under a newer extraction rule than this build implements") // ErrOtherRule reports a ledger or refs recorded under an older extraction // rule, which is the upgrade path: unchanged blocks can report drift until // the next scan restamps both files, so hosts warn rather than refuse. ErrOtherRule = errors.New("docsync: recorded under an older extraction rule; unchanged blocks may report drift until the next scan") // ErrUnknownEnv refuses an environment name that [env] known does not // list, when it lists any. A misspelled --env used to run the whole // command against an environment nothing defines, and every citation // then reported a missing definition instead of the one typo. ErrUnknownEnv = errors.New("docsync: environment not in env.known") )
Sentinel errors.
var ErrContextMode = errors.New("context: unknown mode")
ErrContextMode is a ContextOptions.Mode outside ModeValues. It used to be accepted and served as a bare location, so a typo returned less than asked for without a word.
var ErrNoStore = errors.New("docsync: no store configured (WithStore)")
ErrNoStore is returned by SaveState when no Store was given.
var ErrSinceCommit = errors.New("context: since a commit needs OldBody, the body of a block at that commit")
ErrSinceCommit is a Since that names a commit with no OldBody hook to read the commit. Since was a commit nothing ever read: any value was accepted and the diff was the one since the last scan (bug 61).
ModeValues is the canonical list callers may pass.
Functions ¶
func CheckRule ¶
CheckRule compares the extraction rule the ledger and refs record with extract.Rule. A newer rule is ErrNewerRule, which WithPrevious refuses; an older one is ErrOtherRule, which hosts print as a warning (`ds check`, `ds scan`, `ds doctor`). Both name the file and the two rules. It is exported so a host that inspects the state without building a System (`ds doctor`) reports the same thing.
The ack log is not checked. Its header is written once and never restamped, so its rule says nothing about its rows, and each row carries its own rule, which check already reports by name ("ack was recorded under sentence rule N", section 18).
Types ¶
type AckRequest ¶
type AckRequest struct {
ID string
Doc string
Line int
Env string
Actor string
ActorKind ledger.ActorKind
DelegatedBy string
Note string
// Claim renews the claim on Doc:Line rather than acking a citation:
// ID is then ignored, and a line with no claim is ErrNoReference.
Claim bool
// Preview builds the row a real ack would record and notifies no
// observer, for `ack --dry-run`: an embedder watching acks must not be
// told of one that was never written.
Preview bool
// Page records that the whole of Doc was reread, for its review_every
// schedule: ID and Line are ignored, and the row carries no hashes.
// Before, a page review could only be recorded by acking a citation on
// the page, so a page with review_every and nothing cited had a finding
// nothing could clear.
Page bool
}
AckRequest describes one approval (§19, §26.7).
type AdoptResult ¶
type AdoptResult struct {
Envelope
// Edits insert defs into source and rewrite doc links to cites. Source
// edits come first so the ids exist before the cites do.
Edits []Edit `json:"edits"`
// Adopted counts links converted.
Adopted int `json:"adopted"`
// Unresolved lists links whose target could not be located, with why.
Unresolved []Unresolved `json:"unresolved"`
}
AdoptResult is what Adopt proposes.
type AuditOptions ¶
AuditOptions filters the ack log.
type BlameResult ¶
type BlameResult struct {
Envelope
Reference block.Reference `json:"reference"`
Block block.Block `json:"block"`
Change match.Change `json:"change"`
Finding check.Finding `json:"finding"`
Acks []ledger.Ack `json:"acks"`
}
BlameResult is the block behind a reference and what happened to it.
type CheckOptions ¶
type CheckOptions struct {
Strict bool
// Env overrides env.default for this run.
Env string
// Run and Resolve say the caller will execute directives and reach
// providers; the library itself still runs nothing.
Run bool
Resolve bool
// Full ignores the extraction cache.
Full bool
}
CheckOptions selects the passes of `ds check` (§16, §22).
type Classifier ¶
type Classifier = match.Classifier
Classifier replaces change classification (§20); it is match.Classifier.
type ContextItem ¶
type ContextItem struct {
Rank int `json:"rank"`
Why string `json:"why"`
ID string `json:"id"`
File string `json:"file"`
Lines [2]int `json:"lines"`
Tokens int `json:"tokens"`
Mode string `json:"mode"`
Content string `json:"content"`
}
ContextItem is one ranked piece of context.
type ContextOptions ¶
type ContextOptions struct {
Budget int
// Since is the baseline a diff is taken against: "" (the last scan),
// SinceAck (the last ack, the same diff `check` reports), or a commit,
// which needs OldBody.
Since string
Mode string
// OldBody returns a cited block's body at the commit Since names, in
// the form the scan gives it (false when the block did not exist
// there). The library reads no history; the caller's VCS does.
OldBody func(b block.Block) (string, bool)
}
ContextOptions bounds `ds context` (§26.4).
type ContextResult ¶
type ContextResult struct {
Envelope
Target string `json:"target"`
BudgetTokens int `json:"budget_tokens"`
UsedTokens int `json:"used_tokens"`
Items []ContextItem `json:"items"`
Omitted []Omitted `json:"omitted"`
}
ContextResult is the bundle.
type CopyNote ¶ added in v0.1.6
type CopyNote struct {
Doc string
Line int
ID string
// Skipped is true when no copy was written; false for a copy written
// with a caption only.
Skipped bool
Reason string
}
CopyNote is one thing refresh has to say about a repo-mode copy: that it was skipped, and why, or that it was written with less than the code (only the caption and link), and why.
Fences used to drop every such reason. A copy it could not render kept its old closer, check then called it `stale` with "run ds refresh" as the fix, and refresh said "0 repo-mode copies rewritten" and nothing else, so the one command named as the fix never said why it did nothing (bug 136).
type DefineOptions ¶
type DefineOptions struct {
// Label is the id prefix; empty derives one from the symbol or file.
Label string
Owner string
Stability string
Tags string
Desc string
Env string
}
DefineOptions are the directive keys `ds def` may set (§9.1).
type DefineResult ¶
type DefineResult struct {
ID string `json:"id"`
Existing bool `json:"existing"`
// Block is the block as the scanning tier binds it. For a new def its
// Pos is in the file as it was read, before Edit; DirectivePos is the
// line Edit writes the directive at.
Block block.Block `json:"block"`
Edit Edit `json:"edit"`
}
DefineResult is what Define returns.
type Edit ¶
type Edit struct {
File string `json:"file"`
Line int `json:"line"`
Old string `json:"old,omitempty"`
New string `json:"new"`
// Delete removes the line instead of rewriting it. It exists for the one
// write that cannot be expressed as a replacement: taking a directive out
// of a format with no comment syntax, where commenting it is impossible.
Delete bool `json:"delete,omitempty"`
// Next is the line that followed the deleted one when the edit was
// computed, or "" when it was the last. It is what makes a delete
// reversible: undo finds that line where the deleted one was, and only
// then puts the deleted line back above it, so an edit made since is never
// overwritten or misplaced.
Next string `json:"next,omitempty"`
}
Edit is a proposed change to one source file: the library never writes (§37.2). It has three shapes, told apart by its fields:
- insert: Old empty -- New goes in as a new line before Line.
- replace: Old set -- that exact line becomes New.
- delete: Delete set -- the line Old at Line is removed, and Next is the line that followed it.
Apply refuses when the file no longer has Old at Line, so an edit computed against a stale read cannot land on the wrong line.
type Envelope ¶
type Envelope struct {
JSONFormat int `json:"json_format"`
GeneratedAt time.Time `json:"generated_at"`
Repo string `json:"repo,omitempty"`
Commit string `json:"commit,omitempty"`
}
Envelope is the header every JSON result carries (§26.2).
type Fact ¶
type Fact struct {
ID string `json:"id"`
Value string `json:"value"`
Type string `json:"type,omitempty"`
File string `json:"file"`
Line int `json:"line"`
Env string `json:"env,omitempty"`
Owner string `json:"owner,omitempty"`
Secret bool `json:"secret,omitempty"`
CitedBy []block.Position `json:"cited_by"`
}
Fact is a one-line def with its current value (§11, `ds facts`).
type FindOptions ¶
FindOptions narrows Find (§26.5 `ds find <query> | --file path | --tag t`). Query matches id and symbol by case-insensitive substring; File is a path prefix; Tag is exact. Set fields combine with and; an empty set matches everything.
type GraphEdge ¶
type GraphEdge struct {
From string `json:"from"`
To string `json:"to"`
Kind string `json:"kind"`
Line int `json:"line,omitempty"`
}
GraphEdge links two nodes.
type GraphNode ¶
type GraphNode struct {
ID string `json:"id"`
Kind string `json:"kind"`
Label string `json:"label"`
State check.State `json:"state,omitempty"`
}
GraphNode is a def or a doc.
type ImpactGroup ¶
ImpactGroup is findings grouped by one key.
type ImpactResult ¶
type ImpactResult struct {
Envelope
Total int `json:"total"`
ByDoc []ImpactGroup `json:"by_doc"`
ByOwner []ImpactGroup `json:"by_owner"`
ByRepo []ImpactGroup `json:"by_repo"`
}
ImpactResult is what a change will flag (§22 `ds impact`).
type KeySpec ¶
KeySpec declares a verb's keys so unknown keys warn and missing required keys are problems, the same rule the built-in verbs follow.
type Literal ¶
type Literal struct {
Doc string `json:"doc"`
Line int `json:"line"`
ID string `json:"id"`
Value string `json:"value"`
}
Literal is a fact value typed by hand in prose instead of cited.
type ManualFix ¶
type ManualFix struct {
File string `json:"file"`
Line int `json:"line"`
Reason string `json:"reason"`
}
ManualFix is one line Repair found and left for a person.
type MapChain ¶
type MapChain struct {
Root string `json:"root"`
Hops int `json:"hops"`
State check.State `json:"state"`
}
MapChain is one chain row.
type MapDef ¶
type MapDef struct {
ID string `json:"id"`
Desc string `json:"desc,omitempty"`
File string `json:"file"`
Lines [2]int `json:"lines"`
CitedBy int `json:"cited_by"`
Stability block.Stability `json:"stability"`
State check.State `json:"state"`
Tokens int `json:"tokens"`
}
MapDef is one def row.
type MapPage ¶
type MapPage struct {
Path string `json:"path"`
Covers int `json:"covers"`
Cites int `json:"cites"`
State map[check.State]int `json:"state"`
Owner string `json:"owner,omitempty"`
Tokens int `json:"tokens"`
}
MapPage is one page row.
type MapResult ¶
type MapResult struct {
Envelope
Pages []MapPage `json:"pages"`
Defs []MapDef `json:"defs"`
Chains []MapChain `json:"chains"`
Freshness map[check.State]int `json:"freshness"`
BudgetTokens int `json:"budget_tokens"`
UsedTokens int `json:"used_tokens"`
Omitted int `json:"omitted"`
}
MapResult is the table of contents an agent reads instead of the tree.
type Option ¶
Option configures a System. Functional options only (§37.2).
func WithBodyAt ¶
WithBodyAt supplies block bodies by content hash from the body store (§20.1). It is what answers "what did this block say when the sentence was acked" across several scans and across repositories, which WithOldContent — keyed to the previous ledger — structurally cannot. Without it a drift the change table does not span is reported with block.ClassUnknown.
func WithClassifier ¶
func WithClassifier(c Classifier) Option
WithClassifier replaces change classification entirely.
func WithCommandName ¶ added in v0.1.3
WithCommandName names the binary that findings tell the reader to run, for a custom build (cli.WithName): its remedies say "pds ack", not a "ds ack" its users do not have. Empty keeps check.DefaultCommand.
func WithCommit ¶
WithCommit records the commit the tree is at, for permalinks and headers.
func WithCommitLookup ¶
WithCommitLookup answers `at=` pins.
func WithConfig ¶
WithConfig sets the parsed config; the library never reads the file itself. Omitted, config.Default() with `docs/**` and `**` as scan globs is used so a zero-config call still scans something.
func WithExtractCache ¶
WithExtractCache makes scans incremental: files whose bytes did not change reuse the cached extraction (§16), and a cache that also implements scan.StatCache spares unchanged files the read itself. CheckOptions.Full bypasses it.
func WithExtractor ¶
WithExtractor adds tiers ahead of the built-in ones; the last given wins for a path both match.
func WithForeignLink ¶ added in v0.1.3
WithForeignLink supplies the URL of a block another repository in the workspace defines, for `Render` (render.Options.ForeignLink). Repo-mode copies never use it: see render.Fragment. The library knows the defining repository's name and the block's path inside it, not where that repository is hosted, so the URL is the caller's decision. Without it such a block renders its location unlinked, with the repository named, rather than a link relative to this repository (bug 105).
func WithForeignSnapshot ¶
func WithForeignSnapshot() Option
WithForeignSnapshot says the merged blocks came from a committed snapshot rather than the live workspace index, so a citation this run cannot resolve is reported as unrecorded rather than as undefined (§21).
func WithLocalReader ¶ added in v0.1.3
WithLocalReader lets check look at `local=true` targets (§9.1, §12): f reads a def's file= path on the machine running check. A target that f reads, and whose pick= finds something, is `ok` there; one f cannot read stays `unverifiable`, which is what CI reports. Without it every local def is unverifiable everywhere (bug 85). Nothing read is hashed or stored: the ledger is shared and the file exists on one machine.
func WithMerged ¶
WithMerged supplies blocks from other repos in the workspace, as produced by sync (§21). They can be cited and rendered but are not this repo's.
func WithMergedRefs ¶
WithMergedRefs supplies references published by other repositories that point into this one (§21), so deleting a block here reports the docs elsewhere that depend on it.
func WithNotifier ¶
WithNotifier adds a delivery channel used by Notify.
func WithObserver ¶
WithObserver adds a sink for findings and acks.
func WithOldContent ¶
WithOldContent supplies the body a block had in a previous ledger row, for diffs and change classes; see match.Options.OldContent for why it takes the row. Typically backed by `git show` in the CLI.
func WithPrevious ¶
WithPrevious supplies the committed ledger and refs to diff against. Both zero means a first run: everything is new and ok. Either one recorded under a newer extraction rule is refused with ErrNewerRule.
func WithPreviousForeign ¶
WithPreviousForeign supplies the committed snapshot's rows as the previous position of every foreign block, so a block that moved in another repository since the last sync is reported as `moved` rather than in silence (§21).
func WithRecords ¶
WithRecords supplies a record source for `ds:table`.
func WithRegistry ¶
WithRegistry replaces tier selection entirely; the escape hatch (§37.3).
func WithRemoved ¶
WithRemoved names ids published by repositories that left the workspace, so citations report "repo removed" rather than "deleted" (§21).
func WithRenderer ¶
WithRenderer replaces the markdown output of Render.
func WithResolver ¶
WithResolver supplies the secret resolver used under --resolve (§12).
func WithSnapshot ¶
WithSnapshot supplies block bodies at a commit for `at=` rendering.
func WithSnapshotBlock ¶ added in v0.1.3
WithSnapshotBlock supplies the whole block at a commit for `at=` rendering: its body and where it was, so the caption and link of a snapshot name the lines the code occupied at that commit rather than today's. It takes precedence over WithSnapshot when both are given.
func WithStore ¶
WithStore loads the previous ledger, refs, and acks from st and keeps it for SaveState. It replaces WithPrevious and WithAcks.
func WithStoredHashes ¶
WithStoredHashes supplies truth hashes kept from an earlier resolve, so a changed truth reports as rotated.
func WithTestResults ¶
func WithTestResults(m map[string]check.TestOutcome) Option
WithTestResults supplies the last published CI outcomes for `assert=`.
func WithURLCheck ¶
WithURLCheck answers `ds:url` under --resolve.
func WithVerb ¶
WithVerb registers plugin verb names so references to them are not reported as unknown. Their check and render behaviour is the plugin's.
func WithVerbHandler ¶
WithVerbHandler registers a verb implementation. Its name is also added to the known verbs, so `WithVerb` is not needed alongside.
type OwnerMetrics ¶
OwnerMetrics is freshness per owner or page.
type RemoteCiter ¶ added in v0.1.3
type RemoteCiter struct {
Repo string `json:"repo"`
Doc string `json:"doc"`
Line int `json:"line"`
Verb string `json:"verb"`
}
RemoteCiter is one citation published by another repository: where it is, and the verb it cites with. The sentence itself is not published, so it is not here.
type RenameResult ¶
type RenameResult struct {
// Mapping is old id to new id for every id whose label changed.
Mapping map[string]string `json:"mapping"`
// Edits rewrite every def and reference line; one edit per line even
// when a line holds several ids.
Edits []Edit `json:"edits"`
}
RenameResult is what Rename proposes.
type RenderOptions ¶
type RenderOptions struct {
Env string
// Runs supplies recorded `ds:run` results by doc line.
Runs map[int]render.RunResult
// Source replaces the document's bytes, for `render --at` where the
// caller has the page as it was at a commit; nil reads the tree.
Source []byte
}
RenderOptions tunes Render.
type Renderer ¶
Renderer turns the rendered node sequence into bytes: markdown by default, html or a site generator's own tree when replaced.
type RepairResult ¶
type RepairResult struct {
Envelope
// Edits either comment a bare directive in the file's own syntax, which
// keeps its id so every citation still resolves, or -- in a format with no
// comment syntax -- delete it. A delete removes a def that was never valid
// there; its citations then report the id missing, which is the truth.
Edits []Edit `json:"edits"`
// Manual is damage no edit could be computed for: a file that could not be
// read back when the repair was built.
Manual []ManualFix `json:"manual"`
}
RepairResult is what Repair proposes: edits that mend each damaged directive, and the damage it could not reach.
type Report ¶
type Report struct {
Envelope
Summary map[check.Severity]int `json:"summary"`
States map[check.State]int `json:"states"`
Findings []check.Finding `json:"findings"`
Changes []match.Change `json:"-"`
Scan scan.Result `json:"-"`
ExitCode int `json:"exit_code"`
// TruthHashes are resolved truth hashes for the caller to store.
TruthHashes map[string]string `json:"-"`
}
Report is the result of Check: the JSON contract plus the scan it came from, so callers can build further views without rescanning.
func (Report) ApplyRuns ¶ added in v0.1.3
ApplyRuns records the outcomes of `ds:run` directives the caller executed as their findings, and recounts the summary and exit code: a failed run is a `run failed` error, a run not executed is `skipped` with the reason. The library runs nothing itself; see check.ApplyRuns.
type ReportOptions ¶
type ReportOptions struct {
// Churn is commits touching each file, supplied by the CLI from git;
// nil disables the most-changed-files-without-defs view.
Churn map[string]int
// Limit caps each list; 0 means everything.
Limit int
// ServedBytes and SourceBytes are what agents received through
// `context` and `read` against the size of the files those items came
// from (§26.11), recorded by the host; zero means not measured.
ServedBytes, SourceBytes int64
}
ReportOptions selects the hygiene views of `ds report` (§22, §26.9).
type ReportResult ¶
type ReportResult struct {
Envelope
Uncovered []block.Block `json:"uncovered"`
Unmarked []Unmarked `json:"unmarked"`
Stalest []Stale `json:"stalest"`
Literals []Literal `json:"literals"`
OrphanedOwners []string `json:"orphaned_owners"`
Gaps []string `json:"gaps"`
PerPage []OwnerMetrics `json:"per_page"`
PerOwner []OwnerMetrics `json:"per_owner"`
MeanTimeToAck time.Duration `json:"mean_time_to_ack_ns"`
BusyPrefixes []Prefix `json:"busy_prefixes"`
// ServedBytes and SourceBytes echo the options; ContextSavings is the
// fraction of file bytes an agent did not have to read.
ServedBytes int64 `json:"served_bytes"`
SourceBytes int64 `json:"source_bytes"`
ContextSavings float64 `json:"context_savings"`
}
ReportResult is every view; the CLI prints the ones asked for.
type Stale ¶
type Stale struct {
Doc string `json:"doc"`
OldestAck time.Time `json:"oldest_ack"`
Cites int `json:"cites"`
NeverAck bool `json:"never_acked"`
}
Stale is a page ordered by its oldest live ack.
type Store ¶
type Store interface {
Load(ctx context.Context) (ledger.Ledger, ledger.Refs, ledger.Acks, error)
Save(ctx context.Context, l ledger.Ledger, r ledger.Refs, a ledger.Acks) error
}
Store is where committed state lives. The default is the `.ds/` TSV files in the CLI; a database or the workspace index can stand in.
type System ¶
type System struct {
// contains filtered or unexported fields
}
System is a configured instance. Build one with New; it is safe to share between goroutines because every method is read-only over its fields.
func (*System) Ack ¶
Ack builds the ack row for a reference against the block's current hash and the sentence's current hash. The caller appends it to the log. An agent actor must name who delegated; the library refuses otherwise so no tool path can approve its own work silently.
func (*System) Adopt ¶
Adopt converts hand-written `path#L10-L20` and `path#symbol` links in scanned docs into defs and cites (§22 `ds adopt`). A link whose target already has a def gets a cite to the existing id; otherwise an id is minted and a directive edit is proposed above the block. Every edit is returned, none applied; the caller applies source edits first, then doc edits, then rescans.
func (*System) Audit ¶
func (s *System) Audit(opts AuditOptions) []ledger.Ack
Audit returns ack events matching the filter, oldest first; the log is already append-only so no other ordering is needed (§33).
func (*System) Blame ¶
Blame answers `ds blame <doc> <line>`: the reference on that line, the block it points at, the change since the ledger, the current finding, and every ack recorded for that line (§22). History beyond the previous ledger needs the VCS and belongs to the CLI.
func (*System) Bodies ¶
Bodies is what the caller should add to the body store after a scan: every def's body keyed by its content hash (§20.1). Content-addressed, so re-storing an unchanged block is a no-op and history accumulates without duplication; the caller writes, because the library never does.
Secret and local blocks are excluded and this is enforced here rather than left to the caller: the workspace index is readable by people who may not read the source repository, and a body written there cannot be recalled. A block with no content (a merged row, which carries a hash but no body) contributes nothing.
func (*System) Context ¶
func (s *System) Context(ctx context.Context, target string, opts ContextOptions) (ContextResult, error)
Context returns a page with every block it cites, or a block with every sentence about it, ranked and budgeted. Order is deterministic for identical inputs so prompt caches hit.
func (*System) ContextFor ¶
func (s *System) ContextFor(rep Report, target string, opts ContextOptions) ContextResult
ContextFor is Context over an existing report, for callers that already checked and want several bundles without rescanning.
func (*System) Define ¶
func (s *System) Define(_ context.Context, target string, opts DefineOptions) (DefineResult, error)
Define returns the id for `path#Symbol` or `path:line`, minting one and proposing the directive insertion when the block has none (§22 `ds def`). One def per block: an existing directive on that block is returned as is.
func (*System) ExtractFile ¶
ExtractFile runs the scan pipeline over one file's bytes -- the tier that owns the path, `pick`, the key-to-value step and secret redaction -- and returns the defs it finds, exactly as a scan of that content would.
Why it exists: an OldContent hook has to hand back a block's previous body in the same form as its current one, or the diff compares two different things. The CLI's hook cut the raw lines out of the old file, so a config value changed from 443 to 8443 was diffed as the whole line "port: 443 # ds:def id=…" against "8443", directive comment included, and a secret's old value came back unredacted. Going through the same pipeline makes old and new comparable by construction.
The extraction cache is not used: old bytes must never be stored or served as though they were the current file's.
func (*System) Facts ¶
Facts lists every one-line def and who cites it. Secrets are addresses and render as such; the value is the visible name, never a credential.
func (*System) Fences ¶
Fences rewrites the repo-mode copies in one document (§9.2 include.mode = repo): every block-position `ds:block` gets, or has refreshed, the fragment `refresh` maintains, closed by a line carrying the block's short hash. src is the document's current bytes (the caller read them, so the caller decides what a read failure means); it returns the new bytes and how many regions changed. Nothing is written. FencesReport also says which copies could not be written and why.
func (*System) FencesReport ¶ added in v0.1.6
FencesReport is Fences plus a note for every copy in doc that was skipped or written without its code, in line order. A skip is never silent: the copy keeps whatever it held, and the note says why (bug 136).
It follows [include] mode, where Fences writes every copy whatever the mode. In repo mode every block-position citation gets a copy. In build mode a page is rendered at build time and owes no copy, so none is inserted, but a copy already in the page (left from repo mode, or pasted) is still brought up to date. check compares such a copy with its block in either mode, and before this a build-mode refresh never touched it, so check reported it stale with "run ds refresh" as the fix, forever (bug 141).
func (*System) Find ¶
Find returns defs matching a free query: substring on id or symbol, file prefix, or exact tag, whichever hits.
func (*System) FixDuplicates ¶
func (s *System) FixDuplicates(res scan.Result) (RenameResult, error)
FixDuplicates re-mints every def after the first for each id defined more than once (Part VII "Ids and branches"): the first occurrence in file order keeps the id, the tool never guesses which one is the original, and the caller prints old→new. Edits rewrite only the directive lines; the caller applies them and rescans.
func (*System) Impact ¶
func (s *System) Impact(ctx context.Context) (ImpactResult, error)
Impact checks the working tree against the previous ledger and returns only the findings a change causes: unacked, translation-stale, broken, expired-by-about. Everything else is hygiene, not impact.
func (*System) Map ¶
Map runs a check and ranks pages and defs under the budget: anything not ok first, then most cited, then by path so output is deterministic.
func (*System) Notify ¶
Notify sends the report's non-ok findings to every notifier; the first failure is returned after the rest were tried.
func (*System) Registry ¶
Registry returns the extractor registry in use, so a host that has a document in memory (an editor buffer) can extract it the same way a scan would.
func (*System) Rename ¶
Rename relabels ids whose label starts with oldPrefix so it starts with newPrefix instead (§22 `ds rename`). Identity is the suffix, so the ledger keeps matching after the edit; the old rows simply carry the old label and match by suffix on the next scan. Nothing is written: the caller applies the edits and rescans.
func (*System) Render ¶
func (s *System) Render(ctx context.Context, doc string, opts RenderOptions) ([]byte, []render.Note, error)
Render expands one document to plain markdown (§22 `ds render`).
func (*System) Repair ¶
func (s *System) Repair(res scan.Result) RepairResult
Repair proposes the fix for every directive written as a bare line into a file whose format does not accept one -- the damage `ds def` left behind before it learned to refuse. It returns edits and never writes (§22).
A format with comments gets the line commented: a commented directive is still a def, so its id and every sentence citing it keep working, and the file parses again. A format with no comment syntax -- JSON, CSV, go.sum -- has nothing to comment into, so the line is deleted. That delete is reversible like every other source write: it carries the line that followed it, so `ds undo` can find the place and put it back, and refuses if the file has moved around it since.
Edits in a file are ordered bottom-up, so applying them in order never shifts a line a later edit points at. A directive continued onto following lines is mended whole; a deleted one records as its Next the first line after it that survives, since the line straight after may be going too.
func (*System) Report ¶
func (s *System) Report(rep Report, opts ReportOptions) ReportResult
Report computes the hygiene views from a report (§26.9 "proactive rather than reactive").
func (*System) SaveState ¶
SaveState writes the snapshot of res and the given ack log through the Store.
func (*System) Scan ¶
Scan extracts every def and reference under the config's globs, using the extraction cache when one is configured.
type TriageGroup ¶
type TriageGroup struct {
Group int `json:"group"`
Diff string `json:"diff"`
Classes []block.Class `json:"class,omitempty"`
Findings []check.Finding `json:"findings"`
}
TriageGroup is a set of unacked findings whose diffs look alike.
func Triage ¶
func Triage(rep Report) []TriageGroup
Triage groups a report's unacked findings by diff similarity so a mechanical change across many blocks is one decision with one note. Findings without a diff (no old content was available) group by block id instead: the same block changed is still the same decision. Group numbers are assigned in finding order, so they are stable for identical input.
type Unmarked ¶
type Unmarked struct {
File string `json:"file"`
Symbol string `json:"symbol,omitempty"`
Line int `json:"line,omitempty"`
Churn int `json:"churn,omitempty"`
}
Unmarked is a file with change history and no definitions, or an exported declaration nobody cites.
type Unresolved ¶
type Unresolved struct {
Doc string `json:"doc"`
Line int `json:"line"`
Target string `json:"target"`
Reason string `json:"reason"`
}
Unresolved is a link Adopt left alone.
type Verb ¶
type Verb interface {
Name() string
Carriers() []block.Carrier
Keys() KeySpec
Check(ref block.Reference, st *VerbState) []check.Finding
Render(ref block.Reference, st *VerbState, inline bool) (text string, ok bool, err error)
}
Verb is a plugin directive verb (§9.9). Check returns findings for one reference; Render returns the text that replaces the directive, inline for a link in prose and as a block otherwise. ok=false means "leave the source as written".
type VerbState ¶
VerbState is the read-only view a verb gets: the defs of the tree and the merged workspace, by id.
type Why ¶
type Why struct {
ID string `json:"id"`
Defs []block.Block `json:"defs"`
Refs []block.Reference `json:"refs"`
CoveredBy []string `json:"covered_by"`
// Chain is the from= path from the id to its truth, first element the
// id itself; empty when the id has no from= and nothing points at it.
Chain []block.Block `json:"chain"`
// Copies are defs whose from= is this id.
Copies []block.Block `json:"copies"`
History []ledger.Ack `json:"history"`
// RemoteRefs are citations of the id that other repositories in the
// workspace published (WithMergedRefs). Refs holds only this
// repository's scan, so a block cited from another repository read as
// cited by nobody, the one question `why` exists to answer (bug 103).
RemoteRefs []RemoteCiter `json:"remote_refs,omitempty"`
}
Why is everything that depends on an id (§22 `ds why`).
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package block holds the data model shared by every docsync stage: a defined Block, a Reference to one, and the closed-set constants (kind, carrier, stability, change class) that the ledger, findings, and JSON contract use.
|
Package block holds the data model shared by every docsync stage: a defined Block, a Reference to one, and the closed-set constants (kind, carrier, stability, change class) that the ledger, findings, and JSON contract use. |
|
Package check turns a scan, the previous ledger, and the ack log into findings: one row per reference or per problem, with a state from the spec's table, a severity, the change class and diff where relevant, and a remedy an agent can execute verbatim (docs/SPEC.md §16 passes 3 to 5, §17).
|
Package check turns a scan, the previous ledger, and the ack log into findings: one row per reference or per problem, with a state from the spec's table, a severity, the change class and diff where relevant, and a remedy an agent can execute verbatim (docs/SPEC.md §16 passes 3 to 5, §17). |
|
Package config reads `.ds/config.toml` (docs/SPEC.md §23) and the workspace file, with defaults for everything the spec gives a default.
|
Package config reads `.ds/config.toml` (docs/SPEC.md §23) and the workspace file, with defaults for everything the spec gives a default. |
|
Package directive parses and formats the single docsync directive shape,
|
Package directive parses and formats the single docsync directive shape, |
|
ext
|
|
|
records/sqlite
module
|
|
|
structured
module
|
|
|
treesitter
module
|
|
|
Package extract finds directives in a file and binds `ds:def` directives to the block they define (docs/SPEC.md §7.1, §10).
|
Package extract finds directives in a file and binds `ds:def` directives to the block they define (docs/SPEC.md §7.1, §10). |
|
Package id mints, validates, and splits docsync block identifiers.
|
Package id mints, validates, and splits docsync block identifiers. |
|
internal
|
|
|
difflib
Package difflib computes line-level diffs and a similarity ratio between two texts, with no dependencies.
|
Package difflib computes line-level diffs and a similarity ratio between two texts, with no dependencies. |
|
duration
Package duration parses the duration shape docsync writes in directives and in configuration: an integer followed by a unit.
|
Package duration parses the duration shape docsync writes in directives and in configuration: an integer followed by a unit. |
|
glob
Package glob matches slash-separated paths against patterns with `*`, `?`, `[...]`, and the `**` segment that spans directories.
|
Package glob matches slash-separated paths against patterns with `*`, `?`, `[...]`, and the `**` segment that spans directories. |
|
keypath
Package keypath is the one grammar for config key paths, shared by the config tier that binds keys in a file (extract) and the pick that reads a key out of a remote def's target (pick).
|
Package keypath is the one grammar for config key paths, shared by the config tier that binds keys in a file (extract) and the pick that reads a key out of a remote def's target (pick). |
|
linerange
Package linerange parses the `lines=` fragment a citation uses to show part of a block: `a-b` or `a`, 1-based and inclusive.
|
Package linerange parses the `lines=` fragment a citation uses to show part of a block: `a-b` or `a`, 1-based and inclusive. |
|
mdspan
Package mdspan finds the inline spans of a markdown line that are not running prose: code spans and links.
|
Package mdspan finds the inline spans of a markdown line that are not running prose: code spans and links. |
|
textnorm
Package textnorm normalizes text before hashing so that changes which carry no meaning never register as changes.
|
Package textnorm normalizes text before hashing so that changes which carry no meaning never register as changes. |
|
Package ledger reads and writes the three committed state files (docs/SPEC.md §15, §19): the ledger of every defined block, the reverse index of every reference, and the append-only ack log.
|
Package ledger reads and writes the three committed state files (docs/SPEC.md §15, §19): the ledger of every defined block, the reverse index of every reference, and the append-only ack log. |
|
Package match compares the blocks a scan found against the previous ledger and decides, per id, what happened (docs/SPEC.md §16 pass 3): ok, moved, changed, moved-unmarked, rewritten?, deleted, or new.
|
Package match compares the blocks a scan found against the previous ledger and decides, per id, what happened (docs/SPEC.md §16 pass 3): ok, moved, changed, moved-unmarked, rewritten?, deleted, or new. |
|
Package pick evaluates `pick=` expressions: how a single value or a single contiguous range is taken out of a bound block (docs/SPEC.md §10).
|
Package pick evaluates `pick=` expressions: how a single value or a single contiguous range is taken out of a bound block (docs/SPEC.md §10). |
|
Package procplugin implements both sides of the process-plugin protocol (docs/SPEC.md §37.4): executables named `ds-<kind>-<name>` on PATH that speak one JSON object per line over stdin and stdout, so a plugin can be written in any language and a Go plugin can be shipped as a process with no extra code.
|
Package procplugin implements both sides of the process-plugin protocol (docs/SPEC.md §37.4): executables named `ds-<kind>-<name>` on PATH that speak one JSON object per line over stdin and stdout, so a plugin can be written in any language and a Go plugin can be shipped as a process with no extra code. |
|
Package records is the first record source for `ds:table` (docs/SPEC.md §9.5): a directory of markdown files whose YAML frontmatter holds the fields.
|
Package records is the first record source for `ds:table` (docs/SPEC.md §9.5): a directory of markdown files whose YAML frontmatter holds the fields. |
|
Package render expands directives in one markdown document into plain markdown at build time (docs/SPEC.md §9, §22 `ds render`).
|
Package render expands directives in one markdown document into plain markdown at build time (docs/SPEC.md §9, §22 `ds render`). |
|
Package scan walks a file tree, hands each eligible file to the extractor registry, and merges the results into one Result with repo-relative positions, resolved remote defs, and duplicate-id detection (docs/SPEC.md §16 passes 1 and 2).
|
Package scan walks a file tree, hands each eligible file to the extractor registry, and merges the results into one Result with repo-relative positions, resolved remote defs, and duplicate-id detection (docs/SPEC.md §16 passes 1 and 2). |
|
Package sentence decides what prose a reference binds to (docs/SPEC.md §18).
|
Package sentence decides what prose a reference binds to (docs/SPEC.md §18). |
|
Package workspace merges what every repository in a workspace published into one id table and one reverse index (docs/SPEC.md §21), and reads the index layout that `publish` writes and `sync` reads:
|
Package workspace merges what every repository in a workspace published into one id table and one reverse index (docs/SPEC.md §21), and reads the index layout that `publish` writes and `sync` reads: |