Skip to content

Releases: ddsha441981/wiredoctor

v1.1.4 — Honest media

Choose a tag to compare

@ddsha441981 ddsha441981 released this 24 Aug 20:01
f122dbb

The README hero and every screenshot in the report tour were captured on 0.7.1 — four releases of UI ago. The front door was showing a product that no longer existed. This release recaptures all of it from a real 1.1.4 run, and recapturing it turned up two genuine bugs, both fixed here.

No API, schema, or configuration changes. Drop-in upgrade from 1.1.x.

Fixed

The startup-time trend chart was empty on diff runs. trendHistory was only put on the report inside the baseline-write=true branch, so the run you actually do day to day — diff mode, gates armed — rendered "Need at least 2 baseline writes" even with a full history committed in your baseline. The history is now handed to the report in diff mode too. The current run is deliberately not appended: it is not a baseline entry, and putting an unrecorded point on a committed trend would be a lie the chart cannot take back.

Every generated report was stamped dev. The header chip reads its version from the jar manifest, and the build never wrote an Implementation-Version into it — so every report anyone has ever generated said dev instead of the release that produced it. Fixed in the build, for everyone, not just for the screenshots.

Changed

All report media recaptured from a real 1.1.4 run. A start.spring.io app on Boot 4.1.x — 429 beans, 436 wiring edges — carrying a genuine setter-injected dependency cycle, a slow @PostConstruct bean, an untouched exporter, first-touch ghost tracking enabled, and three baseline writes behind the trend chart. Seven screenshots plus three GIFs: the full tour, a graph drill-down, and the timing charts.

The report tour is rewritten against that run. Every number, bean name and verdict in the prose now comes from the report the screenshots show, and the "captured on 0.7.1" disclaimer is gone.

sample/v1.1.4/ holds the complete matching set — report, JSON, baseline, diff, ghost report and gate status — and is what the live open this report links point at. The 0.10.0 report stays in sample/test2/ for comparison.

Added

tools/capture-media.js drives a real generated report in a headless browser and writes exactly the files the docs embed — so the media cannot quietly drift from what the report renders again.

Install

<dependency>
    <groupId>io.github.ddsha441981</groupId>
    <artifactId>wiredoctor-autoconfigure</artifactId>
    <version>1.1.4</version>
</dependency>

Note: 1.1.4 is not on Maven Central yet — this is the tagged GitHub release. Until it is published, 1.1.0 is the version that resolves.

Tests: 261 in wiredoctor-autoconfigure + 11 in wiredoctor-actuator, green across Boot 2.7 / 3.3 / 3.5 / 4.0 on Java 17, 21 and 25.

Full changelog: 1.1.3...v1.1.4

v1.1.0 — Thread Distribution & Startup Time Trend

Choose a tag to compare

@ddsha441981 ddsha441981 released this 23 Aug 05:51
ed56530

Two new diagnostics, one architecture migration that fixes a real bug, and a UI pass on the HTML report. Purely additive — schemaVersion stays 1, no config property renamed, no new dependency.

🧵 Thread Distribution — did anything actually leave main?

spring.beans.instantiate startup steps now carry a threadName tag captured at step-creation time — the only point where the instantiating thread is still on the stack. Reading Thread.currentThread() at analysis time, as the old code did, always returned main.

The report gains a threadDistribution section mapping each thread to its beans plus a per-thread count. The Timing tab renders it as a donut chart and a table ordered by bean count.

"threadDistribution": {
  "perThread": { "main": ["dataSource", "entityManagerFactory"], "app-bg-1": ["warmCacheBean"] },
  "counts": { "main": 2, "app-bg-1": 1 }
}

The honest framing matters here: Spring does not parallelise bean initialisation by default, and no Boot version has. Background init is opt-in per bean and needs both @Bean(bootstrap = Bean.Bootstrap.BACKGROUND) (Framework 6.2+ / Boot 3.4+) and a bootstrapExecutor. Without both, a 600-bean application legitimately reports 100% on main — the card shows a parallel init not active pill rather than implying something is wrong. The one case where this chart really earns its place: you marked a slow bean BACKGROUND and gave it an executor — did it actually move off main, or is it silently still blocking startup?

Validated on Spring Cloud Config Server (616 beans, Boot 4.1): 610 on main, 1 on configserver-bg-1 — the single @Bean(bootstrap = BACKGROUND).

📈 Startup Time Trend — catch creep before the gate trips

Every run with wiredoctor.baseline-write=true appends {timestamp, totalStartupMs, slowBeanCount} to trendHistory[] in wiredoctor-baseline.json, capped by wiredoctor.trend-history-size (default 30, 0 = unlimited). The Timing tab renders a sparkline, so a +50ms/week drift becomes visible long before the startup-time gate trips on a single bad run.

Worth knowing: the sparkline appears only in reports from a baseline-write=true run, and only from the second write onward — trendHistory[] lives in the baseline file, not in the per-run report. A nightly baseline-refresh job is the natural place to look.

📊 Report UI

Still plain HTML/CSS/JS in one self-contained file — no libraries added.

  • Overview charts — a 5-bucket bean instantiation-time histogram (0 / 1–9 / 10–49 / 50–99 / ≥100 ms), a bean-role stacked bar (ROLE_APPLICATION / SUPPORT / INFRASTRUCTURE), and an autoconfiguration-outcome stacked bar (matched / unconditional / notMatched / excluded). Every column carries its exact count, so the slow tail — always the smallest bucket and always the one you care about — never renders as an invisible sliver. Palettes are colour-blind validated against the dark surface, and every series is legend-labelled so identity is never colour-alone.
  • Responsive sidebar — under 860px the sticky nav becomes an off-canvas drawer (hamburger, backdrop, Escape, auto-close on tab select). KPIs, cards, and header chips reflow at 860px/560px instead of overflowing. Motion respects prefers-reduced-motion.
  • Table polish — sticky uppercase headers, zebra rows, tabular-aligned numeric columns, hover row highlight with an accent edge marker, and horizontal scroll confined to the card instead of the page.

🔧 Changed

  • WireDoctorStartupListener (ApplicationListener) → WireDoctorEnvironmentPostProcessor (EnvironmentPostProcessor) + WireDoctorBufferingApplicationStartup (extends BufferingApplicationStartup). The processor now runs before context preparation, so ApplicationStartup is installed at the correct lifecycle phase; the subclass keeps Actuator /actuator/startup type checks intact.
  • beanThreadMap is now Map<String, Set<String>>, so a prototype instantiated on several threads keeps all of them instead of overwriting.

🐛 Fixed

  • Politeness contract restored. The processor only replaces ApplicationStartup.DEFAULT or null. A plain BufferingApplicationStartup is transparently upgraded (same type, extra thread tagging); a foreign implementation is never overwritten — threadDistribution is omitted with a warning and every other analysis still runs.
  • Compat fix: a new test used JsonNode.values(), which only exists on the Jackson shipped with Boot 3.5+/4.x. Now iterates JsonNode directly, which works on Jackson 2.x and 3.x alike.
  • Report layout: fan-in counts no longer wrap one digit per line; two-column rows no longer stretch the shorter card.
  • Docs: five false claims removed from docs/thread-distribution.md (including a non-existent donut hover interaction and invented task-1/task-2 thread names); wiredoctor.trend.history-size corrected to wiredoctor.trend-history-size.

✅ Verification

  • 253 tests green — 242 autoconfigure + 11 actuator, 0 failures. 7 new tests cover trend-history carry-forward and capping, thread tagging, and the EnvironmentPostProcessor politeness paths.
  • Compatibility matrix green across Boot 2.7.18 / 3.3.13 / 3.5.15 / 4.0.1 on Java 17 / 21 / 25 (12 combinations).
  • Report UI checked at 1440px / 430px / 390px on every tab.

📦 Install

<dependency>
    <groupId>io.github.ddsha441981</groupId>
    <artifactId>wiredoctor-spring-boot-starter</artifactId>
    <version>1.1.0</version>
</dependency>

📚 Documentation

Full docs are live at https://ddsha441981.github.io/wiredoctor/ — including the two new v1.1.0 guides, Thread Distribution and Startup Time Trend.

A set of links on the docs site was broken at the moment this release was published and was fixed immediately after in #42: doc-to-doc links pointed at .md, which serves raw Markdown source instead of the rendered page, and the sample-report link 404'd because sample/ lives at the repo root while Pages publishes only docs/. The start.spring.io sample report is now published and browsable: open it live.

Full changelog: v1.0.0...v1.1.0

v1.0.0 API Freeze & Certification

Choose a tag to compare

@ddsha441981 ddsha441981 released this 07 Aug 23:56

The promises become contracts. From this release, wiredoctor.* config property names, report JSON schema, and performance budget are frozen — patch/minor releases in 1.x carry no breaking changes.

Changes

  • 📌 schemaVersion: 1 as first field in every wiredoctor-report.json (frozen)

  • 🔒 CycleDetector + WireDoctorHtmlReporter sealed final

  • ⚡ AOT/GraalVM native graceful skip via NativeDetector.inNativeImage()

  • ⏱️ Performance budget test — 1k beans < 30s, asserts schemaVersion: 1

  • 📚 mkdocs.yml + docs/index.md — GitHub Pages foundation

  • 📋 Deprecation policy in docs/configuration.md

  • 🔢 Version bump: 0.10.01.0.0 across all poms

Test results

224 tests green, 0 failures.

v0.10.0 — Graph Timing

Choose a tag to compare

@ddsha441981 ddsha441981 released this 29 Jul 10:14
ce9c620

Graph Timing: WireDoctor's core value — startup timing analysis — is now visible directly in the Graph tab, not just the Timing tab.

Added

  • 🔥 Timing heat chip — toggles node color (green→red, log scale) and size mapped to per-bean instantiation time, so expensive beans jump out at a glance. Off by default; cycle/ghost/proxy/orphan colors keep priority; untimed (never-instantiated) beans stay default.
  • 🥇 Critical path chip — traces the startup critical path in gold through the graph (nodes glow, path edges widen) and dims everything else. Handles condensed [cycle: a, b] path entries by highlighting all members. Hidden when no timing data is available. Composes with filters and heat.
  • 🔍 Inspector timing line — the node panel now shows Instantiation: N ms and an on critical path tag where applicable.
  • 📊 beanTimings JSON field — the full per-bean instantiation timing map is serialized in the report (previously only slowBeans above the threshold survived).

Verification

Full Changelog: v0.9.0...v0.10.0

v0.9.0

Choose a tag to compare

@ddsha441981 ddsha441981 released this 20 Jul 16:56
cc8c6c5

What's Changed

Full Changelog: v0.8.0...v0.9.0

feat: v0.8.0 — Verification Debt

Choose a tag to compare

@ddsha441981 ddsha441981 released this 20 Jul 16:29
8fdb661

v0.8.0 — Verification Debt

Closes the original design plan's unfinished verification checks (§3) before the v1.0.0 API freeze turns their answers into contracts — plus a CI-flakiness fix found during real-world gate
validation.

🌊 WebFlux/reactive validation (plan §3 check #4 — never done until now)

  • New WireDoctorWebFluxIntegrationTest boots a REACTIVE (Netty, non-servlet) context in CI and asserts reports are written, startup timings populated, and ghost analysis runs
  • Reactive entry points added to ghost detection: WebHandler, WebSocketHandler, WebExceptionHandler (joining RouterFunction) — fixes ghost false-positives in reactive apps
  • Pinned by test: a RouterFunction bean is never flagged as a ghost
  • spring-boot-starter-webflux added test-scope only; README supported-versions note added

🔬 Bean-scope behavior pinned by tests (plan §3 check #2 — doc-only until now)

  • New WireDoctorBeanScopeTest asserts the documented behavior per scope:
    • prototype definitions appear as graph nodes but are never instantiated (zero-intrusion promise, now regression-tested)
    • untouched @Lazy beans survive the full analysis untouched
    • FactoryBean product edges resolve to the factory's bean name
    • skipped not-instantiated beans are honestly counted (proxies.notInstantiatedSkipped)
  • README Limitation #5 rewritten from vague ("may not fully map out") to these test-backed facts

🤝 Never overwrite a user-set ApplicationStartup (found in plan audit)

  • The startup listener previously replaced any ApplicationStartup the app (or another tool) had installed — silently breaking foreign instrumentation
  • Now: a pre-existing non-default instance is kept. Buffering ones keep timings working (INFO); foreign ones get a WARN and the timing section degrades gracefully while every other
    analysis runs normally
  • getApplicationStartup() verified available on Boot 2.7 → 4.0 (same floor as BufferingApplicationStartup)
  • Contract pinned by WireDoctorStartupCoexistenceTest

⏱️ Slow-bean gate jitter margin — wiredoctor.slow-bean-margin-ms (default 20)

  • Real-world validation on start.spring.io tripped the gate at 101ms vs a 100ms threshold — pure JVM jitter, not a regression. That exact case is now a permanent test
  • A NEW slow bean must exceed threshold + margin to trip; beans inside the margin band stay in the report's slow-bean list but never fail CI
  • Mirrors the dual-threshold noise tolerance the startup-time gate already has; 0 restores exact pre-0.8.0 behavior
  • Margin surfaces in gates.config and the HTML gate card ((+20ms jitter margin))
  • Docs: docs/performance-gates.md + README config section updated

Verified

  • 233 tests green (222 autoconfigure + 11 actuator) via full mvn verify — up from 219
  • ~60 lines production code, ~350 lines tests — code-light, proof-heavy by design
  • Version bumped in all 4 poms; CHANGELOG entry added

Plan §3 checklist after this PR

Check Status
#1 SPI hook timing ✅ resolved v0.1.0 + CI matrix
#2 Bean scopes this PR
#3 AOT/native → v1.0.0 (deliberate, task 3)
#4 WebFlux this PR

v0.7.1

Choose a tag to compare

@ddsha441981 ddsha441981 released this 20 Jul 15:03
a906e7d

What's Changed

Full Changelog: v0.6.1...v0.7.1

v0.7.0

Choose a tag to compare

@ddsha441981 ddsha441981 released this 19 Jul 18:24
a906e7d

What's Changed

Full Changelog: v0.6.1...v0.7.0

v0.6.1

Choose a tag to compare

@ddsha441981 ddsha441981 released this 19 Jul 10:35
3152ea3

What's Changed

  • feat: HTML report redesigned as tabbed diagnostic console (v0.6.1) by @ddsha441981 in #18

Full Changelog: v0.6.0...v0.6.1

v0.6.0

Choose a tag to compare

@ddsha441981 ddsha441981 released this 19 Jul 07:45
4cf8a38

What's Changed

Full Changelog: v0.5.0...v0.6.0