Context
Part of #4737 (parent epic — deterministic tier). Depends on the
complexity-delta and duplication-delta sub-issues (sibling sub-issues in this epic); reuses
codecov/patch's existing coverage numbers and (optionally) slop.ts's existing test-evidence signal.
The problem
This epic's deterministic tier is currently four separate signals (complexity delta, duplication delta,
coverage delta, test-evidence delta) with no combined read. src/signals/slop.ts already establishes the
house pattern for exactly this kind of aggregation — a named weighted-findings model plus a band — and
this sub-issue is that same pattern applied to the positive axis.
Fix
Add src/signals/improvement.ts (mirrors slop.ts's shape deliberately, for a maintainer who already
knows how to read one to immediately understand the other):
StructuralImprovementInput: the REES findings from the complexity-delta and duplication-delta
analyzers for this PR, plus a coverage-delta figure (reuse Codecov's own patch-coverage numbers where
available — this repo already computes a real, precise before/after coverage percentage per PR; don't
recompute it), plus a test-evidence signal (reuse or adapt slop.ts's existing
missingTestEvidence/test-file detection rather than re-deriving it).
- A weighted-findings formula,
buildStructuralImprovementAssessment, output as
{ improvementScore: number; band: ImprovementBand; findings: SignalFinding[] } — deliberately
parallel to SlopAssessment's shape.
- Bands mirroring
slopBandFor's clean/low/elevated/high pattern, renamed for the positive axis (e.g.
none/minor/moderate/significant — exact naming is the implementer's call, but must be an ordinal
band, not a raw percentage presented as fact — see the epic's design constraint 1).
Requirements
- This is deterministic-only, no LLM — matches the tier split the epic requires. The LLM-tier
contribution (sibling sub-issue) is combined at the surfacing layer (sibling sub-issue), not blended
into this score.
- Every finding needs a plain-language reason string (mirrors
SignalFinding shape already used by
slop.ts and buildPublicReadinessScore) so the eventual panel row can explain itself without needing
new sanitizer-unsafe vocabulary.
- Zero applicable findings (e.g. a docs-only PR with nothing for complexity/duplication analyzers to
measure) must degrade to an explicit "not enough signal" band, not a fabricated none/neutral score —
don't let an analyzer's silence get misread as "no improvement."
Acceptance criteria
Context
Part of #4737 (parent epic — deterministic tier). Depends on the
complexity-delta and duplication-delta sub-issues (sibling sub-issues in this epic); reuses
codecov/patch's existing coverage numbers and (optionally)slop.ts's existing test-evidence signal.The problem
This epic's deterministic tier is currently four separate signals (complexity delta, duplication delta,
coverage delta, test-evidence delta) with no combined read.
src/signals/slop.tsalready establishes thehouse pattern for exactly this kind of aggregation — a named weighted-findings model plus a band — and
this sub-issue is that same pattern applied to the positive axis.
Fix
Add
src/signals/improvement.ts(mirrorsslop.ts's shape deliberately, for a maintainer who alreadyknows how to read one to immediately understand the other):
StructuralImprovementInput: the REES findings from the complexity-delta and duplication-deltaanalyzers for this PR, plus a coverage-delta figure (reuse Codecov's own patch-coverage numbers where
available — this repo already computes a real, precise before/after coverage percentage per PR; don't
recompute it), plus a test-evidence signal (reuse or adapt
slop.ts's existingmissingTestEvidence/test-file detection rather than re-deriving it).buildStructuralImprovementAssessment, output as{ improvementScore: number; band: ImprovementBand; findings: SignalFinding[] }— deliberatelyparallel to
SlopAssessment's shape.slopBandFor's clean/low/elevated/high pattern, renamed for the positive axis (e.g.none/minor/moderate/significant— exact naming is the implementer's call, but must be an ordinalband, not a raw percentage presented as fact — see the epic's design constraint 1).
Requirements
contribution (sibling sub-issue) is combined at the surfacing layer (sibling sub-issue), not blended
into this score.
SignalFindingshape already used byslop.tsandbuildPublicReadinessScore) so the eventual panel row can explain itself without needingnew sanitizer-unsafe vocabulary.
measure) must degrade to an explicit "not enough signal" band, not a fabricated
none/neutral score —don't let an analyzer's silence get misread as "no improvement."
Acceptance criteria
buildStructuralImprovementAssessmentcombines all four deterministic inputs into one bandedresult with structured findings.
(tested).
slop.ts's existing invariant-test style (correctoutput per band, no cross-band leakage).
wired into any gate/blocker path (epic design constraint 2).