MeridiansMeridians

Static-analysis maintenance

Source path: knowledge-base/knowledge/operations/knowledge-management/04-static-analysis-maintenance.md

# Static-analysis maintenance

Static analysis is a set of **review instruments**, not a quality score or an automatic refactoring backlog. Its job is to make change risk, architectural drift, and comprehensibility visible early enough for a maintainer to inspect the real contract.

## Cadence and evidence

Run `npm run gen:quality-worklog` before structural work, during a weekly maintenance pass, and before a release when the worktree is stable. Use the focused generators when a signal needs fresh detail:

- `npm run gen:boundaries` for runtime direction debt;
- `npm run gen:hotspots` for history-weighted pressure;
- `SURFACE.md` for exports unused outside their declaring module;
- `DUPLICATION.md` for exact per-file clone budgets and largest clone pairs;
- `CONTRACTS.md` for registered actions, operations, queries, and controls without behavioural tests;
- `npm run static-insights` for local graph and type-risk charts;
- `npm run knowledge:check` after maintained knowledge changes.

Do not start a refactor from one rank alone. Promote an item only after two independent signals and the implementation agree. Record the compact hypothesis in the handoff: **constraint, evidence, smallest whole move, proof, remaining risk**.

## What each signal is for

| Signal | It reveals | First confirmation |
| --- | --- | --- |
| Boundary direction / cycles | blurred ownership and expensive refactors | importing module, imported contract, direct callers |
| Fan-in / fan-out | critical contracts or modules that know too much | caller groups and responsibility split |
| Change coupling / hotspots | hidden dependencies and risky change pressure | recent diffs, defect history, focused tests |
| Complexity / large-module tail | a missing seam or decision flow too hard to inspect | the largest branch, its effects, and observable behaviour |
| Escape hatches / unchecked parse | unproven data narrowing | malformed-input path and boundary validator |
| Knowledge drift | a misleading route into the system | owning hub, source implementation, named claim |

## Ratchets, not scorecards

Keep runtime boundary violations and dependency cycles non-increasing. Treat a new suppression, unsafe parse, or public export as a review prompt with an explicit reason and test. Track the top risks over time, but never fail work just because a count changes: an intentional validation assertion or a necessary adapter can be correct.

The `uncheckedJson` signal counts a raw `JSON.parse` only while its inferred `any` can escape. A parse assigned to an explicit `unknown` variable or returned through an `unknown` / `Promise<unknown>` contract is already contained for downstream narrowing and is deliberately excluded.

A successful move improves the underlying contract—clearer ownership, a pure seam, immutable public data flow, a durable guard, or truthful documentation—and proves it with the smallest relevant test. Functional design is a lens for finding these gains: separate deterministic decisions from I/O, inject time and randomness, return typed data, and keep caller-owned inputs unchanged. It is not a demand for `reduce`, point-free syntax, recursive cloning, or an abstraction for every repeated expression; private local mutation is fine when it cannot escape and is the clearest implementation.

Do not hide a boundary behind a re-export, lower a threshold, split a file mechanically, add navigation solely to make a report greener, or compress an explicit decision until its policy becomes harder to see.

## Closing a maintenance move

1. Verify the chosen signal against current code and its owner.
2. Make one coherent change, including its test and maintained documentation when behaviour or ownership moves.
3. Run focused checks, then regenerate the affected report.
4. Report the before/after evidence and any signal deliberately left unchanged.

After a sustained cleanup pass, compare the next candidate with the last completed batch. Stop when it
cannot name a responsibility, effect, invalid state, repeated policy, or failure mode it will remove. At
that point lower line count or more uniform syntax is not corroborating evidence; resume maintenance when
feature work, an incident, or a fresh signal exposes a concrete seam.

For the broader selection discipline, see [Hill-climbing opportunities](03-hill-climbing-opportunities.md). The generated [quality worklog](../../../generated/QUALITY_WORKLOG.md) is the entry point; it is never the source of truth by itself.
Open on GitHub

Raw Markdown source