Repository navigation
Release: Prerelease 10.6.0-alpha.5 - #35715
Merged
Merged
Conversation
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
2 times, most recently
from
August 4, 2026 08:07
30e9bcd to
0ef7257
Compare
This reverts commit 745d2c4.
The docgen work needs one place that says what gets measured, how, and what a number is allowed to mean. Without it every later change re-argues the same questions inline. The note fixes the metric set, the determinism method, the budget shape and the CI tiers. Two decisions carry the rest: measurements compare ratios taken in one job on one machine, because absolute wall-clock on shared CI executors is too noisy to gate; and a pair whose two sides documented different amounts of work is marked not like-for-like and must not become a budget. The rules are written per engine rather than per framework, so adding a framework does not mean adding a section.
Two docgen harnesses need the same pieces: parse and validate flags, take a memory sample, run a series of simulated saves, summarize it, truncate a child's output for an error message. This adds them once, under scripts/bench/docgen-shared/, so the memory harness and the perf harness that follows do not each keep their own copy. Flags go through node:util parseArgs in strict mode and then a Zod schema, so a typo is rejected instead of falling back to a default. That was a real hole: --component 5, with the s missing, used to be ignored. EngineId lists only the engine that exists today. Each later engine adds its own id when it lands.
- parseHarnessOptions now returns z.infer<Schema> instead of casting onto a caller-supplied type parameter. The memory harness's hand-written option interface was a duplicate of its schema that nothing checked, so it is gone. - Drop the harness's own --max-retained-growth self-gate. Nothing passed it, its 400MB default disagreed with the 60MB budget gate.ts actually asserts, and it gave a memory threshold the power to fail an unrelated run. - Time the cold pass and each save with performance.now(). A warm re-extraction of one component takes single-digit milliseconds, and at Date.now()'s 1ms granularity a series can median to 0, which every ratio then divides by. - Report a retained slope only from two or more samples. leastSquaresSlope answers 0 for a shorter series, which reads as a measured flat one. - gate.ts resolves SANDBOX_DIRECTORY through docgen-shared/paths.ts, the same module the harness defaults from, rather than a second copy. - Print "n/a" rather than 0 for an unreported warm member count.
The flag parsed as a nonnegative count and componentSource then clamped it with Math.max(1, ...), so a run asked for at 0 silently measured something else. The schema now takes a positive count and the clamp is gone. Reported by CodeRabbit on #35631.
Named imports from node:path and node:fs, which is what the rest of scripts uses - the namespace form appears nowhere else in the workspace. Join the renderer module path instead of concatenating it into a URL. The concatenation only worked while the directory ended in a separator and the caller's argument did not begin with one. Also record what actually stops paths.ts importing SANDBOX_DIRECTORY from scripts/utils/constants.ts, since 'cannot import it' invites the question.
This is the base of the per-engine perf suite: the metric types, the fixed measurement profiles, the aggregation that turns repetitions into medians, the child-process spawn helper, and the BenchEngine base class every engine implements. It comes with the first engine, compodoc, which measures Angular. Compodoc runs as a fresh CLI process, so cold extraction and whole-project scan are the same measurement and peak memory is sampled from outside the child. The engine also reads the documentation.json compodoc writes, and reports two counts: how many members it documented, and how many of those carry a type it never resolved. The second count matters because compodoc never expands a named type. Chain a type through twenty files and it documents every member at the same speed, having looked through none of them, so a member count alone would read as identical to an engine that expanded all of them. @compodoc/compodoc is pinned at exactly 2.0.0, the version the Angular docgen baselines capture against. Its cost moves between versions. The profile and the engine id list carry Angular only. React and Vue arrive with their engines in the next PR. There is no CLI entry point yet. registry.ts, cli.ts and run.ts land in the PR stacked on top, so this cannot be run end to end; the two test files cover the aggregation and the documentation.json parsing.
Collapse coldMembers/warmMembers/coldOpaqueTypes into one members() hook
returning MemberCounts, and give BenchEngine an assemble() that turns a
scenario's repetitions into its ScenarioResult.
Both engines implemented the three count hooks as pass-through one-liners, and
the orchestrator had to call all three plus aggregate() and pick the designated
repetition itself - which meant naming a sample shape it cannot know, so the
generic parameter was erased and re-asserted with a cast. assemble() keeps
Sample bound inside the class, so the cast has nowhere to live, and picking the
designated repetition happens in one place instead of two. Sample is now
constrained to { coldMs: number }, which is what designatedRep has always
required and what the erased generic hid.
Pin N at 6 rather than 5. The two sides of a control pair alternate which runs
first by repetition parity, so an odd N hands one side the first slot once more
than the other, and the cold median then lands on a repetition from the majority
slot - turning the ordering effect the alternation exists to cancel into a
systematic bias on the headline ratio.
Report compodoc's peak RSS as n/a when nothing was sampled. `ps` is POSIX-only
and a run can finish inside one poll interval, and the initial 0 was reported as
a measured peak on either path. oneShotMetrics now requires every repetition to
carry a reading before it reports a mean.
Also: read the compodoc RSS poll interval from its constant rather than back out
of the params bag, and say in the "retained metrics missing" error that a series
shorter than two saves reaches it too.
The orchestrator settles on the child's close event, so a compodoc that hangs - which it can, on some inputs - stalled the whole suite with no way out. The run is now killed after ten minutes and reported as a timeout, so the engine fails on its own rather than taking the suite with it. Reported by CodeRabbit on #35636.
The generator was a sequence of writes, so the only way to see what compodoc is pointed at was to run it and look at a directory. angularProjectFiles returns the project as path -> contents instead, and generateAngularProject writes that map. The bookkeeping of which paths are components stops being tracked separately from the writes that create them. The new test snapshots that map: the tree, the fake @angular/core that keeps it hermetic, the tsconfig include that decides the measured set, and a component at zero and four extra props. Generated output is byte-identical.
run.ts is the entry point behind the new yarn bench:docgen-perf. registry.ts is the table of which engine measures what, with which flags; adding an engine means adding one row, and the orchestrator has no per-engine branches. ratios.ts divides each framework's legacy median by its new-engine median, both taken in the same run. report.ts prints the table. Only the Compodoc engine is registered here, so a run measures Angular. The React and Vue engines land next, and the control pairs they belong to are already listed: a pair whose two engines are not both registered yields no ratio. The suite prints documented-member counts next to every ratio and marks a pair not like-for-like when the two sides disagree. A ratio between engines that did different amounts of work measures resolution depth, not speed, and must not become a budget. No CI job runs this. Only bench:docgen-memory is wired into CI, and only on the daily tier, so manual runs are how anyone finds out whether the suite still works.
engineOrderForRep reverses the engine list on even repetitions instead of swapping each control pair in place. Pairs can share an engine, and swapping such a chain pairwise moves the shared engine twice, which leaves the first pair in its original relative order - so a pair could alternate on paper and never in the run. A reversal flips every pair at once, needs no knowledge of the pair table, and cannot be defeated by adding a pair. The test now asserts that property rather than one expected permutation, driven off CONTROL_PAIRS so it keeps covering new pairs as they are added. medianRatio returns undefined for a non-finite ratio. A warm re-extraction can finish below the clock's resolution, and dividing by that median yielded Infinity, which rendered as a ratio and serialized into the results file as null. run.ts hands each scenario's repetitions to engine.assemble(), so it no longer names a sample shape it cannot know: the unknown[] store, the cast onto it, and the second designated-repetition pick are gone. renderResults formats the retained slope through formatCell like every other cell, instead of hand-rolling the one column formatCell could not express.
report.test.ts checked the renderer with toContain on individual lines, which could not see the thing the module exists to produce: an aligned table, and the notes that travel beside a ratio. The cases are now inline snapshots of the joined output, so a diff shows the report as a reader would see it. The fixtures grew to match: a series engine and a one-shot engine side by side, plus a skip and a failure, because the column widths are computed across the whole table and a status line replaces a row rather than joining one. Adds the two comparability verdicts nothing rendered before, next-documents-less and next-resolves-less. Writing the output down also showed that every row carried trailing spaces, since the last column is padded like the rest. Rows are trimmed now.
process.exit truncates a piped stderr, which is the one case where the per-engine failure reasons are actually being read. Match the pattern the top-level catch handler already uses. Also stop the intro promising a CI tier that gates, since the same document says a few sections later that the gate does not exist yet.
Windows unit tests failed when recast.print emitted CRLF while the assertion expected LF. The expected/received strings looked identical in the log. Normalize printed code to LF in the shared test helpers. Co-authored-by: Cursor <cursoragent@cursor.com>
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 7, 2026 13:07
5f24b83 to
4f3b7fc
Compare
Tanstack: Wait for router to load before rendering
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 7, 2026 13:39
4f3b7fc to
82d4a8d
Compare
…rovider-skeleton Vue: Add story-docs provider skeleton
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 7, 2026 13:48
82d4a8d to
f724d93
Compare
…s-crlf Build: Normalize CRLF in story-shape print assertions
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 7, 2026 14:00
f724d93 to
259d0fc
Compare
…nning-compodoc-on-demand Angular-Vite: Run Compodoc on demand
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 7, 2026 14:17
259d0fc to
11c4621
Compare
React's snippet generator grew several helpers that are not React-specific:
resolving a `render` identifier to the function it names, telling an absent
`render` apart from an unreadable one, and reading CSF2's `Story.args = {}`
assignment form. The Angular and Vue providers need the same answers.
They move into `csf-tools/story-shape` and React imports them back, so its
snapshots are what proves the move is behaviour-preserving. `propertyValue`
and `returnedObjectExpression` join them for the providers stacked on top.
…hape-helpers Core: Share the CSF story-shape helpers snippet generators need
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 8, 2026 18:33
11c4621 to
89e832b
Compare
The single bullet under Code Authoring Principles said comments should explain why rather than narrate an investigation, which left most of the decisions open. It did not say when a comment is warranted at all, it said nothing about JSDoc, and agents kept producing `@param`/`@returns` that restate the TypeScript signature, ASCII section banners, and change narration that git history already carries. Replaces the bullet with a section stating the two cases that justify a comment, the shape of public-API JSDoc, and an explicit list of what never to write.
AGENTS.md is read in full on every session, so a 40-line rule that only matters when you are about to write a comment belongs one hop away. The section keeps the two-sentence summary and links out; the detail moves to `.agents/guidelines/comments-and-jsdoc.md`, next to the skills already living under `.agents/`.
Measured against the Angular docgen stack after a cleanup pass that applied the previous wording: one comment per seven lines of source, 224 JSDoc blocks, six of them on private members, and eighteen where the docblock was longer than the code it described (worst: eleven lines of prose on a one-line body). Every rule in the previous version was a judgement the author makes about their own writing, and "internal, non-exported helpers get no JSDoc" does not read as covering a private method on an exported class. Replaces them with four rules that can be applied without deciding whether the sentence is any good: JSDoc only for what a consumer can import, a comment never longer than its code, nothing on private members, and no JSDoc in tests. Reframes the "why" escape hatch as a deletion test whose output is one sentence.
The blanket ban went too far. A private method implementing a subtle algorithm, or holding a non-obvious invariant, is worth a docblock, and banning those outright trades one failure mode for another. Keeps the pressure without the ban: the deletion test still applies, and so does the rule that a comment may not outgrow its code. What changes is that "rename or split it instead" becomes the usual better answer rather than the only permitted one.
Co-authored-by: Valentin Palkovic <dev@valentinpalkovic.dev>
…-guidance Build: Give AGENTS.md a real comments and JSDoc rule
storybook-bot
force-pushed
the
version-non-patch-from-10.6.0-alpha.4
branch
from
August 10, 2026 07:34
89e832b to
3049590
Compare
ndelangen
approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is an automated pull request that bumps the version from `10.6.0-alpha.4` to `10.6.0-alpha.5`.
Once this pull request is merged, it will trigger a new release of version `10.6.0-alpha.5`.
If you're not a core maintainer with permissions to release you can ignore this pull request.
To do
Before merging the PR, there are a few QA steps to go through:
And for each change below:
This is a list of all the PRs merged and commits pushed directly to `next`, that will be part of this release:
If you've made any changes doing the above QA (change PR titles, revert PRs), manually trigger a re-generation of this PR with this workflow and wait for it to finish. It will wipe your progress in this to do, which is expected.
Feel free to manually commit any changes necessary to this branch after you've done the last re-generation, following the Make Manual Changes section in the docs, especially if you're making changes to the changelog.
When everything above is done:
Generated changelog
10.6.0-alpha.5