Record maintainability and complexity audit findings
This commit is contained in:
283
docs/roadmap/complexity.md
Normal file
283
docs/roadmap/complexity.md
Normal file
@@ -0,0 +1,283 @@
|
||||
# Maintainability And Complexity Audit
|
||||
|
||||
Reviewed revision: `320d0c5f439a059a7081cf7532c9b5d65891f5c7`.
|
||||
Audit date: 2026-10-25.
|
||||
|
||||
## Scope And Method
|
||||
|
||||
This audit examines readability, responsibility boundaries, state handoffs, and
|
||||
interface duplication. It covers the root facade, engine subsystems, document
|
||||
and YAML boundaries, and relevant tests, documentation, and prior refactoring
|
||||
decisions. It does not propose new feature behavior or performance guarantees.
|
||||
|
||||
The codebase-memory graph was refreshed and its function spans, cyclomatic and
|
||||
cognitive complexity estimates, parameter counts, and caller traces were used
|
||||
to select code for inspection. The graph contains 907 non-test functions/methods
|
||||
and 940 test-file functions/methods. Its index excludes examples, documentation,
|
||||
and scripts; tracked-file inventory and direct inspection supplemented it.
|
||||
Standalone `gocyclo`, `gocognit`, and `golangci-lint` were unavailable. No tool
|
||||
installation, benchmarks, or empirical performance testing was needed.
|
||||
|
||||
The tracked production inventory, excluding examples, contains 16 root Go files,
|
||||
97 engine files, one document file, and two YAML adapter files: approximately
|
||||
22,612 physical lines overall. The largest production files are `compose.go`
|
||||
(599 lines), `history.go` (568), `overlay.go` (564), and `discovery.go` (540).
|
||||
These measurements locate responsibilities; they are not refactoring thresholds.
|
||||
|
||||
Representative graph measurements:
|
||||
|
||||
| Function | File | Function span | Cognitive estimate |
|
||||
| --- | --- | ---: | ---: |
|
||||
| `valueOperation.clone` | `internal/engine/clone.go` | 130 | 104 |
|
||||
| `acquireInput` | `internal/engine/acquisition.go` | 202 | 99 |
|
||||
| `valueBuilder.build` | `internal/engine/value.go` | 104 | 93 |
|
||||
| `decodeValue` | `internal/engine/decode.go` | 115 | 85 |
|
||||
| `selectGlobImportCandidates` | `internal/engine/glob.go` | 112 | 73 |
|
||||
| `assembleLayeredInput` | `internal/engine/load_request.go` | 146 | 63 |
|
||||
| `executeLoadRequest` | `internal/engine/load.go` | 198 | 56 |
|
||||
| `mergeOverlayMappingsWithCollectionPolicy` | `internal/engine/overlay.go` | 163 | 46 |
|
||||
|
||||
Spans include comments and blank lines; scores are tool estimates for comparative
|
||||
triage, not standardized quality grades. Source review, rather than a numerical
|
||||
cutoff, determines the findings below.
|
||||
|
||||
## Architectural Assessment
|
||||
|
||||
The [implemented architecture](../internal/overview.md) remains coherent: the
|
||||
root owns the supported public types and explicit conversions; the engine owns
|
||||
loading and frozen inspection; the document package owns the ordered tree; and
|
||||
the YAML adapter isolates the upstream parser. Ordinary and layered loads share
|
||||
one normalized request and execution lifecycle. Imports and inheritance retain
|
||||
their separate scopes and use the common dependency scheduler.
|
||||
|
||||
The recent consolidation improved import ownership and file boundaries, separated
|
||||
inheritance preparation/combination/finalization, shared filesystem facts, and
|
||||
clarified schema and projection responsibilities. The findings concern remaining
|
||||
maintenance opportunities, not a recommendation to repeat that refactor or split
|
||||
the engine into a package per subsystem.
|
||||
|
||||
The existing [correctness](correctness.md) and [efficiency](efficiency.md) audits
|
||||
remain separate owners of their findings. No additional runtime defect was
|
||||
established in this pass. Related risks are referenced rather than duplicated.
|
||||
|
||||
## 1. Remove The Test-Only Eager Acquisition Mode
|
||||
|
||||
Status: open. Priority: medium. Scope: engine acquisition and its test helpers.
|
||||
|
||||
**Relevant code.** `inputAcquisitionRequest.deferAssembly` in
|
||||
[acquisition.go](../../internal/engine/acquisition.go), and the final branch of
|
||||
`acquireImportedWithAccess` in
|
||||
[import_acquisition.go](../../internal/engine/import_acquisition.go), lines
|
||||
206–224. Production construction sites in `executeLoadRequest`
|
||||
([load.go](../../internal/engine/load.go), lines 210–214) and
|
||||
`acquireUnderlayGroupScopes`
|
||||
([load_request.go](../../internal/engine/load_request.go), lines 243–246) both
|
||||
set this flag to true.
|
||||
|
||||
**Complexity.** Caller tracing found no production caller selecting eager
|
||||
composition. The false branch remains exercised by private test entry helpers,
|
||||
including `testImportRequest`, `testAcquireImport`, and `testAcquireInput` in
|
||||
[imports_test.go](../../internal/engine/imports_test.go). Acquisition therefore
|
||||
maintains two return protocols: an acquired scope with a nil composed root, or
|
||||
an already composed document. The eager branch reconstructs `assembledInput`
|
||||
and reenters composition from the acquisition function, while the published
|
||||
loading paths perform that phase later. Tests can consequently exercise a
|
||||
different handoff from the one consumers use.
|
||||
|
||||
**Potential refactoring.** Make acquisition return retained scopes consistently
|
||||
and remove the unused production mode. Tests needing composed values can invoke
|
||||
the real composition phase explicitly through a small test-only convenience
|
||||
helper. Keep acquisition-only tests acquisition-only. Preserve handle closure,
|
||||
pending-item placement reservation, accounting, diagnostics, and meaningful
|
||||
composition coverage. This removes a private alternative path, not support for
|
||||
any public loading workflow. Do not infer that other nil-state or directive
|
||||
contexts are unused without separately tracing their callers.
|
||||
|
||||
## 2. Clarify Acquisition And Load-Coordinator Phase Handoffs
|
||||
|
||||
Status: open. Priority: medium. Scope: engine, across acquisition, version,
|
||||
assembly, and lifecycle files.
|
||||
|
||||
**Relevant code.** `acquireInput` in
|
||||
[acquisition.go](../../internal/engine/acquisition.go), `executeLoadRequest` in
|
||||
[load.go](../../internal/engine/load.go), and `assembleLayeredInput` in
|
||||
[load_request.go](../../internal/engine/load_request.go).
|
||||
|
||||
**Complexity.** `acquireInput` still combines search outcome handling, parsing,
|
||||
disabled-directive checks, three directive/version-processing branches,
|
||||
import-versus-standalone dispatch, placement/accounting, and passive context
|
||||
construction. Its version-processing section repeats source-ID extraction,
|
||||
failure handling, and `mainProcessing` updates, while the layered branch must
|
||||
extract directives separately and restore them after version processing.
|
||||
|
||||
The coordinators also manipulate several intentionally distinct representations:
|
||||
parsed source, local payload, acquired scope, composed root, inherited root,
|
||||
local/protected version paths, and effective version evidence. For example,
|
||||
`executeLoadRequest` includes a substantial ordinary-load resource-context
|
||||
fallback between assembly and inheritance, while `assembleLayeredInput` repeats
|
||||
declaration gathering, tier application, and destination projection for underlays
|
||||
and main. Understanding a source-version or placement change requires tracing
|
||||
both those mechanics and the overall phase order through long functions.
|
||||
|
||||
**Potential refactoring.** Extract cohesive operations for processing one parsed
|
||||
input's directives/version evidence and for placing/registering a standalone
|
||||
contribution. Reuse the existing processing result and acquisition state rather
|
||||
than inventing another context hierarchy. Isolate the substantial context and
|
||||
structural-expansion operations from the top-level lifecycle, and consider one
|
||||
helper for the repeated tier application/projection handoff. Keep phase order,
|
||||
error exits, and source acquisition order readable in the coordinators.
|
||||
|
||||
Extraction is useful only when it gives one operation a clear owner and result;
|
||||
moving blocks into helpers that still share the same mutable surrounding locals
|
||||
would not solve the problem. Preserve the deliberate ordinary/layered overlay
|
||||
differences, default versus enabled version-check timing, warning accumulation,
|
||||
exactly-once callbacks, and load-wide versus tier-local state. This is separate
|
||||
from finding 1: removing the eager branch does not simplify these active paths.
|
||||
|
||||
## 3. Separate Collection-Policy Preparation From Merge Evidence Application
|
||||
|
||||
Status: open. Priority: medium. Scope: engine precedence and inheritance.
|
||||
|
||||
**Relevant code.** `mergeOverlayMappingsWithCollectionPolicy` and
|
||||
`applyOverlaySequenceEvidence` in
|
||||
[overlay.go](../../internal/engine/overlay.go);
|
||||
`resolveStrictCollectionPolicies` in
|
||||
[compose.go](../../internal/engine/compose.go);
|
||||
`combineInheritanceTemplate` in
|
||||
[inheritance_combine.go](../../internal/engine/inheritance_combine.go); and the
|
||||
policy/origin helpers in
|
||||
[inheritance_collection.go](../../internal/engine/inheritance_collection.go).
|
||||
|
||||
**Complexity.** The overlay coordinator prepares claims and declaration groups,
|
||||
discovers applicable destinations, resolves operations, configures recursive
|
||||
merge callbacks, accumulates diagnostics/history, reconciles declaration-only
|
||||
policies after mutation, and sorts the output. Its callbacks close over several
|
||||
maps and mutate the assembly while reporting failures through an outer slice.
|
||||
`applyOverlaySequenceEvidence` then mixes policy retirement, displaced origins,
|
||||
replacement records, copied incoming origins, and record-policy reconstruction.
|
||||
|
||||
There is also concrete duplicated bookkeeping: overlay and inheritance callbacks
|
||||
both translate a sequence result into replace-versus-mapped history descriptors;
|
||||
overlay evidence and `applyInheritanceSequencePolicy` both rebuild record policy
|
||||
order from lower/higher item projections. The shared `combineSequence` is already
|
||||
the correct value-combination owner, but maintainers must separately coordinate
|
||||
these sidecar translations when its result representation changes.
|
||||
|
||||
**Potential refactoring.** Give overlay preparation, value/evidence application,
|
||||
and declaration-only finalization explicit local boundaries. Let a small
|
||||
operation owner or result carry the diagnostic and evidence collections currently
|
||||
captured by the large callbacks. Share the straightforward history-descriptor
|
||||
construction; evaluate a common projected-record selection helper while retaining
|
||||
named precedence and inheritance ownership rules.
|
||||
|
||||
Do not merge the distinct origin semantics or hide mode-lifetime differences
|
||||
behind a generic strategy framework. Keep `combineSequence` and the recursive
|
||||
mapping merge shared, and consume their result rather than recomputing values.
|
||||
Coordinate this work with collection-policy findings 1–2 in the
|
||||
[efficiency audit](efficiency.md) so clearer preparation does not preserve or
|
||||
introduce repeated whole-table copying/scanning. Preserve replacement ordering,
|
||||
pending declarations, new versus retained record owners, and stable history.
|
||||
|
||||
## 4. Extract Patterned Glob Entry Preparation From Traversal Orchestration
|
||||
|
||||
Status: open. Priority: medium. Scope: engine import discovery.
|
||||
|
||||
**Relevant code.** `selectGlobImportCandidates` in
|
||||
[glob.go](../../internal/engine/glob.go), especially its patterned-entry branch.
|
||||
The corresponding directory-search entry operation already has a named owner,
|
||||
`prepareImportDirectoryEntry` in
|
||||
[import_selection.go](../../internal/engine/import_selection.go).
|
||||
|
||||
**Complexity.** The glob function nests pattern-segment traversal, parent
|
||||
candidates, and directory entries. Its innermost branch handles matching,
|
||||
hidden-entry policy, lexical and access paths, containment, link inspection,
|
||||
follow behavior, intermediate-directory eligibility, native/host identity
|
||||
differences, canonicalization, labels, and candidate creation. Set-union and
|
||||
component-advancement mechanics are interleaved with those admission decisions,
|
||||
making the important lexical-versus-canonical distinction difficult to follow.
|
||||
|
||||
**Potential refactoring.** Extract a glob-specific entry preparation operation
|
||||
returning an admitted candidate, an ordinary skip, or a diagnostic. Leave pattern
|
||||
component advancement, literal segments, per-component union/sorting, and final
|
||||
exclusion/requiredness visible in the selector. Reuse low-level filesystem facts
|
||||
where semantics coincide; directory and glob admission need not become one
|
||||
general visitor interface. Preserve inspection/error order, entry accounting,
|
||||
native namespace spelling, and selected-file validation. This is a readability
|
||||
change, not a proposal to change the selected discovery algorithm or add caching.
|
||||
|
||||
## 5. Simplify Redundant Facade-To-Engine Input Transport
|
||||
|
||||
Status: open. Priority: low. Scope: root facade and engine, across packages.
|
||||
|
||||
**Relevant code.** Root `toEngineImportDefaults` in
|
||||
[conversion.go](../../conversion.go), `toEngineOptions` in
|
||||
[lifecycle.go](../../lifecycle.go), and `toEngineLayeredOptions` in
|
||||
[layered.go](../../layered.go); engine transport/private defaults and option
|
||||
decorators in [import_spec.go](../../internal/engine/import_spec.go), lines
|
||||
46–87; and placement transport helpers in
|
||||
[destination.go](../../internal/engine/destination.go), lines 23–39.
|
||||
|
||||
**Complexity.** Import defaults have a root-owned public representation, an
|
||||
engine facade-transport representation, and a second engine-private representation
|
||||
with the same five fields. Conversion constructs the transport, an option
|
||||
decorator converts it to private defaults, and load normalization snapshots it
|
||||
again. Placement similarly requires constructing an engine record and then
|
||||
passing it through a separate setter-style helper. Even a simple control change
|
||||
has multiple mechanical mapping sites across the package boundary.
|
||||
|
||||
Caller and text-reference checks also found no uses of the standalone
|
||||
`PlacementModeFromFacade` and `PlacementModeForFacade` functions beyond their
|
||||
declarations. The similarly named `SourceInfoPlacementModeForFacade` is used by
|
||||
root source-record conversion and is not dead code. The unused pair adds a
|
||||
second apparent placement conversion route for maintainers to investigate.
|
||||
|
||||
Root type ownership and explicit conversion are deliberate and useful; the
|
||||
opportunity is the extra engine-internal representation/construction protocol,
|
||||
not eliminating the facade. The public wrappers do not need to change.
|
||||
|
||||
**Potential refactoring.** Remove the two unused enum bridges. Then consider one
|
||||
engine representation of import-default input values and a straightforward
|
||||
construction surface on the existing engine option/input records. Review inert
|
||||
placement decorators as part of the same bounded cleanup. Keep helpers that
|
||||
actually encode domain rules or ownership conversion, and keep
|
||||
definition/registration compilation separate from transport.
|
||||
Avoid adding another universal request DTO, code generator, reflective mapper,
|
||||
or adapter framework to remove a few mechanical functions.
|
||||
|
||||
Preserve root-owned named types and signatures, invalid-enum validation,
|
||||
nil-versus-empty patterns, pointer/slice snapshots, and the two public loading
|
||||
entry points. Exported declarations inside Go's `internal` boundary need not
|
||||
become public root aliases or bridge methods. Pursue this low-priority cleanup
|
||||
only if it reduces total concepts and mapping sites, rather than relocating them.
|
||||
|
||||
## Areas To Retain And Review Boundaries
|
||||
|
||||
- The clone traversal was explicitly reviewed and retained in the completed
|
||||
consolidation record at `34cbc0d:docs/roadmap/consolidation.md`. Its high score
|
||||
is not new evidence for reopening that work. `valueBuilder.build`, typed
|
||||
decoding, and the YAML translator also contain substantial but recognizable
|
||||
type dispatch; no repository-wide visitor framework is recommended.
|
||||
- The cohesive engine package and explicit root record conversions follow
|
||||
[ADR 0006](../adr/0006-public-facade.md). Function/file counts alone do not
|
||||
justify package extraction, public API consolidation, or generated conversions.
|
||||
- The shared scheduler, mapping/sequence primitives, recently separated
|
||||
inheritance phases, schema field assembly, and resolved filesystem facts remain
|
||||
useful common owners. Preserve those improvements.
|
||||
- `history.go` and the larger integration-test files have several substantial
|
||||
routines, but file size alone did not establish another prioritized refactor.
|
||||
The deferred replay, copy-handoff, caching, and contributor-index experiments
|
||||
remain in [future work](future.md#3-performance-experiments).
|
||||
|
||||
These are opportunities for further consideration, not a staged implementation
|
||||
plan or new release blockers. Favor the concrete unused-mode removal and active
|
||||
acquisition/collection boundaries before lower-value transport cleanup. A later
|
||||
implementation should preserve the established contracts and relevant behavioral
|
||||
coverage; complexity scores, helper counts, and private call sequences should
|
||||
not become test thresholds or repository guarantees.
|
||||
|
||||
## Validation
|
||||
|
||||
This audit changes only this findings document. No production code, tests,
|
||||
dependencies, policies, or public contracts are changed. Validation consists of
|
||||
the existing local documentation-link test and `git diff --check`; runtime and
|
||||
performance measurements are not part of this review.
|
||||
Reference in New Issue
Block a user