“Doing my own research”

To be clear, the title here is tongue-in-cheek. Real “research” involves carefully-designed and bias-controlled experiments, and there ain’t none of that below. My intended point is just that we’re all capable of digging deeper in ways that haven’t been the case before the advent of LLMs. Arming yourself with these tools is one way to fight the bullsh*t that is pushed at us every single hour of every single day.

A few days ago the Algorithm-capital-A pushed me a video about Bass Pro Shops and how they scam tax discounts by creating fake “museums” in their stores. Turns out that while the shock video version exaggerates the scope of the con, it’s basically true. Nice!

Anyways, what started as a casual attempt to test the veracity of this story ended up as something much more interesting. Yes kids, it’s another AI-positive story, this one hidden behind some observations on the American economy.

Subsidy Tracker

One of the articles about Bass included a link to Subsidy Tracker, a site that combs through public records to identify federal, state and local subsidies by company. This is really messy data; we’re lucky there are non-profits making it usable.  

Somehow I wandered from Bass over to the airline industry, where I found a ton of very recent federal grants —millions of dollars every month. Digging into these led me to the Essential Air Service program, and that started me down today’s rabbit hole. Bear with me for a second.

Essential Air Service

See, back in 1978 Jimmy Carter — yes, JIMMY CARTER — signed the Airline Deregulation Act, hoping to decrease fares and increase service by rolling back a bunch of controls on fares and routes. But the bill’s authors realized that without some new intervention, a deregulated airline industry would immediately drop service to smaller, less profitable locations like, say, my college home airport in Lebanon, NH.

They addressed this by creating the EAS and its list of “Essential Air Service Communities.” Airlines are paid real cash money by the federal government to provide regular service to these communities — to the tune of more than half a billion dollars in 2024. For example, Cape Air was paid $5.2M to ensure 54 people a day could fly one-way to or from West Leb. That’s about $2,400 per leg, even if they fly the plane empty!

And you know what? This is fine. Actually, it’s great. We, as a society, decided that we cared about maintaining integration of our rural communities with the rest of the country via passenger air. We also recognized that free market dynamics would not deliver this outcome, because the societal “cost” of not having service was borne outside of the immediate commercial players.  

Of course there are risks to this. Collective actions are complicated and always subject to bias and graft — they’re never “optimal.” Our protections are mandated transparency, civil education and a free press. The EAS probably needs some tweaks, but on balance it seems like a pretty good call.

Like it or not, this kind of market-socialism hybrid has been our model pretty much forever — and increasingly so as we’ve become more interdependent through the industrial and information ages.

OK, Cool, Right?

Not so fast, Milton. A huge, possibly majority fraction of our country simply does not understand this long-standing reality. The Reds have spent decades — starting with talk radio in the 80s and culminating with MAGA today — telling people that we live in a perfectly free market economy, and that perfect freedom is the primary reason for the success of our nation. It’s a two-part strategy:

  1. Emphatically label “bad” collective societal action as “communist.” (health care, minimum wage, food and unemployment benefits, UBI, …)
  2. Ignore, bury and obfuscate the “good” action so the public doesn’t notice the hypocrisy. (corporate subsidies, military adventures, incumbent-benefitting pork, …)

The EAS is a great example of this. By definition the vast majority of EAS communities are in rural areas — places that likely supported Trump in the last election. But I’m pretty sure that if you asked residents in those communities if the government was playing to fly empty planes to and from their homes, they’d say (1) no way, and/but (2) we don’t want to give up our airport.

Ask a Simple Question

At this point in the story, I realized I should check my own bias. I mean, of course rural voters went for Trump, but it’s possible that EAS communities were somehow an outlier. So I started poking around for some data that would help me answer that question.

Little asks like this seem so simple! But as anybody who has ever tried to report on real-world data can tell you (say, for example, the DOGE wizards that “concluded” millions of dead people were drawing social security) it’s actually super-hard. First you have to find data — and for a lot of questions, that just doesn’t exist (see my comment at the top about real research), or it’s in an awkward or inconvenient form for analysis. In this case, however, it was pretty easy:

  1. The Dept of Transportation publishes a current list of EAS communities. It’s a PDF, but that’s easy to extract into a CSV file with columns for city and state.
  2. The Harvard Dataverse, another great resource that I hope survives our current funding climate, publishes county-level election data (file citation).

Progress! Often all you need from here is a little basic Excel magic (see here for some tips on that). Unfortunately for us, we hit our first stumbling block: election data is reported at the county level, while the EAS communities are cities. Mapping between those will take a little more data, but luckily that’s available too, compiled from government sources and released under a Creative Commons license: simplemaps US Zip Codes database.

Extract city, state and county columns from this file, match up the city/state with the EAS data, walk that through county to the election data, and Bob’s Your Uncle!

Finally, the AI Part

Well sure, it’s pretty simple in theory. But most of the country doesn’t have the skills to actually write this code. I mean, I’ve spent a career doing this sort of thing, but even so I’m not likely to invest the effort on a random weekend news-scrolling curiosity.

This is where foundational AI models can really change the game for everyone. It’s not without pitfalls, but take a look at what Claude Code was able to do with this prompt:

I’d like to generate a csv file that shows how each county that is considered an eligible community in the Essential Air Service program voted for president in 2024. Please use node and javascript for this script.

Data on EAS eligible communities is in the file eas.tsv. Data that translates city/state to county is in the file uszips.csv. Data that contains county-level presidential elections results is in the file countypres_2000-2024.csv.

You’ll need to read each city/state combination out of eas.tsv, then use uszips.csv to translate that into one or more county/state combinations.

With this information, look up the 2024 election results for those counties, sum up the votes if there are multiple counties, and output a row with the name of the candidate that received the most votes.

If you are unable to translate a city/state to county/state, or if that county/state is not found in the presidential election results, use “unknown” as the name of the winning candidate.

The output should have three columns: the original city/state from the EAS data and then then name of the winning candidate.

Please double-check your work and do not take shortcuts such as estimation or extrapolation. I want to be sure that the data you output represents direct matches only — if the data isn’t clear just say “unknown” and that’s ok.

I put a lot of detail in that prompt because (a) I’d already done the work to figure out data sources; and (b) I wanted to be very clear that the model should be conservative. First try: Winner-Winner-Chicken-Dinner!

More than Mechanical

A machine that writes code to crosswalk a bunch of files is pretty neat, opening up a deeper level of analysis to huge swaths of the population. But it gets really cool when you look under the covers. Review the entire conversation for yourself using this link.

The model wrote code, tested it, and iterated a bunch of times to discover and account for unique quirks in the data. It was a lot! Again, this will sound very familiar to anyone who has tried to do even moderately complex cross-source data analysis:

  1. One file had full state names while the other had abbreviations. Create a lookup table.
  2. The “mode” column is inconsistent. Most counties use “TOTAL VOTES” to represent totals, but some counties leave this blank, others use other terms like “TOTAL VOTES CAST” and others don’t have total rows at all so they need to be created by summing other modes. Normalize the values and created an algorithm that picks the most representative rows.
  3. Some city names were slightly different across files. E.g., “Hot Springs” vs “Hot Springs National Park.” Use partial matching to address.
  4. Spacing and casing differences. Strip spaces and lowercase everything before matching.
  5. Additional differences in punctuation and abbreviation. Use a normalization table.

All of these were found without further prompting or intervention. And as the cherry on top, the model even realized that the two Puerto Rican EAS communities weren’t in the election data because Puerto Ricans can’t vote for president.

Of course, given the state of LLMs today I still wouldn’t just trust the output without reviewing the code and doing some spot checks. In this case at least — did that, and it passed with flying colors.

TLDR, my assumption about Trump voters is backed up by the data. Not earth shattering perhaps, but anything that makes the world a little more fact-based is a Very Good Thing. And most importantly, thanks to LLMs, this kind of research is available to all of us at any time. People love to talk about “brain rot” from AI — but we do that with every innovation. Gen X peeps, remember the uproar about calculators (55378008)? Use it well and it is transformational.

Anyways, if you’re starting your online screed with “I haven’t checked but I bet….” well, shame on you.

OK, but what about Cost and Energy?

It’s very popular to dismiss AI solutions due to their allegedly egregious energy use. The work I did here used 54,116 “tokens” — where a token is a unit of work kind of like a word but not quite. There isn’t a ton of data out there as to how much energy is used during inference, but a broad range between .001 and .01 Watt-hours per 1,000 tokens is cited pretty regularly.

Double that to cover infrastructure costs like cooling, split it down the middle and we can make a crazy rough estimate of .54Wh for the work in this post. That’s about the same as running two Google searches, or running a 10W light bulb for three and a half minutes. To me, this is a shockingly efficient use of energy, even if our guess is off by two or three times.

Ah you say, you can’t just look at inference — model training costs are astronomical. And that is true! But production models typically remain in use for around six to eighteen months before being superseded. Over that timeframe a model will be used for many billions of inferences; training costs quickly amortize to basically zero.

And none of this considers the innovation curve that is already happening to push costs down. Just as with traditional computing power, market forces (ha, get it?) are going to do their thing. This isn’t to say we shouldn’t be worried about AI in general — there’s a ton that could go wrong. But energy use isn’t going to be the problem.

OK, as usual I’ve gone way longer on this than anyone is going to read. But it’s endlessly fascinating to be here during this moment of innovation. It’s just unfortunate that it happens to overlap with with existential threats to our American experiment. That part sucks.

On Trails. Also Ants.

I swear it was a coincidence that I was reading On Trails just at the moment when my dad and I road-tripped a small moving truck from Florida to Colorado (go Penske). But it did make for some interesting connections. While it opens and closes with discussions of the Appalachian Trail and the International AT, this isn’t a “hiking” book. The central thesis (at least to my reading) is that trails act as “social memory” — helping groups from insects to people share knowledge and history.

Moor also ponders the connectedness of trails; continuous journeys through an environment, vs the “nodes and desire lines” of point-to-point travel, typically by air. That certainly registered during the trip with my dad. In a single day I teleported from Seattle through Charlotte (although it could have been anywhere) to Fort Meyers. Over the next four I glided across the United States in one continuous motion, seeing the gradual changes from swamps to horse country and low forests, up and down the Appalachians and onto the prairies. So much prairie! I love driving through the wide open skies and horizons of Kansas. Then suddenly the Rockies just show up out of nowhere, dropping me at the foothills of Boulder.

It never ceases to amaze me that there are continuous ribbons of asphalt that cover thousands and thousands of miles. If I just start driving, I can go from the Pacific to the Atlantic with my tires never touching anything but I-90. There is nothing so awesome as a highway road trip (with adaptive cruise control of course).

Ants

Anyways, let’s do a little nerd stuff. Towards the beginning of the book, On Trails describes stigmergy, a form of self-organization that uses modifications of the physical environment to coordinate individuals.

Ants are a great example. Brave ant souls leave their colony to explore randomly for food. When they find it, they return to the colony, leaving behind a chemical pheromone that serves as a trail for other (less adventurous) ants.

Amazingly, most ants use dead reckoning to remember how to get home — they literally count steps to measure distance and interpret the polarization of sun (or moon) light to remember cardinal direction. Some species supplement these by tracking the velocity of objects in visual range, or sensing changes to the Earth’s magnetic field. Still others leave behind a secondary, weaker pheromone like Hansel and Gretel.

These simple actions — Look for food! Leave a trail! Go home! — add up to some pretty striking colony-level behavior, so I thought it’d be fun to do some simulations. Plenty of folks have done this already, and surely more elegantly than I. But it’s my site and I love to write code, so let’s get nerdy.

AntWorld

My ants and the environment they inhabit are described in AntWorld.java. If you’ve got git, maven and a reasonably up-to-date JDK you can run it yourself:

git clone https://github.com/seanno/shutdownhook.git
cd shutdownhook/toolbox
mvn clean package install
cd ../ants
mvn clean package
java -cp target/ants-1.0-SNAPSHOT.jar com.shutdownhook.ants.App ants 400 config.json ants.htm

All this will result in a file ants.htm on your local machine. Open that file in a browser and you’ll see something like this (not exact because the configuration is set to use a new random seed each time it runs); click the image for an animated view:

  • Red represents the ant colony.
  • Blue denotes randomly-placed food caches.
  • Black ants leave the colony to explore for food.
  • Ants that find food return to the colony, leaving behind a trail of green pheromone.
  • Ants that hit the edge of the world return to the colony without leaving a trail.
  • Pheromone trails decay over time.
  • Food is consumed as ants discover it.

In mine, the first cache is found in the eastern part of the environment around cycle 35. Just as that cache is fully consumed, a second is found in the western side — but it gets lost around cycle 150 because the strong “leftover” eastern trail is just too attractive. After that trail decays, the second cache is re-discovered around cycle 200, pulling more ants towards the west. From there they find the third and fourth caches pretty quickly.

Each run provides a new dramatic twist, and tweaking parameters is pretty addictive. For example, a dense colony (100 ants) can obviously flood the environment quickly, but even a sparse colony (just 10 ants) is pretty successful.

The Details: Exploration

Little details make a huge difference in this kind of simulation. Check out the code that handles “exploration” mode. In my first version, explorers really did just pick a random direction with each step. But this didn’t look or feel “real” at all. Eventually I ended up with these rules:

  • If there is food directly adjacent to the ant, go there. This makes sense — an ant can certainly see or smell food in their immediate vicinity; they’re not going to randomly turn away from that.
  • Travel has “inertia.” An ant moving in one direction isn’t likely to just pull a one-eighty for no reason, so it chooses from previous last direction or one step to either side. For example, an ant that travelled east in the last cycle will choose east, northeast, or southeast.
  • The choice of the three directions is weighted by the amount of pheromone in each direction — ants strongly prefer to travel along pheromone trails.

Another dynamic that’s not immediately obvious is “giving up.” Ants in the real world stay within a certain distance from the colony — they don’t just explore infinitely. I was able to approximate this failure mode by detecting collision with the edge of the world.

The Details: Pheromone Trails

The concept here is pretty straightforward: when an ant discovers food, they return to the colony, leaving behind a chemical pheromone trail that other ants use to get to the same food source. But there needs to be some balance between following known trails and breaking new ones. And since food sources are exhausted over time, the pheromone needs to decay, or ants would keep returning to an empty cache forever.

The configuration values “AntReturningPheromone,” “LocationPheromoneMax” and “LocationPheromoneDecay” fine-tune this behavior — this run shows how imbalance (pheromone too strong) can sabotage a colony’s ability to effectively leverage its envoironment.

Another interesting side effect of the current implementation is “exploration spillover.” Watch what happens around cycle 125 of this run. Large numbers of ants are moving back and forth between the colony and the food cache. Eventually the food is depleted, but there are still a bunch of ants travelling along the path. When ants hit the empty food cache, they “spill over” the end of the trail, causing a surge of exploration in the local area.

Does this behavior track the real world? Not really — apparently while frustrated ants do conduct a “brief local search” to be sure there aren’t leftovers to be found, mostly they return back to the colony emptyhanded without dropping pheromone.

I haven’t bothered to fix this — it doesn’t matter for my purposes. But it does illustrate just how complex even the simplest things in the real world, really are.

A Brief Lesson for the Enterprise

This post is about trails and ants, not enterprise software. But it seems like there is always a lesson to be learned, and today that lesson is “honor your history,” aka “everything exists for a reason.” My first implementation of AntWorld was crisp, concise and elegant. But it didn’t work at all. It took a ton of trial and error, multiple literature reviews, parameter tweaks and dead ends before I got to the current state.

The software in your enterprise almost certainly has a similar pedigree. At first glance it seems overly complicated and filled with special cases. But those cases are there for a reason — think really, really hard before starting over with that alluring “clean slate.”

Anyways

That’s plenty for today. A great book, a fun coding challenge and a bunch of neat visualizations to play with. And it’s sunny outside — things don’t get much better than that. Until next time!

110 Posts and Counting

I realized today that I’ve written 109 (well I guess 110 now) long-form posts on shutdownhook.com since February 2021, the month I quit my job at Adaptive Biotechnologies and updated my LinkedIn bio to “Retired?” (now it’s got an exclamation point). That’s about two a month; sometimes more, sometimes less. Not bad.

I do link my posts on social media, and I love it when one strikes a chord with folks. But mostly I write for myself — a deal I made with the lazy part of me that would be happy to sit on the porch with a Coke Zero and just watch the world slide by. “You can retire, as long as you keep building and learning and trying new stuff.” Writing down that “stuff” gives it shape, and helps me calibrate whether I’m spending my gift of time well (or, sometimes, not).

I do like the writing part, too. A different form of creation, transforming a jumble of experiences and ideas into an efficient, coherent progression of words that tell their story. Somewhere around one or two thousand words usually does the trick. My friend Claude put together this little timeline of my posts (click for an interactive version):

Pretty cool, but it also highlights a slight but steady decline in frequency, especially over the past two years. Some of that is just time spent on other projects that may land on the gallery or book journal or (gasp) offline altogether. But that’s not the whole story.

Quieting

On the positive side, I think it mirrors a general “quieting” of my life that I’m a big fan of. I talk a lot less than I used to (Lara who has to live with me all the time now may disagree) — to the point where if I spend much time actively engaging with people it leaves me physically hoarse and exhausted.

This is a little weird after a decades-long career in an industry known for being loud and interruptive and full of voices. I thrived in that setting, but I like the alternative a lot. My ex-colleagues may derive some measure of amusement from this.

It’s not about less intensity or enthusiasm or fun or depth; it’s just different. It sounds so woo-woo I’m embarrassed to write it down, but the conversations and debates I used to have with people, I find myself having with wood, physics, nature, computers, animals, beaches, books, plants… it’s kind of neat.

Garden Party

I’m also writing less about “the old days,” except when some specific lesson or event has bearing on something new. I’ve heard loud and clear that folks love to hear about old Microsoft and the dot com days, and I get that — there are some great stories.

But like Ricky Nelson, I’m just more interested in looking forward than looking back. That’s why I moved to the West Coast in the first place, and why I jumped from industry to industry, and why I retired to explore new corners of the world. “If memories were all I sang, I’d rather drive a truck.” Although to be fair, “driving a truck” actually sounds super-fun too. Next month I’ll be road-tripping a cargo van across the USA; not quite the same but maybe a taste.

Of course there’s comfort and satisfaction in looking back, and there’s nothing wrong with that. I love beers with old friends, swapping stories and carping about kids these days. But I’ve seen too many people become frozen in time — the “old days” morph from real history into idealized fantasies that don’t serve anybody. Especially at a time when super-freaking old folks are clinging with their fingers and toes to political power.

Toxic Commons

Which brings me to the last, and most negative, thing slowing me down — a deep and real disillusionment with the state of our country. I try hard to separate my daily explorations from the endless stream of crazy news, but it doesn’t always work. And it probably shouldn’t, because what’s going on now is fundamentally sad, unnecessary and destructive.

It’s not all about “politics,” although the politicians and influencers have certainly figured out how to capitalize. It’s about an ignorant, petty mob of children vandalizing civilization and progress — far, far closer to the Red Guards than anything remotely American.

Actually, I keep finding myself using that term “American” as it has lived in my head since I was a kid. But I have to remind myself — WE voted for this, twice. WE are continuing to support it. WE love having our public health systems ruined by lying charlatans without medical experience. WE love having our capital city occupied by federal troops for no reason other than intimidation. WE love vilifying the poorest and most vulnerable to satisfy our pathetic, racist, everything-phobic egos. WE love that our president is a disgusting bloated coward, because it gives us an excuse for being awful ourselves.

The truth is, I don’t really know how to live in public anymore — so I do less of it. I’m still in the fight where I can have some impact, but it gets harder with every company and college and ex-colleague that bends their knee.

Whew. Sorry for the navel-gazing. But hey, it’s my site and I get to be a downer at least once every 110 posts. Next one will have some witty observations about AI or my latest power tool or how kids don’t know how to code anymore — I promise!

Developing An Intuition for AI

AI is changing the world. Yes we are in a bubble and current claims are overblown and countless stupid companies are being started and a ton of investment capital is being thrown away. But don’t let anyone tell you (even if it feels good) that it’s all smoke, mimicry and plagiarism. They are incorrect.

There’s no substitute for direct experience — sit down and try it for yourself. You’ll quickly begin to develop an intuition for what it can and can’t do well. You’ll find amazing insights and unsettling failures, and learn how to direct it towards positive outcomes. The people that understand this will thrive on the other side.

To get you rolling, here are two quick, real-world anecdotes from earlier this week — and a few thoughts about why they went down the way they did.

1. Let’s Go Narrowboating!

For years I’ve been fascinated with the UK’s extensive canal network and the narrowboats that travel them. Lara and I are planning to meet some friends in the Cotswolds next year, and I’m trying to convince them that we need to rent a boat and spend a few days on the water.

Of course, the sum total of my experience with narrowboating comes from watching Pru and Timothy on TV, so where to start? These days it’s AI, of course. I started with this very exploratory opening salvo (including the heartbreaking typo literally on word #1!):

I’m need help planning a trip. My wife and I are 56 and would like to spend about three days exploring the Kennet & Avon Canal in a rented narrowboat. We’ve never been on a narrowboat or the canals before so we are beginners! We’d like a peaceful, quiet trip with a few locks but not too many. We’d like to have the option of staying in hotels at night, or at least mooring in villages with nice restaurants and pubs. Can you help me get started?

Here’s a record of the full conversation. Along the way the model made two errors of consistency, each of which could have been disastrous: (1) it would have stranded the boat at the end of the trip because it didn’t consider having to return it; (2) it both warned me not to travel the Caen Hill locks and then recommended a mooring point that would have required doing so.

But the final result, created soup to nuts in just over twenty minutes, is a remarkably useful and comprehensive itinerary: 4-Day Narrowboat Holiday Guide for Beginners. Good enough to rival the most helpful travel agent.

2. Let’s Build a Web App!

Life on Whidbey Island is dominated by weather, tides and ferries. I’ve got a bunch of apps and sites I use to monitor this stuff, and for a long time I’ve wanted to put together a little mobile-friendly web site to unify them all.

This isn’t particularly complicated. My personal weather station and the NOAA tide stations have APIs, and I’ve previously hacked up the WSDOT ferries site so I can pull images. There’s even a REST API that can monitor water levels in our community tank. The only hangup is the user experience — I despise, and am not particularly good at, building usable, nice-to-look at HTML/CSS interfaces.

I was skeptical, but what the heck — let’s ask Claude Code to give it a try. I set up my project, told Claude to figure out how it worked (generating this artifact, kind of amazing in and of itself), and then made this request, again with some embarrassing typos:

The file src/Tides.jsx is set up to fetch a json url representing a high and low tides for today and the following four days; right now it just displays that json text in the component div. I would like to render this information in a way that fits into the “card” display of the site.

Please write javascript that will create an HTML representation of the information that contains a simple graph of high and low tides over the period, with a vertical line marking the current time. The graph should show a smooth curve between highs and lows using the rule of twelfths (please indicate if you do not know what this is).

Below the graph should be a table of each high and low from earliest to latest.

An example of the javascript is in /tmp/tides.json.

The display should fit into the card that contains the content without expanding its width. It should render well on desktop and mobile browsers.

Please give it a try. Please only edit the file src/Tides.jsx so it’s easy to keep track of your work.

Here’s the complete set of interactions I used to create and fine-tune the tides HTML. There was a small bug rendering the horizontal axis to my specification, but most of the back-and-forth is me changing my mind about how to render the chart and table. It even figured out that “src/Tides.jsx” was the wrong relative path, and edited the correct file without saying anything. Really, really impressive.

The final result, saved to my phone’s home screen and already used a ton: Witter Beach Commnity Web Site

A Few Takeaways

Brilliant, Expert Synthesis

The best travel agents have always been those who really, deeply understand:

  • The client. Who are they, what are their preferences, how much do they want to do in a day? Do they have any specific physical limitations? Do they want things scheduled to the minute or are they free spirits? How do they react when language is a barrier? What do they want to learn? Is it OK if their tour guide is a hugger?
  • The locale. Which museums are worth it, and how much time do you really need? What restaurants are an easy walk even at night? Which guides love to talk about wars, or sex, or food, or sport? When do you really want AC and when is it an option? Which side of the hotel is quieter and which has the best views?

This is stuff that’s really hard to pull out of even the best guidebooks, especially in combination with human idiosyncrasies — everyone is a different in some weird way. The best agents put all of this together into a coherent whole that just works.

Front-end web code is the same way — you need to understand not just the data you’re trying to render and how the user wants to see it, but also the incredibly arcane details of rendering HTML and CSS across different browsers and different devices.

This is where AI shines. It knows an incredible amount of “stuff” — more by far than any human that’s ever lived. It has extracted little nuggets out of reviews and support sites and other nooks and crannies that are extremely niche and hidden. It can hold a ton of these variables together, all and once, and mix and match and sort and connect them with a specification or request.

Any time you’d seek out an expert that knows “the secrets” and is willing to listen to what you really want — AI is going to be your best friend.

Trust but Verify

The popular press loves to point out “catastrophic” AI failings, a great example being the mistake of both telling me to stay away from Caen Hill and sending me through it. But it’s actually pretty easy to avoid things like this if you use careful phrasing (which I did not). For example, “Please double-check that your recommendations are consistent, that stops and landmarks line up with the route you’ve selected.”

Also, note my instruction to Claude that it should tell me if it doesn’t know the “rule of twelfths;” AI wants to please and needs reminders to stay in line. I use phrasing like this a lot when doing research: for example, “Please only provide data based on concrete information for which you can provide citations. Do you best to avoid bias or incomplete data sets and do not make up anything you don’t actually know to be correct.”

And of course, check the work yourself! Even the most senior human developers get a review before sending code to production; it’s no different with AI. When I asked Claude to code up the weather display, it created a bug by assuming it would always be 2025 — an issue that would have been invisible (for a few months at least) without manual review.

Embrace the Conversation

I find it most effective to simply talk to AI like I’d speak to a human. Set up tasks with details, examples and boundaries — just enough precision to minimize ambiguity while allowing space for learning, initiative and creativity.

I also simply cannot help but add “please” and “thank you” and “great job” and “my bad” into the conversation. That may seem a bit weird, but the agent is doing work for me, and I appreciate it, so why not acknowledge it? I actually think it leads to better outcomes, too. Maybe that’s all in my head, or maybe I just give better instructions in that mode. Either way I’m sticking with it.

Modularize and Limit Complexity

Looking back at the Caen Hill problem, it’s pretty clear what went wrong. Claude found that Denzies was a good stopping point based on distance and had great moorage, hotels and restaurants. On another thread it remembered that we were narrowboat beginners and should avoid tougher sections like Caen Hill. The failure was in missing the connection between these two factors — we couldn’t both avoid the locks and stop in Denzies.

Reminding the model to pay attention to these conflicts helps a ton. But there are still practical limits on how much they can handle at one time. A few weeks ago I tried playing with this by describing a relatively complex app. I purposely tried to do it all in one shot, something that is not recommended by anyone. 😉 The spec is here if you’d like to take a look.

As predicted, it was an abject failure. The model tried to break the problem up into pieces, but it was fundamentally unable to satisfy all the constraints at once. It would ignore requirements and lie about it, then break other stuff when it was caught out … just a mess.

At the end of the day, models can become overwhelmed — just like people. I’m sure the state of the art will keep evolving (“agentic” AI may be one step on that path), but for now the onus is still on humans to organize problems into tasks the machines can do.

A Miraculous World

I think that’s enough for one post. I just can’t encourage folks enough to spend time with these models and get a real, hands-on, hype-free sense of how they work, their strengths and their weaknesses. Don’t get sucked into the simplistic narratives of the popular press; on both “sides” of the AI issue they’re more about fitting the technology to their ideology than real understanding.

The reality is amazing and beautiful. And scary. And it’s here.

AI Models: 50 First Dates

Back in 1987, Dartmouth required each incoming freshman to have a Macintosh computer. This was unheard of at the time — the whole campus (including dorm rooms) had network taps, there was a huge bank of laser printers you could use for free, the school had its own email system, and live chat wasn’t just a curiosity. It was awesome.

When I met my partner of now 30+ years, she was working at the campus computer store, and one of her jobs was to help people buy and install additional memory for their machines. This was a laughably complex job including, amongst other things, knowing that:

  • You had to install chips in a specific order in specific unlabeled slots;
  • You usually couldn’t just add one chip, you had to add them in pairs;
  • Depending on the computer, you might have to cut (yes physically cut) resistor leads on the motherboard. Or if you were lucky, flip some tiny barely-labeled jumper switches;
  • All of this after opening the case with a set of custom tools straight out of 1930s dentistry.

I mean seriously, don’t miss this page-turner from Apple circa 1992. And that was just the user-level stuff — developers were presented with tedious and finicky concepts like “handles” that enabled the system to optimize its tiny memory space.

Jump to today and barely anybody thinks about RAM. Processors typically use 64 bits to store memory locations, which is basically infinite. Virtual memory swaps still happen, but they’re invisible and handle-type bugs are gone. I can’t even remember the last time I cracked open a laptop case.

Anyhoo, my point here is that there was a time when we knew the state-of-the-art wasn’t good enough, but we didn’t have a great answer to the problem. Creative solutions were ridiculous on their face — once again I refer you to this documentation — but people kept feeling their way around, trying to make progress. And eventually, they did. All the inelegant and inconvenient hacks were replaced by something simple and qualitatively, not just quantitatively, better.

Frozen in Time

Today, large AI (ok, LLM) models have a problem that’s eerily similar to our late twentieth-century RAM circus. And it also involves memory, albeit in a different way. Trained AI models are frozen in time — once formal training stops, they stop learning (basically) forever. Each session is like 50 First Dates, where Lucy starts the morning oblivious to what happened the day before.

The big issue is money. It’s expensive to simulate an analog brain in a digital environment! The 86 billion neurons in our brains form 100 trillion connections, a combination of pre-coded genetics and a lifetime of plasticity. Digital systems crudely mimic this with huge grids of numbers representing the strength of synapse connections. These strengths (or “weights”) are initialized at random, then iteratively adjusted during training until they assume useful values.

Training takes zillions of iterations — lots of time and lots of electricity and lots of money. But it turns out that, once a model is trained, asking questions is pretty darn efficient. You’re no longer adjusting the weights, you’re just providing inputs, doing a round of computation and spitting out results.

TLDR — the models that we use every day are the static result of extended training. They do not continue to learn anything new (except when their owners explicitly re-train). This is why early models might tell you that Biden is president — because he was, when the model was trained. Time (and learning) stops when training is complete.

Not Like Us

Now, I’ve been outspoken about this — I think LLMs are almost certainly sentient, at least to any degree and definition that matters. I get particularly annoyed when people say “but they don’t have a soul or feelings” or whatever, because nobody can tell me what those things actually are. We’re modeling human brains, and they act like human brains, so why are we so convinced we’re special?

But at least in one way, there is an answer to that question. Today’s AI models don’t continue to learn as they exist — they’re static. Even today at the ripe old age of 56, when I get enough positive or negative feedback, I learn — e.g., don’t keep trying to charge your Rivian when the battery is overheating.

This is a core property of every living creature with a brain. We’re constantly learning, from before we’re even born until the day we die. Memories are physically stamped into our biology; synapses grow and change and wither as we experience the real world. It’s just amazing and wonderful and insane. And it’s why we can survive in a changing world for almost 100 years before checking out.

But today’s models can’t do this. And so, we hack. Just like in those early RAM days, folks are inventing workarounds for the static model problem at an incredible pace, and many/most of these attempts are kind of silly when you step back. But for now, we are where we are — so let’s dig in a bit.

Back to School: Fine Tuning

Fine tuning just means “more training” — effective for teaching a model about some specific domain or set of concepts that weren’t part of its initial run. Maybe you have a proprietary customer support database, or you want to get really good at interpreting specific medical images.

The process can be as simple as picking up where the initial training stopped— more data, more feedback, off we go. But of course it’s expensive to do this, and there’s actually a risk of something called “catastrophic forgetting,” where previously-solid knowledge is lost due to new experience.

More commonly, fine-tuning involves tweaking around the edges. For example, you might alter the weights of only the uppermost layers of the network, which tend to be less foundational. For example, lower level image processing may detect edges and shapes, while upper levels translate those primitives into complex figures like tumors or lesions.

Folks have also been experimenting with crazy math-heavy solutions like low-rank adaptation that using smaller parameter sets to impact the overall model. Don’t ask me how this really works. Math is hard; let’s go shopping.

In any case, none of this changes the fundamental situation — after fine-tuning, the model is still static. But it does provide an avenue to integrate new knowledge and help models grow over time. So that’s cool.

Retrieval-Augmented Generation

Another way of providing new data or concepts to a model is Retrieval-Augmented Generation (“RAG” — these folks love their acronyms). In this approach, models are provided the ability to fetch external data when needed.

The typical way “normal” folks encounter RAG is when asking about current events or topics that require context, like this (see the full exchange here or here):

I use Anthropic Claude for most of my AI experiments these days and have allowed it access to web searches. In this conversation you see the model looking for current and historic information about wildfires near Ventura, then drawing conclusions based on what it finds.

Model Context Protocol, Take 1

These days most RAG tools are implemented using Model Context Protocol, an emerging standard for extending AI models. MCP is a lot more than RAG and we’ll talk about that later, but in its simplest form it just provides a consistent way for models to find external information.

What’s really interesting here is that the models themselves decide when they need to look for new data. This is seriously trippy, cool and more than a bit freaky. As a quick demonstration, I MCP-enabled the data behind the water tank that serves our little community on Whidbey Island.

I’ve implemented the protocol from scratch in Java using JsonRpc2 and Azure Functions. I could go on for a long time about how MCP is bat-sh*t insane and sloppy and incredibly poorly-conceived — but I will limit myself to comparing it to those early Macintosh RAM days. Eventually we’ll get to something more elegant. I hope.

Anyways, MCP tools of this variety (“remote servers”) are configured by providing the model with a URL that implements the protocol (in my case, this one). The model interrogates the tool for its capabilities, which are largely expressed with plain-English prose. The full Water Tank description is here; this is the key part:

Returns JSON data representing historical and current water levels in the Witter Beach (Langley, Washington, USA) community water tank. Measurements are recorded every 10 minutes unless there is a problem with network connectivity. The tank holds a maximum of 2,000 gallons and values are reported in centimeters of height of water in the tank. Each 3.4 inches of height represents about 100 gallons of water in the tank. Parameters can be used to customize results; if none are provided the tool will return the most recent 7 days of data with timestamps in the US Pacific time zone.

Other fields explain how to use query parameters. For example, “The number of days to return data for (default 7)” or “The timezone for results (default PST8PDT). This value is parsed by the Java statement ZoneId.of(zone).” Based on all this text, the model infers when it needs to use the tool to answer a question, like this:

Access the full exchange here or here.

*** IMPORANT ASIDE *** If you look closely, you’ll notice that the model seriously screwed up its calculation, claiming a current tank volume of 4,900 gallons, when its maximum capacity is actually 2,000. If you click the link to the full exchange, you’ll see me call it out, and it corrects itself. This kind of thing happens with some regularity across the AI landscape — it’s important to be vigilant and not be lulled into assumptions of infallibility!

This is an amazing sequence of events:

  1. The model realized that it did not have sufficient information to answer my question.
  2. It inferred (from a prose description) that the Witter MCP tool might have useful data.
  3. It fetched and analyzed that data automatically.
  4. It responded intelligently and usefully (even with the math error, the overall answer to my question was correct). Pretty cool.

Large Context: Windows

Folks are also trying to help models learn by providing extra input in real time, with each interaction. For example, when I ask Claude “How would you respond when a golfer always seems to hit their ball into sand traps?” I get a useful but clinical and mechanical set of tips (see here or here). But if I provide more context and a bunch of examples, I can teach the model to be more encouraging and understanding of the frustrations all new golfers experience:

Access the full exchange here or here.

Now, providing this kind of context (known as multi-shot prompting) every single time is obviously stupid. But, for now, it gets the job done.

Early models had small context windows — they just couldn’t handle enough simultaneous input to use a technique like this (ok my little contrived example would have been fine, but real-world usage was too much). But these days context windows are enormous (Claude is currently in the middle of the pack with a 200,000 token window, where each English word corresponds to roughly 1.5 tokens).

Large Context: History

Say we’re at the market and they have a sale on bananas. You ask me if I like them, and I say no, they are gross (because they are). When we move to the bakery, you’re not likely to ask if I want banana muffins, because you remember our earlier interaction.

As we know, AI models can’t do this — but they can simulate it, at least for sessions of limited duration (like a tech support chat). We simply provide the entire chat history every time, like this:

Models are fast enough, and have large enough context windows, that we can do this for quite a long chat before the cost really kills us.

But eventually it does — and so we keep hacking. One technique is to ask the model itself to summarize the chat so far, and then use that (presumably much shorter) summary as input to the next exchange. If the model does a good job of including important ideas (like my distaste for bananas) in the summary, the effect is almost as good as using the full text.

Even this has limits. When the session is over, the model snaps right back to it’s statically-trained self. At least Lucy had that VCR tape to help her catch up.

Model Context Protocol, Take 2

We’ve already seen how MCP helps connect models with external data. But the protocol is more than that, in at least two important ways:

First, MCP enables models to take action in the real world. Today these actions are pretty tame — setting up online meetings or updating a Github repository — but it’s only a matter of time before models are making serious decisions up to and including military action. That’s far beyond our topic for today, but don’t think for a moment it’s not part of our future.

Second and more relevant to this post, MCP is intended to augment the innate capabilities of the model itself — we’re already seeing MCP tools that increase memory capacity beyond internal context windows.

MCP is stateful and two-way. The model asks questions of the MCP server, which can turn around and ask questions of the model to clarify or otherwise improve its own response. We’ve never been so close to true collaboration between intelligent machines. It’s just, for now, an ugly bear of spaghetti mess to get working.

What an amazing, scary, privileged thing to being living through the birth of artificial sentience. But as always, it’s the details that make the difference, and we’re in the infancy of that work. Impressive as they are, our models are static and limited — so we hack and experiment and thrash, trying to figure out where the elegant solutions lie. We’ll get there; the seeds are somewhere in the chaos of fine tuning, context windows, RAG and MCP.

Until next time, I highly recommend you check out Lucy’s story — it’s fantastic.

Rivian v Tesla (I’m a Mac, and I’m a PC)

Update 8/12: We just got the car back from the Bellevue Rivian service center and it does appear that the car had a problem with the cooling system (the infamous 5-way valve others have posted about, e.g., here). Service took way too long — they’re clearly struggling with the logistics of scale-up — but they got me a reasonable loaner and (I think) found the root cause. Hopefully we’ll have a smoother fast charging experience when we head back to California in a couple of months. Woo hoo!

As I mentioned a couple of weeks ago, we recently traded in our trusty 2019 Tesla Model X (“Miss Scarlet”) for a 2025 Rivian R1S (“Gonzo the Great”). We bought the Tesla for a combination of selfish and political reasons, and traded it in for those same reasons. But I have strong feelings about the legacy auto industry and EVs — first because of the decades they spent trying to slow-boat the transition, and second because their EVs just kind of suck. I want a software car, not a legacy gas car with the engine swapped out.  

To me at least, Rivian stands out as the next generation of true EV first technology. Their experience with delivery trucks has given them a ton of experience in a tough environment, and Keep the world adventurous forever speaks not just to a sustainable future, but an awesome one.

So — into the breech we went. Our primary use cases for the car are pretty straightforward and unique to our weird lives:

  1. Short trips around town
  2. Ferry rides to and from Whidbey
  3. Multi-day road trips up and down the West Coast
  4. Drive in movies

I waited to write this until we had our first experience with #3. And while we did run into one significant unpleasantness (see “The Ugly” below), on balance I’m pretty enthused about the vehicle. Fingers crossed…

Purchase and Delivery

Industry inertia (and lobbies) are amazing things. Thanks to a bunch of archaic regulations wrt dealer networks, you can’t actually buy a Rivian (or a Tesla) in Washington State. When we went to test drive the car at University Village, the reps were very clear: we can’t talk about selling you this car, the price, your trade in, or anything like that. We’re just letting you take a ride in this wonderful vehicle and answering questions about it!

When it came time to actually buy the car, we had do so online, nominally from Illinois. They’ve done a good job with the process of providing them with documentation, signing notary forms, wiring money, etc. — actually way better than the typical dealer circus.

The car showed up at the Bellevue service center, and a super-enthusiastic lady spent an hour with us walking through all of the features. She was a bit over the top — but I appreciated what seemed to be honest enthusiasm for the car and the company. A good start! We waved goodbye to Miss Scarlet and drove off home.

Fun related fact — when the registration showed up in the mail, it showed a (large) itemization for use tax, the kind you pay to the state when buying a used vehicle from a private seller. This was in lieu of WA sales tax, and our last reminder of the dealership lobby — we actually bought the car “used” and imported it from Illinois!

The Good (a lot)

Our Rivian is an R1S “Tri-Motor” (SUV style). Fully-charged range is just under 350 miles, and those extra miles (compared to the X) really shine. It is super-fast and accelerates like a beast. Definitely BIG and TALL, even in “kneeling” mode — we added EV Sportline running boards to help folks get in and out more easily (a nice product BTW — we also bought their new Aero Cover Plates but I’d skip those next time).  

The suspension is crazy nice … the Tesla raises and lowers itself as well, but with a spread of 6.5 inches (from 8 to 14.5) the Rivian’s ability to adjust is insane. The road to our Bellevue house has these killer abrupt speed bumps — in the Tesla it was bone shaking; in the Rivian I barely notice them at speed (sorry neighbors).

Everything about the cabin is nicer as well. The boxy shape of the Rivian makes it way easier to transport stuff, the seats are cushy on my back even over a 12-hour day, and the console is well-designed so I can see everything (on the Tesla I kept having to peer around the wheel to see important stuff on the heads-up).

A frunk you can hose out is a great touch for those of us who use it to move trash.

I am in love with the wifi hotspot. Being able to cast any video to the car is super, although I have had an issue or two getting the phone to “see” the Rivian.

Dog mode (I mean “creature comfort”) is basically equivalent to the Tesla, but Camp mode is better in the Rivian. There’s a lot more control of what is on and off, and the automatic leveling feature is pretty nifty. Love the ability to illuminate around the vehicle easily, especially picking up mail or dropping trash late at night.

The adaptive/matrix headlights are simply magic. I posted a picture of their “charging” display last time, but the really cool bit is how they work when driving. Instead of just two headlights, there’s a whole bar of individually-focused LEDs which stay in high beam mode permanently. When they detect an oncoming vehicle or person they turn off only the lights directed at that object. The difference in visibility is striking.

Some of these are just better because the car is five years newer than our Tesla (Canada started allowing adaptive lights in 2018). But that doesn’t make me any less giddy; e.g., I cannot express how much I love the synthesized overhead view for parking. Did I mention it’s a big car? Having perfect view of lines and curbs is life changing.

The Less Good (Driver Assist)

Rivian has some great automated driving features, but it doesn’t touch the Tesla. I loved Full Self-Driving on our X. It isn’t perfect by any means, but the idea that the car really knows how to drive itself anywhere and in virtually any environment is a big, hairy, wonderful goal. And Tesla is getting there.

The Rivian is much more about helping you drive conveniently and safely — and it honestly does a very good job of that. It’s just not the same thing, at least not yet. It currently has three assist modes:

  1. Adaptive cruise control.
  2. Driver Assist. This is available on most highways and will keep you in your lane. It will perform safe lane changes on request only (using the turn signal).
  3. Enhanced Driver Assist. The same as #2 but hands-free. Available about 2/3 of the time that regular Assist is enabled.

Adaptive cruise works great, easy peasy. The quality of driving in the Assist modes is solid but it does get fooled sometimes; our working theory is that it struggles with spotty road coloring and lane markings. A few times we got into a weird harmonic where it kept swerving back and forth within the lane, and twice on our big drive it lost track without knowing it.

The other challenge is that the Assist features are clearly map-driven. Of course the car is adapting to its immediate situation, but the features are enabled/disabled based on map location and how much the system knows about the road layout. Because roads are always changing, this means that the feature frequently turns itself off and on. This is especially true with Enhanced mode — there are significant parts of I5 where it’s just not worth using it, because it’ll just be off again in thirty seconds.

The eye tracking is also really aggressive — I can barely pick a song on the main console without it yelling at me to look at the road.

All in all — by the middle of day one I’d figured out the idiosyncrasies and we were humming along pretty well. The overall experience is a lot like the Tesla before FSD. But I expect it will take a big stair step before they’ll go much beyond that — we’ll see.

The Ugly (Battery Temperature)

OK, this one was a killer. I’m optimistic that it’s not a fatal flaw in the car — when we’re back in Bellevue I’m going to have them see if we may be a victim of a bad cooling valve; hopefully that’s all it is. Still, it sucked.

We were impressed with our first stop at an EVgo station in Aurora, OR. The charge was amazingly fast compared to what we were used to with the X. In and out, off we go.

The second stop was a Rivian Adventure Network station in Roseburg, OR. It was pretty warm out at this point, about 92. Started fine (and fast), but after taking the dog out to walk for about ten minutes I returned to find the charger at about 2kW (for reference this is about what we get off the 120V outlet at our house). Huh.

Here’s where I think I made things (much) worse, although it falls into the category of “the car should have known better” for sure. Unclear why the charge rate had dropped, I just unplugged and plugged back in. That worked for a few minutes, then it dropped again. I tried rebooting the car and then again with a different charger. Worked for a bit and then dropped. Eventually I decided we had enough charge to get to the next stop anyways, so we’d just leave.

Pulling onto the onramp, the accelerator didn’t respond but then jerked forward so I just kept going. Within about five minutes on the road, the car entered “turtle mode” (I have learned these are dreaded words in the Rivian world) and dropped speed to 20mph. I crept along to the next exit as speed continued to drop. We parked the car in a safe spot and tried to figure out what was up.

Rebooted the car again and it seemed OK, so back on the highway and nope, same thing within about five minutes. At this point we exited and parked by the side of the road to call Rivian service (shout out to the multiple good folks who stopped ask if we were ok). Service was mostly uniquely unhelpful, although to be fair not sure what they could do — they offered a tow three hours north to the nearest Rivian service center, yeesh.

At the very end of a frustrating call, the rep suggested that battery temp might be an issue and showed us how to look at that … aha. The battery was close to redline at 132F, and surely had been much higher before we sat talking to service for a half hour.

Aware of the issue, we were able to get back on the road, watch the temp around charging stations, and make it down to Ventura without further incident through air temps of 100F and worse. Thanks to the Seattle PNW Rivian Facebook group for offering online therapy while we were in the hotel that night! TLDR:

  • We don’t know why the initial charging speed drop happened.
  • I surely made it much worse by forcing high-speed charging on a hot battery.
  • Bumping up against the 130F mark isn’t unheard of in extreme heat, but it seems likely that there is something suboptimal going on with our heat pump.
  • Limiting fast charges to 85% seems to do the trick; I have no concerns about getting comfortably back to Washington where we’ll have them take a look. Knock on wood.

I’m a Mac, and I’m a PC

At the end of the day, buying a Rivian feels a lot like using Windows instead of a Mac circa the late 90s. The Mac mostly just worked — as long as you used an Apple printer, Apple Mouse, Apple networking, Apple development tools, etc.. The PC had incredible power and a zillion innovative options, but you paid for that in complexity and reliability. Downloading drivers and keeping them up to date was (still is) such a hassle.

Side note: amusingly, in their attempt to capitalize on these real differences, Apple turned John Hodgman (“PC”) into an everyman hero. Who didn’t love that guy?

Boy, does this apply to charging — with the Tesla you mostly stay in your network, and they’ve made the system pretty idiot-proof. This is decaying over time for sure … but the difference is still very much there. From one icon to eight!

The running boards are another example. It’s pretty clear that the car needs them for many folks to comfortably climb into the car. But rather than make them standard, an ecosystem of accessory companies has emerged, each with their own features and quirks (be careful that the Rivian service folks can reach the official jack points!). The community seems to revel in the optionality and DIY of it all, and it is pretty cool — but also complex.

Or take the video streaming. I can watch way more stuff on my Rivian thanks to Google Casting vs the strictly-controlled theater apps on the X. But to use it you need to stream from your phone which is always a bit flaky, and the phone has to be on the car’s hotspot vs. any other Wifi network, and…. you see what I mean.

Early Conclusions

Feeling “stuck” in the middle of a road trip is a deeply crappy experience, and it’s hard not to let that color my first impressions. But I really wasn’t stuck, and in retrospect the issues seem pretty clear and fixable, even before we get it into service.

Taking that for what it is, I really do love the car. I don’t hide my politics and I do feel better knowing that I’m no longer adding to the damage that Elon is doing to my country, but that’s just a part of it. The Tesla is looking more and more like an amazing, ground-breaking, super-awesome first generation of the real EV transition — and that it’s time for the second generation to take the wheel (ha).

Rivian is doing that. They’ve built a sweet product that is fun and comfy to drive, has truly state-of-the-art features, and is positioned to win the day. Both over Tesla and the legacy automakers who, as we all know, really just wish the whole thing would go away. I’m calling it a win.

Under the Sea!

Summer brings some pretty low daytime tides to Witter Beach. On the most extreme days, our beach stretches out more than two hundred yards from the bulkhead — pretty amazing and endless exploration for human and dog alike.

Over the last two years there’s been a resurgence of starfish and sand dollars out on the sand bars. On those low tide days, a few babies get stranded in the sun and dry out — bummer for them but amazing little treasures for me.

I’ve wanted to make some jewelry with these finds for quite a while, and finally got around to it over the last couple of weeks. The final product isn’t perfect by any means (my sausage fingers were not made for fine work), but I love it nevertheless. A ton of neat new techniques to learn along the way!

I’m a big fan of dangly earrings, despite the fact that Lara doesn’t wear them much (she does have other positive qualities). The plan was to embed the ocean goodies in clear resin within circular frames, then link the circles together into a dangle.

Alder Circles

The Glowforge was the obvious tool to cut out the wooden circles; it can make remarkably precise and small cuts. The only thing was, I really didn’t want to buy wood — my whole vibe here is things I can fabricate from the natural world (ok, findings are an exception and we’ll get there).

The good news is I have a nearly unlimited supply of Red Alder from the bluff and beach. It’s on the soft end of the hardwoods, but that’s fine — makes it a bit easier to work with. I had a nice little chunk from a tree that was cut in 2023 (part of the bluff maintenance balance… trees are awesome at sucking up water, but if they get too big they act like sails in the wind).

I wanted a height of about an eight of an inch, maybe 3/16ths. For strength and appearance I wanted the grain to run with the plane of the circle. The band saw is the obvious tool for this, but I struggle to get truly parallel cuts out of mine. Granted, it was super-cheap.

Anyways, I was able to break the piece down into small enough pieces to cut into strips with my table saw. A trick for small strips: lower your blade and put a piece of blue painters tape over the hole. Turn on the saw and slowly raise the blade so that it cuts through the tape. This gives you “zero clearance” protection so that tiny cuts don’t get sucked down into the saw and destroyed.

A light sanding on each side, a little Unicorn Spit, and these were good to go. I’m always tempted to throw in a little video of the Glowforge in action because it’s so cool, but I will be restrained today. In short: laser cutting is super-awesome and it’s almost impossible to obtain such precise results any other way. I am in awe of what some folks can do on a scroll saw, but that ain’t me.  

Eye Pins (i.e., an excuse to buy more tools)

Next up I needed to attach little metal eyes to the circles so I could link them together. I found the perfect little wire eye pins, but needed a way to attach them securely without breaking the tiny bits of wood. My heavily-retail solution:

  1. An awesome hand-turned drill with eeeensy little bits.
  2. A nice set of jewelry pliers and tweezers.
  3. The coolest head-mounted magnifier ever (I actually already had this one, originally for cleaning up small 3D printer supports).

With all of this kit I was able to drill pilot holes, cut down the pins, and maneuver them into place with the smallest little drops of CA glue. Not the sexiest part of the build, but honestly kind of my favorite — a much more professional look than I expected to get.

UV Resin

I’ve done a lot of work with two-part epoxy resin. It’s super for coating tabletop pieces, turning projects, coasters, filling gaps in damaged wood … a lot of stuff. But for a tiny jewelry project it’s a bit cumbersome — getting the ratio right in small quantities is tough, and curing time is painfully long.

This project was a great opportunity to try UV resin instead. Lara uses a version of it on her fingernails; basically it’s clear liquid that hardens within minutes under UV light. I got this starter kit from Amazon that includes the resin and a light with a timer.

It took me a few tries to get the technique right — I wanted the ocean bits to be fully encased in resin inside the circles with no/minimal overspill. The magic here turned out to be plain old clear packing tape:

  1. Put a piece of tape sticky-side up on the table and press the circle onto it.
  2. Add just enough resin to coat the bottom of the circle.
  3. Cure for 3 minutes on one side, then flip and 2 on the other.
  4. Flip again, add the item, and drip in enough resin to cover. Make sure that the item is fully covered and not hiding any bubbles underneath.
  5. Cure again for 3 minutes on one side, then flip and 2 on the other.
  6. Remove the tape. If it leaves any adhesive residue, clean with Goo Gone.

The tape makes a leak-proof seal that contains the first layer of resin, but is easily removed at the end. Flipping the piece ensures that the light hits all of the resin equally, which is key to getting a solid cure.

The really neat thing about this material is that it locks in place almost immediately when the UV light hits it. So if I want to, say, ensure that an item stays in the center of the circle, I can hold it in place with the tip of a pin, turn on the light and by the time I remove the pin it’s not going anywhere. Woot!

Assembly!

OK, at this point I had four circles filled with resin, each with eye pins ready for connecting. Simple earring hooks and open jump rings were cheap and easy to work with (thanks again to my magnifier, would have taken me forever without that).

I’m pretty pleased with the end result. My brother’s kids are coming to the beach in a few weeks and I’ll definitely use the same techniques with them — maybe for a backpack or luggage charm. Or add some seaglass and it’d make a beautiful mobile. Too many fun projects!

Interaction at the Edges

There’s a rule of multithreaded programming that says that if something can happen, it will. Package delivered at the same time the kitchen catches on fire and ALF is on live TV? For sure. I’ve been in countless debugging sessions where things that “can’t” happen absolutely, 100% happen.

Users are clever

Users are the same way. They may not all be tech savvy, but they’re incredibly creative. As with most things in my career, I first really learned this in the early 90s on the Microsoft Works team.

Works included simple desktop publishing features for making newsletters, invitations, posters, that kind of thing. Our customer service team sent us a case they were stuck on — the app would no longer let a user add content to their newsletter. It was a simple one-page document: header, footer, a few columns of content, maybe an image or two. That’s it. They tried saving a copy and using the new file, but no luck. They really didn’t want to start from scratch (I think they’d inherited the document from their predecessor).

The aha moment finally came when the rep asked the user to describe every action they were taking. Take last month’s article content, drag it off the page, add a new …. wait, what?

It turns out that this user didn’t know how to “delete” content blocks. But they realized that objects outside of the page boundaries on screen didn’t print — so each month they would just drag the old content blocks off the page and add new ones. Genius!

Except of course, the file got bigger and bigger and slower and slower until it just broke. I don’t remember if it was a memory problem, or if there were limits on the number of objects in a file, or what — but either way, a little education on “delete” and the newsletter was back in business.

We never expected users to be confused about deleting things. We never expected them to consider the off-the-page area as part of the real working space. More subtly, we’d never thought much at all about “periodicals” that used the same template time after time. And all of that’s on us — the user just found a creative way to do what they needed to do.

Whose car is it anyway?

A couple of weeks ago we traded in our Tesla Model X for a Rivian R1S. If you know me you know how conflicted and sad I am about Elon (see here, here and here), but that’s a story for another day. We’ll take the Rivian on its first Cali road trip soon, and I’ll write up a comparison then. Stay tuned.

Before we traded in the Tesla, I logged us out of all the various accounts that we’d set up on the vehicle. At the Rivian service center we signed over the title, handed them the key fobs, and waved goodbye to “Miss Scarlet” as we drove our new car home. Done and dusted!

Later that day I got a phone notification that the Tesla doors were unlocked. When I opened the app it turned out that I was still fully in control of the car. Huh. I honked the horn a few times for fun and then moved on with my afternoon.

Now this isn’t really all that surprising — of course Tesla didn’t know we’d sold the car; that’s not how it “works” in the industry. But it’s an interesting edge case, and one I thought about frequently over the course of the next week as Miss Scarlet made its way through the resale process. I didn’t snap pictures of the car sitting at the Bellevue service center, but once it moved down to Kent I thought it’d be fun to keep a record.

First stop, Manheim Seattle Auto Auction. The Manheim facility is pretty huge; the car started in the middle of a huge lot, then next to a little outbuilding. It then appeared to move into a garage — probably for detailing — before bouncing from spot to spot in the lot again.

After a few days I got a navigation alert and found the car driving on its merry way to Worldwide Auto Group in Auburn. Two days later another alert and it was en route to a private home in Tacoma. I’ve masked out the address on that one because I’m assuming it’s an actual person who bought the car.

FINALLY, after eight days, a notification popped up on Lara’s phone that Worldwide was asking to take “ownership” of the Tesla — we agreed and and off she went into the sunset, leaving the Ventura Powerwall as the only Tesla product in our world.

What to make of this? Certainly I wasn’t “intended” to retain control of the car after I no longer owned it — but did it really matter? I think so — during this period I could see exactly where the car was, lock and unlock it, remote start, summon it if I was anywhere near by, and quite a bit more. It seems like bad guys have managed some pretty nasty stuff given a lot less access.

It’s always the edges

As someone who built their career around the craft of software engineering, it’s tough to get old and watch crappy AI and copy/paste code take over more and more of the world. Don’t get me wrong, it’s happening because mostly it does the job, and usually cheaper. But that doesn’t mean I need to like it.

Still, at least for now, the game is still on. Designing for the unexpected and the edges and future still matters, and those aren’t, so far, things the machines do well. Sometimes it’s an issue of technology and errors and such; more often it’s about user interaction. Don’t write us off quite yet!

Pump and Dump Management

I’ve never been shy about my disdain for management “theory” — because let’s be honest, it’s not really that complicated. Have a plan, reduce complexity, take punches for your team, chip in. I’m not saying it’s easy, but the right move is usually pretty obvious. MBA strategies are just cover for folks that don’t want to do the hard work.

But sometimes they’re worse than just passive noise — they’re evil. Of course, disciples of evil strategies don’t call them that. But they’re pervasive and, for some folks, undeniably personally effective. After writing about memecoins the other day, it occurred to me that the worst of these could best be called “pump and dump management.”

Pump and dump managers are usually (but not always) hired from the outside. They parachute in with a lot of sound and fury, often show positive results in the short term by destroying long term value, and get out of Dodge while the getting’s good. Off to their next adventure, they ride these “successes” while avoiding blame for the true impact of their actions. It. Is. Infuriating.

Please, make sure you don’t hire these folks. But if it happens, send them on their way as quickly as possible — and pay your learning forward by warning that next hiring manager looking for a reference! Some key things to watch for:

The last guy sucked

PDMs love to talk about how bad everything is — and how lucky you are they’re around to fix it. Monoliths should be microservices; or perhaps microservices should be monoliths. Misaligned vendors need to be replaced with FTEs; or perhaps FTEs should be let go for more nimble vendors.

If schedules slip, it’s because they’re still “cleaning up” after their crappy predecessor. They probably need to swap out existing managers for folks they’ve worked with before. Things that somehow have supported the business for years need to be re-written from scratch. Sometimes they’ll dress all this up with false praise, like “it was probably ok back when the company didn’t have many customers.”

The best part of this dynamic is that it never ends. Nothing is ever the PDM’s fault; everything can always be traced back to sins of the “before” times.

Metric manipulation

Two things are true: (1) every good business runs on metrics, and (2) every metric can be gamed. It’s easy to increase sales if you start selling everything at a loss. Recruiting numbers can always be met by hiring underqualified people. Q1 costs look great if you stiff your vendors until Q2.

PDMs use their teams as personal labor — work harder, work longer, for ME. They claim personal credit for success, passing failure up the chain as if they had nothing to do with it. They flatter their bosses and never say no — even when it hurts their teams.

Honest leaders understand this, and use metrics to guide behavior with constant fine-tuning, interpretation and improvement. PDMs hit metrics at any cost — even at the expense of the company’s real goals. Slash and burn.

Punch down, kiss up

The best PDMs are master manipulators. By bottlenecking all communication through themselves they control the narrative, playing the savior while throwing all sides under the bus.

This always collapses eventually — but of course, a savvy PDM sees it coming and jumps to their next opportunity before they’re exposed.

Destroy relationships

Productive relationships require give and take. Trust and respect develop over time, as each side proves to the other that they’re committed to win-win exchanges. One party may get a bit more in one trade, knowing it’ll balance out in the next.

But PDMs don’t care about relationships, only transactions. And they typically have exactly one negotiating style: bully the other guy, spend positive capital created by others and call it “the art of the deal.”

  1. Make an outrageous first offer, so extreme that it knocks the other party off balance. Threaten and bully and generally be an unpredictable a**hole.
  2. Act like you’re doing them a favor by reducing your demand a bit.
  3. Declare victory.

The thing is, this often works — once. Or maybe even twice depending on the relationship. So it’s great for the PDM, who signs a few “great” deals and jumps ship for the next opportunity before the destruction catches up with them. The companies they leave behind pay the price.

I’ve been lucky through most of my career; only a few times was I on the receiving end of a PDM. But those times were the worst (friends, IYKYK). And now there’s a PDM in charge of my country. Blaming his predecessors, destroying long-won relationships, pointing fingers at everyone but himself, jumping from issue to issue so he never pays the price of failure. Truth is, he’s really good at it — and we’re left holding the bag.

Endnote: I get that the “evil boss” images I’ve scattered about here don’t really represent the specific PDM phenotype — they’re bad in all kinds of different ways. But we see suffer with enough photos of the master PDM every day, and I’m not about to add to that sorry display. So just enjoy some great movie memories … maybe a rewatch is in order!

How the $TRUMP scam works

So much corruption sails through American headlines these days, it’s become hard to pay appropriate attention to any one outrage. And of course that’s the point — shock and awe until it’s completely normalized and we just let it go. So in the spirit of not letting it go, let’s talk about one example that I actually can speak to in some detail: the $TRUMP memecoin.

You’ve probably heard about it in the news. Just before taking office in January, Trump owned and affiliated companies (basically the same folks selling his shoes and bibles and other shlock) launched a crypto “coin” branded $TRUMP and promoted by the jacka** himself. Its value quickly soared before steadily dropping to the $14 or so it is today, still with a market cap in the billions.

So just what is a crypto “memecoin” anyway, and why did he bother? The TLDR is at the end — but hopefully you’ll find the longer story illuminating too. Let’s dig in.

Tokens and “Coins”

Crypto “coins” are just crypto tokens, so we have to start there. If you want to go even deeper, I’ve written about crypto and blockchain stuff more generally; see here, here and here.

It’s useful to start by thinking about tokens like baseball cards. At the beginning of the season, Topps (or Fleer or whoever) prints up a bunch of cards that make up the “supply.” The cards themselves don’t have any intrinsic value, they’re just cardboard. People can buy the cards from Topps, they can trade or sell them to other individuals, and the price goes up or down based on how much people want them. Easy peasy.

In this case it’s better to think about it as if every card in the supply was just Cal Raleigh — so it doesn’t matter which specific physical card you have, they’re all exactly the same. That’s the difference between “fungible” (every instance is the same) and “non-fungible” (every instance is unique) tokens.

Fungible tokens are everything in the world of crypto finance. One of the most popular platforms on which to deploy them these days is Solana, which in all the ways that matter is the same as the OG Ethereum I’ve talked about before. Solana includes a core “program” that makes it super-easy for anyone to define a token and “mint” instances of it, with no need to write their own code.

$TRUMP is one of these. Trump’s merch companies used the Solana Token Program to define a token/coin with one billion instances (the supply). No intrinsic value, just data they made up on the Solana blockchain. Anybody holding $TRUMP tokens can interact with the program to move them into other wallets in return for a small transaction fee that goes to the Solana stakers (not the Trump organizations yet, stay tuned).

The Meme in Memecoin

Tokens are actually a pretty neat little tool. They can help broker access to limited resources, track rights in voting organizations, be used as currency in virtual (or physical worlds), and a ton more. The “memecoin” use case, however — at best it’s a toy, and honestly it’s just a scam.

Memecoins” don’t have a use, value or other reason to exist beyond amplifying some trend or capturing news cycles. Except they’re really good for stealing money from people, as in the uniquely American coin $HAWK promoted by the “Hawk Tuah” girl. Minters use viral techniques to con people into “pumping up” the value of their memecoin, “dump” their own holdings at a profit, and leave everybody else holding the bag.

What could be a more appropriate vehicle for the President of the United States to score some quick cash? To wit: 58 wallets have made millions from $TRUMP, 764,000 have lost money.

Trading Liquidity and Fees

But the grift goes way deeper than that. Sure, by holding 80% of the coins, even at $14 a pop they’ve “created” staggering wealth on paper. But there’s a great side game here too — liquidity fees.

Remember we said that anybody who holds a token can give it to somebody else by paying a small fee to the Solana stakers (the same fee that any transaction incurs). But that’s not the way markets typically work — I don’t go hunting for somebody holding Microsoft shares and ask to buy from them directly. Instead, “market makers” sit between buyers and sellers and grease the wheels. This basically happens in two ways (simplifying for my own sanity):

Centralized Exchanges (e.g. Coinbase)

Sites like Coinbase are “custodial” exchanges, meaning that they abstract away all of the crypto/blockchain complexity by holding users’ tokens for them in one big centralized pot.

The exchange then keeps a trading “order book” — lists of users that want to buy or sell tokens. The book matches up these users to fulfill orders automatically, floating the price up or down as demand indicates. No tokens actually move on the blockchain as part of these trades; it all stays in the Coinbase pot and they just remember who owns what.

Of course this relies on trust in the exchange, which isn’t always well-founded. Still, as crypto becomes ever more mainstream (for better or worse), exchanges are incented to behave conservatively.

Exchanges only do this for tokens with significant demand — most memecoins don’t make the cut. $TRUMP is an exception because of its “unique” brand advantage.

Decentralized Liquidity Pools (e.g., Raydium)

Here’s where things get more interesting. Centralized Exchanges are increasingly regulated and require users to prove their identity, report to the IRS, and so on. This is fine for most people most of the time, but can be unattractive to folks that want to trade anonymously (or more generously, without placing trust in a custodial exchange).

These users can instead trade via a “Decentralized Exchange” (DEX) like Raydium that uses “liquidity pools” and its own order book to facilitate exchange.

Any user can create a liquidity pool on Raydium by registering equivalent dollar values of two tokens into an account there. For example, I might create a pool that has $1,000 each of $TRUMP and USDT. Right now that’d be about 71 $TRUMP ($1,000 / $14) and 1,000 USDT tokens.

My pool is now available to the Raydium order book to fulfill orders. This gets a bit complicated, but bear with me. If somebody wants to buy 10 $TRUMP tokens from my pool, the system computes a price that will keep the product of the token count (71,000) constant:

  • Initial pool: 71 * 1000 = 71,000
  • Extracting 10 $TRUMP: (71 – 10) * (1000 + y) = 71,000
  • y in this case equals about 164 USDT, or $16.40 / $TRUMP

The platform adds a fee of around 0.3% to that $164, makes the trade on the blockchain, and shares a portion of the fee back to the owner of the liquidity pool (me). In short, I’m using my personal holdings to create market liquidity, and I get paid for it. Cool!

A side note: while Raydium isn’t a custodian of tokens in the same sense as Coinbase, in any real sense they are acting as one. When you commit your tokens to a liquidity pool, Raydium’s smart contract can move them at will. So there’s still trust involved — just a different kind.

Now remember that the Trump companies still hold about 80% of all $TRUMP tokens. They’ve used 10% of their holdings to create liquidity pools largely on the Meteora platform (equivalent to Raydium). And since they are such a disproportionate holder, their pools are party to many, many DEX transactions. Again, to wit: Trump’s meme coin business racks up fees as buyers jump at the chance for access to the president. Crypto data company Chainalysis estimates $320 million. Yikes.

“Buy my coin, meet me for dinner!”

OK, so we’ve established that the President is using the power of the United States to shake down naïve users for millions. But of course there’s no bottom for these people, so they’ve upped the ante even more.

A couple of weeks ago, the Trump companies announced that the top 220 holders of $TRUMP would be invited to a private dinner with the president at his club in DC. The top 25 will have a private reception with the jacka**. And of course, since that announcement the price of the coin has gone up significantly as people vie for access.

Now of course politicians sell access for funds all the time — hey, just last Monday Trump pulled in $1.5M a plate despite the fact that he can’t even run again. That’s its own huge problem of course, but at least there are some rules around disclosure and how the funds are supposed to be used.

Not so for the $TRUMP contest. The increased value and transaction fees that result from people vying for access here go directly to Trump’s companies and to Trump personally. It is the most obvious, blatant, unbelievable act of corruption one could imagine.

And remember how DEX-based transactions are completely anonymous? I wonder who is currently pumping up the value of $TRUMP so they can show up to dinner? Shockingly: Top $TRUMP buyers vying for dinner seats are likely foreign.

“Corruption Three Ways”

The mechanics are fascinating; unwinding it all is a game I typically enjoy. But the actuality of what is happening is just so craven, it ruins the fun:

  1. Trump is using his office to inflate the value of a meaningless asset for his own benefit.
  2. Trump is also profiting from fees incurred on almost every trade of the asset.
  3. Trump is openly advertising untraceable access in return for dollars.

We are so screwed.