<?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>Forem: MarB</title>
    <description>The latest articles on Forem by MarB (@learn_deco).</description>
    <link>https://forem.com/learn_deco</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3643424%2F94aaccf3-7a20-43f7-840e-e05ed187f6b1.png</url>
      <title>Forem: MarB</title>
      <link>https://forem.com/learn_deco</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/learn_deco"/>
    <language>en</language>
    <item>
      <title>Building a Mentor, Not a Bot: From Linear Chains to Feedback Loops</title>
      <dc:creator>MarB</dc:creator>
      <pubDate>Sun, 14 Dec 2025 13:34:32 +0000</pubDate>
      <link>https://forem.com/learn_deco/the-end-of-prompt-engineering-entering-the-era-of-agent-control-2ild</link>
      <guid>https://forem.com/learn_deco/the-end-of-prompt-engineering-entering-the-era-of-agent-control-2ild</guid>
      <description>&lt;p&gt;For the last two years, &lt;strong&gt;"prompt engineering"&lt;/strong&gt; was the main event. It was fun, messy, and creative. While it had structure, the outcomes were rarely consistent enough to ship with confidence.&lt;/p&gt;

&lt;p&gt;In the Google &amp;amp; Kaggle AI Agents Intensive Course, I learned that this era is ending. We are entering the era of &lt;strong&gt;Agent Engineering&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But what does this mean for developers used to traditional software where you write 1 + 1, the output is always 2?&lt;/p&gt;

&lt;p&gt;AI Agents, however, are &lt;strong&gt;non-deterministic&lt;/strong&gt;; launching the exact same prompt twice can yield two completely different trajectories. This unpredictability manifests in several critical failure modes: the agent might drift off course (&lt;strong&gt;Hallucination&lt;/strong&gt;), burn all its fuel spinning in circles (&lt;strong&gt;Loops&lt;/strong&gt;), or encounter an asteroid field (&lt;strong&gt;API Timeouts&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;Because of this, we have to stop optimizing for the &lt;strong&gt;Output (The Black Box)&lt;/strong&gt; and start optimizing for the &lt;strong&gt;Trajectory (The Glass Box)&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The "Mission Control" Framework
&lt;/h2&gt;

&lt;p&gt;To handle this unpredictability, you need a framework. To move from Prototype to Production, your telemetry must cover four pillars of a successful mission:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Effectiveness (Did we land on Mars?)
&lt;/h3&gt;

&lt;p&gt;This is your primary success metric: &lt;strong&gt;Task Completion&lt;/strong&gt;. Think of it as the pass/fail state for the entire run. Specifically: Did the agent fully resolve the user's intended task? A highly conversational agent that returns a perfect, charming response but fails to integrate with the required external API is a critical mission failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Efficiency (Fuel Management)
&lt;/h3&gt;

&lt;p&gt;Did you reach orbit, or did you burn your entire tank on the launchpad? Efficiency tracks your &lt;strong&gt;"burn rate"&lt;/strong&gt;—tokens, latency, and steps.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rule of Thumb:&lt;/strong&gt; If your agent takes 50 "thoughts" and $\$2.00$ in API credits to answer a simple "Hello," you need to abort the launch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. Robustness (Structural Integrity)
&lt;/h3&gt;

&lt;p&gt;Space is hostile. APIs fail. Data is messy. A robust agent has backup systems. When it hits an error, it shouldn't crash or hallucinate a fake reality—it should correct its course, retry, or signal for help.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Safety (Containment Protocols)
&lt;/h3&gt;

&lt;p&gt;Safety ensures your agent respects the &lt;strong&gt;"flight corridors" (Guardrails)&lt;/strong&gt;. It must never leak data, accept prompt injections, or execute harmful commands.&lt;/p&gt;




&lt;h2&gt;
  
  
  Case Study: From Assembly Line to Feedback Loop
&lt;/h2&gt;

&lt;p&gt;The original design of the multi-agent system used a &lt;strong&gt;Linear Chain&lt;/strong&gt; (Architect \ Tutor \ Reviewer), functioning like an assembly line where failure at any step stopped the process. To better enforce deep logic and prioritize iterative refinement, we refactored the system from a strict chain into a &lt;strong&gt;Self-Correcting Loop&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Architecture Shift: Break the Chain
&lt;/h3&gt;

&lt;p&gt;This rigid chain doesn't teach; it just processes. To mimic a real senior developer, we need &lt;strong&gt;Iterative Refinement&lt;/strong&gt;. We moved the Tutor and Reviewer inside a &lt;code&gt;LoopAgent&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD
    User(Student Input) --&amp;gt; Generator
    subgraph "The Loop"
        Generator[Tutor Agent] --&amp;gt;|Draft Code| Critic[Reviewer Agent]
        Critic --&amp;gt;|Feedback| Gate{Pass Standards?}
        Gate --&amp;gt;|No: Specific Critique| Generator
    end
    Gate --&amp;gt;|Yes| Success(Final Grade)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This diagram illustrates an iterative feedback loop where the &lt;strong&gt;Tutor Agent&lt;/strong&gt; initially processes student input to create a code draft. A &lt;strong&gt;Reviewer Agent&lt;/strong&gt; immediately critiques this draft; if it fails to meet quality standards, specific feedback is looped back to the Tutor for refinement. This cycle of correction continues automatically until the logic satisfies the &lt;strong&gt;Decision Gate&lt;/strong&gt;. Once the standards are met, the process concludes with a final grade.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Generator (Tutor):&lt;/strong&gt; Prompts the student for code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Critic (Reviewer):&lt;/strong&gt; Grades the logic/style.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Loop:&lt;/strong&gt; If the code fails the "Senior Dev Standard," the system rejects it and sends it back to the Tutor with specific feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Smart Routing: Flash for Speed, Pro for Brains
&lt;/h3&gt;

&lt;p&gt;We used &lt;strong&gt;Model Routing&lt;/strong&gt; to balance the budget (Efficiency). We reserve the "heavy compute" only for where it matters.&lt;/p&gt;

&lt;p&gt;Here is the pseudo-code logic for the router:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;agent_loop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;student_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# 1. FAST &amp;amp; CHEAP: Interactive Chat
&lt;/span&gt;        &lt;span class="c1"&gt;# Use Gemini 2.5 Flash for high-speed, low-cost iterations
&lt;/span&gt;        &lt;span class="n"&gt;refined_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tutor_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;student_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-2.5-flash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# 2. SLOW &amp;amp; SMART: The Judge
&lt;/span&gt;        &lt;span class="c1"&gt;# Use Gemini 3 Pro for deep reasoning and subtle bug detection
&lt;/span&gt;        &lt;span class="n"&gt;feedback&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reviewer_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;refined_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gemini-3-pro&lt;/span&gt;&lt;span class="sh"&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;feedback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PASS&lt;/span&gt;&lt;span class="sh"&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;feedback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;

        &lt;span class="c1"&gt;# 3. FEEDBACK INJECTION
&lt;/span&gt;        &lt;span class="c1"&gt;# Pass the 'Pro' insights back to the 'Flash' agent
&lt;/span&gt;        &lt;span class="n"&gt;student_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Previous attempt failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;critique&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;. Try again.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;MaxRetriesExceeded&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Student needs human intervention.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. The Trajectory is the Teacher
&lt;/h3&gt;

&lt;p&gt;By moving to a loop, we gained a massive advantage: &lt;strong&gt;Observability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a linear chain, you just get a final score. In a loop, you get a &lt;strong&gt;Trajectory&lt;/strong&gt;. We can trace the student's entire struggle—how many attempts they took, where they got stuck, and how they fixed it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logs:&lt;/strong&gt; Capture the raw code attempts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traces:&lt;/strong&gt; Show the causal link between the Reviewer's feedback and the student's next move.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are no longer just "coding" instructions; we are directing autonomous systems. The ground is shifting from creation to control.&lt;/p&gt;

&lt;p&gt;By shifting from a straight line to a &lt;strong&gt;"Think, Act, Observe"&lt;/strong&gt; loop, we stopped building a quiz bot and started building a mentor. The agent doesn't just grade; it guides until the mission is accomplished.&lt;/p&gt;




</description>
      <category>googleaichallenge</category>
      <category>ai</category>
      <category>agents</category>
      <category>devchallenge</category>
    </item>
    <item>
      <title>Marley’s Ledger: Gothic Productivity with Next.js</title>
      <dc:creator>MarB</dc:creator>
      <pubDate>Fri, 05 Dec 2025 12:09:16 +0000</pubDate>
      <link>https://forem.com/learn_deco/building-a-haunted-to-do-app-with-nextjs-16-1lg8</link>
      <guid>https://forem.com/learn_deco/building-a-haunted-to-do-app-with-nextjs-16-1lg8</guid>
      <description>&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%2Fiz58i2997z482wq6t6zi.gif" 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%2Fiz58i2997z482wq6t6zi.gif" alt="A home page of the web application 'Marley's Ledger'" width="1000" height="320"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Mankind was my business."&lt;/em&gt;&lt;br&gt;
- Ch. Dickens&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Today, what is the true business of your day?&lt;/p&gt;

&lt;p&gt;We have all become &lt;strong&gt;obsessed&lt;/strong&gt; with productivity and efficiency and when the &lt;strong&gt;Kiroween&lt;/strong&gt; challenge asked for something spooky, I wondered: &lt;em&gt;What if productivity itself was the horror story?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Drawing inspiration from Charles Dickens' &lt;strong&gt;A Christmas Carol&lt;/strong&gt;, I found the perfect metaphor to bridge the themes of Halloween and Christmas. Just as Jacob Marley was weighed down by chains forged from a lifetime of neglect, every task we abandon is another link in our own chains. Every task we complete is a soul saved.&lt;/p&gt;

&lt;p&gt;The result is 'Marley's Ledger'—a to-do app where tasks literally haunt you, and your productivity determines whether you are redeemed or condemned.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does
&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.amazonaws.com%2Fuploads%2Farticles%2Fxof2nrav7n02cq6viypf.gif" 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%2Fxof2nrav7n02cq6viypf.gif" alt="Chains" width="605" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I wear the chain I forged in life. I made it link by link, and yard by yard."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Marley's Ledger isn't just a to-do list; it's a haunting. Commit to your work, or face the weight of your own procrastination: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Orbital Haunting&lt;/strong&gt;: Your tasks don't sit; they haunt. To-dos circle your screen as visual ghosts that demand attention. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chains of Neglect&lt;/strong&gt;: Subtasks are the fetters you forge. Unfinished items tighten the chains; completing them shatters the links. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soul Tracking&lt;/strong&gt;: Judge your own worth. The 'Saved vs. Lost' scale weighs your productivity instantly. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;'Consult the Spirits'&lt;/strong&gt;: Don't plan alone. Our Vercel-powered AI whispers specific, actionable guidance to guide you through the fog. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tonight's Ledger&lt;/strong&gt;: Face your judgment. End the day with a thematic verdict: 'Your chains grow lighter. Marley would be proud'.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How We Built It
&lt;/h2&gt;

&lt;p&gt;I moved beyond "vibe coding" into spec-driven development. Before writing a single line of code, I established a strict plan using the AI IDE Kiro.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;10 User Stories with formal acceptance criteria.&lt;/li&gt;
&lt;li&gt;12 Correctness Properties for property-based testing.&lt;/li&gt;
&lt;li&gt;14 Implementation Phases to ensure steady progress.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Framework: Next.js 16 + React 19&lt;/li&gt;
&lt;li&gt;Language: TypeScript&lt;/li&gt;
&lt;li&gt;Styling: Tailwind CSS 4 (Victorian palette: gold, deep purple, coral, pale pink)&lt;/li&gt;
&lt;li&gt;State: Zustand&lt;/li&gt;
&lt;li&gt;Testing: Vitest + fast-check&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Hydration Haunt
&lt;/h2&gt;

&lt;p&gt;After deployment, the project immediately hit the dreaded React Error #185. This hydration mismatch appeared strictly in production, threatening to derail the launch.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;Initially, I used a standard React Context approach with useEffect to load data from localStorage on mount.&lt;br&gt;
In development, this worked fine. However, in production, the server rendered the initial HTML (an empty state), but the client immediately replaced it with data from &lt;code&gt;localStorage&lt;/code&gt;. Next.js detected the difference between the server HTML and the first client paint, triggering the crash.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Code That Broke Production
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The original TaskContext.tsx&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;TaskProvider&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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReactNode&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;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setTasks&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Task&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;// 🚩 THIS CAUSED THE HYDRATION ERROR&lt;/span&gt;
  &lt;span class="c1"&gt;// Server renders [], Client immediately loads storage and re-renders&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loadState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;setTasks&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;tasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ← Hydration mismatch!&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;h3&gt;
  
  
  The Fix: Zustand + SkipHydration
&lt;/h3&gt;

&lt;p&gt;After struggling to debug the issue manually, I consulted Kiro. The AI immediately proposed migrating from React Context to Zustand with its persist middleware.&lt;/p&gt;

&lt;p&gt;The key was using &lt;code&gt;skipHydration&lt;/code&gt;. This forces the store to wait until the client has fully mounted before reconciling the state, ensuring the server and client HTML match exactly on the first paint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Store Configuration:&lt;/strong&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="c1"&gt;// src/stores/taskStore.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useTaskStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TaskState&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;
  &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;get&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="na"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
      &lt;span class="na"&gt;savedSouls&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;lostSouls&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="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;marleys-ledger-state&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;skipHydration&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;// ← Key: Don't auto-hydrate on SSR&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;strong&gt;The Hydration Component:&lt;/strong&gt;&lt;br&gt;
We added a component to handle the sync manually after the mount:&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;// src/stores/StoreHydration.tsx&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&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;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useTaskStore&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;./taskStore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;StoreHydration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;useEffect&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;useTaskStore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rehydrate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// ← Hydrate only on client&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;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This refactor took minutes, removed complex providers, and completely solved the SSR issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accomplishments &amp;amp; Wins
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;45 Property-Based Tests:&lt;/strong&gt; Kiro caught complex logic bugs—like broken chain visibility states—before writing a single line of UI code. The tests identified edge cases I never would have found manually.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Metaphor Hits Hard:&lt;/strong&gt; The ghost/chain/soul system isn't just decoration; it reframes the psychology of work. Abandoning a to-do item feels significantly heavier when you see "Lost Soul +1" flash on the screen.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Assisted Architecture:&lt;/strong&gt; Instead of scouring documentation for hours, I described the symptom to Kiro, and it immediately proposed the architecture shift to Zustand, turning a panic moment into a five-minute fix.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sound Design:&lt;/strong&gt; Adding atmospheric audio, such as chain rattles when adding tasks and bell chimes for saved souls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiplayer Haunting:&lt;/strong&gt; A feature allowing you to share ledgers with friends and see each other's ghosts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile App:&lt;/strong&gt; A React Native version so your ghosts can follow you offline.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Thanks for checking out Marley's Ledger! If you want to see if your productivity is redeemed or condemned, check out the repo below.&lt;br&gt;
&lt;a href="https://github.com/marina-deco/marley-ledger/settings" rel="noopener noreferrer"&gt;Marley's Ledger&lt;/a&gt;&lt;br&gt;
If you have any questions about the technical choices, the Dickensian themes, or why I chose to build Marley's Ledger, please leave them in the comments below! I'd love to spark additional discussion and explain why I personally found this project helpful (and hopefully why you might, too).&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>nextjs</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
