<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Piyush Chauhan</title>
    <description>The latest articles on DEV Community by Piyush Chauhan (@frorning).</description>
    <link>https://dev.to/frorning</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F34577%2F0f35e688-bd8c-49e7-8c53-51d1ca4f2819.jpg</url>
      <title>DEV Community: Piyush Chauhan</title>
      <link>https://dev.to/frorning</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/frorning"/>
    <language>en</language>
    <item>
      <title>Why big monorepos get slow, and what Rush.js + Sparo do about it</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Fri, 16 Oct 2026 11:40:20 +0000</pubDate>
      <link>https://dev.to/frorning/why-big-monorepos-get-slow-and-what-rushjs-sparo-do-about-it-239p</link>
      <guid>https://dev.to/frorning/why-big-monorepos-get-slow-and-what-rushjs-sparo-do-about-it-239p</guid>
      <description>&lt;p&gt;&lt;em&gt;How Rush.js, PNPM workspaces, and Sparo's sparse checkout attack the three things that slow big monorepos: Git, install, and build&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A big monorepo gets slow in three places that fail independently: Git, the dependency install, and the build. A fix for one does nothing for the others.&lt;/li&gt;
&lt;li&gt;Sparse checkout made a test repo of 407 projects clone twice as fast, halved &lt;code&gt;.git&lt;/code&gt;, and cut &lt;code&gt;git status&lt;/code&gt; from 76 ms to 13 ms.&lt;/li&gt;
&lt;li&gt;Sparse checkout did not speed up the install at all, because Rush cannot install from a checkout that is missing project folders.&lt;/li&gt;
&lt;li&gt;Selection flags cut a leaf-file rebuild from 407 projects to 4. A change to a widely-used package still rebuilds everything, because that is what the graph says.&lt;/li&gt;
&lt;li&gt;Most of this assumes you use npm, pnpm, or yarn. If you do not, the Rush half of the article does not apply to you.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Picture a new hire's first day. They run &lt;code&gt;git clone&lt;/code&gt; and wait ten to forty minutes, watching the object counter climb past a million.&lt;/p&gt;

&lt;p&gt;Then the install runs. A lockfile with tens of thousands of entries resolves, and &lt;code&gt;node_modules&lt;/code&gt; grows past a gigabyte. By lunch they have not opened an editor.&lt;/p&gt;

&lt;p&gt;On day two they change one line in one package. CI rebuilds the whole repository to check it.&lt;/p&gt;

&lt;p&gt;Three separate costs produced that day, and each one scales with something different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Git&lt;/strong&gt;: the bytes of history, and the number of files in your working tree. Not which of those files you edit. You see it in clone time, pack size, &lt;code&gt;git status&lt;/code&gt;, and &lt;code&gt;checkout&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt;: the number of third-party packages, and the size of the dependency graph the package manager must resolve and write. You see it in &lt;code&gt;node_modules&lt;/code&gt; size and install wall time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build&lt;/strong&gt;: the number of projects, and whether you rebuild ones that did not change. You see it in "it rebuilt everything", and in CI minutes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why one fix never covers all three. A sparse checkout does not make an install faster. A build cache does not make &lt;code&gt;git status&lt;/code&gt; faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyzytvju5wmp4cyfwfvo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkyzytvju5wmp4cyfwfvo.png" alt="Three monorepo bottlenecks: Git, install, and build/test, with the tool that addresses each" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The repo this is grounded in
&lt;/h2&gt;

&lt;p&gt;Everything below is checked against a small tutorial repo. It is a toy hotel-booking app with a NestJS API and a TanStack Start frontend. The domain logic is thin on purpose. The repo exists to demonstrate the tooling.&lt;/p&gt;

&lt;p&gt;The repo has seven projects, all registered by hand in &lt;code&gt;rush.json&lt;/code&gt;. Two are apps (&lt;code&gt;@hotel/api&lt;/code&gt; and &lt;code&gt;@hotel/web&lt;/code&gt;). Five are packages (&lt;code&gt;@hotel/ui&lt;/code&gt;, &lt;code&gt;@hotel/shared-types&lt;/code&gt;, &lt;code&gt;@hotel/api-client&lt;/code&gt;, &lt;code&gt;@hotel/eslint-config&lt;/code&gt;, and &lt;code&gt;@hotel/typescript-config&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The runtime edges are &lt;code&gt;web → ui&lt;/code&gt;, &lt;code&gt;web → api-client&lt;/code&gt;, &lt;code&gt;web → shared-types&lt;/code&gt;, &lt;code&gt;api-client → shared-types&lt;/code&gt;, and &lt;code&gt;api → shared-types&lt;/code&gt;. Each project also lists both config packages as dev dependencies. Dev-only edges therefore outnumber runtime edges two to one, which matters later when we select projects by what changed.&lt;/p&gt;

&lt;p&gt;The toolchain is pinned: Rush 5.181.0, PNPM 11.5.1, and Node in the range &lt;code&gt;&amp;gt;=20.9.0 &amp;lt;25.0.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The repo is 120 tracked files with a 1.1 MB &lt;code&gt;.git&lt;/code&gt; directory. At that size sparse checkout buys you nothing, so this repo cannot tell you whether any of it works at scale. That is why the numbers later come from a synthetic scale-up instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sparo: make Git deliver less
&lt;/h2&gt;

&lt;p&gt;Sparo is a small wrapper around two Git features. To understand the wrapper, you need to know what it wraps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Partial clone: download fewer objects
&lt;/h3&gt;

&lt;p&gt;A normal &lt;code&gt;git clone&lt;/code&gt; downloads every commit, every directory listing, and every version of every file. Most of that you will never read.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git clone --filter=blob:none&lt;/code&gt; asks the server for a subset. You still get all the commits and all the directory listings. What you skip is file contents. Git fetches a file's contents later, on demand, from a remote it marks as a &lt;strong&gt;promisor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That deferral has a price. Git's own documentation says dynamic fetching "tends to be slow as objects are fetched one at a time". A &lt;code&gt;git checkout&lt;/code&gt; fetches everything it needs in one batch, so a checkout is fine. A script that reads arbitrary files out of history is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sparse checkout: write fewer files
&lt;/h3&gt;

&lt;p&gt;Partial clone reduces what you download. Sparse checkout reduces what you write to disk. You give Git a list of directories, and Git leaves everything else out of the working tree.&lt;/p&gt;

&lt;p&gt;The list goes in one of two formats. &lt;strong&gt;Cone mode&lt;/strong&gt; is the default, and it takes directories: everything under a directory you name, plus the files at the top level. &lt;strong&gt;Non-cone mode&lt;/strong&gt; takes gitignore-style patterns. It is deprecated, it costs O(N×M) pattern matches, and it does not work with a sparse index.&lt;/p&gt;

&lt;p&gt;You can speed up the resulting tree further. The &lt;strong&gt;sparse index&lt;/strong&gt; (&lt;code&gt;index.sparse&lt;/code&gt;) stores whole directories as single entries instead of one entry per file. That shrinks the index and speeds up &lt;code&gt;git status&lt;/code&gt; and &lt;code&gt;git add&lt;/code&gt;. Git only writes it when you pass &lt;code&gt;--sparse-index&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;file system monitor&lt;/strong&gt; (&lt;code&gt;core.fsmonitor&lt;/code&gt;) lets Git find modified files without checking every one on disk. It works natively on Windows and macOS. Linux support arrived in Git 2.55.0 in June 2026.&lt;/p&gt;

&lt;p&gt;Two warnings about sparse checkout. It removes files that are already on disk, and it will refuse to proceed if a file it wants to remove has unstaged changes. Resolve those, then run &lt;code&gt;git sparse-checkout reapply&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Profiles: name the set you want
&lt;/h3&gt;

&lt;p&gt;Hand-writing sparse directory lists is worse than it sounds. The list changes as the repo grows, and every developer would maintain their own. Sparo replaces the list with a committed file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sparo clone&lt;/code&gt; differs from &lt;code&gt;git clone&lt;/code&gt; in four documented ways. It fetches only the default branch. It enables blobless partial clone. It checks out the &lt;strong&gt;skeleton&lt;/strong&gt; folders. It configures cone mode. It also applies some Git settings for you, including fsmonitor, the untracked cache, &lt;code&gt;feature.manyFiles&lt;/code&gt;, &lt;code&gt;fetch.prune&lt;/code&gt;, and &lt;code&gt;pull.rebase&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;profile&lt;/strong&gt; lives at &lt;code&gt;common/sparo-profiles/&amp;lt;name&amp;gt;.json&lt;/code&gt; and is committed to Git, so it is versioned with the branch it applies to. It has four fields: &lt;code&gt;$schema&lt;/code&gt;, &lt;code&gt;selections&lt;/code&gt;, &lt;code&gt;includeFolders&lt;/code&gt;, and &lt;code&gt;excludeFolders&lt;/code&gt;. Each entry in &lt;code&gt;selections&lt;/code&gt; is a selector and an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://developer.microsoft.com/json-schemas/sparo/v1/sparo-profile.schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"selections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--to"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@hotel/web"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The selectors are Rush's project selectors. So &lt;code&gt;--to&lt;/code&gt;, &lt;code&gt;--from&lt;/code&gt;, and &lt;code&gt;--impacted-by&lt;/code&gt; all work here, and you can list several. Multiple selections union together. &lt;code&gt;excludeFolders&lt;/code&gt; beats &lt;code&gt;includeFolders&lt;/code&gt; and beats selections.&lt;/p&gt;

&lt;p&gt;Because the selector is Rush's, the profile above materializes exactly the projects that &lt;code&gt;rush build --to @hotel/web&lt;/code&gt; would build: the app plus everything it depends on.&lt;/p&gt;

&lt;p&gt;From a fresh clone the workflow is two commands: &lt;code&gt;sparo clone &amp;lt;remote-url&amp;gt;&lt;/code&gt;, then &lt;code&gt;sparo checkout --profile web&lt;/code&gt;. Two related commands are worth knowing. &lt;code&gt;sparo checkout --to&lt;/code&gt; and &lt;code&gt;--from&lt;/code&gt; add to the profiles already recorded instead of replacing them, and &lt;code&gt;--no-profile&lt;/code&gt; clears the recording.&lt;/p&gt;

&lt;p&gt;One part never gets stripped. Sparo calls it the &lt;strong&gt;skeleton&lt;/strong&gt;, and it includes the whole &lt;code&gt;common/&lt;/code&gt; directory. That matters, because &lt;code&gt;common/&lt;/code&gt; holds Rush's config, its scripts, and its autoinstallers. No profile can leave you with a checkout that cannot install or build.&lt;/p&gt;

&lt;p&gt;One caveat about the profiles in this repo. Both were written by hand, and their &lt;code&gt;$schema&lt;/code&gt; points at a Microsoft-hosted URL. I checked that URL on 2026-10-16 and it returned HTTP 404. Sparo's own published schema at &lt;code&gt;https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json&lt;/code&gt; returned 200. The Microsoft URL is not an old location; it does not exist, and Sparo's docs never mention it. Run &lt;code&gt;sparo init-profile --profile web&lt;/code&gt; to generate a template from your installed Sparo version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkepj9hc8jzyafenmoqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkepj9hc8jzyafenmoqi.png" alt="Which projects each Sparo profile materializes, and which stay out of the working tree" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What a sparse tree looks like day to day
&lt;/h3&gt;

&lt;p&gt;I wrote this article inside a working copy created by &lt;code&gt;sparo clone&lt;/code&gt; with a profile applied. That makes the mechanism inspectable instead of theoretical.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git ls-files | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;                                                      &lt;span class="c"&gt;# 120&lt;/span&gt;
git ls-files | &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; f&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;x&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;     &lt;span class="c"&gt;# 118&lt;/span&gt;
git status &lt;span class="nt"&gt;--porcelain&lt;/span&gt; | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;                                             &lt;span class="c"&gt;# 0&lt;/span&gt;
git config &lt;span class="nt"&gt;--get&lt;/span&gt; remote.origin.partialCloneFilter                          &lt;span class="c"&gt;# blob:none&lt;/span&gt;
git config &lt;span class="nt"&gt;--get&lt;/span&gt; remote.origin.promisor                                   &lt;span class="c"&gt;# true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git tracks 120 files. Only 118 are on disk. &lt;code&gt;git status&lt;/code&gt; calls the tree clean, because the two missing files are marked skip-worktree.&lt;/p&gt;

&lt;p&gt;Those two files are &lt;code&gt;docs/BANG_OPERATOR.md&lt;/code&gt; and &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;. To read the workflow I had to run &lt;code&gt;git show HEAD:.github/workflows/ci.yml&lt;/code&gt;, because it is not on disk in this clone. The sparse settings live in &lt;code&gt;.git/config.worktree&lt;/code&gt; rather than &lt;code&gt;.git/config&lt;/code&gt;, because &lt;code&gt;git sparse-checkout set&lt;/code&gt; upgrades a repo to worktree-specific config.&lt;/p&gt;

&lt;p&gt;That is the pitfall to plan around. A profile that selects &lt;code&gt;--to @hotel/web&lt;/code&gt; excludes &lt;code&gt;.github/&lt;/code&gt;, so your CI configuration disappears from the working tree. Everything that walks the tree sees a smaller repo than Git does. &lt;code&gt;git grep&lt;/code&gt; returns fewer results, and &lt;code&gt;git commit -a&lt;/code&gt; will not record an out-of-cone file as deleted.&lt;/p&gt;

&lt;p&gt;If a tool needs a directory, name it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"selections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--to"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"argument"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@hotel/web"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"includeFolders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;".github"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three further problems come up in practice. The clone is blobless, so reading content Git has not fetched costs a network round trip. A repo-wide lint or a background IDE index will trigger exactly that. Sparo refuses to check out a profile that omits a folder with local edits, so stash or commit first. And &lt;code&gt;sparo-ci checkout&lt;/code&gt; uses a &lt;strong&gt;treeless&lt;/strong&gt; clone in CI rather than a blobless one. Anything that assumes directory listings are present will behave differently on a runner than on your laptop.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sparse checkout fights the install
&lt;/h3&gt;

&lt;p&gt;This is the result I didn’t expect, and it affects how you should plan.&lt;/p&gt;

&lt;p&gt;A caveat on method: I built these three cases by hand with &lt;code&gt;git sparse-checkout&lt;/code&gt;, not with &lt;code&gt;sparo checkout --profile&lt;/code&gt;. That separates what Rush and PNPM require from what Sparo configures. Read the findings below as a property of Rush’s install, not as a measurement of Sparo’s own checkout.&lt;/p&gt;

&lt;p&gt;Rush and PNPM need every registered project's &lt;code&gt;package.json&lt;/code&gt; to be on disk. A profile that omits project folders therefore cannot install. I hit three failures in a row on the 407-project test fixture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A cone set naming only the app and package folders leaves out &lt;code&gt;common/&lt;/code&gt;, and &lt;code&gt;rush update&lt;/code&gt; died in 0.29 s with &lt;code&gt;MODULE_NOT_FOUND&lt;/code&gt; for &lt;code&gt;common/scripts/install-run-rush.js&lt;/code&gt;. Cone mode includes root files and the directories you name, and nothing else.&lt;/li&gt;
&lt;li&gt;Adding &lt;code&gt;common/&lt;/code&gt; was not enough. Rush still needs every project's &lt;code&gt;package.json&lt;/code&gt;, so the same command failed with &lt;code&gt;Could not find package.json for @hotel/eslint-config&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A non-cone set that materializes all 408 &lt;code&gt;package.json&lt;/code&gt; files plus &lt;code&gt;common/&lt;/code&gt; does install, with 513 files on disk instead of 3,328. But &lt;code&gt;rush build --to @hotel/ui&lt;/code&gt; then failed with &lt;code&gt;TS6053: File '@hotel/typescript-config/react.json' not found&lt;/code&gt;, because the shared config packages were missing too.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A workable set is therefore narrower than "only the app I’m working on". Keep every &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;common/&lt;/code&gt;, and the config packages, and sparsify only the source directories. That still takes you from 3,328 files to 513.&lt;/p&gt;

&lt;p&gt;This recipe has a catch: it needs non-cone patterns. A cone set can only name directories, but the files you must keep sit at the root of every package. Non-cone mode is deprecated and slower. When you don’t need to install, cone mode is still the better choice.&lt;/p&gt;

&lt;p&gt;The lever for install size is not the checkout. It is Rush's &lt;strong&gt;filtered install&lt;/strong&gt;, which I cover in the next section. In the fixture, sparse checkout changed install time and install size by nothing measurable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rush: the graph, the install, the selection
&lt;/h2&gt;

&lt;p&gt;Rush builds the dependency graph and delegates the install to PNPM. Four pieces of it do the work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmi31vif5h5xz3iej7kff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmi31vif5h5xz3iej7kff.png" alt="The seven projects and their runtime and dev-only dependency edges" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The project registry
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;rush.json&lt;/code&gt; lists every project by hand. There is no glob discovery and no directory scan.&lt;/p&gt;

&lt;p&gt;From &lt;code&gt;rush.json&lt;/code&gt;, abridged to two of the seven entries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rushVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5.181.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pnpmVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"11.5.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nodeSupportedVersionRange"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;gt;=20.9.0 &amp;lt;25.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"projects"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"packageName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@hotel/shared-types"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"projectFolder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packages/shared-types"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"shouldPublish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"packageName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@hotel/ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"projectFolder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packages/ui"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"shouldPublish"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All seven entries omit three optional fields: &lt;code&gt;tags&lt;/code&gt;, &lt;code&gt;versionPolicyName&lt;/code&gt;, and a truthy &lt;code&gt;shouldPublish&lt;/code&gt;. Each omission costs you a feature. Without tags you cannot select projects by &lt;code&gt;tag:&amp;lt;name&amp;gt;&lt;/code&gt;. Without a version policy nothing is lockstepped. With &lt;code&gt;shouldPublish: false&lt;/code&gt; Rush tracks no change files.&lt;/p&gt;

&lt;p&gt;Listing projects by hand costs you one line per project, and buys a shortcut everywhere else. Every command reads one small file instead of walking the tree for &lt;code&gt;package.json&lt;/code&gt;. Adding a project becomes a one-line diff in the file that is obviously authoritative.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install: one lockfile, and a way to install less
&lt;/h3&gt;

&lt;p&gt;Rush delegates the install to PNPM in workspaces mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"useWorkspaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"minimumReleaseAgeMinutes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rush generates &lt;code&gt;common/temp/pnpm-workspace.yaml&lt;/code&gt; listing every local project, then runs PNPM once for the whole repo. You get one lockfile at &lt;code&gt;common/config/rush/pnpm-lock.yaml&lt;/code&gt;, one content-addressed store, and symlinks into each project's &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rush install&lt;/code&gt; performs an install but will not modify any file. It fails if the lockfile is out of date. &lt;code&gt;rush update&lt;/code&gt; is the command that resolves and rewrites. Use &lt;code&gt;update&lt;/code&gt; while working and &lt;code&gt;install&lt;/code&gt; in CI. A CI job that runs &lt;code&gt;update&lt;/code&gt; will accept a lockfile that no longer matches the manifests, which is the state you want CI to reject.&lt;/p&gt;

&lt;p&gt;To install less, pass the same project selectors you would pass to &lt;code&gt;rush build&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rush &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--to&lt;/span&gt; @hotel/web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rush still generates the full workspace. It then passes &lt;code&gt;--filter&lt;/code&gt; to PNPM for each selection, so only the selected projects and their dependency closure get installed. Two constraints apply. The flags work only when &lt;code&gt;useWorkspaces&lt;/code&gt; is true. And &lt;code&gt;rush update&lt;/code&gt; rejects them, so this narrows the install and not the resolution.&lt;/p&gt;

&lt;p&gt;It helps to know what ends up on disk. After a full install in this repo, &lt;code&gt;common/temp&lt;/code&gt; holds 1.6 GB. The PNPM store accounts for 707 MB, &lt;code&gt;node_modules&lt;/code&gt; for 344 MB, and Rush's own downloaded tooling under &lt;code&gt;install-run&lt;/code&gt; for 336 MB. The &lt;code&gt;rush-recycler&lt;/code&gt; cache adds 164 MB. About half a gigabyte is Rush managing itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  The supply-chain age check
&lt;/h3&gt;

&lt;p&gt;PNPM can refuse packages that were published too recently. Its setting is &lt;code&gt;minimumReleaseAge&lt;/code&gt;, measured in minutes, added in PNPM 10.16.0 and defaulting to 1440 from PNPM 11. Rush surfaces the same value under its own key, &lt;code&gt;minimumReleaseAgeMinutes&lt;/code&gt;. The check applies to transitive dependencies, not only the ones you name.&lt;/p&gt;

&lt;p&gt;The reason to write the number down is where exemptions go. PNPM keeps them in &lt;code&gt;minimumReleaseAgeExclude&lt;/code&gt;, inside &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt;. In a Rush repo that file is generated under &lt;code&gt;common/temp&lt;/code&gt;, which is gitignored and dockerignored. An exemption added on one laptop therefore exists only on that laptop. Your local build keeps working while a fresh clone, CI, or &lt;code&gt;docker compose build&lt;/code&gt; fails lockfile verification.&lt;/p&gt;

&lt;p&gt;When you need a release younger than the window, the install fails with &lt;code&gt;ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION&lt;/code&gt;. Pin an older release, or add a deliberate exemption. Disabling the policy to land one patch is the third option, and the wrong one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bulk, global, and phased commands
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;common/config/rush/command-line.json&lt;/code&gt; defines six custom commands here. Three are &lt;code&gt;bulk&lt;/code&gt;, which means they run once per selected project in dependency order: &lt;code&gt;lint&lt;/code&gt;, &lt;code&gt;typecheck&lt;/code&gt;, and &lt;code&gt;seed&lt;/code&gt;. Three are &lt;code&gt;global&lt;/code&gt;, which means they run once for the repo: &lt;code&gt;dev&lt;/code&gt;, &lt;code&gt;format&lt;/code&gt;, and &lt;code&gt;format:check&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dev&lt;/code&gt; has to be global. Bulk commands buffer every project's output until that project finishes, and two watch servers never finish. The global command runs a small script that spawns each server in its own process group. Signalling the group tears down the whole &lt;code&gt;rushx&lt;/code&gt; chain. Signalling only the leader leaves a server holding its port.&lt;/p&gt;

&lt;p&gt;Rush also supports &lt;strong&gt;phased commands&lt;/strong&gt;, which this repo does not use. Instead of one &lt;code&gt;build&lt;/code&gt; script per project, a project declares operations such as &lt;code&gt;_phase:build&lt;/code&gt; and &lt;code&gt;_phase:test&lt;/code&gt;, along with their inputs and outputs, in &lt;code&gt;rush-project.json&lt;/code&gt;. Phases are what make operation-level caching possible, because the cache key is computed per operation. A project can then cache its build and not its test. If you move to the build cache, this is the file you edit.&lt;/p&gt;

&lt;p&gt;Subspaces are the other scaling feature this repo leaves switched off. A subspace is a group of projects with its own lockfile and its own install. That is how a monorepo of a few thousand projects splits resolution work by product group instead of resolving one enormous graph on every install. Cross-subspace dependencies are injected rather than symlinked in some configurations, so enabling subspaces is a deliberate step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selection: build only what changed
&lt;/h3&gt;

&lt;p&gt;This is the half of Rush that keeps CI honest. Pass a project selector and Rush builds a subset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rush build &lt;span class="nt"&gt;--to&lt;/span&gt; @hotel/web                 &lt;span class="c"&gt;# @hotel/web and everything it depends on&lt;/span&gt;
rush build &lt;span class="nt"&gt;--from&lt;/span&gt; @hotel/shared-types      &lt;span class="c"&gt;# shared-types, its dependents, and their dependencies&lt;/span&gt;
rush build &lt;span class="nt"&gt;--only&lt;/span&gt; @hotel/ui                &lt;span class="c"&gt;# exactly this project, dependencies ignored&lt;/span&gt;
rush build &lt;span class="nt"&gt;--from&lt;/span&gt; git:origin/main          &lt;span class="c"&gt;# everything this branch changed, closed over&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four properties matter if you build automation on top of these.&lt;/p&gt;

&lt;p&gt;Selectors combine as a &lt;strong&gt;union&lt;/strong&gt;. The same flag can repeat, as in &lt;code&gt;--only a --only b&lt;/code&gt;, and no flag removes projects from the selection. To narrow a set, narrow the inputs.&lt;/p&gt;

&lt;p&gt;Three flags are documented as &lt;strong&gt;unsafe&lt;/strong&gt;: &lt;code&gt;--only&lt;/code&gt;, &lt;code&gt;--impacted-by&lt;/code&gt;, and &lt;code&gt;--impacted-by-except&lt;/code&gt;. Each can select a project without its dependencies, so the build fails if those dependencies were never built. They suit a CI stage that runs after a build stage. They are the wrong choice for a cold checkout. &lt;code&gt;--from&lt;/code&gt; is the safe form, because it pulls in the dependencies of everything it selects.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--from&lt;/code&gt; changed meaning in Rush 5.38.0. Today it means the project, its dependents, and the dependencies of that whole set. Before 5.38.0 it behaved like &lt;code&gt;--impacted-by&lt;/code&gt; and added no dependencies, so older documentation describes the older behaviour. The &lt;code&gt;git:&amp;lt;ref&amp;gt;&lt;/code&gt; selector is newer still, added in Rush 5.57.0.&lt;/p&gt;

&lt;p&gt;There is no &lt;code&gt;--from-except&lt;/code&gt;. Only &lt;code&gt;--to-except&lt;/code&gt; and &lt;code&gt;--impacted-by-except&lt;/code&gt; exist. &lt;code&gt;--from-except&lt;/code&gt; shows up in generated CI configs and blog posts that were never run.&lt;/p&gt;

&lt;p&gt;A selector can be a project name, &lt;code&gt;.&lt;/code&gt; for the current project, &lt;code&gt;git:&amp;lt;ref&amp;gt;&lt;/code&gt;, &lt;code&gt;subspace:&amp;lt;name&amp;gt;&lt;/code&gt;, or &lt;code&gt;tag:&amp;lt;name&amp;gt;&lt;/code&gt;. For the Git form, the documented shape is a single ref such as &lt;code&gt;git:origin/main&lt;/code&gt;. Rush resolves it, and falls back to &lt;code&gt;git merge-base -- HEAD &amp;lt;ref&amp;gt;&lt;/code&gt; when the ref is not a full commit hash. I found no documented support for a triple-dot range such as &lt;code&gt;git:origin/main...HEAD&lt;/code&gt;, so I would compute the base commit and pass the hash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental builds, and the assumption under them
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;rush build&lt;/code&gt; is incremental and cannot be made otherwise. It hashes each project's inputs and skips any project whose inputs are unchanged since the last successful build. That state lives in &lt;code&gt;&amp;lt;project&amp;gt;/.rush/temp/package-deps_build.json&lt;/code&gt;. It is why this repo's &lt;code&gt;make clean&lt;/code&gt; deletes those files: the state tracks source hashes, not whether output still exists.&lt;/p&gt;

&lt;p&gt;With the cache disabled, Rush uses &lt;strong&gt;output preservation&lt;/strong&gt;. If no inputs changed, Rush assumes the output on disk is still correct. Delete &lt;code&gt;apps/api/dist&lt;/code&gt; by hand and the assumption is now false. &lt;code&gt;rush build&lt;/code&gt; reports everything up to date, emits nothing, and the failure surfaces later as a missing file at runtime.&lt;/p&gt;

&lt;p&gt;The two build commands differ in a way that catches people out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rush build&lt;/code&gt; reads from the cache and writes to it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rush rebuild&lt;/code&gt; cleans and rebuilds every project. It does &lt;strong&gt;not&lt;/strong&gt; read from the cache, and it &lt;strong&gt;does&lt;/strong&gt; write to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a CI job running &lt;code&gt;rebuild&lt;/code&gt; gets no cache benefit while still filling the cache that other jobs read. If you adopt the cache, move CI to &lt;code&gt;rush build&lt;/code&gt;. You can turn writes off with &lt;code&gt;RUSH_BUILD_CACHE_WRITE_ALLOWED=0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The cache itself is still documented as experimental, and it is off in this repo. That is why no &lt;code&gt;build-cache&lt;/code&gt; directory exists under &lt;code&gt;common/temp&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Rush and PNPM are not installed globally. &lt;code&gt;mise.toml&lt;/code&gt; pins the toolchain for developers. Where mise is unavailable, as in the Dockerfiles, &lt;code&gt;common/scripts/install-run-rush.js&lt;/code&gt; reads &lt;code&gt;rushVersion&lt;/code&gt; from &lt;code&gt;rush.json&lt;/code&gt; and runs that release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Versioning and publishing
&lt;/h3&gt;

&lt;p&gt;Every project here sets &lt;code&gt;shouldPublish: false&lt;/code&gt;, and &lt;code&gt;version-policies.json&lt;/code&gt; is empty, so this repo has no &lt;code&gt;common/changes/&lt;/code&gt; directory and publishes nothing. In a repo that does publish, &lt;code&gt;rush change&lt;/code&gt; writes a per-change file, and &lt;code&gt;rush change --verify&lt;/code&gt; fails CI when a public package changed without one. &lt;code&gt;rush version --bump&lt;/code&gt; then applies the bumps, and &lt;code&gt;rush publish&lt;/code&gt; writes the changelogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the numbers look like
&lt;/h2&gt;

&lt;p&gt;I built a fixture and measured it, because estimating would have been worse than saying nothing.&lt;/p&gt;

&lt;p&gt;The fixture is this repo's working tree plus 400 generated packages. Each generated package has a &lt;code&gt;package.json&lt;/code&gt;, a &lt;code&gt;tsconfig.json&lt;/code&gt;, and six source files. The result is 407 registered projects and 3,328 tracked files, committed to a local bare remote of 1.7 MB, 5,785 objects, and a 1.32 MiB pack. The machine was an 8-core arm64 laptop running Node 24.22.0, Rush 5.181.0, and PNPM 11.5.1.&lt;/p&gt;

&lt;p&gt;One setup detail cost me a wasted run. A bare remote needs &lt;code&gt;uploadpack.allowFilter=true&lt;/code&gt;. Without it, &lt;code&gt;git clone --filter=blob:none&lt;/code&gt; prints &lt;code&gt;warning: filtering not recognized by server, ignoring&lt;/code&gt; and quietly produces a full clone. Every blobless number below comes from after that setting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Baseline&lt;/strong&gt; is a plain &lt;code&gt;git clone&lt;/code&gt; plus a full &lt;code&gt;rush rebuild&lt;/code&gt;. &lt;strong&gt;Optimised&lt;/strong&gt; is &lt;code&gt;git clone --filter=blob:none --sparse&lt;/code&gt; with a cone-mode sparse set, plus selection-based builds. Timings are nearest-rank percentiles over the stated run count.&lt;/p&gt;

&lt;p&gt;Two caveats before you read the numbers. The clones run over &lt;code&gt;file://&lt;/code&gt; on one machine, so they measure Git's object and tree work rather than network transfer. Across a real network a sparse clone would look better than it does here, because the bytes it skips are the expensive part. And these measurements use three different trees, so each table names the tree it came from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Checkout&lt;/strong&gt;, measured on a cone-mode sparse set applied to a blobless clone:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Baseline&lt;/th&gt;
&lt;th&gt;Optimised&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clone and sparse set (p50, n=10)&lt;/td&gt;
&lt;td&gt;284 ms&lt;/td&gt;
&lt;td&gt;160 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.git&lt;/code&gt; on disk&lt;/td&gt;
&lt;td&gt;1,824 KiB&lt;/td&gt;
&lt;td&gt;920 KiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files on disk&lt;/td&gt;
&lt;td&gt;3,328&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;git status&lt;/code&gt; (p50 / p95, n=50)&lt;/td&gt;
&lt;td&gt;76 / 80 ms&lt;/td&gt;
&lt;td&gt;13 / 14 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Install and build.&lt;/strong&gt; The install rows compare a full clone against the install-capable sparse tree, which holds 513 files and every &lt;code&gt;package.json&lt;/code&gt;. Both build rows ran in the full clone.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Baseline&lt;/th&gt;
&lt;th&gt;Optimised&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold &lt;code&gt;rush update&lt;/code&gt; (p50, n=5)&lt;/td&gt;
&lt;td&gt;46.5 s&lt;/td&gt;
&lt;td&gt;41.9 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;common/temp&lt;/code&gt; after install&lt;/td&gt;
&lt;td&gt;1.20 GiB&lt;/td&gt;
&lt;td&gt;1.20 GiB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build after a leaf-file change&lt;/td&gt;
&lt;td&gt;24.60 s, 407 projects&lt;/td&gt;
&lt;td&gt;1.04 s, 4 projects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build after a hub-file change&lt;/td&gt;
&lt;td&gt;24.60 s, 407 projects&lt;/td&gt;
&lt;td&gt;24.74 s, 401 projects&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Four things in those tables are worth reading twice.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blobless clone on its own is worse than useless
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;--filter=blob:none&lt;/code&gt; alone cloned in 341 ms with a 1,972 KiB &lt;code&gt;.git&lt;/code&gt;, both worse than the plain clone. Checking out &lt;code&gt;HEAD&lt;/code&gt; materializes every blob anyway, and the deferred ones land in a second, unconsolidated pack. The win comes from the sparse set that stops those files being written.&lt;/p&gt;

&lt;p&gt;Order matters too. Applying the sparse set after a blobless clone cost 561 ms and left the largest &lt;code&gt;.git&lt;/code&gt; of any mode at 1,988 KiB. Cloning with &lt;code&gt;--sparse&lt;/code&gt; first and setting the cone afterwards took 160 ms and half the &lt;code&gt;.git&lt;/code&gt; size.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;git status&lt;/code&gt; number is the one you feel
&lt;/h3&gt;

&lt;p&gt;76 ms to 13 ms. Git stops checking 3,242 files that are no longer on disk. That is the difference between a command you do not notice and one you do.&lt;/p&gt;

&lt;h3&gt;
  
  
  The install does not move
&lt;/h3&gt;

&lt;p&gt;Sparse checkout cut the working tree by 97% and changed install time by nothing.&lt;/p&gt;

&lt;p&gt;Read the spread rather than the median. The full clone gave 39.6, 41.8, 46.5, 49.3, and 52.9 seconds. The install-capable sparse tree gave 36.6, 40.5, 41.9, and 60.1 seconds, plus one run that stalled at 330.6 seconds on the registry. Two of the five sparse runs beat every full-clone run, and the sparse distribution is the wider one. That is what "no effect" looks like when the metric is dominated by network and registry latency: the two distributions overlap, and neither ordering is stable. &lt;code&gt;common/temp&lt;/code&gt; came out identical at 1.20 GiB.&lt;/p&gt;

&lt;p&gt;Install cost is the resolution and materialization of the dependency graph, and that graph is the same however many project folders you checked out. The three failures in the previous section explain why you cannot sparsify your way out of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Selection depends on the graph, not on the flag
&lt;/h3&gt;

&lt;p&gt;A file with no dependents rebuilt 4 projects in 1.04 s, which is 4% of the full 24.60 s. A file in a package that 400 others depend on rebuilt 401 projects in 24.74 s, which is a full rebuild plus bookkeeping.&lt;/p&gt;

&lt;p&gt;Selection is not magic. It is a function of your dependency graph, and a widely-used shared package will always be expensive to change. The fixture wires all 400 generated packages downstream of that hub package, so the second row is the worst case rather than a rigged one.&lt;/p&gt;

&lt;p&gt;The cache was off in this fixture, and a grep across all 30 build and install logs found no cache messages. The only skip reported anywhere came from Rush's incremental change detection.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI and CD
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The workflow this repo commits
&lt;/h3&gt;

&lt;p&gt;The repo commits one workflow, and its ordering encodes two lessons. From &lt;code&gt;.github/workflows/ci.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CI&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;22&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js install&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js format:check&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js lint&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js typecheck&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js rebuild --verbose&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git diff --exit-code -- apps/web/src/routeTree.gen.ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first lesson is that &lt;code&gt;typecheck&lt;/code&gt; runs before &lt;code&gt;build&lt;/code&gt;. Vite does not type-check during &lt;code&gt;build&lt;/code&gt;, so &lt;code&gt;rush build&lt;/code&gt; can succeed on a web app that has type errors in it. Type-checking has to be its own pass.&lt;/p&gt;

&lt;p&gt;The second lesson follows from the first. Because &lt;code&gt;typecheck&lt;/code&gt; runs before anything is built, &lt;code&gt;apps/web/src/routeTree.gen.ts&lt;/code&gt; has to be committed. TanStack Start's Vite plugin generates that file, and &lt;code&gt;src/router.tsx&lt;/code&gt; imports it, but at typecheck time nothing has produced it yet. The last step re-runs the generator during the build and diffs the file, so drift fails the job.&lt;/p&gt;

&lt;p&gt;Two smaller choices are deliberate. CI uses &lt;code&gt;rebuild&lt;/code&gt; rather than &lt;code&gt;build&lt;/code&gt;, because it wants a clean full build. And &lt;code&gt;--production&lt;/code&gt; is absent, because it is not a built-in Rush parameter. &lt;code&gt;rush.json&lt;/code&gt; does not declare it, and Rush 5 rejects the whole command with &lt;code&gt;Unrecognized arguments: --production&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This job installs everything and builds everything, so it scales linearly with the repo. That is the right default at this size. The next section is the shape it should take at a large one. None of it is implemented in this repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuzinbiss8y7q13m6cqoo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuzinbiss8y7q13m6cqoo.png" alt="How a developer machine, CI, and a shared remote build cache fit together" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The workflow a large repo wants
&lt;/h3&gt;

&lt;p&gt;In a large repo the checkout is the first thing to shrink.&lt;/p&gt;

&lt;p&gt;What follows is a design, not a pipeline I have run. I tested the pieces it depends on: the selectors, the filtered install, and the cache behaviour. I did not run this workflow end to end, so treat it as something to verify rather than a recipe.&lt;/p&gt;

&lt;p&gt;The rule that matters most is to use &lt;strong&gt;one selector for every step&lt;/strong&gt;. If the checkout materializes a different set of projects than the later steps select, some step ends up running against a project that is not on disk.&lt;/p&gt;

&lt;p&gt;Call the file &lt;code&gt;ci-affected.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git fetch origin main&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx sparo-ci checkout --from git:origin/main&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js install --from git:origin/main&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js format:check&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js lint --from git:origin/main&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js typecheck --from git:origin/main&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node common/scripts/install-run-rush.js build --from git:origin/main&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;git diff --exit-code -- apps/web/src/routeTree.gen.ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some choices there are deliberate. It uses &lt;code&gt;--from&lt;/code&gt; rather than &lt;code&gt;--impacted-by&lt;/code&gt;, because &lt;code&gt;--impacted-by&lt;/code&gt; selects dependents without their dependencies and fails on a cold worker. It keeps &lt;code&gt;typecheck&lt;/code&gt; before &lt;code&gt;build&lt;/code&gt;. It uses &lt;code&gt;build&lt;/code&gt; rather than &lt;code&gt;rebuild&lt;/code&gt;, because only &lt;code&gt;build&lt;/code&gt; reads the cache. And it uses a filtered install, which is the one place install time drops.&lt;/p&gt;

&lt;p&gt;Four parts of that snippet I have not verified, and would check first on a real repo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;fetch-depth: 0&lt;/code&gt; fights the point of a sparse checkout.&lt;/strong&gt; Selection needs the merge-base, and that needs the base commit locally, so a shallow clone breaks it. Cloning full history is the blunt fix. &lt;code&gt;--filter=blob:none&lt;/code&gt; makes that history cheap, or you can fetch just the target branch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;format:check&lt;/code&gt; cannot be scoped.&lt;/strong&gt; It is a global command, so it takes no selector, and on a sparse tree it only sees the files that were materialized. It quietly checks less than it did before.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The route-tree drift check only means something when the web app is in the selected set.&lt;/strong&gt; On a change that does not touch &lt;code&gt;apps/web&lt;/code&gt;, that step compares a file nothing regenerated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The install step may fail outright.&lt;/strong&gt; This is the constraint from the previous section: Rush needs every registered project's &lt;code&gt;package.json&lt;/code&gt; on disk. If the checkout does not keep them, the install fails however the rest is arranged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcy1ul5qssqbtku1ug66r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcy1ul5qssqbtku1ug66r.png" alt="The pull request pipeline, with the build-cache branch made explicit" width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Four ways affected selection goes wrong
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A shallow clone breaks merge-base.&lt;/strong&gt; This repo's &lt;code&gt;fetch-depth: 2&lt;/code&gt; is enough for its route-tree diff and not enough for selection. Rush resolves a &lt;code&gt;git:&amp;lt;ref&amp;gt;&lt;/code&gt; selector through Git, and falls back to &lt;code&gt;git merge-base -- HEAD &amp;lt;ref&amp;gt;&lt;/code&gt; when the ref is not a full commit hash. That needs the base commit locally. On a shallow clone the merge-base is missing, or it is the shallow boundary rather than the real one. Either way the selected set silently comes out too small.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A stale cache returns wrong output.&lt;/strong&gt; With &lt;code&gt;buildCacheEnabled: true&lt;/code&gt;, cache restoration replaces output preservation, so a project's output folders are always replaced by a restore. The cache key covers the project's source files, plus the sources of its workspace dependencies. It also covers the versions of external npm dependencies including indirect ones, and the Rush command-line parameters. It does not cover environment variables or the Node.js version unless you opt in through &lt;code&gt;operationSettings[].dependsOnEnvVars&lt;/code&gt; and &lt;code&gt;dependsOnNodeVersion&lt;/code&gt;. No documentation states that Rush's or PNPM's own version invalidates an entry. A build that reads &lt;code&gt;process.env.SOMETHING&lt;/code&gt; will therefore restore wrong output with full confidence. Rush's docs point at &lt;code&gt;rush-audit-cache-plugin&lt;/code&gt; for finding inputs you failed to declare.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache reads and writes go the wrong way round.&lt;/strong&gt; &lt;code&gt;isCacheWriteAllowed&lt;/code&gt; defaults to false in the cloud provider blocks. The documented pattern is read-only on developer machines and &lt;code&gt;RUSH_BUILD_CACHE_WRITE_ALLOWED=1&lt;/code&gt; on CI. Get it backwards and developer machines overwrite entries while CI reads nothing useful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flaky tests block merges.&lt;/strong&gt; A test that fails one run in twenty is worse than a slow test, because it teaches people to re-run until green. Select affected projects for speed, but do not make the merge decision depend on a suite you do not trust.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Do not copy this repo's Node pinning
&lt;/h3&gt;

&lt;p&gt;This repo runs three different Node versions and gets away with it. &lt;code&gt;mise.toml&lt;/code&gt; pins Node 24 for developers. The workflow above uses Node 22. Both Dockerfiles use &lt;code&gt;node:22-slim&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It works because &lt;code&gt;rush.json&lt;/code&gt; enforces a range rather than an exact version, and all three sit inside it. It also works because Rush and PNPM are pinned exactly, so the tool that resolves the graph is the same everywhere.&lt;/p&gt;

&lt;p&gt;I would not copy it. A range is a tolerance, not a pin, and the failure mode of drift is a build that reproduces on one machine and not another. Pick one Node version and use it in all three places.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;Deployment starts from the same problem. Two of the seven projects produce runnable artifacts, and both need the shared workspace to build.&lt;/p&gt;

&lt;p&gt;The Dockerfiles are single-stage and deliberately pragmatic. Each is &lt;code&gt;node:22-slim&lt;/code&gt;, copies the whole repo, installs with the install-run bootstrap, and builds one selection. From &lt;code&gt;apps/api/Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:22-slim&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /repo&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;node common/scripts/install-run-rush.js &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;node common/scripts/install-run-rush.js build &lt;span class="nt"&gt;--to&lt;/span&gt; @hotel/api
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/main.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The web variant carries one detail worth copying to any Vite app. &lt;code&gt;VITE_API_URL&lt;/code&gt; is a build &lt;code&gt;ARG&lt;/code&gt; and not a runtime environment variable, because Vite inlines &lt;code&gt;import.meta.env.*&lt;/code&gt; at build time. Server-side rendering needs a different URL from the browser. It runs inside the container, so it must reach the API by its Compose service name rather than &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The single-stage choice trades image size for reliability. Rush and PNPM link packages through symlinks into &lt;code&gt;common/temp&lt;/code&gt;, and copying a pruned subset of that layout across build stages is fragile.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rush deploy&lt;/code&gt; is the improvement, and it is not implemented here. It copies the selected project plus its regular dependencies, npm packages and local projects alike. Dev dependencies are left out by default. Its config lives at &lt;code&gt;common/config/rush/deploy.json&lt;/code&gt;, which you create with &lt;code&gt;rush init-deploy --project &amp;lt;name&amp;gt;&lt;/code&gt; and commit. Output goes to &lt;code&gt;common/deploy/&lt;/code&gt; unless you pass &lt;code&gt;--target-folder&lt;/code&gt;, and &lt;code&gt;--create-archive&lt;/code&gt; produces a zip.&lt;/p&gt;

&lt;p&gt;The setting that needs care is &lt;code&gt;linkCreation&lt;/code&gt;, which accepts &lt;code&gt;default&lt;/code&gt;, &lt;code&gt;script&lt;/code&gt;, or &lt;code&gt;none&lt;/code&gt;. With &lt;code&gt;script&lt;/code&gt; you get a &lt;code&gt;create-links.js&lt;/code&gt; to run on the server, and &lt;code&gt;node_modules/.bin&lt;/code&gt; binaries are not generated yet.&lt;/p&gt;

&lt;p&gt;Per-app pipelines fall out of the same selection machinery as CI. Trigger the API pipeline when &lt;code&gt;--from&lt;/code&gt; says the API's closure changed, and the web pipeline on the same test for the web closure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8n6onifap3iej027g79f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8n6onifap3iej027g79f.png" alt="Merge-to-main deployment, with migration and API/web ordering" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ordering is where deployment differs from affected selection. Migrations run before the API deploy, because the new code expects the new schema. The API deploys before the web app, because the running frontend may be calling an API one version ahead of it or behind it. Keep that skew window as short as your API contract tolerates.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Rush and Sparo compare with the alternatives
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Rush + Sparo&lt;/th&gt;
&lt;th&gt;Nx / Turborepo&lt;/th&gt;
&lt;th&gt;Bazel / Buck2&lt;/th&gt;
&lt;th&gt;Scalar, Sapling / EdenFS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unit of work&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A project in &lt;code&gt;rush.json&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;A workspace project&lt;/td&gt;
&lt;td&gt;A &lt;code&gt;BUILD&lt;/code&gt; file target&lt;/td&gt;
&lt;td&gt;A path in the repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caching&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Per-project hashing&lt;/td&gt;
&lt;td&gt;Task hashing, remote cache&lt;/td&gt;
&lt;td&gt;Content-addressed, sandboxed&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Git scaling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sparse checkout and blobless clone&lt;/td&gt;
&lt;td&gt;Not addressed&lt;/td&gt;
&lt;td&gt;Not addressed&lt;/td&gt;
&lt;td&gt;The whole point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Migration cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Register packages, one lockfile&lt;/td&gt;
&lt;td&gt;A config file, keep your layout&lt;/td&gt;
&lt;td&gt;Highest: build files, hermetic tools&lt;/td&gt;
&lt;td&gt;Low for Scalar; a new client for Sapling&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nx and Turborepo optimise task execution on top of whatever install you already have. Turborepo explicitly does not manage dependencies. Bazel and Buck2 buy isolation and reproducibility at the cost of modelling every build. Buck2's own list of ready languages runs to nine, including Haskell and OCaml.&lt;/p&gt;

&lt;p&gt;Scalar, Sapling, and EdenFS attack Git's I/O rather than your build graph, and Scalar ships inside upstream Git. That group combines with any of the first three, since a sparse checkout is orthogonal to how you cache builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use this
&lt;/h2&gt;

&lt;p&gt;Skip all of it if your repo holds a few dozen packages and one team.&lt;/p&gt;

&lt;p&gt;The setup cost is real. You maintain a registry, agree on a lockfile policy, keep profiles current, and understand cache invalidation. Below that size the tooling is a bigger maintenance surface than the problem.&lt;/p&gt;

&lt;p&gt;Rush is the wrong pick if you are not on the npm family of package managers, because its value is owning the npm lockfile and install strategy.&lt;/p&gt;

&lt;p&gt;Skip the build cache until your projects declare accurate inputs and outputs. A cache that restores wrong output is worse than no cache, because it is fast and wrong. Skip it as well if your builds touch state outside the project folder, or read environment variables you have not declared in &lt;code&gt;rush-project.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Skip sparse checkout if the whole repo already checks out in a second, or if your tools assume a full tree and you cannot change them. The &lt;code&gt;docs/&lt;/code&gt; and &lt;code&gt;.github/&lt;/code&gt; experience above is what that looks like, and it applies to search tools and CI scripts as much as to IDEs.&lt;/p&gt;

&lt;p&gt;Finally, do not adopt any of this on instinct. If you cannot state your current clone time, install time, and CI p50, you cannot tell whether a change helped.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to measure your own repo
&lt;/h2&gt;

&lt;p&gt;Baseline with four commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-sh&lt;/span&gt; .git                  &lt;span class="c"&gt;# total Git footprint on disk&lt;/span&gt;
git count-objects &lt;span class="nt"&gt;-vH&lt;/span&gt;        &lt;span class="c"&gt;# object count and pack size&lt;/span&gt;
git ls-files | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;         &lt;span class="c"&gt;# index size: what Git knows about&lt;/span&gt;
&lt;span class="nb"&gt;time &lt;/span&gt;git status              &lt;span class="c"&gt;# the command you run a hundred times a day&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;count-objects -vH&lt;/code&gt; prints &lt;code&gt;in-pack&lt;/code&gt; and &lt;code&gt;size-pack&lt;/code&gt;, which are the numbers that move when you go blobless. Compare &lt;code&gt;git ls-files | wc -l&lt;/code&gt; against the files actually on disk to see what a profile removed.&lt;/p&gt;

&lt;p&gt;Then measure the two things those commands cannot tell you. Time an install cold and warm. Count the projects selected for the change you make most often. Run each timing five times and report p50 and p95 rather than the mean. Clone and install times are heavy-tailed, so the mean is dominated by whichever run was slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this tutorial does not cover
&lt;/h2&gt;

&lt;p&gt;The Dockerfiles are single-stage, and &lt;code&gt;rush deploy&lt;/code&gt; is a follow-up rather than implemented. The build cache is off, so nothing here exercises cache keys. There is no Bazel or Buck2 depth, and that table row summarises each project's own documentation.&lt;/p&gt;

&lt;p&gt;The two Sparo profiles were written by hand, their &lt;code&gt;$schema&lt;/code&gt; URL does not resolve, and neither has been verified with &lt;code&gt;sparo init-profile&lt;/code&gt;. CI installs and rebuilds everything. Subspaces and phased commands are not configured. And there is no real test suite: every &lt;code&gt;test&lt;/code&gt; script is &lt;code&gt;echo "no tests"&lt;/code&gt;. The flaky-test failure mode is therefore described from the design side rather than observed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://rushjs.io" rel="noopener noreferrer"&gt;Rush&lt;/a&gt;, with &lt;a href="https://rushjs.io/pages/developer/selecting_subsets/" rel="noopener noreferrer"&gt;project selection&lt;/a&gt; and &lt;a href="https://rushjs.io/pages/maintainer/build_cache/" rel="noopener noreferrer"&gt;the build cache&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rushjs.io/pages/maintainer/deploying/" rel="noopener noreferrer"&gt;&lt;code&gt;rush deploy&lt;/code&gt; and &lt;code&gt;deploy.json&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tiktok.github.io/sparo/" rel="noopener noreferrer"&gt;Sparo&lt;/a&gt;, with &lt;a href="https://tiktok.github.io/sparo/schemas/sparo-profile.schema.json" rel="noopener noreferrer"&gt;the profile schema&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Git: &lt;a href="https://git-scm.com/docs/git-sparse-checkout" rel="noopener noreferrer"&gt;sparse checkout&lt;/a&gt;, &lt;a href="https://git-scm.com/docs/partial-clone" rel="noopener noreferrer"&gt;partial clone&lt;/a&gt;, and &lt;a href="https://git-scm.com/docs/scalar" rel="noopener noreferrer"&gt;Scalar&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pnpm.io/settings" rel="noopener noreferrer"&gt;PNPM settings&lt;/a&gt;, including &lt;code&gt;minimumReleaseAge&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/piyushchauhan2011/rushjs-sparo-tutorial" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>monorepo</category>
      <category>javascript</category>
      <category>devops</category>
      <category>git</category>
    </item>
    <item>
      <title>A type-safe decision engine in ReScript</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Sat, 10 Oct 2026 07:27:05 +0000</pubDate>
      <link>https://dev.to/frorning/a-type-safe-decision-engine-in-rescript-903</link>
      <guid>https://dev.to/frorning/a-type-safe-decision-engine-in-rescript-903</guid>
      <description>&lt;p&gt;How a ReScript + Next.js demo runs experiments and rules through one validated registry, with deterministic bucketing and provenance on every decision&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Experiments, rules, and preview overrides through one validated registry, with provenance on every value.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; every variant question becomes one typed decision computed on the server, and every value remembers which layer wrote it. Two experiments cannot write the same field without failing loudly. The engine lives in the Elsewhere demo, a hotel site built with ReScript and Next.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why stringly-typed flags keep breaking
&lt;/h2&gt;

&lt;p&gt;A flag pipeline starts cheap. Someone puts &lt;code&gt;hero_layout = split&lt;/code&gt; in a config table, reads it inside a component, and branches on the string. Nothing connects the read to the write: no compiler knows that &lt;code&gt;splti&lt;/code&gt; is a typo, and no test knows which component owns the field.&lt;/p&gt;

&lt;p&gt;Then the experiments multiply. Two of them write the same field, one silently wins, and the bug report says the hero layout flips between requests. Six months later nobody can answer why a particular visitor saw &lt;code&gt;compact&lt;/code&gt;, because the value is in a payload and the reason is nowhere. One registry plus one resolve step fixes both problems, and that is the rest of this post.&lt;/p&gt;

&lt;h2&gt;
  
  
  The demo: Elsewhere, a hotel site with experiments baked in
&lt;/h2&gt;

&lt;p&gt;I built the demo to test one architecture end to end. It is a hotel and destinations site that renders on the server, reads a SQLite catalog, and ships a development-only inspector. Everything runs from &lt;a href="https://github.com/piyushchauhan2011/rescript-react-nextjs" rel="noopener noreferrer"&gt;the Elsewhere repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code is split three ways, and the dependency direction is the point:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi4x27zbicr9mlts6b0as.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi4x27zbicr9mlts6b0as.png" alt="Three workspaces: apps/web and packages/ui both import packages/core, which depends only on the ReScript runtime" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The engine owns seven decision paths. Nothing else is adjustable, by design:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Path&lt;/th&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;What it changes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hero.layout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;immersive&lt;/code&gt; / &lt;code&gt;split&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;hero image treatment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search.layout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;overlay&lt;/code&gt; / &lt;code&gt;inline&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;destination search placement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;destinationCard.layout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;image&lt;/code&gt; / &lt;code&gt;compact&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;which card component renders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;destinations.columns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;three&lt;/code&gt; / &lt;code&gt;two&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;destination grid density&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;offers.visible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;seasonal offers section&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;planningGuide.visible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;"PLAN AHEAD" prompts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;planningGuide.detail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;brief&lt;/code&gt; / &lt;code&gt;expanded&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;prompt wording&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Those seven fields are the only surface any experiment or rule may touch, which is what keeps ownership checkable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The request path, end to end
&lt;/h2&gt;

&lt;p&gt;A request crosses four layers before any HTML exists. The proxy handles identity, the page route validates and calls the engine, the engine returns a snapshot, and the ReScript React shell renders from that snapshot without re-deriving anything.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;sequenceDiagram
    participant B as Browser
    participant P as Next proxy (middleware)
    participant R as Page route
    participant C as @repo/core (decision engine)
    participant U as @repo/ui (ReScript React)
    B-&amp;gt;&amp;gt;P: GET / (no visitorId)
    P-&amp;gt;&amp;gt;P: verify or issue signed cookie
    P--&amp;gt;&amp;gt;B: Set-Cookie: visitorId=&amp;lt;uuid&amp;gt;.&amp;lt;hmac&amp;gt;
    B-&amp;gt;&amp;gt;R: GET / (with cookie)
    R-&amp;gt;&amp;gt;C: resolveDecisionRequest(page, search, visitorId, rollout)
    C-&amp;gt;&amp;gt;C: validate search, build context, allocate, resolve
    C--&amp;gt;&amp;gt;R: decisionSnapshot {values, provenance, assignments, ignored}
    R--&amp;gt;&amp;gt;U: snapshot + catalog + search
    U--&amp;gt;&amp;gt;B: HTML (SSR)&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  Decisions are types, not strings
&lt;/h2&gt;

&lt;p&gt;Every decision value is a variant. &lt;code&gt;heroLayout&lt;/code&gt; is &lt;code&gt;#immersive&lt;/code&gt; or &lt;code&gt;#split&lt;/code&gt;, &lt;code&gt;destinationCardLayout&lt;/code&gt; is &lt;code&gt;#image&lt;/code&gt; or &lt;code&gt;#compact&lt;/code&gt;, and a renderer that handles one case but not the other fails compilation. That property is why the engine is written in ReScript rather than TypeScript.&lt;/p&gt;

&lt;p&gt;Strings still exist, but only at the wire boundary. &lt;code&gt;@as("hero.layout")&lt;/code&gt; keeps the JSON key dotted while the value stays a variant, and &lt;code&gt;@tag("source")&lt;/code&gt; labels every provenance case with the layer that produced it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#home&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#destinations&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#control&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#treatment&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;country&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#IN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#US&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;heroLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#immersive&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#split&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;searchLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#overlay&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#inline&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;cardLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#image&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#compact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#three&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#two&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;guideDetail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;#brief&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;#expanded&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="nd"&gt;@unboxed&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hero.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;HeroLayout&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"search.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;SearchLayout&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"destinationCard.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;DestinationCardLayout&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"destinations.columns"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;DestinationsColumns&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"offers.visible"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;OffersVisible&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"planningGuide.visible"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;PlanningGuideVisible&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"planningGuide.detail"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;PlanningGuideDetail&lt;/span&gt;

&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;decisionValues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hero.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;heroLayout&lt;/span&gt;: &lt;span class="n"&gt;heroLayout&lt;/span&gt;,
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"search.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;searchLayout&lt;/span&gt;: &lt;span class="n"&gt;searchLayout&lt;/span&gt;,
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"destinationCard.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;destinationCardLayout&lt;/span&gt;: &lt;span class="n"&gt;cardLayout&lt;/span&gt;,
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"destinations.columns"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;destinationsColumns&lt;/span&gt;: &lt;span class="n"&gt;columns&lt;/span&gt;,
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"offers.visible"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;offersVisible&lt;/span&gt;: &lt;span class="kt"&gt;bool&lt;/span&gt;,
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"planningGuide.visible"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;planningGuideVisible&lt;/span&gt;: &lt;span class="kt"&gt;bool&lt;/span&gt;,
  &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"planningGuide.detail"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;mutable&lt;/span&gt; &lt;span class="n"&gt;planningGuideDetail&lt;/span&gt;: &lt;span class="n"&gt;guideDetail&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Sparse fields are read through the validated string-keyed boundary codec.&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;decisionPatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hero.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;heroLayout&lt;/span&gt;?: &lt;span class="n"&gt;heroLayout&lt;/span&gt;,
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"search.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;searchLayout&lt;/span&gt;?: &lt;span class="n"&gt;searchLayout&lt;/span&gt;,
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"destinationCard.layout"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;destinationCardLayout&lt;/span&gt;?: &lt;span class="n"&gt;cardLayout&lt;/span&gt;,
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"destinations.columns"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;destinationsColumns&lt;/span&gt;?: &lt;span class="n"&gt;columns&lt;/span&gt;,
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"offers.visible"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;offersVisible&lt;/span&gt;?: &lt;span class="kt"&gt;bool&lt;/span&gt;,
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"planningGuide.visible"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;planningGuideVisible&lt;/span&gt;?: &lt;span class="kt"&gt;bool&lt;/span&gt;,
  &lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"planningGuide.detail"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;planningGuideDetail&lt;/span&gt;?: &lt;span class="n"&gt;guideDetail&lt;/span&gt;,
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="nd"&gt;@tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;provenance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rule"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Rule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"experiment"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Experiment&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="n"&gt;variant&lt;/span&gt;: &lt;span class="n"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The codec helpers below that block (&lt;code&gt;cast&lt;/code&gt;, &lt;code&gt;dictionary&lt;/code&gt;, &lt;code&gt;objectValue&lt;/code&gt;, &lt;code&gt;fail&lt;/code&gt;, &lt;code&gt;defaults&lt;/code&gt;, &lt;code&gt;validPatchValue&lt;/code&gt;, and &lt;code&gt;decodePatch&lt;/code&gt;) validate the wire boundary, rejecting unknown paths and out-of-range values before any write happens.&lt;/p&gt;

&lt;h2&gt;
  
  
  One registry owns every experiment and rule
&lt;/h2&gt;

&lt;p&gt;Experiments and rules are declared as data, and &lt;code&gt;createDecisionRegistry&lt;/code&gt; validates the whole declaration at module load. Duplicate IDs, overlapping allocations, and two owners claiming the same path all throw at startup, so a broken registry never serves a request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;experiments&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;experiment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"arrival-flow"&lt;/span&gt;,
    &lt;span class="n"&gt;surface&lt;/span&gt;: &lt;span class="s2"&gt;"arrival-flow"&lt;/span&gt;,
    &lt;span class="n"&gt;enabled&lt;/span&gt;: &lt;span class="kc"&gt;true&lt;/span&gt;,
    &lt;span class="n"&gt;allocation&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;, &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
    &lt;span class="n"&gt;owns&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;HeroLayout&lt;/span&gt;, &lt;span class="nc"&gt;SearchLayout&lt;/span&gt;, &lt;span class="nc"&gt;DestinationCardLayout&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;,
    &lt;span class="n"&gt;variants&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;control&lt;/span&gt;: &lt;span class="p"&gt;{}&lt;/span&gt;,
      &lt;span class="n"&gt;treatment&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;heroLayout&lt;/span&gt;: &lt;span class="nc"&gt;#split&lt;/span&gt;, &lt;span class="n"&gt;searchLayout&lt;/span&gt;: &lt;span class="nc"&gt;#inline&lt;/span&gt;, &lt;span class="n"&gt;destinationCardLayout&lt;/span&gt;: &lt;span class="nc"&gt;#compact&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;,
    &lt;span class="p"&gt;}&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;,
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"destination-density"&lt;/span&gt;,
    &lt;span class="n"&gt;surface&lt;/span&gt;: &lt;span class="s2"&gt;"destination-density"&lt;/span&gt;,
    &lt;span class="n"&gt;enabled&lt;/span&gt;: &lt;span class="kc"&gt;true&lt;/span&gt;,
    &lt;span class="n"&gt;allocation&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;, &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
    &lt;span class="n"&gt;owns&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;DestinationsColumns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;,
    &lt;span class="n"&gt;variants&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;control&lt;/span&gt;: &lt;span class="p"&gt;{}&lt;/span&gt;, &lt;span class="n"&gt;treatment&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;destinationsColumns&lt;/span&gt;: &lt;span class="nc"&gt;#two&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;,
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"planning-guide-detail"&lt;/span&gt;,
    &lt;span class="n"&gt;surface&lt;/span&gt;: &lt;span class="s2"&gt;"planning-guide-detail"&lt;/span&gt;,
    &lt;span class="n"&gt;enabled&lt;/span&gt;: &lt;span class="kc"&gt;true&lt;/span&gt;,
    &lt;span class="n"&gt;allocation&lt;/span&gt;: &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;, &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;,
    &lt;span class="n"&gt;owns&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;PlanningGuideDetail&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;,
    &lt;span class="n"&gt;variants&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;control&lt;/span&gt;: &lt;span class="p"&gt;{}&lt;/span&gt;, &lt;span class="n"&gt;treatment&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;planningGuideDetail&lt;/span&gt;: &lt;span class="nc"&gt;#expanded&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;,
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ownership is the strictest of those checks, because it is the one that catches a logic mistake rather than a typo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;      &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;conflict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;surface&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt;.&lt;span class="n"&gt;surface&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;surface&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;own&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;, &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;conflict&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;previousOwner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;.&lt;span class="n"&gt;owner&lt;/span&gt;
        &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Ownership conflict on "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;": "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;previousOwner&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;" and "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives a registry with five members:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Kind&lt;/th&gt;
&lt;th&gt;id&lt;/th&gt;
&lt;th&gt;owns&lt;/th&gt;
&lt;th&gt;effect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;experiment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arrival-flow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;hero.layout&lt;/code&gt;, &lt;code&gt;search.layout&lt;/code&gt;, &lt;code&gt;destinationCard.layout&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;treatment sets &lt;code&gt;split&lt;/code&gt; / &lt;code&gt;inline&lt;/code&gt; / &lt;code&gt;compact&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;experiment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;destination-density&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;destinations.columns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;treatment sets &lt;code&gt;two&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;experiment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;planning-guide-detail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;planningGuide.detail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;treatment sets &lt;code&gt;expanded&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rule&lt;/td&gt;
&lt;td&gt;&lt;code&gt;india-seasonal-offers&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;offers.visible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;when &lt;code&gt;seasonal-offers&lt;/code&gt; flag AND country &lt;code&gt;IN&lt;/code&gt;, sets &lt;code&gt;offers.visible = true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rule&lt;/td&gt;
&lt;td&gt;&lt;code&gt;planning-guide-flag&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;planningGuide.visible&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;when &lt;code&gt;planning-guide&lt;/code&gt; flag, sets &lt;code&gt;planningGuide.visible = true&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Allocation is &lt;code&gt;(0, 10000)&lt;/code&gt; on each surface, which is the full slot range: one experiment owns the whole surface and every visitor lands on one of its two variants.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deterministic assignment without server state
&lt;/h2&gt;

&lt;p&gt;Assignment is a pure function of the visitor ID plus a namespace string. FNV-1a hashes the concatenation, and the result is reduced twice: modulo 100 picks the 50/50 variant, modulo 10000 picks the slot inside a surface. There is no assignment table, no database write, and no session store.&lt;/p&gt;

&lt;p&gt;That makes assignment replayable. The same cookie and the same experiment ID produce the same variant on a cold server, after a restart, or behind a different edge node, which is the whole reason the engine can run without shared state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/** FNV-1a hashes JavaScript UTF-16 code units, including surrogate pairs. */&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;fnv1a32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2128831035&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;hash&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;imul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bitwiseXor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt;, &lt;span class="n"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;, &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;, &lt;span class="mi"&gt;16777619&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;unsigned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bucketForExperiment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitorId&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="n"&gt;experimentId&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nn"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fnv1a32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitorId&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;":"&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;experimentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;.&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;bucketForSurface&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitorId&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="n"&gt;surface&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nn"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fnv1a32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitorId&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;":surface:"&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;.&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;assignVariant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitorId&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="n"&gt;experimentId&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="nn"&gt;DecisionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bucketForExperiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;visitorId&lt;/span&gt;, &lt;span class="n"&gt;experimentId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;#control&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;#treatment&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The four externals and the &lt;code&gt;unsigned&lt;/code&gt; helper I left out of that snippet bind &lt;code&gt;Math.imul&lt;/code&gt;, &lt;code&gt;charCodeAt&lt;/code&gt;, &lt;code&gt;length&lt;/code&gt;, and the &lt;code&gt;&amp;gt;&amp;gt;&amp;gt; 0&lt;/code&gt; unsigned coercion.&lt;/p&gt;

&lt;p&gt;Both reductions are visible in the geometry of one experiment:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvvyp0ygqplj3up84guw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmvvyp0ygqplj3up84guw.png" alt="The 0 to 10000 slot axis for the arrival-flow surface, and the mod 100 split into control and treatment" width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slots live in a sorted table per surface, so picking one is a binary search:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;findSlot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nn"&gt;Experiments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;experiment&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;, &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Belt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;middle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;, &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Belt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;, &lt;span class="n"&gt;middle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;.&lt;span class="n"&gt;allocation&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;low&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middle&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;high&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;middle&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;None&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Belt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getUnsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;, &lt;span class="n"&gt;low&lt;/span&gt;.&lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;, &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt;.&lt;span class="n"&gt;allocation&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nc"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The whole path from cookie to variant is one hash, one modulo, and one comparison:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A["visitorId + ':surface:' + surface"] --&amp;gt; B[FNV-1a 32-bit hash]
    B --&amp;gt; C["mod 10000 → bucket 0..9999"]
    C --&amp;gt; D[Binary search sorted allocation table]
    D --&amp;gt; E[Experiment owns that slot]
    E --&amp;gt; F["bucket % 100 &amp;lt; 50 → control / treatment"]&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  Rules: eligibility and effects
&lt;/h2&gt;

&lt;p&gt;Experiments and rules both end in a patch, but they get there differently. An experiment is picked by slot and then filtered by &lt;code&gt;eligibleWhen&lt;/code&gt;, so a visitor can be in a slot and still hold out. A rule has no allocation at all: its &lt;code&gt;when&lt;/code&gt; clause is the entire gate, and it applies whenever that clause is true.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@genType&lt;/span&gt; &lt;span class="nd"&gt;@tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="k"&gt;rec&lt;/span&gt; &lt;span class="n"&gt;rule&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"all"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;All&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"any"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"not"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Not&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;: &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"eq"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nd"&gt;@live&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="n"&gt;value&lt;/span&gt;: &lt;span class="n"&gt;country&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nd"&gt;@as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"flag"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Flag&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Predicates are data too, and the demo ships two of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ruleEffects&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ruleEffect&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"india-seasonal-offers"&lt;/span&gt;,
    &lt;span class="n"&gt;owns&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;OffersVisible&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;,
    &lt;span class="n"&gt;when_&lt;/span&gt;: &lt;span class="nc"&gt;All&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="n"&gt;rules&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;Flag&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="s2"&gt;"seasonal-offers"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;, &lt;span class="nc"&gt;Eq&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;: &lt;span class="s2"&gt;"visitor.country"&lt;/span&gt;, &lt;span class="n"&gt;value&lt;/span&gt;: &lt;span class="nc"&gt;#IN&lt;/span&gt;&lt;span class="p"&gt;})]&lt;/span&gt;,
    &lt;span class="p"&gt;})&lt;/span&gt;,
    &lt;span class="n"&gt;patch&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;offersVisible&lt;/span&gt;: &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;,
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;: &lt;span class="s2"&gt;"planning-guide-flag"&lt;/span&gt;,
    &lt;span class="n"&gt;owns&lt;/span&gt;: &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;PlanningGuideVisible&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;,
    &lt;span class="n"&gt;when_&lt;/span&gt;: &lt;span class="nc"&gt;Flag&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;: &lt;span class="s2"&gt;"planning-guide"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;,
    &lt;span class="n"&gt;patch&lt;/span&gt;: &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;planningGuideVisible&lt;/span&gt;: &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;,
  &lt;span class="p"&gt;}&lt;/span&gt;,
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;decodeRule&lt;/code&gt; validates the JSON shape of a predicate and rejects unknown fields, flags, and rule nodes, so &lt;code&gt;evaluateValidatedRule&lt;/code&gt; can walk the tree without re-checking anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resolution and provenance
&lt;/h2&gt;

&lt;p&gt;Resolution applies patches in a fixed order: the selected experiments first, then the rules. A second write to the same path is a failure, not an overwrite, and every write records its source. That pairing is what makes the inspector honest, because a value and its reason are produced by the same line of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;: &lt;span class="n"&gt;decisionPatch&lt;/span&gt;, &lt;span class="n"&gt;owner&lt;/span&gt;, &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Registry codecs have validated these wire keys and values already.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;: &lt;span class="kt"&gt;array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;, &lt;span class="n"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Belt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;, &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;getOwn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writtenBy&lt;/span&gt;, &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;previous&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Decision write conflict on "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;": "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;previous&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;" and "&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nn"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writtenBy&lt;/span&gt;, &lt;span class="n"&gt;name&lt;/span&gt;, &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;decodePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;HeroLayout&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;heroLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;heroLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;SearchLayout&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;searchLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;searchLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;DestinationCardLayout&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;destinationCardLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;destinationCardLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;DestinationsColumns&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;destinationsColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;destinationsColumns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;OffersVisible&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;offersVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;offersVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlanningGuideVisible&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;planningGuideVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;planningGuideVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;PlanningGuideDetail&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;planningGuideDetail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;provenance&lt;/span&gt;.&lt;span class="n"&gt;planningGuideDetail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A snapshot for one visitor (country &lt;code&gt;IN&lt;/code&gt;, &lt;code&gt;offers=on&lt;/code&gt;, arrival-flow treatment) carries a badge per value:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fisjs2dukk2u0vn1ggf7o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fisjs2dukk2u0vn1ggf7o.png" alt="A decision snapshot: seven paths with values, and badges marking default, rule, and experiment writes" width="800" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The order of operations, from query string to provenance:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A[Search params] --&amp;gt; B[validatePageSearch allowlist]
    B --&amp;gt; C[Rule context: country + flags]
    C --&amp;gt; D[Allocate: one experiment per surface]
    D --&amp;gt; E[Resolve: apply experiment then rule patches]
    E --&amp;gt; F[decisionSnapshot]
    F --&amp;gt; G["provenance: default | rule | experiment"]&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  Preview overrides and the decision inspector
&lt;/h2&gt;

&lt;p&gt;In development, query params force a variant: &lt;code&gt;?exp.arrival-flow=treatment&lt;/code&gt;. The allowlist decides what survives the trip. An unknown key is dropped, and a recognized key whose value is malformed stays in the snapshot as a diagnostic instead of disappearing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;recognized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"country"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"offers"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"guide"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;, &lt;span class="s2"&gt;"exp."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
  &lt;span class="n"&gt;own&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Experiments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decisionRegistry&lt;/span&gt;.&lt;span class="n"&gt;experimentById&lt;/span&gt;, &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;, ~&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="nd"&gt;@genType&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;validatePageSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;: &lt;span class="n"&gt;unknown&lt;/span&gt;, &lt;span class="n"&gt;production&lt;/span&gt;: &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="n"&gt;pageSearch&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dictionary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="nn"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nn"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nn"&gt;Belt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;, &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"destination"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;production&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;recognized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nn"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;#string&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nn"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;, &lt;span class="n"&gt;key&lt;/span&gt;, &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The decision inspector is a development-only panel that prints every resolved value next to its provenance, lists ignored overrides with their raw values, and lets you flip country, flags, and individual experiments to re-render the page from a new snapshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signed cookies and rollout flags
&lt;/h2&gt;

&lt;p&gt;Identity is a cookie. In production that cookie is a UUID plus an HMAC-SHA-256 signature: the edge proxy verifies it or issues a new one, and the page verifies it again before the engine sees it. A missing, tampered, or unsigned cookie is treated as no identity at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createHmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sha256&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;visitorFromCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;cookie&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;([&lt;/span&gt;&lt;span class="sr"&gt;0-9a-f-&lt;/span&gt;&lt;span class="se"&gt;]{36})\.([&lt;/span&gt;&lt;span class="sr"&gt;0-9a-f&lt;/span&gt;&lt;span class="se"&gt;]{64})&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;timingSafeEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;visitorCookie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I left out the &lt;code&gt;uuid&lt;/code&gt; regex constant above those functions, which checks the UUID shape before any signature comparison happens.&lt;/p&gt;

&lt;p&gt;Rollout configuration is validated the same way, eagerly, at startup. Flag values accept only &lt;code&gt;on&lt;/code&gt;, empty, or absent, and anything else throws before the server listens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;on&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Invalid &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: expected on or empty`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;on&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The disabled-experiment list and the production cookie secret get the same treatment, both inside &lt;code&gt;readRollout&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;readRollout&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;rollout&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;cookieSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;known&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;experiments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;disabledIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DECISION_DISABLED_EXPERIMENTS&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;disabledIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;known&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Invalid DECISION_DISABLED_EXPERIMENTS: unknown experiment &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;cookieSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cookieSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DECISION_COOKIE_SECRET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cookieSecret&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;byteLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cookieSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid DECISION_COOKIE_SECRET: at least 32 UTF-8 bytes required&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;seasonalOffers&lt;/code&gt; and &lt;code&gt;planningGuide&lt;/code&gt; are read with the same &lt;code&gt;flag()&lt;/code&gt; call, so both accept only absent, empty, or &lt;code&gt;on&lt;/code&gt;, and &lt;code&gt;off&lt;/code&gt; fails startup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crossing the ReScript ↔ TypeScript boundary
&lt;/h2&gt;

&lt;p&gt;genType emits a &lt;code&gt;.gen.tsx&lt;/code&gt; and a &lt;code&gt;.res.mjs&lt;/code&gt; per module, which is how the &lt;code&gt;RegistryCore&lt;/code&gt; and &lt;code&gt;RegistryUi&lt;/code&gt; namespaces become importable TypeScript. &lt;code&gt;@live&lt;/code&gt;, &lt;code&gt;@as&lt;/code&gt;, and &lt;code&gt;@tag&lt;/code&gt; carry the wire contract across, so the TS side sees the same strings the JSON has.&lt;/p&gt;

&lt;p&gt;The React shell needs one context and one hook, and that is the entire UI-side integration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RegistryCore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;DecisionTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decisionValues&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;: &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@react.component&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;~&lt;span class="n"&gt;values&lt;/span&gt;: &lt;span class="n"&gt;values&lt;/span&gt;, ~&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;useDecision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selector&lt;/span&gt;: &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;: &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;JsError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;throwWithMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"useDecision requires a DecisionProvider"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A page component then reads a single field through that hook, and the field name is checked by the ReScript compiler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;heroLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;DecisionProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useDecision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;.&lt;span class="n"&gt;heroLayout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One more adaptation lives in &lt;code&gt;apps/web/src/server/page-data.ts&lt;/code&gt;, where &lt;code&gt;resolved&lt;/code&gt;, &lt;code&gt;assignments&lt;/code&gt;, and &lt;code&gt;ignored&lt;/code&gt; are spread into plain objects before they cross into React Flight, because null-prototype dictionaries are not accepted there.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this cost us
&lt;/h2&gt;

&lt;p&gt;Registering an experiment is ceremony. Every new one needs an &lt;code&gt;id&lt;/code&gt;, a &lt;code&gt;surface&lt;/code&gt;, an &lt;code&gt;allocation&lt;/code&gt;, an &lt;code&gt;owns&lt;/code&gt; list, and both variants declared before anything renders. The registry catches the mistakes at startup, but I still wrote that record by hand each time.&lt;/p&gt;

&lt;p&gt;ReScript is a second compiler and a second syntax. The OCaml heritage shows up in &lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;Belt.Array&lt;/code&gt;, and pipe-first argument order, and the exhaustiveness that makes the engine safe also means every new &lt;code&gt;path&lt;/code&gt; case touches every consumer.&lt;/p&gt;

&lt;p&gt;The wire still speaks strings. &lt;code&gt;hero.layout&lt;/code&gt; appears as a string in the JSON, in the serialized snapshot, and in the generated TypeScript types. The variants only exist after validation, which is a real cost in a codebase that is mostly TypeScript.&lt;/p&gt;

&lt;p&gt;Identity is one sticky cookie. Anyone who clears cookies or switches devices is a new visitor to the engine, and there is no cross-device merge.&lt;/p&gt;

&lt;p&gt;Nothing tracks exposure or conversions. The inspector panel states that in one line, and it is accurate: the engine assigns deterministically and reports provenance, and analytics are out of scope for the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it yourself
&lt;/h2&gt;

&lt;p&gt;Node &amp;gt;= 22.12 and pnpm 12.4.2 are the only prerequisites.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm &lt;span class="nb"&gt;exec &lt;/span&gt;playwright &lt;span class="nb"&gt;install &lt;/span&gt;chromium
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DB_FILE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/absolute/path/to/catalog.db
pnpm db:setup
pnpm dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://127.0.0.1:3000&lt;/code&gt;, then try &lt;code&gt;/?exp.arrival-flow=treatment&amp;amp;country=IN&amp;amp;offers=on&lt;/code&gt; to see a forced variant, a forced country, and the India offers rule land in the same snapshot. All of it is in &lt;a href="https://github.com/piyushchauhan2011/rescript-react-nextjs" rel="noopener noreferrer"&gt;the Elsewhere repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why ReScript instead of TypeScript?
&lt;/h3&gt;

&lt;p&gt;Exhaustive matching turns an omitted variant into a compile error, and this engine leans on that harder than on any other language feature: a new &lt;code&gt;path&lt;/code&gt; case cannot be added without updating every consumer. The typed core is roughly 900 lines of &lt;code&gt;.res&lt;/code&gt; across eight modules, with the whole domain expressed as variants.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I add a new experiment?
&lt;/h3&gt;

&lt;p&gt;Add one record to the &lt;code&gt;experiments&lt;/code&gt; array in &lt;code&gt;packages/core/src/Experiments.res&lt;/code&gt; with an &lt;code&gt;id&lt;/code&gt;, a &lt;code&gt;surface&lt;/code&gt;, an &lt;code&gt;allocation&lt;/code&gt;, an &lt;code&gt;owns&lt;/code&gt; list, and both &lt;code&gt;variants&lt;/code&gt;. &lt;code&gt;createDecisionRegistry&lt;/code&gt; validates it at startup: duplicate IDs, overlapping allocations, and paths already owned by another experiment or rule all throw before a request runs.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I kill an experiment in production?
&lt;/h3&gt;

&lt;p&gt;Set &lt;code&gt;DECISION_DISABLED_EXPERIMENTS&lt;/code&gt; to a comma-separated list of registered IDs. Unknown IDs reject startup, and the disabled set is applied to allocation as well as resolution, so a disabled experiment stops writing even if a preview URL forces it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does it track conversions or metrics?
&lt;/h3&gt;

&lt;p&gt;No. The engine assigns a variant deterministically and records which layer wrote each value, and that is all it does. Exposure logging, conversion events, and analysis are out of scope for the demo, which the inspector says in one line.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>typescript</category>
      <category>architecture</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I Built a .NET + React Islands Site With a Playwright Snapshot Worker</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Sat, 26 Sep 2026 15:35:31 +0000</pubDate>
      <link>https://dev.to/frorning/how-i-built-a-net-react-islands-site-with-a-playwright-snapshot-worker-56h7</link>
      <guid>https://dev.to/frorning/how-i-built-a-net-react-islands-site-with-a-playwright-snapshot-worker-56h7</guid>
      <description>&lt;p&gt;&lt;em&gt;Razor owns the pages. React owns a few interactions. A separate browser publishes the finished HTML before anyone visits.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: interactive pages without browser rendering per visitor
&lt;/h2&gt;

&lt;p&gt;Imagine opening &lt;code&gt;/hotels/casa-aurelia&lt;/code&gt;. You should get the hotel's description, prices, photos, and metadata in the HTML response. Then, if you click a photo, a gallery dialog should open. A client-only SPA that initially sends a nearly empty shell makes discovery of that content depend on executing JavaScript; rendering Chromium on every visitor request would solve a different problem at a high operational cost. I wanted crawlable first-response HTML &lt;strong&gt;and&lt;/strong&gt; hydration, without either compromise.&lt;/p&gt;

&lt;p&gt;This project is a hotel-and-editorial site built with ASP.NET Core 10 Razor Pages, React islands, PostgreSQL, and a Node/Playwright worker. The public site has catalog pages, a journal, search, and a stay &lt;strong&gt;inquiry&lt;/strong&gt; flow—not a reservation or payment system. Its editors have a separate protected React admin. The awkward part is that the public gallery and other islands begin as empty markers in Razor: rendering only Razor would ship the page content but not the gallery's initial HTML.&lt;/p&gt;

&lt;p&gt;My solution was to move browser execution to &lt;strong&gt;publication time&lt;/strong&gt;. Razor generates the source document; a background Chromium process mounts its islands, validates the result, and saves the completed HTML in PostgreSQL. The public gateway serves that saved document. The visitor's browser hydrates the already populated islands for interaction. This is browser-rendered React at publication time, &lt;strong&gt;not React server-side rendering in .NET&lt;/strong&gt;, and Chromium is not on the visitor request path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who owns what?
&lt;/h2&gt;

&lt;p&gt;The architecture becomes easier to reason about when each layer has a narrow job:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;th&gt;What it does not own&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ASP.NET Core Razor Pages&lt;/td&gt;
&lt;td&gt;Public routes, catalog and article content, HTML shell, SEO title, description, canonical links, structured data, and no-JS results&lt;/td&gt;
&lt;td&gt;React's interactive state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React islands&lt;/td&gt;
&lt;td&gt;Search/date controls, gallery, mobile navigation, and inquiry form interaction&lt;/td&gt;
&lt;td&gt;Public-page routing or the catalog's canonical HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;React Router admin&lt;/td&gt;
&lt;td&gt;Protected editor UI behind the server's document guard and APIs&lt;/td&gt;
&lt;td&gt;Public visitor routes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;Catalog, snapshot jobs, and published HTML&lt;/td&gt;
&lt;td&gt;Browser rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Playwright worker&lt;/td&gt;
&lt;td&gt;Off-request source-page capture, validation, and conditional publication&lt;/td&gt;
&lt;td&gt;Serving a visitor request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The distinction between content and controls matters. Razor writes the hotel heading, text, cards, and inquiry link. It also renders search results and GET-based sort/pagination so those remain useful without JavaScript. React adds the gallery dialog and richer search controls; those controls do need JavaScript. The admin is deliberately different: it is a protected React Router SPA, not an island pretending to be a public page.&lt;/p&gt;

&lt;p&gt;This arrangement does not claim that every part of the site works without JavaScript. It makes the &lt;strong&gt;public content and search-results path&lt;/strong&gt; independently useful while treating interactive controls as an enhancement with an explicit dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  One request, two paths
&lt;/h2&gt;

&lt;p&gt;A canonical public GET or HEAD—such as &lt;code&gt;/hotels/casa-aurelia&lt;/code&gt;, a journal post, or bare &lt;code&gt;/search&lt;/code&gt;—passes through the snapshot gateway. It looks up a published HTML document by path. The document already includes Razor content &lt;strong&gt;and&lt;/strong&gt; the gallery markup produced by Chromium. Only after delivery does the visitor's React runtime attach behavior.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    V[Visitor GET /hotels/casa-aurelia] --&amp;gt; G[ASP.NET snapshot gateway]
    G --&amp;gt; P[(PostgreSQL published HTML)]
    P --&amp;gt; H[HTML with populated islands]
    H --&amp;gt; B[Visitor browser hydrates controls]
    Q[Filtered /search?..., inquiry, admin] --&amp;gt; L[Live private server route]
    L --&amp;gt; R[Dynamic response, not public snapshot]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The second path is not an exception hidden behind a cache key. &lt;code&gt;/search?destination=...&lt;/code&gt; is a live Razor result page with &lt;code&gt;private, no-store&lt;/code&gt; and &lt;code&gt;noindex,follow&lt;/code&gt;; the bare &lt;code&gt;/search&lt;/code&gt; page is eligible for a canonical snapshot. Inquiry pages and submissions, admin documents, and APIs are live/private, not publicly cached snapshot variants. This keeps a filter query, a guest's inquiry, or an editor session out of the shared HTML store.&lt;/p&gt;

&lt;p&gt;The gateway returns persisted HTML with &lt;code&gt;Cache-Control: public, max-age=60, stale-while-revalidate=300&lt;/code&gt;. That policy also sets the limit on how quickly an already cached public page may reflect an edit. It is a deliberate tradeoff, not instant global invalidation. In non-snapshot development mode the same canonical Razor pages can be served live; the diagram describes the snapshot-enabled delivery path.&lt;/p&gt;

&lt;h2&gt;
  
  
  How an island becomes published HTML
&lt;/h2&gt;

&lt;p&gt;Razor emits an island marker and JSON props. Here is the gallery marker excerpt from the hotel page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div data-island="Gallery" data-hydrate="visible"
     data-props="@(PublicPageModel.IslandProps(new
     {
         name = hotel.Name,
         items = stay.Gallery.Select(x =&amp;gt; new
         {
             x.Id, x.Src, x.Alt, x.Caption, x.Category, x.RoomId
         })
     }))"&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;_Layout.cshtml&lt;/code&gt; likewise supplies the shared &lt;code&gt;MobileNav&lt;/code&gt; marker and the runtime script, and owns the document's metadata. The marker above is empty in the Razor source. &lt;code&gt;data-island&lt;/code&gt; selects a dynamically imported component; &lt;code&gt;data-props&lt;/code&gt; passes its serialized input; &lt;code&gt;data-hydrate="visible"&lt;/code&gt; tells the &lt;strong&gt;visitor&lt;/strong&gt; runtime that it can defer mounting until near the viewport.&lt;/p&gt;

&lt;p&gt;The worker visits &lt;code&gt;/_snapshot-source?path=/hotels/casa-aurelia&lt;/code&gt; with a private token. That route only delegates to Razor for an allowed canonical path that has a job or an existing snapshot. On the protected source page, the island runtime mounts &lt;strong&gt;all&lt;/strong&gt; markers, even normally deferred ones. When every mount's effect has run, it sets &lt;code&gt;window.__SNAPSHOT_READY__&lt;/code&gt;. Playwright waits for that signal and for successful browser execution before serializing the document. It rejects invalid documents rather than saving a partial render: among its checks are the canonical path, exactly one &lt;code&gt;h1&lt;/code&gt;, populated islands, the expected runtime script, absence of private-form inputs and the token, and browser errors. It also strips Chromium-added Vite modulepreload hints and inserts separators between adjacent island text nodes so the saved HTML can hydrate correctly.&lt;/p&gt;

&lt;p&gt;On a visitor's request, this HTML already contains a gallery grid &lt;strong&gt;inside the same marker&lt;/strong&gt;. The runtime checks whether the marker has child markup. Its essential choice is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Excerpt from the public island runtime; Ready wraps the imported component.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;hydrateRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Ready&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;marker&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Ready&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;hydrateRoot&lt;/code&gt; attaches to captured markup; &lt;code&gt;createRoot&lt;/code&gt; fills an empty marker in live Razor development or another uncaptured context. Visitors defer &lt;code&gt;visible&lt;/code&gt; islands with &lt;code&gt;IntersectionObserver&lt;/code&gt; (with a near-viewport margin), whereas the source-page capture mounts them eagerly. There is no duplicate static gallery fallback sitting beside a second React gallery. Without JavaScript, the published gallery grid and Razor text are still present, but its dialog and other island controls will not work.&lt;/p&gt;

&lt;p&gt;This is testable as behavior, not just a design sketch. The repository's &lt;code&gt;tests/e2e/hydration.spec.ts&lt;/code&gt; reads the published hotel HTML and finds one &lt;code&gt;.gallery-grid&lt;/code&gt; inside the gallery island with no duplicate fallback. It then loads that hotel page, opens a gallery image, advances to the next photo, and closes the dialog. The static representation survives delivery and the same representation gains interaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing without serving stale work
&lt;/h2&gt;

&lt;p&gt;The worker needs a precise answer to a race: what if an editor changes the hotel again while Chromium is rendering the first change? Saving that first render afterward would roll the public page backward.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A[Admin edits catalog] --&amp;gt; T[One DB transaction: content + affected jobs]
    T --&amp;gt; J[(Versioned snapshot jobs)]
    J --&amp;gt; W[Worker leases due job]
    W --&amp;gt; S[Token-protected Razor source]
    S --&amp;gt; C[Chromium mounts islands; waits; validates]
    C --&amp;gt; X{Job version still current?}
    X -- Yes --&amp;gt; P[Atomic HTML upsert + job removal]
    X -- No --&amp;gt; D[Discard obsolete capture]
    P --&amp;gt; G[Gateway serves published HTML]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Admin publication and affected-route invalidation share a database transaction. Editing a hotel can affect its own route, destination listing/detail, bare search, home page, offer pages, and published articles that embed catalog records. Renames include old paths. A route that is no longer published loses its snapshot and job immediately rather than retaining discoverable old HTML. Valid published routes get a new desired job version.&lt;/p&gt;

&lt;p&gt;The worker leases due jobs using PostgreSQL &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt;, renders the protected Razor source in its own Chromium context, and checks the job's &lt;strong&gt;current&lt;/strong&gt; desired version under a row lock before inserting/updating the HTML and deleting the job in one transaction. If the version changed, it discards the obsolete capture. Errors never publish a partial document: the job is released and retried with exponential backoff. The old complete snapshot stays available while a published route is regenerated.&lt;/p&gt;

&lt;p&gt;A first-time canonical path has no old document to serve. If it is queued, the gateway responds &lt;code&gt;503&lt;/code&gt; with &lt;code&gt;Retry-After: 5&lt;/code&gt; until publication succeeds. Unknown or unpublished detail routes return &lt;code&gt;404&lt;/code&gt; (the fixed canonical index routes can return &lt;code&gt;503&lt;/code&gt; while their first capture is pending). Once a route is unpublished or renamed, its persisted HTML is removed immediately; already cached copies may still live for the declared cache window, so publication and caching policy must be understood together.&lt;/p&gt;

&lt;h2&gt;
  
  
  What must never be snapshotted
&lt;/h2&gt;

&lt;p&gt;The easiest way to leak private data would be to treat the snapshot store as a generic response cache. It is not. Its key is a canonical public &lt;strong&gt;path&lt;/strong&gt;, not arbitrary combinations of query string, cookies, authentication, or POST body. Filtered search remains a live private response. The inquiry flow carries personal input, is CSRF-protected, and must remain private. Admin sessions and protected API responses cannot become public snapshots either.&lt;/p&gt;

&lt;p&gt;The source endpoint is also a security boundary. It requires a sufficiently long &lt;code&gt;SNAPSHOT_INTERNAL_TOKEN&lt;/code&gt;, compares the supplied header, rejects unrecognized canonical routes, sends &lt;code&gt;private, no-store&lt;/code&gt; and &lt;code&gt;noindex&lt;/code&gt;, and should be blocked from the public ingress as well. A robots directive alone would not secure it. The worker restricts fetched resources to its configured API origin and validates the captured result before publication; neither check replaces proper network isolation and authentication.&lt;/p&gt;

&lt;p&gt;The worker rejects a source document containing password or antiforgery inputs, a token string, unexpected executable scripts, missing canonical metadata, unrendered islands, or browser errors. These checks are a publishing guard, not a blanket proof that arbitrary application data is safe to cache. The safe baseline remains an explicit allowlist of canonical public routes and a separate live/private path for anything user-specific.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SEO advantage over a client-only SPA
&lt;/h2&gt;

&lt;p&gt;A client-only SPA can be indexed by search engines that render JavaScript, but its initial HTML may contain little more than an app root. Content discovery then depends on fetching and running scripts successfully; rendering can be delayed or missed by crawlers that do not execute them. A React SPA with SSR or prerendering does &lt;strong&gt;not&lt;/strong&gt; have that limitation by definition. The comparison here is with a &lt;strong&gt;client-rendered shell&lt;/strong&gt;, not with all SPAs.&lt;/p&gt;

&lt;p&gt;For a published hotel URL, a crawler's first HTML response already contains the hotel heading, description, links, gallery markup, and metadata. It does not have to execute React to discover the principal content. Razor provides the page-specific title and description, a canonical URL, and &lt;code&gt;Hotel&lt;/code&gt; JSON-LD; the worker preserves these in the published document. The gateway generates &lt;code&gt;robots.txt&lt;/code&gt; and an XML sitemap of catalog-published canonical routes. When a route is unpublished, it is removed from that sitemap and its stored HTML is deleted. Bare &lt;code&gt;/search&lt;/code&gt; is canonical; filtered search URLs specify &lt;code&gt;noindex,follow&lt;/code&gt; to avoid indexing many query variants. Inquiry and admin documents are marked &lt;code&gt;noindex&lt;/code&gt; and are not public snapshots.&lt;/p&gt;

&lt;p&gt;This is the outcome I like about prerender-then-hydrate designs: &lt;strong&gt;content is present before client JavaScript, while controls become interactive after hydration&lt;/strong&gt;. It shares that goal with several other rendering strategies, but the publication boundary here is different.&lt;/p&gt;

&lt;p&gt;The concrete SEO benefit is a more reliable path for crawlers to discover and assess canonical content, links, and metadata. It is not a guaranteed ranking. A sitemap is a discovery hint, structured data does not guarantee a rich result, and an indexable response does not mean a search engine will index or rank it. A newly queued URL returns &lt;code&gt;503&lt;/code&gt; until its first capture; finish publication before directing production traffic or crawlers to it. After an origin change, wait for republishing and check the actual canonical URLs in the returned HTML: &lt;code&gt;PUBLIC_ORIGIN&lt;/code&gt; is embedded at capture time. Old cached pages can also persist briefly after an edit or removal.&lt;/p&gt;

&lt;p&gt;Lighthouse audits the loaded page, so it is not a direct test of what a no-JavaScript crawler sees. Here, the first response already exposes content and metadata, while off-request publication avoids Chromium work on the visitor path; both are useful starting conditions. But a high Lighthouse &lt;strong&gt;performance&lt;/strong&gt; score is not automatic: React chunks, CSS, images, fonts, server/cache behavior, hydration work, and audit settings still affect LCP, CLS, and interactivity. Deferred visible islands and removal of captured modulepreload hints can reduce unnecessary upfront work. Audit the &lt;strong&gt;published snapshot&lt;/strong&gt;, not Vite HMR: the repository documents &lt;code&gt;make lighthouse-https&lt;/code&gt; for a local HTTPS run and &lt;code&gt;pnpm lighthouse&lt;/code&gt; for its desktop preset. Compare repeated runs under the same conditions and inspect the generated HTML, canonical, robots directives, sitemap, and metric breakdown rather than quoting a single score.&lt;/p&gt;

&lt;h2&gt;
  
  
  How SSR, SSG, ISR, and PPR compare
&lt;/h2&gt;

&lt;p&gt;These names describe &lt;strong&gt;when and where HTML is produced&lt;/strong&gt;, not whether React can hydrate it. Each can ship crawlable HTML when configured to render the actual public content. The useful question for this site was where to pay the rendering cost and how to update edited catalog pages.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;When HTML is produced&lt;/th&gt;
&lt;th&gt;Advantage&lt;/th&gt;
&lt;th&gt;Cost or mismatch for this site&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSR (server-side rendering)&lt;/td&gt;
&lt;td&gt;On each request, potentially cached afterward&lt;/td&gt;
&lt;td&gt;Fresh request-specific data; a natural fit for personalized search or inquiry pages&lt;/td&gt;
&lt;td&gt;Uncached rendering and data access add request-path work; cache keys and private data need care&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSG (static site generation)&lt;/td&gt;
&lt;td&gt;At build time&lt;/td&gt;
&lt;td&gt;Simple, fast delivery of already complete public HTML&lt;/td&gt;
&lt;td&gt;Catalog edits or new pages need a rebuild and redeploy unless another regeneration mechanism is added&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ISR (incremental static regeneration)&lt;/td&gt;
&lt;td&gt;Initially prerendered or generated on demand, then regenerated after revalidation&lt;/td&gt;
&lt;td&gt;Reuses HTML between visits and can refresh without rebuilding the whole site&lt;/td&gt;
&lt;td&gt;Refresh policy and stale windows must be managed; in the common request-triggered model, regeneration waits for traffic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PPR (Partial Prerendering)&lt;/td&gt;
&lt;td&gt;Static shell prepared ahead of time; dynamic regions render and stream at request time&lt;/td&gt;
&lt;td&gt;Static content can arrive early while request-specific regions stay dynamic&lt;/td&gt;
&lt;td&gt;More per-request rendering and cache-boundary coordination than these wholly public canonical documents need&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;This site's snapshot publication&lt;/td&gt;
&lt;td&gt;Razor source plus browser-mounted islands captured for queued paths after catalog edits or release changes, then stored in PostgreSQL&lt;/td&gt;
&lt;td&gt;Full public HTML and hydrated controls, with no Chromium on visitor requests; versioned jobs can target affected routes&lt;/td&gt;
&lt;td&gt;Publication delay, first-capture &lt;code&gt;503&lt;/code&gt;, and a database/browser worker to operate; private routes still need live rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The closest analogy is ISR's &lt;strong&gt;last-good HTML while regenerating&lt;/strong&gt;, not an identical implementation. This worker queues affected paths when editors publish, captures eagerly in the background, and discards a capture if its desired version changed. It does not wait for a visitor or a timer to trigger regeneration. PPR is also not what happens here: the canonical snapshot is a complete shared document, not a static shell with request-time streamed islands. The project's filtered search and inquiry pages use live Razor responses instead. &lt;a href="https://nextjs.org/docs/app/guides/incremental-static-regeneration" rel="noopener noreferrer"&gt;Next.js describes ISR's request-triggered revalidation&lt;/a&gt; and &lt;a href="https://nextjs.org/docs/app/getting-started/caching" rel="noopener noreferrer"&gt;its static-shell/streamed-region model&lt;/a&gt;; those are comparisons, not dependencies of this .NET implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tradeoffs and running it
&lt;/h2&gt;

&lt;p&gt;The split removes Chromium from visitor latency, but adds a publication pipeline. An edit can take time to appear; a new page waits for its first successful capture. If the worker, Chromium, or PostgreSQL is unavailable, publication stalls even while an old complete snapshot may continue to be served. No performance score or SEO result follows automatically from this architecture: measure the deployed site and audit the generated document.&lt;/p&gt;

&lt;p&gt;Locally I use two different modes from the repository root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm dev             &lt;span class="c"&gt;# Live Razor pages and Vite HMR; no snapshot worker required&lt;/span&gt;
pnpm dev:snapshots   &lt;span class="c"&gt;# Build Vite manifest; run .NET plus continuous worker&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The production-like mode needs PostgreSQL, a valid internal token, and Playwright Chromium; the quick-start guide covers initial setup and seeding. When it first starts, a new canonical route may answer &lt;code&gt;503&lt;/code&gt; until captured. Failed jobs back off rather than writing half a page, so a persistent &lt;code&gt;503&lt;/code&gt; is a reason to inspect worker logs and the snapshot job table—not to bypass the gateway.&lt;/p&gt;

&lt;p&gt;Deploy the API and worker from the &lt;strong&gt;same release&lt;/strong&gt;: the worker's asset fingerprint includes the Vite manifest, relevant source files, and &lt;code&gt;PUBLIC_ORIGIN&lt;/code&gt;. A changed fingerprint requeues stored pages; changing &lt;code&gt;PUBLIC_ORIGIN&lt;/code&gt; matters because canonical links are embedded in HTML. Keep old hashed assets available while old snapshots still reference them, and restart a running API after rebuilding its manifest in snapshot mode. Otherwise an intact stored page can point at a chunk the server no longer serves. These are operational costs of publishing HTML with client-side hydration rather than computing every page on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design rule I kept
&lt;/h2&gt;

&lt;p&gt;Give the public document a single owner and give interactivity a clear boundary. Here, Razor defines the public page and its metadata; a background browser completes its islands once for publication; React hydrates that exact markup for visitors. The protected admin and user-specific flows never cross into the public snapshot store.&lt;/p&gt;

&lt;p&gt;That buys immediately useful content without putting Chromium on each request. It also makes the limitations visible: editorial publication delay, a PostgreSQL-and-browser worker to operate, JavaScript required for controls, and strict route/cache/security boundaries. For this site, those are easier to reason about than making the entire public experience depend on a client-rendered shell or hiding a browser render in the request path.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Github: &lt;a href="https://github.com/piyushchauhan2011/dotnet-islands" rel="noopener noreferrer"&gt;https://github.com/piyushchauhan2011/dotnet-islands&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>dotnet</category>
      <category>react</category>
      <category>architecture</category>
      <category>playwright</category>
    </item>
    <item>
      <title>Integration Is the Product: Platform Engineering for Fast Frontend Teams</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Sat, 12 Sep 2026 13:26:14 +0000</pubDate>
      <link>https://dev.to/frorning/integration-is-the-product-platform-engineering-for-fast-frontend-teams-1df8</link>
      <guid>https://dev.to/frorning/integration-is-the-product-platform-engineering-for-fast-frontend-teams-1df8</guid>
      <description>&lt;p&gt;&lt;em&gt;How local composition, exact artifacts, and versioned releases turn a dependency queue into continuous feedback.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpdmfwsn02t6q7w3ap3kd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpdmfwsn02t6q7w3ap3kd.png" alt="A visual overview of the four feedback loops: local workbench, real product shell, PR preview, and versioned release." width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The useful measure of team autonomy is not “can it publish?” It is “how quickly can the team see its exact change running in a realistic product?”&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A frontend package can compile, test, and publish successfully—and still break when the product shell owns routing, authentication, server-side rendering (SSR), hydration, global styles, middleware, or a singleton dependency such as React.&lt;/p&gt;

&lt;p&gt;I learned this through a familiar local loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build package → pnpm pack → edit the shell's package.json → install → run → discover → repeat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That loop proves the product boundary matters. It is also a warning: integration has become manual, temporary state leaks into committed files, and every cross-team change waits for the central application to catch up.&lt;/p&gt;

&lt;p&gt;The answer is not “never integrate” or “put everything in a monorepo.” The answer is to make integration a &lt;strong&gt;self-service product capability&lt;/strong&gt;: composable locally, verified as an artifact, previewable in a pinned product, and promotable as an immutable release.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model in one picture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8xr2428kx3qceib0git.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft8xr2428kx3qceib0git.png" alt="Four feedback loops progress from a fast local workbench to a real shell, an exact-artifact preview, and an immutable release." width="800" height="345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each loop answers a different question. Do not make the slowest one the default.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Loop&lt;/th&gt;
&lt;th&gt;Question it answers&lt;/th&gt;
&lt;th&gt;Default use&lt;/th&gt;
&lt;th&gt;Evidence it produces&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1. Domain workbench&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the domain feature behave correctly?&lt;/td&gt;
&lt;td&gt;Daily implementation&lt;/td&gt;
&lt;td&gt;Fast, deterministic UI and contract feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2. Local product composition&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does my source work in the real shell?&lt;/td&gt;
&lt;td&gt;Host-boundary changes&lt;/td&gt;
&lt;td&gt;Routing, auth, SSR, hydration, styling feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3. PR product preview&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Does the artifact I intend to ship work in a clean product?&lt;/td&gt;
&lt;td&gt;Before merge&lt;/td&gt;
&lt;td&gt;A reviewable URL using exact candidate bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4. Versioned release&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Is this selected composition healthy under shared and production conditions?&lt;/td&gt;
&lt;td&gt;Promotion&lt;/td&gt;
&lt;td&gt;Canary and operational evidence&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important design rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A failure found in an outer loop should improve the cheapest inner loop that can catch it next time.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some failures—real traffic, irreversible migrations, external side effects—belong in the outer loop. Pretending every risk can move left makes local feedback less trustworthy, not more.&lt;/p&gt;

&lt;h2&gt;
  
  
  A concrete example: the Booking module
&lt;/h2&gt;

&lt;p&gt;Assume a &lt;strong&gt;Booking&lt;/strong&gt; frontend module mounted in a product shell. It calls Hotel APIs, participates in auth and routing, emits booking events, and server-renders UI.&lt;/p&gt;

&lt;p&gt;Here are the four boundaries where its “green” isolated build can still fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────┐    ┌────────────────────────┐
│ Booking package  │───▶│ Product shell          │
│ exports, assets, │    │ routing, auth, SSR,    │
│ peer dependencies│    │ hydration, CSS         │
└────────┬─────────┘    └──────────┬─────────────┘
         │                         │
         ▼                         ▼
┌──────────────────┐    ┌────────────────────────┐
│ Domain contracts │    │ Environment and data   │
│ Hotel API/events │    │ pinned versions, known │
│ errors, timing   │    │ scenarios, replayable  │
└──────────────────┘    └────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Build and artifact boundary
&lt;/h3&gt;

&lt;p&gt;Local linking can succeed while the published tarball omits types, CSS, assets, compiled files, or an export-map entry. It can also hide bad peer-dependency resolution.&lt;/p&gt;

&lt;p&gt;A particularly expensive frontend failure is a duplicate singleton: Booking bundles React or framework context while the shell expects to own it. Hooks, contexts, or hydration then fail only in the composed application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design consequence:&lt;/strong&gt; support fast local source overrides &lt;em&gt;and&lt;/em&gt; install the packed artifact into a clean shell in CI. Neither replaces the other.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Platform and runtime boundary
&lt;/h3&gt;

&lt;p&gt;A mini-shell is valuable, but it is not the product. The real shell may resolve auth asynchronously, evaluate flags on the server, enforce CSP, select locale, apply global CSS, and hydrate browser markup.&lt;/p&gt;

&lt;p&gt;A synchronous fake user can hide a lifecycle race. A &lt;code&gt;window&lt;/code&gt; access can pass locally and fail during SSR. A global selector can quietly override the product header.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design consequence:&lt;/strong&gt; teams need an easy route into the real shell before release—not a handoff to another team.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Domain contract boundary
&lt;/h3&gt;

&lt;p&gt;Types alone are not contracts. A Hotel response can make a field optional; an event can be duplicated; a shared package can preserve its type while changing runtime behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design consequence:&lt;/strong&gt; contracts need examples for absence, errors, timeout, compatibility, and delivery semantics. Providers own valid fakes; consumers own the assumptions they make.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Environment and data boundary
&lt;/h3&gt;

&lt;p&gt;A shared environment called &lt;code&gt;dev&lt;/code&gt; is usually a location, not a reproducible state. It may contain yesterday’s Hotel build, today’s Payment candidate, mutable test accounts, and an unannounced shell change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design consequence:&lt;/strong&gt; pin composition and provide named, deterministic data scenarios. A passing result should be attributable; a failure should be replayable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The paved road: two local modes, one composition contract
&lt;/h2&gt;

&lt;p&gt;The productive workflow is not “fake everything” versus “run the whole company.” It offers two intentionally different local modes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mode A: domain workbench
&lt;/h3&gt;

&lt;p&gt;The workbench mounts local Booking with the production rendering mode, design system, route contract, and named auth, flag, and locale scenarios. Hotel and Payment provide provider-owned fakes; inexpensive, behaviorally important infrastructure can run locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;platform dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it for focused work. It should be fast, deterministic, usable offline where practical, and let an engineer select success, absence, timeout, error, and authorization states in one command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mode B: real-shell composition
&lt;/h3&gt;

&lt;p&gt;The real product shell runs with released dependencies while the developer substitutes only local Booking source and gets HMR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;platform dev &lt;span class="nt"&gt;--composition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;integration-stable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it when the change touches routing, auth lifecycle, SSR/hydration, global CSS, middleware, or framework ownership. It removes the &lt;code&gt;pnpm pack&lt;/code&gt; / edit-manifest / reinstall loop without claiming to prove the tarball.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0dbd3cgh7mnvvye9bfxa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0dbd3cgh7mnvvye9bfxa.png" alt="A resolved composition makes every local override, remote dependency, and scenario visible." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Both modes resolve the same &lt;strong&gt;composition contract&lt;/strong&gt;. The interface can be a CLI, package-manager feature, dev server, container stack, or managed environment; the durable part is the input and output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;composition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integration-stable@sha256:8f1e...&lt;/span&gt;
&lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product-shell@13.2.1&lt;/span&gt;
&lt;span class="na"&gt;modules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;booking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local-source&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;../booking&lt;/span&gt;
    &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hotel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integration-stable&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5.8.2&lt;/span&gt;
  &lt;span class="na"&gt;payment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fake&lt;/span&gt;
    &lt;span class="na"&gt;scenario&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authorized&lt;/span&gt;
&lt;span class="na"&gt;scenarios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signed-in-customer&lt;/span&gt;
  &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;en-GB&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;booking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local-isolated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good &lt;code&gt;platform dev&lt;/code&gt; command does four things before it starts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resolves peer, shell-API, rendering-mode, and contract compatibility.&lt;/li&gt;
&lt;li&gt;Leaves the application’s normal &lt;code&gt;package.json&lt;/code&gt; and lockfile untouched.&lt;/li&gt;
&lt;li&gt;Watches &lt;strong&gt;only&lt;/strong&gt; explicit local overrides; released components remain immutable.&lt;/li&gt;
&lt;li&gt;Prints the resolved versions, modes, paths, scenario IDs, and manifest digest.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last point matters. “Works on my machine” is useful only when “it” has an identity another developer or CI job can reproduce.&lt;/p&gt;

&lt;p&gt;Useful companion commands are straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;platform preview  &lt;span class="c"&gt;# create or show this change's pinned preview&lt;/span&gt;
platform trace    &lt;span class="c"&gt;# inspect correlated diagnostics&lt;/span&gt;
platform doctor   &lt;span class="c"&gt;# explain peers, credentials, ports, versions, dependencies&lt;/span&gt;
platform reset    &lt;span class="c"&gt;# remove generated state; never normal project files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Let contracts unblock implementation—not conversation
&lt;/h2&gt;

&lt;p&gt;Composition accelerates feedback after code exists. Contracts solve the earlier scheduling problem: &lt;strong&gt;how can Booking start when Hotel is not finished?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The teams still need to agree on meaning. The goal is to turn that agreement into a versioned candidate someone can consume immediately.&lt;/p&gt;

&lt;p&gt;For a cancellable reservation hold, the sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Agree on the smallest useful contract.&lt;/strong&gt; Request, response, errors, idempotency, timeout expectations, and representative examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish a provider-owned candidate.&lt;/strong&gt; Hotel ships the contract plus valid fixtures, fake adapter, or mock server under an immutable candidate ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement the consumer against it.&lt;/strong&gt; Booking exercises success, absence, timeout/error, and compatibility scenarios in the workbench.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the provider against the same agreement.&lt;/strong&gt; Hotel’s CI verifies the implementation. Consumer-driven contracts can run concrete consumer expectations before merge; &lt;a href="https://docs.pact.io/" rel="noopener noreferrer"&gt;Pact&lt;/a&gt; is one option.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compose both candidates.&lt;/strong&gt; The preview pins Booking and Hotel candidates for product-level review.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep a declared compatibility window.&lt;/strong&gt; Support current and previous versions unless an exception is explicit and time-bounded.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;semantic decision
        │
        ▼
provider contract candidate ──────▶ consumer implementation
        │                                      │
        └──── provider verification ◀──────────┘
                         │
                         ▼
               pinned combined preview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This separates a necessary &lt;strong&gt;semantic dependency&lt;/strong&gt; from an avoidable &lt;strong&gt;implementation dependency&lt;/strong&gt;. Contract verification does not prove assembled-product behavior, so the combined preview remains necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the bytes you will release
&lt;/h2&gt;

&lt;p&gt;Source composition is for speed. Artifact verification is for release confidence.&lt;/p&gt;

&lt;p&gt;Before merge, CI should:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build once → pack once → attach commit and provenance → clean install into pinned shell → test → preview
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a Node package, &lt;a href="https://pnpm.io/cli/pack" rel="noopener noreferrer"&gt;&lt;code&gt;pnpm pack&lt;/code&gt;&lt;/a&gt; produces the tarball under test. The clean shell install should verify exports, included files, types, assets, lifecycle behavior, package metadata, SSR/hydration where relevant, and only the critical product journeys affected by the module.&lt;/p&gt;

&lt;p&gt;The artifact that passes is the artifact that moves forward. Rebuilding for staging or production invalidates prior evidence.&lt;/p&gt;

&lt;p&gt;The shell owns singleton dependencies such as React, framework runtimes, and shared contexts. Modules declare supported ranges through &lt;code&gt;peerDependencies&lt;/code&gt; rather than bundling private copies. A compatibility manifest adds constraints package resolution cannot express—such as supported shell APIs, rendering modes, or contract generations—and fails an invalid composition with an explanation before it runs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://slsa.dev/spec/v1.2/provenance" rel="noopener noreferrer"&gt;Provenance&lt;/a&gt; answers a different question: which source revision and CI build produced these tested bytes? It complements, rather than replaces, compatibility testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preview a product, not an isolated copy of the company
&lt;/h2&gt;

&lt;p&gt;A PR preview should be a &lt;strong&gt;hybrid composition&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dedicate the changed Booking candidate and shell where needed;&lt;/li&gt;
&lt;li&gt;reuse known-stable Hotel, Payment, and other remote services;&lt;/li&gt;
&lt;li&gt;pin every reused version;&lt;/li&gt;
&lt;li&gt;expose the final composition and artifact IDs in the preview.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives QA, design, and product a reviewable URL without creating a full company clone for every pull request. It catches artifact omissions, clean-install failures, selected cross-domain behavior, and visual product issues. It still has bounded data, traffic, scale, and external integrations—so it is strong evidence, not a production guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitOps gives promotion a memory
&lt;/h2&gt;

&lt;p&gt;A composition is already declarative, so GitOps is useful connective tissue between verified bytes and running environments. It does not “solve integration”; it records, applies, and reconciles a selected product state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;composition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;booking-canary-2026-09-12&lt;/span&gt;
&lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;product-shell@13.2.1&lt;/span&gt;
&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;booking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.example/booking@sha256:4d8c...&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;7.5.0&lt;/span&gt;
    &lt;span class="na"&gt;sourceCommit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;91ac...&lt;/span&gt;
    &lt;span class="na"&gt;buildProvenance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;attestations/booking/4d8c...&lt;/span&gt;
  &lt;span class="na"&gt;hotel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;artifact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.example/hotel@sha256:70be...&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5.8.2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;candidate artifact → composition-manifest PR → verification + preview
    → merge → reconciled environment → canary → manifest revert if unhealthy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This aligns with the &lt;a href="https://opengitops.dev/#principles" rel="noopener noreferrer"&gt;OpenGitOps principles&lt;/a&gt;: desired state is declarative, versioned and immutable, automatically pulled, and continuously reconciled.&lt;/p&gt;

&lt;p&gt;Keep environment semantics distinct:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Environment&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;What may change it?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;integration-latest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Early compatibility signal from accepted updates&lt;/td&gt;
&lt;td&gt;Accepted component updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;integration-stable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dependable baseline for local hybrid development&lt;/td&gt;
&lt;td&gt;Deliberate known-compatible promotion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;staging / release candidate&lt;/td&gt;
&lt;td&gt;Release evidence&lt;/td&gt;
&lt;td&gt;Deliberately selected manifest only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;production&lt;/td&gt;
&lt;td&gt;Real customer and traffic evidence&lt;/td&gt;
&lt;td&gt;Canary promotion of a reviewed manifest&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Routine deployments must not mutate staging. Otherwise it becomes contested shared workspace exactly when it needs to represent a release candidate.&lt;/p&gt;

&lt;p&gt;A manifest revert restores the prior artifact digest. It cannot reverse destructive migrations or external side effects, so every module still needs a forward- and backward-compatible migration strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make failure attributable in one screen
&lt;/h2&gt;

&lt;p&gt;Pinning versions is necessary but incomplete. Reproducibility also needs data and diagnostics.&lt;/p&gt;

&lt;p&gt;A provisioned Booking scenario should have a &lt;code&gt;testRunId&lt;/code&gt;, TTL, and cleanup policy. Records across Booking, Hotel, and Payment carry that identifier where permitted. Stable fixtures are immutable or automatically reset; tests needing mutation receive isolated data.&lt;/p&gt;

&lt;p&gt;Requests and events should propagate trace and request IDs plus:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module version · product composition ID · contract version · testRunId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/concepts/signals/traces/" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; provides the trace and context-propagation model. Adding composition context makes a trace actionable integration evidence.&lt;/p&gt;

&lt;p&gt;A failed Booking request should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which Booking artifact and product composition handled it?&lt;/li&gt;
&lt;li&gt;Which Hotel contract and service version were selected?&lt;/li&gt;
&lt;li&gt;Which test scenario supplied the data?&lt;/li&gt;
&lt;li&gt;Where did time or failure enter the trace?&lt;/li&gt;
&lt;li&gt;Which team owns the failing capability and what changed last?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ownership then follows the boundary: Booking triages a failure in its artifact; Hotel owns a published-contract violation; the platform team owns a composition engine rejection of a valid declared configuration. A bare failure routed to a team channel recreates the integration queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start small: improve one developer journey
&lt;/h2&gt;

&lt;p&gt;Do not begin by building a universal portal. Begin with the most painful edit-to-integrated-feedback loop and give it a measurable exit condition.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Deliverable&lt;/th&gt;
&lt;th&gt;Exit condition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;1. Make composition explicit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Pinned shell/module versions, clean artifact install&lt;/td&gt;
&lt;td&gt;Any authorized engineer can reproduce a candidate from clean state without editing &lt;code&gt;package.json&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2. Shorten local feedback&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Workbench, named scenarios, real-shell local overrides&lt;/td&gt;
&lt;td&gt;One command reaches a usable shell while the normal lockfile remains unchanged.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;3. Move compatibility before merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Candidate contracts, packed-artifact CI, hybrid preview&lt;/td&gt;
&lt;td&gt;CI installs exact candidates into a clean pinned composition and reviewers can identify every changed/reused component.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4. Close the production loop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GitOps manifests, canary, trace metadata, ownership routing&lt;/td&gt;
&lt;td&gt;The PR-tested artifact reaches canary/production unchanged and a safe revert restores the prior compatible version.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Measure the wait, not the tooling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;median edit-to-feedback time, separately for workbench and real shell;&lt;/li&gt;
&lt;li&gt;percentage of PRs verified with the exact artifact later promoted;&lt;/li&gt;
&lt;li&gt;local composition startup &lt;strong&gt;success&lt;/strong&gt; rate, not just process starts;&lt;/li&gt;
&lt;li&gt;preview request-to-ready and recovery time;&lt;/li&gt;
&lt;li&gt;failures found before versus after merge, classified by boundary;&lt;/li&gt;
&lt;li&gt;dependency-update lead time and blocked days caused by cross-team dependencies;&lt;/li&gt;
&lt;li&gt;deployment failure/recovery outcomes and observed developer task success.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://dora.dev/guides/dora-metrics/" rel="noopener noreferrer"&gt;DORA’s delivery metrics&lt;/a&gt; are useful alongside these leading indicators. Do not turn them into a cross-team leaderboard: trends for one product journey reveal more than a blended organizational number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration is the platform product
&lt;/h2&gt;

&lt;p&gt;A weak platform makes teams publishable, then centralizes the moment of truth. A healthy platform makes the product boundary continuously available to the team changing it.&lt;/p&gt;

&lt;p&gt;For Booking, that means one connected path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;local source in real shell
  → exact packed candidate in clean CI
  → pinned PR preview
  → reviewed composition manifest
  → canary with traceable identity
  → manifest revert when healthy evidence disappears
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Packages, separate repositories, and independent releases can all support this model. The decisive capability is faster, self-service feedback at progressively realistic levels—not the repository topology or a portal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integration is not the gate after development. Integration is the product the platform team provides.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://github.com/cncf/tag-app-delivery/blob/main/platforms-whitepaper/latest/index.md" rel="noopener noreferrer"&gt;CNCF Platforms White Paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dora.dev/capabilities/platform-engineering/" rel="noopener noreferrer"&gt;DORA: Platform engineering capability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dora.dev/guides/dora-metrics/" rel="noopener noreferrer"&gt;DORA: Software delivery performance metrics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opengitops.dev/#principles" rel="noopener noreferrer"&gt;OpenGitOps principles v1.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pact.io/" rel="noopener noreferrer"&gt;Pact introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pnpm.io/cli/pack" rel="noopener noreferrer"&gt;pnpm &lt;code&gt;pack&lt;/code&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slsa.dev/spec/v1.2/provenance" rel="noopener noreferrer"&gt;SLSA provenance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/docs/concepts/signals/traces/" rel="noopener noreferrer"&gt;OpenTelemetry trace concepts&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>platformengineering</category>
      <category>frontend</category>
      <category>architecture</category>
      <category>devops</category>
    </item>
    <item>
      <title>Graph Coloring: A Simple Implementation with JavaScript</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Tue, 08 Sep 2026 17:04:14 +0000</pubDate>
      <link>https://dev.to/frorning/graph-coloring-a-simple-implementation-with-javascript-4jdo</link>
      <guid>https://dev.to/frorning/graph-coloring-a-simple-implementation-with-javascript-4jdo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Graph coloring is a fundamental problem in computer science and graph theory, often used to solve various real-world problems such as scheduling tasks, register allocation in compilers, and solving map coloring puzzles. In this article, we will explore how to implement a simple graph coloring algorithm using JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Graph Coloring?
&lt;/h2&gt;

&lt;p&gt;Graph coloring involves assigning colors to the vertices of a graph such that no two adjacent vertices share the same color. The goal is to use the minimum number of colors required to achieve this condition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Map Coloring
&lt;/h3&gt;

&lt;p&gt;A classic example is map coloring, where countries (vertices) are colored so that no two adjacent countries have the same color. This ensures that maps can be visually distinguished and avoids confusion between neighboring regions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation in JavaScript
&lt;/h2&gt;

&lt;p&gt;We will implement a graph coloring algorithm using JavaScript objects to represent the graph structure and perform depth-first search (DFS) for coloring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Guide
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Graph Representation&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;We will use an adjacency list representation of the graph.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Color Assignment&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;We will use DFS to assign colors while ensuring no two adjacent vertices share the same color.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict Detection&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;We will detect conflicts and return false if a valid coloring cannot be achieved.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  JavaScript Code
&lt;/h3&gt;

&lt;p&gt;Here's the complete implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to perform the graph coloring using DFS&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If the vertex is already colored, return true&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Initialize with a default color&lt;/span&gt;
    &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Conflict found&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Conflict found&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Assign the next available color&lt;/span&gt;
    &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Function to perform graph coloring on the entire graph&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;graphColoring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;colorMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;vertex&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;vertex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Conflict found&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Coloring scheme:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;colorMap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage:&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;A&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;D&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;E&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;E&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;graphColoring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Graph is colored successfully!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Conflict found in graph coloring.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explanation
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;dfs Function&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This function performs a depth-first search to assign colors.&lt;/li&gt;
&lt;li&gt;If the vertex has already been assigned a color, it returns true.&lt;/li&gt;
&lt;li&gt;It initializes the color map for unvisited vertices and recursively assigns the next available color while checking for conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;graphColoring Function&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initializes &lt;code&gt;visited&lt;/code&gt; and &lt;code&gt;colorMap&lt;/code&gt; arrays.&lt;/li&gt;
&lt;li&gt;Iterates over all vertices in the graph and calls &lt;code&gt;dfs&lt;/code&gt; for unvisited vertices.&lt;/li&gt;
&lt;li&gt;If a conflict is found during the DFS, it returns false; otherwise, it prints the color map.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example Graph
&lt;/h3&gt;

&lt;p&gt;Let's consider the example graph:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vertices&lt;/strong&gt;: A, B, C, D, E&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edges&lt;/strong&gt;: A-B, A-C, B-D, C-D, C-E, D-E&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output will be a valid coloring scheme for this graph if one exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, we explored how to implement a simple graph coloring algorithm using JavaScript. By representing the graph as an adjacency list and performing depth-first search, we can efficiently assign colors while ensuring no two adjacent vertices share the same color.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>beginners</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Navigating Python Development: A Step-by-Step Guide to Using Poetry</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Tue, 08 Sep 2026 17:03:46 +0000</pubDate>
      <link>https://dev.to/frorning/navigating-python-development-a-step-by-step-guide-to-using-poetry-14n3</link>
      <guid>https://dev.to/frorning/navigating-python-development-a-step-by-step-guide-to-using-poetry-14n3</guid>
      <description>&lt;h3&gt;
  
  
  What is Poetry?
&lt;/h3&gt;

&lt;p&gt;Poetry is an opinionated package management system for Python projects. It helps you:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Set up your project&lt;/strong&gt; with all the necessary files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manage dependencies&lt;/strong&gt; easily.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolate environments&lt;/strong&gt; to ensure that different projects have separate dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resolve dependency conflicts&lt;/strong&gt; automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why Use Poetry?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplifies Project Setup&lt;/strong&gt;: Automatically generates &lt;code&gt;pyproject.toml&lt;/code&gt; and &lt;code&gt;poetry.lock&lt;/code&gt; files, making it easier to share your project with others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment Management&lt;/strong&gt;: Creates isolated virtual environments for each project, which helps avoid version conflicts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Resolution&lt;/strong&gt;: Automatically handles dependencies and their versions, reducing the risk of issues related to dependency mismatches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installing Poetry
&lt;/h3&gt;

&lt;p&gt;You can install Poetry using pip:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;poetry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a New Project with Poetry
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open your terminal or command prompt.&lt;/li&gt;
&lt;li&gt;Navigate to the directory where you want to create your project.&lt;/li&gt;
&lt;li&gt;Run the following command to create a new Python project:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   poetry new my_project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new directory named &lt;code&gt;my_project&lt;/code&gt; with the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my_project/
├── pyproject.toml
└── src/
    └── my_project/
        ├── __init__.py
        └── main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing Dependencies
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add a Dependency&lt;/strong&gt;: You can add dependencies to your project using the &lt;code&gt;add&lt;/code&gt; command:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   poetry add requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;List Installed Dependencies&lt;/strong&gt;: To see all installed dependencies, use:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   poetry show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Update a Dependency&lt;/strong&gt;: To update an existing dependency, use:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   poetry update requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Remove a Dependency&lt;/strong&gt;: To remove a dependency, use:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   poetry remove requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Managing Environments
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Activate the Environment&lt;/strong&gt;: Run the following command to activate your project's virtual environment:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   poetry shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deactivate the Environment&lt;/strong&gt;: Simply type &lt;code&gt;exit&lt;/code&gt; in the activated shell.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Running Scripts
&lt;/h3&gt;

&lt;p&gt;You can run scripts from within a Poetry-managed environment by using the &lt;code&gt;poetry run&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry run python src/my_project/main.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs &lt;code&gt;main.py&lt;/code&gt; with the virtual environment's Python interpreter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Poetry is a powerful tool for managing Python projects. It simplifies dependency management, ensures isolated environments, and helps resolve version &lt;br&gt;
conflicts. By following these steps, you can effectively use Poetry to manage your Python projects.&lt;/p&gt;

</description>
      <category>python</category>
      <category>poetry</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The browser only talks to one server — composing Marko, React, and Riot into one hotel page</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Mon, 07 Sep 2026 12:32:03 +0000</pubDate>
      <link>https://dev.to/frorning/the-browser-only-talks-to-one-server-composing-marko-react-and-riot-into-one-hotel-page-3355</link>
      <guid>https://dev.to/frorning/the-browser-only-talks-to-one-server-composing-marko-react-and-riot-into-one-hotel-page-3355</guid>
      <description>&lt;p&gt;You open a hotel page. It looks like one product: a search grid, a featured stay, local highlights, reviews, a sticky trip summary.&lt;/p&gt;

&lt;p&gt;Under the hood it is &lt;strong&gt;eight HTTP servers and three UI runtimes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is the experiment behind &lt;strong&gt;HarborStay&lt;/strong&gt;, a demo booking app I built to answer a stubborn question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can independent teams ship independent UI, in independent frameworks, and still give the browser a single, paint-ready HTML page?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The punchline: &lt;strong&gt;yes — if the shell never imports a component.&lt;/strong&gt; It only fetches HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one rule
&lt;/h2&gt;

&lt;p&gt;The browser never talks to a fragment.&lt;/p&gt;

&lt;p&gt;It talks to the &lt;strong&gt;composer&lt;/strong&gt; on port &lt;code&gt;3100&lt;/code&gt;. The composer owns routes, layout, and the booking flow. Everything else is a fragment server that returns a chunk of HTML.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
  Browser["Browser"] --&amp;gt; Composer["Composer :3100"]

  subgraph fragments["Fragment servers"]
    Nav["Navigation Marko :3101"]
    Search["Hotel search Marko :3102"]
    Details["Hotel details Marko :3103"]
    Reviews["Reviews Marko :3104"]
    Recs["Recommendations Marko :3105"]
    Highlights["Local highlights React :3106"]
    Disco["Experiences discovery Riot :3107"]
    Itin["Experiences itinerary Riot :3108"]
  end

  Composer --&amp;gt; Nav
  Composer --&amp;gt; Search
  Composer --&amp;gt; Details
  Composer --&amp;gt; Reviews
  Composer --&amp;gt; Recs
  Composer --&amp;gt; Highlights
  Composer --&amp;gt; Disco
  Composer --&amp;gt; Itin
  Composer --&amp;gt; CDN["CDN :3200"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This is the opposite of the usual microfrontend story (Module Federation, shared React, a host that &lt;code&gt;import()&lt;/code&gt;s widgets). HarborStay is &lt;strong&gt;HTML composition&lt;/strong&gt;. The shell does not know whether a fragment was rendered by Marko, React, or a hand-rolled Riot string. It only knows a URL.&lt;/p&gt;

&lt;p&gt;That one constraint buys a lot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fragment teams can pick a runtime without asking the shell.&lt;/li&gt;
&lt;li&gt;A fragment outage becomes a fallback box, not a blank page.&lt;/li&gt;
&lt;li&gt;You can deploy search without redeploying reviews.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also forces honesty. If two fragments need to share a Redux store, the architecture is already leaking.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the user actually sees
&lt;/h2&gt;

&lt;p&gt;HarborStay models a small premium catalog: &lt;strong&gt;Harbor View Lodge&lt;/strong&gt; in Lisbon, &lt;strong&gt;Copper Hill Suites&lt;/strong&gt; in Seville, &lt;strong&gt;Sunset Terrace House&lt;/strong&gt; in Barcelona, &lt;strong&gt;Moss &amp;amp; Lantern&lt;/strong&gt; in Copenhagen.&lt;/p&gt;

&lt;p&gt;Routes the composer owns:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;/&lt;/code&gt; and &lt;code&gt;/hotel/:hotelId&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Streaming stays page&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/experiences/:hotelId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Neighborhood explorer + day plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/booking/confirm/:hotelId&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Confirmation (I got &lt;code&gt;HS-470455&lt;/code&gt; for Moss &amp;amp; Lantern)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On &lt;code&gt;/hotel/moss-lantern&lt;/code&gt; the page is not “a React tree.” It is a &lt;strong&gt;layout of slots&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
  subgraph page["One HTML page from the composer"]
    Topbar["Topbar: HarborStay + Stays / Experiences"]
    subgraph main["Main column"]
      Search["Search island: Where to next?"]
      Details["Details island: Featured stay"]
      Highlights["Highlights island: What to do in Copenhagen"]
      Reviews["Reviews island: What travelers say"]
      Recs["Recommendations island: More stays nearby"]
    end
    Sidebar["Sticky trip summary + Book this stay"]
  end&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Click &lt;strong&gt;Luxury&lt;/strong&gt; on the search chips and the grid collapses to Harbor View Lodge and Moss &amp;amp; Lantern. The reviews below do not re-fetch. They never heard about the filter. That is not a bug — that is the point.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Island rule:&lt;/strong&gt; each fragment owns its own interactivity. Search filters are Marko state. Highlight selection is React state. Experience categories are Riot state. The composer does not have a global store.&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  A tiny protocol instead of a shared SDK
&lt;/h2&gt;

&lt;p&gt;Every fragment speaks &lt;code&gt;harborstay-fragment/v1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /?hotelId=moss-lantern
GET /manifest
GET /assets/&amp;lt;name&amp;gt;.css
GET /assets/&amp;lt;name&amp;gt;.js
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And a few provenance headers:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;X-Fragment-Name: search
X-Fragment-Hotel-Id: moss-lantern
X-Fragment-Protocol: harborstay-fragment/v1
X-Fragment-Css: http://localhost:3200/assets/search.css
X-Fragment-Js:  http://localhost:3200/assets/search.js
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The composer reads the HTML body. Asset URLs are informational. In this demo, CSS and JS are served from a tiny CDN app on &lt;code&gt;:3200&lt;/code&gt; that copies fragment assets on startup.&lt;/p&gt;

&lt;p&gt;That split is the real-world shape: &lt;strong&gt;SSR lives with the team that owns the UI. Bytes live on a CDN.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Assets belong to the fragment that created them, not to the shell:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/hotel-search/src/assets/search.css
apps/hotel-search/src/build-client.js   → cdn/public/assets/search.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If search wants a new filter chip, reviews does not rebuild.&lt;/p&gt;
&lt;h2&gt;
  
  
  Three runtimes, one HTML contract
&lt;/h2&gt;

&lt;p&gt;This is the part people assume is impossible.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runtime&lt;/th&gt;
&lt;th&gt;Fragments&lt;/th&gt;
&lt;th&gt;Server render&lt;/th&gt;
&lt;th&gt;Client&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Marko&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;navigation, search, details, reviews, recommendations&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@marko/compiler&lt;/code&gt; → &lt;code&gt;template.render().toString()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Marko DOM runtime mounts into a root&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;React 19&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;local highlights&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;react-dom/server&lt;/code&gt; &lt;code&gt;renderToStaticMarkup&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hydrateRoot&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Riot&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;experiences discovery + itinerary&lt;/td&gt;
&lt;td&gt;hand-written &lt;code&gt;renderSsrMarkup()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;riot.component()&lt;/code&gt; after clearing the SSR root&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The composer does not care. All three return strings.&lt;br&gt;
&lt;/p&gt;
&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
  subgraph marko["Marko :3102"]
    M1["hotel-search.marko"] --&amp;gt; M2["HTML string"]
  end
  subgraph react["React :3106"]
    R1["HighlightsView.jsx"] --&amp;gt; R2["HTML string"]
  end
  subgraph riot["Riot :3107"]
    T1["renderSsrMarkup()"] --&amp;gt; T2["HTML string"]
  end
  M2 --&amp;gt; Composer["Composer stitches slots"]
  R2 --&amp;gt; Composer
  T2 --&amp;gt; Composer
  Composer --&amp;gt; Browser["Browser paints HTML before any island JS"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Why SSR in a microfrontend at all?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The first paint does not wait for JavaScript.&lt;/li&gt;
&lt;li&gt;HTML is the only lingua franca three frameworks share.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;experiences-discovery.js&lt;/code&gt; fails, the user still sees the cards.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last one is Islands architecture in the small: &lt;strong&gt;static HTML with pockets of JS&lt;/strong&gt;, not a SPA that hydrates the entire document.&lt;/p&gt;
&lt;h2&gt;
  
  
  How data crosses the SSR/client gap
&lt;/h2&gt;

&lt;p&gt;Every interactive fragment embeds props as JSON, not &lt;code&gt;data-&lt;/code&gt; attributes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hotel-search-fragment-data"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hotels&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:[...],&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hotelId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;moss-lantern&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hotel-search-fragment-root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- SSR HTML --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The client bundle reads that script and mounts. Before embedding, fragment servers escape &lt;code&gt;&amp;lt;&lt;/code&gt; as &lt;code&gt;\u003c&lt;/code&gt; so a hotel description cannot break out of the script tag.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;data-hotels='[{...}]'&lt;/code&gt; looks simpler. It is worse: large JSON in attributes bloats the DOM, needs ugly escaping, and is visible to everything that walks the tree.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hydration is not one word
&lt;/h2&gt;

&lt;p&gt;Walking the live app made this concrete.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marko search&lt;/strong&gt; hydrates into &lt;code&gt;#hotel-search-fragment-root&lt;/code&gt;. Luxury / Value / Top rated re-render the grid without a navigation. The client template must match the server template or you get a flash.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;React highlights&lt;/strong&gt; hydrates with &lt;code&gt;hydrateRoot&lt;/code&gt;. On Moss &amp;amp; Lantern you get &lt;em&gt;Garden loop&lt;/em&gt;, &lt;em&gt;Sauna ritual&lt;/em&gt;, &lt;em&gt;Harbor market&lt;/em&gt;. Click a card and only that island updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Riot cannot hydrate&lt;/strong&gt; the way React does. There is no reconcile-existing-DOM API in this setup, so the client &lt;strong&gt;wipes the SSR HTML and remounts&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;mountNode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DiscoveryTag&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;mountNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;You still get a fast first paint. You also get a tiny risk of visual flash if the Riot template and &lt;code&gt;renderSsrMarkup()&lt;/code&gt; drift. Keep class names, element types, and copy identical.&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;/experiences/moss-lantern&lt;/code&gt; I clicked &lt;strong&gt;Food&lt;/strong&gt;: three cards became one tasting session. I clicked &lt;strong&gt;Day 2&lt;/strong&gt;: breakfast / walk / dinner became scenic run / museum / sunset lounge. Two Riot islands, two state machines, zero shared store.&lt;br&gt;
&lt;/p&gt;
&lt;pre data-lang="mermaid"&gt;&lt;code&gt;sequenceDiagram
  participant U as User
  participant D as Discovery Riot
  participant I as Itinerary Riot
  U-&amp;gt;&amp;gt;D: Click Food
  D-&amp;gt;&amp;gt;D: state.activeCategory = Food
  Note over I: Itinerary does not care
  U-&amp;gt;&amp;gt;I: Click Day 2
  I-&amp;gt;&amp;gt;I: state.selectedDay = 2
  Note over D: Discovery does not care&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;
  
  
  Streaming: do not wait for the slowest fragment
&lt;/h2&gt;

&lt;p&gt;The stays page does not &lt;code&gt;await Promise.all&lt;/code&gt; then send one blob.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;streamPage()&lt;/code&gt; is an &lt;code&gt;async function*&lt;/code&gt; . It yields the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; and shell immediately, then races fragment promises and flushes HTML as each one finishes.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;headPrefix&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;fragmentOrder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;safeRenderFragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hotelId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;()].&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fragment&lt;/span&gt; &lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Fastify wraps that in &lt;code&gt;Readable.from(...)&lt;/code&gt;. The response header &lt;code&gt;x-ssr-stream: true&lt;/code&gt; is a breadcrumb that this is a streamed document.&lt;br&gt;
&lt;/p&gt;
&lt;pre data-lang="mermaid"&gt;&lt;code&gt;gantt
  title Streaming vs waiting for everyone
  dateFormat  X
  axisFormat  %s ms
  section Buffered
  Wait for slowest fragment     :a1, 0, 860
  First paint                   :a2, 860, 50
  section Streamed
  Head + shell                  :b1, 0, 40
  Search HTML                   :b2, 160, 40
  Recommendations HTML          :b3, 300, 40
  Details HTML                  :b4, 540, 40
  Reviews HTML                  :b5, 860, 40&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The demo even fakes latency so you can &lt;em&gt;see&lt;/em&gt; streaming:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FRAGMENT_STREAM_DELAY_MS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;recommendations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;540&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;860&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In production you delete those delays. Keep the race. First Contentful Paint becomes “when the shell arrives,” not “when reviews finally woke up.” Skeletons (&lt;code&gt;.loading-fragment&lt;/code&gt;) hold layout so later chunks do not shove the page around.&lt;/p&gt;

&lt;p&gt;If a fragment is restarting, &lt;code&gt;safeRenderFragment&lt;/code&gt; catches the error and yields:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;reviews fragment is warming up.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Independent deploys stop being theoretical.&lt;/p&gt;
&lt;h2&gt;
  
  
  JavaScript budget is a route problem
&lt;/h2&gt;

&lt;p&gt;A composed page can accidentally ship four frameworks to every visitor. HarborStay avoids that with &lt;strong&gt;page splits&lt;/strong&gt;, not heroics.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;pnpm dev:home&lt;/code&gt; runs composer + CDN + stays fragments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pnpm dev:experiences&lt;/code&gt; runs composer + CDN + the two Riot apps.&lt;/li&gt;
&lt;li&gt;The stays page builder never emits &lt;code&gt;experiences-discovery.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The experiences page never emits &lt;code&gt;search.js&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the cheapest performance win in the repo. Intersection Observer hydration, click-to-hydrate, and &lt;code&gt;requestIdleCallback&lt;/code&gt; are next — the docs already sketch them — but route-level omission beats all of them.&lt;br&gt;
&lt;/p&gt;
&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
  StayPage["/hotel/:id"] --&amp;gt; StayJS["search.js + highlights.js"]
  ExpPage["/experiences/:id"] --&amp;gt; ExpJS["discovery.js + itinerary.js"]
  StayPage -.-&amp;gt; NoRiot["Riot bundles not referenced"]
  ExpPage -.-&amp;gt; NoMarko["Search bundle not referenced"]&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;
  
  
  State: URL, local, or an event — pick one
&lt;/h2&gt;

&lt;p&gt;Shared mutable global state is how microfrontends become a distributed monolith.&lt;/p&gt;

&lt;p&gt;HarborStay’s rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ephemeral UI state stays in the island.&lt;/strong&gt; Filter chips, selected highlight, active day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shareable state lives in the URL.&lt;/strong&gt; &lt;code&gt;/hotel/moss-lantern&lt;/code&gt; is the source of truth for “which stay.” Full page reload is intentional in this demo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-fragment talk is an event, not a store import.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;harborstay:hotel-selected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;bubbles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hotelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;moss-lantern&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Do not do this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;store&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@harborstay/store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// two bundles = two stores&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Two IIFE bundles that “import the same store” get two closures. They will not share state. They will gaslight you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;BroadcastChannel&lt;/code&gt; is the right tool only when tabs or iframes must stay in sync. &lt;code&gt;localStorage&lt;/code&gt; is for values that must survive a round trip. Neither belongs in the first version.&lt;/p&gt;
&lt;h2&gt;
  
  
  How this would ship
&lt;/h2&gt;

&lt;p&gt;Each fragment is a Node HTTP server. DNS for users points at the composer. Fragments live on internal hostnames. Static assets go to a real CDN.&lt;br&gt;
&lt;/p&gt;
&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
  User["User"] --&amp;gt; LB["Load balancer / CDN"]
  LB --&amp;gt; Composer["Composer"]
  Composer --&amp;gt; F1["mfe-hotel-search"]
  Composer --&amp;gt; F2["mfe-reviews"]
  Composer --&amp;gt; F3["mfe-local-highlights"]
  Composer --&amp;gt; F4["other fragments"]
  Assets["cdn.example.com"] -.-&amp;gt; User&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Rolling deploy order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Publish content-hashed assets.&lt;/li&gt;
&lt;li&gt;Roll fragment servers (any order — fallbacks cover restarts).&lt;/li&gt;
&lt;li&gt;Roll the composer last.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Turborepo is the monorepo glue: &lt;code&gt;pnpm dev:home&lt;/code&gt; fans out with persistent &lt;code&gt;dev&lt;/code&gt; tasks, and &lt;code&gt;turbo run build&lt;/code&gt; only rebuilds what changed.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;demo&lt;/strong&gt;, not a production platform. The goal is a shape you can reason about: one contract, many runtimes, progressive HTML.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I would do next
&lt;/h2&gt;

&lt;p&gt;The interesting unfinished work is not “add another framework.” It is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soft navigation&lt;/strong&gt; — &lt;code&gt;history.pushState&lt;/code&gt; + swap only the fragments that changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;True streaming inside fragments&lt;/strong&gt; — Marko &lt;code&gt;template.stream()&lt;/code&gt;, React &lt;code&gt;renderToPipeableStream&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Riot hydrate()&lt;/strong&gt; when the API is stable, so we stop wiping SSR DOM.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge composer&lt;/strong&gt; — the generator already looks like a Web Streams mental model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SWR cache&lt;/strong&gt; of fragment HTML at the composer for anonymous hotel pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Run it
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm dev:home          &lt;span class="c"&gt;# stays flow&lt;/span&gt;
pnpm dev:experiences   &lt;span class="c"&gt;# experiences flow&lt;/span&gt;
pnpm dev:all           &lt;span class="c"&gt;# everything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then open &lt;code&gt;http://localhost:3100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want a mental model to steal, steal this one:&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Compose HTML, not components. Hydrate islands, not pages. Keep state with the team that owns the UI. Let the slowest fragment arrive last without blocking the first paint.&lt;/strong&gt;&lt;br&gt;

&lt;/div&gt;



&lt;p&gt;The user still sees one hotel page. The architecture is allowed to be many rooms behind one door.&lt;/p&gt;

&lt;p&gt;GITHUB: &lt;a href="https://github.com/piyushchauhan2011/marko-mfe" rel="noopener noreferrer"&gt;https://github.com/piyushchauhan2011/marko-mfe&lt;/a&gt;&lt;/p&gt;

</description>
      <category>microfrontends</category>
      <category>ssr</category>
      <category>webperf</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why Your JavaScript Sums Are Wrong (And How to Fix Them)</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Wed, 05 Aug 2026 07:24:22 +0000</pubDate>
      <link>https://dev.to/frorning/why-your-javascript-sums-are-wrong-and-how-to-fix-them-55cp</link>
      <guid>https://dev.to/frorning/why-your-javascript-sums-are-wrong-and-how-to-fix-them-55cp</guid>
      <description>&lt;p&gt;You know that &lt;code&gt;Array.prototype.reduce&lt;/code&gt; you've used a thousand times to sum numbers? It's lying to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. A One-Liner That Should Work
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;        &lt;span class="c1"&gt;// 99.9999999999986&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// false (!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A thousand tenths should equal one hundred. But in JavaScript — and in virtually every other mainstream language — it doesn't. Not exactly.&lt;/p&gt;

&lt;p&gt;If you've ever shrugged off a &lt;code&gt;0.0000000000001&lt;/code&gt; discrepancy, this article is for you. Because at scale, that "tiny" error isn't tiny at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Problem: Why Floats Betray Us
&lt;/h2&gt;

&lt;p&gt;JavaScript uses &lt;a href="https://en.wikipedia.org/wiki/IEEE_754" rel="noopener noreferrer"&gt;IEEE 754 double-precision floating-point&lt;/a&gt; for all numbers. In plain English: your numbers are stored as binary fractions, and most decimal fractions (like &lt;code&gt;0.1&lt;/code&gt;) have no exact binary representation.&lt;/p&gt;

&lt;p&gt;When you add &lt;code&gt;0.1 + 0.2&lt;/code&gt;, the computer isn't adding "one-tenth plus two-tenths." It's adding the closest binary approximations it can store. The result? &lt;code&gt;0.30000000000000004&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now multiply that imperfection across a thousand, a million, or a billion additions. The error doesn't stay small — it &lt;strong&gt;accumulates&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Issue
&lt;/h3&gt;

&lt;p&gt;When you sum left-to-right with a running total, you eventually reach a point where the running total is huge and the next number is tiny. In floating-point arithmetic, adding a tiny number to a huge number often results in &lt;strong&gt;no change at all&lt;/strong&gt; — the tiny number gets "swallowed."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Imagine pouring water into a bucket with a small hole. Each pour loses a few drops. After 1,000 pours, you're missing a puddle.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. The Fix: Kahan Summation
&lt;/h2&gt;

&lt;p&gt;In 1965, William Kahan published an algorithm that tracks and recovers the low-order bits lost in each addition. The trick? A &lt;strong&gt;compensation variable&lt;/strong&gt; that remembers what got rounded away.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Intuition
&lt;/h3&gt;

&lt;p&gt;Instead of just keeping a running total, Kahan summation keeps two values:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;sum&lt;/code&gt; — the best approximation so far&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;c&lt;/code&gt; (compensation) — the error that was discarded in the last step&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before each new addition, the compensation from the previous step is added back in. After the addition, the new error is computed and stored for the next iteration.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Algorithm
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: x
       │
       ▼
    x + c  ◄── compensation from last step
       │
       ▼
   t = sum + (x + c)
       │
       ▼
   c = (t - sum) - (x + c)  ← the "recovered" error
       │
       ▼
   sum = t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;kahanSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// compensation for lost low-order bits&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// subtract previous error&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// tentative sum&lt;/span&gt;
    &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;         &lt;span class="c1"&gt;// new error: (what we added) - (what we meant to add)&lt;/span&gt;
    &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Line-by-Line Breakdown
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Line&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;y = numbers[i] - c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add back the error from the previous step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;t = sum + y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Perform the actual addition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;c = (t - sum) - y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Calculate what got lost in rounding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;sum = t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Commit the new sum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The magic is in &lt;code&gt;(t - sum) - y&lt;/code&gt;. Because of how floating-point subtraction works, this expression recovers the bits that were rounded away during &lt;code&gt;sum + y&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Live Comparison: Naive vs. Kahan
&lt;/h2&gt;

&lt;p&gt;Let's run both algorithms on the same pathological dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 10 million copies of 0.0001&lt;/span&gt;
&lt;span class="c1"&gt;// True answer: exactly 1000&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;naive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;naive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;naive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kahan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kahan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;kahanSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kahan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Naive: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;naive&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// 999.9998999965879&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Kahan: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kahan&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// 1000.0000000000001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The naive sum is off by &lt;code&gt;0.0001&lt;/code&gt;&lt;/strong&gt;. That might not sound like much, but in financial systems processing millions of transactions, "small" errors compound into real money.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kahan's error?&lt;/strong&gt; &lt;code&gt;1.1e-13&lt;/code&gt; — effectively zero for all practical purposes.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. The Middle Ground: Pairwise Summation
&lt;/h2&gt;

&lt;p&gt;Before we crown Kahan the winner, there's a third contender that often gets overlooked: &lt;strong&gt;pairwise summation&lt;/strong&gt; (also called cascade summation).&lt;/p&gt;

&lt;p&gt;The idea is beautifully simple: instead of accumulating left-to-right, recursively split the array in half, sum each half, then add the two results. This ensures you're always adding numbers of roughly the same magnitude.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Intuition
&lt;/h3&gt;

&lt;p&gt;Imagine balancing a scale. Naive summation keeps piling weights on one side until the running total dwarfs every new addition. Pairwise summation weighs equal-sized groups against each other at every step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1, 2, 3, 4, 5, 6, 7, 8]
    /              \
[1,2,3,4]      [5,6,7,8]
  /    \          /    \
[1,2] [3,4]    [5,6] [7,8]
 |     |        |     |
 3     7        11    15
   \   /          \  /
    10             26
         \        /
           36
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Recursive Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pairwiseSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;len&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;pairwiseSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;pairwiseSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ &lt;strong&gt;Caution:&lt;/strong&gt; For very large arrays (&amp;gt; ~10,000 items), the recursive version will blow the call stack. Here's a stack-safe iterative version:&lt;/p&gt;

&lt;p&gt;🔧 Stack-safe iterative version&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pairwiseSumIterative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;queue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. The Heavyweight: decimal.js
&lt;/h2&gt;

&lt;p&gt;Sometimes you need &lt;strong&gt;exact&lt;/strong&gt; decimal arithmetic, not just "less error." That's where &lt;code&gt;decimal.js&lt;/code&gt; comes in. It represents numbers as strings internally and performs arbitrary-precision math.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;decimal.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Decimal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decimal.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;decimalSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;numbers&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Pro tip:&lt;/strong&gt; Always pass numbers through &lt;code&gt;.toString()&lt;/code&gt; before constructing a &lt;code&gt;Decimal&lt;/code&gt;. &lt;code&gt;new Decimal(0.1)&lt;/code&gt; still inherits floating-point imprecision because &lt;code&gt;0.1&lt;/code&gt; is already corrupted by the time it reaches the constructor.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  7. The Showdown: Four-Way Comparison
&lt;/h2&gt;

&lt;p&gt;Let's put them all to the test with a pathological dataset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 10 million copies of 0.0001&lt;/span&gt;
&lt;span class="c1"&gt;// True answer: exactly 1000&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nums&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="nx"&gt;_000_000&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Relative Speed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Naive &lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;999.9998999965879&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~1.0e-4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.0x (baseline)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pairwise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;999.9999999999123&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~8.8e-11&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~1.5x slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kahan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1000.0000000000001&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;~1.1e-13&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~3.5x slower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;decimal.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;1000&lt;/code&gt; (exact)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~40-80x slower&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What the Numbers Tell Us
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Naive&lt;/strong&gt; is fast but wrong at scale. The error is small in absolute terms, but in financial systems, "small" errors compound into real money.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pairwise&lt;/strong&gt; dramatically reduces error with minimal overhead. Its error grows logarithmically &lt;code&gt;O(log n)&lt;/code&gt; instead of linearly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kahan&lt;/strong&gt; achieves near-constant error &lt;code&gt;O(ε)&lt;/code&gt; — the gold standard for floating-point summation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;decimal.js&lt;/strong&gt; is exact but slow. It's not really a summation algorithm; it's a different number system entirely.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. The Decision Framework
&lt;/h2&gt;

&lt;p&gt;Here's a quick cheat sheet for choosing the right tool:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Small arrays (&amp;lt; 1,000 items)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Naive &lt;code&gt;reduce&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Error is negligible; don't over-engineer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large arrays, need speed, "good enough" accuracy&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pairwise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logarithmic error growth, parallelizable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Financial/scientific computing, must minimize error&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Kahan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Constant error bound, no extra dependencies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Accounting, currency, must be &lt;strong&gt;exact&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;decimal.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Arbitrary precision eliminates rounding entirely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU/Web Worker parallel processing&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Pairwise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Perfectly parallelizable; Kahan is inherently sequential&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The Trade-off Triangle
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Speed
         /\
        /  \
       /    \
      /      \
     /   ⚠️   \
    /__________\
 Accuracy    Simplicity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pick &lt;strong&gt;two&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast + Simple&lt;/strong&gt; → Naive&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast + Accurate&lt;/strong&gt; → Pairwise&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accurate + Simple&lt;/strong&gt; → Kahan&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exact&lt;/strong&gt; → decimal.js (sacrifices speed)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. When NOT to Use Kahan
&lt;/h2&gt;

&lt;p&gt;Kahan summation is great, but it's not always the right call:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Integers only&lt;/strong&gt; — If your array contains only integers representable in 53 bits, naive summation is exact until you exceed &lt;code&gt;Number.MAX_SAFE_INTEGER&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Already using a decimal library&lt;/strong&gt; — If you've bought into &lt;code&gt;decimal.js&lt;/code&gt; or &lt;code&gt;big.js&lt;/code&gt;, you don't need Kahan; you're already exact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time graphics/animation&lt;/strong&gt; — A 3-4x slowdown for a pixel-perfect particle position is rarely worth it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Very small datasets&lt;/strong&gt; — The error on &lt;code&gt;[0.1, 0.2, 0.3]&lt;/code&gt; is &lt;code&gt;5.55e-17&lt;/code&gt;. Your users don't care.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  10. One-Liners for Your Toolkit
&lt;/h2&gt;

&lt;p&gt;For the copy-paste engineers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Kahan (functional, but slightly slower due to array destructuring)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kahanSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// Pairwise (iterative, stack-safe)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pairwiseSum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="nx"&gt;q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Floating-point summation is one of those problems that seems trivial until it isn't. The good news: JavaScript gives you options.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reach for &lt;strong&gt;pairwise summation&lt;/strong&gt; when you need a quick accuracy boost without a performance cliff.&lt;/li&gt;
&lt;li&gt;Reach for &lt;strong&gt;Kahan summation&lt;/strong&gt; when precision is paramount and you're working with raw floats.&lt;/li&gt;
&lt;li&gt;Reach for &lt;strong&gt;decimal.js&lt;/strong&gt; when you're dealing with money, tax calculations, or anything where "close enough" isn't in your vocabulary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And sometimes? Just use &lt;code&gt;reduce&lt;/code&gt;. Not every array needs a PhD.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your go-to strategy for numerical accuracy in JavaScript? Drop your war stories in the comments below.&lt;/em&gt; 👇&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>algorithms</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Backtracking Unveiled: Mastering Depth-First Search and Pruning Techniques</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Sat, 22 Feb 2025 09:04:27 +0000</pubDate>
      <link>https://dev.to/frorning/backtracking-unveiled-mastering-depth-first-search-and-pruning-techniques-251c</link>
      <guid>https://dev.to/frorning/backtracking-unveiled-mastering-depth-first-search-and-pruning-techniques-251c</guid>
      <description>&lt;p&gt;Backtracking is a systematic way to iterate through all possible configurations of a problem. It is often used to solve problems where a sequence of decisions must be made, and each decision leads to a new set of possibilities. Backtracking uses &lt;strong&gt;depth-first search (DFS)&lt;/strong&gt; to explore the state space, and it employs &lt;strong&gt;pruning functions&lt;/strong&gt; to eliminate invalid or suboptimal paths early in the search process.&lt;/p&gt;




&lt;h3&gt;
  
  
  Components of Backtracking Problems
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initial State&lt;/strong&gt;: The starting point of the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target/Goal State&lt;/strong&gt;: The desired solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediate States&lt;/strong&gt;: States generated while moving from the initial state to the target state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path&lt;/strong&gt;: The sequence of states from the initial state to the target state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operators&lt;/strong&gt;: Rules or actions that transform one state into another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning Function&lt;/strong&gt;: A heuristic to eliminate invalid or suboptimal states early.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Backtracking Algorithm
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Start with the initial state.&lt;/li&gt;
&lt;li&gt;Use DFS to explore all possible states.&lt;/li&gt;
&lt;li&gt;If a state is invalid (based on the pruning function), backtrack and try another path.&lt;/li&gt;
&lt;li&gt;If a state is the goal state, return the solution.&lt;/li&gt;
&lt;li&gt;Repeat until all possible states are explored or a solution is found.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Example Problems Solved Using Backtracking
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. &lt;strong&gt;3-Digit Lock Problem&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial State&lt;/strong&gt;: "111"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target State&lt;/strong&gt;: The correct combination (e.g., "352")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operators&lt;/strong&gt;: Increment each digit by 1 (from 1 to 9).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning Function&lt;/strong&gt;: If a digit is correct (e.g., produces a "click"), fix it and move to the next digit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;findLockCombination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;combination&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Found combination:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;combination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newCombination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;combination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;combination&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newCombination&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Click at position&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;with digit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newCombination&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;111&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;targetCombination&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;352&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;findLockCombination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetCombination&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  2. &lt;strong&gt;Monks and Demons Problem&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial State&lt;/strong&gt;: 3 monks, 3 demons, and the boat on the left shore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target State&lt;/strong&gt;: All monks and demons on the right shore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operators&lt;/strong&gt;: Move 1 or 2 people in the boat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning Function&lt;/strong&gt;: Ensure that monks are never outnumbered by demons on either shore.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;solveMonksAndDemons&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;boat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isSafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Solution found:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newRight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;monks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="na"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;demons&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newRight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="na"&gt;boat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;};&lt;/span&gt;

                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isSafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;solveMonksAndDemons&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  3. &lt;strong&gt;Farmer, Goat, Cabbage, and Wolf Problem&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial State&lt;/strong&gt;: Farmer, goat, cabbage, and wolf on the left shore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target State&lt;/strong&gt;: All on the right shore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operators&lt;/strong&gt;: Farmer can take one item (goat, cabbage, or wolf) in the boat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning Function&lt;/strong&gt;: Ensure the goat is not left alone with the cabbage, and the wolf is not left alone with the goat.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;solveFarmerProblem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;goat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cabbage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wolf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="na"&gt;boat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isSafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unsafe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;goat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cabbage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wolf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;goat&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;unsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;unsafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;stateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Solution found:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fromShore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;left&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Possible moves: Farmer alone or Farmer + one item&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;fromShore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;newRight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;newLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newLeft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;newRight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;newRight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;newRight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;newRight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;newRight&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="nx"&gt;newLeft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;newLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;farmer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;newLeft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newRight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;boat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boat&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;left&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isSafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;solveFarmerProblem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h4&gt;
  
  
  4. &lt;strong&gt;Water Jug Problem&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial State&lt;/strong&gt;: Both jugs are empty.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target State&lt;/strong&gt;: 2 gallons in the 4-gallon jug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operators&lt;/strong&gt;: Fill, empty, or pour water between jugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pruning Function&lt;/strong&gt;: Avoid revisiting states.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Implementation:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;solveWaterJug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;initialState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jug4&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Solution found:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Fill jug4&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Fill jug3&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Empty jug4&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Empty jug3&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="na"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Pour jug4 to jug3&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;jug3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;jug3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;jug4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// Pour jug3 to jug4&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;moves&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;move&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;backtrack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;solveWaterJug&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Key Points:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Backtracking is a &lt;strong&gt;systematic way&lt;/strong&gt; to explore all possible solutions.&lt;/li&gt;
&lt;li&gt;It uses &lt;strong&gt;depth-first search&lt;/strong&gt; and &lt;strong&gt;pruning functions&lt;/strong&gt; to eliminate invalid paths.&lt;/li&gt;
&lt;li&gt;It is useful for solving &lt;strong&gt;NP-hard problems&lt;/strong&gt; like puzzles, constraint satisfaction problems, and combinatorial optimization.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>algorithms</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>A* Search Algorithm and Iterative Deepening A* in JavaScript</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Sat, 08 Feb 2025 05:44:55 +0000</pubDate>
      <link>https://dev.to/frorning/a-search-algorithm-and-iterative-deepening-a-in-javascript-4c0o</link>
      <guid>https://dev.to/frorning/a-search-algorithm-and-iterative-deepening-a-in-javascript-4c0o</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;1. Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Search algorithms play a crucial role in solving problems across computer science, robotics, game development, and beyond. Among them, heuristic-based search algorithms stand out for their ability to efficiently find solutions by leveraging additional knowledge about the problem domain. This article delves into two such algorithms: the widely used A* search algorithm and its memory-efficient counterpart, Iterative Deepening A* (IDA*).&lt;/p&gt;

&lt;p&gt;By the end of this article, you will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand the core principles of A* and IDA*.&lt;/li&gt;
&lt;li&gt;Learn how these algorithms work through code implementations in JavaScript.&lt;/li&gt;
&lt;li&gt;Explore their mathematical underpinnings and use cases.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. Understanding A* Search Algorithm&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What is A*?
&lt;/h4&gt;

&lt;p&gt;A* is a best-first search algorithm that aims to find the shortest path from a start node to a goal node. It uses an evaluation function:&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="katex-element"&gt;
  &lt;span class="katex-display"&gt;&lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;


&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
: The cost of the path from the start node to the current node 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/li&gt;
&lt;li&gt;
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
: A heuristic estimate of the cost to reach the goal node from 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The algorithm prioritizes nodes with the smallest 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 value, making it both optimal and complete, provided the heuristic 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is admissible (never overestimates the true cost).&lt;/p&gt;
&lt;h4&gt;
  
  
  Properties of A*
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Completeness&lt;/strong&gt;: Guaranteed to find a solution if one exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimality&lt;/strong&gt;: Finds the shortest path with an admissible heuristic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admissibility and Consistency&lt;/strong&gt;: Ensures the heuristic is reliable for optimal solutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  &lt;a href="https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode" rel="noopener noreferrer"&gt;Wikipedia Pseudocode for A*&lt;/a&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function reconstruct_path(cameFrom, current)
    total_path := {current}
    while current in cameFrom.Keys:
        current := cameFrom[current]
        total_path.prepend(current)
    return total_path

// A* finds a path from start to goal.
// h is the heuristic function. h(n) estimates the cost to reach goal from node n.
function A_Star(start, goal, h)
    // The set of discovered nodes that may need to be (re-)expanded.
    // Initially, only the start node is known.
    // This is usually implemented as a min-heap or priority queue rather than a hash-set.
    openSet := {start}

    // For node n, cameFrom[n] is the node immediately preceding it on the cheapest path from the start
    // to n currently known.
    cameFrom := an empty map

    // For node n, gScore[n] is the currently known cost of the cheapest path from start to n.
    gScore := map with default value of Infinity
    gScore[start] := 0

    // For node n, fScore[n] := gScore[n] + h(n). fScore[n] represents our current best guess as to
    // how cheap a path could be from start to finish if it goes through n.
    fScore := map with default value of Infinity
    fScore[start] := h(start)

    while openSet is not empty
        // This operation can occur in O(Log(N)) time if openSet is a min-heap or a priority queue
        current := the node in openSet having the lowest fScore[] value
        if current = goal
            return reconstruct_path(cameFrom, current)

        openSet.Remove(current)
        for each neighbor of current
            // d(current,neighbor) is the weight of the edge from current to neighbor
            // tentative_gScore is the distance from start to the neighbor through current
            tentative_gScore := gScore[current] + d(current, neighbor)
            if tentative_gScore &amp;lt; gScore[neighbor]
                // This path to neighbor is better than any previous one. Record it!
                cameFrom[neighbor] := current
                gScore[neighbor] := tentative_gScore
                fScore[neighbor] := tentative_gScore + h(neighbor)
                if neighbor not in openSet
                    openSet.add(neighbor)

    // Open set is empty but goal was never reached
    return failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. Implementing A* in JavaScript&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Below is a JavaScript implementation of A* for a grid-based shortest path problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PriorityQueue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;dequeue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;aStar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PriorityQueue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;openSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cameFrom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;gScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cols&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;fScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;openSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;openSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dequeue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;reconstructPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tentative_gScore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tentative_gScore&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;gScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;gScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tentative_gScore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="nx"&gt;fScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tentative_gScore&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

          &lt;span class="nx"&gt;openSet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fScore&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No path found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;reconstructPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Test A* Algorithm&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;aStar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Found Path:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notStrictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No path found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Test for no path&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blockedGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noPathResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;aStar&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;blockedGrid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noPathResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No path found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;4. Mathematical Proofs and Analysis&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Proof of Optimality
&lt;/h4&gt;

&lt;p&gt;A* guarantees the shortest path if the heuristic 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is admissible and consistent.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Admissibility&lt;/strong&gt;: 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 never overestimates the true cost to the goal. This ensures that A* will not bypass the optimal path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt;: For every pair of nodes 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, the heuristic satisfies:

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≤&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;c&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;

where 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;c&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 is the cost of transitioning from 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. This property ensures that the 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 values along a path are non-decreasing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Time and Space Complexity
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Time Complexity&lt;/strong&gt;: In the worst case, A* explores all nodes with 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 less than the cost of the optimal solution. This can grow exponentially with the branching factor 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and the depth 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 of the solution: 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Space Complexity&lt;/strong&gt;: A* stores all explored nodes in memory, leading to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mathnormal mtight"&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 space usage.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;5. Limitations of A&lt;/strong&gt;*
&lt;/h3&gt;

&lt;p&gt;While A* is highly efficient for many problems, it has significant limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory Requirements&lt;/strong&gt;: Storing all explored nodes can become infeasible for large graphs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt;: On graphs with high branching factors or inaccurate heuristics, A* may perform poorly.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;6. Iterative Deepening A* (IDA*)&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Why IDA*?
&lt;/h4&gt;

&lt;p&gt;IDA* addresses A*'s memory limitations by combining the benefits of A*'s heuristic-guided search with the memory efficiency of depth-first search. Instead of maintaining a priority queue, IDA* performs iterative depth-first searches with increasing 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
-cost thresholds.&lt;/p&gt;

&lt;h4&gt;
  
  
  How It Works
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Initialize the threshold to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;s&lt;/span&gt;&lt;span class="mord mathnormal"&gt;t&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mord mathnormal"&gt;r&lt;/span&gt;&lt;span class="mord mathnormal"&gt;t&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
.&lt;/li&gt;
&lt;li&gt;Perform a depth-first search, pruning paths with 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 threshold.&lt;/li&gt;
&lt;li&gt;If no solution is found, increase the threshold to the smallest 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 value that exceeded the current threshold.&lt;/li&gt;
&lt;li&gt;Repeat until the goal is reached.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  &lt;a href="https://en.wikipedia.org/wiki/Iterative_deepening_A*#Pseudocode" rel="noopener noreferrer"&gt;Wikipedia Pseudocode for IDA*&lt;/a&gt;
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path              current search path (acts like a stack)
node              current node (last node in current path)
g                 the cost to reach current node
f                 estimated cost of the cheapest path (root..node..goal)
h(node)           estimated cost of the cheapest path (node..goal)
cost(node, succ)  step cost function
is_goal(node)     goal test
successors(node)  node expanding function, expand nodes ordered by g + h(node)
ida_star(root)    return either NOT_FOUND or a pair with the best path and its cost

procedure ida_star(root)
    bound := h(root)
    path := [root]
    loop
        t := search(path, 0, bound)
        if t = FOUND then return (path, bound)
        if t = ∞ then return NOT_FOUND
        bound := t
    end loop
end procedure

function search(path, g, bound)
    node := path.last
    f := g + h(node)
    if f &amp;gt; bound then return f
    if is_goal(node) then return FOUND
    min := ∞
    for succ in successors(node) do
        if succ not in path then
            path.push(succ)
            t := search(path, g + cost(node, succ), bound)
            if t = FOUND then return FOUND
            if t &amp;lt; min then min := t
            path.pop()
        end if
    end for
    return min
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;7. Implementing IDA* in JavaScript&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;idaStar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cameFrom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;reconstructPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No path found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cameFrom&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;minThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;Infinity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;dy&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;nx&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dfs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;neighbor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;g&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;cameFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;visited&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;minThreshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;minThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;minThreshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pathIdaStar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;idaStar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;IDA* Found Path:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pathIdaStar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notStrictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathIdaStar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No path found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathIdaStar&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blockedGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;noPathResultIdaStar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;idaStar&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;blockedGrid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;heuristic&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strictEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;noPathResultIdaStar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No path found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  &lt;strong&gt;8. Comparing A* and IDA&lt;/strong&gt;*
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;A*&lt;/th&gt;
&lt;th&gt;IDA*&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Memory Usage&lt;/td&gt;
&lt;td&gt;High (stores all nodes)&lt;/td&gt;
&lt;td&gt;Low (depth-first search)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;Faster for smaller graphs&lt;/td&gt;
&lt;td&gt;Slower due to iterative nature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementation Complexity&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suitability for Large Graphs&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;More suitable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;9. Use Cases&lt;/strong&gt;
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Game Development&lt;/strong&gt;: Pathfinding for characters and AI in games (e.g., NPC movement).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robotics&lt;/strong&gt;: Navigation for autonomous robots in real-world environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network Routing&lt;/strong&gt;: Finding the shortest paths in network graphs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puzzle Solving&lt;/strong&gt;: Solving puzzles like the 8-puzzle or 15-puzzle efficiently.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;10. Common Pitfalls and Best Practices&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When implementing and applying A* or IDA*, it’s essential to avoid common mistakes and adopt best practices to ensure optimal performance.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Choosing Heuristics Wisely&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Admissibility&lt;/strong&gt;: Ensure that the heuristic never overestimates the cost to reach the goal. This guarantees that A* will find the optimal solution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency (Monotonicity)&lt;/strong&gt;: Verify that the heuristic satisfies the triangle inequality: 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;≤&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;c&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mpunct"&gt;,&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;′&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. This ensures that the algorithm’s 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 values are non-decreasing.&lt;/li&gt;
&lt;li&gt;Common heuristics include:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manhattan Distance&lt;/strong&gt;: Suitable for grid-based problems where movement is restricted to horizontal or vertical directions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Euclidean Distance&lt;/strong&gt;: Best for problems allowing diagonal or free movement in a continuous space.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain-Specific Heuristics&lt;/strong&gt;: Tailor heuristics based on specific problem knowledge to improve performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Balancing 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 and 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Assign appropriate weights to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 (path cost so far) and 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 (estimated cost to goal).&lt;/li&gt;
&lt;li&gt;Overemphasizing 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 might lead to suboptimal solutions or longer paths.&lt;/li&gt;
&lt;li&gt;Relying heavily on 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 might degrade performance, as the algorithm explores more nodes unnecessarily.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Debugging and Visualization Techniques&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visualization&lt;/strong&gt;: Tools like heatmaps or animations of the search process can help debug and optimize the algorithm.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt;: Track 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, and 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 values for each node to identify anomalies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Testing&lt;/strong&gt;: Validate heuristic functions and graph structures with simple test cases to ensure correctness.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Benchmarking&lt;/strong&gt;: Test the implementation on different datasets to measure performance and identify bottlenecks.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;11. Advanced Topics&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Variants of A&lt;/strong&gt;*
&lt;/h4&gt;

&lt;p&gt;A* has inspired several variants tailored to specific scenarios or performance needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Weighted A&lt;/strong&gt;*:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modifies the evaluation function to 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;f&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;g&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;+&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;h&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord mathnormal"&gt;n&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
, where 
&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;w&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 (weight) adjusts the heuristic's influence.&lt;/li&gt;
&lt;li&gt;Used to trade optimality for speed by biasing the search toward the goal.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Memory-Bounded A&lt;/strong&gt;*:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Examples include &lt;a href="https://en.wikipedia.org/wiki/SMA*" rel="noopener noreferrer"&gt;Simplified Memory-Bounded A* (SMA*)&lt;/a&gt; and &lt;a href="http://ai-maker.atrilla.net/the-recursive-best-first-search-algorithm/" rel="noopener noreferrer"&gt;Recursive Best-First Search (RBFS)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;These variants limit memory usage by discarding or revisiting nodes as needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://aaai.org/papers/079-aaai96-079-hierarchical-a-searching-abstraction-hierarchies-efficiently/" rel="noopener noreferrer"&gt;Hierarchical A*&lt;/a&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Splits large graphs into smaller subgraphs, solves each independently, and combines results.&lt;/li&gt;
&lt;li&gt;Ideal for complex environments like city navigation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Integration with Machine Learning&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Machine learning can enhance A* by dynamically adjusting heuristics or guiding the search process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Heuristics&lt;/strong&gt;: Use neural networks or reinforcement learning to predict better heuristic values for each state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptive Pathfinding&lt;/strong&gt;: Train models to optimize paths based on historical data or changing environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid Models&lt;/strong&gt;: Combine A* with ML-driven approaches for problems like real-time strategy games or robotics.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Parallelizing A&lt;/strong&gt;* for Performance Optimization
&lt;/h4&gt;

&lt;p&gt;Parallelization can significantly speed up A* for large graphs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Parallel Open Set&lt;/strong&gt;: Divide the open set among multiple threads or processes, each exploring a subset of nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Search&lt;/strong&gt;: Use distributed systems to partition the graph and execute search concurrently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPU Acceleration&lt;/strong&gt;: Leverage GPUs for massive parallelism, especially for heuristic computations and large-scale graph traversal.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;12. Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The A* search algorithm and Iterative Deepening A* are powerful tools for solving pathfinding and graph traversal problems. While A* excels in speed and guarantees optimality with sufficient memory, IDA* offers a memory-efficient alternative for large graphs. By understanding their principles, properties, and implementations, you can leverage these algorithms to tackle a wide range of computational problems effectively.&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>ai</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>How I Use AI, Sticky Notes, and Pomodoro to Stay Productive as a Software Engineer</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Fri, 24 Jan 2025 15:43:44 +0000</pubDate>
      <link>https://dev.to/frorning/how-i-use-ai-sticky-notes-and-pomodoro-to-stay-productive-as-a-software-engineer-3kl3</link>
      <guid>https://dev.to/frorning/how-i-use-ai-sticky-notes-and-pomodoro-to-stay-productive-as-a-software-engineer-3kl3</guid>
      <description>&lt;p&gt;As a software engineer juggling frontend and backend tasks, I’ve found that staying organized and focused is key to delivering quality work without burning out. Over time, I’ve developed a workflow that combines &lt;strong&gt;AI assistance&lt;/strong&gt;, &lt;strong&gt;sticky notes&lt;/strong&gt;, and the &lt;strong&gt;Pomodoro Technique&lt;/strong&gt; to break down tasks, track progress, and maintain my sanity. In this article, I’ll share my process and how you can adapt it to your own workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Problem: Overwhelming Tasks and Context Switching&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When working on a new feature or story, I often start with a vague set of requirements. Breaking these down into actionable steps can be overwhelming, especially when I’m still figuring out the details. Add in the constant context switching between frontend and backend work, and it’s easy to lose track of what’s done and what’s left.&lt;/p&gt;

&lt;p&gt;To tackle this, I needed a system that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Helps me break down tasks into manageable chunks.&lt;/li&gt;
&lt;li&gt;Keeps me aware of my progress.&lt;/li&gt;
&lt;li&gt;Allows me to adapt as I learn more about the problem.&lt;/li&gt;
&lt;li&gt;Ensures I stay focused and hydrated (because, let’s be honest, we all forget to drink water sometimes).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;My Workflow: AI, Sticky Notes, and Pomodoro&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here’s how I’ve structured my workflow to address these challenges:&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;1. Generate an Initial To-Do List with AI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When I start a new subtask, I use &lt;strong&gt;AI tools&lt;/strong&gt; (like Perplexity.ai or Continue.dev with Codellama) to generate an initial to-do list based on the requirements. For example, if I’m working on a user login feature, I might ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Generate a to-do list for implementing a user login feature with email and password authentication. Include frontend and backend tasks."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI might suggest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up login API endpoint.&lt;/li&gt;
&lt;li&gt;Create frontend login form.&lt;/li&gt;
&lt;li&gt;Add input validation for email and password.&lt;/li&gt;
&lt;li&gt;Implement error handling for invalid credentials.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives me a solid starting point with 2–5 high-level tasks.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;2. Create a Feature Branch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once I have my initial to-do list, I create a feature branch for the subtask. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; feature/user-login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps my work isolated and makes it easier to manage changes.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;3. Work Incrementally and Extend the To-Do List&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I start by tackling the first task on my list. As I work, I often uncover additional subtasks or edge cases. This is where AI comes in again. I’ll share my current progress and ask for suggestions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I’m working on implementing the login API. Here’s what I’ve done so far: [details]. What additional tasks should I consider?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI might suggest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add rate limiting to prevent brute force attacks.&lt;/li&gt;
&lt;li&gt;Log failed login attempts for security monitoring.&lt;/li&gt;
&lt;li&gt;Write unit tests for the login functionality.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I add these tasks to my to-do list and continue working incrementally.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;4. Track Progress with Sticky Notes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I’m a big fan of &lt;strong&gt;sticky notes&lt;/strong&gt; for tracking progress. Whether physical or digital, they give me a visual representation of what’s done and what’s left.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Physical Sticky Notes&lt;/strong&gt;: I place them on my desk or monitor, moving completed tasks to a "Done" section.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Digital Tools&lt;/strong&gt;: If I’m working remotely, I use tools like &lt;strong&gt;Trello&lt;/strong&gt;, &lt;strong&gt;Notion&lt;/strong&gt;, or &lt;strong&gt;Todoist&lt;/strong&gt; to manage my to-do list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crossing off tasks gives me a sense of accomplishment and keeps me motivated.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;5. Stay Focused with the Pomodoro Technique&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To maintain focus, I use the &lt;strong&gt;Pomodoro Technique&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work for 25 minutes, then take a 5-minute break.&lt;/li&gt;
&lt;li&gt;After four Pomodoros, take a longer break (15–30 minutes).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assign specific to-do items to each Pomodoro session. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pomodoro 1&lt;/strong&gt;: Set up login API endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pomodoro 2&lt;/strong&gt;: Add input validation for email and password.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During breaks, I make sure to hydrate, stretch, or take a short walk. &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;6. Create a Pull Request and Request Review&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once all tasks are completed, I create a &lt;strong&gt;pull request (PR)&lt;/strong&gt; for my feature branch. I write a detailed PR description summarizing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What was implemented.&lt;/li&gt;
&lt;li&gt;Any challenges faced.&lt;/li&gt;
&lt;li&gt;Testing performed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I then request a review from my team and iterate based on feedback.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Tools I Use&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here are some tools and methods that have been invaluable in my workflow:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;AI Tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Perplexity.ai&lt;/strong&gt;: For generating initial to-do lists and brainstorming solutions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continue.dev&lt;/strong&gt;: For seamless integration with my IDE and local development environment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local AI Models&lt;/strong&gt;: I use &lt;strong&gt;Qwen2.5-Coder 7B&lt;/strong&gt; and &lt;strong&gt;CodeLlama 7B&lt;/strong&gt; for code completion, debugging, and extending my to-do lists as I work. Running these models locally ensures privacy and customization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Task Management&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trello&lt;/strong&gt;: For visual task tracking with boards, lists, and cards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notion&lt;/strong&gt;: For documenting requirements, progress, and reference materials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JIRA&lt;/strong&gt;: For aligning my tasks with team-wide project management and sprint planning.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Pomodoro Timers&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual iPhone Timer&lt;/strong&gt;: I use the built-in timer on my iPhone for Pomodoro sessions. It’s simple and effective.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paper Checklist&lt;/strong&gt;: I keep a handwritten checklist on paper to track tasks for each Pomodoro session. There’s something satisfying about physically crossing off completed tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Hydration Tracking&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manual iPhone Timer&lt;/strong&gt;: I set recurring reminders to drink water throughout the day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paper Drawing&lt;/strong&gt;: I draw circles on paper and color them in to track my hydration progress. Each circle represents a glass of water, and filling them in gives me a visual sense of accomplishment.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why This Works for Me&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This workflow works because it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Breaks down complex tasks&lt;/strong&gt; into manageable chunks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapts to new information&lt;/strong&gt; as I learn more about the problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keeps me focused&lt;/strong&gt; with the Pomodoro Technique.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provides a visual representation of progress&lt;/strong&gt; with sticky notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensures I stay hydrated and energized&lt;/strong&gt; throughout the day.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Example Workflow in Action&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Scenario&lt;/strong&gt;: Implementing a User Login Feature
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Initial To-Do List (AI-Generated)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set up login API endpoint.&lt;/li&gt;
&lt;li&gt;Create frontend login form.&lt;/li&gt;
&lt;li&gt;Add input validation for email and password.&lt;/li&gt;
&lt;li&gt;Implement error handling for invalid credentials.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Feature Branch&lt;/strong&gt;: &lt;code&gt;feature/user-login&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Incremental Work&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with "Set up login API endpoint."&lt;/li&gt;
&lt;li&gt;Commit: &lt;code&gt;git commit -m "Add login API endpoint with email/password validation"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Ask AI: &lt;em&gt;"What else should I consider for the login API?"&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;AI suggests: Add rate limiting, log failed attempts, and write unit tests.&lt;/li&gt;
&lt;li&gt;Add these tasks to your to-do list.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sticky Notes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move "Set up login API endpoint" to "Done."&lt;/li&gt;
&lt;li&gt;Add new tasks: "Add rate limiting," "Log failed attempts," "Write unit tests."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pomodoro Sessions&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session 1: Work on "Add rate limiting."&lt;/li&gt;
&lt;li&gt;Session 2: Work on "Log failed attempts."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PR and Review&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create PR with title &lt;em&gt;"feat: implement user login"&lt;/em&gt; and description: &lt;em&gt;"Implemented user login feature with email/password authentication. Added rate limiting and logging for security. Unit tests included."&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Request review and iterate based on feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Key Benefits of This Workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clarity&lt;/strong&gt;: Breaking tasks into smaller chunks makes complex work manageable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus&lt;/strong&gt;: Pomodoro sessions and sticky notes help maintain focus and track progress.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptability&lt;/strong&gt;: AI assistance allows you to dynamically adjust your plan as you learn more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wellness&lt;/strong&gt;: Regular breaks and hydration keep you energized and productive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By formalizing and refining this workflow, you can enhance your productivity, reduce stress, and deliver high-quality work consistently.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Try It Out!&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you’re feeling overwhelmed by your tasks or struggling to stay focused, give this workflow a try. Start small—use AI to generate a to-do list, create a feature branch, and work incrementally. Experiment with sticky notes and the Pomodoro Technique to see what works best for you.&lt;/p&gt;

&lt;p&gt;I’d love to hear how you stay productive in your day-to-day work. Share your tips and tools in the comments below!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Happy coding!&lt;/strong&gt; 🚀&lt;/p&gt;

</description>
      <category>chatgpt</category>
      <category>productivity</category>
      <category>git</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Introduction to WebAssembly (WASM)</title>
      <dc:creator>Piyush Chauhan</dc:creator>
      <pubDate>Fri, 10 Jan 2025 16:21:06 +0000</pubDate>
      <link>https://dev.to/frorning/introduction-to-webassembly-wasm-4g35</link>
      <guid>https://dev.to/frorning/introduction-to-webassembly-wasm-4g35</guid>
      <description>&lt;p&gt;WebAssembly (WASM) is a binary instruction format for a stack-based virtual machine, designed as a portable target for high-performance applications. In this article, we'll explore how to compile a simple C program to WebAssembly, load it into a web browser, and interact with it using JavaScript. We'll also explore some useful tools and commands for working with WASM outside the dev container environment.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Setting Up the Development Environment&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Create the necessary folder structure and files for your WebAssembly project.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Create Project Folder&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Begin by creating a new directory for your project. Inside this folder, you'll add the necessary files and configurations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;wasm-web-example
&lt;span class="nb"&gt;cd &lt;/span&gt;wasm-web-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Set Up Dev Container&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;In the &lt;code&gt;wasm-web-example&lt;/code&gt; directory, create the &lt;code&gt;.devcontainer&lt;/code&gt; folder to store the dev container configuration files. These files will set up a container with Emscripten installed to compile C code into WebAssembly.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;.devcontainer&lt;/code&gt; folder, create the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;devcontainer.json&lt;/strong&gt;: 
The &lt;code&gt;devcontainer.json&lt;/code&gt; file configures VSCode to use the Docker container with the necessary extensions and environment settings.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Emscripten DevContainer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dockerfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dockerfile"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customizations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"terminal.integrated.shell.linux"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/bin/bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"C_Cpp.default.configurationProvider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode.cmake-tools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"C_Cpp.default.intelliSenseMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gcc-x64"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode.cpptools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode.cmake-tools"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"emcc --version"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dockerfile&lt;/strong&gt;: 
The &lt;code&gt;Dockerfile&lt;/code&gt; will set up the Emscripten environment. Here's the content for that file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use the official Emscripten image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; emscripten/emsdk:3.1.74&lt;/span&gt;

&lt;span class="c"&gt;# Set the working directory&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /workspace&lt;/span&gt;

&lt;span class="c"&gt;# Copy the source code into the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Install any additional packages if necessary (optional)&lt;/span&gt;
&lt;span class="c"&gt;# Ensure to clean up cache to minimize image size&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    apt-get clean &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Create VSCode Settings&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;In the root of your project, create a &lt;code&gt;.vscode&lt;/code&gt; folder with the following files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;c_cpp_properties.json&lt;/strong&gt;:
This file configures the C++ IntelliSense and include paths for your project.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Linux"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"includePath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}/**"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"/emsdk/upstream/emscripten/system/include"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"defines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"compilerPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/usr/bin/gcc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cStandard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"cppStandard"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gnu++17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"configurationProvider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode.cmake-tools"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;settings.json&lt;/strong&gt;: 
This file includes specific VSCode settings for language associations.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"files.associations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"emscripten.h"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"[javascript]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode.typescript-language-features"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"[typescript]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode.typescript-language-features"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"[jsonc]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode.json-language-features"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"[json]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode.json-language-features"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"[html]"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"editor.defaultFormatter"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode.html-language-features"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Create C, JavaScript, and HTML Files&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Now, create the following files for your project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;test.c&lt;/strong&gt;:
This C file contains the simple function that will be compiled to WebAssembly.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.c&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lhs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lhs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;test.html&lt;/strong&gt;:
This HTML file will load the WebAssembly module using JavaScript.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;WebAssembly Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;WebAssembly Example&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"test.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;test.js&lt;/strong&gt;:
This JavaScript file will fetch the WebAssembly module and call the exported function.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.js&lt;/span&gt;
&lt;span class="c1"&gt;// Path to the .wasm file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wasmFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test.wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Load the WebAssembly module&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasmFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed to load &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;wasmFile&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Access exported functions&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wasmExports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;wasmExports&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Example: Call a function exported from the WebAssembly module&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasmExports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wasmExports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Example function call&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Result from WebAssembly: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No "add" function found in the WebAssembly module.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error loading or running the WebAssembly module:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error loading WebAssembly module.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that you've set up all the necessary files and configurations, you can move on to compiling and interacting with WebAssembly.&lt;/p&gt;

&lt;p&gt;The project structure looks like following now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  wasm-web-example: tree &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt;
├── .devcontainer
│&amp;nbsp;&amp;nbsp; ├── Dockerfile
│&amp;nbsp;&amp;nbsp; └── devcontainer.json
├── .vscode
│&amp;nbsp;&amp;nbsp; ├── c_cpp_properties.json
│&amp;nbsp;&amp;nbsp; └── settings.json
├── test.c
├── test.html
├── test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  &lt;strong&gt;Compiling C Code to WebAssembly Using Emscripten&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Basic C Program&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;The file &lt;code&gt;test.c&lt;/code&gt; contains a simple function &lt;code&gt;add&lt;/code&gt; that adds two integers. We will compile this C function into WebAssembly using Emscripten.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.c&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;lhs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lhs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Emscripten Command&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Inside the dev container, open the terminal (use &lt;code&gt;cmd+j&lt;/code&gt; in VSCode) and run the following Emscripten command to compile the C code to WebAssembly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;emcc test.c &lt;span class="nt"&gt;-O3&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; STANDALONE_WASM &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;EXPORTED_FUNCTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'["_add"]'&lt;/span&gt; &lt;span class="nt"&gt;--no-entry&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; test.wasm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u8ybcwjwinz7cgytqct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u8ybcwjwinz7cgytqct.png" alt="Webassembly Example Devcontainer" width="800" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Breakdown of the Command
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;emcc&lt;/code&gt;&lt;/strong&gt;: This is the Emscripten C/C++ compiler command. It compiles C/C++ source files into WebAssembly or asm.js.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;test.c&lt;/code&gt;&lt;/strong&gt;: This specifies the input C source file that you want to compile.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-O3&lt;/code&gt;&lt;/strong&gt;: This flag enables aggressive optimizations during the compilation process. The &lt;code&gt;-O3&lt;/code&gt; optimization level is typically used for performance-critical applications, as it applies various optimization techniques that can significantly improve runtime performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-s STANDALONE_WASM&lt;/code&gt;&lt;/strong&gt;: This option instructs Emscripten to generate a standalone WebAssembly module. A standalone WASM module does not depend on any JavaScript glue code and can be executed independently in environments that support WebAssembly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-s EXPORTED_FUNCTIONS='["_add"]'&lt;/code&gt;&lt;/strong&gt;: This flag specifies which functions from the C code should be exported and made available for calling from JavaScript. In this case, the function named &lt;code&gt;_add&lt;/code&gt; will be accessible in the resulting WASM module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;--no-entry&lt;/code&gt;&lt;/strong&gt;: This option tells the compiler that there is no entry point (like a &lt;code&gt;main()&lt;/code&gt; function) in the program. This is useful for libraries or modules that are intended to be used by other code rather than executed directly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;-o test.wasm&lt;/code&gt;&lt;/strong&gt;: This specifies the output file name for the compiled WebAssembly module. In this case, it will create a file named &lt;code&gt;test.wasm&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This command will generate &lt;code&gt;test.wasm&lt;/code&gt;, the WebAssembly binary, and ensure that the &lt;code&gt;add&lt;/code&gt; function is exported for use in JavaScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Loading and Interacting with WebAssembly in the Browser&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;HTML Setup&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;The file &lt;code&gt;test.html&lt;/code&gt; contains a simple HTML page that loads the WebAssembly binary using JavaScript. The JavaScript code in &lt;code&gt;test.js&lt;/code&gt; fetches the &lt;code&gt;.wasm&lt;/code&gt; file and instantiates it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- test.html --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;WebAssembly Example&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;WebAssembly Example&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"output"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"test.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;JavaScript Setup&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;The JavaScript file &lt;code&gt;test.js&lt;/code&gt; loads the &lt;code&gt;test.wasm&lt;/code&gt; file and calls the exported &lt;code&gt;add&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// test.js&lt;/span&gt;
&lt;span class="c1"&gt;// Path to the .wasm file&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wasmFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test.wasm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Load the WebAssembly module&lt;/span&gt;
&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasmFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Failed to load &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;wasmFile&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayBuffer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Access exported functions&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wasmExports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;wasmExports&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;// Example: Call a function exported from the WebAssembly module&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasmExports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;wasmExports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Example function call&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Result from WebAssembly: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No "add" function found in the WebAssembly module.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error loading or running the WebAssembly module:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error loading WebAssembly module.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will display the result of the &lt;code&gt;add&lt;/code&gt; function in the HTML page when the module is loaded successfully.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Using External Tools on macOS&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Outside the dev container, there are several useful commands you can run to work with WebAssembly on your Mac.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Install &lt;code&gt;wabt&lt;/code&gt;&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;wabt&lt;/code&gt; (WebAssembly Binary Toolkit) provides utilities for working with WebAssembly, including converting &lt;code&gt;.wasm&lt;/code&gt; files to the human-readable WAT (WebAssembly Text) format. Install it via Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;wabt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Convert WASM to WAT&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;Once &lt;code&gt;wabt&lt;/code&gt; is installed, you can use the &lt;code&gt;wasm2wat&lt;/code&gt; tool to convert your WebAssembly binary (&lt;code&gt;test.wasm&lt;/code&gt;) to the WAT format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wasm2wat test.wasm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output a text representation of the WebAssembly module that you can read and inspect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(module
  (type (;0;) (func))
  (type (;1;) (func (param i32 i32) (result i32)))
  (type (;2;) (func (param i32)))
  (type (;3;) (func (result i32)))
  (func (;0;) (type 0)
    nop)
  (func (;1;) (type 1) (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add)
  (func (;2;) (type 2) (param i32)
    local.get 0
    global.set 0)
  (func (;3;) (type 3) (result i32)
    global.get 0)
  (table (;0;) 2 2 funcref)
  (memory (;0;) 258 258)
  (global (;0;) (mut i32) (i32.const 66560))
  (export "memory" (memory 0))
  (export "add" (func 1))
  (export "_initialize" (func 0))
  (export "__indirect_function_table" (table 0))
  (export "_emscripten_stack_restore" (func 2))
  (export "emscripten_stack_get_current" (func 3))
  (elem (;0;) (i32.const 1) func 0))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Serve the HTML Page&lt;/strong&gt;:
&lt;/h3&gt;

&lt;p&gt;To view the HTML page that interacts with the WebAssembly module, you can use Python’s simple HTTP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; http.server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will start a local web server on &lt;code&gt;http://localhost:8000&lt;/code&gt;, where you can open &lt;code&gt;index.html&lt;/code&gt; in your browser to see the WebAssembly module in action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsk8amzwwxy9if5hkboy6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsk8amzwwxy9if5hkboy6.png" alt="Webassembly Example Output" width="800" height="179"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By following the steps outlined in this article, you can set up a development environment to compile C code to WebAssembly, interact with it using JavaScript, and convert the resulting WebAssembly binary to the WAT format for inspection. The use of external tools like &lt;code&gt;wabt&lt;/code&gt; and Python’s HTTP server makes it easier to manage and explore WebAssembly modules on your macOS system.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webassembly</category>
      <category>vscode</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
