Documentation
¶
Overview ¶
Package initcfg discovers project structure and renders a starter .archfit.yaml. It is an adapter (uses toolrun.Runner for go list) and may import os for filesystem inspection (DiscoverTS, DiscoverPy).
Package initcfg — source patcher for .archfit.yaml files. ApplyEdits locates nodes via goccy AST, then mutates the original bytes via line splices so comments, formatting, and untargeted sections are preserved.
Index ¶
- Constants
- func ApplyEdits(src []byte, edits []Edit) ([]byte, error)
- func DiscoverRust(ctx context.Context, root string, runner toolrun.Runner) ([]ModuleDef, []ModuleEdge, error)
- func PinModuleValues(src []byte, field ModuleField, current map[string]string, pins []ValuePin) ([]byte, int, error)
- func PinSubdomains(src []byte, currentSubdomains map[string]string, pins []SubdomainPin) ([]byte, int, error)
- func Render(cfg DiscoveredConfig, ann map[string]ModuleAnnotation, apply bool) string
- func RenderUpdateReport(r UpdateReport, ann map[string]ModuleAnnotation, allowedLayers []string) string
- func WriteSubdomainDrafts(path string, f SubdomainDraftFile) error
- func WriteValueDrafts(path string, f ValueDraftFile) error
- type AddModuleEdit
- type ClassifyTarget
- type CommentModuleEdit
- type DiscoveredConfig
- type Edit
- type ExistingModule
- type ModuleAnnotation
- type ModuleDef
- type ModuleEdge
- type ModuleField
- type PathDelta
- type SetModuleFieldsEdit
- type SubdomainDraft
- type SubdomainDraftFile
- type SubdomainPin
- type UpdateModulePathsEdit
- type UpdateReport
- type ValueDraft
- type ValueDraftFile
- type ValuePin
Constants ¶
const ( SubdomainStatusDraft = "draft" SubdomainStatusApproved = "approved" )
Draft status values for SubdomainDraft.Status.
const ( DraftStatusDraft = "draft" DraftStatusApproved = "approved" )
Draft status values shared by the single-scalar draft files (owner, volatility).
Variables ¶
This section is empty.
Functions ¶
func ApplyEdits ¶ added in v0.2.0
ApplyEdits applies a list of edits to src in a single bottom-up pass. The original bytes outside targeted line ranges are preserved exactly, keeping comments, key order, rules, and exceptions intact.
func DiscoverRust ¶ added in v0.6.0
func DiscoverRust(ctx context.Context, root string, runner toolrun.Runner) ([]ModuleDef, []ModuleEdge, error)
DiscoverRust enumerates first-party crates from `cargo metadata` and returns one ModuleDef per workspace member. Each module's Paths glob is the crate name itself — Rust graph nodes are "package:<crate>" (path = crate name) and the change-locality file mapping also keys on the crate name, so a crate-name glob matches both the dependency node and the file-derived module key.
Returns (nil, nil, nil) when cargo is absent (a Cargo.toml can exist without a toolchain installed); a present-but-failing cargo or unparseable output is a real error, mirroring discoverGo's loud-on-failure behaviour.
func PinModuleValues ¶ added in v0.5.0
func PinModuleValues(src []byte, field ModuleField, current map[string]string, pins []ValuePin) ([]byte, int, error)
PinModuleValues applies approved pins for one module field to the .archfit.yaml source bytes. field selects which scalar to write (FieldOwner or FieldVolatility). current maps module name → current value for that field (empty string if unset). Only modules whose field is absent are updated — a field already set to a different value is left alone (never overwrite human edits); a field already set to the same value is an idempotent no-op. Returns (patched bytes, count of modules actually patched, error).
func PinSubdomains ¶ added in v0.3.0
func PinSubdomains(src []byte, currentSubdomains map[string]string, pins []SubdomainPin) ([]byte, int, error)
PinSubdomains applies approved subdomain pins to the .archfit.yaml source bytes. currentSubdomains maps module name → current subdomain value (empty string if unset). Only modules whose subdomain field is absent (or whose current value already matches the pin — idempotent) are updated. Returns (patched bytes, count of modules actually patched, error).
func Render ¶
func Render(cfg DiscoveredConfig, ann map[string]ModuleAnnotation, apply bool) string
Render converts a DiscoveredConfig into a YAML string suitable for saving as .archfit.yaml. The output includes a TODO comment and uses only known config fields so it round-trips through config.Load.
ann maps module names to LLM annotations. When ann is nil the output is byte-identical to the pre-annotation Render. apply controls plan vs live mode: false = comment-only suggestions; true = write live fields.
func RenderUpdateReport ¶ added in v0.2.0
func RenderUpdateReport(r UpdateReport, ann map[string]ModuleAnnotation, allowedLayers []string) string
RenderUpdateReport produces a human-readable plan-mode drift report. Sections are omitted when their slice is empty.
- ADDED: paste-ready YAML stanzas via writeModuleStanza (apply=true so fields are visible to copy; out-of-set layers still render as comments per writeModuleStanza rules).
- REMOVED: each removed module noted as "not found in discovery — verify or remove".
- PATH DRIFT: config vs discovered paths, with an explicit note that --apply replaces module paths with the discovered paths and writes a backup.
- UNCLASSIFIED: modules missing classification; shows LLM suggestion from ann when present, otherwise suggests running with --llm.
- When r.StructuralInSync is true, emits a "structurally in sync" line.
Output is deterministic. Must not import internal/config or internal/llm.
func WriteSubdomainDrafts ¶ added in v0.3.0
func WriteSubdomainDrafts(path string, f SubdomainDraftFile) error
WriteSubdomainDrafts writes the draft file atomically (temp + rename).
func WriteValueDrafts ¶ added in v0.5.0
func WriteValueDrafts(path string, f ValueDraftFile) error
WriteValueDrafts writes the draft file atomically (temp + rename).
Types ¶
type AddModuleEdit ¶ added in v0.2.0
type AddModuleEdit struct {
Def ModuleDef
Ann *ModuleAnnotation // may be nil
}
AddModuleEdit inserts a new module stanza. NO-OP if the module key already exists live.
type ClassifyTarget ¶ added in v0.2.0
ClassifyTarget bundles the information sent to the LLM classifier for one module. Paths mirrors ModuleDef.Paths verbatim. Files holds up to 20 first-level file basenames resolved from filesystem-glob paths (Go/TS style, e.g. "internal/x/**") or from a Python dotted path converted to a directory (e.g. "ccgram.handlers" → <root>/ccgram/handlers). Files is empty when the directory does not exist or when paths are purely dotted with no corresponding directory.
func BuildClassifyTargets ¶ added in v0.2.0
func BuildClassifyTargets(root string, mods []ModuleDef) []ClassifyTarget
BuildClassifyTargets produces one ClassifyTarget per ModuleDef, in the same order as mods. For each module it attempts to collect up to 20 first-level regular-file basenames:
- Filesystem-glob paths (contain "/" — Go "internal/x/**" or TS "src/x/**"): strip a trailing "/**" to get the directory, join under root, read first-level regular files, skip dot- and underscore-prefixed names.
- Python dotted paths (contain ".", no "/"): convert dots to slashes and look for the directory under root. If absent, Files is left empty (explicit degrade).
Files are de-duplicated, sorted, and capped at 20. Output is deterministic: target order matches mods; Files within each target are sorted.
type CommentModuleEdit ¶ added in v0.2.0
CommentModuleEdit prefixes the module's full source range (incl. head comment) with a removal marker. NO-OP if the marker already exists.
type DiscoveredConfig ¶
type DiscoveredConfig struct {
// ModulePath is the Go module path (e.g. "github.com/alexei-led/archfit").
ModulePath string
// Modules are the discovered candidate modules.
Modules []ModuleDef
// Layers are the inferred layers in order (outermost to innermost).
Layers []string
// Edges are the directed module-level dependency edges, populated when a
// dependency graph was available at discovery time (go list Imports, cargo
// metadata resolve). Empty when no graph data was available.
Edges []ModuleEdge
// PyPackage is the primary Python top-level package name (e.g. "ccgram").
PyPackage string
// HasGo is true when a go.mod was found at root.
HasGo bool
// HasPython is true when Python packages were discovered.
HasPython bool
// HasTS is true when TypeScript packages were discovered.
HasTS bool
// HasRust is true when a Cargo.toml was found at root.
HasRust bool
}
DiscoveredConfig holds all discovered modules from Go, TypeScript, and Python.
func Discover ¶
Discover detects Go, Python, and TypeScript modules at root. Go discovery is skipped when no go.mod exists. Python and TypeScript discovery run unconditionally (they guard on their own marker files).
Name uniqueness is guaranteed by a two-pass disambiguation applied after all language discoverers have run:
First pass — only colliders are touched. For each module name shared by more than one module, every module with that name is renamed to a slug derived from its first Paths glob: strip a trailing "/**", then replace every "/" and "." with "_". Modules whose names are already unique are left completely unchanged.
Second pass — if any slug still collides with another entry (slug or an original name that was never touched), a deterministic numeric suffix is appended ("_2", "_3", …). Suffixes are assigned in ascending order over the slice position so the result is stable across runs.
type Edit ¶ added in v0.2.0
type Edit interface {
// contains filtered or unexported methods
}
Edit is a sealed mutation to apply to an .archfit.yaml source. Only the types defined in this package satisfy Edit.
type ExistingModule ¶ added in v0.2.0
type ExistingModule struct {
Name string
Paths []string
HasSubdomain bool
HasVolatility bool
HasLayer bool
}
ExistingModule represents a module already present in the config file.
type ModuleAnnotation ¶ added in v0.2.0
type ModuleAnnotation struct {
Subdomain string
Volatility string
Owner string
Layer string
Role string
SuggestedName string
}
ModuleAnnotation carries optional LLM-suggested metadata for a module. Layer holds the raw LLM layer suggestion; whether it is written live vs as a comment is decided in writeModuleStanza based on allowedLayers.
type ModuleDef ¶
type ModuleDef struct {
// Name is a short human-readable identifier (e.g. "extract", "model").
Name string
// Paths contains the glob patterns that own this module's files.
Paths []string
// Public contains globs for exported/public surface files.
Public []string
// Internal contains globs for package-private files.
Internal []string
// Layer is the inferred architectural layer (e.g. "adapter", "core", "cmd").
Layer string
}
ModuleDef is a candidate module discovered from the project structure.
func DiscoverPy ¶
DiscoverPy reads Python packages from root and root/src (src-layout). A Python project is detected by pyproject.toml or setup.py at root. For each top-level package found, sub-packages are returned as individual modules. If a top-level package has no sub-packages it is returned itself.
func DiscoverTS ¶
DiscoverTS reads src/ or lib/ subdirectories if package.json is present at root. Returns discovered module definitions, one per subdirectory.
type ModuleEdge ¶ added in v0.6.0
type ModuleEdge struct {
From string // module Name of the dependent
To string // module Name of the dependency
}
ModuleEdge is a directed dependency edge between two discovered modules. From depends on (imports) To.
type ModuleField ¶ added in v0.2.0
type ModuleField int
ModuleField is the set of module scalar fields that SetModuleFieldsEdit can insert.
const ( FieldSubdomain ModuleField = iota // subdomain: ... FieldVolatility // volatility: ... FieldOwner // owner: ... FieldLayer // layer: ... FieldReviewedAt // reviewed_at: 2026-06-18T... FieldReviewedBy // reviewed_by: ... )
ModuleField enum values in canonical order.
type PathDelta ¶ added in v0.2.0
PathDelta records a module present in both config and discovery whose paths differ.
type SetModuleFieldsEdit ¶ added in v0.2.0
type SetModuleFieldsEdit struct {
Module string
Fields map[ModuleField]string
}
SetModuleFieldsEdit inserts absent scalar fields (subdomain/volatility/layer) into an existing module. All absent fields are coalesced into ONE block insertion, in canonical order subdomain→volatility→layer. Skips Layer if value not in layers:.
type SubdomainDraft ¶ added in v0.3.0
type SubdomainDraft struct {
Module string `yaml:"module"`
Subdomain string `yaml:"subdomain"` // llm draft: core|supporting|generic
Volatility string `yaml:"volatility"` // llm draft: low|medium|high (may be empty)
Rationale string `yaml:"rationale"`
Status string `yaml:"status"` // SubdomainStatusDraft or SubdomainStatusApproved
}
SubdomainDraft is one LLM-suggested subdomain assignment awaiting human review.
type SubdomainDraftFile ¶ added in v0.3.0
type SubdomainDraftFile struct {
Version int `yaml:"version"`
Drafts []SubdomainDraft `yaml:"drafts"`
}
SubdomainDraftFile is the top-level container for .archfit-subdomains.yaml.
func LoadSubdomainDrafts ¶ added in v0.3.0
func LoadSubdomainDrafts(path string) (SubdomainDraftFile, error)
LoadSubdomainDrafts loads the draft file from path. Returns an empty file (version 1, no drafts) when the file is absent.
func MergeSubdomainDrafts ¶ added in v0.3.0
func MergeSubdomainDrafts(existing SubdomainDraftFile, newDrafts []SubdomainDraft) SubdomainDraftFile
MergeSubdomainDrafts merges newDrafts into existing:
- Approved entries are untouchable.
- An existing draft for the same module is replaced by the new draft.
- New modules not in existing are appended.
- Output is sorted by Module for a deterministic file.
type SubdomainPin ¶ added in v0.3.0
type SubdomainPin struct {
Module string
Subdomain string // core|supporting|generic
Volatility string // low|medium|high (may be empty)
ReviewedAt time.Time
ReviewedBy string
}
SubdomainPin is one approved subdomain assignment for a module.
type UpdateModulePathsEdit ¶ added in v0.2.0
UpdateModulePathsEdit replaces the paths: block of an existing module. If the module exists but has no paths:, inserts block-style paths: as first key. REJECTS inline flow-style paths: [...].
type UpdateReport ¶ added in v0.2.0
type UpdateReport struct {
Added []ModuleDef
Removed []ExistingModule
PathDrift []PathDelta
Unclassified []string
StructuralInSync bool
}
UpdateReport is the result of DiffModules.
func DiffModules ¶ added in v0.2.0
func DiffModules(existing []ExistingModule, fresh []ModuleDef) UpdateReport
DiffModules computes the structural difference between the existing config modules and freshly discovered modules. Output slices are sorted by Name for determinism.
- Added: modules in fresh (by Name) not in existing.
- Removed: modules in existing (by Name) not in fresh.
- PathDrift: modules present in both whose paths differ as normalized sets. ConfigPaths and DiscoveredPaths preserve their original ordering.
- StructuralInSync: true when Added, Removed, and PathDrift are all empty.
- Unclassified: non-removed existing modules missing any of subdomain/volatility/layer. Modules in Removed are excluded from Unclassified.
type ValueDraft ¶ added in v0.5.0
type ValueDraft struct {
Module string `yaml:"module"`
Value string `yaml:"value"`
Rationale string `yaml:"rationale"`
Status string `yaml:"status"` // DraftStatusDraft or DraftStatusApproved
// Confidence records how trustworthy the judgment is (high|medium|low).
// Set by the LLM draft path; empty = unset (treated as high for human-approved entries).
Confidence string `yaml:"confidence,omitempty"`
// Provenance records the source of the judgment (human|llm|tool).
// Set to "llm" by the LLM draft path; empty = unset (treated as human).
Provenance string `yaml:"provenance,omitempty"`
}
ValueDraft is one LLM-suggested single-scalar module annotation awaiting human review. Owner and volatility share this shape (module → one value); the containing ValueDraftFile.Field records which module field the value targets. This mirrors SubdomainDraft but for fields that carry exactly one scalar.
type ValueDraftFile ¶ added in v0.5.0
type ValueDraftFile struct {
Version int `yaml:"version"`
Field string `yaml:"field"` // "owner" | "volatility"
Drafts []ValueDraft `yaml:"drafts"`
}
ValueDraftFile is the top-level container for .archfit-owners.yaml / .archfit-volatility.yaml.
func LoadValueDrafts ¶ added in v0.5.0
func LoadValueDrafts(path, field string) (ValueDraftFile, error)
LoadValueDrafts loads the draft file from path. Returns an empty file (version 1, given field, no drafts) when the file is absent.
func MergeValueDrafts ¶ added in v0.5.0
func MergeValueDrafts(existing ValueDraftFile, newDrafts []ValueDraft) ValueDraftFile
MergeValueDrafts merges newDrafts into existing:
- Approved entries are untouchable.
- An existing draft for the same module is replaced by the new draft.
- New modules not in existing are appended.
- Output is sorted by Module for a deterministic file.