<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Grady Berry Ward — Projects, Essays, and Notes</title>
    <link>https://grady.dev/</link>
    <description>Projects, essays, and notes about technology, people, privacy, work, and the things worth caring about.</description>
    <language>en-US</language>
    <generator>Hugo</generator>
    <ttl>60</ttl>
    <copyright>Copyright © Grady Berry Ward</copyright>
    <atom:link href="https://grady.dev/index.xml" rel="self" type="application/rss+xml" />
    <atom:link href="https://grady.dev/" rel="alternate" type="text/html" />
    <image>
      <url>https://grady.dev/favicon-32x32.png</url>
      <title>Grady Berry Ward — Projects, Essays, and Notes</title>
      <link>https://grady.dev/</link>
      <width>32</width>
      <height>32</height>
    </image>
    <lastBuildDate>Fri, 25 Sep 2026 00:00:00 +0000</lastBuildDate><item>
      <title>Pharos: Token Library</title>
      <link>https://grady.dev/projects/pharos/</link>
      <guid isPermaLink="true">https://grady.dev/projects/pharos/</guid>
      <pubDate>Fri, 25 Sep 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>tools</category>
      <description>LLM transcripts are the ultimate proprietary dataset - get the most out of yours</description>
      <content:encoded>&lt;p&gt;TL;DR: &lt;a href=&#34;https://github.com/gbdubs/alexandria&#34;&gt;A Mac app&lt;/a&gt; to make your past AI transcripts searchable, and easy to mine for insights. Free and open source (MIT).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;LLM transcripts are goldmines.&lt;/strong&gt; When you work with an AI to design or build a system, any value that comes from it originates in the back and forth conversation. The code gets committed, but the conversation often contains insight and context that never makes it into git (and shouldn&amp;rsquo;t).&lt;/p&gt;&#xA;&lt;p&gt;If a human says:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&amp;ldquo;Oh we actually don&amp;rsquo;t want to do X because of Y&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;&amp;ldquo;Can you revert X, I don&amp;rsquo;t think we need it anymore because of Y&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;&amp;ldquo;Can you do a deep dive to explain X to me, I want to make sure I understand it&amp;rdquo;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Or an LLM says (in a visible reasoning summary or response)&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&amp;ldquo;I hadn&amp;rsquo;t realized that X&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;&amp;ldquo;Ahh now I see that we always have to do X when we do Y&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;&amp;ldquo;I thought X was going to work but it looks like it did not&amp;rdquo;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Every one of those snippets is wildly useful - for future users or modifiers of the system, the deliberative process is more valuable than the final result.&lt;/p&gt;&#xA;&lt;p&gt;Thankfully, conversations are recorded. Claude Code, and Codex, and other agentic harnesses all write down your conversation to a file. These &amp;ldquo;transcript&amp;rdquo; files are typically JSONL, structured slightly differently for each model provider, but they record everything about a conversation, including the messages to and from the agent, the agent&amp;rsquo;s tool calls, and the files that were modified. These files are gold mines.&lt;/p&gt;&#xA;&lt;p&gt;I built Pharos to mine gold.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-pharos&#34;&gt;What is Pharos&lt;/h2&gt;&#xA;&lt;p&gt;Pharos is a Mac App that pulls in transcripts of chat conversations from known locations, backs them up, and indexes them to make them unreasonably useful across a wide range of questions you might want to ask about your chat conversations. Pharos can be used to look at your conversations and find answers to your questions:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;What kind of errors are my models making frequently?&lt;/li&gt;&#xA;&lt;li&gt;What websites have my agents visited, CURL&amp;rsquo;ed, or POST&amp;rsquo;ed to?&lt;/li&gt;&#xA;&lt;li&gt;Which conversation did I mention &amp;ldquo;curmudgeon&amp;rdquo; in?&lt;/li&gt;&#xA;&lt;li&gt;In what weeks am I breaking even on API-level pricing, and by how much?&lt;/li&gt;&#xA;&lt;li&gt;How many tokens have I used this week?&lt;/li&gt;&#xA;&lt;li&gt;How much of my prompts are human generated?&lt;/li&gt;&#xA;&lt;li&gt;Do cross-model reviews actually yield meaningful PR findings?&lt;/li&gt;&#xA;&lt;li&gt;What are common sources of latency in my conversations?&lt;/li&gt;&#xA;&lt;li&gt;Where in agent transcripts do I see the phrase &amp;ldquo;Oh I misunderstood&amp;rdquo;?&lt;/li&gt;&#xA;&lt;li&gt;How efficient are my compaction strategies?&lt;/li&gt;&#xA;&lt;li&gt;I remember that I accidentally pasted an API key into a chat conversation - is it the key XYZ or does that not show up in conversation history (i.e. already rotated)?&lt;/li&gt;&#xA;&lt;li&gt;Where are my uses of sub-agents inefficient/how much context do I waste with common prefixes?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;But these are questions a human might ask. Pharos also holds the indexes and tools to help other LLMs find and navigate past conversations:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;What conversations are most relevant to the task I&amp;rsquo;ve been given, XYZ?&lt;/li&gt;&#xA;&lt;li&gt;What chat conversation produced this chunk of code that I now need to modify?&lt;/li&gt;&#xA;&lt;li&gt;What were the last 10 chat conversations in this repo about?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Pharos ships with a super simple, context efficient MCP server that gives LLMs access to layered sets of tooling that let them explore data at the right level of granularity.&lt;/p&gt;&#xA;&lt;h3 id=&#34;how-does-it-work&#34;&gt;How does it work?&lt;/h3&gt;&#xA;&lt;p&gt;Pharos is simple. It&amp;rsquo;s a very basic database and Mac App Wrapper that backs up and indexes conversations so you can (instantly) see metrics and answers to each of these questions.&lt;/p&gt;&#xA;&lt;p&gt;Pharos operates best off of an SSD - that way you can plug it into multiple computers (if you have several dev machines like I do) and it pulls in transcripts and keeps them in sync automatically, automatically syncing from its host machine every time it&amp;rsquo;s plugged in.&lt;/p&gt;&#xA;&lt;h3 id=&#34;on-naming&#34;&gt;On Naming&lt;/h3&gt;&#xA;&lt;p&gt;I started off calling this project &amp;ldquo;Alexandria&amp;rdquo;, like the library, but then I realized the value isn&amp;rsquo;t in the archival, it&amp;rsquo;s in the way that indexing can shine light on data at scale, and thus the lighthouse was a better analogy. Thankfully Alexandria had both - the lighthouse was called &amp;ldquo;Pharos&amp;rdquo;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-not-rely-on-the-labs&#34;&gt;Why not rely on the labs?&lt;/h2&gt;&#xA;&lt;p&gt;Most folks are relying on built-in harness and agent systems to manage context and history for them. After all, every agentic system ships with built-in tools for managing memory across sessions, for backing up transcripts to their clouds, etc.&lt;/p&gt;&#xA;&lt;p&gt;Folks will say &amp;ldquo;oh Claude will just update its own memory&amp;rdquo; or &amp;ldquo;if it&amp;rsquo;s important the agent will write it down somewhere to the repo&amp;rdquo;. Those might be true today, but the incentive misalignment around transcripts should give you pause:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Model providers have every incentive to make transcript files proprietary - to prevent distilling, engender lock-in, and centralize control and access to the tokens you&amp;rsquo;ve paid for.&lt;/li&gt;&#xA;&lt;li&gt;Model providers also have every incentive to keep your use of AI inefficient. Pharos has helped me radically reduce token usage while achieving better outcomes. This allows me to increase the efficiency of my AI spend, and reduce the amount of money I have to fork over every month.&lt;/li&gt;&#xA;&lt;li&gt;Model providers might not be so cynical to clamp down on transcripts today, but there&amp;rsquo;s no guarantee about tomorrow. A new release of Claude Code could easily wipe out the transcript directory on your Mac (replacing its functionality with a cloud-based alternative that they control). Back up your data while you can.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Think about it a different way: given you&amp;rsquo;re spending hundreds (or thousands) of dollars to access the results from LLMs, why are you not backing up (and getting the most value out of) the core thing you&amp;rsquo;re paying for?&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-downside-visibility&#34;&gt;The Downside: Visibility&lt;/h2&gt;&#xA;&lt;p&gt;The main downside of using Pharos is that it forces you to grapple with three very uncomfortable truths:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;You&amp;rsquo;ve wasted huge volumes of usage on stupid stuff or silly bugs (I had accidentally launched a 2k agent swarm once with the wrong permissions that blew through a billion tokens)&lt;/li&gt;&#xA;&lt;li&gt;If you&amp;rsquo;re like me, your AI use has quickly eclipsed all of your other forms of CO2 (Pharos comes with a CO2 estimate - it&amp;rsquo;s rough)&lt;/li&gt;&#xA;&lt;li&gt;My usage would be unaffordable at API-level pricing. At API list prices (which Pharos helps you keep up to date), Pharos estimates my usage would have cost more than $150k.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;im-sold-how-do-i-use-it&#34;&gt;I&amp;rsquo;m sold, how do I use it?&lt;/h2&gt;&#xA;&lt;p&gt;Download the Mac app &lt;a href=&#34;https://github.com/gbdubs/alexandria&#34;&gt;here&lt;/a&gt; - it&amp;rsquo;s free, and you can audit its dependencies - it has essentially no non-standard deps.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;LLM transcripts are the ultimate proprietary data set - get the most out of yours.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h1 id=&#34;appendix-screenshotsworkflow&#34;&gt;Appendix: Screenshots/Workflow&lt;/h1&gt;&#xA;&lt;h2 id=&#34;1---choose-your-sources&#34;&gt;1 - Choose your sources&lt;/h2&gt;&#xA;&lt;p&gt;The first time you open Pharos, it checks the places where Claude Code, Codex, and other AI harnesses store transcripts.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-new-mac.png&#34; alt=&#34;The &amp;ldquo;New Mac detected&amp;rdquo; panel listing Claude Code, Codex, and Conductor sources with session counts, sizes, and date ranges&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;2---capture&#34;&gt;2 - Capture&lt;/h2&gt;&#xA;&lt;p&gt;Pharos copies conversation files, unparsed, into the library. This takes seconds to minutes, making it easy to plug in an SSD and quickly extract content.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-capture.png&#34; alt=&#34;Capture progress per source: claude captured, codex copying, conductor waiting&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;3---index-on-any-mac&#34;&gt;3 - Index, on any Mac&lt;/h2&gt;&#xA;&lt;p&gt;Captured files are indexed into a searchable catalog in a secondary step, which can be programmed to happen overnight. Indexing can happen later, on any Mac. Indexing from scratch can take hours, but incremental indexing is typically under a minute - I have it run every 30m.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-macs-and-captures.png&#34; alt=&#34;Macs and captures: this MacBook Air&amp;rsquo;s sources need indexing, while a Mac Studio&amp;rsquo;s are indexed&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;4---find-past-work&#34;&gt;4 - Find past work&lt;/h2&gt;&#xA;&lt;p&gt;The Library tab offers the ability to search by regex, trigram, vector, or use a combination of boolean and/or logic to find just the conversations you want to.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-library.png&#34; alt=&#34;Filterable table of conversation results&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;5---read-a-conversation&#34;&gt;5 - Read a conversation&lt;/h2&gt;&#xA;&lt;p&gt;The conversation view: prompts, responses, and every agent action in between, marked with the token additions to context. The scrollbar on the right tracks context size across the whole conversation, and clicking it jumps to that point.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-conversation.png&#34; alt=&#34;A conversation in Pharos&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;6---see-where-the-tokens-go&#34;&gt;6 - See where the tokens go&lt;/h2&gt;&#xA;&lt;p&gt;We&amp;rsquo;ve all wondered: how many tokens have I used, and how much would that have cost? Now you can know.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-usage.png&#34; alt=&#34;The Usage tab&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;7---count-the-words-you-actually-typed&#34;&gt;7 - Count the words you actually typed&lt;/h2&gt;&#xA;&lt;p&gt;But how much are you actually typing? How much thought are you adding to the conversation? I love this tab.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-human-words.png&#34; alt=&#34;Human Word counts - where does text come from&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;8---audit-tool-calls&#34;&gt;8 - Audit tool calls&lt;/h2&gt;&#xA;&lt;p&gt;Tool calls are a rich dataset in which you can see patterns of usage, find evidence of exfiltration, and debug frequently failing tool calls.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-tools.png&#34; alt=&#34;The Tools tab&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;9---unplug-safely&#34;&gt;9 - Unplug safely&lt;/h2&gt;&#xA;&lt;p&gt;Because Pharos runs (best) on an external SSD, it helps you understand when ejecting is safe and can manage ejects for you.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-drive-panel.png&#34; alt=&#34;The eject warning panel&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;10---carbon-accounting&#34;&gt;10 - Carbon accounting&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/pharos-carbon-impact.png&#34; alt=&#34;The Carbon Impact tab showing estimated all-time emissions of 1.38 t CO₂e&#34;&gt;&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Cheap Skinny Ports</title>
      <link>https://grady.dev/projects/ports/</link>
      <guid isPermaLink="true">https://grady.dev/projects/ports/</guid>
      <pubDate>Sun, 13 Sep 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>tools</category>
      <category>websites</category>
      <description>Customize software to meet your needs</description>
      <content:encoded>&lt;p&gt;I’m building software &lt;a href=&#34;https://xplo.pythia.software&#34;&gt;to emulate Excel’s calculation engine&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;From the beginning, I knew this would require an enormous volume of test cases - authoritative pairs of workbooks and cell values (inputs), and the values calculated by Excel for each (outputs). To capture these, I created a “harness” for Excel on windows - you hand it an XLSX file, and it produces a test case in the format that anchors my Excel-emulating calculation engine.&lt;/p&gt;&#xA;&lt;p&gt;The immediate problem I ran into was throughput. I needed to generate many test cases, but each step was monstrously slow: opening an excel spreadsheet in Windows, mutating some of its values through python libraries, saving it, and then parsing relevant features from the resulting file (Excel stores the calculated cell values in the saved XLSX file format). With off-the-shelf libraries, it took longer to run the harness infrastructure than it took to open the Excel spreadsheet and do the calculation. I was giving away over half of the computational energy to overhead - CPU cycles that then couldn’t be spent on the actual Excel calculations I was interested in.&lt;/p&gt;&#xA;&lt;p&gt;Though I made a variety of algorithmic improvements to improve multiprocessing and reduce COM contention, the largest dent I made in processing time (reducing the overhead time from over a minute to under 100ms) was through what I’m calling “Skinny Ports”.&lt;/p&gt;&#xA;&lt;p&gt;First some definitions: a “clone” of a library is when you make a copy of the library and adapt it for your purposes, a “port” is similar, but the copy is often written in a different language than the original, while preserving its core logic. Porting and cloning code is now simple because AI systems make both creating and verifying a port relatively straightforward, and reduce the burden of managing clones. A “skinny port” is a port where the goal of the port is not comprehensive coverage/equivalence, but a port with the ambition of serving only a small set of needs, and doing it well. In my calculation engine, I’ve made about seven “skinny ports” and “skinny clones” of other libraries, and through them have radically improved the performance at multiple layers.&lt;/p&gt;&#xA;&lt;p&gt;To make this concrete, I’ll tell you a bit about my experience of porting &lt;a href=&#34;https://openpyxl.readthedocs.io/en/stable/&#34;&gt;openpyxl&lt;/a&gt;. Openpyxl is a library in Python that encodes how to read and write Excel file formats, like XLSX. This might sound simple, but these file formats are intricate and nuanced. The team behind openpyxl has (over the course of 15+ years) found all of the little bugs and quirks of the format. Thus, rather than implementing this from scratch, in the first version of my harness, I used openpyxl to capture the results of an Excel file once saved, since the saved version caches the computed formula values. This worked, but it was painfully slow, and I quickly realized that to produce the volume of cases I wanted to, I needed something faster. After testing out a few openpyxl competitors in other languages, I found each to have clear gaps in functionality that would prevent their adoption, so I decided to port openpyxl to Go (because the rest of my harness code is also in Go). I asked a sophisticated AI agent to make the port, which it did in short order, after we co-designed and built a harness for testing equivalency between the original openpyxl code and the ported Go code. This port consumed many tokens, but very little energy from me.&lt;/p&gt;&#xA;&lt;p&gt;Out of the box, the Go port was more than 100x faster than its python equivalent, and with some fine tuning/performance tweaks, that number went far above 1000x. Though the speed is an obvious advantage, and the reason I started the port, the flexibility I got from owning my dependencies in this way turned out to be dramatically more valuable than the speed alone:&lt;/p&gt;&#xA;&lt;h2 id=&#34;1-personalized-interfaces&#34;&gt;1. Personalized Interfaces&lt;/h2&gt;&#xA;&lt;p&gt;A general purpose library has to design its interfaces for a broad range of consumers, and it has to balance speed, simplicity, and comprehensiveness. A personalized port allows you to fine tune the interfaces for your specific use cases.&lt;/p&gt;&#xA;&lt;p&gt;For example, in my openpyxl port, I ended up creating a set of streaming APIs to allow lower RAM usage over large spreadsheets, something that the python library didn’t implement.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2-language-unification&#34;&gt;2. Language Unification&lt;/h2&gt;&#xA;&lt;p&gt;To move fast, you often want to farm out complicated logic to well established libraries. However, it’s often the case that the best libraries for A and B and C are in different languages. Ports allow you to port each of your dependent libraries into the language you want to work in, often achieving type safety and simplifying the call structure.&lt;/p&gt;&#xA;&lt;p&gt;For example, in my first version of the Excel harness, I had a smorgasbord of libraries and processes and binaries that were all trying to talk to each other. It worked, but it was a nightmare to reason about, and context about failures was spread across multiple different tools. By unifying them into a single binary, in a single language, I was able to get unified error reporting, and eliminate a wide array of expensive (and slow) cross-process communication.&lt;/p&gt;&#xA;&lt;h2 id=&#34;3-personalized-optimization&#34;&gt;3. Personalized Optimization&lt;/h2&gt;&#xA;&lt;p&gt;Porting a library from a slower language to a faster one will often provide significant performance benefits, even if all of the logic is equivalent. But the bigger opportunity is that once ported, you’re able to push on optimizing the performance of the ported library to suit the specifics of your use - something that the maintainer of a generic library with many constituent users can’t prioritize&lt;/p&gt;&#xA;&lt;p&gt;For example, the python version of openpyxl did a bunch of processing on first ‘opening’ an excel file that wasn’t necessary in many of the cases I care about. By porting it, I got to refactor that code so that it only does the computation it strictly needs to to accomplish the aims I have.&lt;/p&gt;&#xA;&lt;h2 id=&#34;4-supply-chain-derisking&#34;&gt;4. Supply Chain Derisking&lt;/h2&gt;&#xA;&lt;p&gt;Reliance on open source libraries is a double edged sword. On the one hand, you get the benefit of reusing someone’s intellectual labor. On the other, you have to trust that the author(s) have not embedded anything malicious in their code, and trust that they will not do so in the future. A one-time port is a layer at which you can validate the security of the code, and remove dependencies and behavior that is riskier or broader than you want to maintain.&lt;/p&gt;&#xA;&lt;p&gt;For example, in the openpyxl port, I was able to prune out certain dependencies, like Pillow, because I didn’t require the image functionality that Pillow enables within openpyxl.&lt;/p&gt;&#xA;&lt;h2 id=&#34;implications&#34;&gt;Implications&lt;/h2&gt;&#xA;&lt;p&gt;I think this approach is a really robust one from a development perspective, but I worry about what it means for the future of the open source community. Open source is a massive common good, and dynamics that make it cheaper than ever to copy and modify reduce much of the incentive to be a good steward of it.&lt;/p&gt;&#xA;&lt;p&gt;To that end, I made two decisions about how to handle my ports to balance this newfound capability with the ethos that makes it possible.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;First, when I find bugs or functionality missing from openpyxl, in addition to implementing it in my port, I’m going to offer the changes upstream into the original Python repo.&lt;/li&gt;&#xA;&lt;li&gt;Second, I decided not to publish my port, since I think having a faster equivalent might draw attention away from the more carefully maintained, higher quality project (openpyxl).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content:encoded>
    </item><item>
      <title>AmDo: Automating Ambrook</title>
      <link>https://grady.dev/projects/amdo/</link>
      <guid isPermaLink="true">https://grady.dev/projects/amdo/</guid>
      <pubDate>Sun, 13 Sep 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>brainstorm</category>
      <category>tools</category>
      <description>Reusable human-in-the-loop automation strategy for any web app</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;This is a copy of a blog post I wrote for Ambrook, a company I worked for at the time. I think its core lessons are good ones for anyone thinking about ethical and safe automation.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;TL;DR: Our agentic system for modifying customer data: (a) prompt an AI that has broad access to read-only tools, and have it draft a plan of how to change their books (b) review the pl plans in a comprehensible UI (c) execute the plans deterministically. This approach scales human judgement rather than replacing it, and is flexible to automations of every shape.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-problem&#34;&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/h2&gt;&#xA;&lt;p&gt;After watching Haley click a new sequence of buttons for 8 opp, I knew we could do better. Haley is one of our (fabulous) Account Managers, and she was helping a customer with yet another (not so-fabulous) Loan Statement. She would create an account to track the loan, create a transaction for each payment on the loan statement for the same amount, and finally itemize each transaction using the loan statement PDF to figure out the percentage of each payment on the loan that should be tagged as principal or interest. Each of these operations was several clicks. It was painful to watch, and I’m sure even more painful to do.&lt;/p&gt;&#xA;&lt;p&gt;In the weeks before, Haley and I had spent lots of time together as I tried to understand and accelerate her work as an Account Manager for Ambrook’s customers. Much of the day-to-day work of an Account Manager (AM) consists of helping customers by clicking around the product: setting up their account to reflect their farm operation, and helping them with some basic bookkeeping. Over the prior weeks, shadowing Haley and other AMs had been fruitful. I’d see a pattern of clicks that was inefficient or annoying and try to build automation to make it easier or obviate it. Working hand-in-hand like this, the AMs and I had reworked the authorization model, built many small product shortcuts, and eliminated a class of thorny bugs. Even though each optimization felt like progress, it increasingly felt like we were missing the forest for the trees. At the end of the day, AMs were still spending lots of time in the app, clicking buttons.&lt;/p&gt;&#xA;&lt;p&gt;The core challenge was how heterogenous an Account Manager’s job can be:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;One customer might need Haley’s help itemizing loan statements by interest and principal amounts.&lt;/li&gt;&#xA;&lt;li&gt;Another might need help selectively changing the categorization of a set of transactions.&lt;/li&gt;&#xA;&lt;li&gt;A third might need check memos transcribed from a PDF of a bank statement, and applied to their relevant check.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In each instance, the actual work the AM performs for the customer is fairly mechanical, something that could be automated, but the range of tasks varies enough that automating all of it by creating new workflows or buttons wasn’t tractable. We’d toyed around with using LLMs for part of this job, connecting them to demo MCP servers, and found that they were too frequently wrong to be deployed in these accounting workflows where being exactly correct matters.&lt;/p&gt;&#xA;&lt;p&gt;I spent a week noodling on this problem, and eventually prototyped and productionized a generic solution: PlanBrook and AmDo. In the last few months it has quietly revolutionized not only how AMs do their work, but what we can achieve for our customers, and it presents a hopeful vision for how AI might revolutionize work while centering and scaling human judgement .&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-solution&#34;&gt;&lt;strong&gt;The Solution&lt;/strong&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The core insight was thinking about why we engineers are so comfortable using coding agents extensively. Most of us use them to debug, to summarize, to propose changes, and even to do a first pass of code review - but we still recognize that AI is too often wrong to let it merge without human review. The layer of human review at code submission time is the fence that separates a low consequence playground and the high consequence factory. Account Managers needed a version of “code review”: they needed a step in the process where they could see what was being proposed by the LLM, and carefully consider whether it was good enough to execute.&lt;/p&gt;&#xA;&lt;p&gt;Thus, we built this system with two halves: “PlanBrook” and “AmDo”, separated by a human in the loop:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;PlanBrook&lt;/strong&gt; is a planning agent based on Claude Code - one that has broad access to data in a read-only mode. This means it can search the codebase, Linear, a given customer’s data, and could even take in files like documents our customers submit to us. However, it doesn’t have any access to change any of that data. Our AMs have freeflowing conversations with PlanBrook - they provide it with instructions, meeting recordings, files, and context about the customer’s data setup. It uses its tools (including OCR, python scripts, SQL queries, and bash) to construct a “plan document” - a giant chunk of JSON that describes changes to be made on Ambrook. The AM and agent can go back and forth, repeatedly honing the plan.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;AmDo&lt;/strong&gt; is PlanBrook’s trustworthy sidekick. It is a deterministic piece of code that lives as a page in our frontend. It takes in PlanBrook’s JSON blob, and gives the human agent a comprehensive and clear review interface that lets them quickly understand the plan and interrogate its details. The plan is always easy to understand through the UI, even if it is big, or includes many nested or looped steps (more on that later). Beyond the review interface, AmDo’s other job is executing the plan that the user selects or approves, using the user’s credentials. Since this happens in the browser, on the user’s computer, this is all just straightforward API calls to our server using existing endpoints, with standard authorization (and thus, access controls).&lt;/p&gt;&#xA;&lt;p&gt;I like to think of these two systems as Don Quixote (PlanBrook) and Sancho Panza (AmDo). PlanBrook is an inventive, flexible, and courageous explorer, unconstrained by consequence. AmDo is a trustworthy rate-limiter: informed, careful, and prudent.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-data-model-for-anything&#34;&gt;&lt;strong&gt;A data model for anything&lt;/strong&gt;&lt;/h2&gt;&#xA;&lt;p&gt;The core challenge of this project was building the data model (and corresponding review interface) to represent the variety of plans we wanted to support, and the user interface to allow an Account Manager to understand what would happen at each step. This required solving a variety of small problems:&lt;/p&gt;&#xA;&lt;h3 id=&#34;operation-set&#34;&gt;&lt;strong&gt;Operation Set&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The plan schema needed a registry of operations that could constitute individual steps. To achieve this we turned to our Frontend-to-backend API, GraphQL, and added some lightweight scaffolding to expose the mutations in that schema to PlanBrook. This scaffolding handled things like:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;hiding methods that should never be used,&lt;/li&gt;&#xA;&lt;li&gt;renaming methods to use more commonplace terms,&lt;/li&gt;&#xA;&lt;li&gt;adding hints about how each API should be called in brief documentation,&lt;/li&gt;&#xA;&lt;li&gt;winnowing the input arguments to the set that are most commonly needed&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Each of these optimizations was found by looking at the stumbling blocks models ran into when interacting with our large and sedimentary GraphQL schema. The end result is that adding a new GQL mutation to this set just takes a line of configuration, and can be tweaked when agents get confused.&lt;/p&gt;&#xA;&lt;h3 id=&#34;loops-and-data&#34;&gt;&lt;strong&gt;Loops and Data&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;p&gt;PlanBrook and AmDo are only needed when AMs need to do large volumes of operations - if it’s just a few clicks, it’s still faster for them to do it in the App. To express this, we turned to loops and data sets - plans can include named tables that have columns and rows, and then have blocks in the plan that say “for each row in this table”. As an example, PlanBrook might use OCR to extract out the check numbers and memo lines from a PDF of a checking account statement, and then include in the plan both the data table that was extracted (column of Memo and Check Number), and then run an loop over an operation to set the memo for each check.&lt;/p&gt;&#xA;&lt;h3 id=&#34;dependency-and-reference&#34;&gt;&lt;strong&gt;Dependency and Reference&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;p&gt;If an AM specifies that first an invoice should be created, then it should be itemized, PlanBrook needs to describe (in a single plan document) how that second step relies on knowing the existence of the previous step (in order to know the ID that should be sent in the itemization request).&lt;/p&gt;&#xA;&lt;p&gt;When this is only two steps, it seems straightforward, but we also have concrete use cases where dependencies are 1:N (i.e. create a single invoice and match it to multiple payments) and N:1 (i.e. create multiple transactions, then use a single batch tagging operation to update them).&lt;/p&gt;&#xA;&lt;p&gt;Building this graph structure required careful tinkering with not only what was theoretically supportable, but what kinds of JSON agents could reliably produce. We found that data models that were too abstract took many more tokens for the agent to construct, and more frequently suffered from hallucinations.&lt;/p&gt;&#xA;&lt;h3 id=&#34;intentional-omissions&#34;&gt;&lt;strong&gt;Intentional Omissions&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;p&gt;Even as important as what you build is what you intentionally choose not to build. We decided that in order for plans to be fully comprehensible they needed to be repeatable and deterministic, and so we fully skipped conditionality - the ability for a plan to specify a condition and two branches to take based on the evaluation of that condition. We first thought we would need conditionality to support the common “upsert” scenario, where the AM asks PlanBrook “to create or update the transaction”. We ended up finding we could work around this need by ensuring that PlanBrook had access to an internal Ambrook MCP that gives live read-access to the customer’s data. This allowed the planning agent to act conditionally to create plans that are based on the state of the data, rather than encoding that uncertainty into the plan.&lt;/p&gt;&#xA;&lt;p&gt;This keeps our plans fully deterministic, and highly comprehensible to the AM reviewing them. For the same reason, we opted not to build in Lookups or Error Recovery. Making sure the human reviewer has confidence in what will happen when they press “Run Plan” is invaluable.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-impact&#34;&gt;&lt;strong&gt;The Impact&lt;/strong&gt;&lt;/h2&gt;&#xA;&lt;p&gt;AmDo has been launched for a few months, and we recently added logging to understand usage trends. For the five weeks we have data:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Each week it performs 4k+ operations (each operation would have required someone to navigate to a page and click a button in the app)&lt;/li&gt;&#xA;&lt;li&gt;Every member of our Account Management team has used it at least once a week for the last five weeks (after vacations are taken into account)&lt;/li&gt;&#xA;&lt;li&gt;11 team-members not on our AM team have used it more than once.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The numbers don’t capture the quality of life improvement - our AMs work so hard, and making their lives better has been sincerely rewarding. Some slack quotes that made me smile:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;“It helped me clean up convoluted COA and P&amp;amp;L in like half the time!”&lt;/li&gt;&#xA;&lt;li&gt;“This will save &lt;em&gt;days&lt;/em&gt; of time for our customers!”&lt;/li&gt;&#xA;&lt;li&gt;&amp;ldquo;Consider it AmDONE!&amp;rdquo;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The things our AMs love about PlanBrook isn’t just the automation, it’s the way it allows them to “spend less time squinting” at their screen. With agents, AMs can trust that Claude will figure out the rote pieces of updating books. They can spend more time thinking about what they’re doing, and less time just trying to double check that the buttons they pressed were the right ones.&lt;/p&gt;&#xA;&lt;p&gt;AmDo has become a primitive that we’re composing into more and more workflows - human and agentic. Several tasks that used to consume hours of AM time (including the original example, of itemizing loan statements by principal and interest) have now been turned into standalone Claude Skills, which ensure the creation of the AmDo plan for them. We’re planning on prototyping a version of AmDo to bring to users - so that they might have plain-text conversations with an agent to keep up with their books.&lt;/p&gt;&#xA;&lt;p&gt;This process hasn’t been all roses - AMs often end up having to go back and forth with PlanBrook 2+ times in order to get to the plan that they want. Sometimes that’s due to a lack of specificity in the instructions, but more often than not, AMs have to correct misunderstandings the Agent makes about the scope of what it was tasked with, or even basic accounting concepts that the AM is fluent in but the agent isn’t even aware of.&lt;/p&gt;&#xA;&lt;p&gt;While we’re working to make those kinds of misunderstandings less common through improved context engineering, this problem isn’t one we expect to be able to fully solve any time soon. Even though our AMs are fluent in this tool, and true experts in both the software and accounting, LLMs routinely misunderstand their directions. There’s a lesson in that.&lt;/p&gt;&#xA;&lt;h2 id=&#34;generalizable-lessons&#34;&gt;&lt;strong&gt;Generalizable Lessons&lt;/strong&gt;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;design-scaffolds-weaknesses&#34;&gt;&lt;strong&gt;Design Scaffolds Weaknesses&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;p&gt;The lesson I pull out of this work is that when we’re building human-in-the-loop systems, we should design each phase to amplify the strengths of the actor, and scaffold/minimize their weaknesses.&lt;/p&gt;&#xA;&lt;p&gt;In the planning phase, the actor is an LLM, and they can be tireless, diligent, and have almost any data thrown at them and make sense of it. However, they’re prone to hallucination, bad at math, susceptible prompt injection, and limited context routinely holds them back. The environment we built for this agent thus has access to tools that help it learn, get detailed context, do math, and have firewalls to ensure it can’t access the outside internet.&lt;/p&gt;&#xA;&lt;p&gt;In the review phase, the actor is one of our AMs, and they are brilliant experts in both their customer’s operation, books, and Ambrook. However, they have limited attentional capacity to review plans, so we built the review interface so that it can help them quickly sample the data and confirm the operations that will take place, then see the results when they run.&lt;/p&gt;&#xA;&lt;p&gt;By building software that helps us augment the strengths (and accommodate the weaknesses) of each part of the system, we’re getting more out of AI and helping our team do more.&lt;/p&gt;&#xA;&lt;h3 id=&#34;augment-dont-replace&#34;&gt;&lt;strong&gt;Augment, don’t Replace&lt;/strong&gt;&lt;/h3&gt;&#xA;&lt;p&gt;My experience with AI (including Planbrook and AmDo) has made me bullish on strategies for AI that aim for “scaled judgement” rather than “full automation”. This is a humanizing way to think about AI at work, because it appropriately recognizes the components of intellectual labor that aren’t captured by keystrokes and clicks.&lt;/p&gt;&#xA;&lt;p&gt;The AMs that I’ve gotten to work with on our team (shoutout Aryn, Haley, Shannon, Taylor, and many others) are brilliant and kind people with deep experience. Many have worked in bookkeeping, many have run or live on a farm. The reason our customers like working with them isn’t because they can click around a website for them - it’s because they bring understanding and empathy with them when they jump in to help. Our full service program can’t be replaced by a setup wizard, because the conversation about what makes sense for each business is a fractal. Beyond experience, working with our AMs is better than working with a machine because it gives  our customers someone they know and trust, a real relationship that provides some folks with accountability, others with encouragement to try something new, and still others with partnership in thinking about their business.&lt;/p&gt;&#xA;&lt;p&gt;I’m proud that PlanBrook and AmDo allow these brilliant folks to spend more time with their customers. This experience has convinced me that some of the best use cases for AI will be the ones that help brilliant folks get more done, at a higher quality, rather than ones that try to distill their expertise into a button or a text box. Full automation is only possible when your objectives are unitary and easily described. Few problems in our complex world have that shape.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Practical tips to avoid Agentic Cheating</title>
      <link>https://grady.dev/projects/agentic-cheating/</link>
      <guid isPermaLink="true">https://grady.dev/projects/agentic-cheating/</guid>
      <pubDate>Wed, 02 Sep 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>brainstorm</category>
      <description>Why LLMs misbehave and how to stop them</description>
      <content:encoded>&lt;p&gt;For the last ~8 months &lt;a href=&#34;https://xplo.pythia.software&#34;&gt;I’ve been building an “Engine” to replicate (bit-for-bit) the calculation logic of Microsoft Excel&lt;/a&gt;. Since this problem has a ground truth (what Excel computes as outputs for a given set of inputs), the problem lends itself to automation - agents can generate workbooks, diff the Engine behavior against Excel, and then “Fix Agents” can propose changes to the Engine code to bring it closer to alignment with Excel (learn more about how I’m building that here). When I originally allowed Fix Agents to submit their code changes without my review, they cheated with enough frequency that I had to throw out broad swathes of the implementation, and at one point, had to start the core engine from scratch. After that, I review every PR, and whenever I find a cheating Fix Agent, I read through its transcript to figure out what happened, and then tweak my scaffolding and instructions to try to make it less likely.&lt;/p&gt;&#xA;&lt;p&gt;By “cheating”, I mean everything from hard-coding &lt;code&gt;if (input = valueUnderTest) { return ExpectedResult }&lt;/code&gt; (example below), to building API calls to run Excel within the Engine code, to much more subtle forms of cheating where the agent constructs rube-goldberg machines of massive complexity that solve exactly the set of cases they were presented with, but fail to generalize - essentially overfitting to the scenarios they are given.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/agentic-cheating.png&#34; alt=&#34;An example of agentic cheating where an agent hardcodes &amp;ldquo;if input is X return back Y&amp;rdquo; where both X and Y are arbitrary and only correspond to my test case, not any natural feature of the problem&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Reading the transcripts from agents that cheat is fascinating and fun - it helped me understand both why LLMs might cheat, and helped me imagine the ways I ended up scaffolding against those weaknesses. Over time, I’ve been able to ferret out most of the cheating behaviors with various forms of prompt engineering and process, which has been a pleasant surprise. Here are some generic tips.&lt;/p&gt;&#xA;&lt;h2 id=&#34;1---explicitly-allow-failure&#34;&gt;1 - Explicitly allow failure&lt;/h2&gt;&#xA;&lt;p&gt;Agents tend to cheat only after they have made many legitimate attempts at a problem, and appear (in their transcripts) to express frustration about the paucity of their tools or the impossibility of the task they’ve been given. I’ve found that if you give the agent, in its initial task instructions, the option to declare that the problem cannot be solved within reason, the Agent will often exercise that option rather than trying to cheat.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2---hold-out-all-evaluation-criteria&#34;&gt;2 - Hold out all evaluation criteria&lt;/h2&gt;&#xA;&lt;p&gt;When my systems find a difference between Excel’s calculation logic and my code, they automatically dispatch a Fix Agent to try to diagnose and fix it. Originally, I sent the full failing test case to the Fix Agent. This allowed the agent to overfit or cheat to meet the expected behavior of the failing case. To get around this, I built scaffolding which generates several thousand alternative cases of input/output values (through Excel), and gives the agent only about half of these in the prompt to fix. This serves two functions - it allows the agent to see many more cases for how a calculation with a given structure ought to behave, and it also detects cheating: when the agent says it is “done”, the proposed diff gets routed to my evaluation infrastructure which tests the proposed solution against the full set of cases. When an agent passes all of their cases and fails a significant number of the held out cases, it likely cheated in some way, and that gets flagged to me for review.&lt;/p&gt;&#xA;&lt;h2 id=&#34;3---cross-model-agentic-review&#34;&gt;3 - Cross model agentic review&lt;/h2&gt;&#xA;&lt;p&gt;Much has been written about how effective cross-model review is (including by me), so I’ll not spill more ink. However, for cheating specifically, there are two useful lessons. First, giving the Review Agent specific instructions on what the overarching goal of the project is and the specific context of what a “cheating” might look like allows them to spot cheating with much greater accuracy. Second, warning the Fix Agent that they’re going to be reviewed by another agent appears to induce compliance - if they know their work will be scrutinized, they seem less inclined to find shortcuts.&lt;/p&gt;&#xA;&lt;h2 id=&#34;4---intelligence-escalation-ladder&#34;&gt;4 - Intelligence Escalation Ladder&lt;/h2&gt;&#xA;&lt;p&gt;When one of the above steps fails, it can be an indication of cheating, but also could just be an incomplete or partial implementation, or an indication that the problem is too hard for that agent. In these cases I employ an “Intelligence Escalation Ladder”. When a Fix Agent fails to achieve a task (due to cheating, failing evaluations, a bad review, or it gives up), I have the Fix Agent write up a doc describing what it tried and where it left the work, and then I pass the task up to a more capable/intelligent/effortful model, including information about the Fix Agent’s path (but critically, not any of the cases/info about the anti-cheat, if that is what triggered the escalation). This approach works pretty well because the highest tier models are wildly capacious, and the headstart from a previous fixing session saves precious tokens that make using top-tier intelligence more cost efficient.&lt;/p&gt;&#xA;&lt;p&gt;All of these are bandaids. I am profoundly worried that if we are only able to solve alignment through bandaids, these will fail in important cases. I hope the AI labs throw all the resources they can at the fundamental challenge of alignment. But in the interim, we’re not rudderless - AI consistently falls into patterns of cheating that can be minimized by good scaffolding. It’s possible to make immense and reliable automations, despite the unreliability of the individual parts.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Agentic Scientific Publishing</title>
      <link>https://grady.dev/projects/agentic-perf/</link>
      <guid isPermaLink="true">https://grady.dev/projects/agentic-perf/</guid>
      <pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>algorithms</category>
      <description>LLM experimentation is turbocharged by writing things down</description>
      <content:encoded>&lt;p&gt;I’m building &lt;a href=&#34;https://xplo.pythia.software&#34;&gt;software to replicate the calculation logic of Microsoft Excel&lt;/a&gt;. My code involves many steps that were (originally) very time and resource intensive. However, over the last few months, I’ve found a reliable approach for semi-automated performance optimization that works across wall-time, RAM, CPU, and probably any quantifiable metric of performance.&lt;/p&gt;&#xA;&lt;p&gt;First some background: the unit of work for my code is a “case” - an Excel workbook and a series of mutations of the values in it, and a JSON file that describes the authoritative behavior of how Windows Excel responds to those series of mutations and calculations. Cases can cover a wide or narrow range of behavior - some are like integration tests, which evaluate large sets of functionality in concert, others are closer in construction to unit tests, evaluating all of the nuances of function behavior. When a case is evaluated, it results in many code-generation and compilation steps, each of which can have independent performance bottlenecks.&lt;/p&gt;&#xA;&lt;p&gt;After carefully instrumenting the code so that the resource usage and runtime of each step is evaluated, I set about working on automating performance optimization loops. In the first version of this automated process, I used basic queries to find the worst performing cases in my corpus and then used a standard prompt to ask an agent to:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Read through the case, then find and understand the functionality it exercises&lt;/li&gt;&#xA;&lt;li&gt;Use telemetry and code to understand why overall performance was so much worse on this case than others&lt;/li&gt;&#xA;&lt;li&gt;Come up with 3-5 different hypotheses on how performance might be improved while maintaining computational equivalence&lt;/li&gt;&#xA;&lt;li&gt;Test those hypotheses by implementing fixes/changes for each, and evaluating performance against baseline. Then, keep any positive changes&lt;/li&gt;&#xA;&lt;li&gt;Create a PR that gives me a clear high level understanding of what the changes were, why they are safe, what assumptions they made.&lt;/li&gt;&#xA;&lt;li&gt;Kick off a broad validation run to compare performance on other metrics across many other workbooks to ensure we don’t regress other kinds of performance.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Then, often many hours later, I would review the result. This process worked decently well, but many runs failed to make significant progress. When I dug into why by reading a bunch of transcripts, it was clear agents were often hitting the same dead ends, or making similar incorrect assumptions about what might work. Each agent was still moving the ball forward a bit in their session, but they weren’t benefiting from knowledge of the past attempts.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;What revolutionized this loop was a simple directive to  write down hypotheses and experimental results (positive and negative) as a persistent part of the repository.&lt;/strong&gt; This allowed subsequent agents, during hypothesis generation, to vet their proposed experiments against the outcomes of prior ones, allowing them to avoid known dead ends, share methods and harnesses, and exposed each agent to a set of ideas it hadn’t come up with but were aimed in the same direction.&lt;/p&gt;&#xA;&lt;p&gt;Writing things down completely revolutionized the performance optimization efforts. As one example, there is a very complex multi-megabyte spreadsheet that (at the beginning of my optimization efforts) I used as a benchmark because it could just barely compile using 90+ GB of RAM in about two hours. Today, its compilation uses under 8GB of ram, and takes just over one minute forty seconds. It went from barely being able to run on my Mac Studio to being able to run in an ephemeral cloud run function! Incredible.&lt;/p&gt;&#xA;&lt;p&gt;The big lesson for me here is that agents, like people, can learn from prior experience if they are given the chance to. Next time an agent of yours is spinning on an enormous, hard to solve problem, instead try to decompose that problem into incremental (and evaluable) experimental steps, and have each agent write down what it learned as it goes. Having 40 small sessions that try new things and report back is often preferable to having one gargantuan session to try many things.&lt;/p&gt;&#xA;&lt;p&gt;Agents, like humans, can achieve more when they publish the results of their experiments - positive and negative.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Why Defend the Frontier</title>
      <link>https://grady.dev/projects/frontier-outstrips-demand/</link>
      <guid isPermaLink="true">https://grady.dev/projects/frontier-outstrips-demand/</guid>
      <pubDate>Thu, 13 Aug 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>economics</category>
      <description>Frontier AI capabilities are beginning to outstrip the demand for them</description>
      <content:encoded>&lt;p&gt;I suspect we&amp;rsquo;re at or very close to the top of the bubble in AI valuation for frontier labs. The signal for that is simple: I don&amp;rsquo;t know anyone using Fable, despite everyone espousing its power.&lt;/p&gt;&#xA;&lt;p&gt;Much ink has already been spilled about the headwind that open-weight models will pose to frontier labs. The labs&amp;rsquo; response has always been simple: people will pay for the gap to get to the frontier, and being at the frontier will allow them to build stronger models at every point on the cost/performance curve.&lt;/p&gt;&#xA;&lt;p&gt;I bought this logic for a long time-every time I tried out open-weight models, I could still feel a performance gap between them and the closed-weight frontier. That gap kept me paying for (several) max plans. But in the last three months, my behavior has changed substantially. Not by switching to an open-weight model (Kimi K3 still lags behind what I need out of it), but because of how the cost/performance curve has shifted inside each of the frontier labs&amp;rsquo; offerings.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I mostly use Opus 4.8 instead of Opus 5 because it drains my quota less quickly, and I can&amp;rsquo;t see any gap in performance.&lt;/li&gt;&#xA;&lt;li&gt;I mostly use Terra on high because it performs simple tasks more quickly and cheaply than Sol.&lt;/li&gt;&#xA;&lt;li&gt;I think Fable is incredible, but I only use it on the tasks that need it, and even then only overnight and if I have some slack in my weekly quotas.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In short, AI labs now build budget products that are (mostly) capable of the tasks I need done, so I reach for the true frontier less and less often. Now, I&amp;rsquo;m just a humble SWE—perhaps it will take a year or two for the best security engineers or Terence Tao to feel similarly. But in my job—complex systems engineering—AI capabilities now outstrip my demand for them, and I don&amp;rsquo;t see why that would not be (eventually) true in other fields.&lt;/p&gt;&#xA;&lt;p&gt;Now I want to draw a critical distinction - &lt;a href=&#34;https://grady.dev/projects/iceberg&#34;&gt;AI cannot do my job yet&lt;/a&gt;. I&amp;rsquo;d love to see someone try to replace me with AI - it would be hilarious to see the mess they get into: even Fable still routinely suggests terrible architectures and spins confidently on bogus assumptions. I&amp;rsquo;m not claiming AI can do my job, I&amp;rsquo;m claiming that AI can do a good enough job at most of the tasks I want AI to do in my job - debugging, drafting designs, reviewing PRs, and writing code - such that I don&amp;rsquo;t need to pay for the frontier (in quota, but the logic holds for dollars).&lt;/p&gt;&#xA;&lt;p&gt;Don&amp;rsquo;t take my word for it: ask your most AI-pilled friends. Does anyone use Fable frequently? Does anyone find the 1.5x cost of Opus 5 vs. 4.8 worth it?&lt;/p&gt;&#xA;&lt;p&gt;If the frontier moves out of reach from human necessity, the frontier could still be defensible, but it will make no economic sense to defend it.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Age Based Congressional Districts</title>
      <link>https://grady.dev/projects/gerry/</link>
      <guid isPermaLink="true">https://grady.dev/projects/gerry/</guid>
      <pubDate>Sat, 30 May 2026 09:37:38 -0600</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>government</category>
      <category>brainstorm</category>
      <description>Fixing gerrymandering and gerontocracy</description>
      <content:encoded>&lt;p&gt;&lt;strong&gt;Federal congressional districts should be set based on age, not geography.&lt;/strong&gt; The idea is simple: take the birthdays of all eligible voters in a state, order them, and set boundary lines between districts so that each district has the same number of voters. When you go to the polls you would show your ID and have your birthday determine your ballot. Only one other rule: a candidate would not have to be from within an age bracket to run to represent it.&lt;/p&gt;&#xA;&lt;p&gt;This system has many advantages beyond breaking the Gerrymandering doom-loop:&lt;/p&gt;&#xA;&lt;h2 id=&#34;leaders-from-multiple-generations&#34;&gt;Leaders from Multiple Generations&lt;/h2&gt;&#xA;&lt;p&gt;Today, geographically defined districts bolster our ossified gerontocracy, because the wealthiest folks within every district wield the connections, power, and funding to sway its elections, and thus or politics is overly sensitive to the concerns of this group. Age based districts would force parties and candidates to appeal to multiple generations, and would likely elevate a congress that is much younger, less wealthy, and more diverse.&lt;/p&gt;&#xA;&lt;h2 id=&#34;different-generations-different-concerns&#34;&gt;Different Generations, Different Concerns&lt;/h2&gt;&#xA;&lt;p&gt;&lt;strong&gt;We have far more in common with people of our age than we do with people of our region.&lt;/strong&gt; Pocketbook interests cluster by age cohort - whether it&amp;rsquo;s social security or AI in the labor market - the most potent concerns have age-based constituencies that are today dispersed across districts, without cogent representation (you could even call this &amp;ldquo;cracking&amp;rdquo; of the youth vote in gerrymandering terms… all districting is a choice!). Furthermore, districts exist as a concept to allow for people to have representation for common interests (historically, agricultural and manufacturing, etc). Yet, age tends to be a better predictor than geography when it comes to a wide range of issues (including foreign conflict, climate change, tax policy, social mores, and public benefit structures), issues that have not seen serious public engagement or debate &lt;em&gt;in large part because the constituencies are dispersed.&lt;/em&gt; A politics that has to build cohorts across generations would be a politics that has to grapple with the preferences of people under 40, which today, I think you could argue are largely absent from national politics.&lt;/p&gt;&#xA;&lt;h2 id=&#34;congress-of-leaders-not-of-parties&#34;&gt;Congress of leaders, not of Parties&lt;/h2&gt;&#xA;&lt;p&gt;Many &amp;lsquo;solutions&amp;rsquo; to gerrymandering give more control to parties - encouraging party loyalty and diminishing the personal element of elections. I like personal politics - it brings forward leaders that inspire and ignite us - sometimes through virtue, sometimes through bombast. A congress even more tightly run by parties will weaken the institution, turning a proving ground for our leaders into an organ that only serves parties and their interests. A congress full of intergenerational strivers, personally motivated and branded, is a far more engaging and discursive vision of politics, and is actually much closer to what our founders intended.&lt;/p&gt;&#xA;&lt;h2 id=&#34;unimpeachable&#34;&gt;Unimpeachable&lt;/h2&gt;&#xA;&lt;p&gt;Any approach to districting that relies on discretion by politicians can be gamed. Even in proportional representation and various RCV proposals, there are core elements these plans that rely on the same act of drawing lines on maps, and that leaves the door open for manipulation. The brilliance of age based districting is that it is non-discretionary.&lt;/p&gt;&#xA;&lt;p&gt;Isn&amp;rsquo;t that a great idea? Wouldn&amp;rsquo;t that be a better world?&lt;/p&gt;&#xA;&lt;p&gt;How can we make it so?&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>The Iceberg of Work</title>
      <link>https://grady.dev/projects/iceberg/</link>
      <guid isPermaLink="true">https://grady.dev/projects/iceberg/</guid>
      <pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>writing</category>
      <category>ai</category>
      <category>labor</category>
      <description>A job is more than meets the eye - assume otherwise at your own peril</description>
      <content:encoded>&lt;h2 id=&#34;thesis&#34;&gt;Thesis&lt;/h2&gt;&#xA;&lt;p&gt;Proximity is a fantastic heuristic for authority. The trust you should have in someone&amp;rsquo;s opinion should generally be proportional to how well they understand the idea or problem they are engaging with. &lt;strong&gt;This is why I&amp;rsquo;m optimistic about how AI will reshape white-collar work.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve noticed that people tend to think AI will displace their coworkers but not themselves. This is because our interface to our teammates and their work is mediated through mechanical signals - pixels and keystrokes - but our understanding of our own work is far richer than what we express through those physical inputs and outputs. I&amp;rsquo;m a software engineer, and my work is experienced by others as chat messages and code changes, but the quality and importance of these isn&amp;rsquo;t the text itself. A coworker that sees my work as interchangable with text generation is demonstrating they do not understand my job. It would be silly to see this iceberg (the hidden mass that supports the whole) within my own work and fail to assume it about the work of others. Extrapolating from that principle:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;When I find myself thinking of fully replacing a human function with a machine to emulate it, I try to think through what pieces of that job aren&amp;rsquo;t encoded in inputs and outputs. Judgement, discretion, knowing when to break rules, etc.&lt;/li&gt;&#xA;&lt;li&gt;There are piece of my job I do think are automatable, and I&amp;rsquo;m sure this is true for others too. I deeply trust a laborer&amp;rsquo;s instincts about what pieces of their job could be automated, and which cannot.&lt;/li&gt;&#xA;&lt;li&gt;Companies should be optimistic about bottoms-up automations, and should be skeptical of top-down automation initiatives.&lt;/li&gt;&#xA;&lt;li&gt;While AI will make individuals in every field more efficient, I won&amp;rsquo;t worry about wholesale replacement of a field by AI until I hear the experts - the people who do that job - express that forecast.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;It would be idiotic of me to look at what a CEO does as text generation, yet many of them seem to see the rest of us as input-output text generation cost centers. I marvel at the arrogance it takes to assert &amp;ldquo;AI can replace this job&amp;rdquo; without having ever done that job.&lt;/p&gt;&#xA;&lt;h2 id=&#34;my-experience&#34;&gt;My Experience&lt;/h2&gt;&#xA;&lt;p&gt;I&amp;rsquo;m a software engineer. I use AI in unfathomable volumes and varieties - it makes me radically more effective. Through that use, I&amp;rsquo;ve started to see clearly the pieces of my job that I expect AI systems will not be able to replace, they fall into a few categories:&lt;/p&gt;&#xA;&lt;h3 id=&#34;judgement&#34;&gt;Judgement&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Our profession oscillates between identifying as engineers and hackers. Much of what differentiates a good SWE from a great one is fluidity between these poles. The best engineers know when to go with the quick hack and when to build it right. Folks that haven&amp;rsquo;t paid the price for bad choices (in both directions) rarely have that insight.&lt;/li&gt;&#xA;&lt;li&gt;Similarly, much of software engineering is about balancing between goods, not achieving some maximal outcome along one dimension. Most of the time this means balancing complexity against some other goal like velocity, consistency, performance, or simplicity. LLMs may be great at lifting a concrete implementation into an abstraction, or decomposing an abstraction to concrete implementation, but they rarely demonstrate the prudence to know when to do each.&lt;/li&gt;&#xA;&lt;li&gt;Some of the biggest pieces of impact in my career have been pushing back on our leadership when our current prioritization and approach may lead to technical problems in sequencing, timeline, or bitrot, and knowing how forcefully to make the push. AI systems are good at doing, they rarely display strategic reasoning in &lt;em&gt;what&lt;/em&gt; to do or &lt;em&gt;when&lt;/em&gt; to do it.&lt;/li&gt;&#xA;&lt;li&gt;Though my job is profoundly technical, it often involves aesthetics - amorphous senses of what makes a UI, an algorithm, or an API beautiful. These fleeting moments of inspiration often end up being profoundly impactful on the trajectory of our products and teams. This is an area I have yet to see LLMs express sound judgement in, in large part (I suspect) because most of us rarely have the vocabulary to express and explain our aesthetic preferences in the thin pipe of language.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;human-management&#34;&gt;Human Management&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I mentor our junior engineers, which both helps them become more effective over time, and lets me more deeply understand and revisit our infrastructure, and learn new things from them and the experiences they bring with them. AI makes for a great tutor, but it&amp;rsquo;s unidirectional, and can only answer the questions you know to ask.&lt;/li&gt;&#xA;&lt;li&gt;I temper the instincts of our PMs and designers, often translating their vision through the lens of technical feasibility and maintenance - &amp;ldquo;if we are OK with slightly different functionality, it will be 10x easier to maintain&amp;rdquo; is a series of tokens I regularly emit by vibrating air, but is hard for agents to do precisely because they&amp;rsquo;re optimized to achieve the task as the user has asked for it.&lt;/li&gt;&#xA;&lt;li&gt;I conduct interviews, and have developed intuitions for where candidates should be challenged, assisted, and how a candidate&amp;rsquo;s internal model of the problem evolves over time. The mirrored state of the candidate&amp;rsquo;s mind that lives within mine gives me a much more reliable signal about how someone will perform in a job than externally visible signals.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;context&#34;&gt;Context&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;While solving problems in the codebase and infrastructure, I accumulate whiffs of unrelated data - sometimes it&amp;rsquo;s a log that looks out of place, sometimes its a file that looks too big, or a test that takes longer to run than I expect. It&amp;rsquo;s rarely the right choice for me to dive head-first into solving or understanding these surprising tidbits, but their accumulation is at the heart of my ability to hear about a customer complaint or strange failure mode and quickly identify hypotheses about how it might have come to be. LLMs can solve any problem that is specifically stated, but they don&amp;rsquo;t do well to make connections between sparse signals that cannot all fit into a context window.&lt;/li&gt;&#xA;&lt;li&gt;If I had a dollar for every time an LLM tried to reverse an architectural decision (or bug fix), I&amp;rsquo;d go out to a really nice dinner - one of those ones where the food is tiny. LLMs can be reminded to check git history, they can be given detailed explanations and admonitions, they can have documentation of everything, but at the end of the day, LLM performance is trained against task execution, and the fastest way of accomplishing task X is often deleterious to the thousand other tasks and goals that came before it. I hold more context in my head about bugs that I have fixed than can fit into 1M tokens.&lt;/li&gt;&#xA;&lt;li&gt;The experience that has given me the best insight into our customers has been visiting them in person. Spending two days on a family ranch in South Dakota taught me more about the needs of ranchers than had months of prior reading. Experiencing the frustrations of a vegetable farmer as we watched her click through her invoicing flow in her wash facility in Vermont gave me more insights about how to change the product than had months of playing with the website in my office. Embodied and interpersonal experience is at the heart of figuring out what product should be built.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Note: in these problems of context there are technical ways you could imagine scaffolding an agentic workstream such that they can mimic or even surpass human skill on these kinds of tasks. While the other two categories I&amp;rsquo;m fairly confident are not going away, I do think AI will find ways of chipping away at these advantages.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-gap-is-terrifying&#34;&gt;The Gap is terrifying&lt;/h2&gt;&#xA;&lt;p&gt;The thing I fear is not AI capable of these parts of my job, it&amp;rsquo;s the delusion that these gaps don&amp;rsquo;t exist or matter.&lt;/p&gt;&#xA;&lt;p&gt;That delusion ends poorly for the workers, who face unemployment and systematic de-valuing of their labor and humanity. It ends poorly for the companies - who will eventually fail or pay enormous costs for shortsighted layoffs and automations. It ends poorly for our culture, which further reduces the vibrancy and value of human life and thought to its measurable constituents.&lt;/p&gt;&#xA;&lt;p&gt;I fear our society will steer for this iceberg because it looks so small.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Corporate Extinction</title>
      <link>https://grady.dev/projects/corp-extinction/</link>
      <guid isPermaLink="true">https://grady.dev/projects/corp-extinction/</guid>
      <pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>writing</category>
      <category>ai</category>
      <category>labor</category>
      <description>AI will be a mass extinction event, but not in the ways that Twitter would have you believe</description>
      <content:encoded>&lt;p&gt;In corporate archeology, AI will be a mass extinction event, but not in the ways that Twitter would have you believe. Sure, some companies will die from not taking AI seriously enough: some will be overtaken by nimbler AI-powered competitors, some will implode from cybersecurity breaches, others will lose their best talent to self-employment. But most companies that die in the next five years will die by suicide, not by murder.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Occupational Cosplay.&lt;/strong&gt; AI empowers us to roles that we are not familiar with, and creates the impression of efficacy. Using AI, the CEO can ship code, the coder can write marketing copy, and the marketer can write an investor email. In each case, the employee is using AI in a domain where they can&amp;rsquo;t evaluate the quality of what they&amp;rsquo;re producing, and as a result, assume they&amp;rsquo;re now capable of a job that they never really understood. To crystalize this, think about a metric: the percent of human time spent making decisions in one&amp;rsquo;s areas of expertise. In well run organizations, this number is high. AI tanks this metric because it allows employees to jump into jobs they don&amp;rsquo;t understand. Organizational disfunction and error will result.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Productivity Dysmorphia.&lt;/strong&gt; Healthy organizations have a strong understanding for how all activities tie back to business outcomes. When an organization goes all-in on AI, every incentive pulls employees toward building the project that will demo well, toward blind automations, toward the huge first draft, and the visible signs of AI progress, mistaking use of AI for concrete business value. Employees, management chains, corporations, and markets are all buying into a distorted sense for what building value looks like, substituting the excitement for deployment of AI for genuine progress toward business objectives. Consider three facts that are benign individually, but braid into something lethal: AI is fun to play around with, management is all-in on AI, and AI makes many non-productive tasks feel productive.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Drowning in Content.&lt;/strong&gt; Corporate information systems are delicately balanced ecosystems, and AI is an invasive species, replicating at a pace that will quickly out-compete both human-generated content, and any system of meaningful informational consumption. How&amp;rsquo;s your inbox/slack looked recently? Mine is noisy as hell - filled with AI content - sometimes slop, sometimes insightful and useful. Even when AI outputs are valuable (which isn&amp;rsquo;t always the case), finite constraints on attention, execution, and resources are hard constraints that don&amp;rsquo;t have any easy answers. AI to sort and filter to the important messages? AI to route to other AIs for further summary? AI to react to and take action based on AI analysis? People will try everything, but I suspect all such attempts will treat the symptom of noise rather than it&amp;rsquo;s cause - which is a lack of focus and vision. Teams that turn a blind eye to these hard questions will eventually see the their cattywampus AI infrastructure collapse under the weight of its cost and impotence.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Token Cliff.&lt;/strong&gt; Today, frontier labs are heavily subsidizing token costs, as are the AI-powered venture backed startups running on their infrastructure. When those businesses shift toward making a profit, the cost of AI powered tooling is going to go up, probably a lot, and probably all at the same time. That shift will kill companies that baked unsustainable compute into their business models. For those that survive that cliff, there&amp;rsquo;s a famous saying about ad spend: half is wasted, but it&amp;rsquo;s impossible to know which half. Token costs will be like advertising expenses - generating real value, but spread out thinly over tons of waste, impossible to optimize because of the structure of value produced. Companies are rushing to ramp up a huge cost center without any tools for estimating the value of their expenditures.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Talent Disruptions.&lt;/strong&gt; AI is throwing a wrench in talent pipelines. Experienced employees working with AI can do far more than they could before - competition for senior talent will shorten tenure in ways that incentivize short-termism. On the other side of the pipeline, junior employees leaning on AI can appear more competent than before, but seem to be failing to develop the depth of understanding that inculcates the judgement needed to step into more senior roles. Many companies will die simply because their employees learn less, and don&amp;rsquo;t stick around as long.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Distraction from Competency.&lt;/strong&gt; AI allows companies to build far outside of their core competencies, and many companies will die because they decided to build infrastructure that they should have just paid someone else to build and maintain. Every software system looks like it&amp;rsquo;s just a database and a frontend until you get to know the challenges of its implementation, at which point you&amp;rsquo;ve paid large prices in time and tokens. Many companies will vibecode core pillars of their business, and then be typing into chat GPT &amp;ldquo;what is a race condition&amp;rdquo; when their shipment doesn&amp;rsquo;t show up, or &amp;ldquo;please implement withholding for all states make no mistakes&amp;rdquo; after the IRS sends them a letter. Successful companies have a strong and narrow thesis of how they generate value. Many companies will perish because they tried to solve problems that they were fundamentally not equipped to solve, but for which AI gave them a plausible first draft that gave them naive confidence.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Underinvesting in People.&lt;/strong&gt; The final way that companies will fail is that they&amp;rsquo;ll forget about people. They&amp;rsquo;ll under-invest in their employees - treating them like input/output cost centers. They&amp;rsquo;ll neglect their customers, using bots to mediate and summarize all conversations - keeping them at arms length. They&amp;rsquo;ll scorn craft and judgement, blindly asserting that AIs can replicate things outside of their understanding. They&amp;rsquo;ll pour money into tokens and software, and divert resources and attention and time away from people, and then one day they will wake up and realize that the people are the only piece of this that ever actually mattered.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ll close with an insight I like from someone I don&amp;rsquo;t. Besos advises that companies should build their long-term business strategy not based on what is changing, but on what will stay the same - Amazon wasn&amp;rsquo;t built based on assumptions of how the internet would evolve, but on the recognition that consumers will always want low prices, large variety, and quick delivery. AI is the quintescence of flux - nobody knows where the technology will be in ten years, and projecting forward is speculation, not forecasting. But I&amp;rsquo;d bet even after ten years of AI disruption, expertise will still be valuable, companies will still need to focus, and the economy will still serve on the needs and wants and preferences of people, not machines.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Manifesto</title>
      <link>https://grady.dev/projects/manifesto/</link>
      <guid isPermaLink="true">https://grady.dev/projects/manifesto/</guid>
      <pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>ai</category>
      <category>essay</category>
      <category>love</category>
      <category>writing</category>
      <category>tools</category>
      <description>Humans use tools, never the reverse, a compass for an uncertain future</description>
      <content:encoded>&lt;p&gt;Digital technology quietly delivered us to the shores of a new continent twenty years ago.&lt;/p&gt;&#xA;&lt;p&gt;We began our exploration with the exuberance and arrogance of children - assuming our capacity to create and manipulate technology meant that we could understand and control it. As was developmentally inevitable, today we examine technology with the puerile hungers and fatalism of adolescence - we fantasize about it benefitting us personally, and conceptualize it as a force of nature - a wave to be ridden, its direction outside of our control. It is time for us to grow up - to cultivate the humility and principles befitting adults.&lt;/p&gt;&#xA;&lt;p&gt;For we must now see that the terrain of technology that lies ahead of us is not a small island to be cartographed and catalogued - but a continent of profound abundance, unimaginable danger, and completely unknown boundaries. In such foreign terrain we need not a map but a compass - a pointer toward the indelible; toward truths too sacred to be justified by reason, and virtues inexchangeable for lesser values.&lt;/p&gt;&#xA;&lt;p&gt;For the first cornerstone of this project I volunteer the following: &lt;strong&gt;humans use tools, tools must not be allowed to use humans&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Software, a medium of infinite pliability, illuminates this distinction. When software is a tool, it can extend our capability, deepen our minds, and allows us to flex our volition. Tools empower the holder. They can be used for both constructive and destructive purposes - their use is not constrained by the maker, and does not serve any master but their wielder. Tools that enhance human capacity introduce risk but also profound possibility, beyond even the imagination of their manufacturer. A good tool allows every holder to extend themselves.&lt;/p&gt;&#xA;&lt;p&gt;Other software constrains the volition of individuals - it surveils, addicts, and manipulates. It treats human minds, means, and messages as substrates for its manufacturer to control, squeeze, and engineer. It substitutes the shallow desires of the coder for the diverse aims, preferences, and values of the individuals that it purportedly serves. Such software reduces people to users - a dehumanization in vocabulary that provides cover for profound thefts.&lt;/p&gt;&#xA;&lt;p&gt;We must call it so, while we can. &lt;strong&gt;To capture the attention, distort the preferences of, or facilitate the addiction of another human is a theft.&lt;/strong&gt; It co-opts not only time, money, and energy, but robs a person of the a defining element of their humanity - their agency. Software facilitates small crimes of this sort at unimaginable scale. We must decide that the small harm of billions is no less degrading to our common dignity than the immiseration or murder of few. Our creator endowed us with the pursuit of happiness, not to be traded away for trinkets of convenience, but as inalienable right.&lt;/p&gt;&#xA;&lt;p&gt;We must proclaim that we humans are actors - wielders of tools. We must reject attempts to blur the distinction between principal and agent, between men and machines. We must destroy systems of mechanized manipulation and coercion. We must develop the language, intuition, and zeal to reflexively defend our volition against a wide range of insidious and subtle threats.&lt;/p&gt;&#xA;&lt;p&gt;Humans use tools. Tools must not be allowed to use humans.&lt;/p&gt;&#xA;&lt;p&gt;This is magnetic north. It is not a sufficient to navigate without error, and we should not always go straight toward it. But we have a compass.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>On the name Grady</title>
      <link>https://grady.dev/projects/on-grady/</link>
      <guid isPermaLink="true">https://grady.dev/projects/on-grady/</guid>
      <pubDate>Sun, 20 Jul 2025 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>love</category>
      <category>writing</category>
      <description>Family lore, resillience, and what matters</description>
      <content:encoded>&lt;p&gt;In 2025 I met another Grady, and had a welcome reason to revisit how I came by my name.&lt;/p&gt;&#xA;&lt;p&gt;When my mother was pregnant with me, my parents tentatively planned to name me William. It would have been a family name, and as the first boy born into my extended family, it was a strong contender. As my mother grew larger, they thought about other names, but &amp;ldquo;William&amp;rdquo; remained most likely.&lt;/p&gt;&#xA;&lt;p&gt;But every evening during pregnancy, as they had for a decade before, and at least a decade after, my parents watched the &amp;ldquo;News Hour&amp;rdquo; - the nonpartisan nightly news roundup on PBS. A few weeks before I was born, on July 15th 1994, the News Hour had a segment covering a dam failure in South Georgia, which included a quick interview of a retired couple whose home had been destroyed in the flood - Evelyn and Grady West:&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;EVELYN WEST&lt;/em&gt;: The water come up so fast it, well, it was floated from the top of my washing machine and busted the top off &amp;ndash; all my food &amp;ndash; my food scattered.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;MS. BOWSER (Reporter)&lt;/em&gt;: Evelyn West lost nearly everything. She and her husband, Grady, built this little brick house by the lake five years ago when he retired. It was supposed to be for their golden years. But now at the ages of 68 and 70, they are faced with starting over. They&amp;rsquo;re determined to make the best of it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;GRADY WEST&lt;/em&gt;: I look at it this way, you know, there&amp;rsquo;s no use of grievin&amp;rsquo; over it, it&amp;rsquo;s a material thing, and it can be replaced, and I&amp;rsquo;ve always been a hard worker, and I think that we can &amp;ndash; between the two of us &amp;ndash; we can overcome this, and really that you haven&amp;rsquo;t got much choice.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;MS. BOWSER (Reporter)&lt;/em&gt;: For 32 years, Grady West worked for the Crisp County Power Commission that built this nearby dam. It broke at 5:30 last Saturday morning, causing most of the flooding in the Lake Blackshear area. There had been one inch of rain an hour for more than a day. It was too much water, too quickly for the 65 year old earth dam and power station.&lt;/p&gt;&#xA;&lt;p&gt;From that short clip, my parents decided to add Grady to their list of names. My mom always said it was his smile and resilience that stuck with her. After I was born, they both thought (and the labor nurse confirmed) I looked more like a Grady than a William - and the rest is paperwork.&lt;/p&gt;&#xA;&lt;p&gt;So as not to lose this personal treasure to bit rot, I&amp;rsquo;ve recorded the snippet of it above and it&amp;rsquo;s available &lt;a href=&#34;https://drive.google.com/file/d/1XxtK_ZznkVUu3xH60I7Vp-AlkgZ1szbS/view?usp=sharing&#34;&gt;here&lt;/a&gt;.&#xA;At the time of this writing, you can find the full episode &lt;a href=&#34;https://americanarchive.org/catalog/cpb-aacip-507-zc7rn31636&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I have to admit that though I&amp;rsquo;ve heard the story a dozen times in my life, I always assumed it was apocryphal - lore passed down by telephone, rather than an accurate recounting of events. I first heard it when I was quite young, likely in the late nineties, and we wouldn&amp;rsquo;t get internet until well into the next decade. But in the year 2025, given a happy reason to find the source material, and an excellent public archive, I was able to find it in a few minutes.&lt;/p&gt;&#xA;&lt;p&gt;Right before I watched it, I realized that it didn&amp;rsquo;t matter to me whether it was true. The solace and pride I took in the name wasn&amp;rsquo;t based on its veracity, but what it stood for: capability, partnership, and disposition. That it happens to be true is just a bonus. My mother&amp;rsquo;s memory is (at least at times) as accurate and expansive as she claims.&lt;/p&gt;&#xA;&lt;p&gt;I was named for a smile in face of hardship, for a worker sure of his skills, for a man who knew that what really matters isn&amp;rsquo;t the material stuff, but the people. Seeing the clip today I&amp;rsquo;m also struck by the smile Grady and Evelyn seem to share as they stand with each other, the easy confidence they have that they will rebuild, and do so together.&lt;/p&gt;&#xA;&lt;p&gt;I know life is too full of contingency to attribute too much of anything to something as simple as a name, but I can think of times in my life where the name, and the lore, reminded me that I can do hard things, and that people are what&amp;rsquo;s important.&lt;/p&gt;&#xA;&lt;p&gt;Reflecting back a few weeks later, I&amp;rsquo;m also struck by how we can make meaningful impressions on each other even when our connections are fleeting and tenuous. I doubt Grady West will ever know that his ten second spot on the news ended up shaping the life of some unrelated Grady Ward a dozen states away. But disposition and attitude is like that - it has a surprising way of echoing far beyond ourselves.&lt;/p&gt;&#xA;&lt;p&gt;With that in mind: find people that you love, develop your skills, and build something with both.&lt;/p&gt;&#xA;&lt;p&gt;After all, we haven&amp;rsquo;t got much choice.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Sunrise</title>
      <link>https://grady.dev/projects/sunrise/</link>
      <guid isPermaLink="true">https://grady.dev/projects/sunrise/</guid>
      <pubDate>Tue, 24 Jun 2025 21:05:24 -0600</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>algorithms</category>
      <category>animation</category>
      <description>The best time of the day - faithfully reproduced</description>
      <content:encoded>&lt;p&gt;The colors of this site are copied from nature - they&amp;rsquo;re the colors&#xA;of the sunrise of June 19th, 2025, viewed from RMNP. It was a good one.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-i-built-this&#34;&gt;Why I built this&lt;/h2&gt;&#xA;&lt;p&gt;I love mornings - they&amp;rsquo;re the best time of the day.&#xA;As a new day starts, nothing has yet been decided,&#xA;nature hums with anticipation - tension and potential bound up in stillness.&#xA;I also love sunrises - you get to lay claim to one bookend of the day,&#xA;and if seeing it being born doesn&amp;rsquo;t allow you to sieze it, I can&amp;rsquo;t imagine what could.&lt;/p&gt;&#xA;&lt;p&gt;For several years I had the idea of trying to build a webpage that would capture my&#xA;love for this moment - I knew it would be the fourth iteration of my personal site,&#xA;and would soften my decade-old &lt;a href=&#34;https://grady.dev/destijl/&#34;&gt;V3 de-stijl aesthetic&lt;/a&gt;.&#xA;I wanted it to feel like &lt;a href=&#34;https://www.jambase.com/article/cory-wong-trail-songs-dusk-acoustic-album&#34;&gt;Cory Wong&amp;rsquo;s &amp;ldquo;Trail Songs&amp;rdquo; Albums&lt;/a&gt;, both Daybreak and Dusk sides.&lt;/p&gt;&#xA;&lt;p&gt;I tried many approaches without success.&#xA;I tinkered around with building gradients by hand in Inkscape.&#xA;I tried to build an algorithm for simulating a sunrise based off of photonic refraction&#xA;for &lt;a href=&#34;https://grady.dev/projects/abound/&#34;&gt;Abound&lt;/a&gt;. I played around in SVGator to try to figure out an animation scheme.&#xA;The problem with each approach was I could never get the colors right by eye - even when&#xA;I was sampling from an image of a sunrise, the colors always felt either sterile or&#xA;gaudy. I realized that to emulate the real thing I needed data from the real thing.&#xA;After searching youtube for videos that might suffice (without success), I&#xA;decided:&#xA;&lt;strong&gt;I needed to get a timelapse of the sky on the morning of a perfect sunrise.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;data&#34;&gt;Data&lt;/h2&gt;&#xA;&lt;p&gt;It took me four tries. Three times I found myself up before&#xA;dawn, perched in the foothills in Colordao, looking westward into the black.&#xA;But the sunrise is tricky - you have to get in position before&#xA;&lt;a href=&#34;https://www.timeanddate.com/sun/usa/boulder&#34;&gt;Astronomical Twilight&lt;/a&gt;&#xA;in order to catch it from black (which nescessarily implies doing so on a non-work day).&#xA;You have to have a timelapse setup that is sturdy - and hardest of all, you get at&#xA;most one shot per day. My first attempt failed when my phone was blown over by wind.&lt;/p&gt;&#xA;&lt;p&gt;But the problem that thwarted the next two times was clouds. Clouds are tricky. They&#xA;totally skew the data on colors because they introduce huge dips in saturation and&#xA;skew toward bluer hues (even at sunrise). They&amp;rsquo;re also ubiquitious.&#xA;If you look out to the horizon from a high vantage, only very rarely will there&#xA;truly be no clouds in the sky. When visibility is good, you need sometimes hundreds&#xA;of miles of clear sky in front of you to fully capture the color of the true horizon&#xA;during a sunrise. Twice I found myself thwarted in the wee hours of the morning by&#xA;clouds.&lt;/p&gt;&#xA;&lt;p&gt;But then, the day before Juneteenth 2025 (the Federal holiday most worthy of celebration for other reasons)&#xA;the &lt;a href=&#34;https://opensnow.com/news/post/cloud-cover-forecast-map&#34;&gt;cloud cover forecast on Open Snow&lt;/a&gt; indicated the holiday might be the day.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I set an alarm for 12:55 AM.&lt;/li&gt;&#xA;&lt;li&gt;I packed a bag and hit the road by 1:30 AM.&lt;/li&gt;&#xA;&lt;li&gt;By 2:30AM I reached &lt;a href=&#34;https://www.nps.gov/index.htm&#34;&gt;Rocky Mountain National Park&lt;/a&gt;,&#xA;and was briefly delayed because none of their automated payment machines were working&#xA;(sorry for not paying NPS, I tried).&lt;/li&gt;&#xA;&lt;li&gt;By 3:10AM I was in position at &lt;a href=&#34;https://maps.app.goo.gl/iSXNUcLnHZg3B8fC9&#34;&gt;Rainbow Curve&lt;/a&gt; on Trail Ridge Road.&#xA;I setup the ersatz tripod (a laptop stand with a phone ductaped to it, reinforced by books - see image below),&#xA;pointing to the northeast, and slept fitfully from 3:30AM through howling winds&#xA;&lt;ul&gt;&#xA;&lt;li&gt;During setup, I used a compass to point the camera due east, not thinking about the fact that&#xA;Juneteenth is very close to the summer solstice, and thus the sun would be coming from the furthest&#xA;north it ever does.&lt;/li&gt;&#xA;&lt;li&gt;Luckily, while still dark, the moon was rising to the east, and the crescent on the moon pointed&#xA;toward the north strongly enough that I realized my error and was able to salvage the angle in time.&lt;/li&gt;&#xA;&lt;li&gt;I&amp;rsquo;d chosen Rainbow Curve because it points due east through the foothills, giving me a sunrise over the&#xA;plains. However, because of this error, the sunrise happened over the mountains.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-tripod.jpg&#34; alt=&#34;The ersatz tripod&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;When I crawled out of my car to bask in the warm glow of morning, I was thrilled to see that the&#xA;timelapse was perfect - you can see it &lt;a href=&#34;https://grady.dev/img/sunrise-video.mp4&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;building-the-gradient&#34;&gt;Building the Gradient&lt;/h2&gt;&#xA;&lt;p&gt;I got to work a few days later trying to build the CSS that could replicate the perfection of that video.&lt;/p&gt;&#xA;&lt;p&gt;First, I used Google Photos to stabilize the result, which made subsequent analysis much easier.&lt;/p&gt;&#xA;&lt;p&gt;Then, I created a mask which only included the sky (by hand in GIMP), and ran a bash script&#xA;to extract each frame of the image and apply that mask to it. I also put any of the frames&#xA;that happened after the sun poked over the horizon into a different folder. I had quickly realized it was going to be&#xA;hard to solve both the pre-and-post sunrise with the same algorithm.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-mask-1.png&#34; alt=&#34;An example of how I constructed a mask pixel by pixel to capture only the sunrise.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Using the data to create the output ended up being relatively simple.&#xA;Using Claude Code I tried out 4-5 different algorithms that I sketched out to try to&#xA;achieve the subtle curvature you see in sunrises, including:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Using Iso-Color bands to try to identify the center of a radial gradient based on curvature&lt;/li&gt;&#xA;&lt;li&gt;Using a loss function (of comparison with an original frame) to try to come up with an idealized gradient for each frame&lt;/li&gt;&#xA;&lt;li&gt;Using a vertical color sample from the middle and edges of the image to estimate the eccentricity and center of an elipse we could use as a radial gradient.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;All of these proved unworkable, and while I got some fun failure modes (below), I didn&amp;rsquo;t feel like I was getting much closer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-radial.png&#34; alt=&#34;A failed experiment&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;But the more I played around with it, the more it felt like maybe a linear gradient (a far simpler approach)&#xA;could be sufficient - I realized that if you add a foreground of mountains, you don&amp;rsquo;t mind the ways the light doesn&amp;rsquo;t&#xA;bend as much near the horizon.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-algorithm&#34;&gt;The Algorithm&lt;/h2&gt;&#xA;&lt;p&gt;So the actual algorithm is dead simple: &lt;strong&gt;In each frame F, select N rows evenly spaced through the frame (20-50 worked well). For each row R, average the color of every pixel in the row. This gives you an F-by-N matrix with a single color value for each cell (Row). This matrix can then be used as keyframes for the resulting linear gradient (with F being the keyframe steps).&lt;/strong&gt; Super simple!&lt;/p&gt;&#xA;&lt;p&gt;There are only a small number of additional effects I added after that basic algorithm. The first was recognizing that the&#xA;sampling of individual rows meant that the matrix it generated wasn&amp;rsquo;t &amp;ldquo;smooth&amp;rdquo; - both in the time&#xA;dimension and in the vertical dimension there was a lot of &amp;ldquo;roughness&amp;rdquo; in that the colors would jitter about&#xA;and you could see the bands clearly at keyframes. I solved this through the standard &lt;a href=&#34;https://en.wikipedia.org/wiki/Box_blur&#34;&gt;box blurring algorithm&lt;/a&gt; (applied to the breakpoint colors, not the pixels!) - just&#xA;average each breakpoint within each keyframe value with the 8 adjacent values in the matrix (2 in the same frame, 3 in the next and 3 in the prev).&#xA;This reduced the amount of noise dramatically.&lt;/p&gt;&#xA;&lt;p&gt;The second realization was that averaging RGB values yields colors that tend toward greys - (visualize the&#xA;3-space of the RGB cube to reason about why). &lt;a href=&#34;https://en.wikipedia.org/wiki/HSL_and_HSV&#34;&gt;HSL&lt;/a&gt; on the other hand doesnt suffer from this proprety (because it&amp;rsquo;s cylindrical), so I converted&#xA;the logic to average based on HSL, and that dramatically improved the color fidelity. In the image below,&#xA;the still frame from the video is on the left, the RGB averaged image is in the center, and the HSL averaged image (no other changes)&#xA;is on the right - what a difference that makes eh!?&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-color-averaging.png&#34; alt=&#34;Three side by side images&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Throughout this iteration process, I built out (or rather described to Claude) a comparison tool to enable me to more&#xA;effectively debug and analyze gradients. It worked great, until&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-comparison-tool.png&#34; alt=&#34;The gradient tool that gives statistics on where an image differs from the ccreated gradient, both numerically and visually&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;While Claude was very helpful through this iterative process, I eventually realized there was a serious issue with the&#xA;color interpretation process early in the pipeline stemming from PNG color profiles somehow corrupted by my processing.&#xA;Additionally, the code had become total spaghetti, there were hardcoded ideas about gamma correction, and the code was&#xA;littered with the detritus of past failed experiments. I started from scratch, and built in programmatic checks at each step&#xA;that the colors being generated matched (or were close to) the raw colors sampled from the image, using a different approach&#xA;to image encoding and sampling, and only using HSL colors throughout, rather than doing conversions back and forth (which,&#xA;it turned out were another source of lossy colors). You can see the compounded color errors most clearly in frames like this&#xA;one, where the blues on the left have hues of ~219, and the blues on the right have hues closer to 201. Huge differences!&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-color-error.png&#34; alt=&#34;A demonstration of the compounded color errors&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This also allowed me to rebuild the comparison tool, enabling me to quickly iterate on different approaches to averaging&#xA;the pixels across a row, which I realized was the crux of the algorithm after fixing the color correction issues.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-grid-comparison.png&#34; alt=&#34;A 3x3 grid showing 9 different frames of the sunrise and the different algorithms suggestions projected on each&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The winning algorithm is shown below, labeled as 1. It takes all of the pixels in a row and then does the following to&#xA;decide the color most represenative of that row:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The core of the algorithm is a function called &amp;ldquo;bucketize_colors&amp;rdquo;, which takes in the pixel data in the row, a&#xA;&amp;ldquo;bucket_width&amp;rdquo;, and a &amp;ldquo;bucket_offset&amp;rdquo;. HSL colors represent hues as an angle between 0 and 360 degrees, like a&#xA;color wheel. This algorithm would construct ranges of hues that cover the full color wheel in equal spacings,&#xA;and then assign each pixel to the bucket that contains it. So for example, a bucket_width of 3 and bucket_offset&#xA;of 2 would yield hue buckets like ([2, 5],[5, 8]&amp;hellip;[359-2]), and a pixel with hue 6.22 would get put into the second&#xA;bucket.&lt;/li&gt;&#xA;&lt;li&gt;Then, starting off with buckets of size 1, it gradually increases the bucket size until a single bucket&#xA;contained more than 15% of all of the pixels in the row, searching all bucket_offsets for a given&#xA;bucket_width to find the best fit if more than one offered 15% capture of the pixels.&lt;/li&gt;&#xA;&lt;li&gt;The pixels in this bucket were then taken as the most representative pixels in the set, and we just returned&#xA;the average of their Hues, Saturations, and Lightnesses as the HSL value for the row.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;You can see this algorithm in action below. #1 is this &amp;ldquo;Hue Bucketed Mean&amp;rdquo; method that I described, while #2 is a&#xA;pure HSL averaging approach.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-better-correction.png&#34; alt=&#34;A frame demonstrating the better color correction of the winning algorithm&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-css&#34;&gt;The CSS&lt;/h2&gt;&#xA;&lt;p&gt;After finishing the algorithm and finding the right sets of gradients for each frame, I needed to figure out how&#xA;to render it on a website in a way that is pleasant.&lt;/p&gt;&#xA;&lt;h3 id=&#34;landing-page&#34;&gt;Landing Page&lt;/h3&gt;&#xA;&lt;p&gt;For the landing page, there was the small matter of tricking CSS into being willing to render an animated gradient,&#xA;because the &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient&#34;&gt;specs will tell you&lt;/a&gt;&#xA;that &lt;strong&gt;linear gradients aren&amp;rsquo;t animatable&lt;/strong&gt;. Because of this I started out by using SVG&#xA;animations, which worked great, but wasn&amp;rsquo;t easy to pause or replay using Javascript, and that felt important to get right.&lt;/p&gt;&#xA;&lt;p&gt;Well, it turns out if you use CSS&amp;rsquo; &lt;code&gt;@property&lt;/code&gt; declarations with type color, and then animate&#xA;&lt;strong&gt;all of the properties that impact the linear gradient in the same set of keyframes&lt;/strong&gt;,&#xA;CSS is willing to render a linear gradient as if it is animated. Many thanks to&#xA;&lt;a href=&#34;https://dev.to/afif/we-can-finally-animate-css-gradient-kdk&#34;&gt;Temani Afif&lt;/a&gt; for this very nifty hack.&lt;/p&gt;&#xA;&lt;h3 id=&#34;project-pages&#34;&gt;Project Pages&lt;/h3&gt;&#xA;&lt;p&gt;For the project page, while talking with my dad I realized that I could use the height of the page to represent&#xA;time, and try to show the transition between frames as the user scrolls down the page, just like projects tend&#xA;to become clearer the further you get into them.&lt;/p&gt;&#xA;&lt;p&gt;Implementing this was relatively simple: the page is divided into sections (per paragraph, heading, etc), and&#xA;each section has two linear gradients that go from left to right. The first is a solid background, which corresponds&#xA;to the linear gradient at the top of the block. The second is a linear gradient from the next block (the top of the&#xA;next block) which increases in opacity from zero at the top of the block to one at the bottom of the block, so that&#xA;we get a smooth color transition within each block, and because the top of one block is the same as the bottom of the&#xA;next block, the transition is relatively seamless.&lt;/p&gt;&#xA;&lt;h3 id=&#34;list-pages&#34;&gt;List Pages&lt;/h3&gt;&#xA;&lt;p&gt;I&amp;rsquo;m not satisfied with any of my current approaches to the list page - I expect I&amp;rsquo;ll iterate on it for a while until&#xA;I find something I like.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-real-author&#34;&gt;The Real Author&lt;/h2&gt;&#xA;&lt;p&gt;One big disclosure I need to make about this project is that I didn&amp;rsquo;t write much code for it - mostly just describing and debugging algorithms.&#xA;Though I described how they should work, Claude&#xA;built all of the&#xA;algorithms in several thousand lines of Golang without much assistance. If I had to build it from scratch myself, building the image processing toolkit&#xA;would have taken me much more time and I would have had many more bugs than if I hadn&amp;rsquo;t relied on Claude (though, Claude still had a variety of bugs that required me to dive deep and understand its code, and in the more than one case, start from scratch).&#xA;As a result, the site was quick to build, and I think it looks really nice, but under the hood it&amp;rsquo;s quite grotesque - code that&#xA;carries the scars of dozens of substantial revisions by multiple authors (me and Claude) without much continuity of thought. An instructive co-programming session.&lt;/p&gt;&#xA;&lt;p&gt;One key finding from the project is that if you&amp;rsquo;re vibe coding, you need to build out (or have Claude build out)&#xA;robust processes for validating the work that it tries to do. I found building out this algorithm comparison tool&#xA;was the key to making consistent progress and evaluating &amp;ldquo;success&amp;rdquo;&#xA;(check out a sample output by clicking below).&#xA;As we start to rely more on LLMs, have clearer ideas of what we want, and better tools to evaluate how we&amp;rsquo;re doing&#xA;against those goals is going to be more and more important,&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-final-debugger.png&#34; alt=&#34;A visual debugger where I could see the gradients generated by multiple, distinct algorithms at once and compare the results&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-end-result&#34;&gt;The End Result&lt;/h2&gt;&#xA;&lt;p&gt;I really like it. I like watching it. It&amp;rsquo;s a personal brand I feel connected to and proud of. It feels thoughtful - not overdone, not sloppy. Purposeful, data-driven, gorgeous. Even so, I felt ambivalent making it my new homepage - I really liked the &lt;a href=&#34;https://grady.dev/destijl/&#34;&gt;old site&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I have a list of things I&amp;rsquo;d like to try to get working in the future, including a true radial gradient&#xA;(in particular to capture the 3-5 second range of the original video &lt;a href=&#34;https://grady.dev/img/sunrise-video.mp4&#34;&gt;here&lt;/a&gt;), getting the same view later in the year&#xA;(when the sun will rise in the gap in the mountains instead of over them), and trying a different angle/vantage&#xA;to capture the impact of alpenglow on the atmosphere.&lt;/p&gt;&#xA;&lt;p&gt;But this is good for now. The day is young and there is much to do!&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/sunrise-happy.jpg&#34; alt=&#34;Me, happy and smiling after the successful data capture&#34;&gt;&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Custom Board Games</title>
      <link>https://grady.dev/projects/board_games/</link>
      <guid isPermaLink="true">https://grady.dev/projects/board_games/</guid>
      <pubDate>Thu, 14 Nov 2024 14:32:00 -0500</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>gifts</category>
      <category>art</category>
      <category>design</category>
      <description>Themed gifts for friends and family</description>
      <content:encoded>&lt;p&gt;I love making board games for friends and family as gifts, often themed around a&#xA;shared interest or an inside joke. While these were originally separate posts,&#xA;I&amp;rsquo;ve condensed them here for brevity.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2024---frontier&#34;&gt;2024 - FRONTIER&lt;/h2&gt;&#xA;&lt;p&gt;I (and my ex-boyfriend) both have a love-hate relationship with Frontier&#xA;Airlines. The fares are impossibly cheap, and if you have their credit card and&#xA;Discount Den membership, things can be legitimately a fantastic bargain.&#xA;However, they&amp;rsquo;re often late, the staff isn&amp;rsquo;t the friendliest, and I&amp;rsquo;ve had some&#xA;of my strangest experiences flying with them. We also both really like the game&#xA;PanAm, about the expansion of the PanAm corporation - a gorgeous game with great&#xA;mechanics like stock pricing and technological upgrades.&lt;/p&gt;&#xA;&lt;p&gt;So, when my ex-boyfriend mentioned offhandedly that I should make a version of&#xA;PanAm based off of FRONTIER, I was struck by the jealousy you have when someone&#xA;comes up with a great idea that you should have had. While I initially wrote off&#xA;the idea for that Christmas (because this comment was made in early November), I&#xA;took the cancellation of a flight on FRONTIER a week later as a sign/opportunity&#xA;to build out a full version of the game.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/frontier-rough.png&#34; alt=&#34;A very rough sketch of the board that I&amp;rsquo;d end up creating, with only the cities laid out and circles between them representing approximate distances&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The first sketch (above), the final board, 24h later, below:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/frontier-map.png&#34; alt=&#34;The map from the board game, an enormously complex SVG with colorful routes of airlines criscrossing the United States&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This project was very low-fi - there were only two technical elements,&#xA;simulations to ensure the stock price deviation and expansion frequency was&#xA;distributionally good and within normal bounds - a property the real game fails&#xA;to live up to .&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/frontier-simulation.png&#34; alt=&#34;The output of a simulation from the board game&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The majority of the work on this project was just learning to use InkScape&#xA;effectively - practicing my (minimal) SVG skills on a broader canvas and&#xA;learning the keyboard shortcuts, automation tools (like cloning), and becoming&#xA;diligent about layer and group naming, selectors, and tags.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/frontier-event.png&#34; alt=&#34;An event card from the frontier board game, giving the history of the spirit aquisition attempt from 2022&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Only the destination cards&amp;rsquo; images were generated using AI - and even then there&#xA;was a lot of subjective post processing.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/frontier-dest.png&#34; alt=&#34;A screenshot of a bunch of cards - each corresponding to an airport in the united states, with the airport code shown on top of an iconic landmark from the location of the airport&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The gift has yet to be given - but thankfully I don&amp;rsquo;t think anyone reads my&#xA;blog!&lt;/p&gt;&#xA;&lt;h2 id=&#34;2024---puzzle-generation&#34;&gt;2024 - Puzzle Generation&lt;/h2&gt;&#xA;&lt;p&gt;You can check out my laser-cut puzzles &lt;a href=&#34;https://grady.dev/project/laser_puzzles&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2023---tail-tally-point-salad&#34;&gt;2023 - Tail Tally (Point Salad)&lt;/h2&gt;&#xA;&lt;p&gt;In 2023 I made a board game copy of Point Salad for my (at the time boyfriend).&#xA;He loves the game Point Salad and loves his dogs even more.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/tail-tally-1.png&#34; alt=&#34;The front of a card from the Tail Tally deck&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/tail-tally-2.png&#34; alt=&#34;The back of a card from the Tail Tally deck&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The code for it is written in Go, generates HTML files (mostly to take advantage&#xA;of flexbox positioning), and then automatically screenshots those at 500dpi,&#xA;with bleeding/cutoff that matches the specifications from my favorite&#xA;&lt;a href=&#34;https://www.makeplayingcards.com/&#34;&gt;board game printer&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;This one was particularly fun because I made it fully generalizable - you just&#xA;input six photos and select a few things about the color scheme and sizing you&#xA;want, and the deck pops out. I&amp;rsquo;ve printed (but not yet gifted) another version&#xA;for friends - so beware, friends.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2022---wingspan&#34;&gt;2022 - Wingspan&lt;/h2&gt;&#xA;&lt;p&gt;A writeup of the Wingspan project is &lt;a href=&#34;https://grady.dev/project/wingspan/&#34;&gt;here&lt;/a&gt;, but a few bonus&#xA;images are below.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wingspan-jay.png&#34; alt=&#34;A card depicting a blue jay from the auto-generated wingspan deck project&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wingspan-bluebird.png&#34; alt=&#34;A card depicting a bluebird from the auto-generated wingspan deck project&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wingspan-osprey.png&#34; alt=&#34;A card depicting an osprey from the auto-generated wingspan deck project&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;2020-2021---ticket-to-ride&#34;&gt;2020-2021 - Ticket to Ride&lt;/h2&gt;&#xA;&lt;h3 id=&#34;2020---the-original-gift&#34;&gt;2020 - The Original Gift&lt;/h3&gt;&#xA;&lt;p&gt;My mom loves the board game Ticket to Ride, perhaps to a fault. Starting in 2018&#xA;(and apparently continuing to this day) she regularly plays it by herself late&#xA;into the night - with two distinct players (her right and left hand) competing&#xA;to see which one would win.&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;&amp;ldquo;I think everyone needs something to unwind at the end of a day, some people&#xA;need to watch silly TV some people like to have a drink, for me it&amp;rsquo;s board&#xA;games against myself.&amp;rdquo; - My mother&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In 2020, we&amp;rsquo;d been planning on celebrating her 60th birthday as a family, but we&#xA;were unable to do so because of the pandemic. My sister and I, keenly aware that&#xA;this was a really big loss, decided to pour our energies into a great gift, and&#xA;so took a weekend to create this board game.&lt;/p&gt;&#xA;&lt;p&gt;Each location is one that she has been to and has fond memories of. The photo&#xA;cards we created were a few select ones from family lore. The trains were dowels&#xA;that I&amp;rsquo;d cut to length and dyed, and the tokens my sister made from clay, each a&#xA;fun inside joke.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-card1.png&#34; alt=&#34;An early Ticket to Ride Card, featuring my parents on a green background, representing a green train card&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This was the first custom game I&amp;rsquo;d made, so looking back on it, the build was&#xA;fairly primitive - we sent back and forth PPT files in ultra HD. The background&#xA;is from the CINDI project. The files are large enough that they&amp;rsquo;ve been lost to&#xA;time, but the board(s) itself lives on, as do some artifacts from the early days&#xA;of its creation.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-map-1.png&#34; alt=&#34;the original sketch of the map for the board&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-map-2.png&#34; alt=&#34;the revised map for the board, including distances&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-map-3.png&#34; alt=&#34;the final layout for the board&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-map-final.jpg&#34; alt=&#34;the final board, well used and loved&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;My mom loved it, and it has further extended her TTR obsession.&lt;/p&gt;&#xA;&lt;h3 id=&#34;2021---ticket-to-ride-cards&#34;&gt;2021 - Ticket To Ride Cards&lt;/h3&gt;&#xA;&lt;p&gt;When a year had gone by, the pandemic had continued, and my mother was still&#xA;obsessed with TTR (see below), we decided to build out a nicer deck of the&#xA;cards, with each card capturing a different, unique photo from our family.&lt;/p&gt;&#xA;&lt;p&gt;This project was mostly about selecting the right set of photos from our&#xA;library, though I used some very basic facial detection APIs from Google to make&#xA;sure they were approximately centered within the boundaries of the frame.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-card2.png&#34; alt=&#34;A new ticket to ride card, featuring myself and my sister on a purple background, representing a purple train card&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/ttr-card3.png&#34; alt=&#34;Another TTR train card.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;My mother still refuses to use these cards - to my chagrin - because &amp;ldquo;she hasn&amp;rsquo;t&#xA;fully worn through the other deck yet&amp;rdquo; - in case you thought I was overstating&#xA;the degree of her obsession.&lt;/p&gt;&#xA;&lt;h3 id=&#34;2021---webapp&#34;&gt;2021 - Webapp&lt;/h3&gt;&#xA;&lt;p&gt;One last time I dipped into the TTR well by creating an interactive version of&#xA;the custom board game using the simplest thing you can imagine: global state&#xA;within a Java binary, running on a server on GCP with open connections,&#xA;once-per-second polling, and start/stop mechanics. Building out the bizlogic for&#xA;turns and state proved challenging as I stepped on every rake that someone does&#xA;when creating a state based multiplayer game (validation, transition, etc.). A&#xA;few years later I&amp;rsquo;d read a book on generalized gameplay schemas and be struck by&#xA;how I&amp;rsquo;d made every mistake in the book. You live and learn though!&lt;/p&gt;&#xA;&lt;p&gt;The end result was something that was fun for our family to play a few times,&#xA;actually a decently responsive application, and a great reminder: building&#xA;something hacky can actually get you reasonably far as long as you don&amp;rsquo;t intend&#xA;for it to be around long term.&lt;/p&gt;&#xA;&lt;p&gt;It was a good mother&amp;rsquo;s day gift - though probably the time we spent on the phone&#xA;while we played it was the real one.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Laser Cut Puzzles</title>
      <link>https://grady.dev/projects/laser_puzzles/</link>
      <guid isPermaLink="true">https://grady.dev/projects/laser_puzzles/</guid>
      <pubDate>Thu, 14 Nov 2024 14:32:00 -0500</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>algorithms</category>
      <category>art</category>
      <category>gifts</category>
      <category>crafts</category>
      <category>tools</category>
      <description>Writing algorithms for good jigsaw puzzles, and making them real on laser cutters</description>
      <content:encoded>&lt;p&gt;One of my best friends in the world - Brandon - got married in the summer of&#xA;2024, and insisted that no gifts would be exchanged. I nagged him ceaslessly&#xA;on this point, and he eventually relented that only gifts of creative,&#xA;rather than financial value would be accepted. Game on.&lt;/p&gt;&#xA;&lt;p&gt;After much deliberation, I decided to make them a puzzle. I&amp;rsquo;d been looking&#xA;for the opportunity to learn how to use a laser cutter, and thankfully both&#xA;Boulder + Denver offer the tools in their library makerspaces. Over the course of&#xA;several months (and gifts for several close friends - celebrating a wedding,&#xA;commiserating about the passing of a beloved dog, etc.), I fine tuned both the&#xA;code for generating the puzzle, and the usage of the laser cutters (trying&#xA;out three different kinds over time, and finding the right set of controls&#xA;for each).&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_partial.jpg&#34; alt=&#34;A laser cutter cutting out a puzzle of a photo in memorial of a close friend&amp;rsquo;s dog&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_detail.jpg&#34; alt=&#34;A small section of said puzzle, demonstrating the quality of the print from the GlowForge&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;In the end I was very impressed by the Glowforge PRO, which consistently had&#xA;the lowest amount of hassle, and produced consistently good rasters. The&#xA;Epilog laser I used for the final cut was also quite good both in precision&#xA;and accuracy in the cut,but the raster left quite a bit to be desired.&lt;/p&gt;&#xA;&lt;p&gt;The final process I found to be effective involved first etching the image on&#xA;to the wood in a purely raster pass, and then doing the final cut only once&#xA;masked with masking tape, which prevented burn scars.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_mask.jpg&#34; alt=&#34;The final cut, using masking tape to prevent burn scars&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The primary challenge of this project was scooping up the tool&#xA;appointments at each library as it became available - they were hot commodities&#xA;and I often needed to plan my days to keep free the half hour when I knew&#xA;the appointments would go online.&lt;/p&gt;&#xA;&lt;p&gt;Fine tuning the code was another tricky part, since there were&#xA;a lot of things to tweak, and very slow iteration cycles for trying them&#xA;out in the real world. I eventually figured out a structure for the nubs that&#xA;would cut well, and designed a cool algorithm for making the sides and curves&#xA;generally smooth, while not doing a full grid like a standard puzzle.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_cut.svg&#34; alt=&#34;An example cutting pattern generated by the code&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;By the end, the code was capable of taking in an internal and external cut,&#xA;so that hidden shapes could be included in the puzzle. In this test cut&#xA;you can clearly see the &amp;ldquo;4&amp;rdquo; and the heart, a reference to the date of the marriage.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_test.jpg&#34; alt=&#34;An example of the inset pattern available in the final result&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I gave them the final result at their wedding, and they completed it&#xA;during a subsequent bout of COVID - ultimately framing it on their wall.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_assembled.jpg&#34; alt=&#34;The completed final result&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/laser_framed.jpg&#34; alt=&#34;The framed final result&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;(A piece was lost from the leftmost edge - a standard foible of the genre)&lt;/p&gt;&#xA;&lt;p&gt;This project was a great reminder for me that the best gifts are about&#xA;the thought behind them and the expression of care for the other people.&#xA;Building this gave me ample opportunities to reflect on how much both of&#xA;the people meant to me, and how thankful I was to have the time and skills to&#xA;tinker.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Binding Beauty of Chores</title>
      <link>https://grady.dev/projects/chores/</link>
      <guid isPermaLink="true">https://grady.dev/projects/chores/</guid>
      <pubDate>Tue, 19 Mar 2024 15:21:00 -0600</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>love</category>
      <category>essay</category>
      <category>community</category>
      <description>How automation, specialization, and collectivization enable isolation</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;A long-form narrative version of this essay appeared in a friend&amp;rsquo;s literary&#xA;magazine, The Hart and the Curr - I recommend you read&#xA;&lt;a href=&#34;https://www.thehartandthecur.com/binding-beauty-of-chores&#34;&gt;that version&lt;/a&gt; - it&#xA;benefits from his edits.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;I recently did one of my favorite winter activities: a backcountry hut trip. A&#xA;group of us schlepped a bunch of gear and food into the woods, and spent a few&#xA;days living simply: heating a rustic cabin with firewood, melting snow for&#xA;water, cooking, eating, and exploring the outdoors together. After a long&#xA;weekend in this environment, I feel refreshed, relaxed, and more deeply&#xA;connected with the friends that I accompanied.&lt;/p&gt;&#xA;&lt;p&gt;Counterintuitively, part of the joy of a hut trip comes from the chores: the&#xA;small, quaint, simple challenges that occupied much of our time. These included&#xA;pumping water through a filter, splitting wood for kindling, and scraping ice&#xA;from the door jam, to name a few. These activities may not sound like an&#xA;integral part of a vacation, but they fulfill deeply: through chores we got to&#xA;provide value to each other, and enact concrete transformation of our&#xA;surroundings.&lt;/p&gt;&#xA;&lt;p&gt;Zoom back for a second. Modernity removes routine tasks from our lives through a&#xA;combination of &lt;strong&gt;automation, specialization, and collectivization&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Thermostats and furnaces abstract the management of heat (automation)&lt;/li&gt;&#xA;&lt;li&gt;Professionalized plumbers enable ignorance about pipes (specialization)&lt;/li&gt;&#xA;&lt;li&gt;Public utilities ensure the potability of water (collectivization)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;These three &lt;em&gt;impersonal&lt;/em&gt; processes remove manual labor as they increasingly&#xA;automate, outsource, and collectivize the &lt;em&gt;effort needed to sustain human&#xA;comfort&lt;/em&gt;. Though these are the pillars of human progress, a side effect of their&#xA;efficiency is to weaken the bonds that hold us together.&lt;/p&gt;&#xA;&lt;p&gt;Relationships, Families, and Communities are (in part) held together through&#xA;chores: &lt;strong&gt;small acts of service that connect the individual to the broader unit&#xA;through the wilful contribution to shared value&lt;/strong&gt;. As an easily cognizable&#xA;example, consider how people who live in adjacent dwellings become neighbors.&#xA;The small requests (can you look out for a package, take in the cans while we&amp;rsquo;re&#xA;away), and small offerings (alerting them to an open garage, shoveling their&#xA;part of the sidewalk) that neighbors take from and give to one another form a&#xA;network of communal care that slightly inconveniences every individual, while&#xA;constructing a whole (a neighborhood) that is stronger and more resilient than&#xA;the components considered individually (houses, people). Relationships,&#xA;Friendships, Communities, and even Families are forged through this same force:&#xA;service is a key binding agent in human relationships.&lt;/p&gt;&#xA;&lt;p&gt;While automation, specialization, and collectivization make our lives concretely&#xA;easier, they reduce our reliance on others for our comfort, and conversely&#xA;reduce the number of opportunities we have to serve one another.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Novel technologies that monitor the state of your garage door, and online&#xA;systems for holding mail reduce our reliance on (and capacity to visibly&#xA;assist) our neighbors.&lt;/li&gt;&#xA;&lt;li&gt;The abundance of professional plumbers makes us less likely to reach out to a&#xA;handy family member or neighbor for help.&lt;/li&gt;&#xA;&lt;li&gt;Municipal snow plowing obviates my favorite form of neighborly care: shoveling&#xA;a neighbor&amp;rsquo;s sidewalk.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;These three forces (automation, specialization, and collectivization) meet our&#xA;needs through &lt;strong&gt;impersonal means&lt;/strong&gt;, and in doing so, remove the &lt;em&gt;possibility&lt;/em&gt; of&#xA;the personal connections that used to arise out of these tasks.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s be clear: the fulfillment of need that these forces bring about is&#xA;unquestionably a good: they bring about a world where independence and freedom&#xA;are more broadly accessible and more equitably distributed. While it would be&#xA;ill advised to attempt to revert to some state of unfulfilled need, we must deal&#xA;with the bad side effect of this good medicine: &lt;strong&gt;how do we strengthen and&#xA;cultivate interpersonal bonds, both individually and structurally, in a&#xA;technologically advanced (and advancing) world?&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Zooming back into the hut trip, I think this is part of what makes it so&#xA;magical. Though the setting of a remote hut is contrived in the sense that we&#xA;could return to modernity, in every other way the demands it imposes are real.&#xA;Without heat, water, food, or sanitation, our individual situations would be&#xA;dire. Tackling this reality boils down to chores: to chop wood, melt snow, cook&#xA;food, and filter water. Each individual then has the opportunity (and social&#xA;pressure) to complete parts of this service: to do simple chores, thank one&#xA;another for completing the tasks that they do, and through non-directed&#xA;individual action, become a unit that can keep itself warm, hydrated, fed, and&#xA;clean. It is this togetherness, this communion of purpose, that forges&#xA;friendships, trust, and comfort among group members. I leave every hut trip with&#xA;deeper, stronger relationships with each of the other participants.&lt;/p&gt;&#xA;&lt;p&gt;The appreciation I have for hut trips is not a call for reversion to more&#xA;primitive living conditions. Rather, as automation, specialization, and&#xA;collectivization fulfill more of our physical needs, we must recognize how this&#xA;weakens our dependence upon, and potential service of others. In response, &lt;strong&gt;we&#xA;must invent or discover new acts of service&lt;/strong&gt;, rather than trying to reclaim&#xA;challenges from the forces that obviate them. Human want (and thus capacity for&#xA;support) is unbounded. As we advance as a civilization the mechanism for&#xA;scaffolding interpersonal relationships can change to reflect the needs of the&#xA;present, and the humans working to meet them.&lt;/p&gt;&#xA;&lt;p&gt;Ask yourself:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;What might your neighbor, sibling, or friend struggle with, and how might you&#xA;provide them aid or comfort?&lt;/li&gt;&#xA;&lt;li&gt;Where could others (through small acts of theirs) make a large difference in&#xA;your life?&lt;/li&gt;&#xA;&lt;li&gt;(and critically): how can you foster within yourself &lt;strong&gt;the selflessness to&#xA;offer, and the humility to accept, help&lt;/strong&gt;?&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Whether it&amp;rsquo;s dogsitting, sharing hot food or book recommendations, practicing&#xA;emotional vulnerability, helping with childcare, or simply calling someone out&#xA;of the blue, there are a plethora of ways that we can (through small efforts)&#xA;deliver huge value for others. Each of these represents an opportunity to&#xA;connect with and serve one another, and in the process we enmesh ourselves as&#xA;part of a shared community, &lt;strong&gt;one that is stronger than the sum of its parts&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;These impersonal forces (automation, economic specialization, and&#xA;collectivization) will continue to make our lives simpler, cheaper, and more&#xA;lavish. All good things. But as they grow we must scaffold the structures that&#xA;lie out of their reach. Friendships can&amp;rsquo;t be automated; families can&amp;rsquo;t be bought&#xA;on a marketplace; municipalities can&amp;rsquo;t legislate a community into existence. As&#xA;individual convenience is served by these market forces (and glorified by&#xA;culture), its up to each of us to rediscover the inefficent, sometimes hard, and&#xA;always rewarding tradition of extending help without expectation, and receiving&#xA;it with grace.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Terry v. Ohio &#43; Bulk Infringement</title>
      <link>https://grady.dev/projects/terry/</link>
      <guid isPermaLink="true">https://grady.dev/projects/terry/</guid>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>privacy</category>
      <category>writing</category>
      <category>government</category>
      <description>Case level analysis generates poor precedent</description>
      <content:encoded>&lt;p&gt;&lt;em&gt;Terry v. Ohio&lt;/em&gt; is known for it&amp;rsquo;s implications on the probable cause requirement of the fourth amendment, but something else jumped out at me when I put myself in the shoes of the Warren court: given the fact pattern, they were doing their best to encourage good policework, and in the case of stop and frisk the differentiation between &amp;lsquo;good&amp;rsquo; and &amp;lsquo;bad&amp;rsquo; policing hinges on the quality of the officer&amp;rsquo;s decision making (the only proxy for which we have is the outcome of the individual choices weighed in the decision):&lt;/p&gt;&#xA;&lt;p&gt;The majority tries to write narrowly. I&amp;rsquo;d guess that they thought that the correct outcome was to uphold the search and they were grasping for a reason why the stop could be justified without destroying probable cause. If so, I see where they are writing from. I&amp;rsquo;m at all concerned with Terry&amp;rsquo;s fate, but I definitely care about supporting the McFaddens of the world. McFadden made a judgement call to stop and frisk Terry and his coconspirators, and out of this individual decision, an agreeable outcome arose. Were McFadden less perceptive, more suspicious, or less discriminating we wouldn&amp;rsquo;t be talking about &lt;em&gt;Terry&lt;/em&gt;. But as it happened, the case that justifies Stop and Frisk is a &lt;em&gt;true positive&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Zoom back for a second. An officer&amp;rsquo;s decision on whether to Stop and Frisk (S+F) a civilian has four outcomes, based on whether the officer decides to stop (STOP) or not (PASS), and whether the civilian is actually in possession of illegal goods or arms (GUILTY) or not (INNOCENT):&lt;/p&gt;&#xA;&lt;p&gt;(1) True Negative (PASS, INNOCENT)&#xA;(2) False Negative (PASS, GUILTY)&#xA;(3) False Positive (STOP, INNOCENT)&#xA;(4) True Positive (STOP, ARREST)&lt;/p&gt;&#xA;&lt;p&gt;There are clear downsides to False Positives and False Negatives. &lt;strong&gt;False positives&lt;/strong&gt; seriously intrude on basic liberties to be secure in person and posession, tend to be racially biased, and create mistrust between law enforcement and civilians. &lt;strong&gt;False negatives&lt;/strong&gt; likely increase crime rates and embolden criminals. A city&amp;rsquo;s choice on how and if to conduct S+F &lt;strong&gt;should probably be based on a concious tradeoff between the relative incidence of false positives and false negatives&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;But thats now how courts operate. In &lt;em&gt;Terry&lt;/em&gt;, we only see a single instance, a True Positive. Were the circumstances in front of the Warren court not that of McFadden and Terry, but, say, Sandra Bland and Brian Encinia (a &lt;em&gt;False Positive&lt;/em&gt;), the court might arrive at a different outcome. Heck, if Officer McFadden had stopped 100 innocent people before stopping Terry, I&amp;rsquo;d argue that should change the outcome, but we don&amp;rsquo;t get to know that context in deciding this case. The problem with &lt;em&gt;Terry v. Ohio&lt;/em&gt; is not (as some argue) that the fact pattern sits at the peak of the watershed &amp;lsquo;probable&amp;rsquo; divide (though it does). Instead, the problem with &lt;em&gt;Terry&lt;/em&gt; is that it is a single case.&lt;/p&gt;&#xA;&lt;p&gt;When constitutional rights are in conflict, courts perform our balancing. When the parties with competing constitutional claims are on opposite benches, performing this balancing is easier than when no single case can capture both of the claims. In thinking about S+F, the fact pattern in front of us heavily influences our intuition: true positives show that there are occasions when we want to defer to officer discretion, and false positives show that officer discretion should not be unlimited.&lt;/p&gt;&#xA;&lt;p&gt;It would be impractical and unwise to conclude based on this sentiment that case by case analysis can yield just outcomes (in this case certainly, and in light of the procedural barriers to justice - in the abstract too). Repairing 4th amendment violations is fraught. Instead, we should take a wholistic approach to justice, outside of the confines of a fact pattern to bias our intuition. It is feasible to evaluate the actual numbers of the four outcomes above in any given city. The Positives just need record keeping, and the Negatives  need a few dozen (fully random) stops per day as controls (ignoring the clear constitutional problems with that practice). From there we could evaluate the harms of both groups in direct comparison (consider targeting a 4:1 FalsePositive to FalseNegative ratio).&lt;/p&gt;&#xA;&lt;p&gt;What if a city is above this target ratio? Then officers should exercice more discretion before making a stop: instruct officers to have a higher degree of confidence before chosing to S+F! Rotate cops off of S+F if their ratio is bad! Provide more training on differentiating between suspicious and atypical behavior! Provide pay incentives for good ratios! Similar remedies could be imagined for a ratio below the target (not volumes, ratios!).&lt;/p&gt;&#xA;&lt;p&gt;These are all specific recommendations to a very general and very hard problem: how do you improve the results (say S+F ratio) of a blackbox system (such as the brain of an officer) that can&amp;rsquo;t be reliably inspected? &lt;strong&gt;You define a cost function, and instruct the system to self-optimize&lt;/strong&gt;. Officers know how to police far better than I (or most judges) do. Rather than defining a set of operational rules (that would be near impossible to enforce or evaluate) for how an officer should decide whether to perform a S+F, I&amp;rsquo;d rather we be honest about the aggregated harms of over or under stopping, and encode our relative thoughts about both in a function that can then be actualized by the experts.&lt;/p&gt;&#xA;&lt;p&gt;More broadly, re-reading &lt;em&gt;Terry&lt;/em&gt; I&amp;rsquo;m reminded that cases are instructive, but single-case rulings will typically miss the rights of people outside of the case. This has me thinking about a ton of topics: incremental rights and incremental infringement, actor driven optimization, and the boundaries of case law for achieving social justice.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Sniff</title>
      <link>https://grady.dev/projects/sniff/</link>
      <guid isPermaLink="true">https://grady.dev/projects/sniff/</guid>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>privacy</category>
      <category>writing</category>
      <category>government</category>
      <description>Why Florida v. Harris should be the minimum bar for surveillance</description>
      <content:encoded>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: I wrote this essay many years ago. The evolution of technology over the early 2020s has changed my perspective on some of the ideas presented in this post.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In &lt;em&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Florida_v._Harris#Decision&#34;&gt;Florida v. Harris&lt;/a&gt;&lt;/em&gt; (2012) a unanimous Supreme Court held that statistically derived evidence of efficacy of a drug sniffing dog was not a requirement for establishing probable cause for evaluating fourth amendment claims. I think this misses the mark from one of my favorite cases &lt;em&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/United_States_v._Place&#34;&gt;US v. Place&lt;/a&gt;&lt;/em&gt; (1983), in which O&amp;rsquo;Connor issued this gem of straightforward and balanced reasoning:&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;A &amp;ldquo;canine sniff&amp;rdquo; by a well-trained narcotics detection dog, however, does not require opening the luggage. It does not expose noncontraband items that would otherwise remain hidden from public view, as does, for example, an officer&amp;rsquo;s rummaging through the contents of the luggage. Thus, the manner in which information is obtained through this investigative technique is much less intrusive than a typical search. Moreover the sniff discloses only the presence or absense of narcotics, a contraband item. Thus, despite the fact that the sniff tells the authorities about the contents of the luggage, the information obtained is limited. &amp;hellip; We are aware of no other investigative procedure that is so limited both in the manner in which the information is obtained and in the content of the information revealed by the procedure.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;I really like this passage both because it provides an aspirational goal for law-enforcement, and because it articulates a clear requirement: that the decision procedure used must be found to be accurate to be reasonable (a fact not contended at the Supreme Court, but critical to O&amp;rsquo;Connor&amp;rsquo;s reasoning.) It&amp;rsquo;s worthwhile extracting a few lessons from the court&amp;rsquo;s reasoning in considering the design of what makes a dog&amp;rsquo;s nose, in contrast to most digital technology, such a satisfying balance of rights and state interests.&lt;/p&gt;&#xA;&lt;p&gt;A key consideration that the court tangentially addresses in &lt;em&gt;Place&lt;/em&gt; is that of &lt;em&gt;statistically derived reliability&lt;/em&gt; as assessed through false-positive rate. There must be some threshold of false positive/negative at which a search becomes unjustified (or at which the decision procedure falls out of constructive use toward totality of the circumstances). This is easy to see in the case of a drug sniffing dog because we have no other means by which to reason about the dog&amp;rsquo;s judgement. Outcomes are all that we get to see for a dog, so the question of &amp;ldquo;well-trained&amp;rdquo; is a throwaway line, rather than a core holding.&lt;/p&gt;&#xA;&lt;p&gt;This ties into my thoughts on &lt;a href=&#34;https://grady.dev/projects/terry/&#34;&gt;Terry&lt;/a&gt;: a balancing act of competing harms in 4th amendment law can&amp;rsquo;t be effectively assessed by an individual case.&lt;/p&gt;&#xA;&lt;p&gt;Unfortunately we shed this common sense when answering the same questions about to human judgement. Judges are not blinded by the personhood and autonomy of the dog in evaluating it&amp;rsquo;s impact on competing rights claims. Dogs can&amp;rsquo;t perform post-hoc rationalization, a dog&amp;rsquo;s thought process cannot be interrogated by the law. There&amp;rsquo;s no sensible way of looking at probable cause (a question of prior knowledge) that relies solely on whether the dog is correct in their indication of drugs (knowledge derived after search).&lt;/p&gt;&#xA;&lt;p&gt;By talking about the dog&amp;rsquo;s perception in terms of accuracy, O&amp;rsquo;Conner implies that explanation is &lt;em&gt;not a necessary component of an acceptable test for a decision criterion that results in search or seizure&lt;/em&gt;. This is in stark contrast to the way that the court looks at officer discretion in Terry stops. In that case, because we can ask a human for an explanation, we put extensive weight on the explanation, without falling back or ever examining the far more compelling indication of rights-balancing - statistically derived accuracy.&lt;/p&gt;&#xA;&lt;p&gt;In &lt;em&gt;Harris&lt;/em&gt;, Kagan misses an argument about the dog that we should be making about any tool of law enforcement discernment (whether it is a drug sniffing dog, a thermal imager, or a cop&amp;rsquo;s judgement). All decision criteria used to inform choices of search and seizure should be held against a rights balancing framework that analyzes real world statistical performance. Human judgement is a force that is better inspected from the cold evidence of outcomes, rather than the squishy (and time-skewed) process of post-hoc rationalization.&lt;/p&gt;&#xA;&lt;p&gt;The second component that makes me love O&amp;rsquo;Connor and this decision is the concept of &lt;em&gt;targeted information isolation&lt;/em&gt;. A drug sniffing dog is processing information about a wide array of olfactory inputs, but only is expressing a verdict on a narrow set of targeted criteria. It&amp;rsquo;s likely that a dog can smell a wide array of contents in the baggage of passengers, but the only information it expresses is that of the query &lt;em&gt;does this bag contain drugs&lt;/em&gt;. This is supremely privacy preserving, because the only data that the system outputs (or even has the &lt;em&gt;capacity&lt;/em&gt; to output) is the question of interest, and the test is one the state has a compelling interest in. If dogs could talk, they could tell us a wide array of information about the contents of passerby&amp;rsquo;s suitcases. In that instance, the dog would serve as a broader means of surveillance than is proscribed by a legitimate law enforcement purpose. Good law enforcement tooling should fit this principle: limit the potential output of the system to the outcomes that are of explicit and compelling state interest.&lt;/p&gt;&#xA;&lt;p&gt;The third and final thought that &lt;em&gt;Place&lt;/em&gt; and &lt;em&gt;Harris&lt;/em&gt; bring up is the concept of interaction between tool and law. A consistent frustration for groups that try to combat stop-and-frisk policing is how officers adapt to court rulings about what constitutes articulable/reasonable suspcicion, and start to use that terminology in their reports. &amp;ldquo;The odor of Marijuana&amp;rdquo; is a powerful phrase. One additional (unarticulated) benefit of a drug dog (or more generally, a non-human system) is that it is more immune from this interaction pattern. Dogs will be biased by their training, but their individualized decisions are &amp;ldquo;individualized&amp;rdquo; in the words of &lt;em&gt;Terry&lt;/em&gt; in a way that human&amp;rsquo;s thought processes can never really be. An officer&amp;rsquo;s awareness of the law will always color both their decisions and how they describe their decisions. Man&amp;rsquo;s best friend does not suffer from either of these defects.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Narratives</title>
      <link>https://grady.dev/projects/narratives/</link>
      <guid isPermaLink="true">https://grady.dev/projects/narratives/</guid>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>privacy</category>
      <category>writing</category>
      <category>essay</category>
      <description>Thoughts on how privacy and identity are related.</description>
      <content:encoded>&lt;p&gt;I&amp;rsquo;ve started thinking about how to define privacy. Though I haven&amp;rsquo;t made any traction on that overall question, it&amp;rsquo;s helped me better understand the relationship between privacy and how we manufacture our identity.&lt;/p&gt;&#xA;&lt;p&gt;To avoid exclusively speaking in intellectualisms, I&amp;rsquo;ll describe the circumstances of my morning, which can illustrate the point I&amp;rsquo;m trying to make.&lt;/p&gt;&#xA;&lt;p&gt;I went out to get coffee. I usually make coffee at home, but my french press shattered, so  I ordered a new one and it was slated for delivery a few days ago. However, Amazon informed me that it was damaged in transit, and directed me to purchase a replacement if I still wanted it. I made that purchase, but the replacement wasn&amp;rsquo;t slated to arrive until tomorrow. Thus, to get my daily coffee, I walked myself and my dog to the closest McDonalds (a business I rarely frequent) to get a $1 medium coffee.&lt;/p&gt;&#xA;&lt;p&gt;On the way back, a bee started attacking my dog (for an unknown reason) without his knowledge: it was furiously trying to burrow under his fur to get at his skin. I couldn&amp;rsquo;t have that, so I set down the coffee on the sidewalk and swatted it away using my McDonalds receipt. The bee then directed it&amp;rsquo;s animus toward me, and I spent the remainder of the walk intermittently jogging, swearing and stopping to swat the bee off of myself or my dog, until we were safely back in the confines of my apartment, a pane of glass now between us and the angry insect. I sipped my medium coffee in triumph, my dog and I unscathed.&lt;/p&gt;&#xA;&lt;p&gt;Any subset of the facts above, taken without narrative or broader context could paint a picture that doesn&amp;rsquo;t fit with the narrative that I&amp;rsquo;ve just laid out.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A stranger who only observed me swatting at my dog&amp;rsquo;s fur could have mistaken my concern for abuse.&lt;/li&gt;&#xA;&lt;li&gt;A passing policeman who saw me flustered, erratically waving my arms about, swearing, and unpredictably sprinting may have interpreted these as signs of a mental crisis.&lt;/li&gt;&#xA;&lt;li&gt;McDonalds may have interpreted my  transaction as a sign of a newfound customer.&lt;/li&gt;&#xA;&lt;li&gt;Visa may have interpreted my purchase of two french presses in a week and a coffee at McDonalds as interest in further coffee goods and services.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The construction of each of those narratives could be supported by the same facts I used to create my own anecdote, but none are true. This is why privacy is related to narrative building.&lt;/p&gt;&#xA;&lt;p&gt;The activity that we engage in at each moment in our lives is a piece of information. These data are collected (both in our memories and by external observers) and used to construct narratives that form cohesive stories: what happened, what we want, and who we are. We construct our understanding and model of our&amp;quot;selves&amp;quot; by distilling the facts of our lives into a narrative that that forms our identity and the self that we project to others.&lt;/p&gt;&#xA;&lt;p&gt;The creation of data that occurs as you move through the world makes it easy for others to construct their own counter-narratives of your life. The more data that others have about your actions, the more convincing they can be in painting a picture of who you are. Even an external observer with perfect information about you might describe you differently than you would, either through the omission of information in their depiction, or by including information about you that that you omit from your own.&lt;/p&gt;&#xA;&lt;p&gt;Full information of this morning&amp;rsquo;s events could either paint me as a environmentally concerned animal lover, or a prodigal waster. I use a french press because it avoids the marginal waste of filters. However, I also did appear to purchase two french presses (wasteful), and my purchase of a McDonalds coffee demonstrates a willingness to use disposable cups. Perfect information paints a muddled profile, even though I would consider myself a staunch environmentalist.&lt;/p&gt;&#xA;&lt;p&gt;As this illustrates, there is a deep freedom in having control over your personal narrative, choosing the facts you consider to be illustrative of the person that you are. When you have the power and capacity to influence how others interpret and construe the data points that describe your existence, you have self ownership even in the external representations of you in the minds and systems of others.&lt;/p&gt;&#xA;&lt;p&gt;This is one reason privacy matters.&lt;/p&gt;&#xA;&lt;p&gt;Retailers collect information about your actions in order to construct a &amp;ldquo;consumer profile&amp;rdquo;, a dataset describing who you are as a consumer, what and when you like buy goods, how much cash and debt you hold, etc. Strangers use the information they can immediately glean about you from your external presentation to create a model of what they should expect from you, and how they should react to you. Law enforcement uses data about your criminal history, your zip code, your demography and your public actions to evaluate your likelihood of rule-breaking. Juries are fundamentally trying to decide which narrative best fits the facts presented in a trial. In each of these cases, data about your existence is used to construct a narrative over which you have no direct control. Certainly, you may be able to influence these portraits by deliberately changing your zip code, your purchasing habits or your external presentation, but doing so does not reclaim the authority over your reduction (your characterization in the mind of the officer, the stranger, or the database).&lt;/p&gt;&#xA;&lt;p&gt;In reality, our actions are not wholly consistent with any single narrative. Narratives are less information dense than the facts that go into producing them. The construction of a narrative is inherently a lossy compression - it distills aggregated data into a imperfect (though useful) abstraction. I&amp;rsquo;m certainly not arguing that all such constructions are bad, nor that each should be  within the full control of the person being described. But it seems important to identify that the more information about an individual in the minds, databases and metrics of others, the less power they hold over their identity, and in a way, their personhood.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Clock</title>
      <link>https://grady.dev/projects/clock/</link>
      <guid isPermaLink="true">https://grady.dev/projects/clock/</guid>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>writing</category>
      <category>love</category>
      <description>Something that is more than the sum of its parts can be reduced back to it.</description>
      <content:encoded>&lt;p&gt;&amp;ldquo;Let&amp;rsquo;s go say goodbye.&amp;rdquo;, &amp;ldquo;To the house?&amp;rdquo;, &amp;ldquo;To the house.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s dark inside, the fading day is blue, filtered in. The bathroom light a&#xA;contrasting a vibrant yellow as he goes for a final pee.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m glued to the wall, seeing the house spotless for the first time since it was&#xA;last a house.&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;d made it more. We&amp;rsquo;d chosen mismatched glasses, argued over the layout of the&#xA;couch, compromised, built furniture to accommodate the compromise. We had diner&#xA;parties, new food, guests, dogs, and sex. Just as we did, it grew, sprawled and&#xA;settled. It became more than the things we put in it.&lt;/p&gt;&#xA;&lt;p&gt;But things changed. We changed. What we needed and wanted and were changed. I&#xA;moved out. He finished the lease. And on the 30th, I came over, scrubbed&#xA;floorboards and toilets and when I looked up after a few hours, and loaded the&#xA;cars, and came in to say goodbye to a home, I didn&amp;rsquo;t find it in there.&lt;/p&gt;&#xA;&lt;p&gt;The only sound was from the only object - the clock hanging up where we&amp;rsquo;d&#xA;removed the nails that the last tenants haphazardly threw in. Me on a chair with&#xA;the back of a hammer, him with a bowl for the nails. Taking 60 out to put one in&#xA;for the clock.&lt;/p&gt;&#xA;&lt;p&gt;He came out of the bathroom, and I pointed out the clock. &amp;ldquo;I think we forgot&#xA;something.&amp;rdquo; &amp;ldquo;Do you want it?&amp;rdquo; &amp;ldquo;I think I like it being here-it fits the place.&amp;rdquo;&#xA;&amp;ldquo;Well it&amp;rsquo;s always nice to have a clock - if you don&amp;rsquo;t want it, can I take it?&amp;rdquo;&#xA;&amp;ldquo;Sure.&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;The clock kept ticking as he took it down. We closed windows, locked doors. Now,&#xA;sitting in my lit and full apartment all I can think about is how it must have&#xA;sounded as we closed the door and the ticking faded away.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>ABOUND.art</title>
      <link>https://grady.dev/projects/abound/</link>
      <guid isPermaLink="true">https://grady.dev/projects/abound/</guid>
      <pubDate>Mon, 27 Nov 2023 08:49:31 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>algorithms</category>
      <category>websites</category>
      <category>tools</category>
      <description>A platform for anyone to make gorgeous art</description>
      <content:encoded>&lt;p&gt;I like to build algorithmic art. The piece of it I find the most satisfying is&#xA;the tinkering. You create some code to create an image from some settings, and&#xA;then you play around with the settings to find the most satisfying combinations&#xA;of inputs. This process isn&amp;rsquo;t technical, it&amp;rsquo;s just an expression of pure&#xA;exploration and aesthetic judgement.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/abound_3.png&#34; alt=&#34;A fun squiggly line for a &#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;To allow everyone the joy of this kind of tinkering and discovery, a friend and&#xA;I built ABOUND.art - a platform for generative art. Anyone can upload an&#xA;algorithm, and then anyone else can play around with it, no code needed.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/abound_2.png&#34; alt=&#34;An example input form where a user could tinker with an algorithm called ruffle.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;We spent ~6 months part time working on it, and solved a plethora of hard&#xA;problems. We figured out how to run untrusted code cheaply. We figured out how&#xA;to build generic multipart forms. We figured out a cost structure to make sure&#xA;we didn&amp;rsquo;t hemorrhage money, and we built a lot of cool art.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/abound_1.png&#34; alt=&#34;An &amp;ldquo;explore&amp;rdquo; page on the abound site.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The platform didn&amp;rsquo;t take off in large part because we aren&amp;rsquo;t great at the stuff&#xA;outside of building. Marketing and self promotion are not our strengths.&#xA;Eventually, we gave up trying to make it happen, and just celebrated it for what&#xA;it was: a gorgeous thing that we built and loved to use.&lt;/p&gt;&#xA;&lt;p&gt;The site is still live, and you can explore and access it at&#xA;&lt;a href=&#34;https://abound.art&#34;&gt;https://abound.art&lt;/a&gt;. Check out the instructions&#xA;&lt;a href=&#34;https://abound.art/about&#34;&gt;on the about page&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Happy tinkering!&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Focus on Features</title>
      <link>https://grady.dev/projects/fof/</link>
      <guid isPermaLink="true">https://grady.dev/projects/fof/</guid>
      <pubDate>Mon, 27 Nov 2023 08:49:31 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>government</category>
      <category>online spaces</category>
      <description>A resource for regulators and product managers to minimize digital harms</description>
      <content:encoded>&lt;p&gt;When I worked in Counter-Abuse at Google, I found the largest issue we faced&#xA;wasn&amp;rsquo;t malicious users, but poorly thought out product decisions, and the&#xA;constraints that the business model placed on what we could do to keep users safe.&#xA;It&amp;rsquo;s very hard to clean up a kitchen if you&amp;rsquo;re only empowered&#xA;to mop, rather than trying to understand or change why things keep spilling on the floor.&lt;/p&gt;&#xA;&lt;p&gt;So when the Integrity Institutute (a small thinktank on content moderation issues,&#xA;which I&amp;rsquo;ve been a member of for several years) sent out applications for visiting&#xA;fellowships, I figured it was my chance to try to do something about it. I built a&#xA;resource for product managers and regulators to think through the connections between&#xA;harms they see on platforms, and the features that enable that harm, and the set of&#xA;changes that could minimize that connectivity.&#xA;The best explanation I have is the &lt;a href=&#34;https://fellowship.ii.grady.dev/about/why&#34;&gt;&amp;ldquo;Why I built this&amp;rdquo; recursive essay here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/fof_1.png&#34; alt=&#34;The &amp;ldquo;Self-Harm amplification&amp;rdquo; page on the FOF website.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The site as a whole took a while to build because there was just a lot of writing to do.&#xA;As of this writing, there are 14 intervention categories, 47 harms, 64 interventions, and 9 features.&lt;/p&gt;&#xA;&lt;p&gt;The project ultimately became a group project of the Integrity Institute. Because of that&#xA;every page needed to be fully-editable by a nontechnical audience, which presented a fun set of technical&#xA;challenges.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/fof_3.png&#34; alt=&#34;The editing menu the FOF website.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The technical elements of this project are pretty slick. It&amp;rsquo;s backed by a postgres&#xA;database running on neon.tech, which connects to Strapi, an open source CMS.&#xA;The frontend is made in Nuxt 3 with typescript, and then hosted via firebase cloud functions.&lt;/p&gt;&#xA;&lt;p&gt;However, that&amp;rsquo;s the editing-path. Since the content is static, I set up SSG to&#xA;pre-create every page on the site, and then back-hydrate with a flat file after&#xA;first load. So the page as a whole is incredibly snappy, and costs nothing to host&#xA;since it&amp;rsquo;s just flat files for almost everyone using it, and scale-to-zero for editors.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve gotten more traction on this project than I expected - it&amp;rsquo;s started many conversations&#xA;with PMs, regulators, and other thinktanks, and still (years later) has a steady&#xA;stream of traffic, mostly from the EU.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/fof_2.png&#34; alt=&#34;A filter view tailored for folks trying to find the most helpful/least costly interventions&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Browse for yourself &lt;a href=&#34;https://features.integrityinstitute.org&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Wingspan Deck Generation</title>
      <link>https://grady.dev/projects/wingspan/</link>
      <guid isPermaLink="true">https://grady.dev/projects/wingspan/</guid>
      <pubDate>Mon, 27 Nov 2023 08:49:31 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>birds</category>
      <category>tools</category>
      <category>gifts</category>
      <description>Learn about the birds in your local area through a game</description>
      <content:encoded>&lt;p&gt;One of my favorite board games is Wingspan - an engine building game&#xA;where you collect different species of birds. The game instilled an appreciation&#xA;for our avian friends in me, and was my introduction to the wonderful world of birding.&lt;/p&gt;&#xA;&lt;p&gt;As anyone who loves something desperately, the flaws in the wingspan game were more&#xA;obvious to me than to most. The nest types were often incorrect. The clutch sizes capped&#xA;out at six. Some of the powers within the game were too much, others were too little. The&#xA;maps only showed their geographic proximity in terms of continents.&lt;/p&gt;&#xA;&lt;p&gt;Most importantly, the birds were from all across the world, making them not very useful&#xA;for fine-tuning your skills on your local bird populations. I can&amp;rsquo;t tell you the number&#xA;of times I thought I saw a Dunnock in Colorado, only to learn much later that they&amp;rsquo;re only&#xA;found in Europe! I needed to have a wingspan deck that just had my local birds in it, so I&#xA;could become an expert at identifying at home.&lt;/p&gt;&#xA;&lt;p&gt;So I coded.&lt;/p&gt;&#xA;&lt;p&gt;And I coded.&lt;/p&gt;&#xA;&lt;p&gt;And I coded.&lt;/p&gt;&#xA;&lt;p&gt;Too.&lt;/p&gt;&#xA;&lt;p&gt;Much.&lt;/p&gt;&#xA;&lt;p&gt;Code.&lt;/p&gt;&#xA;&lt;p&gt;I had to build infrastructure&#xA;for scraping sites which were hostile to it (sorry Cornell ornithology lab, All About Birds, Avibase,&#xA;and others). I built infrastructure for coorelating sources, only including a fact like a wingspan&#xA;in the deck if it could be corroborated between two sources to within 10%. I built infrastructure&#xA;for finding creative-commons licensed images of the birds, AI to find the bird in the image and crop it&#xA;well, and build complicated infrastructure for&#xA;keeping detailed records of sources and methods, both for debugging, and appropriate attribution.&#xA;So far I&amp;rsquo;ve written 39k lines of code to tackle this problem.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wingspan_1.png&#34; alt=&#34;A card of an American Golden Plover, generated by the first generation of my code.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve now gone through three generations of these cards, and they&amp;rsquo;ve changed over time significantly&#xA;in response to play-test feedback from my friends and family.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wingspan_2.png&#34; alt=&#34;A card of a Blue-headed Vireo, generated by my code.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;In the third generation of the cards, I started to use AI to generate the images, both because finding good images in the creative commons is hard, and because the uniform style lended itself to it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wingspan_3.png&#34; alt=&#34;A card of a Blue-headed Vireo, generated by my code + generative AI.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I expect this project will never be fully done. There are too many small things I&amp;rsquo;d like to improve.&#xA;Instead, I suspect I&amp;rsquo;ll continue to make small changes every six-ish months when I gift a deck to a&#xA;friend.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Advice for new SWEs</title>
      <link>https://grady.dev/projects/advice/</link>
      <guid isPermaLink="true">https://grady.dev/projects/advice/</guid>
      <pubDate>Thu, 01 Jun 2023 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>education</category>
      <category>writing</category>
      <category>labor</category>
      <description>My recommendations for folks starting (or considering) a career as a software engineer</description>
      <content:encoded>&lt;p&gt;In my time as a SWE I&amp;rsquo;ve been lucky to get the chance to mentor a large number&#xA;of folks as they start their careers in software. Over that time, I&amp;rsquo;ve picked up&#xA;on some trends - habits, mindsets, and tactics that lead to growth as a SWE, and&#xA;common patterns that lead people astray.&lt;/p&gt;&#xA;&lt;p&gt;I also frequently run into folks who have an interest in software engineering,&#xA;but have a hard time envisioning a path for themselves within the industry. It&amp;rsquo;s&#xA;a crowded market of opinions, and it&amp;rsquo;s hard for someone without much experience&#xA;in the field (or a trusted guide) to discern where they should spend their time,&#xA;what they need to know, or even what the job is actually like.&lt;/p&gt;&#xA;&lt;p&gt;So, I decided to write up a document to try to make it a smaller lift to share&#xA;some basic advice with friends and acquaintances in this situation.&lt;/p&gt;&#xA;&lt;p&gt;I wrote the first draft of it when a friend came to me with some questions about&#xA;the field in mid-2023. Since then, I&amp;rsquo;ve reused it with about a dozen folks,&#xA;revising it each time to be shorter, more precise, and trying to keep it up to&#xA;date. My agreement with anyone I send it to is that they have to tell me where&#xA;they think it is unclear, imprecise, or inaccurate - their feedback is the only&#xA;way it can improve.&lt;/p&gt;&#xA;&lt;p&gt;Feel free to forward it to folks, or leave comments or suggestions - it&amp;rsquo;s&#xA;globally suggestable. I would be curious to hear what other folks (both&#xA;experienced and not) think of it, and I hope to continue to have it evolve as a&#xA;resource for new SWEs.&lt;/p&gt;&#xA;&lt;p&gt;You can find it at &lt;a href=&#34;https://grady.dev/advice&#34;&gt;https://grady.dev/advice&lt;/a&gt;.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>GoLog</title>
      <link>https://grady.dev/projects/golog/</link>
      <guid isPermaLink="true">https://grady.dev/projects/golog/</guid>
      <pubDate>Tue, 12 Jan 2021 15:15:13 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>tools</category>
      <description>a visual post-hoc logger for golang</description>
      <content:encoded>&lt;p&gt;I&amp;rsquo;ve been writing a lot more golang of late, so I wrote a (gorgeous) visual debugger for helping to do post-hoc debugging. It&amp;rsquo;s been hugely helpful in my lambda based projects, where one often wants the ability to quickly view &amp;ldquo;what happened during this trace&amp;rdquo; without running locally with a traditional step based debugger.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://raw.githubusercontent.com/gbdubs/golog/master/golog-stack-trace.png&#34; alt=&#34;A screenshot of the Golog interface for visual debugging&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Unlike many of my projects, this one is pretty well supported, and I&amp;rsquo;ve continued to add features as I need them.&lt;/p&gt;&#xA;&lt;p&gt;You can check it out &lt;a href=&#34;https://github.com/gbdubs/golog&#34;&gt;on github here&lt;/a&gt;.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Creditworthy</title>
      <link>https://grady.dev/projects/creditworthy/</link>
      <guid isPermaLink="true">https://grady.dev/projects/creditworthy/</guid>
      <pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>privacy</category>
      <category>books</category>
      <category>writing</category>
      <description>Thoughts on how Josh Lauer’s book “Creditworthy” can help us renegotiate the surveillance social contract.</description>
      <content:encoded>&lt;p&gt;I just finished reading &amp;ldquo;Creditworthy&amp;rdquo;, Josh Lauer&amp;rsquo;s thorough picture of the&#xA;history and trajectory of consumer surveillance by the credit industry.&lt;/p&gt;&#xA;&lt;p&gt;Lauer&amp;rsquo;s work illuminates the early evolution of the social contract at the heart&#xA;of the information era: convenience, service, and social inclusion in exchange&#xA;for privacy. Though this exchange is familiar to a twenty first century reader,&#xA;details from the evolution of this contract (in the context of credit) offer us&#xA;lessons as we seek to broadly re-negotiate the terms of our privacy forfeitures&#xA;in all spheres of modern life.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;strong&gt;first&lt;/strong&gt; lesson is that information is unlike other commodities in how it&#xA;is collected, synthesized and deployed, and regulations that sought to ensure&#xA;its responsible custodianship in the context of credit failed to do so largely&#xA;because they ignored key properties of data that were under-appreciated at the&#xA;time of regulation:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Reproducibility&lt;/strong&gt;: Data can be copied any number of times, at close to zero&#xA;cost, which creates an incentive for its infinite duplication and&#xA;dissemination. Once a piece of data about an individual is collected, we&#xA;should expect that market forces will drive the collecting actor to share or&#xA;sell it broadly and without restraint.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Supra-Summative&lt;/strong&gt;: Data is more identifying, valuable and intrusive the more&#xA;of it that can be accessed and combined by any given actor. Linking two&#xA;datasets together routinely produces more value than the two datasets offer&#xA;when ingested and examined in isolation. The increasing returns to scale of&#xA;surveillance, synthesis and sale of information encourages &amp;ldquo;data-maximalism&amp;rdquo;,&#xA;the indiscriminate and unabashed collection of data in all spheres of life.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Opacity&lt;/strong&gt;: Data can be used to predict outcomes (such as default rate)&#xA;without offering explanations as to why the data is an indicator of the&#xA;outcome. This, in concert with the reality of dense correlations in all&#xA;factors of life, confounds efforts to root out social injustice buried in&#xA;Black-Box algorithms. Racism, sexism and ableism all still exist in credit&#xA;scoring despite the prohibition on the explicit consideration of race, sex or&#xA;ability. The same problems that plagued credit interpretation in the 1970&amp;rsquo;s&#xA;are compounded in today&amp;rsquo;s deep learning algorithms, where nobody understands&#xA;what inferences the system uses to draw its conclusions, even though the&#xA;system may be able to consistently predict reality.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The &lt;strong&gt;second&lt;/strong&gt; lesson is that privacy is rarely taken, it is almost always&#xA;traded away, primarily for convenience, service, and social inclusion. In the&#xA;early days of credit reporting, personal information was relinquished in&#xA;exchange for the convenience of deferring payment on purchased goods to a later&#xA;date. As credit surveillance evolved, even purchasing goods in cash at many&#xA;retailers was recorded for use in credit evaluation - mere access to the service&#xA;demanded the forfeiture of personal data. Later, credit reports were (and are)&#xA;used in job and rental applications, and even social club membership, clearly&#xA;demonstrating that ceding control over one&amp;rsquo;s information was (and is) necessary&#xA;for full participation in society.&lt;/p&gt;&#xA;&lt;p&gt;Today we have to grapple with more totalizing and transparent exchanges of&#xA;privacy, but the same benefits of convenience, service and social inclusion are&#xA;still the weights on the scale opposite privacy. TSA PreCheck offers the&#xA;convenience of shorter airport security lines in exchange for detailed histories&#xA;of your living arrangements, known connections and travel data. Department&#xA;stores use sophisticated IMEI tracking to pinpoint your location while you enjoy&#xA;the service of browsing in their stores. Social networks and ad providers siphon&#xA;up your digital detritus as you browse the internet in order to offer more&#xA;relevant (and lucrative) ads. The tools requisite for living and working&#xA;productively in the 21st century (email, chat, search, maps, and connectivity)&#xA;can easily become tools of surveillance when requested by law enforcement. Full&#xA;participation in 21st century society requires capitulation to surveillance.&lt;/p&gt;&#xA;&lt;p&gt;Though the inevitable arc of credit surveillance presented by Lauer can be&#xA;disheartening, the book also helped me recognize that we may be able to bend the&#xA;world back toward privacy.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;strong&gt;third&lt;/strong&gt; lesson is that Americans do care about privacy. &amp;ldquo;Creditworthy&amp;rdquo; is&#xA;sprinkled with anecdotes about people recognizing the ills of mass-surveillance&#xA;and acting (both as individuals and in collectives) to mitigate its harms. Our&#xA;moral intuition speaks clearly when we are asked whether an individual should be&#xA;able to live down past mistakes, whether personal information should be given&#xA;basic protections, and whether corporations should be allowed to collect data&#xA;for a one purpose and use it for another. Privacy is an integral component of&#xA;freedom, and Americans across the political spectrum throughout our nation&amp;rsquo;s&#xA;history have had the moral wisdom to fight against encroachments on both.&lt;/p&gt;&#xA;&lt;p&gt;Though we frequently forfeit our information in transactions large and small,&#xA;this does not indicate a lack of resistance to the intrusions of surveillance&#xA;into our lives. It is largely rational for a consumer to forfeit information&#xA;when individual transactions are viewed at the margin, as the harms from such&#xA;forfeitures are smeared across all such transactions and their costs are&#xA;impossible to predict. This asymmetry in immediate known marginal benefit&#xA;against abstract high-variance cost helps explain the dissonance between our&#xA;apparent docility as willing consumers and our appetite for institutional change&#xA;as privacy concerned Americans.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;strong&gt;fourth&lt;/strong&gt; lesson is also a hopeful one. Regulation heavily shaped the&#xA;consumer credit industry, and it could influence the shape, scope and intrusions&#xA;of the information economy in the future. The use of credit scoring in federal&#xA;loan screening in the 1960&amp;rsquo;s led to the ascension of algorithms over individual&#xA;intuition within credit offices. When the first regulations were placed on&#xA;credit bureaus in the early 1970&amp;rsquo;s, a waterfall of rapid consolidation resulted.&#xA;Civil rights regulation in the 1980&amp;rsquo;s was able to eliminate much of the explicit&#xA;discrimination on problematic grounds in credit ratings.&lt;/p&gt;&#xA;&lt;p&gt;Though these efforts are sprinkled with as many half-successes as half-failures,&#xA;they all demonstrate the power that regulation has over the information economy,&#xA;and leads me to be hopeful that well structured regulations could allow our&#xA;country to renegotiate the social contract underlying the information age.&lt;/p&gt;&#xA;&lt;p&gt;Creditworthy is a fantastic book. Lauer paints historical details large and&#xA;small with explanation and context, illuminating not only how our present world&#xA;came to be, but the individual and collective incentives and choices that got us&#xA;here. In it I read a history of mass surveillance and a path toward restoring&#xA;balance, but another reader could just as easily find compelling evidence for&#xA;the strength of American capitalism and ingenuity, or the disruptive influence&#xA;of technology. I&amp;rsquo;m sure that it will hold up to multiple readings.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Raison d&#39;être: le chien</title>
      <link>https://grady.dev/projects/dogs/</link>
      <guid isPermaLink="true">https://grady.dev/projects/dogs/</guid>
      <pubDate>Wed, 01 Jan 2020 00:00:00 +0000</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>love</category>
      <category>essay</category>
      <category>writing</category>
      <description>My search for (and approximate answer to) the big questions</description>
      <content:encoded>&lt;p&gt;As a middle-schooler untethered from proscribed answers (I was raised without&#xA;any connection to, or real awareness of religion), I dreaded the few dark&#xA;minutes between bedtime and sleep. I&amp;rsquo;d zoom back from myself - the practiced&#xA;lens of the NOVA documentaries that I loved at that age - losing myself in the&#xA;big questions, the vastness of space, and the darkness in front of my eyes: Why&#xA;was I here? Would my short, finite life mean anything? What could meaning be in&#xA;such a large empty universe?&lt;/p&gt;&#xA;&lt;p&gt;Folks tend to have one of three relationships to the hardest questions: (a)&#xA;belief in the answers of others, (b) avoidance, or (c) fixation. I was (c) all&#xA;the way. For me, as for many others, the unimaginable scale of the universe was&#xA;the fertile ground for existential dread in the same way that it served as a&#xA;crucible for life: as an inevitable consequence of selective pressure. I&#xA;struggled with this set of questions for a long time - middle school, high&#xA;school, even parts of college. I was constantly trying (and constantly failing)&#xA;to convince myself of the less grim answers to these unavoidable questions. I&#xA;didn&amp;rsquo;t want to be a nihilist, but I couldn&amp;rsquo;t find a reason not to be.&lt;/p&gt;&#xA;&lt;p&gt;Eventually I discovered another, one that I find much more convincing, robust,&#xA;and comprehensive. &lt;strong&gt;The key for me was dogs.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;As a kid, while I&amp;rsquo;d happily cross the street to pet a friendly dog, yips from&#xA;coyotes could make my skin crawl with fear. These two canines are closely&#xA;related, so how did my differential reaction come to be? It&amp;rsquo;s simple: previous&#xA;generations took something hazardous (wolves, coyotes, wild dogs), and through&#xA;the successive application of effort of hundreds of thousands of humans, over a&#xA;timeline of centuries, &lt;em&gt;they produced a world that was better&lt;/em&gt;, both for me, and&#xA;most of the people alive today. They made a world of labs and corgis and&#xA;doodles, molded from one of wolves. That is remarkable. &lt;strong&gt;Only human effort&#xA;engineered man&amp;rsquo;s best friend&lt;/strong&gt; - mine is resting his head on my knee as it&#xA;bounces from the keystrokes. He is lightly annoyed by the jostling, but happy to&#xA;be close to me. I am happy to be close to him, too.&lt;/p&gt;&#xA;&lt;p&gt;The seed of this observation (dogs - wolves = human effort) sprouted two&#xA;perspectives within me.&lt;/p&gt;&#xA;&lt;p&gt;The first is an overwhelming gratitude - for the dog snuggled on this couch, for&#xA;the house I did not build, wire or plumb, for the marvels of the&#xA;internationalized economy that makes everything I&amp;rsquo;ll ever own possible, for a&#xA;social and economic system that enables freedom and growth, and for the layer&#xA;cake of open-sourced software that comprises technological life. To be literal,&#xA;I thank the ancestors - the literal people, who stone by brick by plank by beam&#xA;by wire by chip by package imagined, designed, collaborated and built world&#xA;after successive world where their children could live better than they could.&#xA;To be figurative, I see a knotted, divergent quilt stretches back toward a hazy&#xA;horizon - each patch forged by the sweat of people like me - most patches making&#xA;things incrementally better for the builders of the next one - most tightly&#xA;woven into their neighbors. When I fixate too much on this visualization it can&#xA;routinely make my cry (the only other thing that can is pondering the limited&#xA;lifespan of my dog). My gratitude overwhelms me. I did nothing to inherit a&#xA;comfortable world, nor anything to deserve this dog. What gifts!&lt;/p&gt;&#xA;&lt;p&gt;The second perspective is a grim responsibility. The world as it has been handed&#xA;to us is a bounty: in technologies, in goods, in liberties, in kindnesses. On a&#xA;societal level, this inheritance is both finite and brittle. Without effort,&#xA;without collaboration, without shared purpose, without selflessness, we may yet&#xA;squander it, rather than adding to it. On a personal level, it is easy to feel&#xA;useless.&lt;/p&gt;&#xA;&lt;p&gt;The gravity of this perspective is daunting, but grounding. I see the people in&#xA;my life affixing their patches all the time. A doctor cares for the elderly, a&#xA;scientist studies a disease, a construction worker builds a home, a lawyer tries&#xA;to right an injustice, a couple starts a family. I see it in others too: a&#xA;father decides to break the cycle of abuse he was caught in. An engineer shares&#xA;their new idea with the world. A neighbor invites their neighbors over for&#xA;dinner. A teacher bears hardship for their pupils. There are a million ways to&#xA;serve one another, and every day, people do them. It&amp;rsquo;s quiet. It&amp;rsquo;s everywhere.&#xA;It&amp;rsquo;s in our nature. The impulse to help, to build, to share, is our social&#xA;fabric - it&amp;rsquo;s why we&amp;rsquo;re here. It&amp;rsquo;s why we matter.&lt;/p&gt;&#xA;&lt;p&gt;This idea calms my restless mind at night, and informs my career, my&#xA;relationships, and my choices. While it doesn&amp;rsquo;t proscribe action, it is an&#xA;unmistakable clarion: &lt;strong&gt;do good for the present and the future, you owe it to&#xA;the past&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;p&gt;So, what will you do? What little patch will you affix to this great quilt? What&#xA;do you owe the past? What can you offer to the present? What will you promise&#xA;the future?&lt;/p&gt;&#xA;&lt;p&gt;Or said another way, how will you (how could any of us) possibly repay the&#xA;greatest gift, man&amp;rsquo;s best friend?&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Widmanstätten pattern</title>
      <link>https://grady.dev/projects/widmanst%C3%A4tten/</link>
      <guid isPermaLink="true">https://grady.dev/projects/widmanst%C3%A4tten/</guid>
      <pubDate>Tue, 24 Sep 2019 18:17:56 -0600</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>physics</category>
      <category>tools</category>
      <description>Meteorites are beautiful - I learned some chemistry</description>
      <content:encoded>&lt;p&gt;When visiting the Smithsonian Natural History Museum, I saw the inside of a meteorite, stained and polished to reveal a beautiful pattern. Several months later, I remembered it while looking through some photos and decided to learn more about it and try to reproduce it.&lt;/p&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s what I learned from &lt;a href=&#34;https://en.wikipedia.org/wiki/Widmanst%C3%A4tten_pattern&#34;&gt;Wikipedia&lt;/a&gt;: The meteorites that display this pattern are comprised of of two Iron-Nickel alloys, Kamacite and Taenite. This pattern is found in metiorites called Octahidrites, so named because the pattern is actually a result of a crystal structure of Taenite&amp;rsquo;s crystal latice, which is hexoctahedral (cubic) in structure. The pattern generated when such a crystal is sliced along a &amp;ldquo;face&amp;rdquo; of the crystal is the Widmanstätten pattern, but cut along different axes you will see different patterns (a square equivalent to the Widmanstatten, or just chaotic beauty if not at a multiple of 15 degrees). Wikipedia&amp;rsquo;s image here speaks a thousand words:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/cutting_the_octaedron.png&#34; alt=&#34;Cutting the octaedron.png&#34;&gt;&#xA;(Source Davide Bolsi - Different cuts of the octaedron produces different kinds of Widmanstätten patterns. CC BY-SA 3.0, unedited, Created 9 June 2008, &lt;a href=&#34;https://en.wikipedia.org/wiki/Widmanst%C3%A4tten_pattern#Shape_and_orientation&#34;&gt;https://en.wikipedia.org/wiki/Widmanst%C3%A4tten_pattern#Shape_and_orientation&lt;/a&gt;)&lt;/p&gt;&#xA;&lt;p&gt;So I tried to simulate this, with some mixed effects!&lt;/p&gt;&#xA;&lt;p&gt;It took me a long time to figure out how to render it (ended up using polygon intersections using Java&amp;rsquo;s euclidean threed library with raw writing to pngs with the results). Also took me a long time to debug all 35 major bugs in my code (I kept track after I started getting rendered output to show the progression, maybe a topic for another post!). The end results are below:&lt;/p&gt;&#xA;&lt;p&gt;An face cut, producing the iconic Widmanstätten pattern. &lt;img src=&#34;https://grady.dev/img/wid_face_cut.png&#34; alt=&#34;A Square Cut&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;A square cut, producing the less iconic (but verifying) crosshatch pattern. &lt;img src=&#34;https://grady.dev/img/wid_square_cut.png&#34; alt=&#34;A Square Cut&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;But I didn&amp;rsquo;t think these captured the 3D crystal aspect of the project, so I also animated a plane passing through the crystal perpendicular to the face cut: &lt;img src=&#34;https://grady.dev/img/wid_face_cut_go_thru.gif&#34; alt=&#34;A Square Cut Pass Through&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;And animated rotations (aligned with the square and face cuts) that rotate through all the other angles perpendicular ot the face or square cuts. This helps you see the patterns align with the cut angle and then unalign at values that aren&amp;rsquo;t multiples of 15.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wid_square_cut_rotated.gif&#34; alt=&#34;A Square Cut Animated Rotating&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/wid_face_cut_rotated_animated.gif&#34; alt=&#34;A Face Cut Animated Rotating&#34;&gt;&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Shoe Rack 2</title>
      <link>https://grady.dev/projects/shoe_rack_2/</link>
      <guid isPermaLink="true">https://grady.dev/projects/shoe_rack_2/</guid>
      <pubDate>Mon, 04 Mar 2019 19:27:45 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>crafts</category>
      <category>gifts</category>
      <category>design</category>
      <description>A shoe rack made as a gift - that had to fit in a suitcase</description>
      <content:encoded>&lt;p&gt;After seeing the shoe rack I made for my partner, my sister asked for one for her apartment as a&#xA;Christmas gift. More precisely, I asked her what I could make her and she allowed me to make another&#xA;shoe rack.&lt;/p&gt;&#xA;&lt;p&gt;The major design constraint on this project was that the end result had to be transported from Colorado to Pennsylvania, which as I figured out by looking at shipping costs, would be fairly significant if the piece was fully assembled when shipped. I happened to have some old luggage lying around, and came up with the idea of designing the rack to collapse and fit inside of a suitcase.&lt;/p&gt;&#xA;&lt;p&gt;Unlike other projects I&amp;rsquo;ve worked on, this one was fun primarily because of how much went &lt;em&gt;wrong&lt;/em&gt;. I mismeasured/miscounted a half a dozen times. I got snowed in and couldn&amp;rsquo;t go out to get a drill press vice. I ultimately built something that was too dense to put shoes on (until I made some modifications). Despite all of these little hiccups, what I love about woodworking shone through - I was able to overcome most of the hurdles placed by my lack of foresight, and produce something that was still interesting, beautiful and functional.&lt;/p&gt;&#xA;&lt;p&gt;Finished photo first, obviously.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_0_.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_1.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_2.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_3.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_4.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_5.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_6.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_7.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_8.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_9.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_10.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_11.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_12.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_13.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_14.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_15.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_16.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_17.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_18.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_19.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2_20.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Shoe Rack</title>
      <link>https://grady.dev/projects/shoe_rack/</link>
      <guid isPermaLink="true">https://grady.dev/projects/shoe_rack/</guid>
      <pubDate>Thu, 30 Aug 2018 19:59:14 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>crafts</category>
      <category>gifts</category>
      <category>design</category>
      <description>A simple and fun shoe rack that fits exactly 3x4 pairs of shoes</description>
      <content:encoded>&lt;p&gt;My partner and I really both like building things, which makes anniversaries both an occasion for expression of caring through mutal gift giving, and a bit of a self-indulgent excuse to carve out time to make stuff. It only took him noting once that the width of our shoe rack was exactly 2.5 shoes for me to think through how I could build something better.&lt;/p&gt;&#xA;&lt;p&gt;Over weeks of sketches, a trip to IKEA, and a trip to John Houston&amp;rsquo;s Kennebunkport workshop (unrelated), I was inspired by the idea of sneaky intersections - of furniture that has non-standard joints and that provides standard functionality in non-standard ways.&lt;/p&gt;&#xA;&lt;p&gt;Planes are the foundation of furniture, but the way they are constructed is usually unimaginative. This idea was to try to construct planes through convoluted connections that rely on planning (rather than clear joints) to accomplish the surfaces on which the shoes would rest. This would be in contrast to the dominant feature of the rack - an elegant top portion of wood that would be both planar, simple and elevated above the constructed planes below.&lt;/p&gt;&#xA;&lt;p&gt;Finished photo first, obviously.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_0.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I bought a bunch of pine because apparently it was purported easy to work with and cheap. After compleing this project I can affirm both of these characteristics.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_1.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;First step was cutting the pieces to length. Lots and lots of this.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_2.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Next was sanding. Each prisim has 6 planes and 12 edges that all needed sanding. This, in combo with 30 pieces of wood meant 540 sanding planes/lines&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_3.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The oscillating sander takes a lot of the brunt of this project. My hands got a nice massage though! Went through three disks like this one.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_4.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Assembling the first set of three rungs of the rack.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_5.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;All three assembled rungs.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_6.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;It took me a while to figure out how to attach these to the top. This was probably where I spent like 1 day in the garage scribbling. This is the start of me prototyping what ended up being the solution.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_7.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Attached two vertical columns to the center most rung.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_8.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I made a relatively grave miscalculation with the way the three rungs were going to attach (hint, screws in perpendicular directions to each other can&amp;rsquo;t work). Instead I decided to do the attachment at random staggers. Turned out to be a good idea, but I executed it in the wrong order and had to do FAR too much manual hand-turning of screws.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_9.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Two rungs attached! In this photo you can see what my partner made for me - some lovely shuffleboard boards! This was past the anniversary because I wasn&amp;rsquo;t able to finish mine in time (due to an unfortunate concussion.)&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_10.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Attachers on the middle rung.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_11.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Rungs fully attached&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_12.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Initial attachment of the top (using hand screws and some pre drilled holes) looked like it was going well&amp;hellip;&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_13.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_14.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;What these photos miss, however, is how incredibly off center the result was! Solidly 5 degrees off of alignment.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_15.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_16.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Time to undo some skrews, and try again&amp;hellip;&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_17.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The prestain made the wood look GOREGOUS particularly on the top. Very happy.&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_18.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The stain turned this pine into a really gorgeous shade of maple. This is unfortunatley the only photo I have of it!&#xA;&lt;img src=&#34;https://grady.dev/img/shoe_rack_19.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Finished product!&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_20.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_21.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/shoe_rack_22.jpg&#34; alt=&#34;Shoe Rack Photo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;It nicely fits our shoes, though certainly not all of them (as we are shoe folk). My partner was quite happy with it, and I am too, despite its slight wobbles!&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Civil Grand Jury</title>
      <link>https://grady.dev/projects/cgj/</link>
      <guid isPermaLink="true">https://grady.dev/projects/cgj/</guid>
      <pubDate>Fri, 30 Mar 2018 17:35:15 -0700</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>government</category>
      <category>community</category>
      <description>San Francisco’s Civil Grand Jury</description>
      <content:encoded>&lt;p&gt;In it&amp;rsquo;s state constitution, California defines a unique institution for each&#xA;county called the &lt;em&gt;Civil Grand Jury&lt;/em&gt;, which is tasked with overseeing the&#xA;effectiveness and efficiency of the county&amp;rsquo;s governance.&lt;/p&gt;&#xA;&lt;p&gt;I volunteered to be on&#xA;&lt;a href=&#34;http://civilgrandjury.sfgov.org/&#34;&gt;San Francisco&amp;rsquo;s Civil Grand Jury&lt;/a&gt; for the&#xA;2017-18 term, and began working with the Jury in September of 2017. Though all&#xA;jury proceedings operate under confidentiality, I can say that I have chaired up&#xA;an investigative committee, and was one of the authors of one of the grand jury&#xA;reports published in July of 2018.&lt;/p&gt;&#xA;&lt;p&gt;You can find these reports &lt;a href=&#34;http://civilgrandjury.sfgov.org/report.html&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I learned so much from this experience: managing a team of folks with wildly&#xA;different skillsets and focuses, doing meticulously detailed researching and&#xA;interviewing, and having a large number of tasks to juggle at every moment.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>CalcU</title>
      <link>https://grady.dev/projects/calc_u/</link>
      <guid isPermaLink="true">https://grady.dev/projects/calc_u/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>websites</category>
      <category>education</category>
      <description>A course aid for mathematics based on a taxonomy of learning</description>
      <content:encoded>&lt;p&gt;I frontloaded my classes to heavily at Brandeis, and coming into my Junior&#xA;Spring Semester, I had completed the majority of the coursework requisite for my&#xA;majors. During that semester, as most of my friends were abroad, I decided to&#xA;work on a side project for the semester, accompanied only by a French class&#xA;requisite for my graduation. This was one of the best decisions of my life.&lt;/p&gt;&#xA;&lt;p&gt;CalcU emerged from a need I saw when tutoring. I was a math tutor throughout&#xA;highschool and into part of college, and I frequently helped out folks who were&#xA;tangentially studying math (Biology, economics) and needed refreshers on&#xA;material far before the material they were trying to apply. A student who needs&#xA;calculus for bioinformatics forgets basic derivative rules, a student in&#xA;microeconomics forgets the basics of geometry, a student in multivariate&#xA;calculus has never taken linear algebra.&lt;/p&gt;&#xA;&lt;p&gt;Students in this position need a resource which has a plethora of examples,&#xA;sample questions and explanations, but more importantly, they need a resource&#xA;that is able to quickly determine what they know, what they do not know, and&#xA;what they are trying to learn. CalcU sought to fill this niche.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/calcu.png&#34; alt=&#34;A Picture of the information taxonomy within CalcU&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The project expanded when I got a grant to continue the work over the summer&#xA;before my Senior year, and with the funding was able to hire three interns. The&#xA;fundamental premise was that we used web-scraping to get the data from a large&#xA;number of open source text books (including problems, examples, solutions and&#xA;explanations). We then used manual categorization into a taxonomy of problems&#xA;that we created. This taxonomy was both recursive and strongly ordered. A&#xA;student’s familiarity with different areas of the taxonomy was recursively&#xA;explored through a placement quiz which sought to understand the set of problems&#xA;the student understood and those that they did not. CalcU built a rating system&#xA;to enable the best examples and problems to drift toward the top, and had the&#xA;ultimate goal of identifiying learning styles and common patterns among learners&#xA;that would enable machine prediction of the next problem a student should see.&lt;/p&gt;&#xA;&lt;p&gt;I could talk about CalcU for days, but I will not.&lt;/p&gt;&#xA;&lt;p&gt;CalcU was my first big independent project, and I loved it. It showed me how&#xA;much fun desigining and building a system from scratch can be. It taught me more&#xA;than I can say about how to manage coders - particularly those hungry to learn.&#xA;It made me believe that I am capable of building big, complicated, and&#xA;technically complex systems. It was the project that enabled me to identify as&#xA;an engineer.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/calcu2.png&#34; alt=&#34;A Picture of some sample problems from CalcU&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;It ultimately failed. The system and software are good at what they do. They are&#xA;built in a way that minimizes server costs, and are fairly well exposed for&#xA;future data science work. However, I failed to generate the enthusiasm about the&#xA;system that I had hoped. I did the classic engineering mistake of building&#xA;without consulting real users: trying to present a polished end result without&#xA;thinking about whether it is what people wanted/needed/could be familiar with. I&#xA;avoided pushing the software into the hands of users because I was afraid of&#xA;what they would think, and by the time I was satisfied with it, it was too rigid&#xA;to enable valid user feedback to influence the final product.&lt;/p&gt;&#xA;&lt;p&gt;I am deeply thankful for the experience that CalcU gave me. The folks I got to&#xA;work with (students and teachers in the high-schools, the faculty at Brandeis&#xA;who advised me (Profs. Torrey and Hickey), and my friends and interns Sofia,&#xA;Russ, Roger and Danny) made it one of the most fun and exciting projects I’ve&#xA;ever worked on.&lt;/p&gt;&#xA;&lt;p&gt;I hope to work more in this space in the future, and learn from the ups and&#xA;downs of the time I spend on this project.I could talk about CalcU for days, but&#xA;I will not.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/calcu3.png&#34; alt=&#34;A Picture of the CalcU Team&#34;&gt;&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Bananagrams</title>
      <link>https://grady.dev/projects/bananagrams/</link>
      <guid isPermaLink="true">https://grady.dev/projects/bananagrams/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>algorithms</category>
      <category>tools</category>
      <description>A beautiful algorithm for playing Bananagrams</description>
      <content:encoded>&lt;p&gt;In 2016, when I began working at Google, I started having breakfast with the&#xA;same group of folks every morning - Chris, Brett, Andrew and Brandon. All of us&#xA;being nerds, techno-optimists and deeply competitive, at one point Brandon&#xA;described having a competition to see who could write the best AI to play the&#xA;game &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Bananagrams&#34;&gt;bananagrams&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;My productivity dipped precipitously over the next few days as I considered how&#xA;to destroy my good friends in tiled combat.&lt;/p&gt;&#xA;&lt;p&gt;Here is the algorithm I designed. I realized that searching for connections in&#xA;any spatial model was going to dominate running time, and that I tile addition&#xA;was going to be near-impossible if you had to maintain state over colliding&#xA;words. To optimize so I didn&amp;rsquo;t have to maintain a model of the board, I figured&#xA;out a layout that assigned ownership over strips of the grid in perpetuity to&#xA;&amp;ldquo;strands&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/bananagrams_strand.png&#34; alt=&#34;An Diagram of an example Strand&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/bananagrams_dock.png&#34; alt=&#34;An Diagram of how strands merge together to fill the full playing space.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Each Strand was a series of words where the ends form a two letter word and have&#xA;no other interactions. In this way, each word simply becomes a starting&#xA;character and finishing character, as length no longer matters, and this reduces&#xA;the search costs considerably.&lt;/p&gt;&#xA;&lt;p&gt;With this model in mind, you can immediately discard all words that dont start&#xA;and end with letters that are constituent to two letter words (on the same&#xA;upbeat/downbeat, too). You can further simplify out all string comparisons and&#xA;just look at character integers. You only need maintain a list of all of the&#xA;open docks, and a simple function to add a new doc on the end. Throw in some&#xA;logic about which strands go up and which go down, and you have a blazingly fast&#xA;addition algorithm.&lt;/p&gt;&#xA;&lt;p&gt;The code is &lt;a href=&#34;http://github.com/gbdubs/bananagrams&#34;&gt;here&lt;/a&gt;, and the result is (in&#xA;my mind) breathtaking.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/bananagrams.png&#34; alt=&#34;A Photo of an incredibly dense bananagrams grid.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Because all lookups are heavily amortized, and the set of words is large enough&#xA;that you only need to look where there are available keys, as the number of&#xA;words on the board increases, the addition time actually decreases, though you&#xA;run into memory issues at some points.&lt;/p&gt;&#xA;&lt;p&gt;The format Brandon used to create the server (Captn&amp;rsquo; Proto) doesn&amp;rsquo;t have a Java&#xA;API, so we didn&amp;rsquo;t end up playing.&lt;/p&gt;&#xA;&lt;p&gt;I learned a good amount from this project:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Decomposing a problem into steps that computers are good at is the key to&#xA;solving hard algorithmic challenges. It doesn&amp;rsquo;t matter how fancy or complete&#xA;your logic is if its orthogonal to the strengths of your processor and the&#xA;data structures you are using.&lt;/li&gt;&#xA;&lt;li&gt;High-level languages are going to be easier to optimize down to their core&#xA;precisely because they add layers of semantic meaning. Optimizing C is not&#xA;something I do well, because my mind is too stuck in the operations of the&#xA;computer, where as when I am optimizing Java, I see the problem in front of me&#xA;clearly.&lt;/li&gt;&#xA;&lt;li&gt;Competition drives me to do some of my best work. There is nothing more&#xA;motivating than sitting around a breakfast table, plotting victory against&#xA;friends. I rise to (and love) challenges.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</content:encoded>
    </item><item>
      <title>Cindi</title>
      <link>https://grady.dev/projects/cindi/</link>
      <guid isPermaLink="true">https://grady.dev/projects/cindi/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>algorithms</category>
      <category>tools</category>
      <description>Algorithmically generated art inspired by Janelle Monae’s Metropolis Suite</description>
      <content:encoded>&lt;p&gt;TL;DR: Janelle Monae&amp;rsquo;s art inspired me to try to build an algorithm that&#xA;programmatically generates emotion-evoking art, and the results are&#xA;&lt;a href=&#34;https://gbdubs.github.io/cindi-gallery/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/CINDI1.png&#34; alt=&#34;A rendering of the CINDI program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you haven’t yet listened to Janelle Monae’s “Metropolis” suite, I highly&#xA;recommend that you drop the committments you can, pour yourself some coffee&#xA;and/or wine, and listen to it carefully.&lt;/p&gt;&#xA;&lt;p&gt;Monae is a magician, a siren, an entertainer, a theorist, a historian, and a&#xA;visionary. Metropolis helped me understand so much about so much that talking&#xA;about it here will certainly do it an injustice. If you are interested, check&#xA;out &lt;a href=&#34;https://github.com/gbdubs/monae&#34;&gt;my 2016 term paper&lt;/a&gt; on her work within the&#xA;context of the history of waves of&#xA;&lt;a href=&#34;https://en.wikipedia.org/wiki/Black_feminism&#34;&gt;Black Feminism&lt;/a&gt;. Or, preferably,&#xA;read one of the many articles&#xA;[&lt;a href=&#34;https://medium.com/black-feminism/black-feminism-through-the-lens-of-janelle-monae-the-electric-lady-a0f917c547e7&#34;&gt;1&lt;/a&gt;]&#xA;[&lt;a href=&#34;https://pqdtopen.proquest.com/doc/1545710995.html?FMT=AI&#34;&gt;2&lt;/a&gt;]&#xA;[&lt;a href=&#34;https://repository.library.georgetown.edu/bitstream/handle/10822/760841/ZaGara_georgetown_0076M_12968.pdf?sequence=1&amp;amp;isAllowed=y&#34;&gt;3&lt;/a&gt;]&#xA;by people who have looked at Monae&amp;rsquo;s work more carefully than I have, and have&#xA;more interesting things to say about it.&lt;/p&gt;&#xA;&lt;p&gt;Within the context of Metropolis, one of the (many) questions Monae raises is at&#xA;the intersection of technology, humanity and art, and this project was an&#xA;attempt to programmatically generate art that evokes real human emotion. To&#xA;understand what I was trying to capture, check out&#xA;&lt;a href=&#34;http://cindi.in&#34;&gt;the page itself&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/CINDI2.png&#34; alt=&#34;A rendering of the CINDI program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This was an expansion of the work I did in in &lt;a href=&#34;https://grady.dev/projects/voat/&#34;&gt;VOAT&lt;/a&gt; - rather than&#xA;using squares with a predictible and pre-defined set of ports to connect, I use&#xA;polygons with arbitrarily defined sub-regions. The results are wild: extreme&#xA;variance, never dull. To see how some of these were generated, check out the&#xA;tesselation photos below.&lt;/p&gt;&#xA;&lt;p&gt;TODO(gradyward) Add tesselation breakdown photos.&lt;/p&gt;&#xA;&lt;p&gt;I hope to do more work in this space, and to keep thinking through where the&#xA;root of emotion and power of art lies. From a technical perspective, I have a&#xA;long backlog of features I want to build: I would ideally like to incorporate&#xA;images, create non-fluid spacefilling, create classifications for common&#xA;aesthetic patterns and entropy filters to filter out boring or repetitive&#xA;generations. From an artistic perspective, I&amp;rsquo;m not yet satisfied with this&#xA;project - it has only begun to scratch the surface of what I think is possible.&lt;/p&gt;&#xA;&lt;p&gt;I hope this project goes somewhere, but I need time to work on it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/cindi.png&#34; alt=&#34;A rendering of the CINDI program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;UPDATE (2023): You can now play around with many derivative algorithms (and see&#xA;the many beautiful images created through them) at&#xA;&lt;a href=&#34;https://abound.art&#34;&gt;ABOUND.art&lt;/a&gt;.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Flux</title>
      <link>https://grady.dev/projects/flux/</link>
      <guid isPermaLink="true">https://grady.dev/projects/flux/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>animation</category>
      <category>algorithms</category>
      <description>Modifying attractor parameters via a parameter space orbit</description>
      <content:encoded>&lt;p&gt;TL;DR: Check out &lt;a href=&#34;https://gbdubs.github.io/flux/&#34;&gt;this data intensive (not recommended for mobile)&lt;/a&gt; looping pattern of an attractor with a multi-dimensional parameter orbit.&lt;/p&gt;&#xA;&lt;p&gt;I saw a blog post by an extremely talented programmer, and was surprised (as he was) to find that there was a natural symmetry to the patterns he was describing.  However, in digging into his code, I found that it was not actually symmetrical, but he had just made a very understandable typo which introduced this artificial symmetry.&lt;/p&gt;&#xA;&lt;p&gt;Working with these equations, I found that the surfaces generated by them were gorgeous, and that the surface appeared to be differentiable with respect to every one of the input paramters.  In my experience, this is rare for a multi-dimensional equation.&lt;/p&gt;&#xA;&lt;p&gt;Just iterating around a bit, I found that the most “interesting” cases all happened at a relatively uniform distance from the origin of the parameter space.  I then thought about how I could generate a nice video of a tour of the parameter space, and my mind lept to an orbit.  I created the software to output a gif of the generated curve for a given circular or elliptical orbit around the center of the parameter space.&lt;/p&gt;&#xA;&lt;p&gt;I then made many of these gifs, all of which share a starting and ending position in the parameter space. This means that played in any sequence, the gifs will make a beautiful pattern that appears continuous, infinite and quasi-random.&lt;/p&gt;&#xA;&lt;p&gt;This work insipred me to do more code-art for the sake of the art, rather than the sake of the code.&lt;/p&gt;&#xA;&lt;p&gt;NOTE it is not recommended that you view this over a mobile connection - the page is about 100MB in total&lt;/p&gt;&#xA;&lt;p&gt;NOTE it might take a while for this page to load. Give it several minutes. It loops, so you will not miss anything if you come back to it later.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>VOAT</title>
      <link>https://grady.dev/projects/voat/</link>
      <guid isPermaLink="true">https://grady.dev/projects/voat/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>art</category>
      <category>algorithms</category>
      <category>tools</category>
      <description>Variations on a Theme (Elgar) meets a classic by Frank Stella</description>
      <content:encoded>&lt;p&gt;TL;DR: With a fun algorithm, slight parameter tweaks lead to really different results, as I show in a &lt;a href=&#34;https://gbdubs.github.io/voat/&#34;&gt;work&lt;/a&gt; based on Elgar&amp;rsquo;s enigma variations.&lt;/p&gt;&#xA;&lt;p&gt;A good piece of art compells you to understand the process that created it, whether it is the emotion of the composer, or the logic of the painter. A revlation while looking at a piece by Frank Stella made me understand the fundamental mechanism that was generating the work, and gave me confidence that I could recreate it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/voat_1.png&#34; alt=&#34;An output of the VOAT program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Squares (with side of size 1), with two quarter-circles in opposite corners (with radius one-half), in both configurations, with space filling between regions, forms the basis of this work by stella.&lt;/p&gt;&#xA;&lt;p&gt;After more time than I would like to admit, I was able to recreate stella’s work in the browser.  There were so many minutia and little tricks that if even slightly off in any function, the code would mis-render the full piece.  I came to enjoy these mis-renderings more than I enjoyed the final piece, so once it was completed, I looked to see if I could alter the rules slightly and capture different feelings/emotions with the results.&lt;/p&gt;&#xA;&lt;p&gt;The results were so varried and interesting that I had to share them.  Each had a personality I could never have tried to design.  The overall impression each left was distinct, and the commonalites between them felt just as important as their many differences.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/voat_2.png&#34; alt=&#34;An output of the VOAT program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/voat_3.png&#34; alt=&#34;An output of the VOAT program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/voat_4.png&#34; alt=&#34;An output of the VOAT program&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;I ended up publishing a set of them as “VOATCSS” - Variations on a theme - a reference to Edward Elgar’s piece by the same name, where he paints portraits of his close friends through the stroke of a common musical theme. Similarly, each of the components of this collection were given a color scheme and parameterization that reminds me of a person that I cared deeply for.&lt;/p&gt;&#xA;&lt;p&gt;UPDATE (2023): You can now play around with many derivative algorithms (and see the many beautiful images created through them) at &lt;a href=&#34;https://abound.art&#34;&gt;ABOUND.art&lt;/a&gt;.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Student Union (In Line)</title>
      <link>https://grady.dev/projects/in_line/</link>
      <guid isPermaLink="true">https://grady.dev/projects/in_line/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>websites</category>
      <category>design</category>
      <category>education</category>
      <description>A multi-owner distributed WYSIWYG editor with CDN hosting</description>
      <content:encoded>&lt;p&gt;In my time at Brandeis University, I spent 3 years working hard for the Brandeis Student Union as a Student Representative to the Board of Trustees, and an Executive Board member. Over those three years, we had three different computer science students as “web-master”, and three politicos as “communications director”.  The problem was that each web-master would build a beautiful website that was never able to be updated because the communications director never had the technical expertise to update the HTML or use the static site generator.&lt;/p&gt;&#xA;&lt;p&gt;As college was coming to an end, I was frusturated because my time with the board of trustees had not been as productive as I had originally hoped. Looking for a place I could have a lasting legacy and impact, I found it in the Student Union’s website.&lt;/p&gt;&#xA;&lt;p&gt;At its heart, the problem is one of distributed data management and editing.  Students within the union should have different access to edit different data, but the site should be rendered in a way that does not reflect this multiple authorship - components should be rigid enough that an author&amp;rsquo;s style does not bleed into a unifying presence.  In addition, a distributed ownership model for content needed to be (A) version controlled (B) auditable (C) completely non-technical.&lt;/p&gt;&#xA;&lt;p&gt;So I built it! The source code is &lt;a href=&#34;https://github.com/gbdubs/StudentUnion&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/in_line_edit_me.png&#34; alt=&#34;A photo of where users could edit the site&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The end product is pretty sweet, and uses some smart optimizations to minimize hosting costs and page serving.  I took advantage of Github’s “pages” platform to serve the static HTML rendered by the site.  A change in one of the underlying sets of data would trigger a re-render of the HTML generated by the data, and then would be written out to Github pages.  This had two main benefits - Github automatically maintains version control history, which enabled auditing of who wrote what and when, and Github stores its HTML files in pages in a blazing fast CDN. This meant that lookups to the webpage were infinitely scalable and cheap (from my perspective), and meant that there were not “read” server costs.&lt;/p&gt;&#xA;&lt;p&gt;The server that processed writes was built on AppEngine, using JSTL templating over datastore objects to render the HTML to write to Github pages.  More exciting than that was the group strucuture that I made so that sub-groups of the Student Union could have access to different sets of permissions for editing. This formed the basis of Committee pages, and organization pages, which were only editible by their members.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/in_line_distributed.png&#34; alt=&#34;User Management controls&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Additionally, the data was reused between pages for common elements (for example, all committees should have the names and bios of their members, even if each member is in 10 committees).&lt;/p&gt;&#xA;&lt;p&gt;On the front end, I used a “Medium”-esque visual markdown editor to enable the construction of HTML elements from a given set of supported ones (which I provided a cohesive design language for on the rendering side).&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/in_line_editor.png&#34; alt=&#34;WISYWIG Editor&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;The result is &lt;a href=&#34;http://union.brandeis.edu&#34;&gt;gorgeous&lt;/a&gt;, and far more importantly, meets the needs of the Union. I left Brandeis two years ago (writing this from 2018), and it has been used effectively by three Student Unions since.  I do occasional performance upgrades and feature requests, but I&amp;rsquo;ve seen the site updated by several dozen Union Members without any technical knowledge.&lt;/p&gt;&#xA;&lt;p&gt;I’m quite proud of this project because it stands solidly at the intersection of technical simplicity and client needs. I have confidence that the Union will be using this product long after anyone remembers me at Brandeis.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Senior Thesis</title>
      <link>https://grady.dev/projects/senior_thesis/</link>
      <guid isPermaLink="true">https://grady.dev/projects/senior_thesis/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>algorithms</category>
      <category>education</category>
      <category>tools</category>
      <description>Senior thesis on the graph isomorphism (GI) problem</description>
      <content:encoded>&lt;p&gt;I wrote my undergraduate thesis on the &lt;a href=&#34;http://mathworld.wolfram.com/IsomorphicGraphs.html&#34;&gt;Graph Isomorphism&lt;/a&gt; (GI) problem, and several topics within that space. My work was &lt;a href=&#34;https://github.com/gbdubs/thesis&#34;&gt;version controlled on github&lt;/a&gt;, and the final result is &lt;a href=&#34;https://github.com/gbdubs/thesis/blob/master/Documentation%20%2B%20Reports/THESIS/thesis.pdf&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I was first interested in the “Paths” invariant, which is incredibly powerful test for discerning between potentially isomorphic graphs in cubic (and fully paralellizable) time, and was originally theorized to be a solution to GI. The primary findings of my thesis were that:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;[Computational Wrangling] Unlike was theorized, copaths graphs do exist, and finding them is easily done brute force calculations on today&amp;rsquo;s standard GPUs.&lt;/li&gt;&#xA;&lt;li&gt;[Theoretical Proof] Paths uniquely determines the chromatic polynomial of a graph.&lt;/li&gt;&#xA;&lt;li&gt;[Analytical Algorithms] Measuring discriminatory power to value ratio of invariants within graph isomorphism is possible and can help us devise better algorithms for practical isomorphism detection, and the paths invariant is well weighted in an analysis of discriminatory power.&lt;/li&gt;&#xA;&lt;li&gt;[Theoretical Proof] Paths as an invariant does not need to be calculated past N vertices.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Since I answered most questions I was interested in  paths stuff earlier than expected, I started working on Random Graph theory and found that:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;[Literature Review] Random Graph generators almost all are random matrix generators. This understates the frequency of highly auto-isomorphic graphs by one-to-factorial odds.&lt;/li&gt;&#xA;&lt;li&gt;[Coding] We can create a better random graph generator to evaluate random graph algorithms.&lt;/li&gt;&#xA;&lt;li&gt;[Analytical Proof] Many algorithms are evaluated across &amp;ldquo;matrix random&amp;rdquo; graphs, and their amortized running time can be exponentially higher when using a true random graph generator.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I defended this thesis was successfully defended in May of 2016, and recieved highest honors in Computer Science.&lt;/p&gt;&#xA;</content:encoded>
    </item><item>
      <title>Parley</title>
      <link>https://grady.dev/projects/parley/</link>
      <guid isPermaLink="true">https://grady.dev/projects/parley/</guid>
      <pubDate>Tue, 16 Jan 2018 11:58:27 -0800</pubDate>
      <dc:creator>Grady Berry Ward</dc:creator>
      <category>websites</category>
      <category>design</category>
      <category>online spaces</category>
      <description>Recursive annotations as a counter-proposal to the comment thread</description>
      <content:encoded>&lt;p&gt;Comment threads are an inherently flawed way to have a discussion, because they are strictly linear.  In recent years, large organizations like facebook have realized this and have tried to reconcile it with a binary tree pattern of &lt;em&gt;deeper&lt;/em&gt; or &lt;em&gt;next&lt;/em&gt;. This only partially solves the problem. Far more frequently, if I want to respond to a comment, there are multiple pieces of it that I want to respond to, and some may already be addressed further down the thread.  The heart of the matter is that a meaningful static discussion is not best facilitated by a linear progression of strings.&lt;/p&gt;&#xA;&lt;p&gt;Parley was my idea on how to change this. It views a document as something which is not responed to in whole, but which can be annotated with comments by different authors.  The comments (in turn) become top level objects which are just as open to annotation and further comment. The recursive, n-ary tree nature of this structure has multiple advantages, but the big one is that you can dive deep on a given line of argument naturally, by clicking through and understanding the points as made in isolation.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://grady.dev/img/parly.png&#34; alt=&#34;A Photo of the parley interface.&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This idea in and of itself is not revolutionary, but I wanted to see if I could make a demo where this is implemented in a way that is comprehensible and intuitive.  I half succeeded here.  The parley interface used the Draw Me CSS pattern to create a right-left layout where the content is displayed with underlines corresponding to annotations, and the text of the annotation is displayed in a scrolling left hand column.  The interface is flexible, relatively intuitive, and fairly simple.&lt;/p&gt;&#xA;&lt;p&gt;Where I ran into problems was in the minutia &amp;ndash; what about really long annotations? What about annotations stacked 15 high? How do you link effectively (as links cannot then be annotated)?&lt;/p&gt;&#xA;&lt;p&gt;The backend is lame (an app engine hack), but I stand behind the fundamental idea (recursive comment sections, rather than linear ones), and I stand behind the UI for what it is - a proof of concept.&lt;/p&gt;&#xA;&lt;p&gt;To use the system, go to &lt;a href=&#34;http://parly.us&#34;&gt;parly.us&lt;/a&gt;, and be aware that the AppEngine backend takes up to a minute to spin up - so allow a minute to pass after a first page access, then reload the page to interact with the software.&lt;/p&gt;&#xA;</content:encoded>
    </item>
  </channel>
</rss>
