12 KiB
Complexity And Maintainability Audit
Reviewed 2026-11-04 against commit 5adc1c1.
Method And Architectural Assessment
Used the local codebase-memory graph's cyclomatic/cognitive complexity, function-length, and call-relationship tools to locate candidates. Reviewed functions and methods, including test hotspots, rather than relying on function-only rankings. Inspected implementation, callers, owning interfaces, and current architecture/internal documentation before selecting findings. Metrics are analyzer-specific indicators, not correctness proofs, acceptance thresholds, or requirements to split every large switch.
PromptKit's overall boundaries remain useful: a public facade adapts values and errors; configuration interprets ConfigKit's final handoff and captures runtime indexes; the runner coordinates preparation and execution; generation owns attempts/retries; capacity owns admission and permits; transport and schema adapters own external protocols. No repository-wide architectural rewrite or new public abstraction is warranted by this review.
Representative hotspot metrics from the current graph:
| Function | Cyclomatic | Cognitive |
|---|---|---|
requirementWalker.visit |
50 | 137 |
validateEffective |
39 | 132 |
requirementWalker.evaluateCommand |
26 | 103 |
providerValueForMapping |
33 | 84 |
jsonvalue.copyValue |
29 | 66 |
loaded.buildExecutionProfiles |
27 | 58 |
loaded.materializePrompt |
30 | 52 |
Coordinator.generate |
24 | 49 |
The findings below are behavior-preserving refactoring opportunities, not confirmed bugs or automatic release blockers. They cover both package-local complexity and interactions between packages. No production code, tests, or dependencies were changed, and no empirical testing or benchmarks were needed.
1. Consolidate Schema Compilation And Express The Runner's Actual Interface
Code: validator interfaces, schema implementations, runner preparation, and engine assembly.
Complexity: The validator maintains direct validation and prepared
validation, with separate filesystem and fs.FS compilation paths. Compiler
construction, resource registration, error wrapping, and cancellation checks
are repeated across direct schema-validation methods and PrepareValidation.
The package's constructors return Validator, although the runner actually
requires ValidationPreparer and discovers it through a runtime type assertion.
An implementation satisfying the declared constructor dependency can therefore
still be unsuitable for the execution path.
Opportunity: Make the runner's preparation dependency explicit in its internal field/constructor types, updating assembly and focused test collaborators together. Retain the direct validation interface where callers actually need it. Consolidate compilation behind one internal operation, with small source-specific loading/URL/loader adapters; direct and prepared callers can reuse that operation rather than separately implementing registration and compilation. No public validator API or generic source framework is needed.
Preserve: Direct validation currently rejects malformed JSON before trying
to compile its schema; simply implementing direct Validate as eager
PrepareValidation followed by plan validation would change that error/I/O
ordering. Keep that short-circuit, operation-local compiled resources, prepared
freezing, schema dialect and containment rules, synchronous cancellation
precedence, and the runner's existing nil-validator behavior where used.
Coordinate schema representation changes with correctness-audit finding 2,
without treating this refactor alone as its fix.
2. Decompose Configuration Validation And Resource Materialization
Code: validateEffective, materializePrompt, buildExecutionProfiles, and resolution callbacks.
Complexity: validateEffective combines namespace checks, reference indexes,
backend settings, capacity arithmetic, smoke metadata, profile bounds, and prompt
references in one nested traversal. Prompt materialization then combines input
validation, presence projection, content-file I/O, message validation, template
compilation, output-contract construction, hashing, and inspection assembly.
Target assembly is another long presence-state decision chain. Reviewing a
single field change requires following several distinct responsibilities inside
large functions.
Opportunity: Keep the top-level traversal/index preparation visible, but delegate coherent record-level work to backend, profile, and prompt helpers with explicit record/path/index arguments. Isolate prompt input projection, message materialization/compilation, and output-contract construction into small functions returning the values the caller needs. Keep target presence interpretation in one identifiable helper rather than distributing it between new callers. Organize files by those responsibilities only where that helps navigation; moving unchanged code between files is not itself the improvement.
Preserve: Validate only final ConfigKit-provided values. Keep recorded normalization, field presence/null distinctions, exact references, error identities, source-relative resource contexts, lazy metadata capture, and construction-time template/hash capture. Materialization legitimately combines validation with resource access; this finding does not require moving every check into a new validation pass or aggregating formerly fail-fast errors. Avoid a reflection-driven field schema that obscures the domain rules.
3. Untangle Requirement Traversal, Expression Evaluation, And Evidence
Code: requirement walker, syntax dispatch, condition evaluation, and command traversal.
Complexity: The approximately thousand-line file contains mutually recursive
syntax walking and partial expression evaluation, branch reachability, caller
scope tracking, template-call handling, evidence promotion, issue construction,
and result sorting. if and with repeat branch orchestration. input, index,
root variables, and skipped-path behavior appear in both evaluation and
conservative traversal. Correctness depends on the interaction of return-value
flags and mutable walker state such as rootKnown, dependencies, and the
unknown-effect flags, not just the local switch case.
Opportunity: Separate the existing roles into small internal units: syntax
recognition/evaluation, branch/scope traversal, and evidence/result accumulation.
Factor shared if/with orchestration while making their different body-dot
rules explicit. Reuse recognition of supported command shapes instead of
duplicating it between evaluative and inventory-only paths. Make existing
template scope entry/exit state handling explicit. Keep a small enum/value model
rather than adding a general expression interpreter or pluggable AST framework.
Preserve: The deliberately conservative recognition scope, skipped-path
inventory, optional index behavior, named-template limitations, incomplete
results, and cancellation semantics. Traversal and evaluation are not
interchangeable: inactive paths must retain recognizable names without
evaluating caller-derived names. Any shared helper must express that distinction.
The evidence-union efficiency finding in audit 02 is related
but separate; a mechanical file split would not fix it.
4. Clarify Ownership And Policies Across The JSON Value Walkers
Code: source mapping conversion, bounded JSON copying, and public-value copying.
Complexity: Three recursive reflection-based paths independently handle
interfaces/pointers, maps, sequences, scalars, and nil values. Each adds its own
policy: source conversion translates into ConfigKit-compatible containers and
defers unsupported-value errors; jsonvalue validates and bounds owned copies;
facade copying detaches already-valid values while preserving their types.
Similar-looking switches conceal different assumptions and failure behavior.
The numeric conversion defect in correctness-audit finding 1 demonstrates a
concrete risk at one of these boundaries, but is not a new finding here.
Opportunity: First make the three responsibilities explicit at their call boundaries. Isolate source-number encoding from structural traversal, and identify reusable scalar/indirection/container-copy primitives only where their semantics truly match. Prefer removing a redundant traversal path or reusing an existing trusted-value copy operation over maintaining another policy-rich reflection switch. Keep ConfigKit-specific mapping encoding in its adapter; do not teach the source-neutral domain about ConfigKit.
Preserve: Supported concrete types, nil behavior, cycle/depth/work handling,
caller ownership, and deferred source errors. In particular, passing source
builders through rejecting CopyMap would introduce validation before the
ConfigKit handoff and is not an acceptable consolidation. Nor should an
infallible facade projection acquire new rejection behavior merely to reuse a
validator. A universal callback-configured reflection framework could increase
complexity; retain separate small adapters where their policies differ.
5. Extract Attempt Accounting From Generation Control Flow
Code: Coordinator.generate, generateInjected, execute, and diagnostic evidence consumers.
Complexity: The coordinator interleaves permit acquisition, dispatch,
cancellation, retry decisions, observer events, diagnostic evidence, and
presence-aware usage accumulation. The built-in and injected paths repeat
generation-number setup, evidence finishing, attempt projection, and usage
projection. The injected path also repeats its non-dispatched cancellation
reporting. execute returns five parallel values, increasing the amount of
state the caller must keep aligned while constructing two reporting forms.
Opportunity: Return one small internal attempt-result value containing outcome and timing/dispatch facts, and extract common projection/accounting operations where evidence is genuinely shared. Keep the retry loop primarily about eligibility, budget, waits, and terminal outcomes. Keep injected and built-in dispatch strategies explicit rather than manufacturing HTTP facts for injected clients or introducing an extensible retry framework.
Preserve: Release active permits before callbacks/backoff, one-shot injected dispatch, frozen built-in requests, usage-presence distinctions, private diagnostic evidence, ordinary observer boundaries, and retention of decoded facts before cancellation discards ordinary results. The HTTP adapter should continue owning transport facts; accounting extraction must not push provider protocol knowledge into the runner or observation package.
Prioritization And Non-Findings
Start with the schema interface/compilation consolidation and configuration helpers: their responsibilities provide comparatively clear refactoring seams. The walker and generation coordinator need narrower, behavior-preserving units because their state transitions are more subtle. Coordinate source conversion cleanup with the independently required number-preservation fix.
High scores alone did not justify findings for explicit public error-category switches, presence-aware source-field encoding, regular-file/schema read loops, or table-driven tests. Those branches often directly express selected contracts. Large facade files also include substantial GoDoc and straightforward value projection, which is not evidence that public/internal separation has failed. Keep useful test scenarios; do not rewrite tests solely to reduce their metrics.
No additional ordinary correctness defect was established in this pass. Audit 01 and audit 02 retain their own findings. No implementation changes or additional consumer guarantees are implied by this refactoring catalog.