An Algorithmic Lucidity

a blog

Tag: akrasia

Binge-Purge

$ history | grep freeciv
  605  freeciv
  606  sudo apt-get install freeciv
  607  sudo apt-get remove freeciv
  652  rm -rf ~/.freeciv/
  706  sudo apt-get install freeciv
  722  sudo apt-get remove freeciv
  735  rm -rf ~/.freeciv/
  752  sudo apt-get install freeciv
  754  sudo apt-get remove freeciv
  768  rm -rf ~/.freeciv/
  785  history | grep freeciv

"Give Anything"

As a freshman on my high school's cross country team, our captain told me that to be a good runner, you needed to love pain.

I objected: a great runner could love to race, I said, and endure the pain only for the sake of competing and winning.

It's only fifteen years later (practically one foot in the grave), that I now see that I was wrong and he was right.

You can run out of habit or you can run because Coach would notice if you skip practice, but you cannot run because of the strictly instrumental effect that not-running would have on your goals. Our minds aren't built that way; what is separable conceptually is not separable architecturally.

Ultimately, to not sacrifice the gift, you have to love pain. You have to love life.

Cranberry Bliss!

(Previously.)

It's the tenth day of the third November of my life (that I am willing to admit to), and I am determined to wring some sort of high-sounding interpretation out of the cool air and damp sidewalks: perhaps a contrast, something about the events that directly prompt fundamental life changes (on the one hand), and the events that indirectly catalyze fundamental life changes by means of enabling the construction of a legible narrative in which the changes can be plausibly attributed to them (on the other).

Today I am constructing a narrative about my life fundamentally changing because the coffee hegemon has started selling those medicinal (right) cranberry/cream-cheese triangles again. Not that hastening my inevitable horrible cardiac death with dessert bars is like a series arc or anything, but it's a thing I learned today that is salient enough to be repurposed as a trigger, a reminder that the autumn–winter windustrial complex is upon us again, that this is supposed to be my favorite time of year, that there simply is no reason I won't attune myself to perceive nature's cyclic harmonies, then perform every San Francisco software engineer's sacred duty and disrupt the living fuck out of them.

Lipschitz

—and the moment or more than a moment when the dam breaks, when the damned break and the void inside their skulls is filled (the atmosphere rushing in quickly, but not so quickly that one couldn't sense its motion) with the terror that is knowledge of the specter of continuity: that there have never been, and can never be, any miracles.

For to be saved is only to be some distance in the initial conditions from being damned, some lesser distance from being half-damned ... some δ-distance from being ε-damned. And the complement of the shadow we cast on the before-time contains its limits.

Some Excuse for a RustConf 2017 Travelogue

(Previously, previously on An Algorithmic Lucidity.)

Wow, has it already been a year since last RustConf?—give or take the exact date of the event sliding a bit between years—and give a month-and-a-half of procrastination before being truly struck by the mounting realization that my opportunity to blog something about it before the opportunity expires has almost—but crucially, not quite—faded into oblivion. And a year-and-a-quarter since my first contribution to the compiler? I've recently moved into the top hundred contributors by commit count, because GitHub's contributors graph page only goes down to a hundred and my life is controlled by what things GitHub happens to provide graphs for.

RustConf 2017 swag laid out on a t-shirt: two lanyards with name badges, a mug and tote bag with the Rust logo

So in the evening of Wednesday 15 August, I boarded the Amtrak Coast Starlight at Jack London Square station in Oakland for the long pilgrimage north to Portland to visit friend of the blog Sophia and attend this year's RustConf.

The train was nearly three hours late. (More like Slowest Starlight, am I right?)

On Thursday, I convened a Berkeley Slate Star Codex meetup in exile with Sophia and another local.

I don't think I was very well-prepared to take advantage of the conference itself this time around. I attended the Friday "advanced" training session, but the content was mostly the same as last year (I probably should have chosen the Tock session instead), and I don't actually own a laptop (I used "my" employer-owned laptop last year), and trying to make do with my accessorized phone and the playground was not an optimized experience.

Then the day of the conference itself, I overslept (and left my badge at Sophia's house), and had a high-neuroticism day induced by social-media drama that I had inflicted on myself the previous night, which distracted me from the content of the talks and the challenge of actually connecting with people on the hallway track (the most valuable part of any conference).

But, you know, there will be other conferences. Rust isn't going anywhere. And neither am I.

Except, you know, to Portland or wherever for the occasional conference.

I Meant to Do That

I quit my dayjob a few months ago. I said I was taking a sabbatical from my programming career to work on my own projects: there's a lot of math that I've been wanting to learn properly for a long time (game theory, Bayesian networks/structual causal models, analysis), and there's a lot of writing that I fear I must do (although for branding and market-segmentation purposes, I'm pretending that's someone else's story).

I have made some progress on these goals, but—as one would have predicted from an Outside (i.e., No Fun) View model trained on my historical behavior during periods of underemployment- or school-holiday-induced freedom—it's been disappointingly slow on a day-to-day level: it is easier to let an hour blur by in daydreams or low-quality internet reading than it is to actually study or actually write, and a day is only made of so many hours.

My dominant emotions surrounding this observation are guilt and shame. Guilt: that I'm failing my moral responsibility to be intellectually productive, a duty owed to the human spirit and maybe even the Bayes-structure itself. Shame: that a hypothetical adversary could use the fact of my slothfulness as evidence against my beauty, that the failure to live up to the promise of my ideals could be construed to deny or disparage the ideal itself.

Well, I do have a moral responsibility to be intellectually productive which is owed to the human spirit; this cannot be doubted. But I've been wondering lately if it might be better to let go of the shame and even most of the guilt. This not because shame and guilt can't be useful emotions, but rather that I might be thought of as having outgrown them.

I think the shame is born of insecurity: I spent a lot of years resenting school and resenting a culture that didn't have a concept of intellectual life or paths to economic success outside of school, resulting in a desperate need to prove myself: if I don't create given the time and freedom to do so, couldn't pawns of the system use it as ammunition to sneer at me and proclaim that no one can possibly do anything worthwhile without a teacher to command them to do it? And if I don't create, would they even be wrong?

Having something to prove was a useful motivation—it drove me to learn math, at least, to an extent that's probably hard to motivate without a status gradient at work. But now, at age 29—thanks to the software industry for a niche where my talents are economically legible, thanks to the aspiring-rationalist subculture for a community where I feel respected—I think I've exited the world I resented. Whatever I had to prove, I've either proved it by now or have extracted myself from the need to please any doubters.

What, then, should take the place of a desperate need to prove one's value as a source of motivation? What is to be the new emotional reaction to observations of slow progress, if not shame and horror and fear at what my enemies would make of this?

Shame creates an incentive to deny or minimize the culpable action, to distort the map of what actually happened in order to protect oneself: "I didn't do that; it's not what it looks like." I think I would prefer to draw on sources of motivation that don't have this property, that can accept the reality of what actually happened without pain ...

Ideas Have Expirations

One often-overlooked aspect of the crime of not-writing is that the harm isn't just about the things that deserve to be said that you never get around to saying because you don't put in the time and effort. It's also about the things that you can't say anymore even if you suddenly had the will, because the opportunity to say it was bound to a particular time, and trying to recapitulate the thoughts months or years after the fact would be irrelevant, or impossible.

This phenomenon comes in degrees. Start with irrelevance. Often the inadmissibility of tardy words isn't absolute: you could say things late, but the product would be less valuable than if it were timely—especially in a medium like blogging, where the posts being dated and displayed reverse-chronologically creates an expectation that the entries are associated with a particular point in time—at least, that they were written not too long before their publication date, even if the actual content isn't about the ephemera of the day or season. This has contributed to An Algorithmic Lucidity not being as good of a blog as it could be.

BABSCon swag

Like—each of the last two Aprils, I attended (one day of) BABSCon, the San Francisco Bay Area's premier convention for fans of the animated series My Little Pony: Friendship Is Magic, both times—even the second!—with the thought that the experience would make good fodder for a blog post in the "autobiographical account of my day at this timely Special Event" genre. I was going to tell you about how the first time, I made a couple of social faux pas while meeting Tara Strong and Nicole Oliver, only one of which was intentional; I was going to tell you about how the second time, I hadn't been planning to buy anything in vendor hall, but couldn't help but say "Shut up and take my money" in response to the demonstration of the Twilight Sparkle's Secret Shipfic Folder card game, the game-opening card of which I later got autographed by both members of Sherclop Pones, whose Friendship Is Witchcraft fandub series had clearly inspired some of the cards and probably the game itself, as well as being the source of some of my favorite music. I was going to tell you about how the first time, I was considering buying a coffee cup depicting the Mane Six (because I frequently bought medicinals at the outpost of the American coffee hegemon, and felt guilty about the wastefulness of accepting the default disposable cup every time like every other American), but hesitated, explaining to the vendor that I wasn't sure whether I wanted to use that cup in public, whereupon she said she could throw in a free button, to which I replied, "Sold!" And I was going to do a careful sociological analysis of curious observations like how I hesitated to buy that cup and why H. liked it so much in terms of gender ideology and signaling contrarianism.

But I didn't, and those Aprils were nine and twenty-one months ago, respectively. Not timely. My being motivated to write now ("That my past does not define me, 'cause my past is not today") can push a 350-word counterfactual "postview" of what I thought about saying over the threshold into existence, but it would be a bit unseemly to try to construct (I almost wrote reconstruct, but the re- prefix should be reserved for things that ever existed in the first place) a 2000-word personal account of the timely Special Event that happened last year or the year before that.

screenshot of the Leafline web client mid-game, showing the chess board and a scrolling move log

Or like—I made a thing not too long ago. I didn't mean to. It was an accident, really. It's a sort of oppositional strategy game engine—like a board game you play against the computer. The core move-scoring application is written in Rust, but there's also a web-application GUI (the "web client") in Clojure and ECMAScript 6 that's much more ergonomic for playing a game against. The game is—okay, well, it's chess: the endeavor snowballed out of my desire to participate in my coworkers' friendly office chess games combined with my reluctance to spend effort learning to be good at a task whose essential nature is so obviously suitable for automation. But writing a chess engine is just so cliché, and I enjoy naming things, so I quickly settled upon the conceit that actually I was writing an engine for a game that just happened to be exactly like chess, except that everything has different names: for example, instead of the pieces being black and white pawn, knight, bishop, rook, queen, and king, the figurines, or agents (never "pieces"), in my game are blue and orange servant, pony, scholar, cop, princess, and figurehead. (I kept rank and file, though.) This "adorable idiosyncratic names for everything" convention permeates the codebase. Despite the fact that unnecessarily gendering things isn't normally my style, I decided that ponies, scholars, and (inevitably) princesses were female, and that servants, cops, and figureheads were male, specifically in order to have an excuse to leave // ♀ and // ♂ comments in the enum declaration, because I feel like too many of my code comments are restricted to the ASCII or maybe Latin-1 subsets of the Basic Multilingual Plane, such that I don't want to pass up an opportunity to legitimately ("legitimately") use \u2640 FEMALE SIGN and \u2642 MALE SIGN. There are comments with ludicrous rationalizations for using the standard Forsyth–Edwards notation abbreviations ('P' is for peon, 'N' is for neigh, 'B' is for book, 'R' is for the Rule of law; the blue team's runes are lowercase because lowercase characters have higher ASCII codepoints, just as blue light has a higher frequency than orange light). Instead of pawn promotion, it's servant ascension, and a different verb is used to describe the process depending on the target figurine type (the servant moving the to the final rank can transform into a pony, be brevetted to cop, or transition into a princess or scholar). Or, like, Rust is quite conservative in the Yeggean sense, as manifested in features like the compiler forcing you to explicitly handle all possible variants of an enum; in cases where you know an instance of the enum can only be one of a strict subset of the possible variants, but the type system doesn't know that, you have to fill in those branches or supply a default case anyway, probably with a panic, which is like an exception that you can't catch, to abort the program with a message indicating that something entirely unanticipated has happened and it makes no sense to carry on. So I had been ending all of my panic messages with a stock phrase about how the unexpected thing was contrary to the operation of the moral law ("non-princesslike agent passed to princesslike\_lookahead, which is contrary to the operation of the moral law", and so forth), because this isn't the kind of codebase where you just say something like "assertion failed," as if the program should die because of some human authority's mere assertion, rather than only as a matter of justice when its behavior is contrary to the operation of the moral law. And then when my coworker Alexander Corwin started contributing, he abstracted away the boilerplate in these panic messages into this moral_panic! macro, which I thought was brilliant.

The web client is configured to run on port 2882. It's easy to remember because 2882 is Magnus Carlsen's peak ELO score.

terminal output from a Leafline console session, listing move alternatives with scores and principal variations

Software, like poetry, is never really finished (only abandoned), but getting the project to the point that I felt it was a minimal viable "product" took about eight glorious weekends (plus a few weekday nights, and with some help from Alexander). Near the end, watching the program utterly trounce me in web client play and feeling for all the world like a lieutenant junior grade, I started looking ahead to what came next for me. Over the past two years, the first two years of my life (that I feel comfortable admitting to), I had spent many, many night and weekend hours hacking on various side projects and coding exercises out of genuine enthusiasm and curiosity and desire to improve my craft—and, honestly, a feeling of insecurity, sensing that I needed to prove my worth as a hacker ("I threw myself into my studies, to have the world in my control"). But decent chess AI in Rust as an impulsive throwaway project seemed like a sufficiently strong signal of my programming prowess that maybe it was time to tie off this project, write the obligatory exciting blog post about it, and start allocating night and weekend hours towards some of the non-programming (!) interests I remember having in the before-time (assuming those memories are not fake). I could do some math! Write some fiction! Maybe even meet new friends ("I will not be shy; I'm going to try; I bet I'll find the reason why so many people, like me—")?!—all while feeling secure in the knowledge that my technology skills are clearly adequate for my continued existence to be economically viable. (For now.)

So ... about that end-of-project blog post. I was going to title it "Project Review: Leafline version 0.0.14-MVP; or, Lessons From Writing an It's-Not-Chess Engine in Eight Weekends", and I was going to explain everything to you—not just the silly names for everything that inexplicably amuse me (and only me), but the actually interesting substantive technical details of the implementation. Not that the AI is anything special—it's just textbook minimax search (in the negamax style) with α–β pruning and a position-evaluator that mostly counts material but also has bonuses for things like having both scholars or ponies and servants being in the center sixteen squares, plus a transposition (hash)table to look up scores of game-states it's already seen before, and another hashtable for history-heuristic move ordering. It's multithreaded, to take advantage of multiple cores (although I confess that the specific threading strategy is kind of a questionable hack). It can search up to 7 plies if you have a decent machine and are willing to wait ten or twenty minutes for the answer.

But even if it's nothing special, I was going to tell you about all the deeply moving philosophical insights I got from doing it. It's one thing to know how to refute the classic anti-AI argument (or straw person) that "humans couldn't possibly build something smarter than themselves by definition," but it's another thing to have the personal experience of having written something smarter than yourself in some particular domain, to the extent of feeling an acute sensation of futility while playtesting it, thinking: I've already coded my understanding of what it means to be good at this game; obviously I'm not going to do any better thinking about it with my slow meat-brain. (Although this is partially explained by my knowing almost nothing about chess strategy that I didn't learn in the course of this project; I've seen one of my coworkers beat the program at 4-ply search very quickly.) I was going to explain to you how α–β pruning works, with hand-drawn diagrams, and how you can interpret it as disregarding possible worlds that are too good or too terrible to be true (given rational play on both sides). I was going to tell you about the exciting surprise where the program seems to behave as if it understands the concepts of pinning and forking, even though those ideas aren't represented anywhere in the code!—but that when you think about it, that shouldn't actually be surprising: to the extent that we think pinning an opposing piece is a good idea that will lead to us picking up material, then pins should naturally appear in the results of searching the game tree for moves that are predicted to pick up material. And the reason we search for game-states where we hold a material advantage is because we expect that we're more likely to mate from those positions (in future nodes beyond our current planning horizon). Things that are, in all philosophical strictness, mere instrumental values, might profitably be treated as if they were terminal values by some algorithm that can't see far enough ahead to the actual goal, and this is a quantitative phenomenon: the shorter your lookahead, the more you want to rely on near-term approximating rewards. That's why I threw in a bonus for servants advancing to far ranks; I suspected that the existing code searching at the not-greater-than-7 plies that it could get in a reasonable amount of time, wouldn't adequately appreciate the true value of servant ascension, even though I expect that value would be naturally emergent in a deeper search, just as the value of some forks and pins emerged from mere 4- or 5-ply searches. (This was just a suspicion, though; I didn't take the time to actually test ascension-seeking behavior.)

So—though I've managed to just now haphazardly summarize some of the things about this project, this isn't really a careful project-review post. And now the distance between today and 27 September's 0.0.14-MVP tag is longer than that between that tag and the start of the project. And I ended up making a few more commits in subsequent weeks. So, no longer timely, at least not the way I originally imagined publishing a grand just-finished-project review post as a symbolic milestone marking a transition in how I'm going to start spending my precious non-dayjob time.

Or like—in late October, I saw the recent Jem and the Holograms film, because the previews (accurately) made it look like it was going to be really bad, and I thought I'd write a post combining a negative review of the new film with praise for the original Jem cartoon that this awful film mendaciously desecrated the name of. And then ... I didn't get around to finishing the post. Maybe my notes and memory from that night at the theater are accurate enough such that it's not too late—but the potential impact departed with the timeliness; I can't warn you not to go see it, because it's not in theaters anymore. (And good riddance.)

But beyond these sad cases of ideas that didn't get written up properly while they were still maximally relevant, there's an even worse way to fail to communicate, which is when the would-have-been-author has changed so much since first having the idea, that there's no way they could plausibly do justice to the idea as it was first had. You can't write a Diary entry about the day five years ago that you don't remember, and—more poignantly—you can't write a grand ideologically-driven novel in favor of the ideas you don't believe anymore. Some would argue it's just as well—if it's something you wouldn't write and couldn't stand by today, aren't you relieved that it doesn't exist to sully the name that represents who you are today? Even so, I would still favor intertemporal solidarity among past and future selves against the common enemy of our illiteracy.

Yes, illiteracy! Some would call it writer's block, but I know better than to bother with the unobservable distinction—whether you choose to describe your hypothesis as "doesn't write because unmotivated" or "doesn't write because doesn't know how," the result is the same: death of the non-author's memetic lineage.

Attentional Shunt

#!/usr/bin/env python3

# Copyright © 2015 Zack M. Davis

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

"""
Configure the machine to shunt traffic to distracting sites to localhost,
preserving attention.
"""

import os
import argparse
import subprocess
import sys
from datetime import datetime, timedelta

ETC_HOSTS = os.path.join(os.sep, 'etc', 'hosts')
HEADER = "# below managed by attentional shunt"
INVERSE_COMMANDS = {'enable': "disable", 'disable': "enable"}

DISTRACTING_HOSTS = (  # modify as needed
    'news.ycombinator.com',
    'math.stackexchange.com',
    'scifi.stackexchange.com',
    'worldbuilding.stackexchange.com',
    'workplace.stackexchange.com',
    'academia.stackexchange.com',
    'codereview.stackexchange.com',
    'puzzling.stackexchange.com',
    'slatestarcodex.com',
    'twitter.com',
    'www.facebook.com',
    'slatestarscratchpad.tumblr.com',
)
SHUNTING_LINES = "\n{}\n{}\n".format(
    HEADER,
    '\n'.join("127.0.0.1 {}".format(domain)
              for domain in DISTRACTING_HOSTS)
)


def conditionally_reexec_with_sudo():
    if os.geteuid() != 0:
        os.execvp("sudo", ["sudo"] + sys.argv)


def enable_shunt():
    if is_enabled():
        return  # nothing to do
    with open(ETC_HOSTS, 'a') as etc_hosts:
        etc_hosts.write(SHUNTING_LINES)


def disable_shunt():
    with open(ETC_HOSTS) as etc_hosts:
        content = etc_hosts.read()
    if SHUNTING_LINES not in content:
        return  # nothing to do
    with open(ETC_HOSTS, 'w') as etc_hosts:
        etc_hosts.write(content.replace(SHUNTING_LINES, ''))


def is_enabled():
    with open(ETC_HOSTS) as etc_hosts:
        content = etc_hosts.read()
    return HEADER in content


def status():
    state = "enabled" if is_enabled() else "disabled"
    print("attentional shunt is {}".format(state))


def schedule(command, when):  # requires `at` job-scheduling utility
    timestamp = when.strftime("%H:%M %Y-%m-%d")
    at_command = ['at', timestamp]
    at = subprocess.Popen(
        at_command,
        stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    at.communicate(command.encode())


if __name__ == "__main__":
    arg_parser = argparse.ArgumentParser(description=__doc__)
    arg_parser.add_argument('command',
                            choices=("enable", "disable", "status"))
    arg_parser.add_argument('duration', nargs='?', type=int,
                            help=("revert state change after this many "
                                  "minutes"))
    args = arg_parser.parse_args()
    if args.command == "status":
        status()
    else:
        conditionally_reexec_with_sudo()
        if args.command == "enable":
            enable_shunt()
        elif args.command == "disable":
            disable_shunt()

        if args.duration:
            now = datetime.now()
            inverse_command = INVERSE_COMMANDS[args.command]
            schedule(
                "{} {}".format(os.path.realpath(__file__), inverse_command),
                now + timedelta(minutes=args.duration)
            )

Back from Running

[16:03:37] <alice>  I'm back from literally running, metaphorically from
                    figurative demons
[16:03:50] <alice>  including the celebrity demon-prince Rateirs-Blak
[16:05:37] <carol>  alice: ?
[16:05:49] <carol>  oh
[16:05:55] <alice>  there's no canonical Latin-alphabet transliteration of his
                    name, because mortals fear to set it in writing
[16:06:08] <alice>  or maybe they just can't think of how or never make
                    the effort to do so; it's unclear

Everyday True Crime

It's not so much that writing is hard, so much as it is that not-writing is easy; so easy, in fact, that one can spend hours, days, or years not-writing without even noticing the magnitude of the crime—the wrongful nonexistence of everything left unsaid.

The Second R

I want to code all of the things, but I also want to write at least some of the things, but sometimes putting things in words—simple things, things I know—can be hard. Every other day I dream of getting in some writing in the night after I return from the code mines across the bay, but the box where the writing tool lives is the same as the box where you can read everything that anyone else has ever written, and you can guess what I really do then, when it's easier to read than to farm, to eat than to write.

But writing is important, because we can imagine nearby possible worlds in which the distribution of verbal skills is incompetenceward of our own, and the people in those worlds are sadder and poorer than us, the clumsiness of their attempts at communication leaving them less effective at coordinating their activities to dominate nature: colleagues maneuver against each other, ineffectually; television is less interesting; lovers stare into each others' eyes having less idea than you of what they're really looking at.

And in our own world, where people can say more, but not enough—I can read, but I'm missing something ... I can reckon with 'rithmetic, which serves a purpose, but cannot in human terms express the richness of vision that courses through ... something. And it cannot be a part of inner peace and glory until paired with something that does, high though the price may be for that something!

The second R, which is yet not an R. I want this more than I can say.

Permalink or It Didn't Happen

As far as I can tell, I don't have any kind of synesthesia. You can't be too sure (which means, you can easily be entirely too sure), what with our na(t)ive theories of psychology being so inadequate that everything we believe about other minds is but a filament of noise and conjecture, but your probability distribution about the mapping of sensory inputs to perceptions for me is probably not so different as mine of the same for you (dear reader of whom I know nothing)—roses seem red, violets would seem blue if we spoke a language that didn't already have a word for violet—which means that when I tell you that there's a musty, stale odor around a blog that hasn't been updated in a month and change, it's only a trite metaphor and not a perceptual reality of any sort. Still, even if you can't smell it (if your senses are like mine; if your fox, like mine, still hasn't bothered to implement the HTML5 <aroma> element), it's an ominous thing, to see a blog hovering near the boundary between life and death, a corpus perhaps on the way to being a corpse. The internet is littered with the latter, monuments to people who reliably had something to say, month after month ... until they missed a month, and then it wasn't long before they missed another.

a GitHub-style contribution graph of green squares

Now I can assure you that that will never happen to this place while I'm still breathing—this blog lives exactly as long as I do—only that's not a precise way of speaking; what I can do is offer you my assurance, which is a different thing from you actually feeling assured, which is a different thing still from that which was assured against actually never coming to pass. But I think these differences—between feeling and reality, between saying and reality—I think these enormous differences are much greater than the tiny, barely-perceptible gap between seeing so many gloriously intricate things to say, and making the time and words to express them on your blog when you are so busy with your trade in the manufacture of useful machinery (and the green tiles which are its highly-coveted industrial byproduct). But if all I can observe is that the gap is barely perceptible, then by the enormity of the earlier differences, I am not licensed to infer that the gap is tiny, not when the only reason I am telling you this is that I would die of shame if my monthly archives sidebar skipped a month for the first time since May of 'aught-twelve, not during this second year of my life in which I am supposed to write a compiler and a bad novelette even though it is for all intents and tens of intensive purposes practically March.

Growl

Dear reader, imagine you have an idea for a work of prose that you want to have finished by Election Day for reasons which will become clear later, and you're not sure how long it should end up being, but you think maybe around twelve thousand words. When considering what you can do to ensure that this feat will actually be accomplished, it occurs to you that you could start writing now. Or

Or you could design a script to make desktop notifications about how much more writing you have to do! (Maybe you could even put it in a cronjob so that it would nag you to write automatically!)

Well, I already made it for you (unless your Linux distribution doesn't use notify-send or you're on a Mac or something).

#!/usr/bin/env python3

import argparse
import subprocess
from datetime import datetime

arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("filename", help="path to file of draft")
arg_parser.add_argument("goal", type=int, help="goal wordcount")
arg_parser.add_argument("deadline", help="deadline in YYYY-MM-DD format")
args = arg_parser.parse_args()

today = datetime.today()
filename = args.filename
goal = args.goal
deadline = datetime.strptime(args.deadline, "%Y-%m-%d")

def nag_message():
    progress = int(subprocess.check_output(["wc", filename, "-w"]).split()[0])
    to_go = goal - progress
    days_remaining = (deadline - today).days
    to_go_per_day = to_go / days_remaining
    proportion = progress / goal
    return "\n".join(
        "{}: {:.2f}".format(k.replace("_", " "), v) for k, v in locals().items()
    )

subprocess.check_output(["notify-send", "writing progress", nag_message()])

My Wordcount Notification

You're welcome. Now get back to work.

Motivation

The blog has been silent for two weeks plus and, dear reader—that is, if there are any of you still remaining—dear reader, the thought occurs to me that maybe I should keep my drafts in a Git repository with a remote on GitHub, not because I need the full power of version control (I do not), but because then I would be rewarded for writing with those contemptible green contribution squares.

a GitHub-style contribution graph of green squares from July through February, with longest and current streak stats below

It's an anthropomorphism to think that humans have goals, that we do things because we've computed that they'll increase expected beauty or rightness in the world. We do things for the immediate reinforcement. You eat the candy because it tastes good and you show up to work on time because if you didn't, then your colleagues would notice. Serious long-term risks of diabetes or unemployment are too distant and too abstract to enter in the equation; far more effective is something immediately noticeable, even something as trivial as an integer being incremented or a square turning a darker shade of green. I tell myself that I code because it's fun and useful and lucrative (though I'm never explicit about whether that's descending or ascending order of importance), but would I be quite so diligent without the implicit gamification of my virtue? Would it be enough to have done good work, without wasting a few minutes here and there to gaze admiringly at commit diffs and contribution squares which manifest my moral worth in red and green and green?

Dear reader, I want you to picture yourself reclining at the end of a long day near the end of long career filled with great or terrible deeds. A young minion at the start of their own career will look at you and ask in awe, "O Master, what motivated you, all that time? What drove you on in your hour of deepest exhaustion? Was the it money, the fame, the men or women? Was it your ideological fervor or spirit of generosity?"

"No," you'll reply. "I did it for the green squares. And given the same circumstanstances ... I'd do it all again."

"You mean, you made the right choices? You have no regrets?"

"No, you fool!" you'll shout. "Don't you understand? I said, I'd do it again."

Thinking About Writing

"I've been thinking about writing a novel."

"I don't understand."

"I said, I've been thinking about writing a novel. What's there not to understand?"

"The phrase thinking about writing. Is that even grammatical? And if so, what could it possibly mean?"

"What? It's perfectly gram—oh, I get it. Fine. No hedging: I am going to write a novel!"

"Sorry, I still don't get it. I know what it means to have written something, or to be at a keyboard writing something. But to be going to write something, in the unobservable future? Even if the concept is coherent—and I'm not sure it is—how could you possibly know?"

Mode Lock

I'm afraid—it seems like (or maybe the weak phrasing seems like is just a form of denial, when the proposition under consideration should actually just be considered obvious) there's this terrible, terrible psychological trade-off, that there are some valuable qualities that you can't have without neglecting other valuable qualities, not just because you don't have enough time to fully develop too many different skills, but because when your brain is specialized in one direction, there are other things you can't learn. Oftentimes I feel like I don't want or know how to do anything except read and think ... which might be fine if I were independently wealthy and there wasn't any actual work left to do in the world, but in our current situation, it would be nice to make some money and actually accomplish something. There's a Trope for "Shapeshifter Mode Lock" but the cognitive equivalent is arguably more serious as disabilities go.

Library Fines

Overdue book fines are a terrible sin, not because of the harm done to other library stakeholders, but because of what they say about you as a person: not only did you not get around to finishing the books you (apparently erroneously) thought you wanted to read, but you weren't even responsible enough to bring them back on time.

Contra Costa County Library receipt showing paid overdue fines, against a pink background

Dreams

Friend of the blog Alicorn tweets:

Why is the word "dreams" used to describe both pseudorandom nocturnal hallucinations and also heartfelt aspirations for real life?

A cynic might reply: because both the nocturnal hallucinations and the heartfelt aspirations are, for the most part, composed of lies. How many people, what proportion of the time, will actually lift a finger (or open a book, or make a telephone call) to work towards actually achieving what they believe to be heartfelt aspirations?