Documentation
Changelog
Release history from the repository CHANGELOG.md.
Latest entries
This page shows the latest entries from CHANGELOG.md. See the repository for the complete release history.
[2.4.2] - 2026-07-08
Fixed
gen-docssuperlinear scaling past ~300-500 source files (docs/backlog/story-gendocs-linear-scaling.md,docs/backlog/adr-linear-scaling-fix.md). Root cause, confirmed vianode --prof(not just a code read):commonRoot(modules)inlib/renderer.jsre-walked every module's split file path on every call, reached throughmoduleLabel/moduleHtmlPathonce per sidebar-tree leaf insiderenderTreeLevel, itself invoked once per generated page (buildSidebar()) -- an O(N³) path overall, not the trie-building step (already fixed in an earlier sprint). Two changes, both additive/targeted (no restructuring of surrounding logic):commonRoot()is now memoized in aWeakMapkeyed on themodulesarray reference (deliberately not a filePath string, to avoid two independentbuildSite()calls bleeding a cached label into each other -- see the ADR's Alternatives).- The sidebar's per-page render now precomputes each tree node's default (closed, non-active) HTML once per
buildSite()call and reuses it for every page; only the active ancestor chain + active leaf are rendered fresh per page (was: the entire tree, every page). The redundant per-page__parent-linking walk was also folded into this one-time pass (same call chain, not called out separately in the original ticket list, disclosed indocs/backlog/task-ls-04-sidebar-node-caching.md's implementation notes). worker_threadsparallelization of the parse phase was evaluated and explicitly not pursued -- profiling at N=300 showed TS Compiler API parse functions at 0.0%-0.1% of JS ticks, nowhere near co-dominant with the render-phase bottleneck above.
Added
bench/generate-fixtures.js+bench/run-perf-gate.js(npm run bench:perf-gate): a deterministic (seeded-PRNG) synthetic-fixture generator and a perf-gate script assertingtime(2000 files) / time(500 files) < 4.5x..github/workflows/perf-gate.yml: runs the gate on every push/PR tomain.test/renderer-memoization.test.js: dedicated cross-call cache-isolation regression suite for the two caches above (twobuildSite()calls sharing a filePath string but a different common root must not bleed a label/href between them).test/gen-docs.test.js: a permanent full-output-tree byte-diff regression test (every generated file, not amodules/-only spot check, both with and without--quality) -- extends the existing byte-diff pattern from a one-time verification into an automated guard against futurerenderer.jsregressions.
Performance
- Wall-clock, synthetic multi-directory fixtures,
gen-docsend to end (single machine, informal numbers -- see README Benchmarks for the full table and the CI gate for the authoritative, continuously-re-measured check): 400 files went from 28.38s pre-fix to 0.90s post-fix; 500 files did not reliably complete pre-fix within a reasonable window and now completes in 2.40s; 1,000 files in 4.68s. Seedocs/backlog/task-ls-02-profiling-spike.mdfor the full profiling data anddocs/backlog/task-ls-04-sidebar-node-caching.mdfor the post-fix numbers.
Disclosed trade-offs / known follow-ups
- A pre-existing, unrelated memory-footprint characteristic surfaced during verification:
buildSite()holds every generated page's full HTML (including each page's own embedded sidebar markup) in memory until the whole site is built. This is not something this fix introduced or worsened, but it means very large sites (order of thousands of files) may hit memory limits on constrained hardware independent of the wall-clock fix above -- not yet sized against realistic CI hardware, tracked as an open follow-up rather than silently declared fine. See README's Known limitations. - The 2,000-file point of the perf-gate's own threshold check was not hand-verified in this development environment (memory-constrained sandbox, see above) -- the CI gate (
.github/workflows/perf-gate.yml) re-measures it on every push/PR going forward, which is the authoritative, continuously-current source rather than a single frozen number in this changelog.
Tests
- Test suite grew from 228 to 234 assertions (2 new full-tree byte-diff tests in
test/gen-docs.test.js, 3 new cross-call isolation tests in the newtest/renderer-memoization.test.js). All pre-existing 228 assertions pass unchanged -- verified via byte-diff againstsample/, both with and without--quality, confirming zero output/behavior change (story AC7).
[2.4.0] - 2026-07-07
Added
- Doc-site version switcher (
docs/backlog/story-doc-version-switcher.md): every generated page (index, module pages, health-detail pages) now carries a "Current" control in the topnav. With history >=2 generations, it's a native<details>/<summary>dropdown listing "Current" plus every preserved prior generation, most-recent-first, each linking to a complete, self-contained rendering of the site as it looked at that generation -- not a changelog/diff summary. With no history yet, it renders as a plain, non-interactiveCurrentlabel instead of a broken empty dropdown. Zero client-side JS -- the control is native HTML disclosure, degrades to plain navigable links with JS disabled. --datanow also backfills<out>/site-versions/<version-id>/-- a full rendered snapshot for everysite-data-history/*.jsonentry that doesn't have one yet ("render-only-missing": an already-rendered, immutable snapshot is never re-rendered, keeping per-run cost O(1) regardless of history depth after a one-time backfill).<version-id>is the same ISO-timestampsite-data.jsalready uses for history filenames, so the two stay trivially correlated.- Per-function/method Code Health drill-down (
docs/backlog/story-function-level-health-drilldown.md): function and class-member (constructor/method/getter/setter) entries on module pages now show their own grade/score chip and metric dots, sourced from code-multivitals'sFileReport.functions[], matched by name + tightest-containing-range (our AST extraction only has a start line; code-multivitals'sstartLine/endLinerange is used as the match target). Falls back to a muted "no data" chip -- never a stale file-level number repeated per function -- when no match is found. - Corrected design tokens (
docs/backlog/adr-phase-n-exact-design-tokens.md): the two newly-uploaded mockups (Code Health Report.html,File Detail Report.html) shipped literal, recoverable design tokens this time (unlike Phase M's reconstruction).--coralcorrected from#FF6452to its real#FF4B2E; full corrected radius/shadow/type-scale token set;Space Grotesk/JetBrains Mononow loaded via Google Fonts CDN@import(Chintan's explicit choice over self-hosting) -- the first generated-output dependency on a third-party network resource, documented as a precedent-setting exception to this project's usual zero-external-dependency posture.
Fixed
- Caught during this batch's own live verification, not by a written test in advance: a version-switcher snapshot's own switcher menu failed to mark itself as the current selection on first render, because the version list passed to a backfill pass was computed from already-existing
site-versions/directories rather than from allsite-data-history/*.jsonentries. Fixed before this shipped; every snapshot's own page now correctly self-identifies (is-current/aria-current="page").
Disclosed trade-offs
- An older version-switcher snapshot does not link forward to snapshots rendered after it (a reader must go via "Current" first, one extra hop) -- the direct, necessary consequence of render-only-missing's cost guarantee (re-patching every prior snapshot on every run would reopen the unbounded-cost problem this design avoided). Accepted at product-owner acceptance.
- The live/current generation's own
site-versions/snapshot is deliberately never pre-rendered (a documented deviation from the original architect spec) --site-data.js's history-eviction timestamp can't be predicted before the eviction actually happens, so only already-evicted, stably-named history entries are ever backfilled.
Tests
- Test suite grew from 222 to 228 assertions: 6 new tests in
test/gen-docs.test.jscover the version switcher's full lifecycle -- fresh-repo static-span shape, 3 successive generations with genuinely differing content producing correctly-ordered history, render-only-missing immutability (mtime + byte-identical content across a later run), cross-pagearia-currentcorrectness (the test that caught the bug above), zero-JS degradation, and themax-height:320pxCSS cap. - Verified live against real, incrementally-modified fixtures across 3 successive
gen-docs --quality --dataruns: correct eviction/backfill sequencing, correct render-only-missing, correct most-recent-first ordering, and correct per-pagearia-currenton both the live index and every snapshot page. - Default (no
--data/--quality)gen-docsoutput confirmed byte-for-byte unaffected.
[2.3.0] - 2026-07-07
Changed
- Exact-design shell (
docs/backlog/adr-phase-m-exact-design-shell.md): the doc site's chrome now matchesCode Health Redesign.dc.html/File Detail Redesign.dc.htmldirectly instead of reusing the prior light theme -- dark sidebar (--sidebar-bg:#0E0E10), offwhite content background (--bg:#F5F4F0), and the mockups' purple/lime/coral/gold accents. This is a site-wide chrome change (every page), not scoped to Code Health/File Detail alone. - The project logo, version tag, and the Overview/Code Health nav buttons moved from the header into the sidebar (
.sidebar-brand,.navbtn); the header now carries only a breadcrumb-style crumb and the search pill, matching both mockups. Thetopnav-quality-linkclass is renamedsidebar-quality-linkat its new location. - Sidebar symbol markers (
symRows()) changed from colored text pills to a small colored dot + kind abbreviation, matching the mockup's member-row style;sym-fn/sym-cls/etc. class names are unchanged (now applied to the dot), so no new taxonomy was invented. - Index hero gauge grows 120px -> 168px (the mockup's literal size); the focus-area cards' "view more" link is now a filled pill button using the card's own tag color (mockup's
focus-btn), andtag-chipgets the mockup's 1.5px white outline. - Disclosed limitation: both mockups
@importahundi-design-systemtoken package that was not included in the upload (only referenced by path) -- exact hex values for most of the palette aren't literally recoverable. A few values ARE literal evidence in the mockups' own markup/JS and are used verbatim (--lime:#C6FF3Dfrom the mockup's owngradeHex,--offwhite:#F5F4F0and--accent:#5B4FE8from hover/active rgba tints, the gold/todo-badge hex codes). The rest of the palette is reconstructed to be visually consistent with those anchors; see the ADR's "Finding" section for the full disclosure.
Tests
test/renderer.test.jswas rebuilt after a second sandbox file-truncation incident (this one struck mid-edit and the git-HEAD recovery path turned out to predate the Code Health/File Detail redesigns entirely, since none of this project's work has ever been committed) -- rebuilt directly against the currentlib/renderer.jsrather than forward-patching a stale baseline. Full suite: 219 assertions passing across all suites (renderer/lint/fix/import-graph/project-facts/quality/site-data/gen-docs).- New coverage: sidebar-brand/navbtn/sidebar-quality-link presence, header crumb content and the absence of
topnav-logo,sym-dot/sym-kind-abbrmarkup (and the absence of legacysym-pill), the dark palette tokens and gauge-size CSS selectors, and a<script>-tag count assertion (zero-new-JS still holds). - Verified live against this repo's own
lib/+bin/+plugin source vianpm run dashboard: dark sidebar, breadcrumb header, 168px index gauge, and dot-based symbol markers all render correctly; default (--quality-less) output unaffected beyond chrome colors.
[2.2.0] - 2026-07-08
Added
- Per-file Code Health hero (
docs/backlog/story-file-detail-redesign.md,docs/backlog/adr-phase-l-file-detail-and-site-data.md): module pages now show a circular grade/score gauge (reusing v2.1.0'sscoreToGrade()/qColor()primitives, scoped to that one file) in place of the old flat.qstripchip row, plus a factual one-line narrative built purely from real error/warning/clone counts (deliberately not stylized "encouraging" copy). Files with no code-multivitals entry keep the same graceful muted fallback as before. - TODO-placeholder badge: any
TODO:-prefixed description (function/param/returns text written by--fix, perlib/fix.js's own literal templates) now renders with a small "todo" badge and muted italic text, in function/class descriptions, the params table's Description column, and the Returns line. Real authored text is unaffected -- this is presentation-only. lib/site-data.js+--data/--from-data:--datawrites<out>/site-data.json, one JSON capturing everythingbuildSite()needs (modules + quality/import-graph/snapshot data). It never silently overwrites a prior generation -- the previoussite-data.jsonis moved into<out>/site-data-history/first, so successive generations stay individually comparable.--from-data <path>builds the full site directly from a savedsite-data.json, skipping source parsing and quality analysis entirely (a template/CSS-only iteration no longer re-parses the tree or re-runs code-multivitals). Fully additive:--json/docs.json's existing shape and behavior are untouched.site-data.json/site-data-history/added to.gitignore(generated output, same category asdocs//snapshots/).
Tests
- Test suite grew from 209 to 231 assertions: 2 new suites (
test/site-data.test.js,test/gen-docs.test.js-- the latter isbin/gen-docs.js's first-ever dedicated test file, spawning the real CLI same astest/cli.test.jsdoes forbin/cli.js) plus renderer-level coverage forisTodoText/descText, the per-file hero's grade/narrative/fallback states, and CSS selector presence. Two pre-existing tests deliberately revised (documented inline, same category as prior sanctioned exceptions): the old flat health-strip field/fallback assertions now check the hero gauge's markup shape instead of the retired.qstrip/qChipoutput. - Verified live against this repo's own
lib/+bin/+plugin source: real per-file grades (e.g.bin/cli.jsgraded F), a real--fix-generated TODO description/param/returns rendering the todo badge (constructed fixture, since this repo's own source currently has none left to exercise),--datarun twice preserving history correctly, and--from-datareproducing byte-identicalindex.html/module pages against the original run. Confirmed default (--quality/--data/--from-data-less) output remains deterministic with no new markup beyond the always-present (page-wide) CSS selectors.
[2.1.0] - 2026-07-07
Changed
- Code Health dashboard redesign (
docs/backlog/story-code-health-redesign.md,docs/backlog/adr-phase-k-code-health-redesign.md): the embedded Code Health section's 7 flat stat cards are replaced by a hero panel -- a CSSconic-gradientgauge showing a letter grade + the existing health score (grade is a purely cosmetic finer scale layered on the existingqColor3-color bands, not a second palette), the remaining 6 stats as a compact metrics list, and a trend sparkline + delta badge sourced from--quality-trend <dir>snapshot history (renders an honest "not enough scan history yet" message below 2 snapshots -- never a fabricated line). - The 4 focus-area cards (files needing attention, duplicate code, most-imported files, orphan files) are restyled with a tag chip, colored top border, and a big headline stat; rows beyond the 5-row preview are reachable via a native
<details>/<summary>inline expand -- zero new client-side JS (reuses the same disclosure pattern already used by the sidebar's directory tree). The standalone detail pages (health-attention.htmletc.) are unchanged and still linked from every card. --quality-trend <dir>now also drives the embedded index-page sparkline when passed alongside plain--quality(previously only wired for the standalone--quality-reporter dashboardmode) -- no new CLI flag.- Environment/hardware requirement badges (cores/RAM/disk/editor/browser) from the originally-proposed mockup were explicitly deferred, not built -- none of those values are derivable from repo state, and inventing them would contradict this project's "derived from actual repo state, never hand-typed prose" principle. See the ADR's Decision 7.
Tests
- Test suite grew by 8 assertions:
scoreToGradeboundary cases at every named grade, hero gauge/metrics rendering against real data,buildHealthSparkline's 0/1/2+-snapshot branches (including correctly-signed delta direction), per-cardqcard-expandpresence/absence, a zero-<script>assertion scoped tobuildQualitySection()'s own output, and new CSS selector coverage. One pre-existing test deliberately revised (documented inline, same category as the prior "5→9 pages" exception): the index card's inline expand now embeds overflow rows in the DOM (behind a native, collapsed<details>), so the assertion now checks that exactly 5 rows are visible *ahead of* the expand, rather than asserting overflow rows are entirely absent fromindex.html. - Verified live against this repo's own
lib/+bin/+plugin source: real avg health 64.1, grade D, 20 errors, 204 warnings (non-placeholder). Confirmed default (--quality-less) output is deterministic and contains zero occurrences of the new markup (qhero/qcard2/code-health). Confirmed the sparkline renders a real trend line from 2 saved snapshots via--quality-snapshot.
[1.21.1] - 2026-07-06
Changed
- Code Health-only index under
--quality(same-day follow-up to v1.21.0,docs/backlog/story-code-health-drilldown.md): when--qualityis passed, the index page's Modules grid is no longer rendered — the Code Health dashboard (7 stat cards + 4 summary cards) is the only content section on the page, instead of sitting alongside the module grid. Module navigation is unaffected: the full module tree remains in the sidebar on the index page (and every page) regardless of this flag. Plaingen-docswith no--qualityis unaffected — the Modules grid renders exactly as before. lib/renderer.js'sbuildSite(): the index body now conditionally skipsbuildIndexBody(modules)whenoptions.qualityis set — a one-line change, additive/conditional only, no other index-page markup touched.README.md: added a "Code Health dashboard (--quality)" preview (assets/preview-quality.svg) and rewrote the### Quality reportingdescription to reflect the card layout, the 4 detail pages, the per-module health strip, and that the dashboard replaces (not sits alongside) the Modules grid on the index page. Also corrected the stale "152 passing tests" figure to the current 201.
Added
assets/preview-quality.svg: new hand-crafted mockup (same style/size convention asassets/preview.svg) depicting the--qualityindex page — stat cards, the 4 summary cards with "View all →" links, no Modules grid.
Tests
- Test suite grew from 195 to 201 assertions: 3 new tests cover (1) Modules grid removed from index body when
--qualityis active, (2) Modules grid still renders when--qualityis absent (regression), and (3) sidebar module navigation is unaffected either way.
[1.21.0] - 2026-07-06
Added
- Code Health card layout + drill-down detail pages (fast-follow to v1.20.1's embedded section,
docs/backlog/story-code-health-drilldown.md): the index page's 4 full inline tables (files needing attention, duplicate code, most-imported files, orphan files) are now compact summary cards (top 3-5 rows + a "View more" link), each linking to its own full, uncapped detail page at the output root:health-attention.html,health-duplicates.html,health-imports.html,health-orphans.html. The 7 stat cards above them are unchanged. - Per-module health strip: every generated module page now shows a health-metrics strip (
<aside aria-label="Code health summary">) directly below its header — Health Score, Maintainability, Functions, Errors, Warnings, Clone involvement, Worst severity, Code smells — so a reader lands on a file's health context without cross-referencing the index. Modules with no code-multivitals entry show a single muted "No code health data for this file." row instead of throwing or omitting the strip. - Both are additive to the existing
--qualityflag — no new CLI flag, and default (--quality-less)gen-docsoutput is unaffected (verified: 0 occurrences of the new markup, 0 new files, when--qualityisn't passed).
Changed
lib/renderer.js:buildQualitySection()now rendersqCard-based summary cards instead of full inline tables; newbuildHealthDetailPages(),buildFileHealthLookup(), andbuildHealthStrip(). Per-file error/warning/function counts for the strip are derived from existingFileReport.functions[].metrics[].severitydata (code-multivitals'sFileSummarydoesn't carry them directly) — no new metrics, no new dependency.- Test suite grew from 187 to 195 assertions. One existing regression test's contract deliberately changed:
buildSite()under--qualitynow returns 9 pages (5 base + 4 health detail pages), not the prior "still exactly 5" — documented inline intest/renderer.test.jsas a sanctioned exception to the single-artifact principle, not a silent regression (the 4 new pages are extensions of the doc site's pre-existing multi-page nature, same category as the one-page-per-module pages that have always existed).
Correction (caught during design review, before implementation)
- The initial architecture pass assumed the 4 new detail pages should live "in the same output directory as module pages." That's incorrect against the actual code — module pages live in a
modules/subdirectory (moduleHtmlPath()), whileindex.htmlis written at the output root. Corrected before implementation: the 4 detail pages live at the output root, sibling toindex.html, since they're extensions of the index page's Code Health section, not per-module content. Seedocs/backlog/story-code-health-drilldown.md.
[1.20.1] - 2026-07-06
Fixed
gen-docs --qualitynow embeds its findings directly intoindex.htmlinstead of writing (or, in the internal-only path, requiring) a separate file. Chintan's direct feedback after reviewing the generateddocs/index.html: the code-multivitals statistics belonged in the same page as the API docs, not off in a second artifact.--qualitywith no--quality-reporternow computes the code-multivitals analysis + the import-graph/orphan-file findings and passes them into the normal doc-site build, which renders a new "Code Health" section (stat cards, files-needing-attention table, duplicate-code pairs, most-imported files, orphan files) on the index page, with a "Code Health" link in the top nav.--quality-reporter <console|json|html|sarif|badge|dashboard>is still available and unchanged for anyone who explicitly wants a standalone report file instead (CI/export use cases) — it still skips the doc-site build, same as before.- Retired
scripts/gen-dashboard.js(and thenpm run dashboard/npm run quality:dashboardscripts) — the separate internaldocs/dashboard.html+docs/dashboard-quality.htmlpair it produced is now redundant with the embedded section above. Newnpm run docs:internalscript documents jsdoc-scribe's ownlib//bin//plugin source with--quality, producing the same one-file result contributors get from any project.npm run qualitynow explicitly passes--quality-reporter console(previously the implicit default) so it keeps its old plain-console behavior now that the flag's un-reportered default means something different.
Changed
lib/renderer.js:buildSite(modules, options)accepts an optionaloptions.quality({ result, graph, orphans }); when present,buildQualitySection()renders the Code Health section on the index page only — module pages are unaffected, and no new page is added to the site (still exactly3 assets + index.html + one page per module, verified by the existing "5 pages total" regression test)..gitignore: addeddocs-internal(the new script's generated output, never committed — same treatment asdocs).
[1.20.0] - 2026-07-06
Added
- Project dashboard (internal, repo-only):
npm run dashboardgeneratesdocs/dashboard.html(onboarding facts — Node version vs. CI-tested matrix, package manager, project structure, global dependencies, test tooling — plus a project-wide import graph and orphan-file report) anddocs/dashboard-quality.html(embedded code-multivitals dashboard). New moduleslib/project-facts.jsandlib/import-graph.js(the latter does its own lightweight import/export extraction via thetypescriptcompiler API — no new dependency, but see Correction below), new repo-onlyscripts/gen-dashboard.js(not part of the published package). Seedocs/backlog/epic-project-dashboard.md/adr-phase-j-project-dashboard.md. - Quality reporting for
gen-docs(--quality,--quality-reporter,--quality-profile,--quality-config,--quality-baseline/--quality-save-baseline,--quality-snapshot/--quality-trend): opt-in [code-multivitals](https://www.npmjs.com/package/code-multivitals) integration (cyclomatic/cognitive complexity, Halstead volume, maintainability index, health score, compound smells, duplicate-code detection, all 6 reporters, baseline/diff mode, snapshots/trends/hotspots).code-multivitalsis an optional peerDependency (peerDependenciesMeta.optional: true) — never installed bynpm install jsdoc-scribe, never affects defaultgen-docsbehavior, and produces a clear install-instruction error (not a crash) if used without it installed. New shared modulelib/quality.js(dynamicrequire, never a top-level import, so the optional-dependency contract holds). code-multivitalsalso added as this repo's first-everdevDependency(distinct from the peerDependency above), used by the internal dashboard. Committed.code-multivitals.json(thedefaultthreshold profile).- New npm scripts:
dashboard,quality,quality:dashboard.
Correction (caught during implementation)
- The original design (
adr-phase-j-project-dashboard.md,story-code-health-dashboard.md) assumedlib/import-graph.jscould reuselib/extractor.js's existing per-file import/export data, the same waylib/drift.js/lib/coverage.jsreuseextractModule()'s output. That data does not exist —extractModule()has never extracted imports/exports.lib/import-graph.jsdoes its own lightweight extraction instead, using thetypescriptcompiler API (the project's existing one runtime dependency) — zero new dependency, but genuinely new parsing, not zero-new-parsing as originally assumed. Corrected in the ADR/story rather than shipped against the false premise.
Changed
- Test suite grew from 152 to 181 assertions (10 new import-graph tests, 12 new project-facts tests, 9 new quality-module tests — the last including a real clean-room "package not installed" repro via a child process, not just a cache-eviction approximation).
package.json:files/binunchanged (still onlybin/cli.jsandbin/gen-docs.js) — the new internal dashboard script lives inscripts/, outside the publishedfilesglob, on purpose (verified vianpm pack --dry-run).
Design note
- Two different, deliberately separate dependency relationships to
code-multivitalsin the same release: adevDependency(internal dashboard, always present in this repo) and an optionalpeerDependency(end-usergen-docs --quality*, never forced on anyone). Conflating the two — e.g. making it a plain runtime dependency so end users get it "for free" — was considered and rejected; seeadr-phase-j-project-dashboard.mdDecision 10 and its Alternatives Considered section.
[1.19.0] - 2026-07-06
Added
--fixflag forgen-comments: rewrites *existing* JSDoc blocks in place to resolve--lintfindings — reorders@paramtags to match real parameter order, fills a missing@param/@returns/description with a fixed, deterministic"TODO: ..."placeholder (never invented prose), strips trailing text off a no-description tag, collapses stray asterisks, and drops an unnecessary@returnson a function that never returns a value. Implies--lint. Does not add JSDoc to undocumented symbols (that stays--write's job) and never auto-fixescheck-tag-names(an unknown/typo'd tag has no safe default — always left as a remaining issue for a human). Newlib/fix.js, zero new npm dependency.eslint-plugin-jsdoc-scribe@0.2.0: 10 of the plugin's 12 rules now ship a real ESLintfix()(fixable: "code"), using the same rebuild strategy andTODO:placeholder convention as the core CLI's--fix.require-jsdocandcheck-tag-namesremain fixer-less, for the same reasons as the core CLI.
Changed
- Internal:
lib/extractor.js'sreadJSDoc()now also returnscommentRange({ pos, end }, the exact source-text range of an existing JSDoc block) per symbol — purely additive, same threading pattern asrawComment/badCommentin v1.18.0. Verified zero behavior change: all 132 pre-existing tests pass unmodified. - Test suite grew from 132 to 152 assertions in the core package (20 new: 16
lib/fix.jsunit tests, 4 CLI-level--fixtests) and from 36 to 39 ineslint-plugin-jsdoc-scribe(3 newLinter.verifyAndFix()convergence/preservation tests, alongside 10 newRuleTesteroutputassertions on already-existing cases).
Design note
- Filling in a missing description with a placeholder is a deliberate, narrow exception to "no AI, no guessing" — every placeholder is a fixed template (
"TODO: describe ...”), never code-derived prose, and is unmistakably marked so a human immediately knows it needs attention (grep -r "TODO: describe"finds every one). Seedocs/backlog/adr-013-lint-autofix.mdfor the full reasoning, including whycheck-tag-namesis the one rule that stays report-only even here.
[1.18.0] - 2026-07-06
Added
--lintflag forgen-comments: native JSDoc content validation — no ESLint required. Newlib/lint.jsrule engine reusesextractModule()'s existing AST + parsed-JSDoc data (plus a new additiverawComment/badCommentfield per symbol) to check the same category of thingseslint-plugin-jsdoc'srecommendedconfig does:require-jsdoc,require-param/require-param-description,check-param-names(ordering),require-returns/require-returns-description/require-returns-check,require-description,check-tag-names,empty-tags,no-multi-asterisks,no-blank-block-descriptions,no-bad-blocks. Read-only, exits 1 if issues are found — same CI-gate contract as--check/--check-drift. Zero new npm dependency.--lintand--check-driftcan be passed together in one invocation; both share a singleextractModule()parse per file rather than parsing twice.
Changed
- Internal:
lib/extractor.js'sreadJSDoc()now also returnsrawComment(the exact/** */block text) andbadComment(a near-miss malformed block, e.g. wrong asterisk count) per symbol, threaded through every extractor function/class/method/constructor/getter/setter/property/interface/typeAlias/enum/variable output. Purely additive — verified zero output change on every existing field via a byte-diff dogfood run acrosslib/andbin/(same method astask-a10-03), excluding the two new fields. - Test suite grew from 101 to 132 assertions (31 new:
lib/lint.jsunit tests plus--lintCLI-level tests).
Known limitation (tracked, not a regression)
extractModule()'s traversal (existing behavior, inherited by--lint) walks into function bodies and picks up local variable declarations as documentable "symbols," not just top-level/exported declarations — the same reason--checkhas always reported jsdoc-scribe's own low internal-helper coverage number.--lint'srequire-jsdocinherits that same scope, so running--lintagainst this repository's ownlib/reports real (not false-positive) gaps on internal helpers that were never intended to carry a doc block, consistent with what--checkalready reports today. Scoping extraction to declaration depth or exported-only symbols is a larger, separate change candidate for a future story — not bundled into this release.
[1.17.0] - 2026-07-05
Added
- Internal AST ergonomics layer: new
lib/ast-utils.jsmodule with four small, purpose-built traversal/guard helpers built directly on thetypescriptCompiler API —getDescendantsOfKind(node, kind),findFirstDescendant(node, predicate, stopAt),asClass(node),asFunctionLike(node). Not part of the public API; internal-only.
Changed
- Internal:
lib/extractor.js's traversal internals migrated onto the new helpers —hasReturnWithValue's hand-rolled walk is nowfindFirstDescendantwith astopAtboundary, and the localisFunctionLike/class-dispatch checks now go throughasFunctionLike/asClass. Zero output/behavior change (verified via a line-number-normalized diff ofextractModule()across every file inlib/andbin/, plus agen-comments --dry-runsanity check) — no new npm dependency, still justtypescript. - Test suite grew from 88 to 101 assertions (13 new, covering the ast-utils helpers directly, including nested-function boundary behavior).
[1.16.0] - 2026-07-02
Added
- Drift detection: new
--check-driftflag forgen-commentscompares existing JSDoc blocks against the current code and flags missing params, removed (stale) params, and return-type mismatches. Read-only and CI-friendly — exits 1 if drift is found, exits 0 otherwise, and never modifies source files. - Coverage badges: new
--coverage-badge <dir>flag forgen-commentsaggregates documentation coverage across a target path and writes a self-contained, shields.io-stylecoverage-badge.svgplus acoverage-summary.json. No network dependency — fully offline and deterministic. - N-level sidebar navigation: the generated docs site sidebar now renders an unbounded-depth collapsible folder tree (previously capped at 2 levels), with the active module's ancestor folders auto-expanded. Full keyboard navigation (arrow keys) and screen-reader support (ARIA tree semantics).
- Breadcrumb context on the index page: module cards for nested files now show a directory breadcrumb (e.g.
helpers / server) above the filename, so it's clear where a module lives at a glance. Deeply nested paths truncate to keep cards tidy.
Changed
- Internal:
--check's coverage math now goes through a sharedaggregateCoverage()helper (also used by--coverage-badge) instead of being computed inline — output is unchanged, this just avoids having the same math defined twice.
Fixed
- Module cards on the documentation index page now include a
titleattribute with the full relative path on hover, matching the tooltip behavior individual symbols already had.
[1.15.0] - 2026-07-01
Changed
- Phase H: Smart sidebar grouping — strips deeper common root from module labels, caps group nesting at 2 dir segments
- Sidebar group labels now show only the deepest relevant directory name (not the full path), fixing the verbose UPPERCASE path bug
- Module links inside groups show only the filename, with the full relative path in
titlefor hover tooltips - Sidebar section title and dir-toggle headers are now sticky (position:sticky) so they stay visible while scrolling
- Index page module cards display shortened labels (deep common root stripped)
- Empty-state message in
buildModuleBodyupgraded to styled<div class="empty">with explicit "No exported items in this module." text - Index page module cards show "No exported items" italic note for modules with zero exports
- New helpers:
deeperCommonRoot()andhasExports()added to renderer.js
[1.14.0] - 2026-07-01
Changed
- Phase G: Stripe-style documentation layout (v1.14.0)
- New sticky top navigation bar with project name (top-left) and centered search
- Sidebar redesigned: white background, uppercase section headers, accent-colored active links
- Right-side TOC restored ("On this page") with scroll-spy via IntersectionObserver
- Three-column CSS Grid layout: sidebar (240px) | main (1fr) | toc (200px)
- Card scroll-margin-top updated for topnav offset
- Search moved from sidebar to topnav center; "/" and Ctrl+K shortcuts
- Accent color: #625bf6 (Stripe purple)
- Hamburger toggle updated for overlay sidebar on mobile
Changelog
All notable changes to jsdoc-scribe are documented here.
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
[1.13.0] - 2026-07-01
Changed — Phase F: Single-design documentation site
lib/renderer.js — complete visual redesign