Skip to content

0.9.13 — The baseline finds its home

Choose a tag to compare

@nrodear nrodear released this 08 Aug 00:33
· 96 commits to main since this release

Release 0.9.13 — The baseline finds its home

Released: 2026-08-08
🇩🇪 Deutsche Version

A big release. Baselines get a canonical home and a CI-safe switch, a
new corpus-proven rule catches a silent Delphi trap, the standalone EXE
catches up with the plugin on triage workflow — and its dark mode looks
like an editor, not a cave. Plus one revival story: two DFM rules that
had silently never fired in production do now.


Baselines: the .sca folder and --baseline-scan

The baseline JSON now has a standard location next to what you scan:
<dir>\.sca\<ProjectName>.baseline.json for a project or group (a
project falls back to its group's .sca one level up), or
<dir>\.sca\sca.baseline.json for a plain path scan.

Everything resolves it the same way — explicit --baseline wins, then
[Baseline] File= from analyser.ini, then the .sca default:

  • CLI: --baseline-scan y filters against the resolved baseline and
    fails hard (exit 99) when none exists, listing every probed path —
    a typo in CI must not silently report "everything is new". A missing
    explicit --baseline <file> is a hard error now too (previously a
    silent no-op). --write-baseline auto writes to the .sca default
    and creates the folder.
  • Standalone EXE and IDE plugin: the Show only new findings
    (baseline)
    toggle lives in both hamburger menus now and resolves the
    .sca location on its own — no hand-edited INI needed. Enabling it
    with no baseline anywhere offers to write one on the spot; Write
    baseline
    pre-fills the .sca target. The plugin resolves via the
    IDE's active project or group and its silent mode (the editor
    markers while you type) honours the baseline too.
  • Opt-in [Baseline] PathInFingerprint=1: fingerprints can include
    the normalized relative path, so same-named files in different folders
    stop sharing accepted findings. Off by default — it costs one baseline
    rewrite and path stability; a pathFingerprint marker in the JSON
    turns a mode mismatch into a warning instead of a silent non-match.

Baseline files remain interchangeable between CLI, EXE, plugin and HTML
report — a baseline written by the plugin filters a CLI scan.

New rule: SCA196 ManagedResultUninit

For managed return types (strings, dynamic arrays, Variant,
interfaces) Result is a hidden var parameter that aliases the caller's
target variable including its old content — and the compiler's
W1035 stays silent for exactly these types. A collector like

function Collect: TArray<string>;
begin
  Result := Result + [x];   // appends to the CALLER's old array
end;

works in the first call and duplicates data ever after. SCA196 reports
the first Result read before the first write. Three corpus measurement
rounds (2171 → 105 → 51 findings after two false-positive hunts), then
every one of the 49 unique sites verified by hand: 100 % precision,
real bugs in well-known projects among them. Ships at medium confidence
— visible in the default profile — with a localized before/after fix
hint (en/de/fr).

Two DFM rules were dead — now they live, hardened

A systematic always-zero audit found that SCA040 DfmCrossFormCoupling
and SCA042 DfmGodHandler ran before the event-binding repository
was populated: zero findings on every real scan since their
introduction. Both moved behind the binding build-up — and then got
hardened on the corpus: SCA040 no longer counts locals/parameters/
fields that shadow a form name (low confidence until the next precision
round); SCA042 stays silent when a handler's bindings all share one
component class and one event type — uniform parameterised bundling is
a pattern, not a god handler (−71 % on the corpus). In the same wave:
SCA032 no longer crashes on duplicate component names,
SCA034/SCA035 skip DataModule roots (false-positive swarm),
SCA091 and 15 further detectors blank string literals before
matching, SCA110–112 stop swallowing the statement after a
single-statement loop, and SCA101 finally sees the most common
if-formatting of all: the branch on the next line.

The standalone EXE catches up

Everything the plugin could do for triage, the EXE does now: keyboard
triage (Enter opens, Ctrl+Alt+S suppresses, Ctrl+Alt+F quick-fixes)
through a byte-faithful line editor that preserves encoding, line
endings and a missing trailing newline exactly — verified by a
round-trip probe that refuses to write rather than damage a file.
Stat tiles filter the grid. Column headers sort honestly. A right-click
menu mirrors the shortcuts. The window remembers size, position and
column widths. Findings can open in the editor of your choice
([Editor] in analyser.ini: VS Code, Notepad++, Sublime, …) or in
the Delphi IDE. Crash diagnostics report module-relative,
ASLR-surviving addresses. And a long tail of fixes — from the arrow key
that overwrote the clipboard thirty times a second to the sort arrow
that sat on the wrong column.

Dark mode: "SCA VSDark"

The EXE follows the Windows app theme (or a fixed choice under
Appearance). New in this release: the embedded dark style is SCA
VSDark
— the VS Code Dark Modern palette (chrome #181818, content
#1F1F1F, inputs #313131, text #CCCCCC) instead of the stock
Windows10 Dark, which literally paints clBlack everywhere. The style
is generated reproducibly from the Redist original by
tools/make_scadark_style.py.


Full details in the CHANGELOG.