<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[nullpointerette]]></title><description><![CDATA[nullpointerette]]></description><link>https://www.nullpointerette.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1753294161657/cb5a680d-169a-42a6-a46b-3c636977c559.png</url><title>nullpointerette</title><link>https://www.nullpointerette.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 01:16:36 GMT</lastBuildDate><atom:link href="https://www.nullpointerette.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[teaching a gpt to judge itself, part one]]></title><description><![CDATA[last time, i laid out the theory: toy datasets, self-critique inspiration, and the idea of tracing evaluations. this week, i actually built it.
the mvp version of reasonsaver is a pipeline that takes prompts, runs completions, scores them, and saves ...]]></description><link>https://www.nullpointerette.dev/teaching-a-gpt-to-judge-itself-part-one</link><guid isPermaLink="true">https://www.nullpointerette.dev/teaching-a-gpt-to-judge-itself-part-one</guid><dc:creator><![CDATA[nullpointerette]]></dc:creator><pubDate>Tue, 30 Sep 2025 21:19:04 GMT</pubDate><content:encoded><![CDATA[<p>last time, i laid out the theory: toy datasets, self-critique inspiration, and the idea of tracing evaluations. this week, i actually built it.</p>
<p>the mvp version of reasonsaver is a pipeline that takes prompts, runs completions, scores them, and saves evaluations — all in one flow. i wanted it to feel like more than a notebook experiment, so i wrapped it in a cli tool and proved it could scale beyond just a few samples.</p>
<h2 id="heading-building-the-flow">building the flow</h2>
<p>i started small: json files in, json files out. <code>prompts.json → completions.json → evaluations.json</code>. on top of that i added a lightweight scoring function using hugging face embeddings. the idea was to measure cosine similarity against a “reasoning anchor” baseline.</p>
<p>once that worked, i wrapped it with argparse so i could call it straight from the terminal. this small shift — typing <code>python</code> <a target="_blank" href="http://cli.py"><code>cli.py</code></a> <code>evaluate</code> instead of rerunning cells — made it feel like a real tool instead of a sandbox.</p>
<h2 id="heading-observability-matters">observability matters</h2>
<p>from the start, i wanted to know what was happening under the hood. i wired in opentelemetry spans, creating a parent span for each evaluation run and child spans for scoring and logging. i also added structured json logs with loguru so every step left a reproducible trail.</p>
<p>watching trace ids pop up in the terminal, and saving logs that linked prompts to scores, was more satisfying than i expected. it proved that evaluation could be transparent, not just opaque “model magic.”</p>
<h2 id="heading-scaling-up">scaling up</h2>
<p>the toy runs went fine, but i needed to stress test. the eli5 dataset i planned to use had been deprecated (boo), so i pivoted to squad. with that, i pushed the pipeline through ten thousand test cases. the results: it held up. logs and spans captured the entire run, and the outputs were reproducible.</p>
<p>along the way i hit a few roadblocks: numpy 2.0 broke pytorch compatibility, so i downgraded to 1.x. i also had to add batch flags to avoid burning tokens on massive runs. though, running 10K test cases didn’t cost as much as i thought, maybe like $12-15, but still..it would have taken a while to go over all 10K runs, and i wanted to save myself the waiting.</p>
<h2 id="heading-what-this-means">what this means</h2>
<p>reasonsaver is no longer just a sketch of an idea. it’s a working pipeline with observability built in, benchmarks at scale, and room to grow.</p>
<p>from a systems lens, it taught me how to combine llm evaluation with the same practices you’d expect in production infra: logging, tracing, reproducibility. from a career lens, it sharpened into a clear line on my resume: engineered a fault-tolerant evaluation pipeline for multi-candidate llm completions, integrated pytorch embeddings for reranking, and added structured logging with opentelemetry spans for observability across 10k+ test cases.</p>
<h2 id="heading-next-steps">next steps</h2>
<p>the foundation is here. what’s next: multi-candidate reranking, a fastapi endpoint for programmatic access, self-critique scoring chains, and eventually piping spans into jaeger or grafana dashboards.</p>
<p>openai and anthropic might run billion-token evaluations, but the same principles can exist at a smaller, personal scale. reasonsaver is my way of shrinking those patterns into something lightweight, but real.</p>
<p>part zero was about inspiration. this part is about proof.</p>
<p>stay tuned for part two. ✨</p>
]]></content:encoded></item><item><title><![CDATA[my first blocknote contribution: closing the popover]]></title><description><![CDATA[i’ve always loved tools that make you forget there’s code underneath. everything feels clean, fluid, inevitable… the kind of products where it seems like ui just melts away.
but of course, every smooth interaction is hiding about a hundred tiny edge ...]]></description><link>https://www.nullpointerette.dev/blocknote-popover</link><guid isPermaLink="true">https://www.nullpointerette.dev/blocknote-popover</guid><dc:creator><![CDATA[nullpointerette]]></dc:creator><pubDate>Wed, 10 Sep 2025 19:44:16 GMT</pubDate><content:encoded><![CDATA[<p>i’ve always loved tools that make you forget there’s code underneath. everything feels clean, fluid, inevitable… the kind of products where it seems like ui just <em>melts away.</em></p>
<p>but of course, every smooth interaction is hiding about a hundred tiny edge cases. wanting to learn more about what makes a smooth product tick, i finally peeked behind the curtain and decided to contribute to <a target="_blank" href="https://www.blocknotejs.org">blocknote</a>, a notion-style text editor. i’ve been a notion fan for years, and blocknote felt like the perfect way to learn how these kinds of editors actually work, while giving something back to the tools i enjoy using.</p>
<h3 id="heading-finding-an-issue">finding an issue</h3>
<p>i didn’t start with a grand feature idea. i scrolled through open issues and saw <a target="_blank" href="https://github.com/TypeCellOS/BlockNote/issues/1696">#1696</a>: <em>“link popover does not close when using static formatting toolbar.”</em></p>
<p>low priority, and labeled “good first issue.” couldn’t have been more perfect.</p>
<h3 id="heading-setting-up">setting up</h3>
<p>blocknote is a pnpm/nx monorepo with packages for <code>core</code>, <code>react</code>, and multiple ui layers (<code>mantine</code>, <code>shadcn</code>, <code>ariakit</code>). the static toolbar lives in <code>mantine</code>.</p>
<p>it took me a hot minute (and A LOT of broken builds) to get the docs site running locally. i even gutted half the demo pages just to isolate the one example i needed: static formatting toolbar. it was super janky, but it worked.</p>
<h3 id="heading-the-fix">the fix</h3>
<p>the difference between the floating toolbar (which was the working one) and the static one (which didn’t) came down to state management:</p>
<ul>
<li><p>the floating toolbar’s plugin explicitly closes the popover after submit</p>
</li>
<li><p>while static toolbar never calls <code>setOpened(false)</code> and therefore stays frozen in time and space.</p>
</li>
</ul>
<p>so the fix was literally like five lines in <a target="_blank" href="https://github.com/TypeCellOS/BlockNote/pull/xxxx/files"><code>CreateLinkButton.tsx</code></a>:</p>
<pre><code class="lang-tsx">editLink={(url) =&gt; {
  update(url);
  setOpened(false);
  editor.focus();
}}
</code></pre>
<p>it’s a tiny change, but now the popover closes like it should.</p>
<h3 id="heading-demo">demo</h3>
<p>before: link applied, popover stayed open.<br />after: link applied, popover closes.</p>
<p><img src="https://github.com/user-attachments/assets/3812adfb-4635-495b-842b-3bba8734076f" alt="screen recording" /></p>
<h3 id="heading-what-i-learned">what i learned</h3>
<ul>
<li><p>monorepos feel like a maze at first, but you get good at pattern-spotting fast.</p>
</li>
<li><p>many bugs are really just “someone forgot to update state.”</p>
</li>
<li><p>you don’t need a huge feature to start contributing to repos, even small ui fixes matter.</p>
</li>
</ul>
<p>it’s a tiny change, but it feels huge. i went from “i don’t even know where to start” to opening a pr that closes a bug.</p>
<p>makes me appreciate how much thought goes into these little interactions. that’s the kind of invisible polish i’ve always loved about products like figma, duolingo, slack, notion.</p>
<p>this isn’t the end, though! i’m so excited to dive in even deeper into blocknote. ✨</p>
]]></content:encoded></item><item><title><![CDATA[teaching a gpt to judge itself, part zero]]></title><description><![CDATA[lately, i’ve been obsessed with how companies are evaluating their large language models. openai has evals, which is “a framework for evaluating LLMs and LLM systems, and an open-source registry of benchmarks.” anthropic has written about "constituti...]]></description><link>https://www.nullpointerette.dev/teaching-a-gpt-to-judge-itself-part-zero</link><guid isPermaLink="true">https://www.nullpointerette.dev/teaching-a-gpt-to-judge-itself-part-zero</guid><dc:creator><![CDATA[nullpointerette]]></dc:creator><pubDate>Mon, 25 Aug 2025 00:26:11 GMT</pubDate><content:encoded><![CDATA[<p>lately, i’ve been obsessed with how companies are evaluating their large language models. openai has evals, which is “a framework for evaluating LLMs and LLM systems, and an open-source registry of benchmarks.” anthropic has written about "<a target="_blank" href="https://www.anthropic.com/news/claudes-constitution">constitutional ai</a>,” where they have models critique their own reasoning.</p>
<p>why not humans? well, according to them, having humans judge the correctness of a model from several answers has some “shortcomings.” one obvious reason is that is doesn’t scale very well. llm’s need A LOT of data to work with, and humans simply can’t keep up with the pace an ai needs to be well-trained. there are some ethical reasons, too, like requiring humans to interact with a number of disturbing content. that’s why anthropic uses <a target="_blank" href="https://arxiv.org/abs/2212.08073">self-critique and fine-tuning techniques</a> for ai’s to do the work themselves.</p>
<p>all of this got me thinking - what if i tried to replicate this myself? and how exactly would monitoring these evaluations work, too? obviously i don’t have access to openai’s resources. i’m not training foundational models or fine-tuning with billions of tokens. but the core ideas of structured evaluation datasets, self-critique, and observability can definitely be explored at a smaller scale.</p>
<p>so after doing some research, i found some helpful resources:</p>
<ul>
<li><p><a target="_blank" href="https://huggingface.co/blog/getting-started-with-embeddings">hugging face tutorials</a> show how to turn text into <a target="_blank" href="https://huggingface.co/blog/static-embeddings">embeddings</a>, aka representing language as vectors so you can measure similarity or cluster outputs.</p>
</li>
<li><p>even infra companies like <a target="_blank" href="https://www.datadoghq.com/architecture/mastering-distributed-tracing-data-volume-challenges-and-datadogs-approach-to-efficient-sampling/">datadog</a> and <a target="_blank" href="https://www.honeycomb.io/blog/time-to-version-observability-signs-point-to-yes">honeycomb</a> write about observability: using traces and spans to log what’s happening inside complex systems.</p>
</li>
<li><p>i also found <a target="_blank" href="https://vfunction.com/blog/opentelemetry-tracing-guide/">opentelemetry tracing guide + best practices</a> super helpful; it explains spans and traces in a way you can actually apply on a toy project.</p>
</li>
</ul>
<p>i’m not training billion-parameter models or shipping production infra. but the <em>patterns</em>-structured datasets (openai), self-critique (anthropic), embeddings (hugging face), and traces (datadog/honeycomb) - felt like something i could shrink down into a side project.</p>
<p>and that’s where <em>reasonsaver</em> comes in. it’s my sandbox for shrinking these big-company ideas into something lightweight and personal. i’d use toy datasets instead of benchmarks, or a tiny pytorch embedder instead of sentence-bert, and a baby <code>trace.py</code> instead of datadog dashboards. but that doesn’t mean evaluation can’t be powerful.</p>
<p>first, i’d lay the foundation: toy datasets to prove the flow, a baseline ranking strategy, and trace spans to make the process observable.</p>
<p>next, i’ll scale it up: integrating a lightweight pytorch embedder (hugging face–style), running across 10k+ structured test cases, and layering in self-critique scoring chains inspired by anthropic. the goal is to measure improvements in reasoning accuracy and make evaluation results reproducible - the same way openai does with evals, just at a smaller but still meaningful scale.</p>
<p>reasonsaver isn’t a throwaway experiment, though. it’s a hands-on framework for exploring how modern ai companies test their systems, and a way to sharpen the evaluation and infra instincts i’ll need as an engineer.</p>
<p>stay tuned for more! ✨</p>
]]></content:encoded></item><item><title><![CDATA[why notion's "offline mode" is a big deal.]]></title><description><![CDATA[disclaimer: while i am a huge notion fan, i am not an employee (well, for now, anyway 😏), so this is just my best guess at what’s going on under the hood. still, as someone who geeks out over infra, i couldn’t resist talking about why this particula...]]></description><link>https://www.nullpointerette.dev/notion-offline-mode</link><guid isPermaLink="true">https://www.nullpointerette.dev/notion-offline-mode</guid><dc:creator><![CDATA[nullpointerette]]></dc:creator><pubDate>Sat, 23 Aug 2025 01:44:51 GMT</pubDate><content:encoded><![CDATA[<p><em>disclaimer: while i am a huge notion fan, i am not an employee (well, for now, anyway 😏), so this is just my best guess at what’s going on under the hood. still, as someone who geeks out over infra, i couldn’t resist talking about why this particular release matters.</em></p>
<h3 id="heading-first-the-old-world">first, the old world.</h3>
<p>for most of its life, notion was online-first, designed to only <em>really</em> work if you had the internet. every keystroke you made streamed to the backend, which acted as the single source of truth. this means that when you typed a letter, the edit was immediately sent over the network to notion’s servers. the app passed your data along, and the official, “real” version of your notes lived in the cloud.</p>
<p>so basically, if you were offline:</p>
<ul>
<li><p>your device didn’t have a full copy of your workspace</p>
</li>
<li><p>edits couldn’t sync</p>
</li>
<li><p>you’d see things like blank pages or “loading” because the app needed to wait for the server to tell it what the document was supposed to look like</p>
</li>
</ul>
<p>now i can only make assumptions, but im sure a few people behind the scenes at notion said something like: “hmm..let’s do something about that.” and the project to make notion work offline was born.</p>
<h3 id="heading-next-the-new-shift">next, the new shift.</h3>
<p>to make offline mode a reality, the team probably needed to reconcile a core problem: <strong>syncing states</strong>.</p>
<p>as we discussed, when you’re online, every notion-motion travels to the backend, updates the database, and syncs back to other clients. offline breaks that assumption. suddenly:</p>
<ul>
<li><p>your edits need to be stored locally, not just in memory</p>
</li>
<li><p>changes need to be merged back into the cloud later</p>
</li>
<li><p>conflicts need to be handled gracefully (ex. two people editing the same page in different states)</p>
</li>
</ul>
<p>this isn’t just “cache some data.” it’s a replicated state machine problem— making sure local copies and the source of truth eventually agree, without losing the user’s work. to do that, you’d need to rethink how the editor worked, at a fundamental level.</p>
<h3 id="heading-thats-where-crdts-come-in">that’s where crdts come in.</h3>
<p>as notion’s ceo <a target="_blank" href="https://twitter.com/ivanhzhao">ivan zhao</a> explained, the team solved this with one of the largest production crdt systems ever built.</p>
<p>crdts, or <strong>conflict-free replicated data types</strong>, are special data structures that make collaboration possible even when edits happen out of order.</p>
<p>here’s the trick: no matter what order changes arrive in, crdts guarantee the document will eventually converge to the same result.</p>
<p>🧩 think of it like lego instructions:</p>
<ul>
<li><p>one person adds a tower on the left</p>
</li>
<li><p>another person adds a tower on the right</p>
</li>
<li><p>even if they build them in different orders, when the instructions are merged, the final castle still has both towers.</p>
</li>
</ul>
<p>that’s what makes crdts so powerful for text editing. everyone can edit offline, and when they reconnect, all the edits merge without overwriting each other.</p>
<p>notion’s team adopted <a target="_blank" href="https://www.inkandswitch.com/peritext/">peritext</a> — a crdt framework from the <a target="_blank" href="https://www.inkandswitch.com/">research lab</a> ink &amp; switch, designed specifically for rich text. and according to notion engineers, this rollout is one of the largest crdt deployments in history.</p>
<p>this is way more than “offline mode.” it’s a deep re-architecture of how the editor works at its core.</p>
<h3 id="heading-the-building-blocks"><strong>the building blocks</strong></h3>
<p>to pull this off, the team needed a whole new stack of infra:</p>
<ul>
<li><p><strong>local storage layer</strong>: large workspaces mean storing potentially gigabytes of content on-device. that requires efficient serialization, compression, and eviction policies.</p>
</li>
<li><p><strong>sync engine</strong>: a system to track deltas (what changed) instead of re-uploading entire pages. this keeps sync fast and bandwidth-light.</p>
</li>
<li><p><strong>conflict resolution</strong>: merges need to be automatic most of the time — but with a clear ux when human decisions are required. think crdts (conflict-free replicated data types) or operational transforms.</p>
</li>
<li><p><strong>consistency guarantees</strong>: notion’s promise is collaboration without surprises. that means prioritizing eventual consistency while making it feel real-time.</p>
</li>
<li><p><strong>resilience at scale</strong>: millions of clients coming online and syncing at once = load spikes. infra has to scale, throttle, and prioritize safely.</p>
</li>
</ul>
<h3 id="heading-why-it-matters"><strong>why it matters</strong></h3>
<ul>
<li><p><strong>reliability &amp; trust:</strong> notion is now “always there,” like virtual pen &amp; paper.</p>
</li>
<li><p><strong>accessibility</strong>: unlocks usage in low-connectivity regions.</p>
</li>
<li><p><strong>infra flex:</strong> solving crdts + sync at scale shows notion isn’t just a design tool, it’s a distributed systems company.</p>
</li>
<li><p><strong>future-proofing</strong>: the same infra powers faster load times, mobile-first workflows, and even edge-aware collaboration down the line.</p>
</li>
</ul>
<h3 id="heading-the-bigger-picture"><strong>the bigger picture</strong></h3>
<p>offline mode shows notion is willing to do the deep, boring, hard engineering work that nobody sees, but everyone feels. this is what separates a pretty app from a real platform.</p>
<p>common W for notion! ✨</p>
]]></content:encoded></item></channel></rss>