Skip to content

fix: rebase onto v4 and apply Deno formatting#1

Closed
taras wants to merge 136 commits intojoshamaju:effect-benchmarkfrom
thefrontside:fix/effect-benchmark-rebase
Closed

fix: rebase onto v4 and apply Deno formatting#1
taras wants to merge 136 commits intojoshamaju:effect-benchmarkfrom
thefrontside:fix/effect-benchmark-rebase

Conversation

@taras
Copy link
Copy Markdown

@taras taras commented Feb 14, 2026

Summary

This PR fixes CI failures for your Effect benchmark PR (thefrontside#981 on thefrontside/effection) by:

  1. Rebasing onto current v4 branch - Your branch was 133 commits behind v4, which meant it was missing the updated deno.json that excludes tasks/ from linting
  2. Applying Deno formatting - The formatting was done with Prettier instead of deno fmt, causing the formatting check to fail
  3. Updating scenario signatures - All benchmark scenarios now accept the optional exit callback parameter that your startup benchmarks introduced

Changes

  • Rebased all commits onto origin/v4 (40faacd)
  • Ran deno fmt to fix formatting
  • Updated existing scenario files to accept (depth, _exit) parameter to match the new scenario() function signature

After merging

Once you merge this into your effect-benchmark branch, your PR thefrontside#981 should pass CI. You may want to squash these commits or rebase interactively to clean up the history before the maintainers merge.


Thanks for contributing the Effect benchmark! 🎉

cowboyd and others added 30 commits February 28, 2025 15:57
Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Co-authored-by: Charles Lowell <cowboyd@frontside.com>
Adding until to v4 to replace call(promise)
- Fixed number formatting in thinking-in-effection.mdx (removed commas in timeout values)
- Removed duplicate section in async-rosetta-stone.mdx
- Fixed URL format in Changelog.md
- Fixed spacing typos in Changelog.md ("w ith" → "with", "iterat or" → "iterator")

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Added all PRs merged between alpha.0 and alpha.8 tags
- Organized entries by their respective alpha versions
- Added initial placeholder for alpha.0

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
When you call coroutine return, any instructions that are currently
enqueued for it are discarded.
- Fixed number formatting in thinking-in-effection.mdx (removed commas in timeout values)
- Removed duplicate section in async-rosetta-stone.mdx
- Fixed URL format in Changelog.md
- Fixed spacing typos in Changelog.md ("w ith" → "with", "iterat or" → "iterator")

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Now that we have our very own `until()` function that can convert any
promise into an operation, we don't need the the `$await()` helper
that the tests were using that does the exact same thing.

Kill it with fire!
docs: fix additional spelling and formatting issues
docs: update changelog with v4.0.0-alpha entries organized by version
jbolda and others added 28 commits December 23, 2025 14:51
…mode (#1068)

* Fix menu dark mode in responsive

* Added a bit of padding to the footer and changed v4 link

* Formatted MD files

* Added until to faq

* Added until to faq

* Fix #1058 Guide navigation links don't work if the same page does not exist on other guide.
* Add llms.txt and llms-full.txt for LLM context

Following the llms.txt convention (https://llmstxt.org), add two files to help
LLMs understand and assist with Effection code:

- llms.txt (~700 tokens): Minimal file with progressive disclosure approach,
  includes core mental models, quick reference table, and links to docs
- llms-full.txt (~2,800 tokens): Comprehensive embedded content from all key
  documentation, removes need for multiple file reads

Both files follow context engineering principles from Anthropic's guide:
- Token efficiency: high-signal information only
- Progressive disclosure: llms.txt uses file paths for exploration
- Right altitude: specific heuristics, not brittle rules
- Canonical examples: show both wrong (async/await) and right (Effection)

Key improvements:
- Fixed Promise/Operation conversion guidance (until() vs run() contexts)
- Removed duplication while maintaining all critical information
- Clear gotchas section with correct/incorrect patterns

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* De-emphasize action() in favor of withResolvers()

- Changed "The Two Primitives" to "Callback Integration" section
- Positioned withResolvers() as primary callback integration method
- Clarified action() as specialized for cleanup requirements
- Removed action() REQUIRES cleanup gotcha (reduced emphasis)
- Renumbered remaining gotchas (2-5)
- Updated Quick Reference to show withResolvers() first

Most callback scenarios use withResolvers(). action() is specifically
for when you need guaranteed cleanup via finally function.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Refactor llms.txt for better readability and consistency

- Changed "Key Mental Models" to "Key Concepts" with concise descriptions
- Removed code examples from Key Concepts section (available in llms-full.txt)
- Updated all documentation links to use markdown link format with descriptions as link text
- Added scope.mdx and context.mdx to "Learn more" section
- Expanded API Reference with complete list of important files using descriptive links
- Removed redundant "Guidance for LLMs" section (content covered by API Reference)
- Removed duplicate llms-full.txt reference at top of Documentation section
- Updated channel.ts description to "Create streams for use in operations"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* Added scoped

* Added suspend, on/once, and Result to llms-full.txt

* Added interval, createQueue, exit, subscribe/stream

* Reorganized content based on priority

* Added short version of llms.txt

* Add llms.txt symlinks to www/assets for website serving

Symlinks allow llms.txt and llms-full.txt to be served at the website
root (frontside.com/effection/llms.txt) while keeping the source files
in the repo root for easy editing.

* Integrate llms.txt into website and README

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
We do not want Google, Bing, and friends crawling these websites and
indexing them independently of the main website. This happened to us
recently when somehow the top google search result for "Effection
JavasScript" yields to `https://effection-www.deno.dev` as its first
result.

This sets up a "canonical" url to point to the main effection site. It
is mapped to whatever the current path is rebased onto
`https://frontside.com/effection`
Our absolute url handling was broken for twitter and go:url images
This allows IDEs to use the Aider coding client along with env files
without creating detritus inside the repo.
* Use effectionx packages from jsr to stay locked on v3

* Add monorepo adapter for Node/PNPM workspaces

Implement a new package/workspace abstraction that supports both Deno
and Node/PNPM monorepos, enabling the website to read package metadata
from effectionx which has migrated from Deno to Node/PNPM.

New modules:
- lib/registries/ - Registry abstractions for JSR and npm
- lib/package/ - Package representation for Deno and Node projects
- lib/workspaces/ - Workspace detection and package enumeration

Key changes:
- Auto-detect workspace type (deno.json vs pnpm-workspace.yaml)
- Parse Node package.json exports with conditional export support
- Filter hidden packages (e.g., .internal) from listings
- Update routes and components to use new useWorkspaces API
- Add @std/yaml dependency for parsing pnpm-workspace.yaml

* Remove JSR references from effectionx UI

Since effectionx packages are no longer published to JSR, remove all
JSR-related fetching and display from the extensions pages.

Changes:
- Remove getJSRDetails() calls, use package manifest data instead
- Remove JSR badge from package headers (keep npm badge only)
- Delete ScoreCard component (was entirely JSR-focused)
- Remove JSR properties from Package interface
- Clean up unused imports and JSR-specific types

* Fix semver OR range parsing in npm specifiers

Package.json peerDependencies can use OR ranges like '^3 || ^4' which
are not valid in Deno npm: specifiers. Sanitize version strings by
taking the first part of OR ranges.

Also handle workspace: protocol versions by converting to '*'.
When a task was halted, the task itself would stop executing but its
associated scope remained alive, causing a memory leak.

This fix makes the `halt()` operation not do any teardown itself, but
instead it delegates to its own scope's `destroy()`. That way, not
only is the task execution halted, but every scope in its entire tree
is also destroyed. This ensures that all resources are cleaned up on
`Task.halt()`.

Note:

Fixing this did break one of the `each()` tests which
relied on this bugged behavior, so the implementation has been updated
to use a simple spawn instead of a resource.

Also, it broke a dubious behavior which is that a child could halt its
parent:

```ts
let task: Task<void> = run(function* root() {
  yield* sleep(0);
  yield* spawn(function* child() {
    yield* task.halt();
  });
  yield* suspend();
});
```

I believe that the intuitive behavior here is deadlock, which is what
now happens. In other words, the child computation uses scope hacking
to capture a reference to its parent, and then depends on that
parent's shutdown, which depends on waiting for the child to complete,
which requires the child to shutdown

I think we can put in a special guard for this at some point and at
least throw an exception here when we detect such an obvious deadlock,
but I don't think it should hold up fixing an egregious memory leak
such as this.
We need to have 1:1 equivalance between a scope closing and a task
settling.

- when a task errors or completes, its scope must be destroyed
- when a task is halted, its scope must be destroyed.

By the same token, when scope is destroyed, its task must halt (if
there is such a task).

With #1081, we established the scope destroy -> task halt
relationship, and now we need to establish the task finalized -> scope
destroyed relatioship.

This moves all of the finalization logic of the task from the actual
coroutine running the task into the scope destructor. Then, the
coroutine itself _explicitly_ destroys the scope as its last official
act. To make this work, we hid need to make Delimiter.close()
re-entrant, so that if it is called from mulitple places it is
idempotent and has the same result.
We have a long history of prefering `let` over `const` for local
function variable bindfings, but we haven't been able to use the
`eslint` plugin because Effection is developed with Deno. However,
with the release of Deno 2.2, there is the capability to write linting
plugins.

This ports over the eslint plugin to Deno, installs it in our
codebase, and makes the corrections that it found
* 🚨 lint and format www/

The www/ webapp was a bit of wild west because linting and formatting
were turned off.

This turns it back on and fixes and formats the code. There were two
files that were causing `deno lint` to crash, so they've been excluded.

- routes/guides-route.tsx
- components/api/api-page.tsx

We can follow up with the deno team to find out why these are crashing
later.

* Add tsx, jsx, svg, and css line-endings in .gitattributes
We're going to end up wrapping unified APIs around most Effection
functions so that they can be decorated with middleware. As such, there
is no need to have separate code paths for Scope.run() and
Scope.spawn() since they end up calling the same thing under the hood.

This has `spawn()`` delegate to `Scope.run()` so that the apis can be
unified and wrapped as one. In other words, wraping `Scope.run()` is
the same as wrapping `spawn()`.
There was a regression introduced with
#1081 such that when a task was
halted, its resources were being shut down _before_ the task body was
finished. This resulted in violation of the structured concurrency
guarantees that required everything in scope to remain alive until
after the body of the task is fully executed. This is because the body
of the operation may use resources that are in scope throughout the
_entirety_ of the operation. For example, in the following code, the
finally block of the main operation requires the `child` task to be
fully complete.

```ts
let task = run(function* () {
  let synchronize = withResolvers<void>();
  let child = yield* spawn(() => synchronize.operation);
  try {
    yield* suspend();
  } finally {
    synchronize.resolve();
    yield* child;
  }
});

await task.halt() // deadlock!
```

Because the main task dependes on `child`, child needs to be active
and only halted _after_ the main task is complete, _not_ before. (in
this case the antecedent resource is a simple spawned `Task`, but it
could be anything; a database connection, file handle, whatever...).
Only after all references to the resource have become inactive can the
resource be destroyed.

When destroying a scope then, we need to first destroy oneself by
interrupting effect iteration, and only once that is complete, destroy
child scopes. This is accomplished by not reversing scope destructors.

It turns out this regression was actually being surfaced by the an
existing testcase which we commented out 😬. Another test has been
added to ensure the proper shutdown order is preserved when explicitly
halting.

> Note: in the future we will simplify this process even further by
removing the scope "destructor" mechanism altogether and replacing it
with middleware. This will replace fiddling with the order of
registration and execution with explicit declaration of sequence of
operations as "around" or "within" other operations.
* ✨ add blog to effection website

Add a blog section to the Effection website following the same patterns
as frontside.com/blog. Features include:

- Blog index page at /blog with featured latest post
- Individual post pages at /blog/:slug/
- Tag filtering at /blog/tags/:tag
- RSS 2.0 feed at /blog/feed.xml
- MDX support with frontmatter for post metadata
- Author avatars and date display
- Dark mode support
- Pagefind search integration

* 🎨 apply formatting

* ✨ add author avatars for charles, jacob, and taras

* 🚨 fix lint errors

* 🎨 fix formatting

* ♻️ refactor RSS feed to use @libs/xml builder

Addresses PR feedback to use the XML builder library instead of
string templates for safer XML generation.
* 📝 add structured concurrency explainer blog post

* 🚨 fmt blog post

* ✍️ make structured concurrency post more conversational

* ✏️ tweak wording: built-in async model

* 🖼️ add featured image for structured concurrency post

* 🔗 clarify Java 21 structured concurrency + Go errgroup

* 📝 format external links as markdown

* 🛠️ fix blog image path by making it post-relative

* 🚨 fmt blog image svg

* 🖼️ fix legend text overflow in blog image

* Fixed formatting on minimized image

* 🖼️ widen effect pills so text fits

* ✍️ integrate PR feedback on narrative and graphic

* 🔗 link structured concurrency classic post

* ✍️ strengthen structured concurrency framing

* ✍️ clarify structured concurrency definition

* ✍️ tighten narrative, fix typos, add code example, deduplicate links

* 🖼️ restore missing container rects, filters, and defs in blog image

* ✍️ tighten blog post per voice profile, add www/AGENTS.md writing guide

* ✍️ remove redundant air/water metaphor in opening paragraph

* ✍️ add inline code example, strengthen async critique, update Go reference and links

* ✍️ echo Wild West metaphor in async section to close narrative loop

* ✍️ add concrete examples of developers normalizing broken async

* ✍️ strengthen JS gap framing, cross-reference blog post from docs

* 🖼️ add dark mode support to blog SVG via prefers-color-scheme, create reusable template

* ✍️ cut context/streams tangent for a tighter ending

* 🖼️ redesign blog image as before/after: Promises leak vs Effection contains

* 🖼️ fix title overlap, replace leak lines with overflowing boxes vs contained boxes

* replace suspend() with sleep(30_000) in code examples, fmt SVG

* reference frontside.com style guide from Effection blog AGENTS.md

* fix arrow to extend from 'scope ends' down to 'halted + cleaned up'

* add stroke to check-text class so arrow line/path render visibly

* improve structured concurrency post pacing and clarify JS async cleanup

* move arrow up 20px and use blue color distinct from check-text

* move scope-ends label down to avoid overlapping parent scope box

* add inline SVG plugin to replace <img> with inline SVG markup for responsive blog images

* fix: namespace SVG CSS classes with svg- prefix to prevent collision with page elements

The inline SVG plugin injects the featured image SVG into the page DOM,
causing its generic CSS class names (.grid, .card, .title, etc.) to leak
into the page scope. The .grid { opacity: 0.25 } rule was hitting every
<pre class="language-js grid"> code block, rendering them nearly invisible.

Prefix all SVG CSS classes with svg- (e.g. .svg-grid, .svg-card) in both
the blog post image and the reusable template. Also adds dark:border for
SVG images on blog list/tag pages and documents the prefix convention in
www/AGENTS.md.

* update blog post and SVG image title to 'Why JavaScript Needs Structured Concurrency'

* add PR template and update blog post title to 'Why JavaScript Needs Structured Concurrency'

- Add .github/pull_request_template.md (Motivation + Approach)
- Document PR template usage in root AGENTS.md
- Update blog post title and SVG image title/aria-label to match

* update blog image template with latest SVG layout

* improve structured concurrency post conclusion and clarify generator-based approach

* refine structured concurrency post conclusion wording

* refine structured concurrency post: ground scope + strengthen transitions

* tighten blog post: cut redundant code example, merge duplicate paragraphs, reframe generators as the missed opportunity

* style: normalize em-dash spacing, capitalization, and paragraph breaks

* soften async/await framing: describe missing semantics without attributing intent

* move missing-semantics paragraph after code example for better narrative flow

* harden post for HN/reddit: clarify scope, preempt promise bikeshedding, compress language list, add bridge lines

* fix consistency: rephrase duplicate parent-child framing, align code example with opening hook

* add audience section to blog writing guide: HN and r/javascript
)

* fix blog wording: separate await vs fire-and-forget failure modes

* refine await paragraph: Promise creates the fork, await vs move-on are both bad
- Run deno fmt to fix Prettier-style formatting
- Update all benchmark scenarios to accept optional exit callback parameter
- Fixes CI formatting check failures
@taras
Copy link
Copy Markdown
Author

taras commented Feb 14, 2026

Closing this PR - it incorrectly included all v4 upstream changes. Will create a new PR with just the formatting fixes.

@taras taras closed this Feb 14, 2026
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.

5 participants