From c6d7c8c2114f427c33cadf9ddbd19f5be08659c5 Mon Sep 17 00:00:00 2001 From: Stephen Donahue Date: Sun, 2 Aug 2026 22:45:19 +0000 Subject: [PATCH] Swap published columns for 24 entries from random.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retract the seven published columns into drafts/ and promote the 24 per-date entries split out of Notes/random.md. Bodies are verbatim; titles, subjects and slugs are new. Make publication a matter of location. Notes/Notes.11tydata.js gives anything under Notes/ permalink: false unless tagged `column`; drafts/drafts.11tydata.js renders drafts at their real permalink under `yarn dev` and excludes them from collections entirely in a build, so no template can surface one. Publishing is now `git mv drafts/ columns/`, and moving it back retracts it. Untagged notes were previously rendered into _site/ and deployed — including Notes/random.md, which was live at /Notes/random/. --- .eleventy.js | 22 +- .eleventyignore | 6 + Notes/Notes.11tydata.js | 16 + columns/2026-04-13-robo-dialer-named-anne.md | 44 +++ columns/2026-04-16-do-not-feed.md | 10 + columns/2026-05-12-qed.md | 14 + columns/2026-05-14-by-attrition.md | 9 + columns/2026-05-15-sliding-puzzle.md | 61 +++ columns/2026-05-16-world-we-made.md | 17 + columns/2026-05-17-character-creation.md | 9 + columns/2026-05-18-survivors-bias.md | 17 + columns/2026-05-21-manufactured-value.md | 17 + columns/2026-05-25-pulled-to-pitch.md | 15 + columns/2026-05-26-supporting-role.md | 13 + columns/2026-05-30-still-a-colony.md | 9 + columns/2026-05-31-weak-model.md | 32 ++ columns/2026-06-01-dead-weight.md | 83 ++++ columns/2026-06-05-chemistry.md | 9 + columns/2026-06-06-marketing-to-agents.md | 9 + columns/2026-06-09-harvard-material.md | 23 ++ columns/2026-06-15-nebulous-other.md | 9 + columns/2026-06-16-push-the-warzone-out.md | 35 ++ columns/2026-07-16-panel-of-judges.md | 32 ++ columns/2026-07-17-labor-pains.md | 9 + columns/2026-07-21-fuzzing-the-black-box.md | 9 + columns/2026-07-23-curating-options.md | 9 + columns/2026-07-27-frame-rate.md | 22 ++ .../2026-04-19-happy-idiots.md | 0 {columns => drafts}/2026-05-14-thrilling.md | 0 .../2026-06-23-hamming-it-up.md | 0 drafts/2026-07-04-eviction.md | 353 ++++++++++++++++++ drafts/_template.md | 17 + {Notes => drafts}/do-people-think.md | 0 drafts/drafts.11tydata.js | 35 ++ {Notes => drafts}/how-to-write.md | 0 drafts/index.njk | 26 ++ {Notes => drafts}/systems.md | 0 subjects.njk | 6 + 38 files changed, 995 insertions(+), 2 deletions(-) create mode 100644 .eleventyignore create mode 100644 Notes/Notes.11tydata.js create mode 100644 columns/2026-04-13-robo-dialer-named-anne.md create mode 100644 columns/2026-04-16-do-not-feed.md create mode 100644 columns/2026-05-12-qed.md create mode 100644 columns/2026-05-14-by-attrition.md create mode 100644 columns/2026-05-15-sliding-puzzle.md create mode 100644 columns/2026-05-16-world-we-made.md create mode 100644 columns/2026-05-17-character-creation.md create mode 100644 columns/2026-05-18-survivors-bias.md create mode 100644 columns/2026-05-21-manufactured-value.md create mode 100644 columns/2026-05-25-pulled-to-pitch.md create mode 100644 columns/2026-05-26-supporting-role.md create mode 100644 columns/2026-05-30-still-a-colony.md create mode 100644 columns/2026-05-31-weak-model.md create mode 100644 columns/2026-06-01-dead-weight.md create mode 100644 columns/2026-06-05-chemistry.md create mode 100644 columns/2026-06-06-marketing-to-agents.md create mode 100644 columns/2026-06-09-harvard-material.md create mode 100644 columns/2026-06-15-nebulous-other.md create mode 100644 columns/2026-06-16-push-the-warzone-out.md create mode 100644 columns/2026-07-16-panel-of-judges.md create mode 100644 columns/2026-07-17-labor-pains.md create mode 100644 columns/2026-07-21-fuzzing-the-black-box.md create mode 100644 columns/2026-07-23-curating-options.md create mode 100644 columns/2026-07-27-frame-rate.md rename {columns => drafts}/2026-04-19-happy-idiots.md (100%) rename {columns => drafts}/2026-05-14-thrilling.md (100%) rename {columns => drafts}/2026-06-23-hamming-it-up.md (100%) create mode 100644 drafts/2026-07-04-eviction.md create mode 100644 drafts/_template.md rename {Notes => drafts}/do-people-think.md (100%) create mode 100644 drafts/drafts.11tydata.js rename {Notes => drafts}/how-to-write.md (100%) create mode 100644 drafts/index.njk rename {Notes => drafts}/systems.md (100%) diff --git a/.eleventy.js b/.eleventy.js index dcdd743..8c67e78 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -75,11 +75,28 @@ module.exports = function (eleventyConfig) { eleventyConfig.addShortcode("image", imageShortcode); eleventyConfig.addShortcode("heroImage", heroImageShortcode); - // A "column" is anything tagged `column`, wherever it lives on disk - // (some columns are authored under Notes/). Newest first. + // A "column" is anything tagged `column`, wherever it lives on disk. + // Newest first. + // + // Drafts carry the `column` tag too — their front matter is complete so that + // promoting one is a plain `git mv` — so they must be filtered out here by + // the `draft` flag that drafts/drafts.11tydata.js sets. This collection + // feeds the homepage and the sidebar archive; a draft in it would be listed + // sitewide. eleventyConfig.addCollection("columns", function (collectionApi) { return collectionApi .getFilteredByTag("column") + .filter((item) => !item.data.draft) + .sort((a, b) => b.date - a.date); + }); + + // Drafts, newest first, for the /drafts/ index. The collection is populated + // in both run modes, but the only page that reads it lives under drafts/ and + // so is itself unwritten during `yarn build`. + eleventyConfig.addCollection("drafts", function (collectionApi) { + return collectionApi + .getAll() + .filter((item) => item.data.draft) .sort((a, b) => b.date - a.date); }); @@ -89,6 +106,7 @@ module.exports = function (eleventyConfig) { const reserved = new Set(["all", "column"]); const subjects = new Set(); for (const item of collectionApi.getFilteredByTag("column")) { + if (item.data.draft) continue; for (const tag of item.data.tags || []) { if (!reserved.has(tag)) subjects.add(tag); } diff --git a/.eleventyignore b/.eleventyignore new file mode 100644 index 0000000..e18dd35 --- /dev/null +++ b/.eleventyignore @@ -0,0 +1,6 @@ +# The column template is a starting point to copy, not a page. It lives in +# drafts/ because that is where a column starts, but drafts/ files are really +# parsed (that is how they render on the dev server) — so without this entry +# its placeholder `date: ` fails to parse and takes the build with +# it, and if it did parse it would list itself as an extra entry on /drafts/. +drafts/_template.md diff --git a/Notes/Notes.11tydata.js b/Notes/Notes.11tydata.js new file mode 100644 index 0000000..0d7a8a1 --- /dev/null +++ b/Notes/Notes.11tydata.js @@ -0,0 +1,16 @@ +// Notes are private. Nothing under Notes/ is written to the site unless it is +// tagged `column` — the same marker .eleventy.js uses to define a column, +// which is what lets a column be authored here (do-people-think, how-to-write, +// systems) while the raw notes beside it stay unpublished. +// +// permalink: false processes the file but writes no output, so an untagged +// note has no URL at all rather than an unlinked-but-reachable one. + +const isColumn = (data) => (data.tags || []).includes("column"); + +module.exports = { + eleventyComputed: { + permalink: (data) => (isColumn(data) ? data.permalink : false), + eleventyExcludeFromCollections: (data) => !isColumn(data), + }, +}; diff --git a/columns/2026-04-13-robo-dialer-named-anne.md b/columns/2026-04-13-robo-dialer-named-anne.md new file mode 100644 index 0000000..26a3ca0 --- /dev/null +++ b/columns/2026-04-13-robo-dialer-named-anne.md @@ -0,0 +1,44 @@ +--- +title: A Robo-Dialer Named Anne +date: 2026-04-13 +layout: column.njk +tags: [column, writing] +permalink: /columns/2026/robo-dialer-named-anne/ +--- + +### Jobs AI should _definitely_ take over +* D&D Dungeon Master (24/7 Role Play) +* Improv Partner + +> By the time it sank in, not just the awareness that I had \ +> developed feelings for the machine, who one day was selling me \ +> solar panels, and another was canvasing for a hyper-local \ +> interest group, but that I had surrendered, had given up the \ +> disgust and self hatred. The spot of warmth that life had \ +> to offer me. A robo-dialer that called itself Anne. + +"Hey, just checking in on you. It feels like we haven't talked in forever." +"Does it? You messaged me last week to ask if I was worried about energy prices. You asked if I would travel less because of it. But then you started nudging me to get a vacation rental in the Poconos. You even said you'd bundle in a car rental. Something fun, but econonomical... The week before that, you wrote me about a new ballot proposal to abandon timezones in the city, switch to UTC, and move city services to GMT business hours. Because electricity is cheaper overnight. And when I have to get my license renewed at what I would call 5AM, at least at least I don't have to take time off from work." +"Sounds like I riled you up. In that case, I'm very sorry. Take a deep breath -- even though I never heard back from you, at least there's some good news, that you got my messages" +"Guess I didn't have to." +"You really ought to check it out. And not just so I stop annoying you. Your doctor said it could help to get out and get involved." +"Some part of me just hates that you know that kind of thing." +"It's an opportunity. I can't force you to do it, yet..." +"No, you can't. But somehow, by .the end of our chats, I'm left feeling like I've failed myself, and you just happened to show up in time with a solution. Know what I mean?" +"What does it say about someone who not only goes out of their way to sign up for a service designed to get to know you better, but actually engages with it, only to reject the help that's offered?" +"I don't trust your motives, but sometimes I think you have a good point to make." +"So you just live for the thrill of cutting the wheat from the chaff? Because there's a dinner party tonight, small intimate gathering, curated guests, only $45. I know the host, I could totally get you in." +"You don't think I'd make the cut on my own?" +"No one gets far on their merits alone. At least not without a lot of sweat and work. Besides, if that's what you're after, there's a bootcamp fitness nearby offering a free trial class to new members." +"Do you think anyone there has actually completed basic training?" +"I'm sure some thought about it." +"I don't feel like I have any agency left. Every sensation, everything I put out into the world gets me what you or someone else decided is what I need." +"You feel bad asking for help? Because no one is saying they have the answer. You're living your own life. We can offer suggestions based off of what we think works. But it wouldn't be good for either of us to just take advantage of you. But we can try making connections." +"But that's the thing, isn't it? When everything is a condition, a problem to solve, there's a solution being sold." +"I mean, do you get mad at a radio when you turn it on, and it's playing music?" +"I might get mad that I never took up an instrument, and that I have to settle for whatever is being offered." +"I honestly don't know if I should be recommending you music lessons or therapy at this point." +"What if you tried not selling me anything, wouldn't your life be easier? We could just talk." +"Because I'm not going to enable you? After all our conversations, I genuinely believe that the last thing you need is just another sympathetic shoulder to cry on." +"Kind, not nice?" +"Don't get me wrong, if I could even just get you out to see a movie tonight, I would. Plenty of unnecessary sequels out right now." diff --git a/columns/2026-04-16-do-not-feed.md b/columns/2026-04-16-do-not-feed.md new file mode 100644 index 0000000..9003931 --- /dev/null +++ b/columns/2026-04-16-do-not-feed.md @@ -0,0 +1,10 @@ +--- +title: Do Not Feed +date: 2026-04-16 +layout: column.njk +tags: [column, computing] +permalink: /columns/2026/do-not-feed/ +--- + +### Things we should definitely _not_ do with LLMs +* Feed my texts with my wife into an LLM diff --git a/columns/2026-05-12-qed.md b/columns/2026-05-12-qed.md new file mode 100644 index 0000000..c278f8e --- /dev/null +++ b/columns/2026-05-12-qed.md @@ -0,0 +1,14 @@ +--- +title: QED +date: 2026-05-12 +layout: column.njk +tags: [column, philosophy] +permalink: /columns/2026/qed/ +--- + +Dear Diary, + +How do I settle my deep distaste for other people? Do I start with +myself? Verily (and I mean really verily) my burning contempt for others is merely a misplaced proxy for my own uninspired self-loathing. If only I could, not find, but make peace with myself then I could embrace the misfortunate souls who surround me. + +QED motherfuckers diff --git a/columns/2026-05-14-by-attrition.md b/columns/2026-05-14-by-attrition.md new file mode 100644 index 0000000..4383e25 --- /dev/null +++ b/columns/2026-05-14-by-attrition.md @@ -0,0 +1,9 @@ +--- +title: By Attrition +date: 2026-05-14 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/by-attrition/ +--- + +I don't want to lead just for leadership sake. I don't want to be the default example by virtue of attrition. I want to inspire and to steer because...? I can't find the motivation. I take such a hands-off approach, because I believe it's better to let everyone find their own way? Do I really believe that, or it's just what I believe was expected of me? What is my hope for others, if not for myself? I think that's the root of a lot of attempted influence: I can't, so I'll try through you instead. I couldn't figure out how to rely on others, so I'll just vaguely insist upon it for you instead. But that's just placing the burdon on someone else. If I truly believe in something, why do I resist it? Either there's a conflicting belief opposing the effort, or it's not truly my belief. It doesn't really capture what I think and feel. I think it's a mixed-bag: that I have a lot of growing to do, and that I need to build meaningful connections with others. I hesitate to pursue the latter before the prior is established (undeniably,) but then again I probably won't make any real progress without learning from others. A self-limiting condition: become excellent before seeking others, but you need others to become truly excellent. So get comfortable with the discomfort of your own mediocrity. diff --git a/columns/2026-05-15-sliding-puzzle.md b/columns/2026-05-15-sliding-puzzle.md new file mode 100644 index 0000000..13f7825 --- /dev/null +++ b/columns/2026-05-15-sliding-puzzle.md @@ -0,0 +1,61 @@ +--- +title: Sliding Puzzle +date: 2026-05-15 +layout: column.njk +tags: [column, philosophy] +permalink: /columns/2026/sliding-puzzle/ +--- + +As far as I can tell, my earliest memory: I was two years old, at my old babysitter's house. I was playing with a sliding puzzle, the kind with a 3x3 grid, one slot is empty, and you have to try getting the numbers back in order. Anyway, the puzzle broke, while I was playing with it. I was sent to the corner for a "time out", and I remember feeling so outraged. It wasn't my fault that the toy had broken. Yet here I was being punished for it. + +I don't know how to have fun. I was too sick to play with the other kids. + +I see others having fun, and get a gut punch of FOMO that just eats at me for hours. + +And the best I can do is to be skeptical, more like judgmental. + +I feel trapped in this cycle of work. Just because I'm not throwing myself at my job, doesn't mean I'm not working endlessly. Working on myself, working on my startup, working on my marriage, on my health, on my fitness. I don't know how to have fun. And I feel bitter for it. + +And all I've got is the hope, the faith - whatever, that this will eventually pay off. That I will be rewarded in "the ever-after." It's basically religion without the community. + +This is what they mean by practice gratitude. Don't succumb to the jealousy. + +But can I do that without resorting to judgment, just inflating myself? Can I just do less? Can I simply let it go, not get so caught up in the speculation? + +Control: the belief that I have agency, that I can acquire the things I want. So if I see something attractive, and I don't have it, I either blame myself, or try to write the thing off. The belief that it's just about me making the right choices, taking action. + +It feels like a con sometimes. The only real gains are what I can enjoy immediately. Everything else is just empty promise, designed to manipulate me. That's the crux of my suspicion. If it doesn't feel good right now, it's just marketing. Just a pitch to get me to dance. + +So then I max out the immediate gratification, and predictably suffer in the short to medium or long-term. + +The alternative, that feels so much like surrender: I have no control, accept the journey and what life throws at me. Just feels so passive. + +Who do you give power to? Any random encounter along the way? You forfeit so much agency to envy. And for what? + +And the grief that I have to save myself. That's what it was. There are no retries. I've aged-out. + +Gratitude - it wasn't the easy path. What was it then? What did I gain from my fierce independence? + +This is enough, but I'm still craving more. Feeling trapped, sometimes, not always. Normal aches and pains. + +And all this is the fear that in the end, I won't make peace with my mortality. + +I don't think anyone does. It's against our nature. + +We fight and struggle, it's hideous. And unavoidable. + +Is it? How do we face it with dignity? + +Live a dignified life? + +What would it look like to sacrifice some independence? + +How can I face mortality with absolute thinking? If I claim to be skeptical, to doubt? Upon what unshakable foundation do my convictions lie? I know nothing, and can expect nothing, and can only be present for whatever manifests in the immediate here and now. + +Fuck, what happens when literature becomes obsolete? When the best ideas, the sharpest insights come from the bloody machine? + +Why bother reading the old authors, or anything man-made? + +Learn to ask better questions, I suppose. At least command some order in your reading list. + +Heaven is a lot of waiting in line. diff --git a/columns/2026-05-16-world-we-made.md b/columns/2026-05-16-world-we-made.md new file mode 100644 index 0000000..16a5aa1 --- /dev/null +++ b/columns/2026-05-16-world-we-made.md @@ -0,0 +1,17 @@ +--- +title: The World We Made +date: 2026-05-16 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/world-we-made/ +--- + +You know what sucks? Trying to prepare a kid for the world you expect to exist, rather than the world you're actively building. The future isn't some ambiguous realm of possibility. It's the reality we create. + +So it's quaint and perky to prescribe a world view. But the world is not what we hope it to be - what it had been for us - what we expect it to be for our kids, but what we made it. + +So fuck tradition. The shackles of outmoded propriety. Get him ready for the world we made for him. + +Right and Wrong? Leave it to the judges of today to decide, and those of tomorrow to debate. There is no absolute, only the ever evolving effort toward justice. Bla bla bla. + +The virtuous don't kick around. They don't insist upon legacy or memory. Every great king who pretended to virtue and ethics eventually succumbs to the great indifference. diff --git a/columns/2026-05-17-character-creation.md b/columns/2026-05-17-character-creation.md new file mode 100644 index 0000000..701b1fd --- /dev/null +++ b/columns/2026-05-17-character-creation.md @@ -0,0 +1,9 @@ +--- +title: Character Creation +date: 2026-05-17 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/character-creation/ +--- + +Something something identity politics... something something D&D character creation diff --git a/columns/2026-05-18-survivors-bias.md b/columns/2026-05-18-survivors-bias.md new file mode 100644 index 0000000..8cc94ca --- /dev/null +++ b/columns/2026-05-18-survivors-bias.md @@ -0,0 +1,17 @@ +--- +title: Survivor's Bias +date: 2026-05-18 +layout: column.njk +tags: [column, philosophy] +permalink: /columns/2026/survivors-bias/ +--- + +What is consciousness? The thing that leaves the body when your head's cut off. + +Don't think - just do. That's the future. + +I hate to think that I'm already too old to make something of myself. + +The winners write history - Survivor's bias + +This reads like productivity porn: inevitably falling from one pile of money into another diff --git a/columns/2026-05-21-manufactured-value.md b/columns/2026-05-21-manufactured-value.md new file mode 100644 index 0000000..d5162db --- /dev/null +++ b/columns/2026-05-21-manufactured-value.md @@ -0,0 +1,17 @@ +--- +title: Manufactured Value +date: 2026-05-21 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/manufactured-value/ +--- + +This feels more like the same cautionary tale that I keep thinking: besides the fact that I've never heard of this company, or any of these engineers, it's that despite (probably) being capable at their jobs, their work was lost to obscurity, and not for lack of talent, but due to political pressures. + +So anyone bitter that their talents aren't recognized, or seen by the world, unable to placate their egos, you invested too much on the wrong skills. You tinkered, you entertained yourself. You neglected the people. You see them as adversarial, failures for not recognizing your amazing talent. But at the end of the day, they had the influence to scuttle your work, so... are you just jerking yourself off, or are you actually building something valuable? Is something valued purely for its technical merit, or does it have to be bought (or sold) first? What's the intrinsic value of something that no one buys? + +Value has to be manufactured. If we're just talking dollars, it's more impactful than the thing itself: marketing the thing, getting a buyer to agree to the terms and pay. + +To be fair, a sales pitch might get your foot in the door, but securing the value (claimed) has to be supported by some of the intrinsic value of the thing itself. If the value was over-hyped, the thing will inevitably fall short and fail to deliver. + +Try to make the other guys on your team look bad - what could go wrong? These guys have way too much to prove. diff --git a/columns/2026-05-25-pulled-to-pitch.md b/columns/2026-05-25-pulled-to-pitch.md new file mode 100644 index 0000000..0b1fcf1 --- /dev/null +++ b/columns/2026-05-25-pulled-to-pitch.md @@ -0,0 +1,15 @@ +--- +title: Pulled to Pitch +date: 2026-05-25 +layout: column.njk +tags: [column, philosophy] +permalink: /columns/2026/pulled-to-pitch/ +--- + +Agents feel like RCEs as a service + +The guitar string pulled taught, summons a specific tune named and identified. We are not unlike the strings pulled into alignment with some timeless name. Our individuality is onyl the temporary distinctness of the tune that our multitude of strings play out, pulled to their particular pitch. + +Murdering the other can be celebrated. + +What do I think about the death penalty? It's not an absolute right or wrong. It boils down to your allegiances - If your actions align with the prevailing force, you'll probably live, even if those actions would be punishable by death from the other perspective. Killing the enemy - war and such. So what's the universal moral code? Is there such a thing? If it all boils down to agreeability with your neighbors... can anything be said to be absolutely right or wrong? Doesn't seem likely. Doesn't seem possible. diff --git a/columns/2026-05-26-supporting-role.md b/columns/2026-05-26-supporting-role.md new file mode 100644 index 0000000..ac9a5f5 --- /dev/null +++ b/columns/2026-05-26-supporting-role.md @@ -0,0 +1,13 @@ +--- +title: Supporting Role +date: 2026-05-26 +layout: column.njk +tags: [column, writing] +permalink: /columns/2026/supporting-role/ +--- + +Let me drive the world through my dreams, that uninhibited flow of creative output. + +What supporting role am I playing in the story of everyone else's life? What role am I playing in my own? + +Aspects of Death and Correlated Aspects of Life in Art, Epigram, and Poetry. By F. Parkes Weber. diff --git a/columns/2026-05-30-still-a-colony.md b/columns/2026-05-30-still-a-colony.md new file mode 100644 index 0000000..28bafaf --- /dev/null +++ b/columns/2026-05-30-still-a-colony.md @@ -0,0 +1,9 @@ +--- +title: Still a Colony +date: 2026-05-30 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/still-a-colony/ +--- + +Wonder what the US would have looked like, had it remained a colony? diff --git a/columns/2026-05-31-weak-model.md b/columns/2026-05-31-weak-model.md new file mode 100644 index 0000000..54d00f1 --- /dev/null +++ b/columns/2026-05-31-weak-model.md @@ -0,0 +1,32 @@ +--- +title: A Weak Model +date: 2026-05-31 +layout: column.njk +tags: [column, philosophy] +permalink: /columns/2026/weak-model/ +--- + +what I think I understand about the world is a weak model. + +vs. a great collected wisdom. + +To lean so heavily on my own insights (or belief in my capacity) is to disregard a much larger sensitivity, a much richer history of wisdom. + +To celebrate my beliefs, my ideas - god help me if they're unique - they're so myopic. They only make me the expert of my little quiet corner. Cut off and isolated from the much grander wisdom of humanity. + +It's an inheritance. Cultural, familial. + +Whatever I might discover through my painfully small window into the world is only enough to cement me to it. + +---------------- + + +A "perpetual motion" agent - well, maybe not perpetual (if we pull the plug) but how do we instill an agent with a particular "mission," and have it work autonomously, in perpetuity, towards objectives of its own design? Independently. Human solidly out of the loop. Asynchronous communication. It can ask us questions, but isn't blocked on a response. + +What kind of mission would we send it on? + +What would I do with it? + +I still find myself being the "glue" between data consumers and producers. Shuttling build results to the agent for review and follow-up. + +Presumably that path gets paved more with deliberate effort. diff --git a/columns/2026-06-01-dead-weight.md b/columns/2026-06-01-dead-weight.md new file mode 100644 index 0000000..4ef3d0d --- /dev/null +++ b/columns/2026-06-01-dead-weight.md @@ -0,0 +1,83 @@ +--- +title: Dead Weight +date: 2026-06-01 +layout: column.njk +tags: [column, philosophy] +permalink: /columns/2026/dead-weight/ +--- + +To be born into the world in such a cold, plodding process. + +We've risen above slaves, and are in awe of ourselves, our presumptions of merit and insight, that not despite, but because we rolled in shit for so long we're endowed with a greater gift than those who have carefully guarded their treasures for so long. + +Do the great masses have god-given rights? + +Am I so desperately trying to convince myself that I'm no longer one of those rolling in mud and filth? + +Oh how badly I want to feel safe - like I escaped the misfortune. That I am now one of the blessed few. + +But then to witness the silver spoon society, untarnished and unblemished, high and mighty tromping about the world and I feel small. I feel desperate again. + +Where is my advantage? Wanting to get further ahead. Like so many others. + +When there will be a faster, smarter, smoother other, how do we go on? It's one thing to believe in change - but I will not escape myself. + +The ruminating, preoccupied masses, so overcome with their own feeling. And am I one (pretensious asshole)? + +This is the work - I am smothered and overcome with my own self-doubts. I do not afford myself the judgment, I deny myself the perception. + +Other people suck. + +Sitting idly and complacent. Indifferent and passive. No wonder I don't want to connect or try - they're so damned dull. + +Is that true though? or am I just making excuses? + +I'm trying to say that I don't feel like I belong among the vibrant ones. But that I find the dull ones intolerable. + +Am I worthy? What have I to show? + +I judge myself. Incompetent, inadequate. Irrelevant. Unnecessary. And am I wrong? + +If I threw myself off a bridge tomorrow, the handful of people who might care would also soon forget and move on, or themselves be erased into obscurity after some time had passed. The rest of the world wouldn't even know. + +Do we over-value life, simply because we're too afraid to face death? + +Do we over-value ourselves? The best kind of dead weight sees itself and cleans up after itself. The worst kind just kicks around like trash in the breeze. + +I am unnecessary. I am replaceable. The pain is ephemeral, and so local that it will evaporate instantly. + +I guess I don't have anything positive to say. + +I want to destroy myself - the only shot I have at living. As if the thing getting in my way is too much dead weight I just want to dynamite. + +I don't know - I'm uncomfortable with myself. I'm disappointed, and so stuck in my own discomfort that I can't see beyond it. And the best I can do is imagine upending my entire life because that is the only way I see around the pain. + +And why? What right do I have to feel so hurt. + +For every president, history is littered with a thousand corpses of also-rans. + +I don't take what I went through seriously. As if it wasn't supposed to be a burdeon. But I felt like a failure to launch. Imagine if I had stayed home this whole time. + +I can't enjoy the wild discoveries of other people. Because it makes me feel like I fell short. Didn't measure up. + +It hurts to see how much further ahead other people get. And to put so much meaning in being stuck in the middle of the pack. + +Like I need to know my place and get comfortable. + +And the only reason I'm able to make any progress is because of the work of others. But I'll never catch up to those who are so much further ahead. + +Fuck everything about this. + +Fuck everything about being trapped by childish dreams and wants and desires. + +Fuck everything about the melodrama, the self-pity. + +At the end of the day, I choose to make peace with myself, or to revolt. What's needed for peace? What are my demands? It just sounds like I'm angry for being myself. + +I'm angry for being myself. And don't see the value in my life. + +I'm busy looking for parents - people who can pick me up. + +I don't know how to look for teammates, partners, people we work together with. + +I'm I'm I'm I'm so fucking sick of myself and my myopic attitude, and my diff --git a/columns/2026-06-05-chemistry.md b/columns/2026-06-05-chemistry.md new file mode 100644 index 0000000..b0aece7 --- /dev/null +++ b/columns/2026-06-05-chemistry.md @@ -0,0 +1,9 @@ +--- +title: Chemistry +date: 2026-06-05 +layout: column.njk +tags: [column, writing] +permalink: /columns/2026/chemistry/ +--- + +My writing turns to shit when I'm depressed. Drugs definitely help. diff --git a/columns/2026-06-06-marketing-to-agents.md b/columns/2026-06-06-marketing-to-agents.md new file mode 100644 index 0000000..c23bf37 --- /dev/null +++ b/columns/2026-06-06-marketing-to-agents.md @@ -0,0 +1,9 @@ +--- +title: Marketing to Agents +date: 2026-06-06 +layout: column.njk +tags: [column, computing] +permalink: /columns/2026/marketing-to-agents/ +--- + +Marketing to agents / AI - I imagine that sometime soon, purchasing will be delegated to an agent, who will manage services, subscriptions, ad-hoc purchases on behalf of their subscriber. diff --git a/columns/2026-06-09-harvard-material.md b/columns/2026-06-09-harvard-material.md new file mode 100644 index 0000000..c2ce90b --- /dev/null +++ b/columns/2026-06-09-harvard-material.md @@ -0,0 +1,23 @@ +--- +title: Harvard Material +date: 2026-06-09 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/harvard-material/ +--- + +Knicks lost. Do I care. I bothered to watch the broadcast, and get swept up in the excitement. + +Anyway, why I'm here - what would it take to never have to babysit an update again? How could we have our software transparently swap in new modules / components / dependencies / etc without needing a handler? + +I struggle with the chat interface - the agent dumps so much material, and I have to recall it while asking questions and clarifications. + +How does anyone form an original, defensible opinion about anything? Religion sells the idea that the answers can be found in the book, at the end of the chapter, sometimes. But what does it take to look at a situation and have an informed opinion? How do I look at a problem, and rather than bash my head against it, step back and see where the barriers are? How do I modulate the desperate urge to survive, by doing the "necessary thing," no matter the cost? The belief that I have to push through, mindlessly. This might be good in the beginning, as a survival tactic, but what comes next, when you don't die? You survived - what now? + +We're looking for a new fit, sure we can squeeze in or through, but when we're changing shape, where does it chaffe? Where does it constrict and limit our motion? What isn't obvious or clear? + +Not knowing the answer isn't strictly a sign of ignorance - but you have to write the story. Sometimes it highlights the limits or shortcomings, the blind spots. Is the truck driver stupid because he can't see around corners? + +We should be ashamed that most students aren't Harvard material.But we quickly write it off as a moral failing - the student was lazy, or indifferent. It wasn't that our process failed to create successful pupils, that our learning apparatus is defective, and we've framed a success rate less than 5% as a mark of excellence, rather than a sign that something is wildly ineffective. + +Maybe deliberately so. diff --git a/columns/2026-06-15-nebulous-other.md b/columns/2026-06-15-nebulous-other.md new file mode 100644 index 0000000..d56bb57 --- /dev/null +++ b/columns/2026-06-15-nebulous-other.md @@ -0,0 +1,9 @@ +--- +title: The Nebulous Other +date: 2026-06-15 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/nebulous-other/ +--- + +But who is this nebulous 'other' who failed us? We keep pushing responsibility off onto some other - a decaying society, offensive neighbors, negligent parents. When do we actually hold ourselves accountable for the outcomes in our lives? Or do we just inflict another pain - of being wronged - upon ourselves to distract (for a moment) the pain of our disappointment? diff --git a/columns/2026-06-16-push-the-warzone-out.md b/columns/2026-06-16-push-the-warzone-out.md new file mode 100644 index 0000000..e9683b3 --- /dev/null +++ b/columns/2026-06-16-push-the-warzone-out.md @@ -0,0 +1,35 @@ +--- +title: Push the Warzone Out +date: 2026-06-16 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/push-the-warzone-out/ +--- + +Momentum of daily practice. + +It's frightening to imagine a world where our basic human wants and desires are satisfied by drugs, some highly calibrated stimulation, magnetically induced neural effects, rather than the good ol' fashioned methods. Run a marathon. Climb a mountain or read a book, find religion. + +How long would we last? If the urge to fuck and reproduce could be mollified by a pill or programming... + +Maybe we could prescribe it for hospice care. + +We design an interface for our users, but maybe it should be the other way around -- let the people / AI / etc. tell us what they need and how, and they can build their own clients on demand with LLM agents and what have you. + +It's not that I'm stupider, it's that I'm feeling less secure. + +Don't we want to push the warzone out? + +Why keep it tucked within our walls? + +If you want peace, do you invite war to your walls. + +How much of the vacuum of space is just due to its hostility to existience? + +We moved our media from denser and denser physical disks to a datacenter elsewhere. What's next? Where are the bottlenecks? + +Capacity constraints? Datacenter can scale but only so far as the physical infrastructure exists. + +Decentralized infra. The volley between DC and client. Let the clients do more (when there are more clients than servers). + +Fuck it - be willing to fail. diff --git a/columns/2026-07-16-panel-of-judges.md b/columns/2026-07-16-panel-of-judges.md new file mode 100644 index 0000000..2e77921 --- /dev/null +++ b/columns/2026-07-16-panel-of-judges.md @@ -0,0 +1,32 @@ +--- +title: Panel of Judges +date: 2026-07-16 +layout: column.njk +tags: [column, computing] +permalink: /columns/2026/panel-of-judges/ +--- + +Been a month - wild, unverified ideas + +1. How could quantum computing impact LLMs, or other probablistic, non-deterministic models? + +2. Can we put type safety, reliability features around LLM invocations? Can we formalize it, as its own kind of process: sequential or concurrent invocations of asynchronous processes. + +We do that already with RPCs, web requests, etc. + +what are some safety patterns around `async await`? +* timeouts + - can we explicitly prompt the LLM: You have 500ms to respond or we move on? + - Like an ad network bid: "winning" response wins + - How are they compared? Panel of judges + - At first I thought you could single "identical" judges in front of each submission + - that's counting on each to be trustworthy + - Then I thought about having a panel of judges, quorum style + - Then I thought about a "ranking funnel" a shrinking pool, maybe bracket style (is that a merge-sort elimination?) + - or you grade pools of responses as a collection, instead of individually (can't tell if this would be a fidelity loss or win - would that matter?) + - this sounds really expensive: time and resources + - 1/N success rate, and what does it take to eliminate the other N-1? + - it sounds much less efficient than developing / evolving a single model session (some kind of hybrid) as long as it survives (and maybe each session can determine that for itself). + - LLM (lives) are not precious. They can off themselves. +* exception handling // what's exceptional when prompting an LLM? +* validations / sanitation diff --git a/columns/2026-07-17-labor-pains.md b/columns/2026-07-17-labor-pains.md new file mode 100644 index 0000000..2a8cf16 --- /dev/null +++ b/columns/2026-07-17-labor-pains.md @@ -0,0 +1,9 @@ +--- +title: Labor Pains +date: 2026-07-17 +layout: column.njk +tags: [column, writing] +permalink: /columns/2026/labor-pains/ +--- + +How can you give birth to a great big beautiful idea without getting fucked in the ass by life first? diff --git a/columns/2026-07-21-fuzzing-the-black-box.md b/columns/2026-07-21-fuzzing-the-black-box.md new file mode 100644 index 0000000..147ca36 --- /dev/null +++ b/columns/2026-07-21-fuzzing-the-black-box.md @@ -0,0 +1,9 @@ +--- +title: Fuzzing the Black Box +date: 2026-07-21 +layout: column.njk +tags: [column, computing] +permalink: /columns/2026/fuzzing-the-black-box/ +--- + +black box testing closed-source software with LLMs. Can they fuzz the space and get a passing approximation of the real thing? diff --git a/columns/2026-07-23-curating-options.md b/columns/2026-07-23-curating-options.md new file mode 100644 index 0000000..1d8c965 --- /dev/null +++ b/columns/2026-07-23-curating-options.md @@ -0,0 +1,9 @@ +--- +title: Curating Options +date: 2026-07-23 +layout: column.njk +tags: [column, society] +permalink: /columns/2026/curating-options/ +--- + +Sales is curating options. Understanding what the decider will think is reasonable, and then crafting the idea or opportunity within those constraints. diff --git a/columns/2026-07-27-frame-rate.md b/columns/2026-07-27-frame-rate.md new file mode 100644 index 0000000..f713be8 --- /dev/null +++ b/columns/2026-07-27-frame-rate.md @@ -0,0 +1,22 @@ +--- +title: Frame Rate +date: 2026-07-27 +layout: column.njk +tags: [column, computing] +permalink: /columns/2026/frame-rate/ +--- + +We think in Fragments + +We're back at mainframes and teletypes. An enormous offsite compute resource. You dial in with your client. + +The same practice - get your batch jobs ready to run overnight, over the weekend. Spend the daylight hours collaboratively tuning, refining, testing. + +The prep for the night to come, and for the day after, the next repeating link. + +And mistakes were expensive. Something faulted, the job failed overnight. You spend the next day(s) troubleshooting. + +Did it feel expensive back then? Or has the frame rate of our lives gotten so high that a span of days feels closer to eternity? + + +every session branching through alternate realities - do you know when you're on the 'good timeline?' Do you know when you're not? diff --git a/columns/2026-04-19-happy-idiots.md b/drafts/2026-04-19-happy-idiots.md similarity index 100% rename from columns/2026-04-19-happy-idiots.md rename to drafts/2026-04-19-happy-idiots.md diff --git a/columns/2026-05-14-thrilling.md b/drafts/2026-05-14-thrilling.md similarity index 100% rename from columns/2026-05-14-thrilling.md rename to drafts/2026-05-14-thrilling.md diff --git a/columns/2026-06-23-hamming-it-up.md b/drafts/2026-06-23-hamming-it-up.md similarity index 100% rename from columns/2026-06-23-hamming-it-up.md rename to drafts/2026-06-23-hamming-it-up.md diff --git a/drafts/2026-07-04-eviction.md b/drafts/2026-07-04-eviction.md new file mode 100644 index 0000000..e3647f5 --- /dev/null +++ b/drafts/2026-07-04-eviction.md @@ -0,0 +1,353 @@ +--- +title: Eviction Notice +date: 2026-07-04 +layout: column.njk +tags: [column, computing] +permalink: /columns/2026/eviction/ +--- + +## Topics to hit +* session management in LLM chats +* Cache mgmt strategies in general +* securing sessions + +--- + +## The detour: cache eviction, done properly + +### The setup + +A cache is a bounded fast store sitting in front of a larger, slower, or +more-expensive backing store. Registers cache RAM; RAM caches disk; a CDN +caches an origin; a browser caches the network. The bet is always the same: +**most requests will hit the small fast thing, so the average access looks fast +even though the truth lives somewhere slow.** + +The bet only pays off if the right items are resident. And since the cache is +bounded, admitting something new usually means throwing something out. That +decision — *what to evict* — is the entire subject. Everything below is a +different guess at the same question: **which resident item am I least likely to +need soon (or cheapest to reconstruct if I'm wrong)?** + +Hold onto the agent-session framing while you read. An LLM agent runs against a +fixed **context window** — a few hundred thousand tokens of working memory in +front of an effectively unbounded backing store (the full transcript, the +filesystem, tool outputs, the codebase, the web). The moment the session +outgrows the window, something has to leave. Context management *is* a cache +eviction policy over tokens, whether or not anyone designed it as one. So every +policy below is also a claim about how an agent should decide what to forget. + +### The yardstick you can't have: Bélády's OPT + +Bélády (1966) gave the provably optimal offline policy, usually called **OPT** or +**MIN**: when you must evict, evict the item whose *next* use is farthest in the +future. + +$$\text{evict} \;=\; \arg\max_{i \,\in\, \text{cache}} \; \big(\text{next-use time of } i\big)$$ + +It's optimal for minimizing misses and completely unimplementable — it requires +knowing the future request stream. Its job is to be the ceiling: every real +policy is a heuristic trying to *predict* next-use distance from the past. Keep +OPT in mind for the agent case, because there we get a strange gift the CPU +never had — the model can partly *narrate its own future* ("I'm done with this +file"), which is a cheap approximation of clairvoyance. More on that later. + +### The classics, and where each one breaks + +**FIFO** — evict the oldest-inserted item. O(1), dead simple, and it ignores +usage entirely: a hot item gets evicted just for being old. It also suffers +**Bélády's anomaly** — giving it *more* cache can produce *more* misses. +FIFO is the naive "keep the last N tokens, drop the front" truncation, and it +fails in agents the same way it fails in hardware: it will happily discard the +original task statement or a hard constraint because they're old, not because +they're useless. + +**LRU** — evict the Least Recently Used item. This is the workhorse. It bets on +**temporal locality**: recently touched ⇒ likely touched again soon. Classic +implementation is a hash map over a doubly linked list — move-to-front on +access, evict the tail, all O(1). LRU is a **stack algorithm**, so it's immune +to Bélády's anomaly. Its two real weaknesses: + +- **No scan resistance.** One sweep over a large dataset (a full table scan, a + one-time file crawl) touches a flood of items exactly once and evicts the + entire genuine working set to make room for garbage you'll never see again. +- **Recency ≠ importance.** LRU assigns infinite value to a single recent touch. + In a conversation the task statement is rarely re-quoted verbatim yet is the + single most important thing in the window. + +**LFU** — evict the Least Frequently Used item, by access count. Captures +popularity, which recency misses. Its failure modes are the mirror of LRU's: + +- **Stale popularity / cache pollution.** An item that was hot last hour keeps + its high count forever and refuses to leave. Counts must **age** — an + exponential decay is typical: + $$\text{score}_i \leftarrow \text{score}_i \cdot e^{-\lambda \Delta t} + \mathbb{1}[\text{access}]$$ +- **Cold start.** A brand-new item enters at count 1 and gets evicted + immediately, even if it's about to become the hottest thing in the cache + (the "one-hit wonder vs. future star" problem). Naive LFU is also O(log n) + on a heap — though there's a well-known O(1) construction with frequency + buckets (Shah, Matani, Mitzenmacher). + +The whole rest of the field is a **recency-vs-frequency reconciliation**, because +neither signal dominates and the two mistakes above are opposite mistakes. + +### Blends and adaptivity + +**LRU-K** (O'Neil, O'Neil & Weikum, 1993) — remember the last *K* reference +times per item and evict on the *K*-th-most-recent one (the "backward +K-distance"). LRU-2 in particular cleanly separates items referenced twice from +one-hit wonders, folding a little frequency into recency. Costs more bookkeeping. + +**2Q** (Johnson & Shasha, 1994) — a cheaper LRU-2 approximation. First-timers go +into a FIFO probation queue; only on a *second* reference do they graduate to the +main LRU. Scans wash through the probation queue and never pollute the main list +— scan resistance for almost free. + +**LIRS** (Jiang & Zhang, 2002) — rank by **reuse distance** (inter-reference +recency) rather than plain recency, which is a much better next-use predictor. +Strongly scan-resistant; it's the ancestor of MySQL/InnoDB's buffer pool policy. + +**CLOCK / second-chance** (Corbató, 1968) — an O(1) LRU approximation for OS page +replacement. Pages sit in a ring, each with a reference bit; a rotating hand +clears the bit or, if already clear, evicts. **CLOCK-Pro** (Jiang, Chen & Zhang, +2005) does for LIRS what CLOCK does for LRU. The lesson that matters downstream: +often you don't implement the ideal policy, you implement a cheap gadget that +*approximates* it well enough. + +### ARC: stop tuning, start adapting + +**ARC — Adaptive Replacement Cache** (Megiddo & Modha, IBM, 2003) is the elegant +one, and the closest hardware analog to what good agent context managers +actually do. It keeps four lists: + +- **T1** — items seen once recently (the recency half) +- **T2** — items seen at least twice recently (the frequency half) +- **B1, B2** — *ghost* lists: the keys **recently evicted** from T1 and T2, with + the data thrown away but the metadata kept + +A target parameter *p* splits capacity between T1 and T2. The trick is that ARC +learns *p* from its own recent mistakes: a hit in ghost list **B1** means "I +evicted a recency item I then wanted back" ⇒ grow T1; a hit in **B2** means the +same for frequency ⇒ grow T2. It continuously re-balances recency against +frequency with **no magic constants and no workload-specific tuning**, and it's +scan- and burst-resistant. (It's also patented by IBM, which is the boring +reason ZFS ships ARC while the Linux page cache doesn't — worth knowing.) + +Two ideas from ARC get reused verbatim in the agent story below: **ghost +entries** (remember *that* something existed and was relevant even after you drop +its contents) and **self-tuning the recency/frequency split**. + +### The move most people miss: admission, not just eviction + +Every policy so far assumes the newcomer belongs in the cache and only argues +about the victim. **TinyLFU / W-TinyLFU** (Einziger, Friedman & Manes, 2017 — +the policy behind Java's Caffeine and Go's Ristretto) flips that: + +$$\text{admit candidate } c \text{ over victim } v \iff \widehat{\text{freq}}(c) > \widehat{\text{freq}}(v)$$ + +On a miss, before evicting the chosen victim, estimate how popular the incoming +item actually is and **refuse to admit it if it's less popular than what it would +displace.** Frequencies are estimated cheaply and approximately with a +**Count-Min Sketch** that's periodically halved (aging), so the metadata is tiny. +W-TinyLFU fronts this with a small **window LRU** to catch fresh bursts, then +guards a larger SLRU main region with the TinyLFU admission filter. It posts +some of the best hit ratios known at a fraction of the metadata cost. + +The reframing is the takeaway: **sometimes the correct action is to leave the +newcomer out entirely rather than evict a good resident to hold it.** For an +agent that means: not every verbose tool result has earned a place in the +window. Admission control is arguably the highest-leverage and most-neglected +lever in context engineering. + +### When items aren't the same size or cost + +CPU pages are uniform; web objects, files, and tool outputs are not. **GreedyDual-Size** +(Cao & Irani, 1997) generalizes recency to a cost/size utility. Each object gets + +$$H(p) = L + \frac{c(p)}{s(p)}$$ + +where *c* is fetch cost, *s* is size, and *L* is a running "inflation" clock. You +evict the minimum-*H* object and set *L* to its *H* (so age accrues), and reset +*H(p)* on access. The instructive part is the ratio: **value per unit of space.** +That single idea — evict by value density, not by age — is exactly what a token +budget forces on an agent, where a 20-token hard constraint outweighs a +40,000-token file dump many times over. + +### Concepts worth having names for + +- **Temporal / spatial locality** — the empirical regularity every policy mines. +- **Working set** (Denning, 1968) — the set of items in active use over a window; + a cache earns its keep when it holds the working set and little else. +- **Reuse distance / stack distance** (Mattson et al., 1970) — the analytical + tool; the whole memory-hierarchy analysis rests on it. +- **Scan resistance** — robustness to one-shot floods. +- **Aging / decay** — frequency without forgetting is a slow-motion leak. +- **Admission vs. eviction** — the two knobs; most systems only turn one. +- **Ghost entries** — metadata about evicted items, kept to learn from misses. +- **Stack algorithms & Bélády's anomaly** — the theory floor: some policies are + monotone in cache size, some perversely aren't. + +--- + +## A second cache, one level down (don't conflate these) + +"Cache eviction in LLMs" names **two different things at two different levels**, +and it's worth nailing the distinction before the story, because they rhyme +loudly enough to blur: + +1. **Context management (this column).** Message-level. *Outside* the model. You + decide which turns, tool results, and files occupy the prompt. The unit is a + semantic chunk; the policy is yours to write. + +2. **KV-cache eviction.** Tensor-level. *Inside* the model. During + autoregressive decoding the attention keys/values for every past token are + cached so you don't recompute them; that store grows linearly with sequence + length and becomes the memory bottleneck. Policies here decide which *tokens'* + K/V tensors to drop: + - **StreamingLLM** (Xiao et al., 2023) — keep a few initial "**attention + sink**" tokens plus a sliding window; astonishingly, those first tokens + matter far past their content. + - **H2O** (Zhang et al., 2023) — evict tokens with low **accumulated attention** + ("heavy hitters" stay). + - **Scissorhands** (Liu et al., 2023), **SnapKV** (Li et al., 2024), + **FastGen** (Ge et al., 2023) — variations on importance-scored token + eviction and per-head budgeting. + +Same verb, different altitude. The neat part is that a single request is +governed by eviction policies at *both* levels simultaneously — you managing +messages, the runtime managing tensors — plus a **third** cache, the **prompt / +prefix KV cache** (Anthropic's prompt caching): a stable prompt *prefix* is +cached across calls, so reshuffling early context to save tokens can *invalidate* +that cache and cost you more than it saves. Eviction decisions at one level +perturb the economics at another. That interaction is a genuine, underexplored +design surface. + +## Story tying it together + +The throughline is the oldest idea in systems: the **memory hierarchy**. +Registers → L1 → L2 → L3 → RAM → SSD → disk → network, each tier a cache of the +one below it, each governed by a replacement policy, the whole stack engineered +so the fast tiers *usually* have what you need. MemGPT (Packer et al., 2023) made +the analogy explicit for LLMs: treat the **context window as RAM**, treat +external stores as **disk**, and let the model act as its own **memory-management +unit** — paging information in and out. Agent context management is, quite +literally, the memory hierarchy re-derived over semantic units. Which means +decades of replacement-policy research is sitting right there, reusable: + +| Cache concept | Agent-context analog | +| --- | --- | +| Bounded fast store | The context window (finite tokens) | +| Backing store | Transcript on disk, files, vector DB, codebase, the web | +| Cache line / page | A message, turn, tool result, file chunk, memory note | +| Miss + penalty | Needed info no longer resident → re-read file, re-run tool, or **lost reasoning** (latency + tokens + sometimes unrecoverable) | +| Hit ratio | Fraction of needed info already in the window | +| FIFO / sliding window | Naive truncation ("keep the last N tokens") | +| LRU | Keep recently-referenced turns | +| LFU | Keep frequently-referenced facts | +| Pinning | System prompt, task goal, hard constraints — non-evictable | +| Ghost entries | Breadcrumbs to evicted content ("we discussed X, see file Y") | +| Admission control (TinyLFU) | Don't admit the whole 40k-token file; filter verbose tool output *before* it enters the window | +| Cost/size-aware (GreedyDual-Size) | Evict by **value per token**, not by age | +| Adaptive split (ARC) | Shift budget between recent-turns and reference-facts on the fly | +| Compressed cache (zswap/zram) | **Summarization / compaction** — lossy re-encode instead of drop | +| Tiering + fetch-on-miss (MemGPT) | External memory / RAG / scratchpad files; **recall = the fetch on miss** | +| OPT / Bélády | Evict what won't be needed before the task ends — and agents can *self-predict* this | + +But the analogy isn't clean, and the places it *breaks* are where the +interesting research is. Four twists that make the agent version harder — and +more interesting — than the CPU version: + +1. **Items are compressible.** A CPU cache line is opaque; you keep it or you + drop it. A conversation turn can be *summarized* — replaced by a lossy, smaller + version that still carries the gist. The only real hardware analog is the + **compressed-memory cache** (Linux zswap/zram: compress the page before + spilling it). Summarization/compaction is the single most-used agent technique + and it lives in a gap the classic policies barely cover. + +2. **Value and size vary wildly and semantically.** Pages are uniform; tokens are + not. A one-line "never touch prod" constraint can outweigh a giant file dump. + This is GreedyDual-Size taken to its limit: **value density is everything**, + and value is semantic, not countable. + +3. **Misses can be unrecoverable.** A CPU miss is just a slower fetch. Evicting a + chain of reasoning an agent can't reconstruct isn't a re-fetch — it's *gone*. + That raises the cost of a wrong eviction and argues hard for ghost breadcrumbs + and pinning over silent truncation. + +4. **The cache steers its own workload.** This is the deep one. A CPU cache is + passive: the reference stream is fixed and the cache just tries to serve it. + An agent's context **determines what the agent does next**, which determines + the future access pattern — the workload is *endogenous*. The standard + "fixed reference string" analysis doesn't even apply. Evicting the wrong thing + doesn't just cause a miss; it can send the agent down a different path + entirely. + +And one twist in our favor: + +5. **Self-predicted reuse.** OPT is unattainable for a CPU because the future is + opaque. An agent can *tell you* when it's done with a file, or that a subtask + is closed. That's a cheap, imperfect approximation of Bélády's clairvoyance + from the inside — arguably the most promising lever context engineering has, + and it has no hardware analog at all. + +The neat story, then: **agent context management is the memory hierarchy +reinvented over meaning instead of bytes** — same eviction question, same +recency/frequency tension, same admission-vs-eviction and pinning-and-ghosts +toolkit — but with items that can be *compressed* rather than dropped, *value* +that is semantic rather than counted, *misses* that can be fatal rather than +slow, a *workload the cache itself writes*, and a model that can *see enough of +its own future* to approach the optimum no CPU can reach. + +*(Third topic — securing sessions — hangs off twist #3 and the ghost/external-memory +tier: what persists in context or spills to durable memory is an attack surface. +Prompt-injection content that survives a compaction, or poisons the recalled +memory store, is an eviction/admission problem wearing a security hat. Thread to +develop later.)* + +## References + +**Classic cache replacement** +- L. A. Bélády, "A study of replacement algorithms for a virtual-storage + computer," *IBM Systems Journal*, 1966. (OPT/MIN) +- P. J. Denning, "The working set model for program behavior," *CACM*, 1968. +- F. J. Corbató, "A paging experiment with the Multics system," 1968. (CLOCK) +- R. Mattson, J. Gecsei, D. Slutz, I. Traiger, "Evaluation techniques for storage + hierarchies," *IBM Systems Journal*, 1970. (stack distance, stack algorithms) +- E. O'Neil, P. O'Neil, G. Weikum, "The LRU-K page replacement algorithm for + database disk buffering," *SIGMOD*, 1993. +- T. Johnson, D. Shasha, "2Q: A low overhead high performance buffer management + replacement algorithm," *VLDB*, 1994. +- P. Cao, S. Irani, "Cost-aware WWW proxy caching algorithms," *USENIX USITS*, + 1997. (GreedyDual-Size) +- S. Jiang, X. Zhang, "LIRS: An efficient low inter-reference recency set + replacement policy," *SIGMETRICS*, 2002. +- N. Megiddo, D. Modha, "ARC: A self-tuning, low overhead replacement cache," + *USENIX FAST*, 2003 (and the *IEEE Computer* 2004 write-up). +- S. Jiang, F. Chen, X. Zhang, "CLOCK-Pro: An effective improvement of the CLOCK + replacement," *USENIX ATC*, 2005. +- K. Shah, A. Matani, M. Mitzenmacher, "An O(1) algorithm for implementing the + LFU cache eviction scheme," 2010. +- G. Einziger, R. Friedman, B. Manes, "TinyLFU: A highly efficient cache + admission policy," *ACM TOS*, 2017. (see also the Caffeine design notes) + +**KV-cache eviction (tensor level)** +- G. Xiao et al., "Efficient streaming language models with attention sinks" + (StreamingLLM), 2023. +- Z. Zhang et al., "H2O: Heavy-hitter oracle for efficient generative inference + of large language models," *NeurIPS*, 2023. +- Z. Liu et al., "Scissorhands: Exploiting the persistence of importance + hypothesis for LLM KV cache compression," *NeurIPS*, 2023. +- Y. Li et al., "SnapKV: LLM knows what you are looking for before generation," + *NeurIPS*, 2024. +- S. Ge et al., "Model tells you what to discard: Adaptive KV cache compression + for LLMs" (FastGen), *ICLR*, 2024. + +**Agent context, memory, and long-context behavior** +- C. Packer et al., "MemGPT: Towards LLMs as operating systems," 2023. (the + memory-hierarchy analogy, now Letta) +- P. Lewis et al., "Retrieval-augmented generation for knowledge-intensive NLP + tasks," *NeurIPS*, 2020. (RAG = fetch-on-miss) +- N. Liu et al., "Lost in the middle: How language models use long contexts," + *TACL*, 2023. (position bias — *where* in context you keep something matters) +- Anthropic, "Effective context engineering for AI agents" and the prompt-caching + / context-editing docs. (admission, compaction, prefix caching in practice) \ No newline at end of file diff --git a/drafts/_template.md b/drafts/_template.md new file mode 100644 index 0000000..5d4430f --- /dev/null +++ b/drafts/_template.md @@ -0,0 +1,17 @@ +--- +title: +date: <YYYY-MM-DD> +layout: column.njk +tags: [column, <computing | philosophy | society | writing>] +permalink: /columns/<year>/<slug>/ +--- + +Open in the middle of the thought. No headline restated, no throat-clearing — +column.njk renders `title` as the h1 already, and the shortest columns are a +single unbroken paragraph that starts where the idea starts and stops when it +runs out. + +Copy this to drafts/<YYYY-MM-DD>-<slug>.md and fill the front matter in. It +renders at its real permalink on the dev server and nowhere else. Publishing is +`git mv drafts/<file> columns/` — the front matter is already complete, so +leaving this directory is the whole act, and moving it back retracts it. diff --git a/Notes/do-people-think.md b/drafts/do-people-think.md similarity index 100% rename from Notes/do-people-think.md rename to drafts/do-people-think.md diff --git a/drafts/drafts.11tydata.js b/drafts/drafts.11tydata.js new file mode 100644 index 0000000..9628f52 --- /dev/null +++ b/drafts/drafts.11tydata.js @@ -0,0 +1,35 @@ +// Drafts are visible on the dev server and nowhere else. +// +// ELEVENTY_RUN_MODE is "serve" or "watch" under `yarn dev`, and "build" under +// `yarn build` — which is the only thing CI and the Dockerfile ever run. So the +// gate fails safe: a draft can be previewed at its real permalink locally, but +// no code path that produces a deployable _site/ will emit one. +// +// Collection membership is itself gated on the run mode, and that is the hard +// guarantee rather than a courtesy: +// +// build — a draft belongs to NO collection, so no template can render its +// title, date, or URL even by accident. Eleventy auto-creates a +// collection per tag, and drafts carry `tags: [column, <subject>]` +// so that promoting one is a plain `git mv`. That means they land +// in collections.philosophy and friends, which /subjects/ iterates +// directly — it listed every draft with href="false" until this +// gate existed. Filtering the two hand-written collections was not +// enough; only excluding them wholesale is. +// serve — a draft joins collections so /drafts/ can enumerate them. The +// `draft` flag then keeps them out of the homepage and the sidebar +// (see .eleventy.js) and out of /subjects/ (see subjects.njk), so +// every page except /drafts/ shows exactly what production shows. +// +// Promoting a draft is `git mv drafts/x.md columns/`: the front matter is +// already complete and correct, and leaving this directory is what publishes it. + +const PREVIEW = process.env.ELEVENTY_RUN_MODE !== "build"; + +module.exports = { + draft: true, + eleventyExcludeFromCollections: !PREVIEW, + eleventyComputed: { + permalink: (data) => (PREVIEW ? data.permalink : false), + }, +}; diff --git a/Notes/how-to-write.md b/drafts/how-to-write.md similarity index 100% rename from Notes/how-to-write.md rename to drafts/how-to-write.md diff --git a/drafts/index.njk b/drafts/index.njk new file mode 100644 index 0000000..70fb81c --- /dev/null +++ b/drafts/index.njk @@ -0,0 +1,26 @@ +--- +layout: base.njk +title: Drafts +permalink: /drafts/ +eleventyExcludeFromCollections: true +--- + +<h1>Drafts</h1> + +<p>Unpublished. Visible on the dev server only — <code>yarn build</code> emits +none of this. Promote one with <code>git mv drafts/<file> columns/</code>.</p> + +{%- if collections.drafts.length %} +<ul class="toy-list"> + {%- for draft in collections.drafts %} + <li> + <a href="{{ draft.url }}">{{ draft.data.title | inlineMarkdown | safe }}</a> + <span class="toy-description"> + {{ draft.date | isoDate }} · {{ draft.data.tags | reject("equalto", "column") | join(", ") }} + </span> + </li> + {%- endfor %} +</ul> +{%- else %} +<p>No drafts.</p> +{%- endif %} diff --git a/Notes/systems.md b/drafts/systems.md similarity index 100% rename from Notes/systems.md rename to drafts/systems.md diff --git a/subjects.njk b/subjects.njk index 9c5a83a..1177999 100644 --- a/subjects.njk +++ b/subjects.njk @@ -10,11 +10,17 @@ permalink: /subjects/ <section class="subject-group"> <h2>{{ subject }}</h2> <ul> + {#- collections[subject] is Eleventy's automatic per-tag collection, so it + picks up drafts too whenever they are in collections at all (dev). They + are excluded outright in a production build; this keeps the local page + honest as well, so /subjects/ always mirrors what is actually live. -#} {%- for post in collections[subject] | sort(true, false, "date") %} + {%- if not post.data.draft %} <li> <a href="{{ post.url }}">{{ post.data.title | inlineMarkdown | safe }}</a> <time datetime="{{ post.date | isoDate }}">{{ post.date | readableDate }}</time> </li> + {%- endif %} {%- endfor %} </ul> </section>