Skip to content

docs(signals): lean posture landed — contract answers, engine-cost cap 14 → 4 - #3654

Merged
ryansolid merged 1 commit into
nextfrom
lean-posture-followup
Sep 25, 2026
Merged

ryansolid merged 1 commit into
nextfrom
lean-posture-followup

Conversation

@ryansolid

Copy link
Copy Markdown
Member

Closes out the lean-posture proposal in documentation/plans/responsiveness-findings-plan.md §Cost — "Lean posture — proposal, needs a decision", landed with #3613 and implemented by #3644. #3644 shipped the gate and the checks off the frame; this PR records the decision and the contract answers in the plan so they are not rediscovered, fills the documentation/test gaps, and does the tripwire ratchet the #3613 cap comment asked for. Docs, JSDoc and tests only.

The decision

Document, no option. There is no enable({ reruns: true }): a consumer that wants re-run records subscribes to rerun or imports a fold — the same "subscribing is what turns them on" the timeline records already had — so the engine has one gate rather than two that compose. The gate as shipped: wantsRerun() = log || folds.length > 0 || OBSERVE.records.observed("rerun"), read at recomputeStart (it decides whether the dep snapshot the record's subscription diff needs is captured; not recomputeEnd as proposed — the snapshot is the first cost) and honoured at recordRerun.

Contract answers

Question from the proposal As landed Pinned
history("rerun") on a lean engine Empty for runs made while nothing wanted a record; holds every record from the moment something did (the run count kept meanwhile is on the first record's nodeRuns). Documented on Attribution.history, RecordTypes, 08-dev-diagnostics.md. attribution-lean-gate.test.ts
why() / subscriptions() why(node) is a view of that buffer and shares its gate (a node whose runs left no record has no nodeId). subscriptions(node) was never a record reader — it walks live _deps, so it answers with or without an audience and with the engine disabled. JSDoc added on both; doc lines added. new test
OBSERVE.records.subscribe("rerun", …) turns records on From the next run start; off again on unsubscribe; log: true and a registered fold do the same. The bare attribution.subscribe(listener) went with #3644 — no untyped form to gate. existing lean-gate tests
Checks read the frame, not the record checkEffectCycle, checkRelayTear, checkHotRuns, checkHotTime, checkWastedRecompute (frame.start, phase, changed, selfMs, causes), checkDepWidth all run in recordRerun before the prevDeps === null return. HOT_SCOPE existing; new test for WASTED_RECOMPUTE without a record
@sentry/solid-2 as a lean consumer Follow-up in getsentry/sentry-javascript#24517 (drop the rerun subscription; InteractionEvent.runs/runMs and the HOT_SCOPE_*/WASTED_RECOMPUTE findings cover its per-interaction hot list). Performance Tracks stays a full consumer by design. —

Tripwire: cap 14 → 4

attribution-engine-cost.test.ts re-measured 2026-09-24 on the observe artifacts under vitest (M-series, best-of-5 interleaved), six runs: folded 1.98–2.14×, listened 1.91–2.11×, lean 1.71–1.90×. On the engine after rebasing onto #3650 (three more runs): folded 1.99 / 2.42 / 2.12×, listened 1.93–2.07×, lean 1.74–2.07×. The #3613 engine, re-measured by the same harness beside this one, was ~2.5–2.8×; the section's original 490/55 ns ≈ 9× table came from a different flush-per-write micro-harness and is not comparable, so the tripwire's numbers are the baseline from here.

Caveat recorded in the cap comment: the ratio is harness-sensitive. A bare node process (no vitest worker transform) measures idle at ~2.8 ms and the folded engine at ~3.1–3.7×, so a faster idle build raises the ratio without the engine changing.

Cap 4: ~85–100% headroom over the folded baseline — trips when the engine costs roughly double what it does today per re-run, the same discipline as observe-idle-cost's 1.25 over 1.03–1.09. The plan's ## Cost bullet ("cap 14 against a measured ~10") is updated to match.

Tests

  • attribution-lean-gate.test.ts: 8/8 (6 existing + why()/subscriptions() on a lean engine, WASTED_RECOMPUTE without a record).
  • attribution-engine-cost.test.ts at cap 4: 3/3 before the rebase, 3/3 after.
  • Full @solidjs/signals suite on the rebased branch: 230 files, 3720 passed / 2 skipped (3698 on the pre-rebase base).
  • observe-idle-cost, attribution-wasted-recompute, attribution suites green.

Public API changes

None — JSDoc, docs and tests only.

Also

The #3644 PR body was updated to cite the plan section and point here for the ratchet.

…4 → 4

Closes out the lean-posture proposal in
documentation/plans/responsiveness-findings-plan.md §Cost (landed with
with the gate as shipped — `wantsRerun() = log || folds.length > 0 ||
OBSERVE.records.observed("rerun")`, read at recomputeStart, honoured at
recordRerun — and the four contract questions answered:

- history("rerun") is empty for runs made while nothing wanted a record
  and holds every record from the moment something did; why() is a view
  of that buffer and shares its gate; subscriptions() reads the graph and
  is unaffected. No enable({ reruns: true }) — document, no option.
- OBSERVE.records.subscribe("rerun", …) turns record-building on from the
  next run start and off on unsubscribe; log and a registered fold do the
  same. The bare attribution.subscribe went with #3644.
- The checks read the frame, not the record: checkEffectCycle,
  checkRelayTear, checkHotRuns, checkHotTime, checkWastedRecompute,
  checkDepWidth all run before the gate.
- @sentry/solid-2 dropping its rerun subscription is the follow-up in
  getsentry/sentry-javascript#24517.

JSDoc on why()/subscriptions() and the diagnostics doc lines say the
same; attribution-lean-gate.test.ts pins WASTED_RECOMPUTE without a
record and why()/subscriptions() on a lean engine.

Tripwire (attribution-engine-cost.test.ts) re-measured 2026-09-24 under
vitest, six runs: folded 1.98–2.14x, listened 1.91–2.11x, lean
1.71–1.90x. The section's 490/55 ns ≈ 9x table was a different
flush-per-write micro-harness; the tripwire's numbers are the baseline
from here. Cap 14 → 4 (~85–100% headroom; trips when the engine costs
roughly double what it does today).

Co-Authored-By: Claude via Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@changeset-bot

changeset-bot Bot commented Sep 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a130c61

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 11 packages
Name Type
@solidjs/signals Patch
test-integration Patch
@solidjs/web Patch
@solidjs/babel-plugin Patch
@solidjs/compiler Patch
@solidjs/diagnostics Patch
@solidjs/element Patch
@solidjs/h Patch
@solidjs/html Patch
solid-js Patch
@solidjs/universal Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 36110683736

Coverage remained the same at 73.611%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1134
Covered Lines: 883
Line Coverage: 77.87%
Relevant Branches: 882
Covered Branches: 601
Branch Coverage: 68.14%
Branches in Coverage %: Yes
Coverage Strength: 25.36 hits per line

💛 - Coveralls

@codspeed

codspeed Bot commented Sep 25, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 176 untouched benchmarks
⏩ 3 skipped benchmarks1


Comparing lean-posture-followup (a130c61) with next (c8a9d23)

Open in CodSpeed

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@ryansolid
ryansolid merged commit 5f28e7d into next Sep 25, 2026
7 checks passed
@ryansolid
ryansolid deleted the lean-posture-followup branch September 25, 2026 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants