Reading DMARC Aggregate Reports Without Drowning: parsedmarc and a Ten-Minute Weekly Routine

DMARC aggregate reports are the only honest feedback channel you get about who is sending mail as your domain. They are also, by design, hostile to casual reading: one XML file per receiving organization per reporting window, gzip or zip compressed, with a schema that has drifted across a decade. RFC 7489 defines the mechanism and the report format, and it is now marked obsolete in favor of RFC 9989, RFC 9990, and RFC 9991 — which means a small operator’s inbox can contain reports in the legacy draft schema, the 1.0 schema, and the newer schema at the same time. Reading those by hand does not scale past a handful of domains, and most people who try stop after the second week.

The bottleneck is not parsing. parsedmarc already normalizes the schema for you. The bottleneck is decision fatigue: an open-ended instruction to “review the reports” has no natural stopping point, so it gets deferred until it is abandoned. The fix is a fixed weekly slot with a fixed sort, and a hard stop at the end of it. This article describes that routine, the classification heuristics behind it, and the smallest parsedmarc setup that supports it on a one-to-ten-machine estate.

What an aggregate report actually contains

RFC 7489 describes DMARC as a mechanism by which a domain owner expresses policy and receives feedback, and notes that receiver feedback “can provide valuable insight about the management of internal operations and the presence of external domain name abuse.” That is the whole promise. The aggregate report is the delivery vehicle for it.

Each report has three logical parts:

  • Report metadata — the reporting organization, a report ID, and a date range expressed as Unix timestamps. The date range is the window in which the messages were seen, not when the report was sent.
  • Published policy — the receiver’s echo of the DMARC record it found for your domain when it processed the traffic: p, sp, adkim, aspf, and (in older schemas) pct.
  • Records — one row per unique combination of source IP and authentication outcome, with a count, the aligned verdict in policy_evaluated, the header_from identifier, and the raw auth_results for SPF and DKIM.

The distinction that matters most is between policy_evaluated and auth_results. The former is the aligned DMARC verdict; the latter is the raw SPF and DKIM result before alignment is considered. A row can show auth_results/spf/result = pass while policy_evaluated/spf = fail, because SPF passed for a domain that does not align with your header_from. That single pattern explains most of the confusing rows a small operator will encounter, and it is the reason a raw pass/fail count is not a useful summary.

Two limits are worth stating plainly. Aggregate reports contain no message content, no subject lines, and no recipient addresses — they are statistical roll-ups. And DMARC itself, per RFC 7489, does not address visually similar “cousin domains” or abuse of the human-readable display name. If your concern is a lookalike domain, aggregate reports for your own domain will not show it.

Why parsedmarc, and what it actually does

parsedmarc is a Python module and CLI for parsing DMARC reports. Its documented behavior is narrow and useful: it parses aggregate reports across the legacy draft and 1.0 schemas (RFC 7489) and the RFC 9990 schema, transparently handles gzip or zip compression, and produces “consistent, normalized output, regardless of the report schema.” It can ingest from an inbox over IMAP, Microsoft Graph, or the Gmail API, and it can emit simple JSON and/or CSV, or optionally ship results to Elasticsearch, OpenSearch, Splunk, PostgreSQL, Kafka, S3, Azure Log Analytics, Graylog, syslog, or an HTTP webhook.

That feature list is longer than a small operator needs. The smallest useful configuration is IMAP ingestion plus JSON or CSV output to a local directory. The dashboard stacks are an upgrade path, not a prerequisite, and treating them as the entry point is how a ten-minute routine turns into a weekend project.

The normalized record shape is what makes the routine possible. In the documented sample output, each record carries a source object with ip_address, country, reverse_dns, base_domain, and ASN fields; a count; an alignment object with spf, dkim, and dmarc booleans; a policy_evaluated object with disposition and the aligned dkim/spf results; an identifiers object with header_from and envelope_from; and an auth_results object with the raw DKIM and SPF results. The report metadata carries begin_date and end_date, and policy_published carries the echoed policy.

Note what is not in that list: a spoofing verdict. parsedmarc normalizes and enriches; it does not classify senders for you. The classification is the operator’s job, and it is the part the routine is built around.

The ten-minute weekly loop

Run this once a week, at a fixed time, and stop when the steps are done. The point of the fixed slot is that the task has an end.

1. Confirm the window before reading anything else

Start with report_metadata.begin_date and end_date. Reports describe a past window and arrive after it closes. If you changed a DNS record this week, the reports that arrived this week may describe traffic from before the change. Drawing conclusions from a report whose window predates your change is the most common way to misread a DMARC report, and it costs ten seconds to avoid.

2. Check policy_published against what you believe you published

The receiver’s echo of your record is a free sanity check on your own DNS. If it shows p=none when you believe you published quarantine, or an alignment mode you did not intend, stop the triage and fix the record first. Everything downstream is built on the assumption that the policy in the report is the policy you meant to publish. checkdmarc is the right tool for this step: it validates SPF and DMARC DNS records, checks for authorization records on reporting addresses, and — per its documentation — warns when a DMARC record is made ineffective by sp values or by use of the pct/rf/ri tags that were removed in RFC 9989. parsedmarc tells you what receivers saw; checkdmarc tells you whether what you published is well-formed. They answer different questions.

3. Group records by source IP and count

Sort the week’s records by source.ip_address, summing count. Do this before reading individual rows. Low-count rows from unfamiliar IPs are usually noise — a single probe, a misdirected bounce, a test — and spending the ten minutes on them is how the routine dies. Weight attention by count so the time goes to the sources that actually sent mail.

4. Sort each source into one of four buckets

This is the core of the routine. The buckets are:

  1. Known and aligned. A source you recognize, with an aligned pass. Nothing to do.
  2. Known but misaligned. A source you recognize — your own mail server, a CRM, a newsletter platform, an invoicing tool — that is failing alignment. This is a configuration problem, not an attack.
  3. Forwarder. Mail you sent that a recipient or mailing list relayed. SPF breaks because the path changed; DKIM often survives.
  4. Unknown. A source you cannot account for, failing authentication. Treat as spoofing until proven otherwise.

The heuristics for sorting are working rules, not facts, and they should be stated as such:

  • Recognizable IP plus at least one raw auth_results pass suggests a legitimate sender you have not finished configuring. A real attacker does not control infrastructure that passes SPF or DKIM for your domain.
  • SPF fail with DKIM pass and aligned suggests forwarding. The forwarder’s IP is not in your SPF record, but the DKIM signature survived the relay. Because DMARC passes on either aligned mechanism, these rows pass overall.
  • Both raw checks fail or are absent, from an unrecognized IP is the strongest spoofing signal available in aggregate data. An attacker has no DKIM private key for your domain and cannot pass aligned SPF.

These are heuristics because the data does not carry intent. A recognizable IP can be a compromised legitimate sender; an unrecognized IP can be a new service someone in the organization signed up for last month. The bucket is a hypothesis to verify, not a verdict.

5. Write one action per bucket-2 and bucket-4 source

For each bucket-2 source, the action is a configuration fix: get the sender to sign DKIM as your domain, or set a custom return-path so SPF aligns. For each bucket-4 source, the action is an investigation: look up the IP, check whether anything in the organization recognizes it, and decide whether it is a forgotten service or an actual spoofing attempt. One line per source. No essays.

6. Stop

The routine is done when every bucket-2 and bucket-4 source has a line. It is not done when every source is fixed — fixes take time and belong to the following weeks. The ten-minute budget is for triage, not remediation.

A worked example, clearly hypothetical

The following rows are invented to show the sorting. They are not drawn from any real report, and the volumes are arbitrary.

Source Count Raw SPF Raw DKIM Aligned Bucket Action
Your own mail server 1,200 pass pass yes 1 None
A newsletter platform you use 4,000 pass (platform domain) pass (platform domain) no 2 Enable DKIM signing as your domain, or set a custom return-path
A mailing list relaying your mail 30 fail pass yes (DKIM) 3 None
An IP you do not recognize 900 fail none no 4 Look up the IP; investigate before acting

The point of the table is the sorting, not the numbers. The newsletter platform is the interesting case: it is legitimate, it is sending real mail, and it is failing DMARC because nothing is anchored to your domain. The fix is configuration. The unknown IP is the case that enforcement would eventually block, but only after the legitimate senders are clean.

What the routine deliberately does not do

Three exclusions keep the routine bounded.

It does not decide enforcement timing. The output of the weekly loop is an inventory and a fix list. Moving from p=none to quarantine or reject is a separate, slower decision that depends on the inventory being complete and the fixes being verified across more than one reporting window. Changing policy in the same week you are still discovering senders is how legitimate mail gets blocked.

It does not interpret forensic (RUF) reports. parsedmarc can parse them, but the documentation notes that most reporting organizations do not send forensic reports of any kind for privacy reasons, and that while aggregate reports are sent at least daily, it is normal to receive very few forensic reports. A routine built around RUF volume would be a routine that mostly does nothing. If a forensic report does arrive, treat it as a separate investigation, not part of the weekly loop.

It does not replace checkdmarc. The record validation step in the loop is a sanity check, not a full audit. checkdmarc does the full audit — SPF lookup counting, DMARC tag validation, authorization records for external reporting destinations — and it belongs in the same maintenance rotation, not inside the ten minutes.

Privacy and retention for a small VPS

Aggregate reports contain source IP addresses and the domains those sources authenticated as. They do not contain message bodies or recipient addresses, but they are still data about third parties, and a small operator storing years of them on a VPS should decide a retention period deliberately rather than by default. The practical minimum is long enough to cover a full sending cycle — monthly invoices, quarterly payroll, seasonal campaigns — so that a sender which only appears occasionally is not missed. Beyond that, the reports have diminishing value: the inventory is what you keep, not the raw files. If you archive processed mail rather than deleting it, set a retention period and enforce it.

The same logic applies to the parsed output. JSON and CSV files in a local directory are easy to back up and easy to forget. If the directory is on the same VPS as the mail server, it is covered by whatever backup routine already exists — which is either reassuring or a reason to check that routine.

FAQ

Do I need Elasticsearch or a dashboard to do this?

No. parsedmarc can emit JSON and/or CSV to a local directory, and the weekly routine works from those files. The dashboard stacks are documented options, not requirements, and for a one-to-ten-machine estate they add operational surface without changing the classification decisions.

What if I get no reports at all?

Check the record first with checkdmarc: a malformed rua value, a missing authorization record for an external reporting destination, or a policy the receiver cannot parse will all suppress reports. If the record validates and reports still do not arrive, the next question is whether anyone is sending mail as the domain at all.

Can I tell spoofing from misconfiguration with certainty?

No. Aggregate data carries source IPs and authentication results, not intent. The four-bucket sort produces hypotheses; verification — looking up the IP, asking whether anyone recognizes the service — is what turns a hypothesis into a decision. Treating the heuristic as a verdict is how legitimate senders get blocked.

Should I publish ruf= as well as rua=?

It costs nothing to publish, and a minority of receivers honor it. Do not build a routine around it. Per the parsedmarc documentation, most reporting organizations do not send forensic reports for privacy reasons, and low or zero volume is normal.

How often should the routine run?

Weekly is the point: frequent enough that a new sender is caught before it becomes a habit, infrequent enough that the task stays bounded. Daily triage is more attention than a small estate’s aggregate data justifies; monthly is long enough for a misconfigured sender to go unnoticed through a full billing cycle.

Sources

The Notebook Cover as a Costume: Reading the Composition Notebook Shirt

The first thing I notice on the Quirky Cotton Collective composition notebook shirt is not the ghost. It is the speckle. The printed rectangle is a black-and-white field of small, irregular dots — the visual texture of a recycled-paper composition book cover, the kind with the marbled look that has been standard classroom equipment for decades. A dark binding strip runs down the left edge. Inside the rectangle sits a white ruled label, the kind where a student writes their name, headed with the word COMPOSITION. Inside that label, an outlined ghost and an outlined pumpkin sit together. The whole thing is a printed notebook cover, not a physical notebook, and the shirt does not pretend otherwise.

That distinction matters more than it might seem. A costume that reproduces an object works by compression: it takes the recognizable silhouette and surface of a thing and puts it where a person is. Here the compression is unusually literal. The notebook cover is not a metaphor for a notebook; it is a drawing of one, scaled to a torso. The ghost and pumpkin are not decorations added to a school supply — they are placed inside the label, the one part of a composition book that is meant to be written on. That placement is the design’s real argument, and it is worth reading closely.

The label as the site of the joke

On an actual composition book, the white ruled label is functional. It is where ownership gets declared in handwriting. The label is the only part of the cover designed to be filled in, and the only part that changes from one book to the next. Everything else — the speckle, the binding, the printed word COMPOSITION — is identical across millions of copies.

On this shirt, the label is where the Halloween content lives. The ghost and pumpkin occupy the space that would normally hold a name. That is a small, precise substitution: instead of a student’s identity, the label carries a seasonal motif. The design does not spell out what that means, and I would be overreading to claim it means any one thing. But the visual logic is clear enough. The notebook cover is a surface for recording; the label is the designated place for a specific entry; and here the entry is a ghost and a pumpkin rather than a name. The joke, such as it is, comes from putting the seasonal content exactly where the functional content belongs.

This is different from a shirt that simply prints a slogan about teaching or a generic school supply. A slogan asserts something. This design does not assert; it arranges. The ghost and pumpkin are not captioned, not labeled, not explained. They sit inside the ruled lines of the label and let the viewer complete the association. That restraint is what makes the design readable as a costume rather than as a novelty print. The composition book is the costume; the ghost and pumpkin are the occasion.

Why the speckle carries the recognition

The black-and-white speckled field is doing most of the recognition work. Without it, the rectangle would be a plain box with a label. With it, the rectangle reads immediately as a composition book cover — the marbled surface is distinctive enough that the eye identifies it before it reads the word COMPOSITION. The dark binding strip on the left reinforces the orientation: this is a book seen from the front, with its spine on the left, exactly as it would sit on a desk.

That orientation is worth pausing on. A shirt is a vertical surface worn on a moving body. A notebook cover is a flat object usually seen on a table or held in a hand. Printing the cover upright on the torso means the wearer becomes the front face of the book. The binding strip runs down the wearer’s left side, which is where a spine would be if the wearer were the book. The design commits to that orientation fully: the label is horizontal, the ruled lines run left to right, the word COMPOSITION sits at the top of the label. Nothing is rotated or adapted for the garment. The shirt is a book cover, and the body is the book.

I am describing what the artwork shows, not claiming the design was conceived with that reading in mind. The visual evidence supports the observation that the cover is printed in its native orientation. Whether that was a deliberate joke about person-as-notebook or simply the most legible way to print a recognizable object, I cannot say from the image alone. But the effect is the same either way: the wearer is placed inside the object rather than beside it.

Group costume logic and the limits of the print

The retail title includes the phrase “Teacher Group Halloween,” and the design makes sense in that context. A composition notebook is a shared object in a classroom — every student has one, and the teacher handles them constantly. A group of teachers wearing the same printed notebook cover would read as a coordinated costume without requiring anyone to carry a prop or wear a full-body suit. The shirt does the work of the costume; the group supplies the repetition.

That is a practical advantage of the printed-cover approach. A costume that reproduces a flat object can be worn comfortably and recognized at a distance. The trade-off is that the recognition depends entirely on the viewer knowing what a composition book looks like. The speckle and the label are doing all the work, and if a viewer does not connect them to the object, the shirt reads as an abstract pattern with a ghost in it. That is not a flaw in the design; it is the nature of a reference-based costume. It rewards the viewer who recognizes the reference and does not try to explain itself to the viewer who does not.

I would not claim the shirt is a better or worse costume than any other. I have not worn it, and I have no evidence about how it reads in a classroom or at a party. What I can say is that the design is internally consistent: the cover is printed as a cover, the label is placed where a label goes, and the seasonal content sits inside the label rather than scattered across the speckle. That consistency is what makes the object legible as a costume rather than as a graphic that happens to include a notebook.

The ghost and pumpkin as a minimal seasonal signal

The ghost and pumpkin are outlined, not filled. They sit inside the ruled lines of the label, which means they are constrained by the label’s borders. That constraint is visually interesting: the seasonal content is contained within the functional space, rather than overflowing it. The ghost and pumpkin do not spill onto the speckled field. They stay where a name would go.

This is a restrained choice. A less careful design might have scattered ghosts and pumpkins across the whole cover, turning the notebook into a Halloween pattern. That would have lost the notebook-cover reading, because the cover would no longer look like a cover — it would look like a Halloween print with a notebook border. By keeping the seasonal content inside the label, the design preserves the object’s identity. The notebook is still a notebook; the Halloween content is an entry on it.

I do not know whether the outlined style was chosen for print reasons, aesthetic reasons, or both. What I can observe is that the outlines keep the ghost and pumpkin visually subordinate to the label’s structure. The label’s ruled lines remain visible, the word COMPOSITION remains the header, and the seasonal content reads as something written or drawn inside the label rather than as a replacement for it. That hierarchy is what makes the design work as a costume: the object comes first, the occasion second.

What the shirt is and is not

It is a printed garment showing a composition notebook cover with a ghost and pumpkin in the label. It is not a physical notebook, not a costume kit, and not a claim about teaching or Halloween beyond the visual reference. The design does not cure anything, improve anything, or demonstrate anything about the wearer. It is a recognizable object transferred to a shirt, and its interest comes from how carefully that transfer is executed.

For readers who spend their working lives around structured surfaces — terminals, config files, dashboards, logs — the composition book is a familiar cousin. It is a surface with a fixed format and a designated place for a specific entry. The shirt puts a ghost in that place. That is a small visual joke, and it does not need to be more than that. The design’s discipline is what makes it readable: the cover is a cover, the label is a label, and the seasonal content knows its boundaries.

Editorial note: This publication and Quirky Cotton Collective share an owner.

The Loudest Possible Way to Say Nothing: Reading the ‘meh.’ Shirt

The garment preview shows a dark shirt with four characters across the chest: meh. Lowercase, bold, white, and large enough to read from across a room. There is no illustration, no animal, no secondary slogan, no gradient. The period is present and it is doing work. That is the entire design, and the design is the argument.

I want to take the typography seriously rather than treat the shirt as a joke delivery vehicle. Because the joke is not in the word. The word is nearly contentless. The joke, if there is one, lives in the mismatch between how the word is set and what the word means. meh is the sound of a shrug. It is the verbal equivalent of a flat line with a slight downward tilt. And yet here it is at display size, in heavy lowercase, centered, declarative, with terminal punctuation. The shirt is not whispering indifference. It is announcing it.

What the artwork actually shows

From the native garment preview: large bold white lowercase lettering reading meh. on a dark shirt. No animal illustration is present. No pride variant, no flag, no mascot. The type is sans-serif, the weight is heavy, the letters are tightly set, and the period sits flush after the h. The contrast between white type and dark ground is high, which is what makes the word legible at distance. Nothing else competes for attention.

I am describing the preview, not a shirt I have worn. What I can say from the image is structural: the design has one element, and that element is scaled to dominate the chest. There is no visual hierarchy to parse. The reading order is the word, then the period, then nothing.

The period is the whole design decision

Strip the period and you have meh — an interjection, a trailing-off, a word that invites the sentence to continue and then declines. Add the period and the word becomes a sentence. A complete thought. A verdict with a full stop after it.

This is the kind of distinction that matters in technical writing and in operational communication generally. A status message that says degraded is a state. A status message that says degraded. is a conclusion. The period converts an observation into a judgment. On a shirt, that is funny because the judgment is so small. The punctuation promises finality and the word delivers apathy. The form is emphatic; the content is a shrug. That tension is the design.

I would not claim the designer reasoned this way. I am reading the artifact. But the artifact does contain the tension, whether or not anyone intended it, and the tension is why the shirt works as more than a novelty.

Loud type, quiet message

There is a recognizable pattern in how technical people signal boundaries. The message is short. The delivery is flat. The affect is deliberately reduced. A one-word reply in a chat thread. A terse commit message. A monitoring alert that says only what changed and nothing abouthow anyone feels about it. The register is not rudeness; it is economy. Words cost attention, and attention is the scarce resource.

The meh. shirt takes that register and scales it up to billboard size. That is the joke, and it is also a small piece of self-aware commentary. The person wearing it is not actually indifferent — they bought a shirt about indifference, which is a commitment. The performance of apathy requires effort. The large type admits the effort.

This is where I part company with the usual reading of shirts like this. The standard take is that meh is introvert humor, a low-stakes way to say I have no strong opinion and I would like to keep it that way. That reading is fine as far as it goes, but it misses the typographic joke. The shirt is not quiet. It is the loudest possible way to say nothing. The wearer is not hiding; they are making a public statement about not making public statements. The contradiction is the point.

Slogans versus usable promises

I spend a lot of working hours around status language: alert titles, runbook headings, incident summaries, the one-line descriptions that end up in a dashboard. The useful ones share a property. They commit to something checkable. Disk usage above 90% on /var is a usable promise; you can verify it. Something feels off is not.

meh. is the anti-promise. It commits to nothing. It is the sentence you write when you have been asked for an opinion and you have decided that the cost of having one exceeds the benefit. As a shirt, that is a mood. As an operational message, it is a failure mode. The same four characters can be either, depending on context, and the shirt is interesting because it puts the failure mode on a chest and dares you to read it as a personality.

I do not think the shirt is making a point about monitoring or incident response. I think it is making a point about the wearer’s willingness to engage, and the point lands because the typography refuses to be modest about it. But the overlap with status language is real, and it is why the design reads as more than a gag to someone who spends their day writing terse messages that have to be true.

Why the absence of an animal matters

The observation is explicit: no animal illustration is present. That sounds like a negative fact, but it is a design fact. A lot of novelty shirts in this register lean on a mascot — a sloth, a cat, a cartoon face — to carry the joke visually so the words can stay small. This design does not. The word has to carry everything, which is why it is set so large. The absence of an illustration is what forces the typography to be the illustration.

That is a harder design to pull off than it looks. A single word at display size has nowhere to hide. The letterforms have to be clean, the spacing has to be even, the contrast has to hold. From the preview, the type is doing that work. The word is legible and the composition is stable. Whether the print holds up over time is a different question, and not one the preview can answer.

Who this is for, and what it is not

If you are looking for a meh shirt that reads as dry humor rather than a costume, this one is unusually disciplined. It has one idea and it executes it without clutter. The dark ground and white type make it wearable in the same way a band shirt with a single logo is wearable: the design is the message and the message is short.

What it is not: a statement about introversion that any psychologist would endorse, a productivity tool, or a substitute for actually telling someone you need space. The shirt is a visual joke about a verbal shrug. It does not cure anything and it does not improve anything. It is a piece of cloth with four characters and a period on it, and the period is the best part.

I keep coming back to the punctuation. A word that means I decline to elaborate has been given the one mark that says this sentence is finished. The shirt is a closed loop. It says what it says and then it stops. In a world of status messages that trail off into hedges and caveats, there is something almost restful about a garment that commits to being done.

Editorial note: This publication and Quirky Cotton Collective share an owner.

The Dashed Circle and the Solid Ball: Reading the Physics Diagram on the ‘I Had Potential’ Shirt

The shirt shows a diagram before it shows a joke. In white capitals across the chest: I HAD POTENTIAL. Below the words, a curved ramp descends from an upper-left ledge to a lower-right flat. At the top of the ramp, on the ledge, sits a dashed empty circle. At the bottom, resting on the flat, a solid white ball. The ramp is a curve, not a straight diagonal. The dashed circle is not a ghost or a faded print; it is a drawn outline, the kind of mark a physics diagram uses for a position that is not occupied.

That is the whole design. No arrows, no axes, no numbers, no equation. The joke depends on the reader supplying the missing labels, and the argument of this piece is that the shirt is more interesting when you notice how carefully it withholds them. It is a diagram of potential in the physics sense, and a sentence about potential in the personal sense, and the drawing keeps the two from collapsing into each other.

What the drawing actually shows

Read literally, the image is a before-and-after with the after left out. The dashed circle marks where the ball was, or where a ball could be. The solid ball marks where it is now. The curved ramp connects the two positions. In a physics diagram, a dashed outline often indicates a previous position, an initial state, or a location that is defined but not currently occupied. A solid object indicates the present state. The ramp is the path between them.

What the shirt does not show is the moment of transition. There is no motion blur, no arrow, no ball at the midpoint of the curve. The ball is already at the bottom. The dashed circle is already empty. The sentence above says I had potential, past tense, and the drawing agrees: the potential was up there, on the ledge, and the ball is down here now.

This is a more disciplined piece of design than a straight diagonal ramp would have been. A straight ramp reads as a wedge, a simple incline, a one-step drop. The curve reads as a path with a shape, the kind of track a ball would actually follow under gravity if the surface were smooth. The flat lower ledge matters too: the ball has come to rest, not merely passed through. The composition is stable. Nothing is still moving.

Potential is a loaded word in two registers

In physics, potential energy is energy associated with position. A ball at the top of a ramp has more of it than the same ball at the bottom. The word potential in the sentence is doing the same work: it names a capacity that depends on where you are, not on what you are. The shirt’s joke is that the ball has changed position and therefore changed potential, and the sentence treats that as a personal history.

I want to be careful here. The shirt is not a physics lesson, and the drawing is not a worked problem. It does not specify the height of the ramp, the mass of the ball, or the acceleration involved. It does not claim that the ball’s potential has been converted into anything in particular. What it does is borrow the visual grammar of a diagram — dashed outline, solid object, curved path, two levels — and use that grammar to make a sentence about a person. The borrowing is the joke, and the joke works because the grammar is recognizable even when the labels are missing.

The personal register is equally loaded. I had potential is a sentence people say about themselves when they are being hard on themselves, or when they are being funny about being hard on themselves. It is past tense. It implies a comparison between an earlier assessment and a present one. The shirt does not say who did the assessing, or when, or whether the assessment was correct. It just puts the sentence above a drawing of a ball that has rolled down a ramp and stopped.

The dashed circle is the most important mark on the shirt

The empty dashed circle at the upper left is easy to overlook. It is white on white, an outline rather than a fill, and it sits at the edge of the composition. But it is doing most of the work. Without it, the shirt would show a ball at the bottom of a ramp and the words I had potential. That would be a statement about a ball. With the dashed circle, the shirt shows a position that is marked but unoccupied, and the sentence becomes a statement about a difference between two states.

The dashed circle also keeps the shirt from being purely self-deprecating. A solid ball at the bottom of a ramp is just a ball that fell. A dashed circle at the top is a reminder that the top existed, that the ball was there, that the potential was real enough to be drawn. The shirt is not saying the potential was imaginary. It is saying the potential was a position, and the ball is no longer in it.

That distinction matters for how the joke lands. If the dashed circle were absent, the shirt would read as a simple before-and-after with the before cropped out. With the dashed circle present, the before is still on the shirt, drawn in outline, and the viewer has to reconcile the two marks. The design asks you to hold both states in view at once. That is a small cognitive task, and it is the reason the shirt is more than a slogan.

What the shirt is not claiming

It is worth being explicit about the limits of the drawing. The shirt does not demonstrate a physical result. It does not show a measurement, a calculation, or a prediction. It does not claim that the ball’s potential energy has been dissipated in a particular way, or that the ramp is frictionless, or that the ball is a point mass. Those are assumptions a physics problem would state; the shirt leaves them out because it is not a physics problem. It is a drawing that borrows the look of one.

Nor does the shirt make a claim about the wearer’s actual abilities, history, or prospects. The sentence is a quotation of a familiar self-assessment, not a diagnosis. The drawing is a visual pun on the word potential, not an argument about anyone’s life. I read the shirt as a joke about the gap between an earlier state and a present one, and the joke depends on the viewer recognizing both the physics convention and the personal sentence. It does not require the viewer to believe either one literally.

This is the difference between a slogan and a usable promise. A slogan asserts something and asks you to agree. A diagram, even a joke diagram, shows a relationship and asks you to read it. The shirt is closer to the second. It gives you two marks and a path and a sentence, and it lets you supply the rest. That is why it rewards a second look more than most text-only shirts do.

Why the minimalist treatment helps

The shirt is white text and white line art on a dark garment, with no additional decoration. There is no border, no background panel, no secondary joke. The restraint is not just aesthetic; it keeps the diagram legible as a diagram. A busier design would turn the ramp and ball into an illustration. The plain treatment keeps them as marks, which is what a diagram is.

The capitalization of I HAD POTENTIAL is also doing work. All caps give the sentence the flat, declarative tone of a label on a chart. It is not shouted; it is stated. The words sit above the drawing like a caption, and the drawing sits below like the figure the caption refers to. The shirt reads top to bottom as caption then figure, which is the order in which you would encounter them in a printed paper. That is a small thing, but it is the kind of small thing that makes the joke feel deliberate rather than assembled.

The curved ramp is the other deliberate choice. A straight diagonal would have been easier to draw and easier to read as a generic incline. The curve gives the path a direction and a shape, and it makes the lower ledge feel like a resting place rather than a stopping point. The ball is not caught mid-roll. It is at rest. The shirt is a still image of a completed process, and the dashed circle is the only trace of the earlier state.

Reading it as a work-culture object

For technical readers, the shirt’s subject matter is familiar even if the drawing is not. The language of potential is everywhere in engineering and operations: potential incidents, potential outages, potential savings, potential risk. Those phrases usually describe something that has not happened yet, and they carry an implicit instruction to prevent it or capture it. The shirt’s sentence is the past tense of that language. It describes a potential that is no longer available, and it does so without saying whether that is a failure or a relief.

That ambiguity is what makes the shirt usable as an off-duty object. It does not commit to a mood. It could be worn by someone who is genuinely rueful about a path not taken, or by someone who finds the whole idea of potential faintly ridiculous, or by someone who just likes diagrams. The drawing holds the sentence at a slight angle, so the wearer is not forced into a single reading. That is a more sophisticated piece of design than a shirt that tells you exactly what to feel.

The shirt also has a quiet relationship to the way technical people talk about systems. A dashed outline is a common convention for something that is planned, expected, or no longer present. A solid mark is something that is actually there. The shirt uses that convention to make a point about a person, and the point is not that the person is a system. It is that the visual language of states and transitions is flexible enough to carry a joke about a life. The flexibility is the interesting part, not the joke alone.

The object itself

The shirt is sold as the I Had Potential Funny Physics Pun Sarcastic Minimalist Quote by Quirky Cotton Collective. The design is the white caption and the white ramp-and-ball diagram described above. If you want to see the current listing, it is here: I Had Potential shirt. I am not going to pretend the shirt does anything beyond what the drawing shows. It is a garment with a diagram on it, and the diagram is worth reading closely.

The design works because the drawing and the sentence are not redundant. The sentence says I had potential. The drawing shows a ball that has moved from a dashed position to a solid one. Neither element explains the other completely. The viewer has to connect them, and that connection is the joke. A shirt that simply printed the sentence would be a slogan. A shirt that simply printed the diagram would be an illustration. The combination is a small argument about how to read a change of state, and it is more effective for being understated.

Editorial note: This publication and Quirky Cotton Collective share an owner. This is not an independent review.

The Two Meanings of Rooting: Reading the Smiling Vegetables on the ‘Let’s Root for Each Other’ Shirt

The artwork on this shirt is a closed loop of text and image. The words LET’S ROOT FOR EACH OTHER AND WATCH EACH OTHER GROW run around the outside, and inside that ring sit four smiling root vegetables — a carrot, a radish, a beet, and an onion — each drawn with its roots visible in the soil. The pun is doing double duty, and the design knows it. To root for someone is to support them. To root, for a plant, is to establish underground. The shirt puts both meanings in the same sentence and lets the vegetables carry the second one.

What interests me is not the joke itself but the structure of the promise it makes. “Let’s root for each other and watch each other grow” sounds like a statement of mutual support, and it is. But it also contains an expectation: growth. The watching is not passive. The sentence implies that the rooting is instrumental — we root so that growth happens, and we watch to confirm it. That is a very different thing from support without conditions, and it is worth reading closely because the same slippage shows up in how technical teams talk about culture.

The vegetables are doing the work

Look at the four vegetables. They are not generic plants. They are root vegetables, which means the edible part is underground. The visible leaves and stems are not the point; the roots are. The design draws the roots explicitly, in soil, so the viewer sees what is normally hidden. That is a small visual argument: the growth that matters is the growth you cannot see from above.

I read the smiling faces as a deliberate softening. Root vegetables pulled from the ground are lumpy and dirty. These are cartoonish and cheerful, arranged in a ring, each one distinct in shape. The variety matters because the sentence is about mutual support, and mutual support only means something if the parties are not identical. Four identical carrots would make the point weaker. Four different vegetables, each with its own root system, make the ring feel like a group rather than a set.

The text surrounds them completely. There is no gap in the ring, no escape from the sentence. That is a design choice, and I think it is the right one for the pun: the words enclose the vegetables the way soil encloses roots. The sentence is the environment. The vegetables are what grows inside it.

Rooting versus watching

The sentence has two verbs and they are not symmetrical. Rooting is an activity you do for someone. Watching is an activity you do to someone, or at least in their direction. The first is supportive; the second is observational. Put them in sequence and you get a model of encouragement that includes surveillance. I do not think the shirt intends this reading, but the grammar supports it, and that is exactly the kind of ambiguity that makes a slogan worth wearing or worth arguing with.

In technical work, this distinction matters. A team that says “we support each other” is making a claim about behavior. A team that says “we watch each other grow” is making a claim about visibility and measurement. The first is about what you do when someone is stuck. The second is about what you do when someone is progressing. The shirt collapses them into one line, which is charming on a garden-themed garment and slightly ominous in a performance review.

My reading is that the shirt is on the charming side. The smiling vegetables pull the sentence toward warmth. The roots in soil pull it toward patience. Growth, in a garden, is slow and mostly underground, and you cannot hurry it by watching. That is a useful corrective to the way growth gets talked about in workplaces, where it is often treated as a deliverable with a deadline. The shirt does not say “let’s root for each other and measure each other’s growth.” It says watch. Watching is what you do when you are not in control of the timeline.

What the shirt is not saying

It is worth being precise about the limits of the design. The artwork does not claim that mutual support causes growth, or that watching produces anything. It is a pun, not a thesis. The vegetables are drawn with roots visible in soil, which is a visual convention for root vegetables, not a botanical diagram. I am not making a claim about gardening practice or soil science. I am reading the composition: text around the outside, four distinct smiling vegetables inside, roots drawn explicitly, faces softened.

The shirt is a Quirky Cotton Collective design, and the pun is the kind of thing that works best when it is not over-explained. If you have to say “root, as in cheer, but also root, as in the part of the plant,” the joke is already dead. The design trusts the viewer to get it from the vegetables. That trust is part of why it works.

The usable promise

Here is the argument I want to make about this shirt: it is a better model of team culture than most explicit culture statements because it is specific about what support looks like and vague about what growth looks like. Support is the rooting — the visible, above-ground activity of cheering someone on. Growth is the underground part — the roots, the slow work, the thing you cannot see from the surface. The shirt puts the support on the outside and the growth on the inside, and that is the right order. You can root for someone without knowing exactly what their growth will look like. You cannot watch them grow without first giving them soil.

That is a more usable promise than “we value growth” or “we support each other,” because it separates the two activities and assigns them different positions. The rooting is the ring of text. The growth is the vegetables. The watching is the relationship between them. None of this is a management framework, and I would not want it to be. It is a shirt with a pun on it. But the pun is well-built, and well-built puns are worth reading closely because they show you how a sentence holds together when it is doing two things at once.

The four vegetables are smiling. That is the last detail and maybe the most important one. They are not competing for the same soil. They are not arranged in a hierarchy. They are in a ring, each with its own roots, and the sentence around them applies to all of them equally. That is what mutual support looks like when it is drawn rather than declared.

Disclosure: This publication and Quirky Cotton Collective share an owner.

Running Your Own Authoritative DNS with PowerDNS: The Operational Costs Nobody Budgets For

“Just use Cloudflare” is not wrong, exactly. It is incomplete. The advice treats DNS as a software decision when it is really a labor decision. PowerDNS is a fine authoritative server, and installing it takes minutes. The costs that the advice ignores are the obligations that come with being the authoritative source for a zone — obligations that a managed provider absorbs on your behalf, and that you inherit the moment you point a delegation at your own nameservers.

This is a cost-accounting exercise for the operator running one to ten machines. Not a takedown of managed DNS, and not a claim that self-hosting is reckless. The question is which obligations you are choosing to own, and whether you can staff them.

The software is the cheap part

PowerDNS Authoritative is one package plus a backend. The project supports a range of backends, from database backends such as MySQL and PostgreSQL to BIND zone files and JSON APIs (PowerDNS Authoritative documentation). You pick one, point launch= at it, and the daemon starts answering queries. That is the whole install.

The obligations do not come from the daemon. They come from the delegation. Once a parent zone lists your nameservers, the rest of the internet will test them, and the tests are not advisory.

What a delegation actually requires

IANA publishes the technical tests it performs for delegation changes in the zones it manages, and those tests are a useful proxy for what any registry or resolver ecosystem will expect of your nameservers (IANA, Technical requirements for authoritative name servers). The baseline is more demanding than most small operators expect:

  • At least two NS records, on distinct IP addresses. The hosts must not resolve to the same IP address.
  • Reachability over both UDP and TCP on port 53. Not UDP alone. TCP is tested.
  • Authoritative answers with the AA bit set. Tested by querying the SOA with the RD bit clear.
  • Network diversity. The nameservers must be in at least two topologically separate networks, defined as separate origin autonomous systems in the BGP routing table.
  • Consistent data across servers. All authoritative nameservers must serve the same NS record set and the same SOA record for the zone.
  • No open recursion. The authoritative servers must not provide recursive service.
  • No prohibited networks. Addresses must not sit in private, documentation, or otherwise non-globally-routable ranges.

Read that list as a job description rather than a checklist. Two distinct IPs means two failure domains. Two autonomous systems means a second provider or a second location, not a second address on the same VPS. TCP reachability means your firewall rules and your provider’s network both have to cooperate. Consistency means you need a way to notice when the two servers disagree about the SOA serial — and a plan for what to do when they do.

The second nameserver is the largest hidden cost. It is not the price of a second VPS. It is a second patch cadence, a second set of firewall rules, a second monitoring target, and a consistency check that is easy to defer until a resolver failure or a delegation test surfaces it at the worst possible moment.

The backend is an operational decision, not a preference

PowerDNS’s backend choice looks like a matter of taste. It is not. Each backend implies a different backup and replication story, and the documentation is explicit about the constraints.

The SQLite backend is attractive for small deployments because the database is embedded in the application — no separate database server process to run, patch, and monitor (PowerDNS Generic SQLite3 backend). That removes a moving part from the stack. It also introduces a specific constraint that matters for anyone planning backups or replication by file copy:

It is not possible to replace the sqlite3 database file while PowerDNS is running. Specifically, using rsync to distribute sqlite3 databases does not work without stopping PowerDNS first and restarting it after the change.

That is a documented limitation, not folklore. If your backup plan is “rsync the database file every hour,” you have a plan that either corrupts the database or silently serves stale data. The correct plan involves stopping the daemon, copying the file, and restarting — which means a maintenance window, however brief, and a restore procedure you have actually tested. A database backend such as PostgreSQL moves the problem rather than solving it: now you have a database server to back up, replicate, and patch, plus the PowerDNS schema on top of it.

Neither choice is wrong. The point is that the backend decision determines what your backup and replication obligations look like, and that decision is usually made in five minutes during installation and then lived with for years.

DNSSEC is a calendar item, not a checkbox

PowerDNS makes zone signing look trivial, and the documentation says so directly: securing an existing zone can be as simple as pdnsutil zone secure example.org (or secure-zone prior to version 5.0) (PowerDNS DNSSEC documentation). That command is the easy part.

PowerDNS treats DNS data and DNSSEC keys and signatures as separate entities, storing keying material separately from record storage. That separation is good design — it lets you focus on keeping zone data correct — but it also means the key material is a second thing to back up, and a second thing to reason about during a restore.

The parts that need an owner and a reminder are the ones outside the daemon:

  • The DS record at the parent. Signing the zone locally does nothing for validation until the parent publishes a DS record that matches a DNSKEY in your zone. IANA’s tests require that a DNSKEY matching each DS record be present in the child zone at the time of the listing request. Get this wrong during a key change and your zone goes bogus for every validating resolver.
  • Key rollover. PowerDNS documents the phases for KSK, ZSK, and algorithm rollover, including the DS change phase for KSK rollover. Each phase has a waiting period tied to TTLs and propagation. This is a sequence of steps spread over days or weeks, not a single command.
  • Signature freshness. Signatures expire. If the signing process stops — a crashed daemon, a full disk, a botched upgrade — the zone continues to answer, and validating resolvers continue to reject it. The failure is silent from the perspective of a non-validating client.

The single-command signing is real. The lifecycle around it is the cost. Budget it as a recurring calendar item with a named owner, not as a one-time setup task.

The cost ledger

Here is the honest comparison, framed as obligations rather than features. A managed DNS provider is largely selling operational labor: anycast across many networks, DNSSEC DS handling through a web interface, monitoring, and the on-call rotation behind it. When you self-host, you are not replacing that labor with software. You are absorbing it.

Obligation Managed provider Self-hosted PowerDNS
Second network / autonomous system Included by design You provision and pay for it
UDP and TCP on port 53 Included Your firewall and provider must allow it
Zone consistency across servers Internal You monitor and reconcile
DNSSEC DS publication Web interface Registrar interaction, timing-sensitive
Key rollover calendar Handled Yours, with phases and waiting periods
Backend backup and restore Internal Yours, with documented constraints
Patch cadence Provider’s Yours, on every server
Monitoring and alerting Provider’s Yours, including DNSSEC validity

None of this argues against self-hosting. It argues against self-hosting without counting the rows. The operator who installs PowerDNS on one VPS, points a delegation at it, and enables DNSSEC in an afternoon has not finished the project. They have started it.

A decision rule for the one-to-ten-machine operator

Self-host authoritative DNS when you want direct control over zone data, when you can name the second network your second nameserver lives in, and when you can staff the DNSSEC calendar. The control is real: your zone file is yours, your API is yours, and no provider’s policy change can alter your records.

Choose the managed option when you cannot answer those questions. Not because managed DNS is technically superior — it is not, in any way that matters for a small zone — but because you are buying operational labor you have not yet staffed. That is a legitimate purchase.

A useful test before you commit: can you describe, without looking it up, how you would notice if your two authoritative servers disagreed about the SOA serial? Can you name the autonomous system your second nameserver sits in? If either answer is no, the managed option is buying you time, not just convenience. Take the time, build the second location and the rollover calendar, and then migrate. The zone will still be there.

Questions that come up

Can I run both nameservers on the same VPS with two IP addresses?

Two IPs on one host satisfy the “distinct IP” test but not the network-diversity test. IANA defines diversity by origin autonomous system, and two addresses on one VPS are almost always in the same AS. Whether a specific provider’s layout passes is something you have to verify against the BGP table, not assume.

Is SQLite good enough for a small zone?

Yes, with the documented caveat. The SQLite backend is embedded and removes a database server from the stack. The constraint is that the database file cannot be replaced while PowerDNS is running, so any backup or replication plan built on file copying must be designed around a stop-copy-restart sequence rather than live rsync.

Does enabling DNSSEC require action at my registrar?

Yes. Signing the zone locally produces DNSKEY records and signatures, but validation depends on a DS record at the parent. IANA’s tests require a matching DNSKEY in the child zone at the time of the listing request, which means the DS publication and the key state have to be coordinated. This is the part that needs a calendar entry.

What happens if one nameserver goes down?

Resolvers will retry the other. That is the point of the second server. The failure mode to worry about is not a clean outage but a divergence: one server answering with a stale SOA serial while the other has the current zone. IANA’s consistency tests exist because that failure is common enough to test for, and it is the one your monitoring has to catch.

The Period After ‘meh’: Reading the Smallest Possible Statement on the Quirky Cotton Collective Shirt

The native garment preview shows a dark shirt with very small, centered lowercase lettering: meh. That is the whole design. No animal, no diagram, no secondary slogan, no decorative frame. The word sits in the middle of the chest at a scale that almost requires leaning in to read, and it ends with a period. The period is the part I keep returning to.

This is a different object from the large lowercase meh shirt I wrote about previously. That one announced itself across the torso; this one whispers. The distinction matters because the two garments make different arguments about the same word. A large meh is a performance — a public declaration of indifference delivered at volume. A small meh. with a full stop is something closer to a status report. It is not asking you to laugh. It is not asking you to agree. It is filing a terse, final assessment and then closing the ticket.

What the period is doing

Punctuation in retail prose is not proof of what is printed on a shirt, so I want to be careful here: the observation is that the preview shows lowercase meh followed by a period. That is a visual fact about the artwork. What the period means is my reading, not a claim about the designer’s intent or the word’s history.

My reading is that the period converts an interjection into a sentence. Meh on its own is a noise — the verbal equivalent of a shrug, something you say when a colleague asks how the migration went and you do not have the energy to explain. Meh. with a period is a complete thought. It has a subject and a predicate implied by context, and it has decided to stop talking. In the register of written communication that technical teams actually use — commit messages, incident notes, ticket comments, one-line Slack replies — the period is what separates a draft from a decision.

I have spent a lot of time in systems where the difference between meh and meh. is the difference between a thread that continues for forty minutes and one that ends. The period is a boundary marker. It says: this assessment is final, the discussion is closed, and no further input is required. That is a useful thing to be able to say, and it is surprisingly hard to say without either over-explaining or sounding hostile. A small word with a period does it without raising its voice.

Scale as the argument

The other half of the design is the size. Very small, centered, lowercase. On a dark shirt, the contrast is low enough that the word does not read from across a room. You have to be close. That is not an accident of the preview; it is the composition. The shirt is not trying to start a conversation with strangers. It is trying to be legible to the person standing next to you, and only if they are paying attention.

This is the opposite of how most slogan shirts work. The genre convention is large type, high contrast, a punchline you can read from the other side of a parking lot. Those shirts are built for the laugh of recognition from a distance. This one is built for the opposite: a private signal that rewards proximity. It is the visual equivalent of a terse reply in a channel where everyone else is writing paragraphs.

I find that more interesting than the joke itself. The word meh is not especially funny on its own; it has been worn thin by a decade of reaction images and low-effort replies. What makes this design worth looking at is the restraint. The designer has taken a word that usually signals exhaustion or dismissal and treated it with the typographic discipline of a formal statement. Small caps would have been too official. All caps would have been shouting. Lowercase, small, centered, period — that is the register of someone who has thought about it and arrived at a conclusion they are not going to elaborate on.

The difference between a slogan and a usable promise

Technical readers spend a lot of their working lives distinguishing between messages that sound meaningful and messages that actually commit to something. A status page that says “investigating” is a slogan. A status page that says “database failover completed at 03:14 UTC, replication lag under 2 seconds, monitoring for 30 minutes” is a usable promise. The difference is not length; it is whether the statement can be acted on or verified.

A shirt is not a status page, and I am not going to pretend this design demonstrates anything about engineering practice. But the aesthetic instinct behind it — the preference for a short, final, low-volume statement over a long, loud, ambiguous one — is recognizable to anyone who has had to write an incident summary at the end of a long night. The best ones are short. They end with a period. They do not include the word “meh,” but they often convey the same thing.

That is the argument I would make for this shirt as an object: it is a study in how little you can say and still be saying something. The word is small, the type is quiet, and the period is doing most of the work. If you are the kind of person who has learned to distrust long explanations and to appreciate a message that knows when to stop, the design will read as familiar rather than ironic.

The object itself

The shirt is sold by Quirky Cotton Collective under the title Meh Funny Sarcastic Introvert Minimalist Saying. The retail title uses words like “funny” and “sarcastic,” which is how listings get found, but the artwork itself is more reserved than that. The preview shows a dark standard t-shirt with the small centered lowercase meh. and nothing else. There is no animal illustration, no pride variant, no secondary graphic. If you are looking for the version with a picture on it, this is not that shirt.

I have not worn it, washed it, or tested how the print holds up over time, so I cannot tell you anything about the fabric or the durability of the lettering. What I can tell you is what the preview shows, and what the preview shows is a design that has made a deliberate choice about scale. The meh shirt is available on Amazon if you want to see the current listing and sizing for yourself.

The keyword that brings people to this kind of listing is usually meh shirt, and the intent behind that search is probably not a deep interest in typography. But the search and the design are not unrelated. People look for a meh shirt because they want a low-stakes way to signal a certain disposition — tired, unimpressed, not particularly moved by whatever is happening around them. This design understands that the signal works better when it is small. A large meh is a costume. A small meh. is a mood.

What the period closes

The more I look at the preview, the more the period feels like the whole point. It is the smallest possible mark of finality. It does not add emphasis; it removes the possibility of continuation. In a work culture that rewards elaboration, that is a quietly subversive thing to wear. It says: I have considered the situation, my assessment is meh, and I am not going to be taking questions.

That is not a cure for anything, and it is not a productivity system. It is a shirt with one word and one punctuation mark on it, and the restraint is what makes it worth a second look. If you have ever ended a long thread with a single short sentence and then closed the laptop, you already know what it is saying.

Editorial note: This publication and Quirky Cotton Collective share an owner.

The Four Tiles That Don’t Spell the Sentence: Reading ‘I Wear This Shirt Periodically’

The shirt reads I WEAR THIS SHIRT PERIODICALLY, and beneath the words sit four tiles in the visual grammar of the periodic table. Each tile carries an atomic number and a symbol: 53 I, 74 W, 22 Ti, 16 S. Read the symbols in order and you get I W Ti S. That is not the word periodically. It is not a word at all. The joke lives in that gap, and the gap is worth taking seriously, because it is the same gap that opens whenever a terse message is asked to carry more meaning than its characters can hold.

The design is doing two things at once, and only one of them is a pun. The first is a sentence about frequency: the wearer puts the shirt on from time to time. The second is a claim about the periodic table: four elements, correctly numbered, arranged left to right. The numbers are real. Iodine is 53. Tungsten is 74. Titanium is 22. Sulfur is 16. Whoever laid this out knew the table well enough to pick symbols whose letters approximate the sounds of the sentence, and knew it well enough not to pretend the approximation is exact. The tile symbols are I W Ti S, and the shirt does not hide that. It asks you to hear the sentence through the symbols rather than read the symbols as a spelling.

That is a more disciplined joke than it first appears. A weaker version would have forced the table to spell the word literally, inventing symbols or fudging numbers until the letters lined up. This one accepts the mismatch and makes the mismatch the point. The eye reads I W Ti S, stumbles, and then the ear supplies periodically. The correction is the punchline. You are not meant to decode the tiles as a cipher; you are meant to notice that they are not a cipher and enjoy the near-miss.

I keep coming back to this because it is a small, clean example of a problem that shows up constantly in technical work: the difference between a message that is recognizable and a message that is precise. A monitoring alert that says disk almost full is recognizable. It is not precise until it names the mount point, the threshold, and the rate of growth. A runbook step that says restart the service is recognizable. It is not precise until it says which unit, under which supervisor, and what to check if the restart loops. The shirt’s tiles are recognizable as periodically and precise as nothing. The humor comes from watching a familiar form — the element tile, with its number and symbol — get drafted into a job it was never built for.

There is a second reading, and it is the one I find more useful. The sentence I wear this shirt periodically is a boundary statement. It is not a promise of constant wear. It is not a claim that the shirt is the wearer’s identity. It is a modest, honest description of frequency, delivered in the driest possible register. In an era when every object seems to arrive with an exhortation attached — always, never, every day — a shirt that says periodically is almost restful. It promises less and therefore promises accurately. The element tiles reinforce the modesty: even the joke is assembled from parts that do not quite fit, and it survives anyway.

The visual arrangement matters to that reading. The four tiles sit in a row, evenly spaced, each one a self-contained box with its number above and its symbol below. That is the layout of a reference table, not a slogan. A slogan would center the words and let the type do the shouting. This design lines up its components like a data sheet and lets the reader do the work of reconciliation. The effect is closer to a diagram than a punchline, which is why it rewards a second look rather than a single laugh. The first look says chemistry joke. The second look says the chemistry joke does not spell the word, and that is the chemistry joke.

I would not overclaim what the shirt demonstrates. It is a printed design on a garment, not a lesson in pedagogy, not a proof about how people learn to read symbols, and certainly not evidence about anything the wearer can or cannot do. The tiles are a visual pun built from real atomic numbers, and the pun works because the numbers are real. That is the whole of the claim. The rest is interpretation, and I am flagging it as interpretation: the pleasure here is the pleasure of a near-miss that has been engineered carefully enough to be worth noticing.

For readers who spend their days writing terse messages that other people have to act on, the shirt is a useful reminder in wearable form. Brevity is not the same as clarity. A short message can be recognizable and still be wrong in the details that matter. The element tiles are short, they are recognizable, and they are wrong as a spelling — and the design knows it, which is why it is funny instead of merely broken. The lesson, if there is one, is to know which kind of message you are sending. If you want to be recognized, four tiles will do. If you want to be understood, you may need the whole sentence.

The shirt is listed as I Wear This Shirt Periodically Funny Chemistry Science Pun from Quirky Cotton Collective. The design observation above is drawn from the listing artwork as of October 2026; it describes the printed arrangement, not a wearing experience, and it does not establish where the joke first appeared or how popular the shirt has been.

Editorial note: this publication and Quirky Cotton Collective share an owner.

The Crossed-Out Hand and the Yellow Triangle: Reading the ‘Not Friendly Do Not Touch’ Warning Sign

The shirt does not say please. It says NOT FRIENDLY in the flat, declarative register of a hazard placard, then DO NOT TOUCH beneath it, and it backs the words with two pieces of borrowed safety iconography: a yellow caution triangle and a hand with a diagonal slash through it. The whole composition is a public-warning sign that has been repurposed to describe a person. That repurposing is the interesting part, and it is worth reading closely before deciding whether it is funny, rude, or both.

Warning signs work because they compress a rule into a shape. A yellow triangle means attention, something here can hurt you. A crossed-out hand means do not put your hand there. Neither symbol is subtle, and neither is meant to be. When they are printed on a t-shirt, the wearer is borrowing the authority of the sign. The joke depends on the mismatch: a human being is not a piece of machinery, and a preference for quiet is not a physical hazard. The design leans into that mismatch rather than resolving it.

What the artwork actually shows

The observed design is straightforward: the words NOT FRIENDLY and DO NOT TOUCH set in warning-sign lettering, a yellow caution triangle, and a crossed-out hand symbol. The lettering is the kind you see on industrial labels and road barriers — uppercase, evenly spaced, built to be read at a distance. The triangle and the hand do the rest of the work. There is no portrait, no mascot, no speech bubble. The shirt is a sign, and the sign is the entire argument.

That restraint matters. A lesser design might have added a cartoon face or a sarcastic caption to make sure the joke landed. This one trusts the visual grammar of the warning sign to carry the meaning. If you have ever walked past a DO NOT ENTER placard without reading the fine print, you already know how quickly that grammar registers. The shirt borrows that speed.

The difference between a slogan and a usable promise

There is a useful distinction between a slogan and a promise, and this shirt sits right on the line. A slogan is a phrase that sounds good. A promise is a statement you can act on. NOT FRIENDLY is a slogan in the sense that it is blunt and memorable, but DO NOT TOUCH is closer to a promise: it tells you what will happen if you ignore it. The crossed-out hand is the enforcement clause.

In technical work, we spend a lot of time thinking about promises. A service-level objective is a promise. A backup policy is a promise. A firewall rule is a promise about what traffic will and will not pass. The good ones are specific, testable, and honest about their limits. The bad ones are vague, aspirational, and quietly broken. This shirt is not a service-level objective, but it shares a virtue with good ones: it does not pretend to be friendlier than it is. It states a boundary in the plainest available language and attaches a symbol that means this is not a suggestion.

That is why the design reads as more than a novelty. It is a small exercise in boundary-setting, dressed up as a hazard sign. The humor comes from the fact that the boundary is social rather than physical, and the sign language is absurdly literal about it. But the underlying move — here is what I am, here is what I need, please adjust accordingly — is one that most people who work on call, or in open-plan offices, or in any role where interruptions have a cost, will recognize.

Why the caution triangle is doing more than decoration

The yellow triangle is the most efficient part of the design. It does not need to be read. It is recognized before it is read, which is exactly what a warning symbol is for. In safety signage, the triangle is a category marker: it tells you what kind of attention to pay before you know the details. Here, it tells you that the words that follow are not small talk. They are a notice.

I am not making a claim about the history of warning-sign design or about any regulatory standard. I am describing what the shape does on this shirt. It frames the text. It gives the words a frame of reference — industrial, official, slightly absurd when applied to a person — and it makes the crossed-out hand feel like part of a system rather than a random doodle. Remove the triangle and the design becomes a grumpy caption. Keep it and the design becomes a sign.

The crossed-out hand and the problem of being perceived

The crossed-out hand is the part that will get the most reactions, and it is worth thinking about why. A hand is the most social part of the body. It is what you extend when you meet someone. It is what you wave with. Crossing it out is a refusal of the most basic social gesture, and doing it in the visual language of a safety label makes the refusal feel institutional rather than personal. The shirt is not saying I am shy. It is saying this area is closed.

That is a stronger statement than most introvert-themed shirts make. The usual move is to soften the message with a joke about social batteries or a cartoon animal. This design does not soften it. It puts the boundary in the same visual category as high voltage and authorized personnel only. Whether that reads as funny or hostile depends entirely on the wearer and the room, and the shirt does not try to control that. It just states the terms.

There is a real question underneath the joke about how much of our social presentation is a promise we did not agree to make. People in technical roles are often assumed to be available — for questions, for context switches, for the small interruptions that add up to a fragmented day. A shirt like this is a low-stakes way of pushing back on that assumption. It is not a policy. It is a sign. But signs exist because assumptions need correcting.

Reading it as an object, not a diagnosis

It would be easy to overread this shirt as a statement about introversion, or about neurodivergence, or about the state of modern office culture. I do not think the design supports that much weight. It is a warning sign with a joke inside it, and the joke is that the warning is about a person. The crossed-out hand is funny because it is disproportionate. The yellow triangle is funny because it is official. The words are funny because they are true enough to sting.

What makes it work as an object is that it does not ask you to agree with a thesis. It asks you to recognize a format. Anyone who has ever stood in front of a locked door, a wet floor, or a piece of equipment with a tag on it knows how to read this shirt in under a second. The design is efficient in the way that good signage is efficient, and that efficiency is the whole point. It is a boundary expressed in the fewest possible marks.

If you are the kind of person who has ever wanted to hang a small sign on your cubicle, or your desk, or your general existence, the shirt is a wearable version of that impulse. It is available as a standard t-shirt from Quirky Cotton Collective. The design does not promise that anyone will read it correctly. It only promises that the terms are stated.

The limit of the joke

The one thing the shirt cannot do is enforce itself. A warning sign works because the hazard is real and the consequences are visible. A crossed-out hand on a t-shirt is a request, not a barrier. The humor depends on everyone in the room understanding that the request is partly a joke, which means the shirt is most effective among people who already know how to read that kind of deadpan. In a room full of strangers, it might read as simply rude. That is not a flaw in the design so much as a limit of the format. Signs are context-dependent. So are people.

What remains after the joke is a small, useful idea: a boundary stated plainly is easier to respect than a boundary hinted at. The shirt says what it means, uses symbols that mean what they have always meant, and does not apologize for the combination. That is a more coherent design argument than most novelty shirts manage, and it is why the crossed-out hand stays with you after the yellow triangle has done its job.

Editorial note: This publication and Quirky Cotton Collective share an owner. This is not an independent review.

DNSSEC KSK Rollovers on a Small Domain: Sequencing the Parent DS Change with Knot DNS

Why a KSK rollover is not a ZSK rollover

Zone signing keys and key signing keys fail in different ways, and the difference matters more than any configuration detail. A ZSK signs the zone’s ordinary data; the RRSIG and the DNSKEY that validates it both come from the same zone, so a caching resolver either has both or can fetch both from the same authoritative server. A KSK signs only the DNSKEY RRset, and trust in that KSK comes from outside the zone: either a DS record in the parent zone or a trust anchor configured directly in the resolver. RFC 7583 states the split plainly: “A ZSK is used to authenticate information within the zone; a KSK is used to authenticate the zone’s DNSKEY RRset.”

The consequence is that a KSK rollover is a two-zone operation. RFC 7583 again: when trust comes via a DS record, “the rollover algorithm will need to involve the parent zone in the addition and removal of DS records, so timings are not wholly under the control of the zone manager.” For a small operator, that sentence is the whole article. The signing server is the part you control. The registrar’s DS update is the part you do not.

This is why the common framing — “the KSK rotation that breaks resolvers” — is misleading. A correctly sequenced rollover does not break resolvers. A rollover that changes the parent DS before the new DNSKEY is visible, or retires the old KSK before the old DS has expired from caches, produces a window in which a validating resolver holds a DS that points at a key it cannot find, or a DNSKEY RRset signed only by a key the parent does not vouch for. Either state is bogus, and bogus means SERVFAIL for every name in the zone. The failure is a sequencing failure, not a property of KSK rollovers in general.

The three KSK rollover methods, and which one fits a small domain

RFC 7583 describes three methods. It presents them; it does not recommend one. The choice is an operational one.

  • Double-KSK. The new KSK is added to the DNSKEY RRset and the RRset is signed with both keys. After the old RRset has expired from caches, the DS record in the parent is changed. After a further interval for that change to be reflected in caches, the old key is removed.
  • Double-DS. The new DS record is published first. After it propagates, the KSK is changed. After the old DNSKEY RRset expires from caches, the old DS is removed.
  • Double-RRset. The new KSK is added and the DNSKEY RRset signed with both keys, and the new DS is added to the parent at the same time. After a suitable interval, the old DNSKEY and DS records are removed.

For a domain served by one or two authoritative servers and registered through a registrar whose DS interface is a web form, Double-KSK is the method that keeps the risky step isolated. Everything before the DS change is reversible: if the new KSK turns out to be wrong, you retire it and nothing has touched the parent. Everything after the DS change depends on the new key staying valid. Double-DS inverts that: the parent is changed first, and the child has to catch up. Double-RRset changes both sides at once, which is fine if you can coordinate them and unpleasant if you cannot.

The recommendation here is Double-KSK for small operators, not because RFC 7583 prefers it but because it puts the irreversible step last and gives you a clean rollback point before it.

Manual key management in Knot DNS, and why it is worth the extra steps

Knot DNS supports automatic DNSSEC signing in two modes. The documentation describes manual key management as follows: “the server maintains zone signatures (RRSIGs) only. The signatures are kept up-to-date and signing keys are rolled according to the timing parameters assigned to the keys. The keys must be generated and timing parameters must be assigned by the zone operator.” Automatic key management, by contrast, generates and rolls keys according to a policy with no operator intervention.

For a KSK rollover on a domain you log into twice a year, manual management is the better default. It forces you to look at the key states between transitions. An automatic rollover you never inspect is a rollover you cannot debug when a resolver starts returning SERVFAIL and you are not sure which key is live. Manual management also makes the DS step an explicit action rather than a side effect of a timer.

A minimal policy for manual management looks like this:

policy:
  - id: manual
    manual: on
zone:
  - domain: example.com
    dnssec-signing: on
    dnssec-policy: manual

Keys are then generated with keymgr. The KASP database that holds them is LMDB-backed and, without an HSM, contains private key material; the Knot documentation warns explicitly: “If no HSM is used, the database also contains private key material – don’t set the permissions too weak.”

Walking the Double-KSK sequence with keymgr

The example below is a hypothetical walkthrough built from documented keymgr primitives. It is not a report of a specific rollover. The timestamps are illustrative; substitute your own TTLs and registrar latency.

Knot’s key states, as documented in the keymgr manual, include publish, ready, active, retire, and remove. For a KSK, ready is described as “Key is waiting for submission (only for KSK).” That state is the hinge of the whole procedure: it is where the child zone has published the new key and is waiting for the parent to vouch for it.

Step 1: generate the new KSK, published but not active

keymgr example.com. generate algorithm=ECDSAP256SHA256 ksk=yes publish=now active=+2d

The new KSK appears in the DNSKEY RRset immediately. The DNSKEY RRset is signed with both the old and new KSK during this window. No DS change has happened yet. If anything looks wrong, delete the new key and nothing outside your zone has changed.

Step 2: wait out the DNSKEY TTL

RFC 7583 assumes constant TTLs in its timelines and notes that changing TTLs around a rollover “may have an impact on event timings.” Do not change TTLs during the rollover. Wait at least the DNSKEY RRset TTL, plus whatever margin you trust, so that any resolver holding a cached DNSKEY RRset has seen both keys. The active=+2d above is a placeholder for that interval.

Step 3: verify the new key is visible from outside

Query your authoritative server directly for the DNSKEY RRset and confirm both KSKs are present. Then query a public validating resolver for the same RRset and confirm it returns both keys with a valid signature. Your local resolver’s cache is exactly the thing that hides rollover mistakes, so do not use it as the only check.

Step 4: change the DS record at the registrar

This is the step that is not under your control. Generate the DS for the new key:

keymgr example.com. ds <new_key_id>

Submit it to the registrar. The Knot documentation is explicit about the timing constraint: “Remember to update the DS record in the parent zone to include a reference to the new key. This must happen within one day (in this case) including a delay required to propagate the new DS to caches.” The “one day” there is the example’s window, not a universal rule; the real constraint is whatever interval you set between active and retire on the old key, minus DS propagation time.

If your registrar supports publishing both the old and new DS simultaneously, do that. If it only supports replacing one DS with another, you are relying on the parent’s negative caching and the child’s dual-signed DNSKEY RRset to cover the gap. That is the standard Double-KSK assumption, but it is worth knowing which case you are in before you submit.

Step 5: wait for the new DS to propagate

Query the parent zone directly for the DS RRset and confirm the new DS is present. Then query a public validating resolver and confirm it validates the chain. Only after both checks pass should you schedule the old key’s retirement.

Step 6: retire the old KSK

keymgr example.com. set <old_key_id> retire=+2d remove=+4d

The old key remains published until retire, then is removed at remove. The gap between the two is the window in which the old DNSKEY RRset expires from caches. Do not shorten it because the rollover “feels done.”

What “safe” means, and why the schedule is secondary

RFC 7583 is direct about the goal: “the point of key management logic is not to ensure that a rollover is completed at a certain time but rather to ensure that no changes are made to the state of keys published in the zone until it is ‘safe’ to do so (‘safe’ in this context meaning that at no time during the rollover process does any part of the zone ever go bogus).”

That reframes the whole exercise. You are not trying to hit a date. You are trying to avoid any moment when a validating resolver holds a DS that does not match a published DNSKEY, or a DNSKEY RRset signed only by a key the parent does not vouch for. Every step above is a wait for caches to converge, not a wait for a calendar.

The same RFC notes that a slow parent is not itself a problem: “even with a parent that is less than ideally responsive, the only effect will be a slowdown in the rollover state transitions. This may cause a policy violation, but will not cause any operational problems.” A registrar that takes three days to publish a DS does not break your zone. A registrar that takes three days while you have already retired the old KSK does.

Verification checkpoints between steps

The checks that matter are the ones run from outside your own network. A short list:

  • After step 1: query the authoritative server for the DNSKEY RRset and confirm both KSKs are present. Query a public validating resolver and confirm it returns the same RRset with a valid signature.
  • After step 4: query the parent zone directly for the DS RRset and confirm the new DS is present. Query a public validating resolver for a name in your zone and confirm it returns an answer, not SERVFAIL.
  • After step 6: query a public validating resolver for a name in your zone again. If it returns SERVFAIL, the old key was retired before the old DS expired from caches, or the new DS was never accepted.

If the registrar is slow, the correct response is to extend the interval before retire on the old key, not to shorten it. The old key is doing useful work as long as the old DS may still be cached somewhere.

Rollback before and after the DS change

Before the DS change, rollback is trivial: delete the new KSK and the zone returns to its previous state. Nothing outside your zone has changed.

After the DS change, rollback is not trivial. If the new KSK turns out to be wrong, you have two options: re-publish the old KSK and submit its DS again, or fix the new key in place. The first is faster if the old key is still in the KASP database and still published; the second is safer if the old key was already retired. Either way, the window between the DS change and the old key’s retirement is the only period in which rollback is cheap. Treat it as such.

When automatic KSK management is the right call

Knot supports automatic KSK management through a submission section pointing at the parent zone server, combined with a finite ksk-lifetime in the policy. The documentation describes this as “semi-automatic DS submission.” The word “semi” is doing real work: the server can publish the new key and prepare the DS, but the actual submission to the registrar is still an operator action unless your registrar exposes an interface Knot can drive.

Automatic management is reasonable when you have a registrar with a reliable API, a monitoring system that alerts on DNSSEC validation failures, and enough rollover frequency that manual steps become a burden. For a domain rolled once a year, the manual sequence above is shorter than the time it takes to debug an automatic rollover that stalled at ready because the parent never accepted the DS.

What you give up with automatic management is observability between states. The server will not tell you that the DS step is the one that failed; it will tell you that the key is still in ready. That is a fine signal if you have a runbook for it and a poor one if you do not.

Scope limits worth knowing

RFC 7583 explicitly scopes out two cases that small operators sometimes conflate with KSK rollover: “it does not cover: rolling a key that is used as both a ZSK and KSK” and “algorithm rollovers.” If you are using a single CSK, the KSK timelines in RFC 7583 do not apply to it. If you are changing algorithms, the constraints are different and the RFC says so. Do not borrow the Double-KSK sequence for either case and expect it to hold.

The other scope limit is TTLs. The RFC assumes constant TTLs in its timelines. If you have been meaning to lower your DNSKEY TTL, do it before the rollover, not during it.

FAQ

Can I skip the wait between publishing the new KSK and changing the DS?

Only if you are certain no resolver holds a cached DNSKEY RRset that lacks the new key. In practice that means waiting at least the DNSKEY TTL. Skipping the wait produces a window in which a resolver has the new DS but not the new DNSKEY, which is bogus.

What happens if my registrar publishes the new DS but not the old one?

You are relying on the child’s dual-signed DNSKEY RRset to cover the gap. That is the standard Double-KSK assumption. It works as long as the old KSK is still published and the old DS has not yet expired from caches. Do not retire the old KSK until you are confident both conditions hold.

How do I know the rollover succeeded?

A public validating resolver returns an answer, not SERVFAIL, for a name in your zone, and a direct query to the parent returns the new DS. Both checks, from outside your network, after each step.

Is automatic KSK management safe for a small domain?

It is safe in the sense that Knot will not change key states until it considers them safe. It is less safe in the sense that the DS submission step still depends on your registrar, and a stalled submission is easier to miss when no one is watching the key states. Manual management is the better default for infrequent rollovers.

Sources

Posts navigation

1 2 3
Scroll to top