cytoscape.js v4 HEAD · 47a5c66d · built 2026-09-16 14:48Z

Documentation: the JSDoc gates and the records

v4 documents itself in JSDoc on the source, and three tags are gated. The rest of this file is about the failure mode those gates cannot see: a comment that is present and wrong.

Where v4's documentation lives

  • The feature inventory is docs/features.csv. Edit it in the same commit as an API, style property, capability or scope decision changes. npm run status validates it and publishes the Features page and an identical CSV download. Keep comments concise, name replacements and limitations, and cite a repository source in Reference (optionally :line). The status definitions live on that page. Proposed marks analytical suggestions, not approved plans; see docs/feature-direction.md. Implemented means prototype support, not release readiness. API rows use eles. for all collection/element/node/edge prefixes, one row per member or alias, with overloads together. Coverage is checked against the generated v4 API, style read registries and frozen v3 API/property definitions; capabilities and recorded plans still require a manual review. Source presence checks do not establish behavioural parity. Do not regenerate statuses from names or overwrite reviewed comments automatically.

  • v4 has no documentation site yet (round 46 builds it); v4 documents itself in JSDoc on the source — see the rest of this file. v3's site is still readable at v3/documentation/: grep v3/documentation/docmaker.json for the v3 API in JSON form (search e.g. "cy.on"), and v3/documentation/md/**/*.md for its prose. Useful for parity questions — what did v3 do here? — but remember it describes v3, and v4 deviates deliberately in many places.

  • EXECUTIVE_SUMMARY.md is derived from the record and is rewritten when a round closes (round 46.5). The round files under plan/rounds/ stay the source of truth, and since round 108.8 the summary is the record's only cross-round narrative — PLAN.md carried a second one that silently stopped at round 64, and it was removed rather than revived, so this rewrite is what keeps the history current. The summary is the five-minute version for a reader who will never open it, organised by calendar week and written in outcomes and decisions rather than rounds and file names. Three rules keep it honest: restate rather than append (later rounds routinely change what an earlier decision meant, so earlier weeks need correcting too — appending a week is not a rewrite); re-measure every figure rather than copying it forward, since test tallies, member counts and benchmark numbers go stale first; and an item leaves its open-questions table when the decision is made, not when the work is scheduled. Its own "Maintaining this file" section carries the full rule, and PLAN.md's process list carries the trigger.

  • v4 has no documentation site yet — round 46 builds it, from the model round 45's generator already emits (npm run docs:api; 362 documented members over 48 sections, gated against the shipped declaration). Until then src/README.md is the maintained prose, MIGRATING.md is the v3->v4 porting guide and CHANGELOG.md the 4.0 summary — both of those ship in the package, so keep them true; test/modules/migration-guide.mjs checks the guide's property table against the running library.

  • v3's documentation HTML under v3/documentation/ is generated. Do not edit it directly when the corresponding markdown or template source (v3/documentation/docmaker.json, template.html) should be changed instead.

  • v3/documentation/ is v3's, and stays that way until v4 ships — the v3 code and docs are kept intact so they remain available for comparison benchmarks and parity work. Do not add v4 pages to it.

  • v4 documents itself in JSDoc (round 26). For anything under src/, prose about what a member does belongs in a doc comment next to the member; the release documentation will be generated from those comments. Use standard tags only (@param name — description, @returns, @throws, @see); one block per overload signature; state the contract and any deliberate deviation from v3, not the implementation. The // -- <group> -- banner comments in core.mts/collection.mts are the section grouping a generator reads, so keep them accurate. Coverage is enforced: node scripts/jsdoc-coverage.mjs --verbose lists any public member of an exported class (or exported function) that lacks a comment, and test/jsdoc-coverage.mjs fails the build if one appears. Since round 31.2 the same script and gate also require an @throws tag on any public member whose body throws — these comments ship as hover text in dist/cytoscape.d.ts, so a doc comment that is wrong (or silent) about failure is a defect a consumer sees. Round 31.1 is the cautionary case: the per-element bypass error told callers to use the style function form, which round 8 removed and 29.3 made throw, and the doc comment repeated it — while this repo's markdown described the replacement correctly the whole time. A docs sweep that only reads markdown never sees this class of drift. Round 32 added the third rule: a public member of the PUBLIC_API files that takes arguments must document them with @param, because docmaker's per-function shape carries a description per argument. @returns (278/278) was written in round 36 and left reporting on that same reasoning — there is no return field — until round 37.1 gated it too, since these comments ship as .d.ts hover text whether or not the generator reads them. Three tags gated, then: @throws, @param, @returns. The two remaining audits (stranded doc blocks, benchmark coverage) stay report-only deliberately, each being heuristic in a way the gated three are not.

  • After a rename, check that the docs' paths resolve — do not grep for the spellings you expect. Round 42's sweep worked from a hand-written substitution list and so fixed every spelling it thought of, leaving typescript/tests/gpu.test-d.ts and test/modules/gpu-import-graph.mjs in src/README.md (neither matches test/gpu- or typescript/tests/gpu), three pointers at v3 sources that had moved under v3/, and one line-wrapped dist/\ncytoscape-gpu.d.ts. Extracting every rooted path from the markdown and testing it with existsSync found all of them in seconds — and it is the only method that catches a spelling nobody anticipated. Allow for the repo's .mjs-specifier convention when you do it.

  • A doc block can strand onto the wrong member, and coverage will not notice. The most repeated documentation defect in this repo — seventeen instances by the close of round 36 (eight across rounds 26.1-26.4, the ninth and tenth in 34.4/34.5, the eleventh in 36.2, and six more the moment a check existed to look) — is a later insertion landing between a /** */ block and the member it documents, after which the comment re-attaches to whatever now follows. The coverage gate sees it only when the displacement leaves some member with no comment; when the block lands on another documented member, coverage stays at 100% and two members carry each other's prose. That variant ships: round 36 found arrowBase's block stacked above lineOpacityConst's in dist/cytoscape.d.ts, so a consumer hovering one read the other. node scripts/jsdoc-coverage.mjs --verbose now lists blocks that document nothing (reporting only — a free-standing module note is legitimate and looks identical), and a block displaced onto another documented member is not statically detectable at all, so reading is still the only defence there.

  • A plan's statements about the code are claims to re-measure, not facts to build on. This repo's records are unusually good, which is exactly why their stale parts are dangerous: a sentence written when it was true reads identically to one that still is. Three rounds in a row tripped on this. Round 37.3 was told @param was at 229/229 and found the package entry point outside every audit; round 37.4 was told namespaced listeners "never fire" and found v4 running v3's namespace semantics in full; round 41 was told v4's "one remaining shared-module dependency" was the emitter and found five more after severing it. The cost of checking is a grep; the cost of not checking is a round built on a premise that was never true. Prefer a spec that measures the claim (test/modules/import-graph.mjs is one) over a sentence asserting it. "Ported verbatim" is one of these claims, and the cheapest to check: round 43.4 said debug/'s compound fixture was v3's graph verbatim, and it had a sorted node list, four different edges and no cols: 3 — a diff of the two files answered it in seconds, and the difference was the whole reason the fixture was unreadable.

  • An audit's scope is part of its claim; check what it enumerates before quoting its 100%. Round 32 reported @param at 221/221 and gated it, but auditParamTags descended class bodies only, while the script's own header defines a public member as a class member plus every top-level exported function — so wire.mts and columnar.mts, whose entire public surface is exported functions, sat outside a gate that read as complete, and two of them had no @param at all. Round 36 widened it to 229/229 — and round 37.3 found the same failure a third time: the widened pattern matched export function and export const f = but not export default function, so src/index.mts — listed in PUBLIC_API since round 26, and whose entire surface is the package entry point export default function cytoscape — contributed zero members to every audit while reading as audited and complete, with all three of its tags in fact missing (231/231 now). The same question applies to the remaining audits: a green gate answers "nothing regressed among the things I look at", so read the enumerator, not the percentage.

  • The package ships declarations built by npm run build:types (rolldown.dts.config.mjsscripts/build-dts.mjsdist/cytoscape.d.ts), which carry those JSDoc comments to consumers. Regenerate and commit that file when the v4 public surface changes; npm run test:types:surface audits its shape.